From 7b9772cec92b45c1bbb99a66949dde97c67669b6 Mon Sep 17 00:00:00 2001 From: dborth Date: Sun, 27 Jun 2010 00:42:17 +0000 Subject: [PATCH] turn off Nagle --- source/utils/http.cpp | 868 +++++++++++++++++++++--------------------- 1 file changed, 436 insertions(+), 432 deletions(-) diff --git a/source/utils/http.cpp b/source/utils/http.cpp index e1e786e..72a44bd 100644 --- a/source/utils/http.cpp +++ b/source/utils/http.cpp @@ -1,432 +1,436 @@ -/**************************************************************************** - * Snes9x Nintendo Wii/Gamecube Port - * - * Tantric December 2008 - * - * http.cpp - * - * HTTP operations - * Written by dhewg/bushing, modified by Tantric - ***************************************************************************/ - -#ifdef HW_RVL - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "menu.h" -#include "http.h" - -#define TCP_CONNECT_TIMEOUT 4000 // 4 secs to make a connection -#define TCP_SEND_SIZE (32 * 1024) -#define TCP_RECV_SIZE (32 * 1024) -#define TCP_BLOCK_RECV_TIMEOUT 4000 // 4 secs to receive -#define TCP_BLOCK_SEND_TIMEOUT 4000 // 4 secs to send -#define TCP_BLOCK_SIZE 1024 -#define HTTP_TIMEOUT 10000 // 10 secs to get an http response -#define IOS_O_NONBLOCK 0x04 - -static s32 tcp_socket(void) -{ - s32 s, res; - - s = net_socket(PF_INET, SOCK_STREAM, 0); - if (s < 0) - return s; - - res = net_fcntl(s, F_GETFL, 0); - if (res < 0) - { - net_close(s); - return res; - } - - res = net_fcntl(s, F_SETFL, res | IOS_O_NONBLOCK); - if (res < 0) - { - net_close(s); - return res; - } - - return s; -} - -static s32 tcp_connect(char *host, const u16 port) -{ - struct hostent *hp; - struct sockaddr_in sa; - struct in_addr val; - fd_set myset; - struct timeval tv; - s32 s, res; - - s = tcp_socket(); - if (s < 0) - return s; - - memset(&sa, 0, sizeof(struct sockaddr_in)); - sa.sin_family= PF_INET; - sa.sin_len = sizeof(struct sockaddr_in); - sa.sin_port= htons(port); - - if(strlen(host) < 16 && inet_aton(host, &val)) - { - sa.sin_addr.s_addr = val.s_addr; - } - else - { - hp = net_gethostbyname (host); - if (!hp || !(hp->h_addrtype == PF_INET)) - return errno; - - memcpy((char *) &sa.sin_addr, hp->h_addr_list[0], hp->h_length); - } - - res = net_connect (s, (struct sockaddr *) &sa, sizeof (sa)); - - if (res == EINPROGRESS) - { - tv.tv_sec = TCP_CONNECT_TIMEOUT; - tv.tv_usec = 0; - FD_ZERO(&myset); - FD_SET(s, &myset); - if (net_select(s+1, NULL, &myset, NULL, &tv) <= 0) - return -1; - } - return s; -} - -static char * tcp_readln(const s32 s, const u16 max_length, const u64 start_time, - const u16 timeout) -{ - char *buf; - u16 c; - s32 res; - char *ret; - - buf = (char *) malloc(max_length); - - c = 0; - ret = NULL; - while (true) - { - if (ticks_to_millisecs(diff_ticks(start_time, gettime())) > timeout) - break; - - res = net_read(s, &buf[c], 1); - - if ((res == 0) || (res == -EAGAIN)) - { - usleep(20 * 1000); - continue; - } - - if (res < 0) - break; - - if ((c > 0) && (buf[c - 1] == '\r') && (buf[c] == '\n')) - { - if (c == 1) - { - ret = strdup(""); - break; - } - - ret = strndup(buf, c - 1); - - break; - } - - c++; - - if (c == max_length) - break; - - usleep(300); - } - - free(buf); - return ret; -} - -static int tcp_read(const s32 s, u8 *buffer, const u32 length) -{ - char *p; - u32 left, block, received, step=0; - s64 t; - s32 res; - - p = (char *)buffer; - left = length; - received = 0; - - t = gettime(); - while (left) - { - if (ticks_to_millisecs(diff_ticks(t, gettime())) - > TCP_BLOCK_RECV_TIMEOUT) - { - break; - } - - block = left; - if (block > TCP_RECV_SIZE) - block = TCP_RECV_SIZE; - - res = net_read(s, p, block); - - if(res>0) - { - received += res; - left -= res; - p += res; - } - else if (res < 0 && res != -EAGAIN) - { - break; - } - - usleep(1000); - - if ((received / TCP_BLOCK_SIZE) > step) - { - t = gettime (); - step++; - } - } - return received; -} - -static int tcp_write(const s32 s, const u8 *buffer, const u32 length) -{ - const u8 *p; - u32 left, block, sent, step=0; - s64 t; - s32 res; - - p = buffer; - left = length; - sent = 0; - - t = gettime(); - while (left) - { - if (ticks_to_millisecs(diff_ticks(t, gettime())) - > TCP_BLOCK_SEND_TIMEOUT) - { - break; - } - - block = left; - if (block > TCP_SEND_SIZE) - block = TCP_SEND_SIZE; - - res = net_write(s, p, block); - - if ((res == 0) || (res == -56)) - { - usleep(20 * 1000); - continue; - } - - if (res < 0) - break; - - sent += res; - left -= res; - p += res; - usleep(100); - - if ((sent / TCP_BLOCK_SIZE) > step) - { - t = gettime (); - step++; - } - } - - return left == 0; -} -static bool http_split_url(char **host, char **path, const char *url) -{ - const char *p; - char *c; - - if (strncasecmp(url, "http://", 7)) - return false; - - p = url + 7; - c = strchr(p, '/'); - - if (c == NULL || c[0] == 0) - return false; - - *host = strndup(p, c - p); - *path = strdup(c); - - return true; -} - -#define MAX_SIZE (1024*1024*15) - -/**************************************************************************** - * http_request - * Retrieves the specified URL, and stores it in the specified file or buffer - ***************************************************************************/ -int http_request(const char *url, FILE * hfile, u8 * buffer, u32 maxsize, bool silent) -{ - int res = 0; - char *http_host; - u16 http_port; - char *http_path; - - http_res result; - u32 http_status; - u32 sizeread = 0, content_length = 0; - - int linecount; - - if(maxsize > MAX_SIZE) - return 0; - - if (url == NULL || (hfile == NULL && buffer == NULL)) - return 0; - - if (!http_split_url(&http_host, &http_path, url)) - return 0; - - http_port = 80; - http_status = 404; - - int s = tcp_connect(http_host, http_port); - - if (s < 0) - { - result = HTTPR_ERR_CONNECT; - return 0; - } - - char *request = (char *) malloc(1024); - char *r = request; - - r += sprintf(r, "GET %s HTTP/1.1\r\n", http_path); - r += sprintf(r, "Host: %s\r\n", http_host); - r += sprintf(r, "Cache-Control: no-cache\r\n\r\n"); - - res = tcp_write(s, (u8 *) request, strlen(request)); - - free(request); - - for (linecount = 0; linecount < 32; linecount++) - { - char *line = tcp_readln(s, 0xff, gettime(), (const u16) HTTP_TIMEOUT); - - if (!line) - { - http_status = 404; - result = HTTPR_ERR_REQUEST; - break; - } - - if (strlen(line) < 1) - { - free(line); - line = NULL; - break; - } - - sscanf(line, "HTTP/1.%*u %u", &http_status); - sscanf(line, "Content-Length: %u", &content_length); - - free(line); - line = NULL; - - } - - if (http_status != 200) - { - result = HTTPR_ERR_STATUS; - net_close(s); - return 0; - } - - // length unknown - just read as much as we can - if(content_length == 0) - { - content_length = maxsize; - } - else if (content_length > maxsize) - { - result = HTTPR_ERR_TOOBIG; - net_close(s); - return 0; - } - - if (buffer != NULL) - { - if(!silent) - ShowAction("Downloading..."); - - sizeread = tcp_read(s, buffer, content_length); - - if(!silent) - CancelAction(); - } - else - { - // read into file - u32 bufSize = (1026 * 256); - u32 bytesLeft = content_length; - u32 readSize; - - if(!silent) - ShowProgress("Downloading...", 0, content_length); - u8 * fbuffer = (u8 *) malloc(bufSize); - if(fbuffer) - { - while (bytesLeft > 0) - { - if (bytesLeft < bufSize) - readSize = bytesLeft; - else - readSize = bufSize; - - res = tcp_read(s, fbuffer, readSize); - if (!res) - break; - - sizeread += res; - bytesLeft -= res; - - res = fwrite(fbuffer, 1, res, hfile); - if (!res) - break; - - if(!silent) - ShowProgress("Downloading...", (content_length - bytesLeft), content_length); - } - free(fbuffer); - } - if(!silent) - CancelAction(); - } - - net_close(s); - - if (content_length < maxsize && sizeread != content_length) - { - result = HTTPR_ERR_RECEIVE; - return 0; - } - - result = HTTPR_OK; - return sizeread; -} -#endif +/**************************************************************************** + * Snes9x Nintendo Wii/Gamecube Port + * + * Tantric December 2008 + * + * http.cpp + * + * HTTP operations + * Written by dhewg/bushing, modified by Tantric + ***************************************************************************/ + +#ifdef HW_RVL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "menu.h" +#include "http.h" + +#define TCP_CONNECT_TIMEOUT 4000 // 4 secs to make a connection +#define TCP_SEND_SIZE (32 * 1024) +#define TCP_RECV_SIZE (32 * 1024) +#define TCP_BLOCK_RECV_TIMEOUT 4000 // 4 secs to receive +#define TCP_BLOCK_SEND_TIMEOUT 4000 // 4 secs to send +#define TCP_BLOCK_SIZE 1024 +#define HTTP_TIMEOUT 10000 // 10 secs to get an http response +#define IOS_O_NONBLOCK 0x04 + +static s32 tcp_socket(void) +{ + s32 s, res; + + s = net_socket(PF_INET, SOCK_STREAM, IPPROTO_IP); + if (s < 0) + return s; + + // Switch off Nagle with TCP_NODELAY + u32 nodelay = 1; + net_setsockopt(s,IPPROTO_TCP,TCP_NODELAY,&nodelay,sizeof(nodelay)); + + res = net_fcntl(s, F_GETFL, 0); + if (res < 0) + { + net_close(s); + return res; + } + + res = net_fcntl(s, F_SETFL, res | IOS_O_NONBLOCK); + if (res < 0) + { + net_close(s); + return res; + } + + return s; +} + +static s32 tcp_connect(char *host, const u16 port) +{ + struct hostent *hp; + struct sockaddr_in sa; + struct in_addr val; + fd_set myset; + struct timeval tv; + s32 s, res; + + s = tcp_socket(); + if (s < 0) + return s; + + memset(&sa, 0, sizeof(struct sockaddr_in)); + sa.sin_family= PF_INET; + sa.sin_len = sizeof(struct sockaddr_in); + sa.sin_port= htons(port); + + if(strlen(host) < 16 && inet_aton(host, &val)) + { + sa.sin_addr.s_addr = val.s_addr; + } + else + { + hp = net_gethostbyname (host); + if (!hp || !(hp->h_addrtype == PF_INET)) + return errno; + + memcpy((char *) &sa.sin_addr, hp->h_addr_list[0], hp->h_length); + } + + res = net_connect (s, (struct sockaddr *) &sa, sizeof (sa)); + + if (res == EINPROGRESS) + { + tv.tv_sec = TCP_CONNECT_TIMEOUT; + tv.tv_usec = 0; + FD_ZERO(&myset); + FD_SET(s, &myset); + if (net_select(s+1, NULL, &myset, NULL, &tv) <= 0) + return -1; + } + return s; +} + +static char * tcp_readln(const s32 s, const u16 max_length, const u64 start_time, + const u16 timeout) +{ + char *buf; + u16 c; + s32 res; + char *ret; + + buf = (char *) malloc(max_length); + + c = 0; + ret = NULL; + while (true) + { + if (ticks_to_millisecs(diff_ticks(start_time, gettime())) > timeout) + break; + + res = net_read(s, &buf[c], 1); + + if ((res == 0) || (res == -EAGAIN)) + { + usleep(20 * 1000); + continue; + } + + if (res < 0) + break; + + if ((c > 0) && (buf[c - 1] == '\r') && (buf[c] == '\n')) + { + if (c == 1) + { + ret = strdup(""); + break; + } + + ret = strndup(buf, c - 1); + + break; + } + + c++; + + if (c == max_length) + break; + + usleep(300); + } + + free(buf); + return ret; +} + +static int tcp_read(const s32 s, u8 *buffer, const u32 length) +{ + char *p; + u32 left, block, received, step=0; + s64 t; + s32 res; + + p = (char *)buffer; + left = length; + received = 0; + + t = gettime(); + while (left) + { + if (ticks_to_millisecs(diff_ticks(t, gettime())) + > TCP_BLOCK_RECV_TIMEOUT) + { + break; + } + + block = left; + if (block > TCP_RECV_SIZE) + block = TCP_RECV_SIZE; + + res = net_read(s, p, block); + + if(res>0) + { + received += res; + left -= res; + p += res; + } + else if (res < 0 && res != -EAGAIN) + { + break; + } + + usleep(1000); + + if ((received / TCP_BLOCK_SIZE) > step) + { + t = gettime (); + step++; + } + } + return received; +} + +static int tcp_write(const s32 s, const u8 *buffer, const u32 length) +{ + const u8 *p; + u32 left, block, sent, step=0; + s64 t; + s32 res; + + p = buffer; + left = length; + sent = 0; + + t = gettime(); + while (left) + { + if (ticks_to_millisecs(diff_ticks(t, gettime())) + > TCP_BLOCK_SEND_TIMEOUT) + { + break; + } + + block = left; + if (block > TCP_SEND_SIZE) + block = TCP_SEND_SIZE; + + res = net_write(s, p, block); + + if ((res == 0) || (res == -56)) + { + usleep(20 * 1000); + continue; + } + + if (res < 0) + break; + + sent += res; + left -= res; + p += res; + usleep(100); + + if ((sent / TCP_BLOCK_SIZE) > step) + { + t = gettime (); + step++; + } + } + + return left == 0; +} +static bool http_split_url(char **host, char **path, const char *url) +{ + const char *p; + char *c; + + if (strncasecmp(url, "http://", 7)) + return false; + + p = url + 7; + c = strchr(p, '/'); + + if (c == NULL || c[0] == 0) + return false; + + *host = strndup(p, c - p); + *path = strdup(c); + + return true; +} + +#define MAX_SIZE (1024*1024*15) + +/**************************************************************************** + * http_request + * Retrieves the specified URL, and stores it in the specified file or buffer + ***************************************************************************/ +int http_request(const char *url, FILE * hfile, u8 * buffer, u32 maxsize, bool silent) +{ + int res = 0; + char *http_host; + u16 http_port; + char *http_path; + + http_res result; + u32 http_status; + u32 sizeread = 0, content_length = 0; + + int linecount; + + if(maxsize > MAX_SIZE) + return 0; + + if (url == NULL || (hfile == NULL && buffer == NULL)) + return 0; + + if (!http_split_url(&http_host, &http_path, url)) + return 0; + + http_port = 80; + http_status = 404; + + int s = tcp_connect(http_host, http_port); + + if (s < 0) + { + result = HTTPR_ERR_CONNECT; + return 0; + } + + char *request = (char *) malloc(1024); + char *r = request; + + r += sprintf(r, "GET %s HTTP/1.1\r\n", http_path); + r += sprintf(r, "Host: %s\r\n", http_host); + r += sprintf(r, "Cache-Control: no-cache\r\n\r\n"); + + res = tcp_write(s, (u8 *) request, strlen(request)); + + free(request); + + for (linecount = 0; linecount < 32; linecount++) + { + char *line = tcp_readln(s, 0xff, gettime(), (const u16) HTTP_TIMEOUT); + + if (!line) + { + http_status = 404; + result = HTTPR_ERR_REQUEST; + break; + } + + if (strlen(line) < 1) + { + free(line); + line = NULL; + break; + } + + sscanf(line, "HTTP/1.%*u %u", &http_status); + sscanf(line, "Content-Length: %u", &content_length); + + free(line); + line = NULL; + + } + + if (http_status != 200) + { + result = HTTPR_ERR_STATUS; + net_close(s); + return 0; + } + + // length unknown - just read as much as we can + if(content_length == 0) + { + content_length = maxsize; + } + else if (content_length > maxsize) + { + result = HTTPR_ERR_TOOBIG; + net_close(s); + return 0; + } + + if (buffer != NULL) + { + if(!silent) + ShowAction("Downloading..."); + + sizeread = tcp_read(s, buffer, content_length); + + if(!silent) + CancelAction(); + } + else + { + // read into file + u32 bufSize = (1026 * 256); + u32 bytesLeft = content_length; + u32 readSize; + + if(!silent) + ShowProgress("Downloading...", 0, content_length); + u8 * fbuffer = (u8 *) malloc(bufSize); + if(fbuffer) + { + while (bytesLeft > 0) + { + if (bytesLeft < bufSize) + readSize = bytesLeft; + else + readSize = bufSize; + + res = tcp_read(s, fbuffer, readSize); + if (!res) + break; + + sizeread += res; + bytesLeft -= res; + + res = fwrite(fbuffer, 1, res, hfile); + if (!res) + break; + + if(!silent) + ShowProgress("Downloading...", (content_length - bytesLeft), content_length); + } + free(fbuffer); + } + if(!silent) + CancelAction(); + } + + net_close(s); + + if (content_length < maxsize && sizeread != content_length) + { + result = HTTPR_ERR_RECEIVE; + return 0; + } + + result = HTTPR_OK; + return sizeread; +} +#endif