/*
File: write_data.c
Description: write data to a client or the server
*/
#include <stdio.h>
#include <unistd.h>
#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);
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1