/*
  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