// // Receive and return bytes up to and including the bytes specified by pContentArg & ContentLength. // extern bool sockReceiveUntilContent(sock * pSock, void * pBufferArg, size_t BufferSize, const void * pContentArg, size_t ContentLength, size_t * pBytesReceived) { char * pBuffer = (char * ) pBufferArg; char * pContent = (char * ) pContentArg; const int BufferBytesAvailable = RECEIVE_BUFFER_SIZE-pSock->m_BytesReceived; if (pSock->m_Closed) return false; if (BufferBytesAvailable > 0) { recvsize_t NewBytesReceived = recv(pSock->m_Socket, pSock->m_pReceiveBuffer+pSock->m_BytesReceived, BufferBytesAvailable, 0); if (WouldBlock(pSock, NewBytesReceived)) { // // If we would block, then there are no bytes available to read, but there // may be bytes already in the receive buffer, so we need to continue to // allow those bytes to be consumed. // NewBytesReceived = 0; } else if (CheckReceiveError(pSock, NewBytesReceived)) { return false; } pSock->m_BytesReceived += NewBytesReceived; } if (pSock->m_BytesReceived >= ContentLength) { const char * pFirst = pSock->m_pReceiveBuffer; const char * pLast = pFirst + pSock->m_BytesReceived - ContentLength; // // Search for content bytes in the receive buffer. // for (; pFirst <= pLast; pFirst++) { if (memcmp(pFirst, pContent, ContentLength) == 0) { // Consume... const size_t Span = oosmos_Min((pFirst-pSock->m_pReceiveBuffer)+ContentLength, BufferSize); memcpy(pBuffer, pSock->m_pReceiveBuffer, Span); *pBytesReceived = Span; // Shift... pSock->m_BytesReceived -= Span; memcpy(pSock->m_pReceiveBuffer, pSock->m_pReceiveBuffer+Span, pSock->m_BytesReceived); return true; } } return false; } return false; }
extern bool sockReceive(sock * pSock, void * pBuffer, size_t BufferSize, size_t * pBytesReceived) { if (pSock->m_Closed) return false; if (pSock->m_BytesReceived < BufferSize) { recvsize_t NewBytesReceived = recv(pSock->m_Socket, pSock->m_pReceiveBuffer+pSock->m_BytesReceived, RECEIVE_BUFFER_SIZE-pSock->m_BytesReceived, 0); if (WouldBlock(pSock, NewBytesReceived)) { // // If we would block, then there are no bytes available to read, but there // may be bytes already in the receive buffer, so we need to continue to // allow those bytes to be consumed. // NewBytesReceived = 0; } else if (CheckReceiveError(pSock, NewBytesReceived)) { return false; } pSock->m_BytesReceived += NewBytesReceived; } if (pSock->m_BytesReceived > 0) { // Consume... const size_t Span = oosmos_Min(pSock->m_BytesReceived, BufferSize); memcpy(pBuffer, pSock->m_pReceiveBuffer, Span); *pBytesReceived = Span; // Shift... pSock->m_BytesReceived -= Span; memcpy(pSock->m_pReceiveBuffer, pSock->m_pReceiveBuffer+Span, pSock->m_BytesReceived); return true; } return false; }
FollowUp ListeningSocket::Perform (const Notification & n) { FollowUp retr; if (do_shutdown) { retr.Remove=true; return retr; } for (;;) { struct sockaddr_storage addr; socklen_t len=sizeof(addr); auto socket=accept( this->socket, reinterpret_cast<struct sockaddr *>(&addr), &len ); // Check for failure if (socket==-1) { // Was the failure just because // the operation would block? if (WouldBlock()) break; // Were we interrupted? if (WasInterrupted()) continue; // Actually an error Raise(); } // Increment statistic ++retr.Accepted; auto ep=GetEndpoint(&addr); SmartPointer<Connection> conn; try { conn=SmartPointer<Connection>::Make( socket, ep.IP, ep.Port, this->ep.IP, this->ep.Port, this->ep.Receive, this->ep.Disconnect ); } catch (...) { // Make sure the socket gets // closed close(socket); throw; } // Fire off a callback to handle this // incoming connections #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" retr.Action.Add([ this, conn=std::move(conn), socket ] (SmartPointer<ChannelBase> channel) mutable { FollowUp f; // Should this connection be allowed? if (this->ep.Accept) { try { // If the connection is not admitted, // return at once, the connection will // automatically be dropped by the Socket // RAII container if (!this->ep.Accept(AcceptEvent{ conn->IP(), conn->Port(), this->ep.IP, this->ep.Port })) return f; } catch (...) { // Consider throwing the same thing // as returning false return f; } } // The connection is allowed ++f.Incoming; // Fire the connect handler if (this->ep.Connect) { ConnectEvent event; event.Conn=conn; try { this->ep.Connect(std::move(event)); // Ignore user exceptions } catch (...) { } } // Add the connection f.Add=Channel{ socket, std::move(conn).Convert<ChannelBase>() }; return f; }); #pragma GCC diagnostic pop } return retr; }