/* Low level socket routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#include "mbuf.h"
#include "netuser.h"
#include "socket.h"
#include "usock.h"
#include "lapb.h"
#include "tcp.h"
#include "nr4.h"
#include "config.h"

/* Convert a socket (address + port) to an ascii string of the form
 * aaa.aaa.aaa.aaa:ppppp
 */
char *
psocket(p)
void *p;	/* Pointer to structure to decode */
{
#if	defined(AX25) || defined(NETROM)
	char tmp[11];
#endif
	static char buf[30];
	union sp sp;
	struct socket socket;

	sp.p = p;
	switch(sp.sa->sa_family){
	case AF_LOCAL:
		buf[0] = '\0';
		break;
	case AF_INET:
		socket.address = sp.in->sin_addr.s_addr;
		socket.port = sp.in->sin_port;
		strcpy(buf,pinet(&socket));
		break;
#ifdef	AX25
	case AF_AX25:
		pax25(tmp,sp.ax->ax25_addr);
		if(strlen(sp.ax->iface) != 0)
			sprintf(buf,"%s on %s",tmp,sp.ax->iface);
		else
			strcpy(buf,tmp);
		break;
#endif
#ifdef	NETROM
	case AF_NETROM:
		pax25(tmp,sp.nr->nr_addr.user);
		sprintf(buf,"%s @ ",tmp);
		pax25(tmp,sp.nr->nr_addr.node);
		strcat(buf,tmp);
		break;
#endif
	}
	return buf;
}

/* Return ASCII string giving reason for connection closing */
char *
sockerr(s)
int s;	/* Socket index */
{
	register struct usock *up;

	if((up = itop(s)) == NULLUSOCK){
		errno = EBADF;
		return Badsocket;
	}
	switch(up->type){
#ifdef	AX25
	case TYPE_AX25I:
		if(up->cb.ax25 != NULLAX25)
			return NULLCHAR;	/* nothing wrong */
		return Axreasons[up->errcodes[0]];
#endif
#ifdef	NETROM
	case TYPE_NETROML4:
		if(up->cb.nr4 != NULLNR4CB)
			return NULLCHAR;	/* nothing wrong */
		return Nr4reasons[up->errcodes[0]];
#endif
	case TYPE_TCP:
		if(up->cb.tcb != NULLTCB)
			return NULLCHAR;	/* nothing wrong */		
		return Tcpreasons[up->errcodes[0]];
	default:
		errno = EOPNOTSUPP;	/* not yet, anyway */
		return NULLCHAR;
	}
}
/* Get state of protocol. Valid only for connection-oriented sockets. */
char *
sockstate(s)
int s;		/* Socket index */
{
	register struct usock *up;

	if((up = itop(s)) == NULLUSOCK){
		errno = EBADF;
		return NULLCHAR;
	}
	if(up->cb.p == NULLCHAR){
		errno = ENOTCONN;
		return NULLCHAR;
	}
	switch(up->type){
	case TYPE_TCP:
		return Tcpstates[up->cb.tcb->state];
#ifdef	AX25
	case TYPE_AX25I:
		return Ax25states[up->cb.ax25->state];
#endif
#ifdef	NETROM
	case TYPE_NETROML4:
		return Nr4states[up->cb.nr4->state];
#endif
	default:
		/* Datagram sockets don't have state */
		errno = EOPNOTSUPP;
		return NULLCHAR;
	}
	/*NOTREACHED*/
}
/* Convert a socket index to an internal user socket structure pointer */
struct usock *
itop(s)
register int s;	/* Socket index */
{
	register struct usock *up;

	s -= SOCKBASE;
	if(s < 0 || s >= Nusock)
		return NULLUSOCK;

	up = &Usock[s];

	if(up->type == NOTUSED)
		return NULLUSOCK;
	return up;
}

void
st_garbage(red)
int red;
{
	int i;
	struct usock *up;

	for(i=SOCKBASE;i<SOCKBASE+Nusock;i++){
		up = &Usock[i];
		if(up->type == TYPE_LOCAL_STREAM)
			mbuf_crunch(&up->cb.local->q);
	}
}

