/** * Attempts to write a series of buffers to a socket in *one* system call so that they are * sent as one packet. * @param socket the socket to write to * @param buf0 the first buffer * @param buf0len the length of data in the first buffer * @param count number of buffers * @param buffers an array of buffers to write * @param buflens an array of corresponding buffer lengths * @return completion code, especially TCPSOCKET_INTERRUPTED */ int Socket_putdatas(int socket, char* buf0, int buf0len, int count, char** buffers, int* buflens) { unsigned long bytes = 0L; iobuf iovecs[5]; int rc = TCPSOCKET_INTERRUPTED, i, total = buf0len; FUNC_ENTRY; if (!Socket_noPendingWrites(socket)) { Log(LOG_SEVERE, -1, "Trying to write to socket %d for which there is already pending output", socket); rc = SOCKET_ERROR; goto exit; } for (i = 0; i < count; i++) total += buflens[i]; iovecs[0].iov_base = buf0; iovecs[0].iov_len = buf0len; for (i = 0; i < count; i++) { iovecs[i+1].iov_base = buffers[i]; iovecs[i+1].iov_len = buflens[i]; } if ((rc = Socket_writev(socket, iovecs, count+1, &bytes)) != SOCKET_ERROR) { if (bytes == total) rc = TCPSOCKET_COMPLETE; else { int* sockmem = (int*)malloc(sizeof(int)); Log(TRACE_MIN, -1, "Partial write: %ld bytes of %d actually written on socket %d", bytes, total, socket); #if defined(OPENSSL) SocketBuffer_pendingWrite(socket, NULL, count+1, iovecs, total, bytes); #else SocketBuffer_pendingWrite(socket, count+1, iovecs, total, bytes); #endif *sockmem = socket; ListAppend(s.write_pending, sockmem, sizeof(int)); FD_SET(socket, &(s.pending_wset)); rc = TCPSOCKET_INTERRUPTED; } } exit: FUNC_EXIT_RC(rc); return rc; }
/* No SSL_writev() provided by OpenSSL. Boo. */ int SSLSocket_putdatas(SSL* ssl, int socket, char* buf0, int buf0len, int count, char** buffers, int* buflens) { int rc = 0; int i; char *ptr; iobuf iovec; int sslerror; FUNC_ENTRY; iovec.iov_len = buf0len; for (i = 0; i < count; i++) iovec.iov_len += buflens[i]; ptr = iovec.iov_base = (char *)malloc(iovec.iov_len); memcpy(ptr, buf0, buf0len); ptr += buf0len; for (i = 0; i < count; i++) { memcpy(ptr, buffers[i], buflens[i]); ptr += buflens[i]; } SSL_lock_mutex(&sslCoreMutex); if ((rc = SSL_write(ssl, iovec.iov_base, iovec.iov_len)) == iovec.iov_len) rc = TCPSOCKET_COMPLETE; else { sslerror = SSLSocket_error("SSL_write", ssl, socket, rc); if (sslerror == SSL_ERROR_WANT_WRITE) { int* sockmem = (int*)malloc(sizeof(int)); Log(TRACE_MIN, -1, "Partial write: incomplete write of %d bytes on SSL socket %d", iovec.iov_len, socket); SocketBuffer_pendingWrite(socket, ssl, 1, &iovec, iovec.iov_len, 0); *sockmem = socket; ListAppend(s.write_pending, sockmem, sizeof(int)); FD_SET(socket, &(s.pending_wset)); rc = TCPSOCKET_INTERRUPTED; iovec.iov_base = NULL; /* don't free it because it hasn't been completely written yet */ } else rc = SOCKET_ERROR; } SSL_unlock_mutex(&sslCoreMutex); if (iovec.iov_base) free(iovec.iov_base); FUNC_EXIT_RC(rc); return rc; }