c - Linux socket send() error EAGAIN -
i designing http tunnel using proxy , http connect request. 90% of time, when try send connect request connect 192.168.1.68:3001 http/1.1\r\n\r\n send fails, returning errno = 11, "try again".
i using non-blocking sockets, , socket closed re-opened between connect attempts. don't think send buffer full, because not sending data. i'm confused why connecting , not (and there doesn't appear pattern, connect twice in row, there 10 failures between connects).
what of reasons getting error?
edit:
(code)
if (connect(sock, psockaddr, isockaddrsize)) { ... char message[80]; sprintf(message, "connect 192.168.1.68:3001 http/1.1\r\n\r\n"); printf("*j* message loaded.\n"); //*j* printf("*j* %s\n", message); //*j* if (send(sock, message, strlen(message) + 1, 0) < 0) printf("*j* send failed: %d\n", errno); else printf("*j* data sent.\n"); } ... printf("\n*j* close socket (reset host command)"); closesocket(sock); (output)
[success] *j* starting connect... *j* message loaded. *j* connect 192.168.1.68:3001 http/1.1 *j* data sent. *j* rv = 1 *j* ending connect... [fail] *j* starting connect... *j* message loaded. *j* connect 192.168.1.68:3001 http/1.1 *j* send failed: 11 *j* ending connect...
you have several bugs in code:
connect()returns 0 on success , -1 on error.ifstatement evaluates true non-zero value. means code sendingconnectmessage whenconnect()failing error. however, not errors fatal. in particular, since using non-blocking socket,einprogress/wsaewouldblockerror indicates connection still pending , need useselect()or(e)poll()wait socket finish connecting (or fail). so, code work ifconnect()connects asynchronously , happens connect proxy before have chance callsend(). behavior should not rely on. need handle errors correctly.the return value of
send()specifies how many bytes accepted, or -1 on error. fewer bytes requested may accepted (especially on non-blocking socket). , need handle non-fatal errors, in particular(wsa)ewouldblock(andeagain, , possiblyeintr, on non-windows platforms), means socket unable accept new data @ momentsend()called, callsend()again. should callingsend()in loop until bytes have been sent, or fatal error occurs.even if
send()'ing data correctly, use of+ 1afterstrlen()wrong. including null terminator in data sent, not part ofconnectprotocol. null terminator treated proxy application data , forwarded as-is through tunnel next server (if tunnel opened), breaking communications server.
with said, try more following instead. use of closeocket() indicates programming windows, windows-specific:
int ret, err; ... ret = connect(sock, psockaddr, isockaddrsize); if (ret == -1) { err = wsagetlasterror(); if (err == wsaewouldblock) { fd_set wfd; fd_zero(&wfd); fd_set(sock, &wfd); fd_set efd; fd_zero(&efd); fd_set(sock, &efd); timeval timeout; timeout.tv_sec = ...; timeout.tv_usec = ...; ret = select(0, null, &wfd, &wfd, &timeout); if (ret == 0) { printf("*j* connect timeout\n"); // handle timeout needed ... return; } if ((ret > 0) && fd_isset(sock, &efd)) { err = 0; getsockopt(sock, sol_socket, so_error, (char*)&err, sizeof(err)); ret = -1; } } if (ret == -1) { printf("*j* connect failed: %d\n", err); // handle fatal error needed ... return; } } ... char message[80]; sprintf(message, "connect 192.168.1.68:3001 http/1.1\r\n\r\n"); printf("*j* message loaded.\n"); //*j* printf("*j* %s\n", message); //*j* char *pmsg = message; int len = strlen(message); { ret = send(sock, pmsg, len, 0); if (ret == -1) { err = getlastsocketerror(); if (err == wsaewouldblock) { fd_set wfd; fd_zero(&wfd); fd_set(sock, &wfd); timeval timeout; timeout.tv_sec = ...; timeout.tv_usec = ...; ret = select(0, null, &wfd, null, &timeout); if (ret > 0) continue; if (ret == 0) { printf("*j* send timeout\n"); // handle timeout needed ... return; } err = wsagetlasterror(); } printf("*j* send failed: %d\n", err); // handle fatal error needed ... return; } else { pmsg += ret; len += ret; } } while (len > 0); printf("*j* data sent\n"); ... printf("*j* close socket\n"); closesocket(sock); if want little more cross-platform, try instead (or use cross-platform socket library instead):
int getlastsocketerror() { #ifdef windows return wsagetlasterror(); #else return errno; #endif }; int ret, err; ... ret = connect(sock, psockaddr, isockaddrsize); if (ret == -1) { err = getlastsocketerror(); if ( #ifdef windows err == wsaewouldblock #else err == einprogress #endif ) { #ifndef windows { #endif fd_set wfd; fd_zero(&wfd); fd_set(sock, &wfd); #ifdef windows fd_set efd; fd_zero(&efd); fd_set(sock, &efd); #endif timeval timeout; timeout.tv_sec = ...; timeout.tv_usec = ...; #ifdef windows ret = select(0, null, &wfd, &wfd, &timeout); #else ret = select(sock+1, null, &wfd, null, &timeout); #endif if (ret == 0) { printf("*j* connect timeout\n"); // handle timeout needed ... return; } #ifdef windows if ((ret > 0) && fd_isset(sock, &efd)) { err = 0; getsockopt(sock, sol_socket, so_error, (char*)&err, sizeof(err)); ret = -1; } #endif #ifndef windows } while ((ret == -1) && (errno == eintr)); #endif } if (ret == -1) { printf("*j* connect failed: %d\n", err); // handle fatal error needed ... return; } } ... char message[80]; sprintf(message, "connect 192.168.1.68:3001 http/1.1\r\n\r\n"); printf("*j* message loaded.\n"); //*j* printf("*j* %s\n", message); //*j* char *pmsg = message; int len = strlen(message); { ret = send(sock, pmsg, len, 0); if (ret == -1) { err = getlastsocketerror(); if ( #ifdef windows err == wsaewouldblock #else (err == ewouldblock) || (err == eagain) #endif ) { fd_set wfd; fd_zero(&wfd); fd_set(sock, &wfd); timeval timeout; timeout.tv_sec = ...; timeout.tv_usec = ...; ret = select( #ifdef windows 0 #else sock+1 #endif , null, &wfd, null, &timeout); if (ret > 0) continue; if (ret == 0) { printf("*j* send timeout\n"); // handle timeout needed ... return; } err = getlastsocketerror(); } #ifndef windows if (err != eintr) #endif { printf("*j* send failed: %d\n", err); // handle fatal error needed ... return; } } else { pmsg += ret; len += ret; } } while (len > 0); printf("*j* data sent\n"); ... printf("*j* close socket\n"); #ifdef windows closesocket(sock); #else close(sock); #endif
Comments
Post a Comment