Note that there are some explanatory texts on larger screens.

plurals
  1. POBroken pipe (EPIPE) on connection to loopback address
    text
    copied!<p>I'm currently testing my networking code. This involves making a connection via the IPv4 loopback address (127.0.0.1). Unfortunately the program often (not always) gives an EPIPE error on sending data.</p> <p>I am using Berkeley network sockets and libevent. I make a non-blocking socket via:</p> <pre><code>CBSocketReturn CBNewSocket(uint64_t * socketID,bool IPv6){ *socketID = socket(IPv6 ? PF_INET6 : PF_INET, SOCK_STREAM, 0); if (*socketID == -1) { if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { return CB_SOCKET_NO_SUPPORT; } return CB_SOCKET_BAD; } // Stop SIGPIPE annoying us. if (CB_NOSIGPIPE) { int i = 1; setsockopt(*socketID, SOL_SOCKET, SO_NOSIGPIPE, &amp;i, sizeof(i)); } // Make socket non-blocking evutil_make_socket_nonblocking((evutil_socket_t)*socketID); return CB_SOCKET_OK; } </code></pre> <p>I make a connection event via:</p> <pre><code>bool CBSocketDidConnectEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onDidConnect)(void *,void *),void * node){ CBEvent * event = malloc(sizeof(*event)); event-&gt;loop = (CBEventLoop *)loopID; event-&gt;onEvent.ptr = onDidConnect; event-&gt;node = node; event-&gt;event = event_new(((CBEventLoop *)loopID)-&gt;base, (evutil_socket_t)socketID, EV_TIMEOUT|EV_WRITE, CBDidConnect, event); if (NOT event-&gt;event) { free(event); event = 0; } *eventID = (uint64_t)event; return event; } void CBDidConnect(evutil_socket_t socketID,short eventNum,void * arg){ CBEvent * event = arg; if (eventNum &amp; EV_TIMEOUT) { // Timeout for the connection event-&gt;loop-&gt;onTimeOut(event-&gt;loop-&gt;communicator,event-&gt;node,CB_TIMEOUT_CONNECT); }else{ // Connection successful event-&gt;onEvent.ptr(event-&gt;loop-&gt;communicator,event-&gt;node); } } </code></pre> <p>And add it via:</p> <pre><code>bool CBSocketAddEvent(uint64_t eventID,uint16_t timeout){ CBEvent * event = (CBEvent *)eventID; int res; if (timeout) { struct timeval time = {timeout,0}; res = event_add(event-&gt;event, &amp;time); }else res = event_add(event-&gt;event, NULL); return NOT res; } </code></pre> <p>To connect:</p> <pre><code>bool CBSocketConnect(uint64_t socketID,uint8_t * IP,bool IPv6,uint16_t port){ // Create sockaddr_in6 information for a IPv6 address int res; if (IPv6) { struct sockaddr_in6 address; memset(&amp;address, 0, sizeof(address)); // Clear structure. address.sin6_family = AF_INET6; memcpy(&amp;address.sin6_addr, IP, 16); // Move IP address into place. address.sin6_port = htons(port); // Port number to network order res = connect((evutil_socket_t)socketID, (struct sockaddr *)&amp;address, sizeof(address)); }else{ struct sockaddr_in address; memset(&amp;address, 0, sizeof(address)); // Clear structure. address.sin_family = AF_INET; memcpy(&amp;address.sin_addr, IP + 12, 4); // Move IP address into place. Last 4 bytes for IPv4. address.sin_port = htons(port); // Port number to network order res = connect((evutil_socket_t)socketID, (struct sockaddr *)&amp;address, sizeof(address)); } if (NOT res || errno == EINPROGRESS) return true; return false; } </code></pre> <p>Upon connection the canSend event is made:</p> <pre><code>bool CBSocketCanSendEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onCanSend)(void *,void *),void * node){ CBEvent * event = malloc(sizeof(*event)); event-&gt;loop = (CBEventLoop *)loopID; event-&gt;onEvent.ptr = onCanSend; event-&gt;node = node; event-&gt;event = event_new(((CBEventLoop *)loopID)-&gt;base, (evutil_socket_t)socketID, EV_TIMEOUT|EV_WRITE|EV_PERSIST, CBCanSend, event); if (NOT event-&gt;event) { free(event); event = 0; } *eventID = (uint64_t)event; return event; } void CBCanSend(evutil_socket_t socketID,short eventNum,void * arg){ CBEvent * event = arg; if (eventNum &amp; EV_TIMEOUT) { // Timeout when waiting to write. event-&gt;loop-&gt;onTimeOut(event-&gt;loop-&gt;communicator,event-&gt;node,CB_TIMEOUT_SEND); }else{ // Can send event-&gt;onEvent.ptr(event-&gt;loop-&gt;communicator,event-&gt;node); } } </code></pre> <p>But sending often gives an EPIPE error:</p> <pre><code>int32_t CBSocketSend(uint64_t socketID,uint8_t * data,uint32_t len){ ssize_t res = send((evutil_socket_t)socketID, data, len, CB_SEND_FLAGS); printf("SENT (%li): ",res); for (uint32_t x = 0; x &lt; res; x++) { printf("%c",data[x]); } printf("\n"); if (res &gt;= 0) return (int32_t)res; if (errno == EAGAIN) return 0; // False event. Wait again. return CB_SOCKET_FAILURE; // Failure } </code></pre> <p>It lands on <code>return CB_SOCKET_FAILURE;</code> and errno is set to EPIPE. Now why would this be? The send flags is just MSG_NOSIGNAL if it is set because SIGPIPE kept interrupting the program with this error. I want EPIPE to cause CBSocketSend to return CB_SOCKET_FAILURE and not interrupt the program, but there is not reason for the send to fail with EPIPE, so why is it doing it?</p> <p>Last time I got the error I noticed the thread that connects was still on the connect() call. Is there danger in making a connection event to be handled by a separate thread than the thread that connects?</p> <p>See the network code in these places:</p> <p><a href="https://github.com/MatthewLM/cbitcoin/blob/master/test/testCBNetworkCommunicator.c" rel="nofollow">https://github.com/MatthewLM/cbitcoin/blob/master/test/testCBNetworkCommunicator.c</a> <a href="https://github.com/MatthewLM/cbitcoin/tree/master/src/structures/CBObject/CBNetworkCommunicator" rel="nofollow">https://github.com/MatthewLM/cbitcoin/tree/master/src/structures/CBObject/CBNetworkCommunicator</a> <a href="https://github.com/MatthewLM/cbitcoin/tree/master/dependencies/sockets" rel="nofollow">https://github.com/MatthewLM/cbitcoin/tree/master/dependencies/sockets</a></p> <p>Thank you.</p> <p>Edit: I ran it again and I got the error after connect() had finished.</p> <p>EDIT 2: It seems the connection event is being given without an accept from the other side.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload