/* ***************************************************************************** * * Copyright 1991, Xylogics, Inc. ALL RIGHTS RESERVED. * * ALL RIGHTS RESERVED. Licensed Material - Property of Xylogics, Inc. * This software is made available solely pursuant to the terms of a * software license agreement which governs its use. * Unauthorized duplication, distribution or sale are strictly prohibited. * * Module Description:: * * API I/F - Application Program Interface Interface. * Supplies I/F from application layer to different API systems; * either sockets, TLI, or EXOS. * * Original Author: D Emond Created on: New Year's Eve * * Module Reviewers: * %$(reviewers)$% * * Revision Control Information: * $Id: api_if.c,v 1.24.5.3 1995/09/26 13:07:07 dfox Exp $ * * This file created by RCS from * $Source: /annex/mckinley/src/libannex/RCS/api_if.c,v $ * * Revision History: * $Log: api_if.c,v $ * Revision 1.25 1995/10/17 15:34:38 carlson * Fixed handling of connection-refused error from network layers. * * Revision 1.24.5.3 1995/09/26 13:07:07 dfox * Reliable ACP * * Revision 1.24.5.2 1995/08/29 11:06:24 slu * Moved defination from inc/config.h to api_if.c to solve problem * installation script overwrite inc/config.h. * * Revision 1.24 1995/03/16 04:58:12 julian * api_recvmsg has been modified to take notice of the users requested * message size. SPR 3609 reviewed by carlson. * * Revision 1.23 1994/11/22 13:37:25 parker * changed sendmsg and recvmsg to macros sendmsg_func/recvmsg_func to avoid * a problem with the NuTcracker library. * * Revision 1.22 1994/11/16 09:24:54 parker * Changes for port to windows NT * * Revision 1.21 1994/08/26 16:43:46 carlson * SPR 2940 -- modifications to support Linux Slackware 1.2. * * Revision 1.20 1993/07/15 11:18:30 carlson * SPR 1344 -- wildly bad error handling in api_recvmsg in TLI section. * * Revision 1.19 93/05/04 13:06:55 carlson * Update to last check-in -- EINTR needs to be checked before doing * perror, not after. * * Revision 1.18 93/04/20 13:05:24 carlson * SPR 1386 -- Bug in api_recv (not handling EINTR code) was causing * aprint to prematurely exit on Unisys hosts. * * Revision 1.17 92/10/12 16:23:45 carlson * More initialization added to api_connect for NCR. * * Revision 1.16 92/10/07 09:18:01 bullock * spr.1172 - for t_connect, need to initialize whole tlicall structure * beforehand so NCR doesn't die. * * Revision 1.15 92/09/11 13:58:37 carlson * SPR 1058 - need to have our own endpoint address cache for UDP * connections, since t_connect doesn't work on all TLI systems. * (Reviewed with M Bullock and tested on Sequent and NCR.) * * Revision 1.14 92/08/26 15:57:46 carlson * Fixed fprintf argument errors and pedantic ANSI compiler warning. * * Revision 1.13 92/08/21 14:36:28 carlson * Removed all references to t_alloc and t_free, fixed many storage * corruptions and losses, fixed some of the debug messages, added * some calls to t_look as needed. The function interfaces should * now be reviewed and modified. * * Revision 1.12 92/07/01 12:56:37 bullock * spr.850 - do a t_free after the t_alloc to return the memory * * Revision 1.11 92/04/02 18:01:27 emond * Per Alan Barnett for Bull - assure msg->namelen = 0 if *name == 0. * * Revision 1.10 92/03/22 22:25:53 emond * Older compilers cannot handle "*="; need space in there "= *". * * Revision 1.9 91/11/21 18:34:25 carlson * SPR 434 -- missing cast in sendto statement. * * Revision 1.8 91/09/16 19:22:23 emond * Had to comment argument following #endif; illegal on ansii compilers. * * Revision 1.7 91/07/29 12:57:34 raison * fix ICL SVR4 Sparc-based DRS6000 compiler error * * Revision 1.6 91/06/27 14:47:28 emond * Move fcntl.h include from api_if.h to api_if.c * * Revision 1.5 91/06/24 16:01:52 barnes * in api_open, change the path type from (char *) to (int) since * the socket call core dumps on XENIX if the socket type is (char *) * * Revision 1.4 91/06/21 11:59:22 emond * Accommodate for EXOS systems. * Fix so t_bind doesn't dereference a zero pointer and crash na. * * Revision 1.3 91/05/19 16:33:47 emond * Assure api_recvmsg() returns a -2 if SLIP configuration fails recvmsg(). * * Revision 1.2 91/04/24 19:16:31 emond * Clean-up error from ICMP msgs being recv'd in t_rcvudata(). TLI specific. * * Revision 1.1 91/04/07 23:45:30 emond * Initial revision * * This file is currently under revision by: $Locker: $ * ***************************************************************************** */ /* * Include Files */ #include "../inc/config.h" #include #include #include "api_if.h" #ifndef _WIN32 #include #include #endif #include #include "../inc/courier/courier.h" #include "../inc/erpc/erpc.h" #include /* #include Do we need this ? */ #ifndef _WIN32 #include #include #endif /* * External Definitions */ extern int so; /* token for socket number */ extern int t_errno; extern int alarm_flag; /* * Defines and Macros */ #ifndef MSGBUFSIZE #define MSGBUFSIZE 2048 #endif #ifndef ECONNREFUSED #define ECONNREFUSED 61 #endif #define DEF_LINGER_TIME 120 #ifndef sendmsg_func #define sendmsg_func sendmsg #endif #ifndef recvmsg_func #define recvmsg_func recvmsg #endif #ifndef __FreeBSD__ extern int sendmsg_func(); extern int recvmsg_func(); #endif #ifdef _WIN32 #define XylogicsWSAGetLastError() \ { \ errno = WSAGetLastError(); \ } #else #define XylogicsWSAGetLastError() #endif /* * Structure and Typedef Definitions */ /* * Forward Function Definitions */ /* * Static Definitions */ #define TLI_TCP "/dev/tcp" #define TLI_UDP "/dev/udp" /* * Global Data Declarations */ /* Map generic Transport options and flags to specific ones */ /* (either TLI or Sockets) */ int tp_opt[MAX_TO_OPTS] = {SO_KEEPALIVE, SO_DEBUG, SO_REUSEADDR, SO_OOBINLINE, SO_LINGER}; #ifdef TLI int tp_flags[MAX_FLGS] = {0,0,0,T_EXPEDITED,}; #else #ifndef EXOS #ifdef LINUX int tp_flags[MAX_FLGS] = {0,MSG_PEEK,0,MSG_OOB}; #else /* LINUX */ int tp_flags[MAX_FLGS] = {0,MSG_PEEK,MSG_DONTROUTE,MSG_OOB}; #endif /* LINUX */ #endif /*EXOS*/ #endif /* TLI */ /* * Static Data Declarations */ #ifdef TLI /* * Special TLI support routines -- TLI doesn't always allow connecting * of a UDP socket, so we implement this function ourselves. */ struct rmt_addr { struct rmt_addr *next; int fd; struct sockaddr_in sin; }; static struct rmt_addr *rmt_head = NULL; struct rmt_addr * get_remote_addr(fd) int fd; { struct rmt_addr *np; for (np = rmt_head;np != NULL; np = np->next) if (np->fd == fd) break; return np; } #endif void dial_timer() { alarm_flag = 1; #ifndef _WIN32 signal(SIGALRM, SIG_DFL); #endif } /***************************************************************************** * * NAME: * api_open() * * DESCRIPTION: * Performs open down to the TLI API layer * * ARGUMENTS: * pd Protocol descriptor * app_nam ptr to application name * sin ptr to socket struct * sho_err flag; TRUE-show error, FALSE-don't show error * * RETURN VALUE: * int File descriptor # of transport endpoint * if == -1 then open failed * */ int api_open(pd, sin, app_nam, sho_err) int pd; /* Protocol descriptor */ char *app_nam; /*ptr to application name */ struct sockaddr_in *sin; /* ptr to socket struct */ int sho_err; #ifdef TLI { char err_msg[80]; int fd; /* file descriptor of transport endpoint */ char *path; /* pathname to transport endpoint */ if (pd == IPPROTO_TCP) path = (char *)TLI_TCP; else /* Assumed UDP */ path = (char *)TLI_UDP; fd = t_open(path,O_RDWR,(struct t_info *)NULL); if (fd < 0 && sho_err) { sprintf (err_msg, "%s:t_open failed for listen",app_nam); t_error(err_msg); } return fd; } #else /* not TLI */ { char err_msg[80]; int fd; /* file descriptor of transport endpoint */ int path; /* socket type */ if (pd == IPPROTO_TCP) path = SOCK_STREAM; else /* Assumed UDP */ path = SOCK_DGRAM; #ifdef EXOS /* 4.1-style sockets, sigh */ fd = socket(path, (struct sockproto *)0, sin, 0); #else fd = socket(AF_INET, path, 0); #endif XylogicsWSAGetLastError(); if ((fd < 0) && (sho_err)) { sprintf (err_msg, "%s: could not get socket",app_nam); perror(err_msg); } return(fd); } #endif /*TLI*/ /***************************************************************************** * * NAME: * api_bind() * * DESCRIPTION: * Bind given address to transport endpoint. * * ARGUMENTS: * fd file (transport endpoint) descriptor * tlibind_p ptr to ptr to t_bind struct * if == 0 then don't alloc any memory for it. * DEPRECATED -- should be removed! * sin_p ptr to the source address * app_nam ptr to name of application * sho_err flag; TRUE-show error, FALSE-don't show error * * RETURN VALUE: * 0 No error * 1 TLI bind failure * 2 Socket bind failure * * SIDE EFFECTS: * None * * EXCEPTIONS: * None * * ASSUMPTIONS: * None */ int api_bind(fd, tlibind_p, sin_p, app_nam, sho_err) int fd; struct sockaddr_in *sin_p; char *app_nam; int sho_err; #ifdef TLI struct t_bind **tlibind_p; { char err_msg[80]; struct t_bind tbind,*temp; /* Use tlibind struct ? */ if (sin_p != (struct sockaddr_in *)NULL) { tbind.addr.buf = (char *)sin_p; tbind.addr.len = sizeof(struct sockaddr_in); temp = &tbind; } else temp = (struct t_bind *)NULL; if (t_bind(fd,temp,(struct t_bind *)NULL) < 0) { if (sho_err) { sprintf (err_msg, "%s:t_bind failed",app_nam); t_error(err_msg); } return(1); } return(0); } #else int **tlibind_p; { char err_msg[80]; #ifndef EXOS int in = bind(fd,(struct sockaddr *)sin_p,sizeof(struct sockaddr_in)); XylogicsWSAGetLastError(); if (in < 0) { if (sho_err) { sprintf(err_msg,"%s: bind", app_nam); perror(err_msg); } return(2); } #endif /*!EXOS*/ return(0); } #endif /*TLI*/ /***************************************************************************** * * NAME: * api_connect() * * DESCRIPTION: * API I/F layer connect. * * Note that a connectionless application can do a Socket API connect * just to store the specified servaddr so that the system know where * to send any future data the applications writes to this socket * descriptor. * * ARGUMENTS: * fd transport endpoint file descriptor * pd protocol descriptor (UDP or TCP) * Indicates whether actual connect should occur * sin ptr to sockaddr_in struct * app_nam ptr to name of application that called us. * sho_err flag; TRUE-show error, FALSE-don't show error * * RETURN VALUE: * 0 No error * 1 TLI bind failure * 2 Socket bind failure * * SIDE EFFECTS: * None * * EXCEPTIONS: * None * * ASSUMPTIONS: * None */ int api_connect(fd, sin, pd, app_nam, sho_err) int fd; /* transport endpoint file descriptor */ int pd; /* protocol descriptor, UDP or TCP */ struct sockaddr_in *sin; char *app_nam; int sho_err; /*flag that indicates whether errors be shown*/ #ifdef TLI { char err_msg[80]; int i,j,retval = 0; if (pd == IPPROTO_TCP) { struct t_call tlicall; tlicall.addr.buf = (char *)sin; tlicall.addr.len = sizeof(struct sockaddr_in); tlicall.opt.buf = tlicall.udata.buf = (char *)NULL; tlicall.opt.len = tlicall.udata.len = 0; tlicall.sequence = 0; for (j=0;j < 10;j++,sleep(1)) { t_errno = errno = 0; if (t_connect(fd,&tlicall,(struct t_call *)NULL) >= 0) break; if (t_errno == TLOOK) { i = t_look(fd); if (i == T_DISCONNECT) continue; if (sho_err) fprintf(stderr,"%s: strange t_look value %d\n", app_nam); retval = 1; break; } if (sho_err) { sprintf(err_msg,"%s: t_connect failed",app_nam); t_error(err_msg); } retval = 1; break; } } else if (sin) { if (get_remote_addr(fd)) { if (sho_err) fprintf(stderr,"%s: api_connect: already connected.\n", app_nam); retval = 1; } else { struct rmt_addr *np; np = (struct rmt_addr *)malloc(sizeof(struct rmt_addr)); if (np == (struct rmt_addr *)NULL) { if (sho_err) fprintf(stderr,"%s: api_connect: out of memory.\n", app_nam); retval = 1; } else { np->fd = fd; bcopy(sin,&np->sin,sizeof(np->sin)); np->next = rmt_head; rmt_head = np; } } } return retval; } #else /* Sockets */ { char err_msg[80]; #ifdef EXOS if (connect(fd, (struct sockaddr *)sin) < 0) { if (sho_err) { sprintf(err_msg,"%s: connect", app_nam); perror(err_msg); } return(2); } #else /* BSD */ if(connect(fd,(struct sockaddr *)sin,sizeof(struct sockaddr_in)) < 0) { if (sho_err) { sprintf(err_msg,"%s: connect", app_nam); perror(err_msg); } XylogicsWSAGetLastError(); return(2); } XylogicsWSAGetLastError(); #endif /* EXOS */ return(0); } #endif /* TLI */ /***************************************************************************** * * NAME: api_listen() * * DESCRIPTION: * Set-up a socket to listen for connections. Currently only support TCP. * * ARGUMENTS: * fd - socket file descriptor * backlog - maximum length for queue of pending connections * app_nam - name of the application that called this function * sho_err - TRUE means display any errors on stdout * * RETURN VALUE: * 0 if successful, -1 if an error (and errno gets set) * * RESOURCE HANDLING: * all done at the lower level * * SIDE EFFECTS: * * EXCEPTIONS: * * ASSUMPTIONS: * Assumes socket is of a type (SOCK_STREAM or SOCK_SEQPACKET) that supports * listen() */ int api_listen(fd, backlog, app_nam, sho_err) int fd; int backlog; char *app_nam; int sho_err; { #ifndef TLI char err_msg[80]; if (listen(fd, backlog) < 0) { XylogicsWSAGetLastError(); if (sho_err) { sprintf(err_msg,"%s: listen", app_nam); perror(err_msg); } return(-1); } #endif return(0); } /***************************************************************************** * * NAME: api_accept() * * DESCRIPTION: * Wait for incoming connection. Currently only supports TCP. * * ARGUMENTS: * fd - socket file descriptor * sin - pointer to remote address for the connection * app_nam - name of the application that called this function * sho_err - TRUE means display any errors on stdout * * RETURN VALUE: * descriptor for the new connected socket or -1 if error * * RESOURCE HANDLING: * all done at the lower level * * SIDE EFFECTS: * * EXCEPTIONS: * * ASSUMPTIONS: * Assumes socket is of a type (SOCK_STREAM or SOCK_SEQPACKET) that supports * listen() */ int api_accept(fd, sin, app_nam, sho_err) int fd; struct sockaddr_in *sin; char *app_nam; int sho_err; { int addrlen = sizeof(struct sockaddr_in); int newsock = -1; #ifdef TLI struct t_call call; int rv; char buffer[MSGBUFSIZE]; char err_msg[80]; for(;;) { bzero(&call, sizeof(struct t_call)); call.addr.maxlen = addrlen; call.addr.buf = (char*)sin; call.opt.maxlen = 0; call.udata.maxlen = sizeof(buffer); call.udata.buf = buffer; if (t_listen(fd, &call) < 0) { switch (t_errno) { case TLOOK: rv = t_look(fd); if (rv == T_DISCONNECT || rv == T_ORDREL || rv < 0) { if (sho_err) fprintf(stderr,"%s: t_listen closed.\n",app_nam); return -1; } if (rv != T_ERROR) continue; if (sho_err) fprintf(stderr,"%s: t_listen/t_look T_ERROR\n", app_nam); return -1; case TNODATA: continue; case TSYSERR: if (errno == EINTR) continue; if (sho_err) { rv = errno; sprintf(err_msg,"%s: t_listen TSYSERR", app_nam); errno = rv; perror(err_msg); } return -1; default: if (sho_err) { sprintf(err_msg,"%s: t_listen failed", app_nam); t_error(err_msg); } return -1; } } break; } if ((newsock = api_open(IPPROTO_TCP, sin, app_nam, sho_err)) < 0) return(newsock); while (t_accept(fd, newsock, &call) < 0) { switch (t_errno) { case TLOOK: rv = t_look(fd); if (rv < 0) { if (sho_err) fprintf(stderr,"%s: t_accept closed.\n",app_nam); return -1; } else if (rv == T_ERROR) { if (sho_err) fprintf(stderr,"%s: t_accept/t_look T_ERROR\n", app_nam); return -1; } else if (rv == T_LISTEN) return 0; continue; /* unsure of other errors, but this is safest */ case TSYSERR: if (sho_err) { rv = errno; sprintf(err_msg,"%s: t_listen TSYSERR", app_nam); errno = rv; perror(err_msg); } return -1; default: if (sho_err) { sprintf(err_msg,"%s: t_listen failed", app_nam); t_error(err_msg); } return -1; } } #else char err_msg[80]; for(;;) { if ((newsock = accept(fd, (struct sockaddr *)sin, &addrlen)) < 0) { XylogicsWSAGetLastError(); if (errno == EINTR) continue; if (sho_err) { sprintf(err_msg,"%s: accept", app_nam); perror(err_msg); } return(-1); } break; } if (sho_err && addrlen != sizeof(struct sockaddr_in)) { printf("%s: accept: warning: %s", app_nam, "address length returned does not match size of sockaddr_in"); } #endif return(newsock); } /***************************************************************************** * * NAME: * api_recv() * * DESCRIPTION: * Read normal or expedited data from network. * * ARGUMENTS: * fd transport endpoint file descriptor * cbuff ptr to charc buffer * len charc buffer length * intr TRUE - propogate EINTR * flags Transport flags * app_name name of application requesting service * sho_error TRUE-show errors; FALSE-don't show errors * * RETURN VALUE: * -1 normal failure * -2 interrupted (usually from timeout) * else equal to number of charcs read * * SIDE EFFECTS: * None * * EXCEPTIONS: * None * * ASSUMPTIONS: * None */ int api_recv(fd, cbuff, len, intr, flags, sho_err, app_nam) int fd; /* file descriptor of transport endpoint */ char *cbuff; char *app_nam; int sho_err; /* TRUE-show error, FALSE-don't show error */ int flags, len, intr; { int cc; char err_msg[80]; #ifdef TLI int tflags,i; for (;;) { tflags = 0; if ((cc = t_rcv(fd, cbuff, len, &tflags)) >= 0) break; switch (t_errno) { case TLOOK: i = t_look(fd); if (i == T_DISCONNECT || i == T_ORDREL || i < 0) { if (sho_err) fprintf(stderr,"(%d) %s: t_rcv closed.\n",getpid(),app_nam); return -1; } if (i != T_ERROR) return -2; if (sho_err) fprintf(stderr,"%s: t_rcv/t_look T_ERROR\n", app_nam); return -1; case TNODATA: return 0; case TSYSERR: if (errno == EINTR) { if (intr) return(-2); else continue; } if (sho_err) { i = errno; sprintf(err_msg,"%s: t_rcv TSYSERR", app_nam); errno = i; perror(err_msg); } return -1; default: if (sho_err) { sprintf(err_msg,"%s: t_rcv failed", app_nam); t_error(err_msg); } return -1; } } return cc; #else for (;;) { #ifdef EXOS cc = read(fd, cbuff, len); #else cc = recv(fd, cbuff, len, tp_flags[flags]); #endif /*EXOS*/ XylogicsWSAGetLastError(); if (intr && alarm_flag) return(-2); if (cc >= 0) return cc; if (errno == EINTR) { if (intr) return(-2); else continue; } if (sho_err) { sprintf(err_msg,"%s: recv/read system error:", app_nam); perror(err_msg); } return(-1); } #endif } /***************************************************************************** * * NAME: * api_recvwait() * * DESCRIPTION: * Read normal or expedited data from network. * * ARGUMENTS: * fd transport endpoint file descriptor * cbuff ptr to charc buffer * len charc buffer length * intr TRUE - propogate EINTR * flags Transport flags * app_name name of application requesting service * sho_error TRUE-show errors; FALSE-don't show errors * * RETURN VALUE: * -1 normal failure * -2 interrupted (usually from timeout) * else equal to number of charcs read * * SIDE EFFECTS: * None * * EXCEPTIONS: * None * * ASSUMPTIONS: * None */ int api_recvwait(fd, cbuff, len, timeout, flags, sho_err, app_nam) int fd; /* file descriptor of transport endpoint */ char *cbuff; char *app_nam; int sho_err; /* TRUE-show error, FALSE-don't show error */ int flags, len, timeout; { char err_msg[80]; int rv; #ifdef TLI alarm_flag = 0; signal(SIGALRM, dial_timer); alarm(timeout); do { rv = api_recv(fd, cbuff, len, TRUE, flags, sho_err, app_nam); } while(alarm_flag == 0 && (rv == 0 || rv == 2)); if (alarm_flag) return(-2); else if (rv < 0) { if (sho_err) { sprintf(err_msg,"%s: recv/read system error:", app_nam); perror(err_msg); } return(-1); } else return(rv); #else struct fd_set fdset; struct timeval tv; int cc; FD_ZERO(&fdset); FD_SET(fd, &fdset); tv.tv_sec = timeout; tv.tv_usec = 0; rv = select(fd+1, &fdset, NULL, NULL, &tv); if (rv > 0) { cc = recv(fd, cbuff, len, tp_flags[flags]); if (cc >= 0) return(cc); } else if (rv == 0) return(-2); if (sho_err) { sprintf(err_msg,"%s: select(%d)/recv(%d) system error:", app_nam, rv, cc); perror(err_msg); } return(-1); #endif } /***************************************************************************** * * NAME: * api_recvmsg() * * DESCRIPTION: * Socket recvmsg() simulated for TLI * recvmsg() is scatter/gather version of recvfrom() * * ARGUMENTS: * fd transport endpoint file descriptor * msg * cc Max character count * timeout_p Ptr to expected turnaround timeout timer. * delay The expected turnaround time (in seconds) of the * message at the remote end. * app_nam Name of application who called us * debug debug level * * RETURN VALUE: * -2 error in SLIP or need_select mode * -1 error not in SLIP or need_select mode * else number of characters recv'd * * SIDE EFFECTS: * * None * * EXCEPTIONS: * * None * * ASSUMPTIONS: * * None */ int api_recvmsg(fd, msg, timeout_p, delay, app_nam, debug) int fd, delay, debug, *timeout_p; struct msghdr *msg; char *app_nam; #ifdef TLI { static char buffer[MSGBUFSIZE]; char err_msg[80]; struct sockaddr_in *from; int bufsize = 0; int nread; int i; int flags=0; int count; /* * NOTE: this assumes that the entire message was * passed atomically to this layer, the data are "padded" * to each vector length. It can then copy data to vectors * in msg from buffer. */ if (debug) fprintf(stderr,"%s api_recvmsg\n",app_nam); from = (struct sockaddr_in *) msg->msg_name; if (from != NULL) { struct t_unitdata req; struct sockaddr addr; if (debug) fprintf(stderr,"api_recvmsg:from=0x%x\n",from); req.udata.buf = buffer; req.udata.maxlen = sizeof(buffer); req.opt.buf = NULL; req.opt.maxlen = 0; req.addr.buf = (char *)&addr; req.addr.maxlen = sizeof(addr); if (t_rcvudata(fd,&req,&flags) < 0) switch (t_errno) { case TLOOK: i = t_look(fd); if (i == T_DISCONNECT || i == T_ORDREL || i < 0) { if (debug) fprintf(stderr,"%s: t_rcvudata closed.\n", app_nam); return -1; } if (i != T_ERROR) { *timeout_p -= delay; return -2; } if (debug) fprintf(stderr, "%s: t_rcvudata/t_look T_ERROR\n", app_nam); return -1; case TNODATA: nread = 0; break; case TSYSERR: if (errno == EINTR) { *timeout_p -= delay; return -2; } if (debug) { i = errno; sprintf(err_msg,"%s: t_rcvudata TSYSERR", app_nam); errno = i; perror(err_msg); } return -1; default: if (debug) { sprintf(err_msg,"%s: t_rcvudata failed", app_nam); t_error(err_msg); } return -1; } else { bcopy(req.addr.buf,from,req.addr.len); nread = req.udata.len; } } else { /* from == NULL */ nread = read(fd, buffer, MSGBUFSIZE); if (nread < 0) { if (errno == EINTR) { *timeout_p -= delay; return -2; } if (debug) { sprintf(err_msg,"%s:api_recvmsg read failed", app_nam); perror(err_msg); } return -1; } } if (debug > 1) { fprintf(stderr, "recv'd %d bytes:", nread); for (i = 0; i < nread; i++) { if (i%16 == 0) fprintf(stderr, "\n%3d: ", i); fprintf(stderr, "%2x ", buffer[i]); } fputs("\n", stderr); } for (i = 0; (i < msg->msg_iovlen) && nread; i++) { count = nread > msg->msg_iov[i].iov_len ? msg->msg_iov[i].iov_len : nread; bcopy(buffer+bufsize, msg->msg_iov[i].iov_base, count); bufsize += count; nread -= count; } return bufsize; } #else /* Sockets */ { char err_msg[80]; int nread; nread = recvmsg_func(fd,msg,0); XylogicsWSAGetLastError(); if (nread < 0) { #if defined(SLIP) || defined(need_select) if(errno == EINTR #ifdef need_select || alarm_flag #endif ) { if (debug) { sprintf(err_msg,"%s: recvmsg", app_nam); perror(err_msg); } *timeout_p -= delay; return(-2); } #endif if (debug) { sprintf(err_msg,"%s: recvmsg", app_nam); perror(err_msg); } return(-1); } return (nread); } #endif /* TLI */ /***************************************************************************** * * NAME: * api_sendmsg() * * DESCRIPTION: * Socket sendmsg() simulated for TLI * api_sendmsg() is scatter/gather * * ARGUMENTS: * fd File/Socket descriptor * debug TRUE - then show debug error messages * msg Ptr to msghdr struct containing data to txmit * app_nam Ptr to name of calling application * * RETURN VALUE: * -1 error * else number of character tx'd * * SIDE EFFECTS: * * None * * EXCEPTIONS: * * None * * ASSUMPTIONS: * * None */ int api_sendmsg (fd, msg, app_nam, debug) #ifdef TLI int fd, debug; struct msghdr *msg; char *app_nam; { int bufsize = 0; static char buffer[MSGBUFSIZE]; int i, tolen, nremain; struct sockaddr_in *to; char err_msg[80]; int nwritten; char *residmsg = buffer; if (debug) fprintf(stderr,"%s: api_sendmsg: fd %d, debug %d\n", app_nam,fd,debug); /* * loop, concatenating vector messages into one large message * NOTE: this assumes that the entire message must be * passed atomically to socket, hence the malloc of buffer. * Otherwise, loop could do writes for each element of vector. * Sigh. */ for (i = 0; i < msg->msg_iovlen; i++) { if (bufsize + msg->msg_iov[i].iov_len > sizeof(buffer)) { if (debug) fprintf(stderr,"%s: api_sendmsg -- too long.\n", app_nam); return -1; } bcopy(msg->msg_iov[i].iov_base,buffer+bufsize, msg->msg_iov[i].iov_len); bufsize += msg->msg_iov[i].iov_len; } to = (struct sockaddr_in *)msg->msg_name; tolen = msg->msg_namelen; if (to == NULL) { struct rmt_addr *np; np = get_remote_addr(fd); if (np != NULL) { to = &np->sin; tolen = sizeof(np->sin); } } /* * If address is passed, assume we have not been "connect()"ed, and so * use t_sndudata(). Otherwise, assume we have been "connect()"ed and * we can use write(). */ if (to) { struct t_unitdata tlireq; if (to == NULL) tolen = 0; tlireq.addr.buf = (char *)to; tlireq.addr.len = tolen; tlireq.udata.buf = buffer; tlireq.udata.len = bufsize; tlireq.opt.buf = NULL; tlireq.opt.len = 0; if (t_sndudata(fd,&tlireq) < 0) { if (t_errno == TFLOW) /* Equivalent to EAGAIN */ bufsize = 0; else { sprintf(err_msg,"%s: api_sendmsg t_sndudata failed", app_nam); t_error(err_msg); bufsize = -1; } } return bufsize; } while (nremain > 0) { nwritten = write(fd, residmsg, nremain); if (nwritten < 0) { sprintf(err_msg,"%s: api_sendmsg send|write",app_nam); perror(err_msg); return nwritten; } nremain -= nwritten; residmsg += nwritten; } return bufsize; } #else /* Sockets */ int fd; struct msghdr *msg; char *app_nam; { char err_msg[80]; int cc; /* fix for BULL DPX/2 300 - Alan Barnett, Pregnana */ if(msg->msg_name == (caddr_t)0) msg->msg_namelen = 0; cc = sendmsg_func(fd, msg, 0); XylogicsWSAGetLastError(); if (cc < 0) { sprintf (err_msg, "%s:sendmsg failed-%d\n", app_nam, errno); perror (err_msg); return(-1); } return(cc); } #endif /***************************************************************************** * * NAME: * api_send() * * DESCRIPTION: * Send normal or expedited data over network. * * ARGUMENTS: * fd transport endpoint file descriptor * cbuff ptr to charc buffer * len number of charcs to write * flags Transport flags * app_name name of application requesting service * sho_error TRUE-show errors; FALSE-don't show errors * * RETURN VALUE: * -1 Send failed with errno * else equal to number of charcs sent * * SIDE EFFECTS: * None * * EXCEPTIONS: * None * * ASSUMPTIONS: * None */ int api_send(fd, cbuff, len, flags, app_nam, sho_err) int fd; /* file descriptor of transport endpoint */ char *cbuff; char *app_nam; int sho_err; /* TRUE-show error, FALSE-don't show error */ int flags, len; { char err_msg[80]; int cc; #ifdef TLI cc = t_snd(fd, cbuff, len, tp_flags[flags]); if (cc < 0) { if (t_errno == TFLOW) return 0; if (sho_err) { sprintf(err_msg,"%s: t_snd failed", app_nam); t_error(err_msg); } return(-1); } return(cc); #else #ifdef EXOS cc = write(fd, cbuff, len); #else cc = send(fd, cbuff, len, tp_flags[flags]); #endif XylogicsWSAGetLastError(); if (cc < 0) { if (sho_err) { sprintf(err_msg,"%s: write failed", app_nam); perror(err_msg); } return(-1); } return(cc); #endif } /***************************************************************************** * * NAME: * api_rcvud() * * DESCRIPTION: * Read user datagram from network via connectionless protocol * * ARGUMENTS: * cc_p ptr to charc count. Upon entry this points to size of * rcv buffer (max rcv size). * al_p ptr to length of address * fd transport endpoint file descriptor * tlireq ptr to tlireq struct (deprecated) * cbuff ptr to charc buffer * app_name name of application requesting service * from ptr to address of desired source of mesg * if == 0, source of mesg already specified via connect * * RETURN VALUE: * 0 No errors * 1 failed TCP read * 2 TLI t_rcvudata error, not TSYSERR and EINTR * 3 TLI t_rcvudata error, TSYSERR and EINTR * * SIDE EFFECTS: * None * * EXCEPTIONS: * If ECONNREFUSED is returned from a datagram type socket, this * means that the remote end has sent us an ICMP PORT UNREACHABLE * or an ICMP PROTOCOL UNREACHABLE. If the caller specifies a * "from" return buffer, then this means he has no specific * connection to that remote end, and we'll ignore the error * (SPR 4756). If the caller does not specify a "from" return * buffer, then we assume this means he has "connected" the UDP * socket to the remote address, so the error means the peer is * gone. * * ASSUMPTIONS: * "from == NULL" means that we've done an api_connect() on this * socket, and "from != NULL" means that we haven't. */ int api_rcvud(cc_p, al_p, fd, tlireqp, cbuff, app_nam, sho_err, from) int *cc_p, *al_p; /* charc count and addr len ptrs */ int fd; /* file descriptor of transport endpoint */ char *cbuff; char *app_nam; int sho_err; /* TRUE-show error, FALSE-don't show error */ struct sockaddr_in *from; /* ptr to address of originator of mesg */ #ifdef TLI struct t_unitdata *tlireqp; { int flags,i,retval; char err_msg[80]; struct t_unitdata tlireq; struct t_uderr uderr; struct sockaddr addr; tlireq.udata.buf = cbuff; tlireq.udata.maxlen = *cc_p; tlireq.addr.maxlen = sizeof(addr); tlireq.addr.buf = (char *)&addr; tlireq.opt.maxlen = 0; tlireq.opt.buf = NULL; retval = 0; while (retval == 0) { flags = 0; if (t_rcvudata(fd,&tlireq,&flags) >= 0) break; switch (t_errno) { case TNODATA: retval = 4; break; case TSYSERR: if (errno == ECONNREFUSED && from != NULL) continue; if (errno == EINTR) retval = 3; else retval = 2; break; case TLOOK: i = t_look(fd); if (i != T_UDERR) { if (sho_err) fprintf(stderr, "%s: api_rcvud/t_look returned %d\n", app_nam,i); retval = 2; break; } uderr.addr.buf = (char *)&addr; uderr.addr.maxlen = sizeof(addr); uderr.opt.buf = NULL; uderr.opt.maxlen = 0; if (t_rcvuderr(fd,&uderr) < 0) { if (sho_err) { sprintf(err_msg,"%s: api_rcvud/t_rcvuderr", app_nam); t_error(err_msg); } retval = 2; break; } break; default: if (sho_err) { sprintf(err_msg,"%s: api_rcvud/t_rcvudata failed.", app_nam); t_error(err_msg); } retval = 2; break; } } if (retval == 0) { *cc_p = tlireq.udata.len; if (from != 0) { *al_p = tlireq.addr.len; bcopy(tlireq.addr.buf,from,*al_p); } } else { *cc_p = 0; if (from != 0) *al_p = 0; } return retval; } #else int *tlireqp; { char err_msg[80]; /* If we already ran connect() just do a read else readfrom */ if (from == 0) { #ifdef _WIN32 if((*cc_p = recv(fd, cbuff, *cc_p, 0)) <= 0) { if((*cc_p != SOCKET_ERROR) && (sho_err)) { sprintf (err_msg, "%s:read failed. errno %d", app_nam, WSAGetLastError()); perror(err_msg); } XylogicsWSAGetLastError(); #else if((*cc_p = recv(fd, cbuff, *cc_p, 0)) <= 0) { if(sho_err) { sprintf (err_msg, "%s:read failed. errno %d", app_nam, errno); perror(err_msg); } #endif return(1); } return(0); } for (;;) { *cc_p = recvfrom(fd, cbuff, *cc_p, 0, (struct sockaddr *)from, al_p); XylogicsWSAGetLastError(); if (*cc_p < 0) { /* We're not connected, so just toss this error. */ if (errno == ECONNREFUSED) continue; if (errno != EINTR) { sprintf(err_msg,"%s: rcvfrom", app_nam); perror(err_msg); } return(3); } return(0); } } #endif /***************************************************************************** * * NAME: * api_sndud() * * DESCRIPTION: * Send user datagram vai API * * ARGUMENTS: * fd transpoint endpoint file descriptor * alen length of destination address * to destination address struct * tlireqsnd TLI specific send struct * databuf ptr to buffer to send * dlen length of buffer to send * sho_err TRUE-show errors; FALSE-don't show errors * * RETURN VALUE: * 0 no errors * 1 TLI send failed * 2 Socket sendto Failed * * SIDE EFFECTS: * * None * * EXCEPTIONS: * * None * * ASSUMPTIONS: * tlireqsnd struct has tx data buffer allocated; DATA from cbuff will * be moved to tlireqsnd-udata.buf, NOT just the ptr to cbuff. * */ int api_sndud(fd, alen, to, tlireqsndp, cbuff, dlen, app_nam, sho_err) int fd, /* transport endpoint file descriptor */ alen, /* length of address */ sho_err, /* flag; !=0 Show errors */ dlen; /* length of data to transmit */ unsigned char *cbuff; /* ptr to data to txmit */ struct sockaddr_in *to; /* ptr to socket struct */ char *app_nam; #ifdef TLI struct t_unitdata *tlireqsndp; { char err_msg[80]; struct t_unitdata tlireqsnd; tlireqsnd.addr.buf = (char *)to; tlireqsnd.addr.len = alen; tlireqsnd.udata.buf = (char *)cbuff; tlireqsnd.udata.len = dlen; tlireqsnd.opt.buf = NULL; tlireqsnd.opt.len = 0; if (t_sndudata(fd,&tlireqsnd) < 0) { if (sho_err) { sprintf(err_msg,"%s: api_sndud/t_sndudata failed", app_nam); t_error(err_msg); } return 1; } return 0; } #else int *tlireqsndp; { char err_msg[80]; if (sendto(fd, cbuff, dlen, 0, (struct sockaddr *)to, alen) < 0) { if (sho_err) { sprintf (err_msg, "%s:sendto failed", app_nam); perror(err_msg); } XylogicsWSAGetLastError(); return(2); } XylogicsWSAGetLastError(); return(0); } #endif /***************************************************************************** * * NAME: * api_release() * * DESCRIPTION: * Orderly release of transport connection. * * ARGUMENTS: * fd File descriptor of transport endpoint * howto How to release file. Passed to shutdown() * (Socket API only) * app_nam Ptr to name of application * * RETURN VALUE: * 0 Success * -1 Release failed * */ int api_release(fd, howto, app_nam) int fd, howto; char *app_nam; #ifdef TLI { char err_msg[80]; if (t_sndrel(fd) < 0) { sprintf(err_msg,"%s: t_sndrel failed", app_nam); t_error(err_msg); return(-1); } return(0); } #else { char err_msg[80]; if (shutdown(fd, howto) == -1) { /* Telnet connection down */ sprintf(err_msg,"%s: shutdown failed", app_nam); perror(err_msg); XylogicsWSAGetLastError(); return(-1); } XylogicsWSAGetLastError(); return(0); } #endif /***************************************************************************** * * NAME: * api_close() * * DESCRIPTION: * Close given transport endpoint * * ARGUMENTS: * fd File descriptor of transport endpoint * * RETURN VALUE: * 0 Success * -1 Close failed * * SIDE EFFECTS: * File closed * */ int api_close(fd) int fd; { #ifdef TLI struct rmt_addr *np,*npp; npp = NULL; np = rmt_head; for (; np != NULL; npp = np,np = np->next) if (np->fd == fd) { if (npp == NULL) rmt_head = np->next; else npp = np->next; free(np); break; } (void)t_close(fd); #else #ifdef _WIN32 closesocket(fd); XylogicsWSAGetLastError(); #else (void)close(fd); #endif #endif return 0; } #ifdef NOTDEF /***************************************************************************** * * NAME: * api_nblk * * DESCRIPTION: * Set file control non-blocking on or off * * ARGUMENTS: * fd transport endpoint file descriptor * nonblk FALSE - turn off "nonblocking" * TRUE - turn on "nonblocking" * * RETURN VALUE: * None * * None */ void api_nblk(fd, nonblk) int fd, nonblk; /* non-blocking flag */ { #ifdef TLI (void)fcntl(fd,F_SETFL,nonblk?O_NDELAY:0); #else int flag; flag = nonblk ? 1 : 0; #ifdef _WIN32 (void)ioctlsocket(fd, FIONBIO, (caddr_t)&flag); XylogicsWSAGetLastError(); #else /* _WIN32 */ (void)ioctl(fd, FIONBIO, (caddr_t)&flag); #endif #endif } #endif /* NOTDEF */ /***************************************************************************** * * NAME: * api_opt() * * DESCRIPTION: * Set/clear given transport layer option * * ARGUMENTS: * fd file descriptor for transport endpoint * option option to set or clear * flag TRUE-set option; FALSE-clear option. * app_name ptr to name of application * * RETURN VALUE: * 0 success * -1 error occurred * * SIDE EFFECTS: * * None * * EXCEPTIONS: * * None * * ASSUMPTIONS: * * None */ int api_opt(fd,option,flag,app_nam) int fd, option, flag; char *app_nam; #ifdef TLI { char on=1; char off=0; char err_msg[80]; int len; struct opthdr *ohdr; struct t_optmgmt topt; struct linger *ling; if (option > MAX_TO_OPTS) { sprintf(err_msg,"%s: Transport option (%d) not available", app_nam, option); perror(err_msg); return(-1); } switch(tp_opt[option]) { case 0: return(0); case SO_LINGER: len = sizeof(struct opthdr) + OPTLEN(sizeof(struct linger)); break; default: len = sizeof(struct opthdr) + OPTLEN(sizeof(int)); break; } if ((topt.opt.buf = malloc(len)) == NULL) { perror(app_nam); return(-1); } topt.opt.len = topt.opt.maxlen = len; topt.flags = T_NEGOTIATE; ohdr = (struct opthdr *)topt.opt.buf; ohdr->level = SOL_SOCKET; ohdr->name = tp_opt[option]; if (tp_opt[option] == SO_LINGER) { ohdr->len = OPTLEN(sizeof(struct linger)); ling = (struct linger*)OPTVAL(ohdr); ling->l_onoff = (flag ? on : off); ling->l_linger = DEF_LINGER_TIME; } else { ohdr->len = OPTLEN(sizeof(int)); *((int *)OPTVAL(ohdr)) = (flag ? on : off); } if (t_optmgmt(fd, &topt, &topt) == -1) { sprintf(err_msg, "%s: t_optmgmt", app_nam); t_error(err_msg); free(topt.opt.buf); return(-1); } free(topt.opt.buf); return(0); } #else /* Sockets */ { char err_msg[80]; char on=1, off=0, *opt_cmd; struct linger ling; int len; if (option > MAX_TO_OPTS) { sprintf(err_msg,"%s: Transport option (%d) not available", app_nam, option); perror(err_msg); return(-1); } switch(tp_opt[option]) { case 0: return(0); case SO_LINGER: len = sizeof(struct linger); ling.l_onoff = (flag ? on : off); ling.l_linger = DEF_LINGER_TIME; opt_cmd = (char*)&ling; break; default: len = sizeof(int); opt_cmd = (flag ? &on : &off); break; } #if !defined(EXOS) && !defined(SLIP) /* no setsockopt() in SLIP library */ if (setsockopt(fd,SOL_SOCKET,tp_opt[option],opt_cmd,len) < 0) { sprintf(err_msg,"%s: setsockopt (%d)", app_nam,tp_opt[option]); perror(err_msg); XylogicsWSAGetLastError(); return(-1); } XylogicsWSAGetLastError(); #endif /*SLIP*/ return(0); } #endif #ifdef NOTDEF /* Print unitdata struct */ #ifdef TLI print_unitdata(x) struct t_unitdata *x; { int i; printf("***** sending to tcp *********\n"); printf("tlireq->addr.maxlen = %d\n", x->addr.maxlen); printf("tlireq->addr.len = %d\n", x->addr.len); printf("tlireq->addr.buf = "); for (i=0; i < x->addr.len && i < 50; i++) printf("%02x ", *(x->addr.buf+i)); printf("\n"); printf("tlireq->udata.maxlen = %d\n", x->addr.maxlen); printf("tlireq->udata.len = %d\n", x->addr.len); printf("tlireq->udata.buf = "); for (i=0; i < x->udata.len && i < 50; i++) printf("%02x ", *(x->udata.buf+i)); printf("\n"); } #endif #endif