X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Fwget_src%2Fmain.c;h=d068053449e737d9fdda9eb5710f8a9c3f28a6ce;hb=2238e69eea50d2274553926f3f294822c1972ff0;hp=ad5b812f04038b0da1768b805bbfb45d8aa0e902;hpb=b65b121c093a4966907dadb14acbb9fa517d59bf;p=tpg%2Facess2.git diff --git a/Usermode/Applications/wget_src/main.c b/Usermode/Applications/wget_src/main.c index ad5b812f..d0680534 100644 --- a/Usermode/Applications/wget_src/main.c +++ b/Usermode/Applications/wget_src/main.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include // struct sockaddr_in +#include // _SysDebug enum eProcols { @@ -21,7 +24,10 @@ enum eProcols const char **gasURLs; int giNumURLs; -int _ParseHeaderLine(char *Line, int State, size_t *Size); + int main(int argc, char *argv[]); +void streamToFile(int Socket, const char *OutputFile, int bAppend, size_t bytes_wanted, char *inbuf, size_t ofs, size_t len); + int _ParseHeaderLine(char *Line, int State, size_t *Size); +void writef(int fd, const char *format, ...); int main(int argc, char *argv[]) { @@ -47,7 +53,7 @@ int main(int argc, char *argv[]) // Do the download for( int i = 0; i < giNumURLs; i ++ ) { - char *outfile; + char *outfile = NULL; tURI *uri = URI_Parse(gasURLs[i]); struct addrinfo *addrinfo; @@ -58,12 +64,15 @@ int main(int argc, char *argv[]) printf("Proto: %s, Host: %s, Path: %s\n", uri->Proto, uri->Host, uri->Path); - if( uri->Path[0] == '\0' ) + if( uri->Path[0] == '\0' || uri->Path[strlen(uri->Path)-1] == '/' ) outfile = "index.html"; - else - outfile = strrchr(uri->Path, '/') + 1; - if( !outfile ) - outfile = uri->Path; + else { + outfile = strrchr(uri->Path, '/'); + if( !outfile ) + outfile = uri->Path; + else + outfile += 1; + } if( strcmp(uri->Proto, "http") == 0 ) { proto = PROTO_HTTP; @@ -78,7 +87,13 @@ int main(int argc, char *argv[]) continue ; } - rv = getaddrinfo(uri->Host, NULL, NULL, &addrinfo); + if( proto != PROTO_HTTP ) { + fprintf(stderr, "TODO: Support protocols other than HTTP\n"); + free(uri); + continue ; + } + + rv = getaddrinfo(uri->Host, "http", NULL, &addrinfo); if( rv != 0 ) { fprintf(stderr, "Unable to resolve %s: %s\n", uri->Host, gai_strerror(rv)); continue ; @@ -88,9 +103,27 @@ int main(int argc, char *argv[]) { int bSkipLine = 0; // TODO: Convert to POSIX/BSD - int sock = Net_OpenSocket(addr->ai_family, addr->ai_addr, "tcpc"); - if( sock == -1 ) continue ; + // NOTE: using addr->ai_addr will break for IPv6, as there is more info before the address + + void *addr_data; + switch(addr->ai_family) + { + case AF_INET: addr_data = &((struct sockaddr_in*)addr->ai_addr)->sin_addr; break; + case AF_INET6: addr_data = &((struct sockaddr_in6*)addr->ai_addr)->sin6_addr; break; + default: addr_data = NULL; break; + } + if( !addr_data ) + continue ; + printf("Attempting [%s]:80\n", Net_PrintAddress(addr->ai_family, addr_data)); + + int sock = Net_OpenSocket_TCPC(addr->ai_family, addr_data, 80); + if( sock == -1 ) { + continue ; + } + + _SysDebug("Connected as %i", sock); + writef(sock, "GET /%s HTTP/1.1\r\n", uri->Path); writef(sock, "Host: %s\r\n", uri->Host); // writef(sock, "Accept-Encodings: */*\r\n"); @@ -98,68 +131,101 @@ int main(int argc, char *argv[]) writef(sock, "\r\n"); // Parse headers - char inbuf[BUFSIZ+1]; - size_t offset = 0; + char inbuf[16*1024]; + size_t offset = 0, len = 0; int state = 0; - size_t bytes_seen = 0; size_t bytes_wanted = -1; // invalid + + inbuf[0] = '\0'; while( state == 0 || state == 1 ) { - if( offset == sizeof(inbuf) ) { + if( offset == BUFSIZ ) { bSkipLine = 1; offset = 0; } - // TODO: Handle -1 return - offset += read(sock, inbuf + offset, sizeof(inbuf) - offset); - inbuf[offset] = 0; - + inbuf[len] = '\0'; + char *eol = strchr(inbuf, '\n'); // No end of line char? read some more - if( eol == NULL ) continue ; - // Update write offset - offset = eol + 1 - inbuf; - + if( eol == NULL ) { + // TODO: Handle -1 return + len += read(sock, inbuf + offset, BUFSIZ - 1 - offset); + continue ; + } + + // abuse offset as the end of the string + offset = (eol - inbuf) + 1; + // Clear EOL bytes *eol = '\0'; // Nuke the \r if( eol - 1 >= inbuf ) eol[-1] = '\0'; - if( !bSkipLine ) state = _ParseHeaderLine(inbuf, state, &bytes_wanted); - - memmove( inbuf, inbuf + offset, sizeof(inbuf) - offset ); - offset = 0; + + // Move unused data down in memory + len -= offset; + memmove( inbuf, inbuf + offset, BUFSIZ - offset ); + offset = len; } if( state == 2 ) { - int outfd = open(outfile, O_WR|O_CREAT, 0666); - if( outfd != -1 ) - { - while( bytes_seen < bytes_wanted ) - { - // Abuses offset as read byte count - offset = read(sock, inbuf, sizeof(inbuf)); - write(outfd, inbuf, offset); - bytes_seen += offset; - } - close(outfd); - } + _SysDebug("RXing %i bytes to '%s'", bytes_wanted, outfile); + streamToFile(sock, outfile, 0, bytes_wanted, inbuf, len, sizeof(inbuf)); } + _SysDebug("Closing socket"); close(sock); break ; } free(uri); } + + return 0; +} + +void streamToFile(int Socket, const char *OutputFile, int bAppend, size_t bytes_wanted, char *inbuf, size_t len, size_t buflen) +{ + int outfd = open(OutputFile, O_WRONLY|O_CREAT, 0666); + if( outfd == -1 ) { + fprintf(stderr, "Unable to open '%s' for writing\n", OutputFile); + return ; + } + + int64_t start_time = _SysTimestamp()-1; + size_t bytes_seen = 0; + // Write the remainder of the buffer + do + { + write(outfd, inbuf, len); + bytes_seen += len; + _SysDebug("%i/%i bytes done", bytes_seen, bytes_wanted); + printf("%7i/%7i KiB (%ikB/s) \r", + bytes_seen/1024, bytes_wanted/1024, + bytes_seen/(_SysTimestamp() - start_time) + ); + fflush(stdout); + + if( bytes_seen < bytes_wanted ) + len = read(Socket, inbuf, buflen); + } while( bytes_seen < bytes_wanted && len > 0 ); + int64_t stop_time = _SysTimestamp(); + close(outfd); + printf("%i KiB done in %is (%i kB/s)\n", + bytes_seen/1024, + (int)(stop_time - start_time)/1000, + bytes_seen/(stop_time - start_time) + ); } int _ParseHeaderLine(char *Line, int State, size_t *Size) { + _SysDebug("Header - %s", Line); // First line (Status and version) if( State == 0 ) { @@ -182,18 +248,37 @@ int _ParseHeaderLine(char *Line, int State, size_t *Size) // Body lines else { + char *value; char *colon = strchr(Line, ':'); if(colon == NULL) return 1; *colon = '\0'; + value = colon + 2; if( strcmp(Line, "Content-Length") == 0 ) { - *Size = atoi(colon + 1); + *Size = atoi(value); } else { - printf("Ignorning header '%s' = '%s'\n", Line, colon+1); + printf("Ignorning header '%s' = '%s'\n", Line, value); } return 1; } } +void writef(int fd, const char *format, ...) +{ + va_list args; + size_t len; + + va_start(args, format); + len = vsnprintf(NULL, 0, format, args); + va_end(args); + + char data[len + 1]; + va_start(args, format); + vsnprintf(data, len+1, format, args); + va_end(args); + + write(fd, data, len); +} +