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:

  1. connect() returns 0 on success , -1 on error. if statement evaluates true non-zero value. means code sending connect message when connect() failing error. however, not errors fatal. in particular, since using non-blocking socket, einprogress/wsaewouldblock error indicates connection still pending , need use select() or (e)poll() wait socket finish connecting (or fail). so, code work if connect() connects asynchronously , happens connect proxy before have chance call send(). behavior should not rely on. need handle errors correctly.

  2. 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 (and eagain, , possibly eintr, on non-windows platforms), means socket unable accept new data @ moment send() called, call send() again. should calling send() in loop until bytes have been sent, or fatal error occurs.

  3. even if send()'ing data correctly, use of + 1 after strlen() wrong. including null terminator in data sent, not part of connect 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

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -