diff --git a/examples/protocols/sockets/tcp_server/main/tcp_server.c b/examples/protocols/sockets/tcp_server/main/tcp_server.c index 062268ebd..bd9606e3a 100644 --- a/examples/protocols/sockets/tcp_server/main/tcp_server.c +++ b/examples/protocols/sockets/tcp_server/main/tcp_server.c @@ -28,53 +28,83 @@ static const char *TAG = "example"; +static void do_retransmit(const int sock) +{ + int len; + char rx_buffer[128]; + + do { + len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (len < 0) { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + } else if (len == 0) { + ESP_LOGW(TAG, "Connection closed"); + } else { + rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + + // send() can return less bytes than supplied length. + // Walk-around for robust implementation. + int to_write = len; + while (to_write > 0) { + int written = send(sock, rx_buffer + (len - to_write), to_write, 0); + if (written < 0) { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + } + to_write -= written; + } + } + } while (len > 0); +} static void tcp_server_task(void *pvParameters) { - char rx_buffer[128]; char addr_str[128]; int addr_family; int ip_protocol; - while (1) { #ifdef CONFIG_EXAMPLE_IPV4 - struct sockaddr_in dest_addr; - dest_addr.sin_addr.s_addr = htonl(INADDR_ANY); - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(PORT); - addr_family = AF_INET; - ip_protocol = IPPROTO_IP; - inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1); + struct sockaddr_in dest_addr; + dest_addr.sin_addr.s_addr = htonl(INADDR_ANY); + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(PORT); + addr_family = AF_INET; + ip_protocol = IPPROTO_IP; + inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1); #else // IPV6 - struct sockaddr_in6 dest_addr; - bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un)); - dest_addr.sin6_family = AF_INET6; - dest_addr.sin6_port = htons(PORT); - addr_family = AF_INET6; - ip_protocol = IPPROTO_IPV6; - inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); + struct sockaddr_in6 dest_addr; + bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un)); + dest_addr.sin6_family = AF_INET6; + dest_addr.sin6_port = htons(PORT); + addr_family = AF_INET6; + ip_protocol = IPPROTO_IPV6; + inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); #endif - int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); - if (listen_sock < 0) { - ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); - break; - } - ESP_LOGI(TAG, "Socket created"); + int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); + if (listen_sock < 0) { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + vTaskDelete(NULL); + return; + } + ESP_LOGI(TAG, "Socket created"); - int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); - if (err != 0) { - ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); - break; - } - ESP_LOGI(TAG, "Socket bound, port %d", PORT); + int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err != 0) { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + goto CLEAN_UP; + } + ESP_LOGI(TAG, "Socket bound, port %d", PORT); + + err = listen(listen_sock, 1); + if (err != 0) { + ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); + goto CLEAN_UP; + } + + while (1) { - err = listen(listen_sock, 1); - if (err != 0) { - ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); - break; - } ESP_LOGI(TAG, "Socket listening"); struct sockaddr_in6 source_addr; // Large enough for both IPv4 or IPv6 @@ -84,47 +114,23 @@ static void tcp_server_task(void *pvParameters) ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); break; } - ESP_LOGI(TAG, "Socket accepted"); - while (1) { - int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); - // Error occurred during receiving - if (len < 0) { - ESP_LOGE(TAG, "recv failed: errno %d", errno); - break; - } - // Connection closed - else if (len == 0) { - ESP_LOGI(TAG, "Connection closed"); - break; - } - // Data received - else { - // Get the sender's ip address as string - if (source_addr.sin6_family == PF_INET) { - inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); - } else if (source_addr.sin6_family == PF_INET6) { - inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); - } - - rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string - ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str); - ESP_LOGI(TAG, "%s", rx_buffer); - - int err = send(sock, rx_buffer, len, 0); - if (err < 0) { - ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); - break; - } - } + // Convert ip address to string + if (source_addr.sin6_family == PF_INET) { + inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); + } else if (source_addr.sin6_family == PF_INET6) { + inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1); } + ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); - if (sock != -1) { - ESP_LOGE(TAG, "Shutting down socket and restarting..."); - shutdown(sock, 0); - close(sock); - } + do_retransmit(sock); + + shutdown(sock, 0); + close(sock); } + +CLEAN_UP: + close(listen_sock); vTaskDelete(NULL); }