/* socket.c Multi protocol socket interface */ /* * Copyright (C) 1988, 1989 by Frederic Hemmer * All rights reserved */ #define DEBUG 1 /* TCP/IP package selection */ #define WinTCP 1 /* Version using Win/TCP */ #define DecBridge 0 /* Version using Ultrix Bridge */ #define Excelan 0 /* Version using Excelan TCP/IP */ #include #include /* for DEBUG */ #include /* System Services definitions */ #include /* VMS IO definitions */ #include /* Network .... */ #include /* Mailbox message types */ #include /* Types */ #include /* Sockets */ #include /* Decnet networking */ #include /* Internet IO definitions */ #define PUBLIC #define PRIVATE static #define to_unix(x) ((0x7fff & x) >> 3) /* Win/TCP error numbers */ #define MAXMBXMSG 128 /* Mailbox size */ #define MAXBUFQUO 128 /* Only one message */ PRIVATE struct Channel { unsigned short Channel; int Type; unsigned short mbx; unsigned short Backlog; /* For Decnet */ struct Channel *Next; }; PRIVATE struct Channel *Head; PRIVATE struct { /* Win/TCP INET descriptor */ int size; char *ptr; } inetdsc = { 7, "_INET0:"}; PRIVATE struct { /* Decnet NET descriptor */ int size; char *ptr; } dnetdsc = { 5, "_NET:"}; PRIVATE struct { /* Decnet mailbox name */ int size; char *ptr; } mbxnamdsc = { 6, "SOCKET"}; typedef struct { unsigned short msgtype; unsigned short unit; unsigned char count; char info[MAXMBXMSG-5]; } mbx; typedef struct { int size; char *ptr; } ncbdsc; /* Decnet NCB descriptor */ typedef struct { /* Decnet Network Function block*/ unsigned char type; unsigned long objnum; } nfb; typedef struct { /* Decnet NFB Descriptor */ int size; nfb *ptr; } nfb_dsc; typedef struct { /* VMS I/O Status Block for QIO */ short status; int bytecount; short unused; } IOSB; PRIVATE int PrintChannelTable() { struct Channel *s; if ((s = Head) == 0) { fprintf(stdout,"Channel Table empty\n"); return(0); } for (;s != 0;s = s->Next) { fprintf(stdout,"Channel %x : %d %x %d %x\n", s->Channel, s->Type, s->mbx, s->Backlog, s->Next); } return(0); } /* * Allocate channel for address family and insert in a linked list * a mailbox is associated for the channel for AF_DECnet */ PRIVATE int AllocateChannel(type, channel) int type; int *channel; { struct Channel *s; int rc; if ((s = (struct Channel *) malloc(sizeof(struct Channel)))== 0) { return(errno); } switch (type) { case AF_INET: rc = sys$assign(&inetdsc, &(s->Channel), 0, 0); #if DEBUG fprintf(stdout,"AllocateChannel(%d, %x): ", type, channel); fprintf(stdout,"assign returned %x (%d)\n", s->Channel, rc); #endif /* DEBUG */ break; case AF_DECnet: rc = lib$asn_wth_mbx(&dnetdsc, 0, 0, &(s->Channel), &(s->mbx)); #if DEBUG fprintf(stdout,"AllocateChannel(%d, %x): ", type, channel); fprintf(stdout,"asn_wth_mbx returned %x %x (%d)\n", s->Channel, s->mbx, rc); #endif /* DEBUG */ break; } if (rc != SS$_NORMAL) { free(s); return(rc); } s->Type = type; s->Backlog = 0; s->Next = Head; Head = s; *channel = s->Channel; /* PrintChannelTable(); */ return (SS$_NORMAL); } /* * Find a channel in the linked list */ PUBLIC struct Channel * FindChannel(channel) { struct Channel *s; /* PrintChannelTable(); */ #if DEBUG fprintf(stdout,"FindChannel(%x)\n",channel); #endif /* DEBUG */ if ((s = Head) == 0) return(0); for (;s != 0;s = s->Next) { #if DEBUG fprintf(stdout," -> %x (type %d): ",s->Channel, s->Type); #endif /* DEBUG */ if (s->Channel == channel) { #if DEBUG fprintf(stdout,"matched\n"); #endif /* DEBUG */ return(s); } #if DEBUG fprintf(stdout, "not matched\n"); #endif /* DEBUG */ } return(0); } PUBLIC int accept(s, addr, addrlen) int s; struct sockaddr *addr; int *addrlen; { struct Channel *C; if ((C = FindChannel(s)) == 0) { errno = EBADF; return(-1); } switch (C->Type) { case AF_INET: return(TCPaccept(s, addr, addrlen)); case AF_DECnet: return(DNPaccept(s, addr, addrlen)); } } PUBLIC int bind(s, name, namelen) int s; struct sockaddr *name; int namelen; { struct Channel *C; if ((C = FindChannel(s)) == 0) { errno = EINVAL; return(-1); } switch (C->Type) { case AF_INET: return(TCPbind(s, name, namelen)); case AF_DECnet: return(DNPbind(s, name, namelen)); } } PUBLIC int connect (s, name, namelen) int s; char *name; /* could be *sockaddr_in or *sockaddr_dn */ int namelen; { struct Channel *C; if ((C = FindChannel(s)) == 0) { errno = EINVAL; return(-1); } switch (C->Type) { case AF_INET: return(TCPconnect(s, name, namelen)); case AF_DECnet: return(DNPconnect(s, name, namelen)); } } PUBLIC int listen(s, backlog) int s, backlog; { IOSB iosb; int rc; struct Channel *C; if ((C = FindChannel(s)) == 0) { errno = EINVAL; return(-1); } switch (C->Type) { case AF_INET: return(TCPlisten(s, backlog)); case AF_DECnet: return(DNPlisten(s, backlog)); } } PUBLIC int recv (s, buf, len, flags) int s; char *buf; int len, flags; { IOSB iosb; struct Channel *C; int rc; if ((C = FindChannel(s)) == 0) { errno = EINVAL; return(-1); } switch (C->Type) { case AF_INET: rc = sys$qiow(0, s, IO$_RECEIVE, &iosb, 0, 0, buf, len, flags, 0, 0, 0); #if DEBUG fprintf(stdout,"recv(%x,%x,%d,%d): qiow returned %d (iosb.status: %d)(iosb[2]: %d)\n", s, buf, len, flags, rc, iosb.status, iosb.bytecount); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (iosb.bytecount); case AF_DECnet: rc = sys$qiow(0, s, IO$_READVBLK, &iosb, 0, 0, buf, len, flags, 0, 0, 0); #if DEBUG fprintf(stdout,"recv(%x,%x,%d,%d): qiow returned %d (iosb.status: %d)(iosb[2]: %d)\n", s, buf, len, flags, rc, iosb.status, iosb.bytecount); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } /* iosb.bytecount = 0x0000FFFF & iosb.bytecount;*/ return (iosb.bytecount); } } PUBLIC int send (s, msg, len, flags) int s; char *msg; int len, flags; { IOSB iosb; struct Channel *C; int rc; if ((C = FindChannel(s)) == 0) { errno = EINVAL; return(-1); } switch (C->Type) { case AF_INET: rc = sys$qiow(0, s, IO$_SEND, &iosb, 0, 0, msg, len, flags, 0, 0, 0); #if DEBUG fprintf(stdout,"send(%x,%x,%d,%d): qiow returned %d (iosb.status: %d)(iosb[2]: %d)\n", s, msg, len, flags, rc, iosb.status, iosb.bytecount); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (iosb.bytecount); case AF_DECnet: rc = sys$qiow(0, s, IO$_SEND, &iosb, 0, 0, msg, len, flags, 0, 0, 0); #if DEBUG fprintf(stdout,"send(%x,%x,%d,%d): qiow returned %d (iosb.status: %d)(iosb[2]: %d)\n", s, msg, len, flags, rc, iosb.status, iosb.bytecount); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } iosb.bytecount = 0x0000FFFF & iosb.bytecount; return (iosb.bytecount); } } PUBLIC int shutdown (s, how) int s, how; { IOSB iosb; int rc; rc = sys$qiow(0, s, IO$_SHUTDOWN, &iosb, 0, 0, how, 0, 0, 0, 0, 0); if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (-1); } PUBLIC int socket (af, type, protocol) int af, type, protocol; { switch (af) { case AF_INET: return(TCPsocket(af, type, protocol)); case AF_DECnet: return(DNPsocket(af, type, protocol)); default: #if DEBUG fprintf(stdout,"socket(%d,%d,%d): Bad address family\n", af, type, protocol); fprintf(stdout," only (%d, %d) are supported\n", AF_INET, AF_DECnet); #endif DEBUG errno = EAFNOSUPPORT; return(-1); } } PRIVATE int TCPaccept(s, addr, addrlen) int s; struct sockaddr *addr; int *addrlen; { IOSB iosb; int ns; int rc; rc = AllocateChannel(AF_INET, &ns); #if DEBUG fprintf(stdout,"accept(%x,%x,%d) (INET): AllocateChannel returned %d\n", s, addr, *addrlen, rc); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } rc = sys$qiow(0, ns, IO$_ACCEPT, &iosb, 0, 0, addrlen, sizeof(addr)+sizeof(int), s, 0, 0, 0); #if DEBUG fprintf(stdout,"accept(%x,%x,%d): qiow returned %d (iosb.status: %d)\n", s, addr, *addrlen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (ns); } PRIVATE int DNPaccept(s, addr, addrlen) int s; struct sockaddr *addr; int *addrlen; { IOSB iosb; int ns; int rc; mbx mailbox; ncbdsc ncb; char ncbstr[100]; struct Channel *C; if ((C = FindChannel(s)) == 0) { errno = EBADF; return(-1); } #if DEBUG fprintf(stdout,"accept(%x,%x,%d) (DECnet)\n", s, addr, *addrlen); #endif /* DEBUG */ rc = sys$qiow(0, (C->mbx), IO$_READVBLK, &iosb, 0, 0, &mailbox, MAXMBXMSG, 0, 0, 0, 0); #if DEBUG fprintf(stdout,"accept(%x,%x,%d) (DECnet): qiow (mbx: %x) returned: %d \n", s, addr, *addrlen ,C->mbx, rc); fprintf(stdout," -> Got message %d\n",mailbox.msgtype); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } switch (mailbox.msgtype) { case MSG$_CONNECT: /* 1) new channel 2) getdvi 3) qio (access) */ rc = AllocateChannel(AF_DECnet ,&ns); if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } /* GETDVI HERE */ ncb.ptr = ncbstr; ncb.size= (int) (* (&mailbox.info + mailbox.count)); bcopy ((char *) (&mailbox.info + mailbox.count + 1), ncb.ptr,ncb.size); rc = sys$qiow( 0, ns, IO$_ACCESS, &iosb, 0, 0, 0, &ncb, 0, 0, 0, 0); #if DEBUG fprintf(stdout,"accept(%x,%x,%d) (DECnet): qiow returned %d (iosb.status: %d)\n", s, addr, addrlen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } break; default: return(-1); } return (ns); } PRIVATE int TCPbind(s, name, namelen) int s; struct sockaddr *name; int namelen; { IOSB iosb; int rc; rc = sys$qiow(0, s, IO$_BIND, &iosb, 0, 0, name, sizeof(struct sockaddr), 0, 0, 0, 0); #if DEBUG fprintf(stdout,"bind(%x,%x,%d) (INET): qiow returned %d (iosb.status: %d)\n", s, name, namelen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (0); } PRIVATE int DNPbind(s, name, namelen) int s; struct sockaddr_dn *name; int namelen; { IOSB iosb; int rc; nfb dnp_object; nfb_dsc dnp_obj_dsc; #if DEBUG fprintf(stdout,"bind(%x, %x, %d) (DECnet): Node (%d.%d) Object(%d)\n", s, name, namelen, ((*(unsigned short *) name->sdn_nodeaddr) >> 10) & 0x003F, (*(unsigned short *) name->sdn_nodeaddr) & 0x03FF, name->sdn_objnum); #endif /* DEBUG */ dnp_obj_dsc.size = 5; dnp_obj_dsc.ptr = &dnp_object; dnp_object.type = NFB$C_DECLOBJ; dnp_object.objnum = name->sdn_objnum; rc = sys$qiow(0, s, IO$_ACPCONTROL, &iosb, 0, 0, &dnp_obj_dsc, 0, 0, 0, 0, 0); #if DEBUG fprintf(stdout,"bind(%x,%x,%d) (DECnet): qiow returned %d (iosb.status: %d)\n", s, name, namelen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } return (0); } PRIVATE int TCPconnect (s, name, namelen) int s; struct sockaddr_in *name; int namelen; { IOSB iosb; int rc; rc = sys$qiow(0, s, IO$_CONNECT, &iosb, 0, 0, name, sizeof(struct sockaddr), 0, 0, 0, 0); #if DEBUG fprintf(stdout,"connect(%x,%x,%d) (INET): qiow returned %d (iosb.status: %d)\n", s, name, namelen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (0); } PRIVATE int DNPconnect (s, name, namelen) int s; struct sockaddr_dn *name; int namelen; { IOSB iosb; int rc; ncbdsc ncb; char ncbstr[100]; /* map the name sock_addr_dn to NCB */ #if DEBUG fprintf(stdout,"connect(%x, %x, %d) (DECnet): Node (%d.%d)\n", s, name, namelen, ((*(unsigned short *) name->sdn_nodeaddr) >> 10) & 0x003F, (*(unsigned short *) name->sdn_nodeaddr) & 0x03FF); #endif /* DEBUG */ sprintf(ncbstr,"%d.%d::\"%d=\"\0", ((*(unsigned short *) name->sdn_nodeaddr) >> 10) & 0x003F, (*(unsigned short *) name->sdn_nodeaddr) & 0x03FF, name->sdn_objnum); ncb.size = strlen(ncbstr); ncb.ptr = ncbstr; rc = sys$qiow(0, s, IO$_ACCESS, &iosb, 0, 0, 0, &ncb, 0, 0, 0, 0); #if DEBUG fprintf(stdout,"connect(%x,%x,%d): qiow returned %d (iosb.status: %d)\n", s, name, namelen, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { vaxc$errno = iosb.status; errno = EVMSERR; return(-1); } return (0); } PRIVATE int TCPsocket (af, type, protocol) int af, type, protocol; { IOSB iosb; int rc; int s; rc = AllocateChannel(AF_INET, &s); #if DEBUG fprintf(stdout,"socket(%d,%d,%d): (INET) AllocateChannel returned %x (%d)\n", af, type, protocol, s, rc); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } rc = sys$qiow(0, s, IO$_SOCKET, &iosb, 0, 0, af, type, protocol, 0, 0, 0); #if DEBUG fprintf(stdout,"socket(%d,%d,%d): qiow returned %d (iosb.status: %d)\n", af, type, protocol, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (s); } PRIVATE int DNPsocket (af, type, protocol) int af, type, protocol; { IOSB iosb; int rc; int s; if (type != SOCK_STREAM) { errno = ESOCKTNOSUPPORT; return(-1); } rc = AllocateChannel(AF_DECnet, &s); #if DEBUG fprintf(stdout,"socket(%d,%d,%d): (DECnet) AllocateChannel returned %x (%d)\n", af, type, protocol, s, rc); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } return (s); } PRIVATE int TCPlisten(s, backlog) int s, backlog; { IOSB iosb; int rc; rc = sys$qiow(0, s, IO$_LISTEN, &iosb, 0, 0, backlog, 0, 0, 0, 0, 0); #if DEBUG fprintf(stdout,"listen(%x,%d) (INET): qiow returned %d (iosb.status: %d)\n", s, backlog, rc, iosb.status); #endif /* DEBUG */ if (rc != SS$_NORMAL) { vaxc$errno = rc; errno = EVMSERR; return(-1); } if (iosb.status != SS$_NORMAL) { errno=to_unix(iosb.status); return(-1); } return (0); } PRIVATE int DNPlisten(s, backlog) int s, backlog; { IOSB iosb; int rc; struct Channel *C; /* we don't do very much, just establishing the backlog */ #if DEBUG fprintf(stdout,"listen(%x,%d) (DECnet)\n",s, backlog); #endif /* DEBUG */ if ((C = FindChannel(s)) == 0) { errno = EBADF; return(-1); } C->Backlog = backlog; return(0); }