pgplus/bin/
pgplus/help_files/
pgplus/port_redirector/
pgplus/src/configure/makefiles/
/*
 * ident_server.c
 * Ident server for rfc1413 lookups
 * ---------------------------------------------------------------------------
 *
 * The majority of the code contained herein is Copyright 1995/1996 by
 * Neil Peter Charley.
 * Portions of the code (notably that for Solaris 2.x and BSD compatibility)
 * are Copyright 1996 James William Hawtin. Thanks also goes to James
 * for pointing out ways to make the code more robust.
 * ALL code contained herein is covered by one or the other of the above
 * Copyright's.
 *
 *       Distributed as part of Playground+ package with permission.
 */

char identserverc_rscid[] = "$Revision: 1.6 $";

#if defined(__STRICT_ANSI__)
 #include <features.h>
 #define __USE_POSIX
 #define __USE_BSD
 #define __USE_MISC 
#endif /* __STRICT_ANSI__ */

#include <unistd.h>
#if defined(HAVE_FILIOH)
 #include <sys/filio.h>
#endif /* HAVE_FILIOH */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/resource.h>

#include "include/config.h"
#include "include/player.h"
#include "include/fix.h"
#include "include/proto.h"
#include "include/ident.h"

/* Extern Function Prototypes */

/* Extern Variables */

#ifndef errno
extern int errno;
#endif

#if !defined(OSF)
 #if !defined(NetBSD) && defined(BSD) /* Check for NetBSD; prevent compilation error -- blimey */
  /* Missing BSD PROTOTYPES */
  extern int             setrlimit(int, struct rlimit *);
  extern int             getrlimit(int, struct rlimit *);
  extern int             setitimer(int, struct itimerval *, struct itimerval *);
  extern int             fclose();
  extern int             select();
  extern time_t          time(time_t *);
  extern int             connect();
  extern int             shutdown(int, int);
  extern int             socket(int, int, int);
  extern int             strftime(char *, int, char *, struct tm *);
  extern void            perror(char *);
  extern int             fflush();
  extern int             ioctl();
  extern int             fprintf();
  extern void            bzero(void *, int);
  extern void            bcopy(char *, char *, int);
  extern int             vfprintf(FILE *stream, char *format, ...);
 #endif /* BSD */
#else /* OSF */
 extern int              ioctl(int d, unsigned long request, void * arg);
#endif /* !OSF */

#if !defined(MALLOC)
 #define MALLOC(c) malloc(c)
#endif /* MALLOC */

#if !defined(FREE)
 #define FREE(c) free(c)
#endif /* FREE */


/* Local Function Prototypes */

void                     catch_sigterm(SIGTYPE);
void                     check_connections(void);
void                     check_requests(void);
void                     closedown_request(int slot);
void                     do_request(ident_request *id_req);
void                     logid(char *,...);  
void                     process_request(int slot);
void                     process_result(int slot);
void                     queue_request(ident_identifier id,
	struct sockaddr_in *local_sockadd, struct sockaddr_in *sockadd);
void                     take_off_queue(int freeslot);
void                     write_request(ident_request *id_req);

/* Local Variables */

#define BUFFER_SIZE 1024
char                     scratch[4096];
char                     req_buf[BUFFER_SIZE];
ident_request            idents_in_progress[MAX_IDENTS_IN_PROGRESS];
ident_request           *first_inq = NULL;
ident_request           *last_inq = NULL;
int                      debug = 0;
int                      status = 0;
int                      beats_per_second;
int                      req_size;

#define IDENT_STATUS_RUNNING 1
#define IDENT_STATUS_SHUTDOWN 2

