/*
* NetworkStreamSupportTCPGlue.c
*
* Demers, November 6, 1989 3:35:46 pm PST
*
* C support for TCP network streams in PCR
*/

#include "xr/Errno.h"
#include "xr/UIO.h"

#include <sys/types.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/sockio.h>

#include <poll.h>

#define LISTEN�KLOG 5


static int
XR←PIDForFildes();


static int
XR←NSSTCPConditionStreamFildes(sock)
XR𡤏ildes sock;
{
int ans;
int one = 1;

ans = XR←SetSockOpt(sock, SOL←SOCKET, SO←OOBINLINE, &one, (sizeof one));
if( ans >= 0 )
ans = XR←SetSockOpt(sock, IPPROTO←TCP, TCP←NODELAY, &one, (sizeof one));

/* This should go away when XR is fixed to do the SETOWN at socket */
/* creation. */
if( ans >= 0 )
ans = XR�ntl(sock, F←SETOWN, XR←PIDForFildes(sock));

if( ans >= 0 )
ans = XR←SetGetTimeout(sock, XR←WAIT𡤏OREVER←MSEC);
if( ans >= 0 )
ans = XR←SetPutTimeout(sock, XR←WAIT𡤏OREVER←MSEC);
if( ans >= 0 )
ans = XR←SetGetBlocking(sock, XR←UIO𡤋LOCKING←SOME�TA);
if( ans >= 0 )
ans = XR←SetPutBlocking(sock, XR←UIO𡤋LOCKING𡤊LL�TA);
return ans;
}

int howFailed = 0;
int failedErrno = 0;

XR𡤏ildes
XR←NSSTCPCreateStreamFildes(inap, timeout)
struct sockaddr←in *inap;
unsigned timeout;
{
XR𡤏ildes sock = XR←nullFildes;
int one = 1;
int ans;
# define GoToBad(x) { howFailed = (x); goto Bad; }

sock = XR←Socket(PF←INET, SOCK←STREAM, IPPROTO←TCP);
if( sock == XR←nullFildes ) GoToBad(1);
ans = XR←SetPutTimeout( sock, timeout );
if( ans < 0 ) GoToBad(2);
ans = XR𡤌onnect( sock, inap, (sizeof (*inap)) );
if( ans < 0 ) GoToBad(3);
ans = XR←NSSTCPConditionStreamFildes(sock);
if( ans < 0 ) GoToBad(4);
return sock;

Bad:
failedErrno = XR←GetErrno();
if( sock != XR←nullFildes ) {
int savedErrno = XR←GetErrno();
(void) XR𡤌lose(sock);
XR←SetErrno(savedErrno);
}
return XR←nullFildes;
}


int
XR←NSSTCPDestroyStreamFildes(sock, abort)
XR𡤏ildes sock;
bool abort;
{
# define NO←SEND←OR←RECV 2
struct linger sol;
int ans = 0;

if( abort ) {
sol.l←onoff = FALSE; /* dont linger */
sol.l←linger = 0; /* for 0 msec */
ans = XR←SetSockOpt(sock, SOL←SOCKET, SO←LINGER, &sol, (sizeof sol));
if( ans == -1 ) XR𡤌onsoleMsg("Can't set DONTLINGER on socket %d, err %d\n",
sock, XR←GetErrno() );
}
if( ans != -1 ) {
ans = XR←Shutdown(sock, NO←SEND←OR←RECV);
if( ans == -1 ) XR𡤌onsoleMsg("Can't shutdown socket %d, err %d\n",
sock, XR←GetErrno() );
}
ans = XR𡤌lose(sock);
if( ans == -1 ) XR𡤌onsoleMsg("Can't close socket %d, err %d\n",
sock, XR←GetErrno() );
return ans;
}


