<div dir="ltr">Hello,<div><br></div><div>We've been experiencing a lot of connection drops due to ECONNABORTED error in reliable agent while sending a lot of data (large file sending). It was critical to us so I did some digging and here's what I've gathered.</div><div><br></div><div>Connection gets aboted in agent/pseudotcp.c (process()) while doing fast retransmit. Speciffically here:</div><div><br></div><div>if (!transmit(self, g_queue_peek_head (&priv->slist), now)) {</div><div>          closedown(self, ECONNABORTED);<br></div><div>          return FALSE;</div><div>        }</div><div><br></div><div>Now, this might sound ok, but the problem is that the transmit function does not account for EAGAIN or EWOULDBLOCK errors (which are not really fatal) and this created a very peculiar race condition that gave us a headache. Enable extended logs - problem gone. Add some sleep - problem gone. The reason for that is that if the fast retransmit happens to be when the socket is (temporarily) busy, our connection goes down. If you give sockets a tiny bit of time to flush - problem goes away.</div><div><br></div><div>So - digging deeper this problem was comming from:</div><div><br></div><div>agent/pseudotcp.c (transmit()):</div><div><br></div><div><div> /* Write out the packet. */</div><div>    wres = packet(self, seq, flags,</div><div>        segment->seq - priv->snd_una, nTransmit, now);</div></div><div><br></div><div>agent/pseudotcp.c (packet()):</div><div><br></div><div><div> wres = priv->callbacks.WritePacket(self, (gchar *) buffer.u8, len + HEADER_SIZE,</div><div>                                     priv->callbacks.user_data);</div></div><div><br></div><div>agent/agent.c (pseudo_tcp_socket_write_packet()):</div><div><br></div><div><div>if (nice_socket_send (sock, addr, len, buffer))</div><div>      return WR_SUCCESS;</div></div><div><br></div><div>socket/socket.c (nice_socket_send()):</div><div><br></div><div>ret = sock->send_messages (sock, to, &local_message, 1);<br></div><div><br></div><div>Now here from the function description I see that this function knows when the error is EWOULDBLOCK:</div><div><br></div><div><div>/* Convenience wrapper around nice_socket_send_messages(). Returns the number of</div><div> * bytes sent on success (which will be @len), zero if sending would block, or</div><div> * -1 on error. */</div></div><div><br></div><div>But the information is then lost / not taken into consideration. What I did was to put the write in a loop and if the error is EWOULDBLOCK just try again for the maximum 100 times (it's an arbitraty number, so far just for tests). So it now looks like that:</div><div><br></div><div><div>gssize</div><div>nice_socket_send (NiceSocket *sock, const NiceAddress *to, gsize len,</div><div>    const gchar *buf)</div><div>{</div><div>  GOutputVector local_buf = { buf, len };</div><div>  NiceOutputMessage local_message = { &local_buf, 1};</div><div>  gint ret         = 0;</div><div>  gint max_iter = 100;</div><div><br></div><div>  while (ret == 0 && max_iter > 0)</div><div>  {</div><div>    //</div><div>    // Send would block. Try a couple times more.</div><div>    //</div><div><br></div><div>    ret = sock->send_messages (sock, to, &local_message, 1);</div><div><br></div><div>    max_iter --;</div><div>  }</div><div><br></div><div>  if (ret == 1)</div><div>    return len;</div><div>  return ret;</div><div>}</div></div><div><br></div><div>And the problem is now completely gone. We can send big files and really large amounts of data between Windows, Linux and in mixed environments. Now of course this kind of solution might not be what you want, but I just wanted to signal a problem to which I think I found a cause and possible solution. Now you can address it in any fitting way you might think of.</div><div><br></div><div>If you have any thoughts on that, please share them.</div><div><br></div><div>Kind regards,</div><div>Radosław Kołodziejczyk.</div><div><br></div></div>