int main(int argc, char *argv[])
{
	struct rlimit        rlp;
#if defined(USE_SIGACTION)
	struct sigaction     sigact;
#endif
	struct sockaddr_in   sadd;
	fd_set               fds_write;
	fd_set               fds_read;
	int                  i;
	struct timeval       timeout;
	time_t               now;

	getrlimit(RLIMIT_NOFILE, &rlp);
	rlp.rlim_cur = rlp.rlim_max;
	setrlimit(RLIMIT_NOFILE, &rlp);

	/* First things first, let the client know we're alive */
	write(1, IDENT_SERVER_CONNECT_MSG, strlen(IDENT_SERVER_CONNECT_MSG));

	/* Need this to keep in sync with the client side
	 *
	 * <start><ident_id><local_port><sin_family><s_addr><sin_port>
	 */
	req_size = sizeof(char) + sizeof(ident_identifier)
                            + sizeof(sadd.sin_addr.s_addr)
                            + sizeof(sadd.sin_port)
                            + sizeof(sadd.sin_family)
							+ sizeof(sadd.sin_addr.s_addr)
							+ sizeof(sadd.sin_port);

#if defined(DEBUG_IDENT)
	logid("ident", "Ident message size = %d", req_size);
#endif
	/* Set up signal handling */
#if defined(USE_SIGACTION)
 #if defined(HAVE_SIGEMPTYSET)
	sigemptyset(&(sigact.sa_mask));
 #else
	sigact.sa_mask = 0;
 #endif /* HAVE_SIGEMPTYSET */
 #if defined(__linux__)
	sigact.sa_restorer = (void *)NULL;
 #endif
	sigact.sa_handler = catch_sigterm;
	sigaction(SIGTERM, &sigact, (struct sigaction *)NULL);
	sigact.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL);
#else /* !USE_SIGACTION */
	signal(SIGTERM, catch_sigterm);
	signal(SIGPIPE, SIG_IGN);
#endif /* USE_SIGACTION */

#if defined(HAVE_BZERO)
	bzero(&idents_in_progress[0], MAX_IDENTS_IN_PROGRESS
					* sizeof(ident_request));
#else /* !HAVE_BZERO */
	memset(&idents_in_progress[0], 0,
		  MAX_IDENTS_IN_PROGRESS * sizeof(ident_request));
#endif /* HAVE_BZERO */
	for (i = 0 ; i < MAX_IDENTS_IN_PROGRESS ; i++)
	{
		idents_in_progress[i].fd = -1;
	}
	/* Now enter the main loop */
	status = IDENT_STATUS_RUNNING;
	while (status != IDENT_STATUS_SHUTDOWN)
	{
		if (1 == getppid())
		{
		/* If our parent is now PID 1 (init) the talker must have died without
		 * killing us, so we have no business still being here
		 *
		 * time to die...
		 */
			exit(0);
		}

		FD_ZERO(&fds_write);   /* These are for connection being established */
		FD_ZERO(&fds_read);    /* These are for a reply being ready */

		FD_SET(0, &fds_read);
		for (i = 0 ; i < MAX_IDENTS_IN_PROGRESS ; i++)
		{
			if (idents_in_progress[i].fd > 0)
			{
				if (idents_in_progress[i].flags & IDENT_CONNREFUSED)
				{
					process_result(i);
				} else if (!(idents_in_progress[i].flags & IDENT_CONNECTED))
				{
					FD_SET(idents_in_progress[i].fd, &fds_write);
				} else
				{
					FD_SET(idents_in_progress[i].fd, &fds_read);
				}
			} else
			{
				/* Free slot, so lets try to fill it */
				take_off_queue(i);
			}
		}

		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
		i = select(FD_SETSIZE, &fds_read, &fds_write, 0, &timeout);
		switch (i)
		{
		case -1:
#if defined(DEBUG_IDENT_TOO)
			 logid("ident", "ident: select failed: %s\n", strerror(errno));
#endif /* DEBUG_IDENT_TOO */
			break;
		case 0:
			break;
		default:
			for (i = 0 ; i < MAX_IDENTS_IN_PROGRESS ; i++)
			{
				if (idents_in_progress[i].fd == -1)
				{
					continue;
				}
				if (FD_ISSET(idents_in_progress[i].fd, &fds_write))
				{
					/* Has now connected, so send request */
					idents_in_progress[i].flags |= IDENT_CONNECTED;
					write_request(&idents_in_progress[i]);
				} else if (FD_ISSET(idents_in_progress[i].fd, &fds_read))
				{
					/* Reply is ready, so process it */
					idents_in_progress[i].flags |= IDENT_REPLY_READY;
					process_result(i);
				}
			}
			if (FD_ISSET(0, &fds_read))
			{
				check_requests();
			}
		}

		now = time(NULL);
		for (i = 0 ; i < MAX_IDENTS_IN_PROGRESS ; i++)
		{
			if (idents_in_progress[i].fd > 0)
			{
				if (now > (idents_in_progress[i].request_time + IDENT_TIMEOUT))
				{
					/* Request has timed out, whether on connect or reply */
					idents_in_progress[i].flags |= IDENT_TIMEDOUT;
					process_result(i);
				}
			}
		}
	}

	return 0;
}

