/* File: write_data.c Description: write data to a client or the server */ #include #include #include "proxy_protos.h" void write_data ( struct kevent *ke, struct mdata *md ) { qdata *q; int w; int to; int rm = 0; int qe = 0; GSList *l; char *ct[2] = { "CLIENT", "SERVER" }; /* if this is the first data we're reading over this connection, record the start time. */ if ( md->r[ke->ident].bytes_written == 0 ) { gettimeofday(&md->r[ke->ident].ti_write,NULL); } /* are we writing to the server or a client? */ to = md->r[ke->ident].type; /* is our connection still open? */ if ( !(ke->flags & EV_EOF) && md->r[ke->ident].status == FD_OPEN ) { /* get the output queue. */ l = md->r[ke->ident].queue; /* pop off its head. */ if ( (q = g_slist_nth_data(l,0)) ) { /* write that chunk of data to the destination. */ w = write(ke->ident,q->s + q->p,q->l - q->p); if ( w > 0 ) q->p += w; rm = q->l - q->p; /* record the time */ gettimeofday(&md->r[ke->ident].tf_write,NULL); if ( w >= 0 ) { if ( md->verbose ) { log_msg(md,"[fd %d] write to %s [%d]", ke->ident, ct[to], w); } md->bytes_written[to] += w; md->r[ke->ident].bytes_written += w; } if ( rm == 0 ) { /* shift the written element off the queue. */ md->r[ke->ident].queue = g_slist_next(l); g_slist_free_1(l); chunk_free(q,md->m); } /* is there anything left on the queue? */ qe = !g_slist_nth_data(md->r[ke->ident].queue,0); /* if so, add another EV_ONESHOT EVFILT_WRITE event. */ if ( !qe ) { if ( kevent(md->kq,ke,1,NULL,0,NULL) == -1 ) { perror("kevent"); md->kevent_errors++; } } } else { /* the queue is empty. */ qe = 1; } } else { /* the write connection has been closed. empty the output queue and close the read connection. */ if ( md->r[ke->ident].queue ) g_slist_foreach(md->r[ke->ident].queue,chunk_free,md->m); /* close the read connection */ qe = 1; md->r[md->r[ke->ident].relay].status = FD_CLOSE; } /* check the relay */ w = md->r[ke->ident].relay; /* if our read connection has been closed and the output queue is empty, we must now close the write connection. */ if ( md->r[w].status == FD_CLOSE && qe ) { /* get rid of the queue entirely. */ if ( md->r[w].queue ) { g_slist_free(md->r[w].queue); md->r[w].queue = NULL; } /* explicitly close the write connection if necessary. */ if ( md->r[ke->ident].status == FD_OPEN ) { log_msg(md,"write_data to %s [%d]: %s [%d] closed: closing %d", ct[to], ke->ident, ct[!to], w, ke->ident); close_connection(md,ke->ident); } } }