/**************************************************************************** * Test if connection to the address is available (PING) ***************************************************************************/ bool CheckConnection(const char *url, float timeout) { //Check if the url starts with "http://", if not it is not considered a valid url if (strncmp(url, "http://", strlen("http://")) != 0) return false; //Locate the path part of the url by searching for '/' past "http://" char *path = strchr(url + strlen("http://"), '/'); //At the very least the url has to end with '/', ending with just a domain is invalid if (path == NULL) return false; //Extract the domain part out of the url int domainlength = path - url - strlen("http://"); if (domainlength == 0) return false; char domain[domainlength + 1]; strlcpy(domain, url + strlen("http://"), domainlength + 1); //Parsing of the URL is done, start making an actual connection u32 ipaddress = getipbynamecached(domain); if (ipaddress == 0) return false; //Initialize socket s32 connection = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (connection < 0) return connection; s32 flags = net_fcntl(connection, F_GETFL, 0); if (flags >= 0) flags = net_fcntl(connection, F_SETFL, flags | 4); struct sockaddr_in connect_addr; memset(&connect_addr, 0, sizeof(connect_addr)); connect_addr.sin_family = AF_INET; connect_addr.sin_port = 80; connect_addr.sin_addr.s_addr = getipbynamecached(domain); Timer netTime; int res = -1; while(res < 0 && res != -127 && netTime.elapsed() < timeout) { res = net_connect(connection, (struct sockaddr*) &connect_addr, sizeof(connect_addr)); usleep(1000); } net_close(connection); return !(res < 0 && res != -127); }
s32 GetConnection(char * domain) { u32 ipaddress = getipbynamecached(domain); if(ipaddress == 0) { return -1; } s32 connection = server_connect(ipaddress, 80); return connection; }
/** * Downloads the contents of a URL to memory * This method is not threadsafe (because networking is not threadsafe on the Wii) */ u8 *downloadfile (const char *url, u32 *size, http_Callback cb) { *size = 0; u8 *buff = NULL; memset (&http, 0, sizeof(s_http)); http.cb = cb; //Check if the url starts with "http://", if not it is not considered a valid url if (strncmp(url, "http://", strlen("http://")) != 0) { //printf("URL '%s' doesn't start with 'http://'\n", url); return NULL; } //Locate the path part of the url by searching for '/' past "http://" char *path = strchr(url + strlen("http://"), '/'); //At the very least the url has to end with '/', ending with just a domain is invalid if (path == NULL) { //printf("URL '%s' has no PATH part\n", url); return NULL; } //Extract the domain part out of the url int domainlength = path - url - strlen("http://"); if (domainlength == 0) { //printf("No domain part in URL '%s'\n", url); return NULL; } char domain[domainlength + 1]; strncpy(domain, url + strlen("http://"), domainlength); domain[domainlength] = '\0'; //Parsing of the URL is done, start making an actual connection u32 ipaddress = getipbynamecached(domain); if (ipaddress == 0) { //printf("\ndomain %s could not be resolved", domain); return NULL; } Debug ("downloadfile:connecting"); s32 connection = server_connect(ipaddress, 80); if(connection < 0) { //printf("Error establishing connection"); return NULL; } Debug ("downloadfile:success"); //Form a nice request header to send to the webserver char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: postLoader2\r\n\r\n"; char header[strlen(headerformat) + strlen(path) + strlen(domain)*2 + 1]; sprintf(header, headerformat, path, domain, domain); //Do the request and get the response send_message(connection, header); buff = read_message(connection, size); net_close(connection); //Search for the 4-character sequence \r\n\r\n in the response which signals the start of the http payload (file) unsigned char *filestart = NULL; u32 filesize = 0; unsigned int i; for(i = 3; i < *size; i++) { if(buff[i] == '\n' && buff[i-1] == '\r' && buff[i-2] == '\n' && buff[i-3] == '\r') { filestart = buff + i + 1; filesize = *size - i - 1; break; } } if(filestart == NULL) { //printf("HTTP Response was without a file\n"); free(buff); return NULL; } //Copy the file part of the response into a new memoryblock to return u8 *file = malloc(filesize); if(file == NULL) { //printf("No more memory to copy file from HTTP response\n"); free(buff); return NULL; } memcpy(file, filestart, filesize); //Dispose of the original response free(buff); *size = filesize; return file; }
/* Downloads the contents of a URL to memory * This method is not threadsafe (because networking is not threadsafe on the Wii) */ struct block downloadfile(u8 *buffer, u32 bufferSize, const char *url, bool (*f)(void *, int, int), void *ud) { //Check if the url starts with "http://", if not it is not considered a valid url if(strncmp(url, "http://", strlen("http://")) != 0) return emptyblock; //Locate the path part of the url by searching for '/' past "http://" char *path = strchr(url + strlen("http://"), '/'); if(path == NULL) return emptyblock; //Extract the domain part out of the url int domainlength = path - url - strlen("http://"); if(domainlength == 0) return emptyblock; char domain[domainlength + 1]; strncpy(domain, url + strlen("http://"), domainlength); domain[domainlength] = '\0'; //Parsing of the URL is done, start making an actual connection u32 ipaddress = getipbynamecached(domain); if(ipaddress == 0) return emptyblock; s32 connection = server_connect(ipaddress, 80); if(connection < 0) return emptyblock; //Form a nice request header to send to the webserver char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: Wiiflow Advanced 3.0\r\n\r\n";; char header[strlen(headerformat) + strlen(domain) + strlen(path)]; sprintf(header, headerformat, path, domain); //Do the request and get the response send_message(connection, header); if (bufferSize == 0) return emptyblock; struct block buf; buf.data = buffer; buf.size = bufferSize; struct block response = read_message(connection, buf, f, ud); net_close(connection); //Search for the 4-character sequence \r\n\r\n in the response which signals the start of the http payload (file) unsigned char *filestart = NULL; u32 filesize = 0; u32 i; for(i = 3; i < response.size; i++) { if(response.data[i] == '\n' && response.data[i-1] == '\r' && response.data[i-2] == '\n' && response.data[i-3] == '\r') { filestart = response.data + i + 1; filesize = response.size - i - 1; break; } } if(response.size == 0 || response.data == NULL) return emptyblock; // Check for the headers char httpCode[3]; memcpy(httpCode, &response.data[9], 3); int retCode = atoi(httpCode); switch(retCode) { case 301: case 302: case 307: // Moved /* { char redirectedTo[255]; if(findHeader((char *) response.data, (filestart - response.data), "Location", redirectedTo, 255) == 0) { return downloadfile(buffer, bufferSize, (char *) redirectedTo, f, ud); } return emptyblock; break; } */ case 404: // Error, file not found! return emptyblock; } if(filestart == NULL) return emptyblock; //Copy the file part of the response into a new memoryblock to return struct block file; file.data = filestart; file.size = filesize; return file; }
struct block downloadfile_fname(const char *url, const char *fname) { //Check if the url starts with "http://", if not it is not considered a valid url if(strncmp(url, "http://", strlen("http://")) != 0) { printf(gt("URL '%s' doesn't start with 'http://'"), url); printf("\n"); return emptyblock; } //Locate the path part of the url by searching for '/' past "http://" char *path = strchr(url + strlen("http://"), '/'); //At the very least the url has to end with '/', ending with just a domain is invalid if(path == NULL) { printf(gt("URL '%s' has no PATH part"), url); printf("\n"); return emptyblock; } //Extract the domain part out of the url int domainlength = path - url - strlen("http://"); if(domainlength == 0) { printf(gt("No domain part in URL '%s'"), url); printf("\n"); return emptyblock; } char domain[domainlength + 1]; strncpy(domain, url + strlen("http://"), domainlength); domain[domainlength] = '\0'; //Parsing of the URL is done, start making an actual connection u32 ipaddress = getipbynamecached(domain); if(ipaddress == 0) { printf("\n"); printf(gt("domain %s could not be resolved"), domain); return emptyblock; } s32 connection = server_connect(ipaddress, 80); if(connection < 0) { printf(gt("Error establishing connection")); return emptyblock; } //Form a nice request header to send to the webserver extern char CFG_VERSION[]; char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\nReferer: %s\r\nUser-Agent: CFG-Loader %s\r\n\r\n"; char header[strlen(headerformat) + strlen(domain) + strlen(path) + strlen(domain) + strlen(CFG_VERSION) + 16]; sprintf(header, headerformat, path, domain, domain, CFG_VERSION); //Do the request and get the response send_message(connection, header); struct block response = read_message(connection, fname); net_close(connection); // Check response status. Should be something like HTTP/1.1 200 OK if (response.size > 10 && strncmp((char*)response.data, "HTTP/", 5)==0) { char htstat[100]; int i; for (i=0; i<100 && i<response.size; i++) { if (response.data[i] == '\n' || response.data[i] == '\r') { strncpy(htstat, (char*)response.data, i); htstat[i] = 0; //printf("HTTP response status: %s\n", htstat); char *codep; codep = strchr(htstat, ' '); if (codep) { int code; if (sscanf(codep+1, "%d", &code) == 1) { //printf("HTTP response code: %d\n", code); //if (code != 200) { if (code >= 400) { printf("%s: %s", gt("ERROR"), htstat); if (!http_progress) printf("\n"); SAFE_FREE(response.data); return emptyblock; } } } break; } } } if (fname != NULL) { return response; } // Search for the 4-character sequence \r\n\r\n in the response // which signals the start of the http payload (file) unsigned char *filestart = NULL; u32 filesize = 0; int i; for(i = 0; i < response.size-3; i++) { if (memcmp(response.data+i, "\r\n\r\n", 4) == 0) { filestart = response.data + i + 4; filesize = response.size - i - 4; break; } } if(filestart == NULL) { printf(gt("HTTP Response was without a file")); printf("\n"); SAFE_FREE(response.data); return emptyblock; } // move file part of the response into the start of the block memmove(response.data, filestart, filesize); // free extra memory response.data = mem_realloc(response.data, filesize); response.size = filesize; return response; }
/** * Downloads the contents of a URL to memory * This method is not threadsafe (because networking is not threadsafe on the Wii) */ struct block downloadfile(const char *url) { int sslcontext = -1; //Check if the url starts with "http://", if not it is not considered a valid url if (strncmp(url, "http://", strlen("http://")) == 0) http_port = 80; else if(strncmp(url, "https://", strlen("https://")) == 0) { http_port = 443; gprintf("Initializing ssl...\n"); if(ssl_init() < 0) return emptyblock; } else return emptyblock; //Locate the path part of the url by searching for '/' past "http://" char *path = 0; if(http_port == 443) path = strchr(url + strlen("https://"), '/'); else path = strchr(url + strlen("http://"), '/'); //At the very least the url has to end with '/', ending with just a domain is invalid if (path == NULL) { //printf("URL '%s' has no PATH part\n", url); return emptyblock; } //Extract the domain part out of the url int domainlength = path - url - strlen("http://") - (http_port == 443 ? 1 : 0); if (domainlength == 0) { //printf("No domain part in URL '%s'\n", url); return emptyblock; } char domain[domainlength + 1]; strlcpy(domain, url + strlen("http://") + (http_port == 443 ? 1 : 0), domainlength + 1); //Parsing of the URL is done, start making an actual connection u32 ipaddress = getipbynamecached(domain); if (ipaddress == 0) { //printf("\ndomain %s could not be resolved", domain); return emptyblock; } s32 connection = tcp_connect(ipaddress, http_port); if (connection < 0) { //printf("Error establishing connection"); return emptyblock; } if(http_port == 443) { //patched out anyways so just to set something sslcontext = ssl_new((u8*)domain,0); if(sslcontext < 0) { //gprintf("ssl_new\n"); result = HTTPR_ERR_CONNECT; net_close (connection); return emptyblock; } //patched out anyways so just to set something ssl_setbuiltinclientcert(sslcontext,0); if(ssl_connect(sslcontext,connection) < 0) { //gprintf("ssl_connect\n"); result = HTTPR_ERR_CONNECT; ssl_shutdown(sslcontext); net_close (connection); return emptyblock; } int ret = ssl_handshake(sslcontext); if(ret < 0) { //gprintf("ssl_handshake %i\n", ret); result = HTTPR_ERR_STATUS; ssl_shutdown(sslcontext); net_close (connection); return emptyblock; } } // Remove Referer from the request header for incompatible websites (ex. Cloudflare proxy) char referer[domainlength + 12]; snprintf(referer, sizeof(referer), "Referer: %s\r\n", domain); if(strstr(url, "geckocodes")) { strcpy(referer, ""); } //Form a nice request header to send to the webserver char* headerformat = "GET %s HTTP/1.0\r\nHost: %s\r\n%sUser-Agent: USBLoaderGX r%s\r\n\r\n"; char header[strlen(headerformat) + strlen(path) + strlen(domain) + strlen(referer) + 100]; sprintf(header, headerformat, path, domain, referer, GetRev()); //gprintf("\nHTTP Request:\n"); //gprintf("%s\n",header); //Do the request and get the response tcp_write(http_port == 443 ? sslcontext : connection, header); read_header( http_port == 443 ? sslcontext : connection); if (http_status >= 400) // Not found { //gprintf("HTTP ERROR: %d\n", http_status); return emptyblock; } if(!content_length) content_length = 0; // create data buffer to return struct block response; response.data = malloc(content_length); response.size = content_length; if (response.data == NULL) { return emptyblock; } if (http_status == 200) { if(displayProgressWindow) { ProgressCancelEnable(true); StartProgress(tr("Downloading file..."), tr("Please wait"), 0, false, false); } int ret = tcp_readData(http_port == 443 ? sslcontext : connection, &response.data, content_length); if(!ret) { free(response.data); result = HTTPR_ERR_RECEIVE; if(http_port == 443) ssl_shutdown(sslcontext); net_close (connection); return emptyblock; } } else if (http_status == 302) // 302 FOUND (redirected link) { // close current connection if(http_port == 443) ssl_shutdown(sslcontext); net_close (connection); // prevent infinite loops retryloop++; if(retryloop > 3) { retryloop = 0; return emptyblock; } struct block redirected = downloadfile(content_location); if(redirected.size == 0) return emptyblock; // copy the newURL data into the original data u8 * tmp = realloc(response.data, redirected.size); if (tmp == NULL) { gprintf("Could not allocate enough memory for new URL. Download canceled.\n"); free(response.data); response.size = 0; free(redirected.data); result = HTTPR_ERR_RECEIVE; if(http_port == 443) ssl_shutdown(sslcontext); net_close (connection); return emptyblock; } response.data = tmp; memcpy(response.data, redirected.data, redirected.size); free(redirected.data); response.size = redirected.size; } retryloop = 0; // reset progress window if used if(displayProgressWindow) { ProgressStop(); ProgressCancelEnable(false); displayProgressWindow = false; } return response; }