/* Catch a SIGTERM, this means to shutdown */

void catch_sigterm(SIGTYPE)
{
	status = IDENT_STATUS_SHUTDOWN;
}

/* Check for requests from the client */

void check_requests(void)
{
	char                 msgbuf[129];
	int                  toread;
	int                  bread;
	static int           bufpos = 0;
	int                  i;

	ioctl(0, FIONREAD, &toread);
	if (toread <= 0)
	{
		return;
	}
	if (toread > 128)
	{
		toread = 128;
	}

	bread = read(0, msgbuf, toread);
	for (i = 0 ; i < bread ;)
	{
		req_buf[bufpos++] = msgbuf[i++];
		if (bufpos == req_size)
		{
			process_request(bufpos);
			bufpos = 0;
		}
	}
}

void process_request(int toread)
{
	int                  i;
	struct sockaddr_in   sockadd;
	struct sockaddr_in   local_sockadd;
	ident_identifier     ident_id;

	for (i = 0 ; i < toread ;)
	{
		switch (req_buf[i++])
		{
		case IDENT_CLIENT_SEND_REQUEST:
			memcpy(&ident_id, &req_buf[i], sizeof(ident_id));
			i += sizeof(ident_id);
			memcpy(&(local_sockadd.sin_addr.s_addr), &req_buf[i],
		 		sizeof(local_sockadd.sin_addr.s_addr));
			i += sizeof(local_sockadd.sin_addr.s_addr);
			memcpy(&(local_sockadd.sin_port), &req_buf[i],
				sizeof(local_sockadd.sin_port));
			i += sizeof(local_sockadd.sin_port);
			memcpy(&(sockadd.sin_family), &req_buf[i],
				sizeof(sockadd.sin_family));
			i += sizeof(sockadd.sin_family);
			memcpy(&(sockadd.sin_addr.s_addr), &req_buf[i],
				sizeof(sockadd.sin_addr.s_addr));
			i += sizeof(sockadd.sin_addr.s_addr);
			memcpy(&(sockadd.sin_port), &req_buf[i],
				sizeof(sockadd.sin_port));
			i += sizeof(sockadd.sin_port);

#if defined(DEBUG_IDENT_TOO)
			logid("ident",
				"Server: Id      = %d\n"
				"        Address = %08X:%d\n"
				"        To      = %08X:%d\n"
				"Bytes needed %d, Bytes to recieve %d\n",
				ident_id,
				(int) ntohl(sockadd.sin_addr.s_addr),
				ntohs(sockadd.sin_port),
				(int) ntohl(local_sockadd.sin_addr.s_addr),
				ntohs(local_sockadd.sin_port),
				i, toread);
#endif /* DEBUG_IDENT_TOO */

			queue_request(ident_id, &local_sockadd, &sockadd);
			break;
		case IDENT_CLIENT_CANCEL_REQUEST:
			memcpy(&ident_id, &req_buf[i], sizeof(ident_id));
			i += sizeof(ident_id);
			break;
		default:
#if defined(DEBUG_IDENT_TOO)
			logid("ident", "Ident_Server: Unknown message from client:"
							 " '%d'\n",
				req_buf[i]);
#endif /* DEBUG_IDENT_TOO */
			 break;
		}
	}
}


/* Queue up a request from the client and/or send it off */

void queue_request(ident_identifier id, struct sockaddr_in *local_sockadd,
	struct sockaddr_in *sockadd)
{
	ident_request       *new_id_req;

	new_id_req = (ident_request *) MALLOC(sizeof(ident_request));
	memset(new_id_req, 0, sizeof(ident_request));
	new_id_req->ident_id = id;
	memcpy(&(new_id_req->local_sockaddr), local_sockadd,
		sizeof(struct sockaddr_in));
	new_id_req->next = NULL;
	memcpy(&(new_id_req->sock_addr), sockadd, sizeof(struct sockaddr_in));
	if (!first_inq)
	{
		first_inq = new_id_req;
	} else if (!last_inq)
	{
		last_inq = new_id_req;
		first_inq->next = last_inq;
	} else
	{
		last_inq->next = new_id_req;
		last_inq = new_id_req;
	}
}

