static int httpd_setup_new_socket(int port) { int one = 1; int status, sockfd; struct sockaddr_t addr_listen; /* create listening TCP socket */ sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { status = net_get_sock_error(sockfd); httpd_d("Socket creation failed: Port: %d Status: %d", port, status); return status; } setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); addr_listen.s_ip = INADDR_ANY; addr_listen.s_port = port; /* bind insocket */ status = bind(sockfd, &addr_listen, sizeof(addr_listen)); if (status < 0) { status = net_get_sock_error(sockfd); httpd_d("Failed to bind socket on port: %d Status: %d", status, port); return status; } status = listen(sockfd, HTTPD_MAX_BACKLOG_CONN); if (status < 0) { status = net_get_sock_error(sockfd); httpd_d("Failed to listen on port %d: %d.", port, status); return status; } httpd_d("Listening on port %d.", port); return sockfd; }
static int httpd_close_sockets() { int ret, status = kNoErr; if (http_sockfd != -1) { ret = close(http_sockfd); if (ret != 0) { httpd_d("failed to close http socket: %d", net_get_sock_error(http_sockfd)); status = -kInProgressErr; } http_sockfd = -1; } if (client_sockfd != -1) { ret = close(client_sockfd); if (ret != 0) { httpd_d("Failed to close client socket: %d", net_get_sock_error(client_sockfd)); status = -kInProgressErr; } client_sockfd = -1; } return status; }
/*Helper function to send a buffer over a connection. */ int httpd_send(int conn, const char *buf, int len) { int num; do { #ifdef CONFIG_ENABLE_HTTPS if (httpd_is_https_active()) num = tls_send(httpd_tls_handle, buf, len); else #endif /* ENABLE_HTTPS */ num = send(conn, buf, len, 0); if (num < 0) { httpd_e("send() failed: %d", net_get_sock_error(conn)); return -WM_FAIL; } len -= num; buf += len; } while (len > 0); return WM_SUCCESS; }
static void httpd_handle_client_connection(const fd_set *active_readfds) { int activefds_cnt, status; fd_set readfds; if (httpd_stop_req) { httpd_d("HTTPD stop request received"); httpd_stop_req = FALSE; httpd_suspend_thread(false); } status = httpd_accept_client_socket(active_readfds); if (status != kNoErr) return; httpd_d("Client socket accepted: %d", client_sockfd); FD_ZERO(&readfds); FD_SET(client_sockfd, &readfds); while (1) { if (httpd_stop_req) { httpd_d("HTTPD stop request received"); httpd_stop_req = FALSE; httpd_suspend_thread(false); } httpd_d("Waiting on client socket"); activefds_cnt = httpd_select(client_sockfd, &readfds, NULL, HTTPD_CLIENT_SOCK_TIMEOUT); if (httpd_stop_req) { httpd_d("HTTPD stop request received"); httpd_stop_req = FALSE; httpd_suspend_thread(false); } if (activefds_cnt == HTTPD_TIMEOUT_EVENT) { /* Timeout has occured */ httpd_d("Client socket timeout occurred. " "Force closing socket"); status = close(client_sockfd); if (status != kNoErr) { status = net_get_sock_error(client_sockfd); httpd_d("Failed to close socket %d", status); httpd_suspend_thread(true); } client_sockfd = -1; break; } httpd_d("Handling %d", client_sockfd); /* Note: * Connection will be handled with call to * httpd_handle_message twice, first for * handling request (kNoErr) and second * time as there is no more data to receive * (client closed connection) and hence * will return with status HTTPD_DONE * closing socket. */ /* FIXME: remove this memset if all is working well */ /* memset(&httpd_message_in[0], 0, sizeof(httpd_message_in)); */ status = httpd_handle_message(client_sockfd); if (status == kNoErr) { /* The handlers are expected more data on the socket */ continue; } /* Either there was some error or everything went well */ httpd_d("Close socket %d. %s: %d", client_sockfd, status == HTTPD_DONE ? "Handler done" : "Handler failed", status); status = close(client_sockfd); if (status != kNoErr) { status = net_get_sock_error(client_sockfd); httpd_d("Failed to close socket %d", status); httpd_suspend_thread(true); } client_sockfd = -1; break; } }
static int httpd_accept_client_socket(const fd_set *active_readfds) { int main_sockfd = -1; struct sockaddr_t addr_from; int addr_from_len; if (FD_ISSET(http_sockfd, active_readfds)) { main_sockfd = http_sockfd; https_active = FALSE; } addr_from_len = sizeof(addr_from); client_sockfd = accept(main_sockfd, &addr_from, &addr_from_len); if (client_sockfd < 0) { httpd_d("net_accept client socket failed %d.", client_sockfd); return -kInProgressErr; } /* * Enable TCP Keep-alive for accepted client connection * -- By enabling this feature TCP sends probe packet if there is * inactivity over connection for specfied interval * -- If there is no response to probe packet for specified retries * then connection is closed with RST packet to peer end * -- Ref: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ * * We are doing this as we have single threaded web server with * synchronous (blocking) API usage like send, recv and they might get * blocked due to un-availability of peer end, causing web server to * be in-responsive forever. */ int optval = true; if (setsockopt(client_sockfd, SOL_SOCKET, 0x0008, &optval, sizeof(optval)) == -1) { httpd_d("Unsupported option SO_KEEPALIVE: %d", net_get_sock_error(client_sockfd)); } /* TCP Keep-alive idle/inactivity timeout is 10 seconds */ optval = 10; if (setsockopt(client_sockfd, IPPROTO_TCP, 0x03, &optval, sizeof(optval)) == -1) { httpd_d("Unsupported option TCP_KEEPIDLE: %d", net_get_sock_error(client_sockfd)); } /* TCP Keep-alive retry count is 5 */ optval = 5; if (setsockopt(client_sockfd, IPPROTO_TCP, 0x05, &optval, sizeof(optval)) == -1) { httpd_d("Unsupported option TCP_KEEPCNT: %d", net_get_sock_error(client_sockfd)); } /* TCP Keep-alive retry interval (in case no response for probe * packet) is 1 second. */ optval = 1; if (setsockopt(client_sockfd, IPPROTO_TCP, 0x04, &optval, sizeof(optval)) == -1) { httpd_d("Unsupported option TCP_KEEPINTVL: %d", net_get_sock_error(client_sockfd)); } httpd_d("connecting %d to %d.", client_sockfd, addr_from.s_port); return kNoErr; }