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.if
statement evaluates true non-zero value. means code sendingconnect
message whenconnect()
failing error. however, not errors fatal. in particular, since using non-blocking socket,einprogress
/wsaewouldblock
error 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+ 1
afterstrlen()
wrong. including null terminator in data sent, not part ofconnect
protocol. 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