void take_off_queue(int freeslot)
{
	ident_request       *old;

	if (first_inq)
	{
		memcpy(&idents_in_progress[freeslot], first_inq, sizeof(ident_request));
		old = first_inq;
		first_inq = first_inq->next;
		FREE(old);
		do_request(&idents_in_progress[freeslot]);
	}
}

void do_request(ident_request *id_req)
{
	int                  dummy;
	int                  ret;
	struct sockaddr_in   sa;

#if defined(DEBUG_IDENT_TOO)
	logid("ident", "Server: Doing request - %d\n",
			  id_req->ident_id);
#endif /* DEBUG_IDENT_TOO */
	if (-1 == (id_req->fd = socket(PF_INET, SOCK_STREAM, 0)))
	{
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "Couldn't get new fd for request");
#endif /* DEBUG_IDENT_TOO */
		/* Erk, put on pending queue */
		queue_request(id_req->ident_id, &(id_req->local_sockaddr),
					&(id_req->sock_addr));
		return;
	}
	if (ioctl(id_req->fd, FIONBIO, (caddr_t)&dummy) < 0)
	{
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "Can't set non-blocking on request sock");
#endif /* DEBUG_IDENT_TOO */
		/* Do without? */
	}
	id_req->request_time = time(NULL);
	/* First bind to correct local address */
#if defined(__FreeBSD__)
	sa.sin_len = sizeof(sa);
#endif /* __FreeBSD__ */
	sa.sin_family = id_req->sock_addr.sin_family;
	sa.sin_port = htons(0);
	sa.sin_addr.s_addr = id_req->local_sockaddr.sin_addr.s_addr;
	ret = bind(id_req->fd, (struct sockaddr *)&sa, sizeof(sa));
	if (ret != 0)
	{
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "do_Request:bind() error \"%s\"\nAddress was: %s, errno = %d\n", strerror(errno), inet_ntoa(sa.sin_addr),
			errno);
#endif /* DEBUG_IDENT_TOO */
	}

	/* Now try and connect to remote address */
	sa.sin_addr.s_addr = id_req->sock_addr.sin_addr.s_addr;
	sa.sin_port = htons(IDENT_PORT);
	ret = connect(id_req->fd, (struct sockaddr *) &sa, sizeof(sa));
	if (ret != 0
#if defined(EINPROGRESS)
		 && errno != EINPROGRESS
#endif /* EINPROGRESS */
		)
	{
		if (errno == ECONNREFUSED)
		{
#if defined(DEBUG_IDENT_TOO)
			logid("ident", "ID %d, CONNREFUSED\n", id_req->ident_id);
#endif /* DEBUG_IDENT_TOO */
			id_req->flags |= IDENT_CONNREFUSED;
		} else
		{
#if defined(DEBUG_IDENT_TOO)
			logid("ident", "Error on connect, NOT CONNREFUSED, errno = %d",
				 errno);
#endif /* DEBUG_IDENT_TOO */
		}
#if defined(EINPROGRESS)
	} else if (errno != EINPROGRESS)
#else /* !EINPROGRESS */
	} else
#endif /* EINPROGRESS */
	{
		id_req->flags |= IDENT_CONNECTED;
		write_request(id_req);
	}
}

void write_request(ident_request *id_req)
{
#if defined(DEBUG_IDENT_TOO)
	logid("ident", "Server: write_request()...\n");
#endif
	sprintf(scratch, "%d, %d\n",
		ntohs(id_req->sock_addr.sin_port),
		ntohs(id_req->local_sockaddr.sin_port));
	if (-1 == write(id_req->fd, scratch, strlen(scratch)))
	{
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "Server: write() failed\n");
#endif
		id_req->flags |= IDENT_CONNREFUSED;
	} else
	{
		id_req->flags |= IDENT_WRITTEN;
	}

#if defined(DEBUG_IDENT_TOO)
	logid("ident", "Server: Sending request '%s'\n", scratch);
#endif /* DEBUG_IDENT_TOO */
}

/* Get a result from an identd and send it to the client in the
 * form:
 *
 * <SERVER_SEND_REPLY><ident_id><reply text>'\n'
 */

