diff --git a/general.h b/general.h index 9f9e854283..a212846dee 100644 --- a/general.h +++ b/general.h @@ -609,6 +609,12 @@ struct global #ifdef HAVE_NETWORKING struct { + struct + { + struct http_connection_t *handle; + transfer_cb_t cb; + char elem1[PATH_MAX_LENGTH]; + } connection; msg_queue_t *msg_queue; struct http_t *handle; transfer_cb_t cb; diff --git a/net_http.c b/net_http.c index ec00f5c0f4..773d2c9d24 100644 --- a/net_http.c +++ b/net_http.c @@ -53,42 +53,15 @@ struct http_t char * data; }; -static bool net_http_parse_url(char *url, char **domain, - int *port, char **location) +struct http_connection_t { + char *domain; + char *location; + char *urlcopy; char* scan; + int port; +}; - if (strncmp(url, "http://", strlen("http://")) != 0) - return false; - - scan = url + strlen("http://"); - *domain = scan; - - while (*scan != '/' && *scan != ':' && *scan != '\0') - scan++; - - if (*scan == '\0') - return false; - - *scan = '\0'; - *port = 80; - - if (*scan == ':') - { - - if (!isdigit(scan[1])) - return false; - - *port = strtoul(scan + 1, &scan, 10); - - if (*scan != '/') - return false; - } - - *location = scan + 1; - - return true; -} static int net_http_new_socket(const char * domain, int port) { @@ -189,38 +162,118 @@ static ssize_t net_http_recv(int fd, bool *error, return -1; } -struct http_t *net_http_new(const char * url) +struct http_connection_t *net_http_connection_new(const char *url) +{ + char **domain = NULL; + struct http_connection_t *conn = (struct http_connection_t*)calloc(1, + sizeof(struct http_connection_t)); + + if (!conn) + return NULL; + + conn->urlcopy = (char*)malloc(strlen(url) + 1); + + if (!conn->urlcopy) + goto error; + + strcpy(conn->urlcopy, url); + + if (strncmp(url, "http://", strlen("http://")) != 0) + goto error; + + conn->scan = conn->urlcopy + strlen("http://"); + + domain = &conn->domain; + + *domain = conn->scan; + + return conn; + +error: + if (conn->urlcopy) + free(conn->urlcopy); + conn->urlcopy = NULL; + if (conn) + free(conn); + return NULL; +} + +bool net_http_connection_iterate(struct http_connection_t *conn) +{ + if (*conn->scan != '/' && *conn->scan != ':' && *conn->scan != '\0') + { + conn->scan++; + return false; + } + return true; +} + +bool net_http_connection_done(struct http_connection_t *conn) +{ + char **location = NULL; + + if (!conn) + return false; + + location = &conn->location; + + if (*conn->scan == '\0') + return false; + + *conn->scan = '\0'; + conn->port = 80; + + if (*conn->scan == ':') + { + + if (!isdigit(conn->scan[1])) + return false; + + conn->port = strtoul(conn->scan + 1, &conn->scan, 10); + + if (*conn->scan != '/') + return false; + } + + *location = conn->scan + 1; + + return true; +} + +void net_http_connection_free(struct http_connection_t *conn) +{ + if (conn->urlcopy) + free(conn->urlcopy); +} + +struct http_t *net_http_new(struct http_connection_t *conn) { bool error; - char *domain = NULL, *location = NULL; - int port = 0, fd = -1; + int fd = -1; struct http_t *state = NULL; - char *urlcopy =(char*)malloc(strlen(url)+1); - strcpy(urlcopy, url); + if (!conn) + goto error; - if (!net_http_parse_url(urlcopy, &domain, &port, &location)) - goto fail; - - fd = net_http_new_socket(domain, port); + fd = net_http_new_socket(conn->domain, conn->port); if (fd == -1) - goto fail; + goto error; error=false; /* This is a bit lazy, but it works. */ net_http_send_str(fd, &error, "GET /"); - net_http_send_str(fd, &error, location); + net_http_send_str(fd, &error, conn->location); net_http_send_str(fd, &error, " HTTP/1.1\r\n"); net_http_send_str(fd, &error, "Host: "); - net_http_send_str(fd, &error, domain); + net_http_send_str(fd, &error, conn->domain); - if (port!=80) + if (conn->port != 80) { char portstr[16]; - snprintf(portstr, sizeof(portstr), ":%i", port); + snprintf(portstr, sizeof(portstr), ":%i", conn->port); net_http_send_str(fd, &error, portstr); } @@ -229,9 +282,7 @@ struct http_t *net_http_new(const char * url) net_http_send_str(fd, &error, "\r\n"); if (error) - goto fail; - - free(urlcopy); + goto error; state = (struct http_t*)malloc(sizeof(struct http_t)); state->fd = fd; @@ -246,14 +297,13 @@ struct http_t *net_http_new(const char * url) state->data = (char*)malloc(state->buflen); if (!state->data) - goto fail; + goto error; return state; -fail: +error: if (fd != -1) socket_close(fd); - free(urlcopy); return NULL; } diff --git a/net_http.h b/net_http.h index 4551083f07..b6b6b3a1e2 100644 --- a/net_http.h +++ b/net_http.h @@ -26,8 +26,17 @@ extern "C" { #endif struct http_t; +struct http_connection_t; -struct http_t *net_http_new(const char * url); +struct http_connection_t *net_http_connection_new(const char *url); + +bool net_http_connection_iterate(struct http_connection_t *conn); + +bool net_http_connection_done(struct http_connection_t *conn); + +void net_http_connection_free(struct http_connection_t *conn); + +struct http_t *net_http_new(struct http_connection_t *conn); /* You can use this to call net_http_update * only when something will happen; select() it for reading. */ diff --git a/runloop_data.c b/runloop_data.c index f7761a2b72..ce4d4011ab 100644 --- a/runloop_data.c +++ b/runloop_data.c @@ -50,6 +50,28 @@ static int rarch_main_iterate_http_transfer(void) return 0; } +static int rarch_main_iterate_http_conn_transfer(void) +{ + if (!net_http_connection_iterate(g_extern.http.connection.handle)) + return -1; + return 0; +} + +static int rarch_main_iterate_http_conn_parse(void) +{ + if (net_http_connection_done(g_extern.http.connection.handle)) + { + if (g_extern.http.connection.handle && g_extern.http.connection.cb) + g_extern.http.connection.cb(g_extern.http.connection.handle, 0); + } + + net_http_connection_free(g_extern.http.connection.handle); + + g_extern.http.connection.handle = NULL; + + return 0; +} + static int rarch_main_iterate_http_parse(void) { size_t len; @@ -66,6 +88,29 @@ static int rarch_main_iterate_http_parse(void) return 0; } +static int cb_http_conn_default(void *data_, size_t len) +{ + g_extern.http.handle = net_http_new(g_extern.http.connection.handle); + + if (!g_extern.http.handle) + { + RARCH_ERR("Could not create new HTTP session handle.\n"); + return -1; + } + + g_extern.http.cb = NULL; + + if (g_extern.http.connection.elem1[0] != '\0') + { + if (!strcmp(g_extern.http.connection.elem1, "cb_core_updater_download")) + g_extern.http.cb = &cb_core_updater_download; + if (!strcmp(g_extern.http.connection.elem1, "cb_core_updater_list")) + g_extern.http.cb = &cb_core_updater_list; + } + + return 0; +} + /** * rarch_main_iterate_http_transfer: * @@ -81,7 +126,7 @@ static int rarch_main_iterate_http_parse(void) **/ static int rarch_main_iterate_http_poll(void) { - char elem0[PATH_MAX_LENGTH], elem1[PATH_MAX_LENGTH]; + char elem0[PATH_MAX_LENGTH]; struct string_list *str_list = NULL; const char *url = msg_queue_pull(g_extern.http.msg_queue); @@ -99,27 +144,18 @@ static int rarch_main_iterate_http_poll(void) if (str_list->size > 0) strlcpy(elem0, str_list->elems[0].data, sizeof(elem0)); - if (str_list->size > 1) - strlcpy(elem1, str_list->elems[1].data, sizeof(elem1)); - g_extern.http.handle = net_http_new(elem0); + g_extern.http.connection.handle = net_http_connection_new(elem0); - if (!g_extern.http.handle) - { - RARCH_ERR("Could not create new HTTP session handle.\n"); - string_list_free(str_list); + if (!g_extern.http.connection.handle) return -1; - } - g_extern.http.cb = NULL; + g_extern.http.connection.cb = &cb_http_conn_default; - if (elem1[0] != '\0') - { - if (!strcmp(elem1, "cb_core_updater_download")) - g_extern.http.cb = &cb_core_updater_download; - if (!strcmp(elem1, "cb_core_updater_list")) - g_extern.http.cb = &cb_core_updater_list; - } + if (str_list->size > 1) + strlcpy(g_extern.http.connection.elem1, + str_list->elems[1].data, + sizeof(g_extern.http.connection.elem1)); string_list_free(str_list); @@ -500,6 +536,12 @@ void do_data_state_checks(void) do_data_nbio_state_checks(&g_extern.nbio); #ifdef HAVE_NETWORKING + if (g_extern.http.connection.handle) + { + if (!rarch_main_iterate_http_conn_transfer()) + rarch_main_iterate_http_conn_parse(); + } + if (g_extern.http.handle) { if (!rarch_main_iterate_http_transfer())