private void Work() { byte[] buffer = new byte[8192]; int selectMaximumTime = -1; while (true) { try { // ReadSet: We want Select to return when either a new connection has arrived or when there is incoming socket data List <Socket> socketsReadSet = OpenSockets.Keys.ToList(); if (tcpListenSocket != null && tcpListenSocket.IsBound) { socketsReadSet.Add(tcpListenSocket); } if (unixListenSocket != null && unixListenSocket.IsBound) { socketsReadSet.Add(unixListenSocket); } Socket.Select(socketsReadSet, null, null, selectMaximumTime); foreach (Socket sock in socketsReadSet) { // In case this sock is in the read set just because a connection has been accepted, // it must be a listen socket and we should accept the new queued connections if (sock == tcpListenSocket || sock == unixListenSocket) { BeginAcceptNewConnections(sock); continue; } // Get some data on the socket FosRequest fosRequest; if (!OpenSockets.TryGetValue(sock, out fosRequest)) { // On socket shutdown we may find a socket returned by Select that has already been removed // from OpenSockets from a normal connection closing continue; } // Read data. The socket could have been disposed here. // We need to remove it from our internal bookkeeping if that's the case. int bytesRead; try { bytesRead = sock.Receive(buffer, SocketFlags.None); } catch (ObjectDisposedException) { // This can happen if the application closed the socket but this loop // still had time to find the request in OpenSockets before it got removed. //TODO: This can also mean the socket was closed by the other side, so we need a way to differentiate them continue; } catch (SocketException e) { if (SocketHelper.IsConnectionAbortedByTheOtherSide(e)) { OnAbruptSocketClose(sock, fosRequest); continue; } else if (e.SocketErrorCode == SocketError.Shutdown) { // Similar to the ObjectDisposedException above, but we tried to call Receive // after the socket had been closed but still not marked as disposed (this should be rare) // Give it another chance in the loop continue; } else { throw; } } if (bytesRead == 0) { // This could indicate both a socket closed prematurely or // still the fact that the application closed the socket correctly and we received a bogus // amount of bytes read (it seems to be possible, at least with Mono). So: // If it was closed by the application it will be removed from OpenSockets // If it was closed prematurely by the webserver it will throw an error next time continue; } // Feed the request's record factory // An exception thrown here means an implementer did not catch the application's exception. It is indeed a server error. try { foreach (var rec in fosRequest.FeedBytes(buffer, 0, bytesRead)) { OnRecordBuilt(fosRequest, rec); } } catch (Exception e) { // Log and end request if (Logger != null) { Logger.LogServerError(e, "The server did not handle an exception thrown by the application"); } fosRequest.Dispose(); continue; } } } catch (Exception e) { if (Logger != null) { Logger.LogServerError(e, "Exception would end the data receiving loop. This is extremely bad. Please file a bug report."); } } } }