void process_result(int slot)
{
	char                 reply[BUFFER_SIZE];
	int                  bread;
	char                *s;
	char                *t = NULL;
	char                *reply_text = NULL;

	s = scratch;
	*s++ = IDENT_SERVER_SEND_REPLY;
	memcpy(s, &(idents_in_progress[slot].ident_id),
		sizeof(ident_identifier));
	s += sizeof(ident_identifier);
	strcpy(s, "<ERROR>");
	reply_text = s;
#if defined(DEBUG_IDENT_TOO)
	logid("ident", "Server: Processing result...\n");
#endif /* DEBUG_IDENT_TOO */
	if (idents_in_progress[slot].flags & IDENT_CONNREFUSED)
	{
		/* Connection was refused */
		strcpy(s, "<CONN-REFUSED>");
		t = strchr(s, '\0');
	} else if (!(idents_in_progress[slot].flags & IDENT_CONNECTED))
	{
		/* No connection was established */
		strcpy(s, "<CONN-FAILED>");
		t = strchr(s, '\0');
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "    Not Connected\n");
#endif /* DEBUG_IDENT_TOO */
	} else if (!(idents_in_progress[slot].flags & IDENT_WRITTEN))
	{
		/* Connection made but no message written */
		strcpy(s, "<DIDN'T-SEND>");
		t = strchr(s, '\0');
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "    Not Written\n");
#endif /* DEBUG_IDENT_TOO */
	} else if (!(idents_in_progress[slot].flags & IDENT_REPLY_READY))
	{
		/* Request written but didn't get reply before timeout */
		strcpy(s, "<TIMED-OUT>");
		t = strchr(s, '\0');
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "    Not Ready for Read\n");
#endif /* DEBUG_IDENT_TOO */
	} else
	{
		/* Got a reply, phew! */
		/* BUFFER_SIZE - 20 (== 1004 atm) should be plenty as RFC1413
		 * specifies that a USERID reply should not have a user id field
		 * of more than 512 octets.
		 * Additionally RFC1413 specifies that:
		 * "Clients should feel free to abort the connection if they
		 *  receive 1000 characters without receiving an <EOL>"
		 *
		 * NB: <EOL> ::= "015 012"  ; CR-LF End of Line Indicator
		 * I assume that under C this will be converted to '\n'
		 */
#if defined(HAVE_BZERO)
		bzero(reply, BUFFER_SIZE);
#else /* !HAVE_BZERO */
		memset(reply, 0, BUFFER_SIZE);
#endif /* HAVE_BZERO */
		bread = read(idents_in_progress[slot].fd, reply, BUFFER_SIZE - 20);
		reply[bread] = '\0';

		/* Make sure the reply is '\n' terminated */
		t = strchr(reply, '\n');
		if (t)
		{
			t++;
#if defined(HAVE_BZERO)
	 bzero(t, &reply[BUFFER_SIZE] - t - 1);
#else
	 memset(t, 0, &reply[BUFFER_SIZE] - t - 1);
#endif /* HAVE_BZERO */
		} else
		{
			reply[1001] = '\n';
#if defined(HAVE_BZERO)
	 bzero(&reply[1002], BUFFER_SIZE - 1002 - 1);
#else
	 memset(&reply[1002], 0, BUFFER_SIZE - 1002 - 1);
#endif /* HAVE_BZERO */
		}
#if defined(DEBUG_IDENT_TOO)
		logid("ident", "Server: Got reply '%s'\n",
			  reply);
#endif /* DEBUG_IDENT_TOO */

		if (!(t = strstr(reply, "USERID")))
		{
			/* In this case the reply MUST be in the form:
			 *
			 * <port-pair> : ERROR : <error-type>
			 *
			 * (see RFC1413, if a later one exists for the ident protocol
			 *  then this code should be updated)
			 *
			 * We will reply to our client with the '<error-type>' text
			 *
			 */
#if defined(DEBUG_IDENT)
			logid("ident_ids", "SERVER: slot %d, ident_id %d, ACTUAL reply '%s'",
				slot, idents_in_progress[slot].ident_id, reply);
#endif /* DEBUG_IDENT */
			 if (!(t = strstr(reply, "ERROR")))
			 {
			 /* Reply doesn't contain 'USERID' *or* 'ERROR' */
				 strcpy(s, "<ERROR>");
			 } else
			 {
#if defined(DEBUG_IDENT_TOO)
				 logid("ident", "Reply: '%s'", t);
#endif /* DEBUG_IDENT_TOO */
				t = strchr(t, ':');
			 /*
			  * <port-pair> : ERROR : <error-type>
			  *                     ^
			  *             t-------|
			  */
				 if (!t)
				 {
					 /* Couldn't find the colon after 'ERROR' */
					 strcpy(s, "<ERROR>");
				 } else
				 {
					 *s++ = '<';
				 }
			}
		} else
		{
			/* Got a reply of the form:
			 *
			 * <port-pair> : USERID : <opsys-field> : <user-id>
			 *               ^
			 *         t-----|
			 *
			 * We will reply to our client with the '<user-id>' text
			 *
			 */

#if defined(DEBUG_IDENT)
			logid("ident_ids", "SERVER: slot %d, ident_id %d, ACTUAL reply '%s'",
			  slot, idents_in_progress[slot].ident_id, reply);
			 logid("ident", "Reply: '%s'", t);
#endif /* DEBUG_IDENT */
			t = strchr(t, ':');
			if (!t)
			{
			/* Couldn't find the : after USERID 
			 *
			 * <port-pair> : USERID : <opsys-field> : <user-id>
			 *                      ^
			 *           t----------|
			 */
				strcpy(s, "<ERROR>");
			} else
			{
				t++;
				t = strchr(t, ':');
				if (!t)
				{
				/* Couldn't find the : after <opsys-field>
				 *
				 * <port-pair> : USERID : <opsys-field> : <user-id>
				 *                                      ^
				 *                           t----------|
				 */
					strcpy(s, "<ERROR>");
				}
			}
		}
		if (t)
		{
		/* t is now at the : before the field we want to return */
		/* Skip the : */
			t++;
		/* Skip any white space */
			while ((*t == ' ' || *t == '\t') && *t != '\0')
			{
				t++;
			}
			if (*t != '\0')
			{
			/* Found start of the desired text */
				sprintf(s, "%s", t);
				t = strchr(s, '\0');
				t--;
				/* The reply SHOULD be '\n' terminated (RFC1413) */
				while (*t == ' ' || *t == '\t' || *t == '\n' || *t == '\r')
				{
					t--;
				}
				/* t now at end of text we want */
				/* Move forward to next char */
				t++;
				/* If char before s is a '<' we put it there ourselves to wrap
				 * an 'ERROR' return in <>. So we need to put the > on the
				 * end
				 */
				if (*(s - 1) == '<')
				{
					*t++ = '>';
				}
			} else
			{
				strcpy(s, "<ERROR>");
				t = 0;
			}
		}
	}
	/* Make sure t is pointing to the NULL terminator of the string */
	if (!t)
	{
		t = strchr(s, '\0');
	}
	/* A newline terminates the message */
	*t++ = '\n';
	*t = '\0';
	/* Now actually send the reply to the client */
	write(1, scratch, (t - scratch));
