
/*
    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 <stdlib.h>
#include "fsystem.h"
#include "logging.h"
#include "connect.h"

static connection conn[MAX_CONNECT];

int alloc_conn()
{
	connection* p;
	struct ncp_reply* buf;
	
	if ((buf=malloc(BUF_SIZE))==NULL) return -1;
	/* first connection #0 is reserved */
	for(p=conn+1;p<conn+MAX_CONNECT;p++)
	{
		if (!p->alloc)
		{
			int* h;
			for(h=p->fh;h<p->fh+MAX_FILE_CONN;h++) {*h=-1;}
			for(h=p->dh;h<p->dh+MAX_DIR_CONN;h++) {*h=-1;}
			for(h=p->sh;h<p->sh+MAX_SEARCH_CONN;h++) {*h=-1;}
			p->dh[0]=0; /* special root dh */
			p->alloc=1;
			p->logged_obj=NULL;
			p->out_buf=buf;
			p->stat_gsalloc=p->stat_gshit=p->stat_lsalloc=p->stat_lshit=0;
/*			*(p->search_path)=0;*/
			return p-conn;
		}
	}
	free(buf);
	return -1;
}

byte* get_conn_buf(connection* c)
{
	return (byte*)(c->out_buf+1);
}

void free_conn(connection* c)
{
	int h;
	int nf=0,ns=0,ndp=0,ndt=0;
	
	if (!c->alloc) return;
	/* dealloc dir & file handles */
	for(h=0;h<MAX_FILE_CONN;h++)
	{
		if (c->fh[h]!=-1) 
		{
			free_file(c,h);
			nf++;
		}
	}
	/* dir handle 0 is special (don't free) */
	if (c->dh[0]!=0) LPRINTF(LL_ERROR,("free_conn: dh[0]!=0 !?!\n"));
	for(h=1;h<MAX_DIR_CONN;h++) 
	{
		if (c->dh[h]!=-1) 
		{
			dir_handle* dh=get_dir_handle(c,h);
			if (dh!=NULL)
			{
				if (dh->permanent)
					ndp++;
				else
					ndt++;
			}
			free_dir(c,h);
		}
	}
	for(h=0;h<MAX_SEARCH_CONN;h++)
	{
		if (c->sh[h]!=-1)
		{
			free_search(c,h);
			ns++;
		}
	}
	LPRINTF(LL_INFO,("free_con: %i files: %i search: %i dirs temp: %i perm: %i\n",get_conn_id(c),nf,ns,ndt,ndp));
	LOG_START(LL_INFO)
	fprint_conn_stat(log_file,c);
	fprint_fs_stat(log_file);
	LOG_END
	c->alloc=0;
	c->logged_obj=NULL;
	free(c->out_buf);
}

int get_conn_id(connection* c)
{
	return c-conn;
}

connection* get_conn(int id)
{
	if (id>=MAX_CONNECT) {LPRINTF(LL_ERROR,("get_conn: %i>=MAX_CONNECT\n",id));return conn;}
	return conn+id;
}

void fprint_conn_stat(FILE* file,connection* c)
{
	fprintf(file,"search stat: global: alloc %i hit %i local: alloc %i hit %i\n",c->stat_gsalloc,c->stat_gshit,c->stat_lsalloc,c->stat_lshit);
}

void notify_unreachable(IPXNet net)
{
	connection* c;
	
	LOG_START(LL_INFO)
	log_printf("network ");
	ipx_fprint_network(log_file,net);
	log_printf(" is unreachable\n");
	LOG_END
	
	for(c=conn;c<conn+MAX_CONNECT;c++)
	{
		if (c->alloc && c->peer_addr.sipx_network==net)
		{
			if (c->logged_obj!=NULL) 
			{
				LPRINTF(LL_INFO,("logout (unreachable network): %s conn: %i\n",c->logged_obj->name.name,get_conn_id(c)));
			}
			else
			{
				LPRINTF(LL_INFO,("connection %i closed (unreachable network)\n",get_conn_id(c)));
			}
			free_conn(c);
		}
	}
}

void init_connections()
{
	connection* p;
	for(p=conn;p<conn+MAX_CONNECT;p++)
	{
		p->alloc=0;
	}
	LPRINTF(LL_INFO,("sizeof(conn)=%i\n",sizeof(conn)));
	LPRINTF(LL_INFO,("connections initialized\n"));
}

void done_connections()
{
	connection* p;
	for(p=conn;p<conn+MAX_CONNECT;p++)
	{
		if (p->alloc)
		{
			LPRINTF(LL_INFO,("closing connection %i\n",p-conn));
			free_conn(p);
		}
	}
	LPRINTF(LL_INFO,("connections shutdown\n"));
}
