#include "../new_common.h" #include "../obk_config.h" #if NEW_TCP_SERVER #include "lwip/sockets.h" #include "lwip/ip_addr.h" #include "lwip/inet.h" #include "../logging/logging.h" #include "new_http.h" #if PLATFORM_ESP8266 #define MAX_SOCKETS_TCP 2 #define REPLY_BUFFER_SIZE 1024 #define INCOMING_BUFFER_SIZE 1024 #define HTTP_CLIENT_STACK_SIZE 4096 #endif #ifndef MAX_SOCKETS_TCP #define MAX_SOCKETS_TCP MEMP_NUM_TCP_PCB #endif void HTTPServer_Start(); #define HTTP_SERVER_PORT 80 #define INVALID_SOCK -1 #ifndef REPLY_BUFFER_SIZE #define REPLY_BUFFER_SIZE 2048 #endif #ifndef INCOMING_BUFFER_SIZE #define INCOMING_BUFFER_SIZE 2048 #endif #ifndef HTTP_CLIENT_STACK_SIZE #define HTTP_CLIENT_STACK_SIZE 8192 #endif typedef struct { int fd; beken_thread_t thread; bool isCompleted; } tcp_thread_t; static beken_thread_t g_http_thread = NULL; static const size_t max_socks = MAX_SOCKETS_TCP - 1; static int listen_sock = INVALID_SOCK; static tcp_thread_t sock[MAX_SOCKETS_TCP - 1] = { [0 ... MAX_SOCKETS_TCP - 2] = { -1, NULL, false }, }; static void tcp_client_thread(tcp_thread_t* arg) { int fd = arg->fd; char* buf = NULL; char* reply = NULL; int replyBufferSize = REPLY_BUFFER_SIZE; reply = (char*)os_malloc(replyBufferSize); buf = (char*)os_malloc(INCOMING_BUFFER_SIZE); if(buf == 0 || reply == 0) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "TCP Client failed to malloc buffer"); goto exit; } http_request_t request; memset(&request, 0, sizeof(request)); request.fd = fd; request.received = buf; request.receivedLenmax = INCOMING_BUFFER_SIZE - 2; request.responseCode = HTTP_RESPONSE_OK; request.receivedLen = 0; while(1) { int remaining = request.receivedLenmax - request.receivedLen; int received = recv(fd, request.received + request.receivedLen, remaining, 0); if(received <= 0) { break; } request.receivedLen += received; if(received < remaining) { break; } // grow by INCOMING_BUFFER_SIZE request.receivedLenmax += INCOMING_BUFFER_SIZE; request.received = (char*)realloc(request.received, request.receivedLenmax + 2); if(request.received == NULL) { // no memory goto exit; } } request.received[request.receivedLen] = 0; request.reply = reply; request.replylen = 0; reply[0] = '\0'; request.replymaxlen = replyBufferSize - 1; if(request.receivedLen <= 0) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "TCP Client is disconnected, fd: %d", fd); goto exit; } //addLog( "TCP received string %s\n",buf ); // returns length to be sent if any // ADDLOG_DEBUG(LOG_FEATURE_HTTP, "TCP will process packet of len %i\n", request.receivedLen ); int lenret = HTTP_ProcessPacket(&request); if(lenret > 0) { ADDLOG_DEBUG(LOG_FEATURE_HTTP, "TCP sending reply len %i\n", lenret); send(fd, reply, lenret, 0); } exit: if(buf != NULL) os_free(buf); if(reply != NULL) os_free(reply); lwip_close(fd); arg->isCompleted = true; #if PLATFORM_RDA5981 arg->thread = NULL; arg->isCompleted = false; arg->fd = INVALID_SOCK; rtos_delete_thread(NULL); #else rtos_suspend_thread(NULL); #endif } static inline char* get_clientaddr(struct sockaddr_storage* source_addr) { static char address_str[128]; char* res = NULL; // Convert ip address to string if(source_addr->ss_family == PF_INET) { res = inet_ntoa_r(((struct sockaddr_in*)source_addr)->sin_addr, address_str, sizeof(address_str) - 1); } #if LWIP_IPV6 else if(source_addr->ss_family == PF_INET6) { res = inet6_ntoa_r(((struct sockaddr_in6*)source_addr)->sin6_addr, address_str, sizeof(address_str) - 1); } #endif if(!res) { address_str[0] = '\0'; } return address_str; } void HTTPServer_Stop(void* arg) { if(g_http_thread != NULL) { rtos_delete_thread(&g_http_thread); } if(listen_sock != INVALID_SOCK) { close(listen_sock); } for(int i = 0; i < max_socks; ++i) { if(sock[i].thread != NULL) { rtos_delete_thread(&sock[i].thread); sock[i].thread = NULL; } if(sock[i].fd != INVALID_SOCK) { close(sock[i].fd); sock[i].fd = INVALID_SOCK; } } } void restart_tcp_server(void* arg) { HTTPServer_Start(); rtos_delete_thread(NULL); } static void tcp_server_thread(beken_thread_arg_t arg) { OSStatus err = kNoErr; int reuse = 1; struct sockaddr_in server_addr = { .sin_family = AF_INET, .sin_addr = { .s_addr = INADDR_ANY, }, .sin_port = htons(HTTP_SERVER_PORT), }; if(listen_sock != INVALID_SOCK) close(listen_sock); for(int i = 0; i < max_socks; ++i) { if(sock[i].fd != INVALID_SOCK) { close(sock[i].fd); } if(sock[i].thread != NULL) { rtos_delete_thread(&sock[i].thread); } sock[i].fd = INVALID_SOCK; sock[i].thread = NULL; sock[i].isCompleted = false; } listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listen_sock < 0) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "Unable to create socket"); goto error; } setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)); err = bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)); if(err != 0) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "Socket unable to bind"); goto error; } ADDLOG_EXTRADEBUG(LOG_FEATURE_HTTP, "Socket bound on 0.0.0.0:%i", HTTP_SERVER_PORT); err = listen(listen_sock, 0); if(err != 0) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "Error occurred during listen"); goto error; } ADDLOG_INFO(LOG_FEATURE_HTTP, "TCP server listening"); while(true) { struct sockaddr_storage source_addr; socklen_t addr_len = sizeof(source_addr); int new_idx = 0; for(int i = 0; i < max_socks; ++i) { if(sock[i].isCompleted) { if(sock[i].thread != NULL) { rtos_delete_thread(&sock[i].thread); sock[i].thread = NULL; } sock[i].isCompleted = false; sock[i].fd = INVALID_SOCK; } } for(new_idx = 0; new_idx < max_socks; ++new_idx) { if(sock[new_idx].fd == INVALID_SOCK) { break; } } if(new_idx < max_socks) { sock[new_idx].fd = accept(listen_sock, (struct sockaddr*)&source_addr, &addr_len); #if LWIP_SO_RCVTIMEO && !PLATFORM_ECR6600 && !PLATFORM_TR6260 struct timeval tv; tv.tv_sec = 30; tv.tv_usec = 0; setsockopt(sock[new_idx].fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)); #endif if(sock[new_idx].fd < 0) { switch(errno) { //case EAGAIN: case EWOULDBLOCK: break; case EBADF: goto error; default: ADDLOG_ERROR(LOG_FEATURE_HTTP, "[sock=%d]: Error when accepting connection, err: %i", sock[new_idx].fd, errno); break; } } else { //ADDLOG_EXTRADEBUG(LOG_FEATURE_HTTP, "[sock=%d]: Connection accepted from IP:%s", sock[new_idx].fd, get_clientaddr(&source_addr)); rtos_delay_milliseconds(20); if(kNoErr != rtos_create_thread(&sock[new_idx].thread, BEKEN_APPLICATION_PRIORITY, "HTTP Client", (beken_thread_function_t)tcp_client_thread, HTTP_CLIENT_STACK_SIZE, (beken_thread_arg_t)&sock[new_idx])) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "[sock=%d]: TCP Client thread creation failed!", sock[new_idx].fd); lwip_close(sock[new_idx].fd); sock[new_idx].fd = INVALID_SOCK; goto error; } } } rtos_delay_milliseconds(10); } error: ADDLOG_ERROR(LOG_FEATURE_HTTP, "TCP Server Error"); if(listen_sock != INVALID_SOCK) { close(listen_sock); } for(int i = 0; i < max_socks; ++i) { if(sock[i].thread != NULL) { rtos_delete_thread(&sock[i].thread); sock[i].thread = NULL; } if(sock[i].fd != INVALID_SOCK) { close(sock[i].fd); sock[i].fd = INVALID_SOCK; } } rtos_delay_milliseconds(2000); rtos_create_thread(NULL, BEKEN_APPLICATION_PRIORITY, "TCP Restart", (beken_thread_function_t)restart_tcp_server, 2048, (beken_thread_arg_t)0); } void HTTPServer_Start() { OSStatus err = kNoErr; if(g_http_thread != NULL) { rtos_delete_thread(&g_http_thread); } err = rtos_create_thread(&g_http_thread, BEKEN_APPLICATION_PRIORITY, "TCP_server", (beken_thread_function_t)tcp_server_thread, 0x800, (beken_thread_arg_t)0); if(err != kNoErr) { ADDLOG_ERROR(LOG_FEATURE_HTTP, "create \"TCP_server\" thread failed with %i!\r\n", err); } } #endif