int
XR←NSSTCPAddressesFromStreamFildes(sock, local, remote)
XR𡤏ildes sock;
struct sockaddr←in *local;
struct sockaddr←in *remote;
{
int addrLen;
struct sockaddr←in al, ar;
int ans;

addrLen = (sizeof ar);
ans = XR←GetPeerName(sock, &ar, &addrLen);
if( ans < 0 ) return(-1);
if( addrLen != (sizeof ar) ) { XR←SetErrno(EINVAL); return(-1); }
addrLen = (sizeof al);
ans = XR←GetSockName(sock, &al, &addrLen);
if( ans < 0 ) return(-1);
if( addrLen != (sizeof al) ) { XR←SetErrno(EINVAL); return(-1); }
*local = al;
*remote = ar;
return 0;
}


int
XR←NSSTCPSend(sock, buf, nBytes)
XR𡤏ildes sock;
char *buf;
int nBytes;
{
return XR←Write(sock, buf, nBytes);
}


int
XR←NSSTCPSendAttn(sock, attnType)
XR𡤏ildes sock;
int attnType;
{
int ans;
char buf;

if( attnType & 0xffffff00 ) {
XR←SetErrno(EINVAL);
return(-1);
}
buf = attnType;
ans = XR←Send(sock, &buf, (sizeof buf), MSG←OOB);
return ans;
}


int
XR←NSSTCPReceive(sock, buf, nBytes)
XR𡤏ildes sock;
char *buf;
int nBytes;
{
return XR←Read(sock, buf, nBytes);
}


int
XR←NSSTCPInputReady(sock, timeout)
XR𡤏ildes sock;
int timeout;
{
struct pollfd fds;
int ans;

fds.fd = sock;
fds.events = POLLIN;
fds.revents = 0;

ans = XR←Poll(&fds, 1, timeout);
if( ans > 0 ) return ((fds.revents & POLLIN) ? 1 : 0);
if( ans == 0 ) return 0;
if( XR←GetErrno() == ETIMEDOUT ) return 0; /* workaround for PCR bug */
return ans;
}


int
XR←NSSTCPWaitOOBAttn(sock, timeout)
XR𡤏ildes sock;
int timeout;
{
struct pollfd fds;
int ans;

fds.fd = sock;
fds.events = POLLPRI;
fds.revents = 0;

ans = XR←Poll(&fds, 1, timeout);
if( (ans > 0) && (fds.revents & POLLPRI) ) return 0;
if( ans == 0 ) {
XR←SetErrno(ETIMEDOUT);
return (-1);
}
return ans;
}


int
XR←NSSTCPAtIBAttn(sock)
XR𡤏ildes sock;
{
int ans;
int atMarkResult = 0;

ans = XR←IOCtl(sock, SIOCATMARK, &atMarkResult);
return ( (ans >= 0) ? atMarkResult : ans );
}


XR𡤏ildes
XR←NSSTCPCreateListenerFildes(inap)
struct sockaddr←in *inap;
{
XR𡤏ildes listener = XR←nullFildes;
int ans;

listener = XR←Socket(PF←INET, SOCK←STREAM, IPPROTO←TCP);
if( listener == XR←nullFildes ) goto Bad;
ans = XR𡤋ind(listener, inap, (sizeof (*inap)));
if( ans < 0 ) goto Bad;
ans = XR←Listen(listener, LISTEN�KLOG);
if( ans < 0 ) goto Bad;
return listener;

Bad:
if( listener != XR←nullFildes ) {
int savedErrno = XR←GetErrno();
(void) XR𡤌lose(listener);
XR←SetErrno(savedErrno);
}
return XR←nullFildes;
}


int
XR←NSSTCPDestroyListenerFildes(listener)
XR𡤏ildes listener;
{
return XR𡤌lose(listener);
}


int
XR←NSSTCPAddressFromListenerFildes(listener, local)
XR𡤏ildes listener;
struct sockaddr←in *local;
{
int addrLen;
struct sockaddr←in al;
int ans;

addrLen = (sizeof al);
ans = XR←GetSockName(listener, &al, &addrLen);
if( ans < 0 ) return(-1);
if( addrLen != (sizeof al) ) { XR←SetErrno(EINVAL); return(-1); }
*local = al;
return 0;
}