#if defined(DEBUG_IDENT)
	logid("ident_ids", "SERVER: slot %d, ident_id %d, reply '%s'",
		slot, idents_in_progress[slot].ident_id, reply_text);
#endif /* DEBUG_IDENT */
#if defined(DEBUG_IDENT_TOO)
	*(t + 1) = '\0';
	logid("ident", "    Sending reply '%s' of %d bytes\n", s, (t - scratch));
#endif /* DEBUG_IDENT_TOO */
	closedown_request(slot);
}

void closedown_request(int slot)
{
	shutdown(idents_in_progress[slot].fd, 2);
	close(idents_in_progress[slot].fd);
	idents_in_progress[slot].fd = -1;
}


/* log using stdarg variable length arguments */

void logid(char *str, ...)
{
	va_list              args;
	FILE                *fp;
	char                *fmt;
	struct tm           *tim;
	char                 the_time[256];
	char                 fname[21];
	time_t               current_time;

	va_start(args, str);

	current_time = time(0);
	tim = localtime(&current_time);
	strftime((char *)&the_time, 255, "%H:%M:%S %Z - %d/%m/%Y - ", tim);
	sprintf(fname, "logs/%s.log", str);

	fp = fopen(fname, "a");
	if (!fp)
	{
		fprintf(stderr, "Eek! Can't open file to log: %s\n", fname);
		return;
	}
	fprintf(fp, "%s", the_time);
	fmt = va_arg(args, char *);
	vfprintf(fp, fmt, args);
	va_end(args);
	fprintf(fp, "\n");
	fclose(fp);
}