#include "dfeed.h"

/*
	SOCKET sk; 
	char *out;
	char *in;
	int inat;
	int outat,outlen;
	int type;
	int sending;
	int gothead;
	int keepalive;
	void (*fn_read)(struct CHAN *this); 
	void (*fn_write)(struct CHAN *this);
	void (*fn_close)(struct CHAN *this);
	struct CHAN *next;
	Head *head;

*/
static Chan *clist;
int chan_ingetc(Chan *c)
{
	int k;
	if (c->in==NULL) return 0;
	k =  c->in[c->inget];
	if (k!=0) c->inget++;
	return k;
}
Chan *chan_getlist(void)
{
	return clist;
}
void chan_setread(Chan *c, void (*fn_read)(struct CHAN *this, void *p1), void *p1)
{
	c->fn_read = fn_read;	
	c->p1 = p1;
}
void chan_setwrite(Chan *c, void (*fn_read)(struct CHAN *this, void *p1), void *p1)
{
	c->fn_write = fn_read;	
	c->p1 = p1;
}
void chan_setclose(Chan *c, void (*fn_read)(struct CHAN *this, void *p1), void *p1)
{
	c->fn_close = fn_read;	
	c->p1 = p1;
}
void chan_open(Chan *c, char *to, char *bind)
{
	char bf[BFSZ];
	char *s;
	int port=119;
	ncpy(bf,to,200);
	s = strchr(bf,':');
	if (s!=NULL) {
		*s = 0;
		port = atoi(s+1);
	}
	imsg("Open chan=%p (%s) port (%d) bind (%s) \n",c,to,port,bind);
	c->sk = tcp_openx(to,port,bind);
	if (c->sk==INVALID_SOCKET) {
		imsg("Open failed to (%s) (%s) \n",to,tcperror());
	}
}	
int chan_write(Chan *c, char *bf, int len)
{
	int r;
	if (c->sk==INVALID_SOCKET) return -1;

	stats_start(S_XWRITE);	
	r = tcp_write(c->sk,bf,len);
	if (r>0) dmsg_data(bf,r);
	stats_end(S_XWRITE);
	if (r<0) {
		imsg("Write failed (%s)\n",tcperror());
		socket_close(c->sk); 
		c->sk = INVALID_SOCKET;
	}
	return r;
}
int chan_write_s(Chan *c, char *bf)
{
	return chan_write(c,bf,strlen(bf));
}
int chan_read(Chan *c, char *bf, int len)
{
	int r;
	if (c->sk==INVALID_SOCKET) return -1;
	r = tcp_read(c->sk,bf,len);
	if (r<0) {
		socket_close(c->sk); 
		c->sk = INVALID_SOCKET;
	}
	return r;
}
int chan_isopen(Chan *c)
{
	if (c->sk==INVALID_SOCKET) return FALSE;
	return TRUE;
}
/* brian */
int chan_isreallyopen(Chan *c)
{
        fd_set readfd,writefd,exceptfd;
	int nc;
	struct timeval timeout;

        timeout.tv_sec = 0;
        timeout.tv_usec = 0;
        FD_ZERO(&readfd);
        FD_ZERO(&writefd);
        FD_ZERO(&exceptfd);
	FD_SET(c->sk,&readfd);		
        nc = select(FD_SETSIZE,&readfd,&writefd,&exceptfd,&timeout);
	emsg("********** CHAN_ISREALLYOPEN nc:%d\n",nc);
	emsg("********** FD_ISSET(c->sk,&exceptfd) %d\n",FD_ISSET(c->sk,&exceptfd));
	if (nc>0) return TRUE;
	return FALSE;
}
void chan_instart(Chan *c)
{	
	c->inget = 0;
}
void chan_add(Chan *c)
{
	c->next = clist;
	clist = c;
}
void chan_idle(void)
{
	Chan *last=NULL;
	Chan *c,*next;

	for (c=clist;c!=NULL;c=next) {
		next = c->next;
		if ((c->sk==INVALID_SOCKET) && (c->canclose)) {
			imsg("Removing channel %p from list\n",c);
			if (last==NULL) clist = c->next;
			else last->next = c->next;
			if (c->in!=NULL) free(c->in);
			free(c);
		} else {
			last = c;	
		}
	}
	/* should free other structures if defined, e.g. head */	


}
void chan_loop(void)
{
	chan_idle();
	dfeed_idle();
}
int chan_close(Chan *c)
{
	imsg("Closing chan %p\n",c);
	if (c->sk!=INVALID_SOCKET) socket_close(c->sk);
	c->sk = INVALID_SOCKET;
	return TRUE;
}
void chan_exit(void)
{
	Chan *c;
	for (c=clist;c!=NULL;c=c->next) {
		chan_close(c);
	}
	chan_idle();	
}
void chan_setcode(Chan *c, int r)
{
	c->code = r;
}
int chan_getcode(Chan *c)
{
	return c->code;
}
Chan *chan_new(void)
{
	Chan *c = malloc(sizeof(Chan));
	memset(c,0,sizeof(Chan));
	c->sk = INVALID_SOCKET;
	c->canclose = FALSE;
	c->next = clist;
	clist = c;
	return c;
}
int chan_init(void)
{
	tcp_startup();
	return TRUE;
}
void chan_setsending(Chan *c, int t)
{
	c->sending = t;
}
void chan_sethost(Chan *c, int h)
{
	c->hostid = h;
}
Chan *chan_findhost(int h)
{
	Chan *c;
	for (c=clist;c!=NULL;c=c->next) {
		if (c->hostid==h) return c;
	}
	return NULL;

}
void chan_run(void)
{
	int r;


	r = tcp_waitchans(clist);
}
void chan_listen_read(Chan *c)
{
}
void chan_release(Chan *c)
{
	c->canclose = TRUE;
}