turn off Nagle

This commit is contained in:
dborth 2010-06-27 00:42:17 +00:00
parent b7881bfa72
commit 7b9772cec9

View File

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