/** * Performs the same function as getipbyname(), * except that it will prevent extremely expensive net_gethostbyname() calls by caching the result */ u32 getipbynamecached(char *domain) { //Search if this domainname is already cached struct dnsentry *node = firstdnsentry; struct dnsentry *previousnode = NULL; while(node != NULL) { if(strcmp(node->domain, domain) == 0) { //DNS node found in the cache, move it to the front of the list if(previousnode != NULL) previousnode->nextnode = node->nextnode; if(node != firstdnsentry) node->nextnode = firstdnsentry; firstdnsentry = node; return node->ip; } //Go to the next element in the list previousnode = node; node = node->nextnode; } u32 ip = getipbyname(domain); //No cache of this domain could be found, create a cache node and add it to the front of the cache struct dnsentry *newnode = malloc(sizeof(struct dnsentry)); if(newnode == NULL) return ip; newnode->ip = ip; newnode->domain = malloc(strlen(domain)+1); if(newnode->domain == NULL) { free(newnode); return ip; } strcpy(newnode->domain, domain); newnode->nextnode = firstdnsentry; firstdnsentry = newnode; dnsentrycount++; //If the cache grows too big delete the last (and probably least important) node of the list if(dnsentrycount > MAX_DNS_CACHE_ENTRIES) { struct dnsentry *node = firstdnsentry; struct dnsentry *previousnode = NULL; //Fetch the last two elements of the list while(node->nextnode != NULL) { previousnode = node; node = node->nextnode; } if(node == NULL) { printf("Configuration error, MAX_DNS_ENTRIES reached while the list is empty\n"); exit(1); } else if(previousnode == NULL) { firstdnsentry = NULL; } else { previousnode->nextnode = NULL; } free(node->domain); free(node); dnsentrycount--; } return newnode->ip; }
/** * 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) { //Check if the url starts with "http://", if not it is not considered a valid url if(strncmp(url, "http://", strlen("http://")) != 0) { sprintf(emptyblock.error,TX.URLnoBegin, url); //doen't start with http:// 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) { sprintf(emptyblock.error,TX.URLnoPath, url); //no path part in URL return emptyblock; } //Extract the domain part out of the url int domainlength = path - url - strlen("http://"); if(domainlength == 0) { sprintf(emptyblock.error,TX.URLnoDomain, url); //couldn't find a domain in url 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 = getipbyname(domain); //slower but doesn't leak memory if(ipaddress == 0) { sprintf(emptyblock.error,TX.errorDomain, domain); //couldn't resolve domain return emptyblock; } s32 connection = server_connect(ipaddress, 80); if(connection < 0) { sprintf(emptyblock.error,TX.errEstablishConn); //couldn't establish connection 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: WiiEarthh 1.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); struct block response = read_message(connection); 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; int 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(filestart == NULL) { sprintf(emptyblock.error,TX.HTTPnoFile); return emptyblock; } //Copy the file part of the response into a new memoryblock to return struct block file; file.data = CFMalloc(filesize); file.size = filesize; if(file.data == NULL) { sprintf(emptyblock.error,TX.noMemCopy ); //couldn't copy the file to the block CFFree(response.data); return emptyblock; } memcpy(file.data, filestart, filesize); //Dispose of the original response CFFree(response.data); return file; }