static int _http_download_file(const char * hostname, const char * remotename, int * size, const char * proxyprotocol, const char * proxyname, const char * proxyport, int recursion) { char * buf; char headers[4096]; char * nextChar = headers; int statusCode; struct in_addr serverAddress; struct pollfd polls; int sock; int rc; union { struct sockaddr_in in; struct sockaddr sa; } destPort; const char * header_content_length = "Content-Length: "; const char * header_location = "Location: http://"; const char * http_server_name; int http_server_port; if (proxyprotocol) { http_server_name = proxyname; http_server_port = atoi(proxyport); } else { http_server_name = hostname; http_server_port = 80; } log_message("HTTP: connecting to server %s:%i (%s)", http_server_name, http_server_port, proxyprotocol ? "proxy" : "no proxy"); if ((rc = get_host_address(http_server_name, &serverAddress))) return rc; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sock < 0) { return FTPERR_FAILED_CONNECT; } destPort.in.sin_family = AF_INET; destPort.in.sin_port = htons(http_server_port); destPort.in.sin_addr = serverAddress; if (connect(sock, &destPort.sa, sizeof(destPort.in))) { close(sock); return FTPERR_FAILED_CONNECT; } if (proxyprotocol) asprintf(&buf, "GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname); else asprintf(&buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", remotename, hostname); write(sock, buf, strlen(buf)); /* This is fun; read the response a character at a time until we: 1) Get our first \r\n; which lets us check the return code 2) Get a \r\n\r\n, which means we're done */ *nextChar = '\0'; statusCode = 0; while (!strstr(headers, "\r\n\r\n")) { polls.fd = sock; polls.events = POLLIN; rc = poll(&polls, 1, TIMEOUT_SECS*1000); if (rc == 0) { close(sock); return FTPERR_SERVER_TIMEOUT; } else if (rc < 0) { close(sock); return FTPERR_SERVER_IO_ERROR; } if (read(sock, nextChar, 1) != 1) { close(sock); return FTPERR_SERVER_IO_ERROR; } nextChar++; *nextChar = '\0'; if (nextChar - headers == sizeof(headers)) { close(sock); return FTPERR_SERVER_IO_ERROR; } if (!statusCode && strstr(headers, "\r\n")) { char * start, * end; start = headers; while (!isspace(*start) && *start) start++; if (!*start) { close(sock); return FTPERR_SERVER_IO_ERROR; } start++; end = start; while (!isspace(*end) && *end) end++; if (!*end) { close(sock); return FTPERR_SERVER_IO_ERROR; } *end = '\0'; log_message("HTTP: server response '%s'", start); if (streq(start, "404")) { close(sock); return FTPERR_FILE_NOT_FOUND; } else if (streq(start, "302")) { log_message("HTTP: found, but document has moved"); statusCode = 302; } else if (streq(start, "200")) { statusCode = 200; } else { close(sock); return FTPERR_BAD_SERVER_RESPONSE; } *end = ' '; } } if (statusCode == 302) { if (recursion >= HTTP_MAX_RECURSION) { log_message("HTTP: too many levels of recursion, aborting"); close(sock); return FTPERR_UNKNOWN; } if ((buf = strstr(headers, header_location))) { char * found_host; char *found_file; found_host = buf + strlen(header_location); if ((found_file = index(found_host, '/'))) { if ((buf = index(found_file, '\r'))) { buf[0] = '\0'; remotename = strdup(found_file); found_file[0] = '\0'; hostname = strdup(found_host); log_message("HTTP: redirected to new host \"%s\" and file \"%s\"", hostname, remotename); } } } /* * don't fail if new URL can't be parsed, * asking the same URL may work if the DNS server are doing round-robin */ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1); } if ((buf = strstr(headers, header_content_length))) *size = charstar_to_int(buf + strlen(header_content_length)); else *size = 0; return sock; }
SocketHostAddress get_remote_host_address(int32 fd) { SocketInetAddress inetaddr = get_remote_inet_address(fd); return get_host_address(inetaddr); }
int ftp_open_connection(const char * host, const char * name, const char * password, const char * proxy) { int sock; struct in_addr serverAddress; union { struct sockaddr_in in; struct sockaddr sa; } destPort; int rc; int port = 21; std::string proxyname; if (!strcmp(name, "")) { name = "anonymous"; password = "******"; } if (strcmp(proxy, "")) { proxyname.append(name).append("@").append(host); name = proxyname.c_str(); host = proxy; } if ((rc = get_host_address(host, &serverAddress))) return rc; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sock < 0) { return FTPERR_FAILED_CONNECT; } destPort.in.sin_family = AF_INET; destPort.in.sin_port = htons(port); destPort.in.sin_addr = serverAddress; if (connect(sock, &destPort.sa, sizeof(destPort.in))) { close(sock); return FTPERR_FAILED_CONNECT; } /* ftpCheckResponse() assumes the socket is nonblocking */ if (fcntl(sock, F_SETFL, O_NONBLOCK)) { close(sock); return FTPERR_FAILED_CONNECT; } if ((rc = ftp_check_response(sock, NULL))) { return rc; } if ((rc = ftp_command(sock, "USER", name))) { close(sock); return rc; } if ((rc = ftp_command(sock, "PASS", password))) { close(sock); return rc; } if ((rc = ftp_command(sock, "TYPE", "I"))) { close(sock); return rc; } return sock; }
SocketHostAddress get_host_address(const SocketInetAddress& addr) { return get_host_address(addr.GetRawSockAddr()); }