/* * Outgoing data service routine. May be called multiple times. */ static void sendOutgoingService(MaQueue *q) { MaConn *conn; MaResponse *resp; int written; int errCode; conn = q->conn; resp = conn->response; if (conn->sock == 0) { return; } /* * Loop doing non-blocking I/O until blocked or all the packets received are written. */ while (1) { /* * Rebuild the iovector only when the past vector has been completely written. Simplifies the logic quite a bit. */ written = 0; if (q->ioIndex == 0 && buildSendVec(q) <= 0) { break; } /* * Write the vector and file data. Exclude the file entry in the io vector. */ written = (int) mprSendFileToSocket(conn->sock, resp->file, q->ioPos, q->ioCount, q->iovec, q->ioIndex, NULL, 0); mprLog(q, 5, "Send connector written %d", written); if (written < 0) { errCode = mprGetError(); if (errCode == EAGAIN || errCode == EWOULDBLOCK) { maRequestWriteBlocked(conn); break; } if (errCode == EPIPE || errCode == ECONNRESET) { maDisconnectConn(conn); } else { mprLog(conn, 7, "mprSendFileToSocket failed, errCode %d", errCode); maDisconnectConn(conn); } freeSentPackets(q, MAXINT); break; } else if (written == 0) { /* Socket is full. Wait for an I/O event */ maRequestWriteBlocked(conn); break; } else if (written > 0) { resp->bytesWritten += written; freeSentPackets(q, written); adjustSendVec(q, written); } } if (q->ioCount == 0 && q->flags & MA_QUEUE_EOF) { maCompleteRequest(conn); } }
PUBLIC void httpSendOutgoingService(HttpQueue *q) { HttpConn *conn; HttpTx *tx; MprFile *file; MprOff written; int errCode; conn = q->conn; tx = conn->tx; conn->lastActivity = conn->http->now; if (tx->finalizedConnector) { return; } if (tx->flags & HTTP_TX_NO_BODY) { httpDiscardQueueData(q, 1); } if ((tx->bytesWritten + q->ioCount) > conn->limits->txBodySize && conn->limits->txBodySize < HTTP_UNLIMITED) { httpLimitError(conn, HTTP_ABORT | HTTP_CODE_REQUEST_TOO_LARGE | ((tx->bytesWritten) ? HTTP_ABORT : 0), "Http transmission aborted. Exceeded max body of %lld bytes", conn->limits->txBodySize); if (tx->bytesWritten) { httpFinalizeConnector(conn); return; } } tx->writeBlocked = 0; if (q->ioIndex == 0) { buildSendVec(q); } /* No need to loop around as send file tries to write as much of the file as possible. If not eof, will always have the socket blocked. */ file = q->ioFile ? tx->file : 0; written = mprSendFileToSocket(conn->sock, file, q->ioPos, q->ioCount, q->iovec, q->ioIndex, NULL, 0); if (written < 0) { errCode = mprGetError(); if (errCode == EAGAIN || errCode == EWOULDBLOCK) { /* Socket full, wait for an I/O event */ tx->writeBlocked = 1; } else { if (errCode != EPIPE && errCode != ECONNRESET && errCode != ECONNABORTED && errCode != ENOTCONN) { httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "sendConnector: error, errCode %d", errCode); } else { httpDisconnect(conn); } httpFinalizeConnector(conn); } httpTrace(conn, "connection.io.error", "error", "msg:'Connector write error',errno:%d", errCode); } else if (written > 0) { tx->bytesWritten += written; freeSendPackets(q, written); adjustSendVec(q, written); } if (q->first && q->first->flags & HTTP_PACKET_END) { httpFinalizeConnector(conn); httpGetPacket(q); } }