/* ** send_queued_write ** This is called when there is a chance that some output would ** be possible. This attempts to empty the send queue as far as ** possible, and then if any data is left, a write is rescheduled. */ void send_queued_write(struct Client *to) { int retlen; #ifndef NDEBUG struct hook_io_data hdata; #endif struct dbuf_block *first; /* ** Once socket is marked dead, we cannot start writing to it, ** even if the error is removed... */ if (IsDead(to) || IsSendqBlocked(to)) return; /* no use calling send() now */ /* Next, lets try to write some data */ if (dbuf_length(&to->localClient->buf_sendq)) { #ifndef NDEBUG hdata.connection = to; #endif do { first = to->localClient->buf_sendq.blocks.head->data; #ifdef HAVE_LIBCRYPTO if(IsSSL(to)) { retlen = safe_SSL_write(to, first->data, first->size); printf("safe_ssl_write: writing: %s\n", first->data); printf("safe_ssl_write: %d written\n", retlen); if (retlen <= 0) break; } else #endif if ((retlen = send(to->localClient->fd, first->data, first->size, 0)) <= 0) break; #ifndef NDEBUG hdata.data = ((struct dbuf_block *) to->localClient->buf_sendq.blocks.head->data)->data; hdata.len = retlen; hook_call_event("iosend", &hdata); #endif dbuf_delete(&to->localClient->buf_sendq, retlen); /* We have some data written .. update counters */ to->localClient->sendB += retlen; me.localClient->sendB += retlen; if (to->localClient->sendB > 1023) { to->localClient->sendK += (to->localClient->sendB >> 10); to->localClient->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ } else if (me.localClient->sendB > 1023) { me.localClient->sendK += (me.localClient->sendB >> 10); me.localClient->sendB &= 0x03ff; }
/* * deliver_it * * Attempt to send a sequence of bytes to the connection. * Returns * < 0 Some fatal error occurred, (but not EWOULDBLOCK). * his return is a request to close the socket and clean up the link. * >= 0 No real error occurred, returns the number of bytes actually * transferred. EWOULDBLOCK and other similar conditions should be mapped * to zero return. * Upper level routine will have to decide what to do with * those unwritten bytes... * *NOTE* alarm calls have been preserved, so this should work equally * well whether blocking or non-blocking mode is used... */ int deliver_it (aClient * client_p, char *str, int len) { int retval; aClient *acpt = client_p->acpt; #ifdef DEBUGMODE writecalls++; #endif #ifdef USE_SSL if (IsSSL (client_p) && client_p->ssl) retval = safe_SSL_write (client_p, str, len); else #endif retval = send (client_p->fd, str, len, 0); /* * Convert WOULDBLOCK to a return of "0 bytes moved". This * should occur only if socket was non-blocking. Note, that all is * Ok, if the 'write' just returns '0' instead of an error and * errno=EWOULDBLOCK. */ if (retval < 0 && #ifdef _WIN32 (WSAGetLastError () == WSAEWOULDBLOCK || WSAGetLastError () == WSAENOBUFS) #else (errno == EWOULDBLOCK || errno == EAGAIN || errno == ENOBUFS) #endif ) { retval = 0; client_p->flags |= FLAGS_BLOCKED; set_fd_flags (client_p->fd, FDF_WANTWRITE); return (retval); /* Just get out now... */ } else if (retval > 0) { if (client_p->flags & FLAGS_BLOCKED) { client_p->flags &= ~FLAGS_BLOCKED; unset_fd_flags (client_p->fd, FDF_WANTWRITE); } } #ifdef DEBUGMODE if (retval < 0) { writeb[0]++; Debug ((DEBUG_ERROR, "write error (%s) to %s", strerror (errno), client_p->name)); } else if (retval == 0) writeb[1]++; else if (retval < 16) writeb[2]++; else if (retval < 32) writeb[3]++; else if (retval < 64) writeb[4]++; else if (retval < 128) writeb[5]++; else if (retval < 256) writeb[6]++; else if (retval < 512) writeb[7]++; else if (retval < 1024) writeb[8]++; else writeb[9]++; #endif if (retval > 0) { client_p->sendB += retval; me.sendB += retval; if (client_p->sendB > 1023) { client_p->sendK += (client_p->sendB >> 10); client_p->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ }