int handle_http_delete(http_req * req, http_rsp * rsp) { char * vpath = NULL; int ret = 0; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif vpath = req->uri; ASSERT(vpath && vpath[0]); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } if(OK != Webdav_CheckPath(vpath)) { return handle_http_error(403, req, rsp); } /* Note that the path can be either a folder, or a file. If it is a folder, it can be either empty, or with files. */ if(TRUE == Webdav_isFolder(vpath)) ret = Webdav_DeleteFolder(vpath); else ret = Webdav_DeleteFile(vpath); if(WEBDAVR_OK == ret) { rsp->code = 204; return http_send_response(rsp); } else { WEBLOG_INFO("<%s> Failed to remove %s.\n", __FUNCTION__, vpath); return handle_http_error(403, req, rsp); } }
DWORD WINAPI http_do_request(void *lPtr) { socket_conn* conn = (socket_conn*)lPtr; if(conn == 0) return 0; printf("[%08x]new connection\n", GetCurrentThreadId()); while(1) { int keepalive = 0; dynamic_object * req = dynamic_create(); if(http_read_request(conn, req) == 0) { dynamic_delete(req); break; } char* path = dynamic_get_string(dynamic_map_find(req, "PATH")); char* method = dynamic_get_string(dynamic_map_find(req, "METHOD")); char* connection = dynamic_get_string(dynamic_map_find(req, HTTP_HEADER_CONNECTION)); if(connection && strcmp(connection, "keep-alive")==0) keepalive = 1; printf("[%08x]%s %s\n", GetCurrentThreadId(), method, path); if(strcmp(path, "/hello") == 0) { char* html = "<html><body>Hello World!</body></html>"; int htmllen = strlen(html); dynamic_object * res = dynamic_create(); dynamic_string_printf(dynamic_map_insert(res, HTTP_HEADER_CONTENT_LENGTH), "%d", htmllen); dynamic_set_string(dynamic_map_insert(res, HTTP_HEADER_CONTENT_TYPE), "text/html"); http_send_response(conn, 200, res); write_socket(conn, html, htmllen, -1); dynamic_delete(res); }else { http_send_file(conn, req); } dynamic_delete(req); if(keepalive == 0) break; } close_socket(conn); printf("[%08x]close connection\n", GetCurrentThreadId()); return 0; }
/* * Handles an HTTP error. */ void http_error(socket_t s, unsigned http_code, const struct http_request_s *request) { const char *content_filename; switch (http_code) { case 404: content_filename = "404.html"; break; case 500: content_filename = "500.html"; break; default: panic("unsupported HTTP code %u", http_code); } if (http_type(request->name) == HTTP_TYPE_HTML) { http_buffer_t content = http_lookup_content(content_filename); if (content != NULL) { if (http_send_response(s, http_code, content, request)) { http_buffer_close(content); return; } http_buffer_close(content); } } // Emergency fall back: static const char http_header[] = "HTTP/1.1 500 Internal Server Error\r\n" "Connection: close\r\n" "\r\n"; size_t http_header_length = sizeof(http_header)-1; if (send(s, http_header, http_header_length, 0) != http_header_length) { warning("unable to send HTTP 500 response of size " SIZE_T_FMT " bytes", http_header_length); } }
int handle_http_error(int errcode, http_req * req, http_rsp * rsp) { char buffer[256] = {0}; http_status * stt = get_http_status(errcode); WEBLOG_API(); ASSERT(stt); sprintf(buffer, "<HTML><BODY><b>%s</b></BODY></HTML>", stt->s_name); rsp->code = errcode; rsp->body = buffer; http_add_rspoption(rsp, "Content-Type", "text/html"); http_add_rspoption(rsp, "Connection", "close"); WEBLOG_INFO("\n<%s> Response >>>>>>>>>>>\n", __FUNCTION__); http_send_response(rsp); WEBLOG_INFO("\n<%s> Response <<<<<<<<<<<\n", __FUNCTION__); return NG; /* Allways return NG here. */ }
static void error(struct http_response *rs, enum pazpar2_error_code code, const char *addinfo) { struct http_channel *c = rs->channel; WRBUF text = wrbuf_alloc(); const char *http_status = "417"; const char *msg = get_msg(code); rs->msg = nmem_strdup(c->nmem, msg); strcpy(rs->code, http_status); wrbuf_printf(text, HTTP_COMMAND_RESPONSE_PREFIX "<error code=\"%d\" msg=\"%s\">", (int) code, msg); if (addinfo) wrbuf_xmlputs(text, addinfo); wrbuf_puts(text, "</error>"); yaz_log(YLOG_WARN, "HTTP %s %s%s%s", http_status, msg, addinfo ? ": " : "" , addinfo ? addinfo : ""); rs->payload = nmem_strdup(c->nmem, wrbuf_cstr(text)); wrbuf_destroy(text); http_send_response(c); }
int handle_http_propfind(http_req * req, http_rsp * rsp) { int ret = OK; HashElement * e = NULL; int depth = -1; HashHandle props = NULL_HANDLE; CacheHandle cache = NULL_HANDLE; char * propxml = NULL; int contentlen = 0; char * vpath = req->uri; struct stat buf; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif if(OK != Webdav_CheckPath(req->uri)) { WEBLOG_ERROR("<%s> PROPFIND is not allowed for non-webdav path [%s].\n", __FUNCTION__, req->uri); handle_http_error(403, req, rsp); ret = NG; goto __error_out; } if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } WEBLOG_INFO("<%s> stat the file \"%s\".\n", __FUNCTION__, vpath); ret = stat(vpath, &buf); /* Check if statistics are valid: */ if(ret != 0) { WEBLOG_ERROR("<%s> fail to stat the file \"%s\".\n", __FUNCTION__, vpath); switch (errno) { case ENOENT: WEBLOG_ERROR("<%s> File %s not found.\n", __FUNCTION__, vpath); handle_http_error(404, req, rsp); ret = NG; goto __error_out; case EINVAL: /* no break */ default: /* Should never be reached. */ WEBLOG_ERROR("<%s> Unexpected error in _stat.\n", __FUNCTION__); handle_http_error(500, req, rsp); ret = NG; goto __error_out; } } props = HashTableCreate(64); ASSERT(props != NULL_HANDLE); /* get depth. */ e = HashLookup(req->headOptions, "Depth"); if(!e) depth = -1; else if(e->value.data.string[0] == '0') depth = 0; else if(e->value.data.string[0] == '1') depth = 1; else depth = -1; if(depth == -1 && TRUE == Webdav_isFolder(vpath)) { WEBLOG_ERROR("<%s> PROPFIND a collection with infinite depth is not allowed.\n", __FUNCTION__); handle_http_error(403, req, rsp); ret = NG; goto __error_out; } #ifdef WEBCFG_MINIMIZE_SERVER #else e = HashLookup(req->headOptions, "Content-Type"); if(e && strstr(e->value.data.string, "xml")) { char * xmlsockbuf = NULL; char strbuf[128] = {0}; char *end, *p, *q; HashValue eeee = HashString("", FALSE); // empty value! WEBLOG_INFO("<%s> Client request props in a xml body.\n", __FUNCTION__); e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" for xml body.\n", __FUNCTION__); handle_http_error(400, req, rsp); ret = NG; goto __error_out; } contentlen = atoi(e->value.data.string); xmlsockbuf = (char *)webmalloc(contentlen+1); memset(xmlsockbuf, 0, contentlen+1); if(req->datalen > 0) // data left in head buffer. { memcpy(xmlsockbuf, req->sockbuf, req->datalen); WEBLOG_VERBOSE("<%s> previous buffered %d/%d bytes consumed.\n", __FUNCTION__, req->datalen, contentlen); } /* if there's more data in socket.... */ if (req->datalen < contentlen) { /* read rest of data from socket. */ p = xmlsockbuf + req->datalen; req->datalen = recv(req->sock, p, contentlen-req->datalen, 0); WEBLOG_VERBOSE("<%s> %d/%d bytes read from socket.\n", __FUNCTION__, req->datalen, contentlen); dumpText(xmlsockbuf, contentlen); } p = strstr(xmlsockbuf, "<prop>") + 6; end = strstr(xmlsockbuf, "</prop>"); if(strstr(xmlsockbuf, "<allprop/>")) { WEBLOG_INFO("<%s> client request all props.\n", __FUNCTION__); } else { ASSERT(p<end); *end = '\0'; /* good for str api. */ /* Possible Value: WinXP: <propname/> Cadaver: <propname xmlns="DAV:"/> */ do { p = strchr(p, '<'); if(!p) break; else p++; q = strstr(p, "/>"); ASSERT(q && (q-p < sizeof(strbuf))); strncpy(strbuf, p, q-p); p = strchr(strbuf, ' '); if(p) *p = '\0'; p = strtrim(strbuf); WEBLOG_INFO("<%s> client request prop: <%s>\n", __FUNCTION__, p); HashAdd(props, p, eeee); p = q + 2; } while(p<end); /* <xxx/>\r\n</prop> */ } } #endif cache = CacheCreate(); Webdav_Props(props, cache, vpath, depth); contentlen = CacheGetData(cache, &propxml); ASSERT(propxml); dumpText(propxml, contentlen); WEBLOG_INFO("<%s> response xml ready. len %d.\n", __FUNCTION__, contentlen); rsp->code = 207; rsp->body = propxml; http_add_rspoption(rsp, "Content-Type", "text/xml"); http_send_response(rsp); __error_out: if (props != NULL_HANDLE) HashTableDestroy(props); if (cache != NULL_HANDLE) CacheDestroy(cache); return ret; }
int handle_http_put(http_req * req, http_rsp * rsp) { HashElement * e = NULL; char * vpath = NULL; int httpbodylen = 0; int readlen = 0; FILE * fp = NULL; int i = 0; unsigned char * buffer = NULL; int buflen = 1024*1024; char strbuf[128] = {0}; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif vpath = req->uri; ASSERT(vpath && vpath[0]); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } e = HashLookup(req->headOptions, "Content-Length"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Content-Length\" in POST/PUT.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } httpbodylen = atoi(e->value.data.string); WEBLOG_INFO("<%s> Content-Length:%d.\n", __FUNCTION__, httpbodylen); if(OK != Webdav_CheckPath(vpath)) return handle_http_error(501, req, rsp); if(WEBDAVR_OK != Webdav_CreateFile(vpath)) return handle_http_error(501, req, rsp); /* read data from socket and save it into target file. */ fp = fopen(vpath, "wb"); if(!fp) return handle_http_error(501, req, rsp); if(req->datalen > 0) // data left in head buffer. { i = fwrite(req->sockbuf, 1, req->datalen, fp); ASSERT(i == req->datalen); WEBLOG_VERBOSE("<%s> write previous buffered %d bytes into %s.\n", __FUNCTION__, req->datalen, vpath); readlen += req->datalen; } /* if there's more data in socket.... req->sockbuf is too small for large files. */ do { buflen /= 2; buffer = (char *)webmalloc(buflen); } while(!buffer); while(readlen < httpbodylen) { req->datalen = recv(req->sock, buffer, buflen, 0); if(req->datalen < 0) { print_socket_error(); break; } else if(req->datalen == 0) { WEBLOG_INFO("<%s> client closed. data progress: %d/%d.\n", __FUNCTION__, readlen, httpbodylen); break; } readlen += req->datalen; WEBLOG_VERBOSE("<%s> progress: %10d/%d, ", __FUNCTION__, readlen, httpbodylen); i = fwrite(buffer, 1, req->datalen, fp); WEBLOG_VERBOSE("R %d <- socket, W %d -> %s.\n", req->datalen, i, vpath); ASSERT(i == req->datalen); } rsp->code = 201; e = HashLookup(req->headOptions, "Host"); if(!e) { /* RFC2616, 14.23. */ WEBLOG_ERROR("<%s> Missing \"Host\" in POST/PUT.\n", __FUNCTION__); sprintf(strbuf, "/webdav%s", vpath); } else { sprintf(strbuf, "http://%s/webdav%s", e->value.data.string, vpath); } http_add_rspoption(rsp, "Location", strbuf); http_send_response(rsp); /****************************** Double Confirm File Size! *******************************/ fseek(fp, 0, SEEK_END); i = ftell(fp); WEBLOG_INFO("<%s> Double Confirm. file-size: %d. content-length: %d.\n", __FUNCTION__, i, httpbodylen); ASSERT(i == httpbodylen); webfree(buffer); fclose(fp); return OK; }
int handle_http_get(http_req * req, http_rsp * rsp) { int ret = OK; HashElement * e = NULL; /* ------------------------------------ */ FILE * fp = NULL; char * timebuf = NULL; /* ------------------------------------ */ size_t total_length = 0; /* total length of the file. */ size_t task_length = 0; /* requested length. */ char strbuf[64] = {0}; size_t from = -1; size_t to = -1; char path[256] = {0}; char * vpath = path; struct stat buf; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif vpath = req->uri; ASSERT(vpath && vpath[0]); ASSERT(rsp->headOptions != NULL_HANDLE); if(0 == strlen(vpath)) { strcat(vpath, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath); } /* Make sure the requesting URI is authorized. */ if(strstr(vpath, "..") || strstr(vpath, "./")) return handle_http_error(403, req, rsp); /* Check if the requesting URI is a directory. */ WEBLOG_INFO("<%s> stat the file \"%s\".\n", __FUNCTION__, vpath); ret = web_stat(vpath, &buf); /* Check if statistics are valid: */ if(ret != 0) { WEBLOG_ERROR("<%s> fail to stat the file \"%s\".\n", __FUNCTION__, vpath); switch (errno) { case ENOENT: WEBLOG_ERROR("<%s> File %s not found.\n", __FUNCTION__, vpath); return handle_http_error(404, req, rsp); case EINVAL: /* no break */ default: /* Should never be reached. */ WEBLOG_ERROR("<%s> Unexpected error in _stat.\n", __FUNCTION__); return handle_http_error(500, req, rsp); } } else { WEBLOG_INFO("<%s> File size : "sizett"\n", __FUNCTION__, buf.st_size ); //WEBLOG_INFO("<%s> Drive : %c:\n", __FUNCTION__, buf.st_dev + 'A' ); timebuf = ctime(&buf.st_mtime); WEBLOG_INFO("<%s> Time modified : %s", __FUNCTION__, timebuf); if(S_IFDIR & buf.st_mode) { #if 1 //#ifdef WEBCFG_SUPPORT_WEBDAV CacheHandle cache = CacheCreate(); if (NULL_HANDLE == cache) return handle_http_error(500, req, rsp); rsp->code = 200; web_lsdir(cache, vpath); http_add_rspoption(rsp, "Content-Type", "text/html; charset=\"utf-8\""); CacheGetData(cache, &rsp->body); http_send_response(rsp); if (cache != NULL_HANDLE) CacheDestroy(cache); return OK; #else WEBLOG_INFO("<%s> client requesting a directory!\n", __FUNCTION__); return handle_http_error(403, req, rsp); #endif } } #ifdef WEBCFG_SUPPORT_HTTPTIME /* RFC2616, 14.25. If-Modified-Since */ e = HashLookup(req->headOptions, "If-Modified-Since"); if(e) { time_t reqtime, acctime; ASSERT(e->value.type == eHashString); reqtime = get_http_time(e->value.data.string); acctime = get_http_time(timebuf); //WEBLOG_INFO("<%s> reqtime=[%u] vs [%u]=acctime\n", __FUNCTION__, reqtime, acctime); if(reqtime >= acctime) { rsp->code = 304; rsp->body = using_customized_body; // 304 has no body. http_add_rspoption(rsp, "Content-Length", "0"); return http_send_response(rsp); } } #endif fp = web_fopen(vpath,"rb"); WEBLOG_INFO("<%s> fopen(%s) == %p \n", __FUNCTION__, vpath, fp); if(!fp) { WEBLOG_ERROR("<%s> failed to open file \"%s\" %s \n", __FUNCTION__, vpath, strerror(errno)); return handle_http_error(500, req, rsp); } ASSERT(fp); /* check if fp is NULL. */ fseek(fp, 0, SEEK_END); total_length = ftell(fp); fseek(fp, 0, SEEK_SET); #ifdef WEBCFG_SUPPORT_HTTPRANGE /* handle range request */ e = HashLookup(req->headOptions, "Range"); if(e) { char * p = e->value.data.string; ASSERT(e->value.type == eHashString); WEBLOG_INFO("<%s> client range request: %s\n", __FUNCTION__, p); /* figure out FROM-TO */ if(0 == strncmp(p, " bytes=-", 8)) { sscanf(p," bytes=-"sizett"", &task_length); from = total_length-task_length; to = total_length-1; } else { sscanf(p," bytes="sizett"-"sizett"", &from, &to); if(to < 0) { task_length = total_length - from; to = total_length-1; } else { task_length = to - from + 1; } } WEBLOG_INFO("<%s> request "sizett"-"sizett", total "sizett", we have "sizett".\n", __FUNCTION__, from, to, task_length, total_length); if(from < 0 || to < 0 || to >= total_length || from >= total_length || from > to) { http_add_rspoption(rsp, "Accept-Ranges", "bytes"); //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); http_add_rspoption(rsp, "Content-Range", "*/*"); return handle_http_error(416, req, rsp); } else { rsp->code = 206; rsp->body = using_customized_body; http_add_rspoption(rsp, "Accept-Ranges", "bytes"); //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); sprintf(strbuf, "bytes "sizett"-"sizett"/"sizett"", from, to, total_length); http_add_rspoption(rsp, "Content-Range", strbuf); sprintf(strbuf, sizett, task_length); http_add_rspoption(rsp, "Content-Length", strbuf); http_send_response(rsp); } } else #endif /* WEBCFG_SUPPORT_HTTPRANGE */ { from = 0; task_length = total_length; to = total_length-1; sprintf(strbuf, sizett, task_length); rsp->code = 200; rsp->body = using_customized_body; #ifdef WEBCFG_SUPPORT_HTTPRANGE http_add_rspoption(rsp, "Accept-Ranges", "bytes"); #endif //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri)); http_add_rspoption(rsp, "Content-Length", strbuf); http_send_response(rsp); } ret = OK; /* Respond with data. For HEAD request, skip this. */ if(HTTP_GET == req->method) { size_t i = 0; size_t buflen = 1024*1024; size_t readsize = 0; size_t counter = 0; char * buffer = NULL; #define SPEED_REPORT #ifdef SPEED_REPORT /* speed test */ //size_t data_1 = 0, data_2 = 0; time_t time_1 = time(NULL), time_2; #endif do { buflen /= 2; buffer = (char *)webmalloc(buflen); } while(!buffer); fseek(fp, from, SEEK_SET); while(1) { memset(buffer, 0, buflen); if(task_length-counter > buflen) readsize=fread(buffer, 1, buflen, fp); else readsize=fread(buffer, 1, task_length-counter, fp); if(readsize <= 0) { WEBLOG_ERROR("<%s> fread fail "sizett". %s.\n", __FUNCTION__, readsize, strerror(socketGetError())); ret = NG; break; } WEBLOG_VERBOSE("<%s> read "sizett" from %s, sent "sizett" to socket.\n ", __FUNCTION__, readsize, vpath, i); i = WebWrite(req->sock, buffer, readsize); if(i != readsize) { WEBLOG_ERROR("<%s> WebWrite fail "sizett". %s.\n", __FUNCTION__, i, strerror(socketGetError())); ret = NG; break; } //ASSERT(i==readsize); counter += readsize; #ifdef SPEED_REPORT time_2 = time(NULL); if (time_2 - time_1 > 1) WEBLOG_VERBOSE("<%s> "sizett"KB/s\n", __FUNCTION__, counter/1024/(time_2-time_1)); #endif WEBLOG_VERBOSE("<%s> "sizett"/"sizett"\n", __FUNCTION__, counter, task_length); if(counter >= task_length) break; } webfree(buffer); } if(fp) fclose(fp); return ret; }
int handle_http_move(http_req * req, http_rsp * rsp) { int ret = 0; char * from = NULL; char * to = NULL; char * tooooo = NULL; char * host = NULL; HashElement * e = NULL; WEBLOG_API(); #ifdef WEBCFG_SUPPORT_AUTH /* Authentication has a very high priority. */ if (OK != CheckAuthorization(req, rsp)) { return handle_http_error(401, req, rsp); } #endif from = req->uri; ASSERT(from && from[0]); if(0 == strlen(from)) { strcat(from, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, from); } e = HashLookup(req->headOptions, "Destination"); if(!e) { WEBLOG_ERROR("<%s> Missing \"Destination\" in Move/Copy.\n", __FUNCTION__); return handle_http_error(400, req, rsp); } ASSERT(e->value.type == eHashString); to = e->value.data.string; e = HashLookup(req->headOptions, "Host"); ASSERT(e); // static int _simple_validation(http_req * req) host = e->value.data.string; /* example To: [http://x.x.x.x:y/webdav/1.txt] Host: [x.x.x.x:y] */ tooooo = to + 7 + strlen(host); // 7 for "http://" if(0 == strlen(tooooo)) { strcat(from, "/"); WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, tooooo); } url_decode(tooooo); WEBLOG_INFO("<%s> %s from %s to %s.\n", __FUNCTION__, (HTTP_MOVE == req->method)?"Move":"Copy", from, tooooo); e = HashLookup(req->headOptions, "Overwrite"); if(e && e->value.data.string[0] == 'T') { if(HTTP_MOVE == req->method) ret = Webdav_Move(from, tooooo, TRUE); else ret = Webdav_Copy(from, tooooo, TRUE); } else { if(HTTP_MOVE == req->method) ret = Webdav_Move(from, tooooo, FALSE); else ret = Webdav_Copy(from, tooooo, FALSE); } switch(ret) { case WEBDAVR_OK: rsp->code = 201; http_add_rspoption(rsp, "Location", to); http_send_response(rsp); break; default: handle_http_error(502, req, rsp); break; } return OK; }
int main(int argc, char **argv) { WSADATA wsa_data; WSAStartup(MAKEWORD(2,0), &wsa_data); /* 初始化 WinSock 资源 */ //web SOCKET web_srv_soc = 0; unsigned short web_port = HTTP_DEF_PORT; web_srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */ if (web_srv_soc == INVALID_SOCKET) { printf("[Web] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } struct sockaddr_in web_serv_addr; /* 服务器地址 */ web_serv_addr.sin_family = AF_INET; web_serv_addr.sin_port = htons(web_port); web_serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); int result; result = bind(web_srv_soc, (struct sockaddr *) &web_serv_addr, sizeof(web_serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(web_srv_soc); printf("[Web Server] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(web_srv_soc, SOMAXCONN); printf("[Web] The server is running ... ...\n"); //FTP SOCKET ftp_srv_soc = 0; unsigned short ftp_port = FTP_DEF_PORT; ftp_srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建 socket */ if (ftp_srv_soc == INVALID_SOCKET) { printf("[FTP] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } struct sockaddr_in ftp_serv_addr; /* 服务器地址 */ ftp_serv_addr.sin_family = AF_INET; ftp_serv_addr.sin_port = htons(ftp_port); ftp_serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); result = bind(ftp_srv_soc, (struct sockaddr *) &ftp_serv_addr, sizeof(ftp_serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(ftp_srv_soc); printf("[FTP Server] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(ftp_srv_soc, SOMAXCONN); printf("[FTP] The server is running ... ...\n"); fd_set afds; FD_ZERO(&afds); FD_SET(web_srv_soc, &afds); FD_SET(ftp_srv_soc, &afds); fd_set rfds; SOCKET web_conn_soc; SOCKET ftp_conn_soc; while(1) { FD_ZERO(&rfds); memcpy(&rfds, &afds, sizeof(rfds)); if(select(FD_SETSIZE, &rfds, (fd_set*)0, (fd_set*)0, (struct timeval *)0)== SOCKET_ERROR) printf("select error\n"); if(FD_ISSET(web_srv_soc, &rfds)) { struct sockaddr_in conn_addr; /* 客户端地址 */ int conn_addr_len = sizeof(conn_addr); web_conn_soc = accept(web_srv_soc, (struct sockaddr*)&conn_addr,&conn_addr_len); if(web_conn_soc == INVALID_SOCKET) { printf("[Web] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[Web] Accepted address:[%s], port:[%d]\n", inet_ntoa(conn_addr.sin_addr), ntohs(conn_addr.sin_port)); char recv_buf[BUF_SIZE]; int recv_len; recv_len = recv(web_conn_soc, recv_buf, BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接收失败 */ { closesocket(web_conn_soc); printf("[Web] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ http_send_response(web_conn_soc, recv_buf, recv_len); closesocket(web_conn_soc); } if(FD_ISSET(ftp_srv_soc, &rfds)) { struct sockaddr_in conn_addr; /* 客户端地址 */ int conn_addr_len = sizeof(conn_addr); ftp_conn_soc = accept(ftp_srv_soc, (struct sockaddr*)&conn_addr,&conn_addr_len); if(ftp_conn_soc == INVALID_SOCKET) { printf("[FTP] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[FTP] Accepted address:[%s], port:[%d]\n", inet_ntoa(conn_addr.sin_addr), ntohs(conn_addr.sin_port)); char recv_buf[BUF_SIZE]; int recv_len; recv_len = recv(ftp_conn_soc, recv_buf, BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接收失败 */ { closesocket(ftp_conn_soc); printf("[FTP] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ ftp_send_response(ftp_conn_soc, recv_buf, recv_len); closesocket(ftp_conn_soc); } } closesocket(web_srv_soc); closesocket(ftp_srv_soc); WSACleanup(); printf("[web] The server is stopped.\n"); printf("[FTP] The server is stopped.\n"); return 0; }
int main(int argc, char **argv) { WSADATA wsa_Data; SOCKET srv_soc = 0, acpt_soc; /* socket 句柄 */ struct sockaddr_in serv_addr; /* 服务器地址 */ struct sockaddr_in from_addr; /* 客户端地址 */ char recv_buf[HTTP_BUF_SIZE]; unsigned short port = HTTP_DEF_PORT; unsigned long from_len = sizeof(from_addr); int result = 0, recv_len; if (argc == 2) /* 端口号 */ port = atoi(argv[1]); WSAStartup(MAKEWORD(2, 0), &wsa_Data); /* 初始化Winsock资源 */ srv_soc = socket(AF_INET, SOCK_STREAM, 0); /* 创建socket */ if (srv_soc == INVALID_SOCKET) { printf("[Web] socket() Fails, error = %d\n", WSAGetLastError()); return -1; } /* 服务器地址 */ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); result = bind(srv_soc, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); if (result == SOCKET_ERROR) /* 绑定失败 */ { closesocket(srv_soc); printf("[Web] Fail to bind, error = %d\n", WSAGetLastError()); return -1; } result = listen(srv_soc, SOMAXCONN); printf("[Web] The server is running ... ...\n"); while (1) { acpt_soc = accept(srv_soc, (struct sockaddr *) &from_addr, &from_len); /* 这里有警告 */ if (acpt_soc == INVALID_SOCKET) /* 接受失败 */ { printf("[Web] Fail to accept, error = %d\n", WSAGetLastError()); break; } printf("[Web] Accepted address:[%s], port:[%d]\n", \ inet_ntoa(from_addr.sin_addr), ntohs(from_addr.sin_port)); recv_len = recv(acpt_soc, recv_buf, HTTP_BUF_SIZE, 0); if (recv_len == SOCKET_ERROR) /* 接受失败 */ { closesocket(acpt_soc); printf("[Web] Fail to recv, error = %d\n", WSAGetLastError()); break; } recv_buf[recv_len] = 0; /* 向客户端发送响应数据 */ result = http_send_response(acpt_soc, recv_buf, recv_len); closesocket(acpt_soc); } closesocket(acpt_soc); WSACleanup(); printf("[Web] the server is stopped.\n"); return 0; }
/* * Launch a http server that listens on the given port. */ void http_server(uint16_t port, void (*callback)(struct http_user_vars_s *), bool launch) { socket_t s_listen = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (s_listen == INVALID_SOCKET) { error("unable to create a socket for the configuration server"); } struct sockaddr_in6 listen_addr; memset(&listen_addr, 0x0, sizeof(listen_addr)); listen_addr.sin6_family = AF_INET6; listen_addr.sin6_port = htons(port); listen_addr.sin6_addr = in6addr_any; int on = 1; setsockopt(s_listen, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); // For Windows we must explicitly allow IPv4 connections on = 0; if (setsockopt(s_listen, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) != 0) { warning("unable to allow incoming IPv4 connections to configuration " "server"); } if (bind(s_listen, (const void *)&listen_addr, sizeof(listen_addr)) != 0) { error("unable to create configuation server; failed to bind to " "address localhost:%u", port); } if (listen(s_listen, 1) != 0) { error("unable to create configuation server; failed to listen to " "address localhost:%u", port); } // Launch the UI: if (launch) { launch_ui(port); } // Main server loop: while (true) { struct sockaddr_in6 accept_addr; socklen_t accept_len = sizeof(accept_addr); socket_t s = accept(s_listen, (struct sockaddr *)&accept_addr, &accept_len); if (s == INVALID_SOCKET) { warning("unable to accept incoming connection to configuration " "server localhost:%u", port); close_socket(s); continue; } static const struct in6_addr in6addr_loopbackv4 = {{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 127, 0, 0, 1}}}; if (memcmp(&accept_addr.sin6_addr, &in6addr_loopback, sizeof(in6addr_loopback)) != 0 && memcmp(&accept_addr.sin6_addr, &in6addr_loopbackv4, sizeof(in6addr_loopbackv4) - 3) != 0) { warning("unable to accept incoming connection to configuration " "server localhost:%u from non-local address", port); close_socket(s); continue; } char request[MAX_REQUEST_BUFF_SIZE]; struct http_parser_s parser; http_parser_init(&parser); do { size_t n = recv(s, request, sizeof(request)-1, 0); if (n <= 0) { http_user_vars_free(&parser.request.vars); warning("unable to read request for configuration server " "localhost:%u", port); close_socket(s); break; } request[n] = '\0'; http_parse_request(request, n, &parser); switch (parser.state) { case HTTP_STATE_FINAL: break; case HTTP_STATE_ERROR: http_user_vars_free(&parser.request.vars); warning("unable to parse request to configuration server " "localhost:%u", port); close_socket(s); break; default: continue; } http_callback_func_t generate; if (parser.request.method == HTTP_METHOD_GET && (generate = http_lookup_callback(parser.request.name)) != NULL) { http_buffer_t content = http_buffer_open(); if (generate(content)) { bool success = http_send_response(s, 200, content, &parser.request); if (!success) { http_error(s, 500, &parser.request); } } else { http_error(s, 404, &parser.request); } http_buffer_close(content); } else { callback(&parser.request.vars); http_handle_request(s, &parser.request); } shutdown(s, SHUT_RDWR); http_user_vars_free(&parser.request.vars); close_socket(s); } while (false); } }