home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3
/
hamradioversion3.0examsandprograms1992.iso
/
misc
/
9q920411
/
nrsock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-11
|
9KB
|
450 lines
#include "global.h"
#include "mbuf.h"
#include "ax25.h"
#include "netrom.h"
#include "nr4.h"
#include "socket.h"
#include "usock.h"
static void autobind __ARGS((struct usock *up));
static void s_nrcall __ARGS((struct nr4cb *cb,int cnt));
static void s_nscall __ARGS((struct nr4cb *cb,int old,int new));
static void s_ntcall __ARGS((struct nr4cb *cb,int cnt));
int
so_n3_sock(up,protocol)
struct usock *up;
int protocol;
{
up->cb.rnr = raw_nr((char)protocol);
strcpy(up->eol,AX_EOL);
return 0;
}
int
so_n4_sock(up,protocol)
struct usock *up;
int protocol;
{
strcpy(up->eol,AX_EOL);
return 0;
}
int
so_n4_listen(up,backlog)
struct usock *up;
int backlog;
{
struct sockaddr_nr *local;
int s;
s = up - Usock + SOCKBASE;
if(up->name == NULLCHAR)
autobind(up);
local = (struct sockaddr_nr *)up->name;
up->cb.nr4 = open_nr4(&local->nr_addr,NULLNRADDR,
backlog ? AX_SERVER:AX_PASSIVE,s_nrcall,s_ntcall,s_nscall,s);
return 0;
}
int
so_n3_conn(up)
struct usock *up;
{
if(up->name != NULLCHAR)
autobind(up);
return 0;
}
int
so_n4_conn(up)
struct usock *up;
{
struct sockaddr_nr *local,*remote;
struct nr4cb *nr4;
int s;
s = up - Usock + SOCKBASE;
if(up->name != NULLCHAR)
autobind(up);
local = (struct sockaddr_nr *)up->name;
remote = (struct sockaddr_nr *)up->peername;
up->cb.nr4 = open_nr4(&local->nr_addr,&remote->nr_addr,
AX_ACTIVE,s_nrcall,s_ntcall,s_nscall,s);
/* Wait for the connection to complete */
while((nr4 = up->cb.nr4) != NULLNR4CB && nr4->state != NR4STCON){
if(up->noblock){
errno = EWOULDBLOCK;
return -1;
} else if((errno = pwait(up)) != 0){
return -1;
}
}
if(nr4 == NULLNR4CB){
/* Connection probably already exists */
free(up->peername);
up->peername = NULLCHAR;
errno = ECONNREFUSED;
return -1;
}
return 0;
}
int
so_n3_recv(up,bpp,from,fromlen)
struct usock *up;
struct mbuf **bpp;
char *from;
int *fromlen;
{
int cnt;
struct raw_nr *rnr;
struct sockaddr_nr *remote;
struct nr3hdr n3hdr;
while((rnr = up->cb.rnr) != NULLRNR
&& rnr->rcvq == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return -1;
} else if((errno = pwait(up)) != 0){
return -1;
}
}
if(rnr == NULLRNR){
/* Connection went away */
errno = ENOTCONN;
return -1;
}
*bpp = dequeue(&rnr->rcvq);
ntohnr3(&n3hdr,bpp);
cnt = len_p(*bpp);
if(from != NULLCHAR && fromlen != NULLINT
&& *fromlen >= sizeof(struct sockaddr_nr)){
remote = (struct sockaddr_nr *)from;
remote->nr_family = AF_NETROM;
/* The callsign of the local user is not part of
NET/ROM level 3, so that field is not used here */
memcpy(remote->nr_addr.node,n3hdr.source,AXALEN);
*fromlen = sizeof(struct sockaddr_nr);
}
return cnt;
}
int
so_n4_recv(up,bpp,from,fromlen)
struct usock *up;
struct mbuf **bpp;
char *from;
int *fromlen;
{
struct nr4cb *nr4;
while((nr4 = up->cb.nr4) != NULLNR4CB
&& (*bpp = recv_nr4(nr4,(int16)0)) == NULLBUF){
if(up->noblock){
errno = EWOULDBLOCK;
return -1;
} else if((errno = pwait(up)) != 0){
return -1;
}
}
if(nr4 == NULLNR4CB){
/* Connection went away */
errno = ENOTCONN;
return -1;
}
return (*bpp)->cnt;
}
int
so_n3_send(up,bp,to)
struct usock *up;
struct mbuf *bp;
char *to;
{
struct sockaddr_nr *remote;
if(len_p(bp) > NR4MAXINFO) {
free_p(bp);
errno = EMSGSIZE;
return -1;
}
if(to != NULLCHAR) {
remote = (struct sockaddr_nr *)to;
} else if(up->peername != NULLCHAR) {
remote = (struct sockaddr_nr *)up->peername;
} else {
free_p(bp);
errno = ENOTCONN;
return -1;
}
/* The NETROM username is always ignored in outgoing traffic */
nr_sendraw(remote->nr_addr.node,up->cb.rnr->protocol,
up->cb.rnr->protocol,bp);
return 0;
}
int
so_n4_send(up,bp,to)
struct usock *up;
struct mbuf *bp;
char *to;
{
struct nr4cb *nr4;
if((nr4 = up->cb.nr4) == NULLNR4CB) {
free_p(bp);
errno = ENOTCONN;
return -1;
}
if(len_p(bp) > NR4MAXINFO){ /* reject big packets */
free_p(bp);
errno = EMSGSIZE;
return -1;
}
send_nr4(nr4,bp);
while((nr4 = up->cb.nr4) != NULLNR4CB && nr4->nbuffered >= nr4->window){
if(up->noblock){
errno = EWOULDBLOCK;
return -1;
} else if((errno = pwait(up)) != 0){
errno = EINTR;
return -1;
}
}
if(nr4 == NULLNR4CB){
errno = EBADF;
return -1;
}
return 0;
}
int
so_n3_qlen(up,rtx)
struct usock *up;
int rtx;
{
int len;
switch(rtx){
case 0:
len = len_q(up->cb.rnr->rcvq);
break;
case 1:
len = 0;
}
return len;
}
int
so_n4_qlen(up,rtx)
struct usock *up;
int rtx;
{
int len;
switch(rtx){
case 0:
len = len_p(up->cb.nr4->rxq) + len_p(up->obuf);
break;
case 1: /* Number of packets, not bytes */
len = len_q(up->cb.nr4->txq);
if(up->obuf != NULLBUF)
len++;
break;
}
return len;
}
int
so_n4_kick(up)
struct usock *up;
{
if(up->cb.nr4 == NULLNR4CB){
errno = ENOTCONN;
return -1;
}
kick_nr4(up->cb.nr4);
return 0;
}
int
so_n4_shut(up,how)
struct usock *up;
int how;
{
switch(how){
case 0:
case 1: /* Attempt regular disconnect */
disc_nr4(up->cb.nr4);
break;
case 2: /* Blow it away */
reset_nr4(up->cb.nr4);
up->cb.nr4 = NULLNR4CB;
break;
}
return 0;
}
int
so_n3_close(up)
struct usock *up;
{
del_rnr(up->cb.rnr);
return 0;
}
int
so_n4_close(up)
struct usock *up;
{
if(up->cb.nr4 != NULLNR4CB){
/* Tell the TCP_CLOSED upcall there's no more socket */
up->cb.nr4->user = -1;
disc_nr4(up->cb.nr4);
}
return 0;
}
/* Issue an automatic bind of a local NETROM address */
static void
autobind(up)
struct usock *up;
{
struct sockaddr_nr local;
int s;
s = up - Usock + SOCKBASE;
local.nr_family = AF_NETROM;
memcpy(local.nr_addr.user,Mycall,AXALEN);
memcpy(local.nr_addr.node,Mycall,AXALEN);
bind(s,(char *)&local,sizeof(struct sockaddr_nr));
}
/* NET/ROM receive upcall routine */
static void
s_nrcall(cb,cnt)
struct nr4cb *cb;
int cnt;
{
/* Wake up anybody waiting for data, and let them run */
psignal(itop(cb->user),1);
pwait(NULL);
}
/* NET/ROM transmit upcall routine */
static void
s_ntcall(cb,cnt)
struct nr4cb *cb;
int cnt;
{
/* Wake up anybody waiting to send data, and let them run */
psignal(itop(cb->user),1);
pwait(NULL);
}
/* NET/ROM state change upcall routine */
static void
s_nscall(cb,old,new)
struct nr4cb *cb;
int old,new;
{
int s,ns;
struct usock *up,*nup,*oup;
union sp sp;
s = cb->user;
oup = up = itop(s);
if(new == NR4STDISC && up != NULLUSOCK){
/* Clean up. If the user has already closed the socket,
* then up will be null (s was set to -1 by the close routine).
* If not, then this is an abnormal close (e.g., a reset)
* and clearing out the pointer in the socket structure will
* prevent any further operations on what will be a freed
* control block. Also wake up anybody waiting on events
* related to this cb so they will notice it disappearing.
*/
up->cb.nr4 = NULLNR4CB;
up->errcodes[0] = cb->dreason;
}
if(new == NR4STCON && old == NR4STDISC){
/* Handle an incoming connection. If this is a server cb,
* then we're being handed a "clone" cb and we need to
* create a new socket structure for it. In either case,
* find out who we're talking to and wake up the guy waiting
* for the connection.
*/
if(cb->clone){
/* Clone the socket */
ns = socket(AF_NETROM,SOCK_SEQPACKET,0);
nup = itop(ns);
ASSIGN(*nup,*up);
cb->user = ns;
nup->cb.nr4 = cb;
cb->clone = 0; /* to avoid getting here again */
/* Allocate new memory for the name areas */
nup->name = mallocw(sizeof(struct sockaddr_nr));
nup->peername = mallocw(sizeof(struct sockaddr_nr));
/* Store the new socket # in the old one */
up->rdysock = ns;
up = nup;
s = ns;
} else {
/* Allocate space for the peer's name */
up->peername = mallocw(sizeof(struct sockaddr_nr));
/* Store the old socket # in the old socket */
up->rdysock = s;
}
/* Load the addresses. Memory for the name has already
* been allocated, either above or in the original bind.
*/
sp.p = up->name;
sp.nr->nr_family = AF_NETROM;
ASSIGN(sp.nr->nr_addr,up->cb.nr4->local);
up->namelen = sizeof(struct sockaddr_nr);
sp.p = up->peername;
sp.nr->nr_family = AF_NETROM;
ASSIGN(sp.nr->nr_addr,up->cb.nr4->remote);
up->peernamelen = sizeof(struct sockaddr_nr);
/* Wake up the guy accepting it, and let him run */
psignal(oup,1);
pwait(NULL);
}
/* Ignore all other state transitions */
psignal(up,0); /* In case anybody's waiting */
}
int
checknraddr(name,namelen)
char *name;
int namelen;
{
struct sockaddr_nr *sock;
sock = (struct sockaddr_nr *)name;
if(sock->nr_family != AF_NETROM || namelen != sizeof(struct sockaddr_nr))
return -1;
return 0;
}
char *
nrpsocket(p)
struct sockaddr *p;
{
struct sockaddr_nr *nrp;
static char buf[30];
char tmp[11];
pax25(tmp,nrp->nr_addr.user);
sprintf(buf,"%s @ ",tmp);
pax25(tmp,nrp->nr_addr.node);
strcat(buf,tmp);
return buf;
}
char *
nrstate(up)
struct usock *up;
{
return Nr4states[up->cb.nr4->state];
}
int
so_n4_stat(up)
struct usock *up;
{
donrdump(up->cb.nr4);
return 0;
}