XR𡤏ildes
XR←NSSTCPAccept(listener)
XR𡤏ildes listener;
{
XR𡤏ildes sock;
struct sockaddr←in a;
int alen = (sizeof a);
int ans;

sock = XR�pt(listener, &a, &alen);
ans = XR←NSSTCPConditionStreamFildes(sock);
if( ans < 0 ) return XR←nullFildes;
return sock;
}


/*
* For debugging
*/

struct sockaddr←in *
XR�←NewSockAddr(a, b, c, d, p)
int a, b, c, d, p;
{
struct sockaddr←in *sin;
unsigned w;

sin = (struct sockaddr←in *) XR�lloc( sizeof(struct sockaddr←in), 1);
sin->sin�mily = AF←INET;
sin->sin←port = htons(((short)(p)));
w = (a << 24) + (b << 16) + (c << 8) + d;
sin->sin�r.s�r = htonl(w);
return sin;
}

char *
XR�←StringFromSockAddr(sin)
struct sockaddr←in *sin;
{
char *s;
unsigned w;

s = (char *)XR←malloc(64);
w = ntohl(sin->sin�r.s�r);
(void)XR←SPrintF(s, "%d.%d.%d.%d:%d",
(w >> 24) & 0xff, (w >> 16) & 0xff, (w >> 8) & 0xff, w & 0xff,
ntohs(sin->sin←port) );
return s;
}
/*
* The rest of this file should go away when the XR system is fixed
* to do the SETOWN at socket-creation time.
* The following declarations are copied from "xr/ThreadsBackdoor.h"
*/

#define XR←IOPOrder struct XR←IOPOrderRep *

typedef struct XR←IOPERep {
unsigned iope←index; /* index of this iope in table */
unsigned iope←pid;  /* UNIX pid, 0 if IOPE not in use */
} * XR←IOPE;



/*
* The following declarations are copied from "xr/UIOPrivate.h"
* to let XR←uioArea be a common symbol.
*/


typedef unsigned XR�State;

#define XR� struct XR�Rep *
#define XR� struct XR�Rep *

typedef struct XR�Rep {
int fde←index;
unsigned fde←gen;   /* generation number */
int fde←opCnt;   /* # ops in progress */
XR�State fde←state;
XR←IOPE fde←owner;   /* IOP that owns descriptor */
int fde←ownerIndex;   /* owner's descriptor index */
XR�Kind fde�Kind;  /* kind of associated descriptors */
     /* (same as kind of IOP) */
XR←UIOBlocking fde←getBlocking; /* input blocking behavior */
XR←UIOBlocking fde←putBlocking; /* output blocking behavior */
XR←Ticks fde←getTimeout;  /* input timeout */
XR←Ticks fde←putTimeout;  /* output timeout */
bool fde←inputPri;   /* poll input => pri */
XR� fde�   /* -> cached fdc or NIL */
struct XR𡤌VRep fde𡤊vail;  /* wait here e.g. for FDC */
#undef XR�
} * XR�

#define XR←UIOWDBuf struct XR←UIOWDBufRep *

typedef struct XR←UIOAreaRep {

/* monitor locks */
 struct XR←MLRep uioa←ml;
 struct XR←MLRep uioa←wdML;

/* PCR working directory cache */
XR←UIOWDBuf uioa←pcrWD;

/* IOPs */
 XR←IOPE uioa←iope;
 int uioa←numIOPE;
# define XR←UIOIOPELimit \
 (&(XR←uioArea->uioa←iope[XR←uioArea->uioa←numIOPE]))

/* FDEs */
 XR� uioa�
 int uioa←numFDE;
# define XR←UIOFDELimit \
 (&(XR←uioArea->uioa�[XR←uioArea->uioa←numFDE]))

/*
* the rest of the structure is not needed ...
*/

} * XR←UIOArea;


XR←UIOArea XR←uioArea;  /* readonly, shared */


/*
* The entire content of this file:
*/

static int
XR←PIDForFildes(fd)
XR𡤏ildes fd;
{
if( XR←uioArea == NIL ) /* not an XR system */ return XR←GetPID();
return (XR←uioArea->uioa�[fd].fde←owner->iope←pid);
}