int main(int argc, char ** argv ) { int i,ret; int fd,sockfd; tftp_t req = {0}; //用于发送读写请求 tftp_t ack = {0}; int reqlen = 0; struct sockaddr_in server = {0}; //服务器端地址 struct sockaddr_in sender = {0}; int addrlen = sizeof(sender); if( argc < 4 ) //参数不够 { fprintf(stderr,"usage: tftp <server IP> <get|put> <file name>\n"); return -1; } //设置服务器地址 server.sin_family = AF_INET; server.sin_port = htons(SERVER_PORT); server.sin_addr.s_addr = inet_addr(argv[1]); if( INADDR_NONE == server.sin_addr.s_addr) { fprintf(stderr,"IP addr invalid"); return -1; } //创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); if( sockfd < 0 ) { perror("socket"); return -1; } if( 0 == strcmp(argv[2], "get") ) //下载文件,覆盖现有文件 { fd = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644); if( fd < 0 ) { perror("open"); goto ERROR_OUT; } reqlen = fill_request( &req, RRQ, argv[3], "octet" ); ret = send_request(sockfd, &server, &req, reqlen); //发送请求 if( ret < 0 ) goto ERROR_OUT; ret = recv_file(sockfd, fd, &server, argv[2]); //接收文件 if( 0 != ret ) goto ERROR_OUT; } else if( 0 == strcmp(argv[2], "put") ) //上传文件 { fd = open(argv[3], O_RDONLY ); if( fd < 0 ) { perror("open"); goto ERROR_OUT; } reqlen=fill_request( &req,WRQ,argv[3],"octet"); for(i=1;i<=3; i++ ) { ret = send_request(sockfd, &server, &req, reqlen); //发送请求 if( ret < 0 ) goto ERROR_OUT; addrlen = sizeof(sender); recvfrom(sockfd, &ack, sizeof(ack),0,(SAP)&sender,&addrlen); if( sender.sin_addr.s_addr == server.sin_addr.s_addr ) { if( ntohs(ack.opcode) == ACK && 0 == ntohs(ack.be.block) ) break; //收到0号确认,服务器启用新端口,新地址放在sender if( ntohs(ack.opcode) == ERROR ) { fprintf(stderr,"ERROR code %d: %s\n", ntohs(ack.be.error), ack.data); goto ERROR_OUT; } } if( 3 == i ) goto ERROR_OUT; } ret = send_file(sockfd, fd, &sender, argv[2]); if( 0 != ret ) goto ERROR_OUT; } else { fprintf(stderr,"usage: client <server IP> <get|put> <filename>\n"); return -1; } close(fd); close(sockfd); return 0; ERROR_OUT: if( sockfd > 0 ) close(sockfd); if ( fd > 0 ) close(fd); return -1; } //end of main()
int win32_net_http_open(char* url, struct httpdata *hd) { mpg123_string purl, host, port, path; mpg123_string request, response, request_url; mpg123_string httpauth1; ws.local_socket = SOCKET_ERROR; int oom = 0; int relocate, numrelocs = 0; int got_location = FALSE; /* workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls this site's apache gives me a relocation to the same place when I give the port in Host request field for the record: Apache/2.0.51 (Fedora) */ int try_without_port = 0; mpg123_init_string(&purl); mpg123_init_string(&host); mpg123_init_string(&port); mpg123_init_string(&path); mpg123_init_string(&request); mpg123_init_string(&response); mpg123_init_string(&request_url); mpg123_init_string(&httpauth1); /* Get initial info for proxy server. Once. */ if(hd->proxystate == PROXY_UNKNOWN && !proxy_init(hd)) goto exit; if(!translate_url(url, &purl)){ oom=1; goto exit; } /* Don't confuse the different auth strings... */ if(!split_url(&purl, &httpauth1, NULL, NULL, NULL) ){ oom=1; goto exit; } /* "GET http://" 11 * " HTTP/1.0\r\nUser-Agent: <PACKAGE_NAME>/<PACKAGE_VERSION>\r\n" * 26 + PACKAGE_NAME + PACKAGE_VERSION * accept header + accept_length() * "Authorization: Basic \r\n" 23 * "\r\n" 2 * ... plus the other predefined header lines */ /* Just use this estimate as first guess to reduce malloc calls in string library. */ { size_t length_estimate = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION) + accept_length() + strlen(CONN_HEAD) + strlen(icy_yes) + purl.fill; if( !mpg123_grow_string(&request, length_estimate) || !mpg123_grow_string(&response,4096) ) { oom=1; goto exit; } } do { /* Storing the request url, with http:// prepended if needed. */ /* used to be url here... seemed wrong to me (when loop advanced...) */ if(strncasecmp(purl.p, "http://", 7) != 0) mpg123_set_string(&request_url, "http://"); else mpg123_set_string(&request_url, ""); mpg123_add_string(&request_url, purl.p); if (hd->proxystate >= PROXY_HOST) { /* We will connect to proxy, full URL goes into the request. */ if( !mpg123_copy_string(&hd->proxyhost, &host) || !mpg123_copy_string(&hd->proxyport, &port) || !mpg123_set_string(&request, "GET ") || !mpg123_add_string(&request, request_url.p) ) { oom=1; goto exit; } } else { /* We will connect to the host from the URL and only the path goes into the request. */ if(!split_url(&purl, NULL, &host, &port, &path)){ oom=1; goto exit; } if( !mpg123_set_string(&request, "GET ") || !mpg123_add_string(&request, path.p) ) { oom=1; goto exit; } } if(!fill_request(&request, &host, &port, &httpauth1, &try_without_port)){ oom=1; goto exit; } httpauth1.fill = 0; /* We use the auth data from the URL only once. */ debug2("attempting to open_connection to %s:%s", host.p, port.p); win32_net_open_connection(&host, &port); if(ws.local_socket == SOCKET_ERROR) { error1("Unable to establish connection to %s", host.fill ? host.p : ""); goto exit; } debug("win32_net_open_connection succeed"); #define http_failure win32_net_close(ws.local_socket); ws.local_socket=SOCKET_ERROR; goto exit; if(param.verbose > 2) fprintf(stderr, "HTTP request:\n%s\n",request.p); if(!win32_net_writestring(ws.local_socket, &request)){ http_failure; } debug("Skipping fdopen for WSA sockets"); relocate = FALSE; /* Arbitrary length limit here... */ #define safe_readstring \ win32_net_readstring(&response, SIZE_MAX/16, NULL); \ if(response.fill > SIZE_MAX/16) /* > because of appended zero. */ \ { \ error("HTTP response line exceeds max. length"); \ http_failure; \ } \ else if(response.fill == 0) \ { \ error("readstring failed"); \ http_failure; \ } \ if(param.verbose > 2) fprintf(stderr, "HTTP in: %s", response.p); safe_readstring; { char *sptr; if((sptr = strchr(response.p, ' '))) { if(response.fill > sptr-response.p+2) switch (sptr[1]) { case '3': relocate = TRUE; case '2': break; default: fprintf (stderr, "HTTP request failed: %s", sptr+1); /* '\n' is included */ http_failure; } else{ error("Too short response,"); http_failure; } } } /* If we are relocated, we need to look out for a Location header. */ got_location = FALSE; do { safe_readstring; /* Think about that: Should we really error out when we get nothing? Could be that the server forgot the trailing empty line... */ if (!strncasecmp(response.p, "Location: ", 10)) { /* It is a redirection! */ if(!win32_net_resolve_redirect(&response, &request_url, &purl)){ oom=1, http_failure; } if(!strcmp(purl.p, request_url.p)) { warning("relocated to very same place! trying request again without host port"); try_without_port = 1; } got_location = TRUE; } else { /* We got a header line (or the closing empty line). */ char *tmp; debug1("searching for header values... %s", response.p); /* Not sure if I want to bail out on error here. */ /* Also: What text encoding are these strings in? Doesn't need to be plain ASCII... */ get_header_string(&response, "content-type", &hd->content_type); get_header_string(&response, "icy-name", &hd->icy_name); get_header_string(&response, "icy-url", &hd->icy_url); /* watch out for icy-metaint */ if((tmp = get_header_val("icy-metaint", &response))) { hd->icy_interval = (off_t) atol(tmp); /* atoll ? */ debug1("got icy-metaint %li", (long int)hd->icy_interval); } } } while(response.p[0] != '\r' && response.p[0] != '\n'); } while(relocate && got_location && purl.fill && numrelocs++ < HTTP_MAX_RELOCATIONS); if(relocate) { if(!got_location) error("Server meant to redirect but failed to provide a location!"); else error1("Too many HTTP relocations (%i).", numrelocs); http_failure; } exit: /* The end as well as the exception handling point... */ if(oom) error("Apparently, I ran out of memory or had some bad input data..."); mpg123_free_string(&purl); mpg123_free_string(&host); mpg123_free_string(&port); mpg123_free_string(&path); mpg123_free_string(&request); mpg123_free_string(&response); mpg123_free_string(&request_url); mpg123_free_string(&httpauth1); if (ws.local_socket == SOCKET_ERROR || oom) return -1; else return 1; }