
/*
    LinuxWare daemon - Netware like server for Linux

    Copyright (C) 1994, 1995  Ales Dryak <e-mail: A.Dryak@sh.cvut.cz>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include "global.h"
#include "logging.h"
#include "wdog.h"

void ipx_wdog_dump(WatchDogPacket* buf,int size)
{
	ipx_wdog_fdump(stdout,buf,size);
}

void ipx_wdog_fdump(FILE* file,WatchDogPacket* buf,int size)
{
	if (size!=sizeof(WatchDogPacket))
	{
		fprintf(file,"Invalid WDOG size %i\n",size);
		return;
	}
	fprintf(file,"connection: %i\nsignature character: %c\n",buf->cid,buf->sign_char);
}

void wdog_send(connection* c,char sign_char)
{
	WatchDogPacket buf;
	struct sockaddr_ipx station_addr;

	station_addr=c->peer_addr;
	station_addr.sipx_port=htons(IPX_WDOG_PORT(c));
	station_addr.sipx_type=IPX_USER_PTYPE;
	buf.cid=get_conn_id(c);
	buf.sign_char=sign_char;

	LOG_START(LL_DEBUG)
	log_printf("Sending WDOG packet to: ");
	ipx_fprint_saddr(log_file,&station_addr);
	log_printf("\n");
	ipx_wdog_fdump(log_file,&buf,sizeof(buf));
	LOG_END
	
	if (sendto(wdog_sock,(char*)&buf,sizeof(buf),
		0,(struct sockaddr*)&station_addr,sizeof(station_addr))==-1)
	{
		if (errno==ENETUNREACH)
		{
			notify_unreachable(station_addr.sipx_network);
			return;
		}
		LPRINTF(LL_ERROR,("WDOG sendto: %s\n",strerror(errno)));
	}
}

void handle_wdog(WatchDogPacket* pkt,int size,struct sockaddr_ipx* sipx)
{
	connection* c;
	if (size!=sizeof(*pkt))
	{
		LPRINTF(LL_ERROR,("WDOG packet invalid size\n"));
		return;
	}
	if (pkt->cid<MAX_CONNECT && (c=get_conn(pkt->cid))->alloc &&
	    sipx->sipx_network==c->peer_addr.sipx_network &&
	    ipx_node_equal(sipx->sipx_node,c->peer_addr.sipx_node) &&
	    ntohs(sipx->sipx_port)==IPX_WDOG_PORT(c))
	
	{
		switch (pkt->sign_char)
		{
			case IPX_WDOG_SESSION_VALID:
				c->wdog_timer=c->timer=0;break;
			case IPX_WDOG_NO_VALID_SESSION:
				if (c->logged_obj!=NULL) 
					LPRINTF(LL_INFO,("logout (invalid session): %s conn: %i\n",c->logged_obj->name.name,get_conn_id(c)));
				free_conn(c);
				break;
			case IPX_WDOG_POOL_INACTIVE:
				LPRINTF(LL_INFO,("Received pool WDOG packet\n"));
				break;	
			default:	
				LPRINTF(LL_ERROR,("WDOG packet invalid signature character %c\n",pkt->sign_char));
		}
	}
}

void init_wdog()
{
	struct sockaddr_ipx wdog_addr;
	
	wdog_sock=socket(AF_IPX,SOCK_DGRAM,PF_IPX);
	if(wdog_sock==-1)
	{
		LPRINTF(LL_FATAL,("WDOG socket: %s\n",strerror(errno)));
		exit(1);
	}
	
	wdog_addr=my_addr;
	wdog_addr.sipx_port=IPX_AUTO_PORT;
	wdog_addr.sipx_type=IPX_USER_PTYPE;
	if(bind(wdog_sock,(struct sockaddr*)&wdog_addr,sizeof(wdog_addr))==-1)
	{
		LPRINTF(LL_FATAL,("bind - WDOG: %s\n",strerror(errno)));
		exit(1);
	}
	LPRINTF(LL_INFO,("WDOG initialized\n"));
}

void done_wdog()
{
	close(wdog_sock);
	LPRINTF(LL_INFO,("WDOG shutdown\n"));
}
