1 /*
2  * ***************************************************************************
3  * MALOC = < Minimal Abstraction Layer for Object-oriented C >
4  * Copyright (C) 1994-- Michael Holst
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * rcsid="$Id: vio.c,v 1.32 2010/08/12 05:40:30 fetk Exp $"
21  * ***************************************************************************
22  */
23 
24 /*
25  * ***************************************************************************
26  * File:     vio.c
27  *
28  * Purpose:  Class Vio: methods.
29  *
30  * Author:   Michael Holst
31  * ***************************************************************************
32  */
33 
34 #include "vio_p.h"
35 
36 VEMBED(rcsid="$Id: vio.c,v 1.32 2010/08/12 05:40:30 fetk Exp $")
37 
38 #if defined(HAVE_UNISTD_H)
39 #   include <unistd.h>
40 #endif
41 
42 #if defined(HAVE_SYS_TYPES_H)
43 #   include <sys/types.h>
44 #endif
45 
46 #if defined(HAVE_SYS_STAT_H)
47 #   include <sys/stat.h>
48 #endif
49 
50 #if defined(HAVE_FCNTL_H)
51 #   include <fcntl.h>
52 #endif
53 
54 #if defined(HAVE_SYS_SOCKET_H)
55 #   include <sys/socket.h>
56 #endif
57 
58 #if defined(HAVE_SYS_UN_H)
59 #   include <sys/un.h>
60 #endif
61 
62 #if defined(HAVE_NETINET_IN_H)
63 #   include <netinet/in.h>
64 #endif
65 
66 #if defined(HAVE_ARPA_INET_H)
67 #   include <arpa/inet.h>
68 #endif
69 
70 #if defined(HAVE_NETDB_H)
71 #   include <netdb.h>
72 #endif
73 
74 
75 #if defined(HAVE_RPC_RPC_H)
76 #   include <rpc/rpc.h>
77 #elif defined(HAVE_RPC_H)
78 #   include <rpc.h>
79 #endif
80 
81 
82 /*#include <rpc/rpc.h>*/
83 
84 #if defined(HAVE_WINSOCK_H)
85 #   include <winsock.h>
86 #endif
87 
88 #if defined(HAVE_IO_H)
89 #   include <io.h>
90 #endif
91 
92 /* ASC modes as dual to the XDR modes */
93 typedef enum ASCmode {
94     ASC_NO_MODE,
95     ASC_DECODE,
96     ASC_ENCODE
97 } ASCmode;
98 
99 /* ASC structure as dual to the XDR structure */
100 typedef struct ASC {
101     ASCmode mode;                    /* ASC_DECODE or ASC_ENCODE            */
102     int     pos;                     /* position of next character in buf   */
103     int     size;                    /* size of buf                         */
104     char    *buf;                    /* the character buffer                */
105     char    whiteChars[VMAX_ARGNUM]; /* white space character set           */
106     char    commChars[VMAX_ARGNUM];  /* comment character set               */
107     int     error;                   /* APBS-KTS: Currently for EOF cond    */
108 } ASC;
109 
110 /* use ASC in place of XDR if XDR does not exist */
111 #if !defined(HAVE_XDR)
112 #   define XDR           ASC
113 #   define XDR_DECODE    ASC_DECODE
114 #   define XDR_ENCODE    ASC_ENCODE
115 #   define xdrmem_create ascmem_create
116 #   define xdr_destroy   asc_destroy
117 #   define xdr_getpos    asc_getpos
118 #   define xdr_setpos    asc_setpos
119 #   define xdr_string    asc_string
120 #   define xdr_char      asc_char
121 #   define xdr_int       asc_int
122 #   define xdr_float     asc_float
123 #   define xdr_double    asc_double
124 #endif
125 
126 /* communication startup */
127 VPRIVATE int VIOstarted = 0;
128 
129 /* default comment char set and white space char set */
130 VPRIVATE char *VIOwhiteChars = " \t\n";
131 VPRIVATE char *VIOcommChars  = "";
132 
133 /* initialization, signals, and other tools */
134 VPRIVATE void VIOregHand(void);
135 VPRIVATE void VIOunregHand(void);
136 VPRIVATE void VIOsigHand(int num);
137 VPRIVATE int VIOgethostname(char *name, unsigned int len);
138 VPRIVATE const char *VIOstrerrno(int err);
139 
140 /* buffer management */
141 VPRIVATE void Vio_initIoPutBuffers(Vio *thee);
142 VPRIVATE void Vio_purgePutBuffer(Vio *thee);
143 VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize);
144 
145 /* ASC analogs to the core XDR routines */
146 VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode);
147 VPRIVATE void asc_destroy(ASC *thee);
148 VPRIVATE int asc_getpos(ASC *thee);
149 VPRIVATE int asc_setpos(ASC *thee, int pos);
150 VPRIVATE int asc_string(ASC *thee, char **sval, int size);
151 VPRIVATE int asc_char(ASC *thee, char *cval);
152 VPRIVATE int asc_int(ASC *thee, int *ival);
153 VPRIVATE int asc_float(ASC *thee, float *fval);
154 VPRIVATE int asc_double(ASC *thee, double *dval);
155 
156 /* some additional ASC routines (no analogs in XDR) */
157 VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars);
158 VPRIVATE void asc_setCommChars(ASC *thee, char *commChars);
159 VPRIVATE char *asc_getToken(ASC *thee, char *tok, int toksize);
160 
161 /* two low-level file-descriptor i/o jewels from Rick Steven's book */
162 VPRIVATE int readn(int fd, void *vptr, unsigned int n);
163 VPRIVATE int writen(int fd, void *vptr, unsigned int n) ;
164 
165 /*
166  * ***************************************************************************
167  * Class Vio: Inlineable methods
168  * ***************************************************************************
169  */
170 #if !defined(VINLINE_MALOC)
171 
172 #endif /* if !defined(VINLINE_MALOC) */
173 /*
174  * ***************************************************************************
175  * Class Vio: Non-inlineable methods
176  * ***************************************************************************
177  */
178 
179 /*
180  * ***************************************************************************
181  * Routine:  Vio_start
182  *
183  * Purpose:  Startup the Vio communication layer.
184  *
185  * Notes:    This routine initializes some internal variables and buffers.
186  *           This routine also deals with the interception of fatal
187  *           SIGPIPE signals which are generated on some systems when a
188  *           socket connection is broken by one of the send/receive pair.
189  *
190  *           We don't want to abort in this situation, but rather do some
191  *           damage control.  Hence we register our own SIGPIPE interrupt
192  *           handler in Vio_start(), and re-register it every time a SIGPIPE
193  *           is intercepted.  We re-register it because some systems reset
194  *           the interrupt mask after a single interrupt is generated.
195  *           We un-register the SIGPIPE handler in Vio_stop().
196  *
197  *           To use the Vio library, you need to call Vio_start() before
198  *           you make any calls to the Vio_ctor().  Calling the Vio_ctor()
199  *           (or any other Vio method) before Vio_start() generates an error.
200  *           For example, you can call this routine as follows:
201  *
202  *               Vio_start()
203  *
204  * Author:   Michael Holst
205  * ***************************************************************************
206  */
Vio_start(void)207 VPUBLIC void Vio_start(void)
208 {
209     /* repeated initializations ARE legal (no error; possibly frees memory) */
210     /* VASSERT( !VIOstarted ); */
211 
212     /* mark as initialized */
213     VIOstarted = 1;
214 
215     /* register the SIGPIPE handler to avoid aborts on a SIGPIPE */
216     VIOregHand();
217 
218     /* normal return */
219     return;
220 }
221 
222 /*
223  * ***************************************************************************
224  * Routine:  Vio_stop
225  *
226  * Purpose:  Shutdown the Vio communication layer.
227  *
228  * Notes:    This routine was written primarily to deal with some
229  *           communication runtime environments which require a shutdown.
230  *
231  * Author:   Michael Holst
232  * ***************************************************************************
233  */
Vio_stop(void)234 VPUBLIC void Vio_stop(void)
235 {
236     /* repeated de-initializations ARE legal (no error; just a no-op) */
237     /* VASSERT( VIOstarted ); */
238 
239     /* un-initialize us */
240     VIOstarted = 0;
241 
242     /* un-register the SIGPIPE handler */
243     VIOunregHand();
244 
245     /* normal return */
246     return;
247 }
248 
249 /*
250  * ***************************************************************************
251  * Routine:  VIOregHand
252  *
253  * Purpose:  Register the signal handler with the operating system.
254  *
255  * Author:   Michael Holst
256  * ***************************************************************************
257  */
VIOregHand(void)258 VPRIVATE void VIOregHand(void)
259 {
260 #if !defined(HAVE_WINSOCK_H)
261     VASSERT( signal(SIGPIPE,&VIOsigHand) != SIG_ERR );
262 #endif
263 }
264 
265 /*
266  * ***************************************************************************
267  * Routine:  VIOunregHand
268  *
269  * Purpose:  Un-Register the signal handler with the operating system.
270  *
271  * Author:   Michael Holst
272  * ***************************************************************************
273  */
VIOunregHand(void)274 VPRIVATE void VIOunregHand(void)
275 {
276 #if !defined(HAVE_WINSOCK_H)
277     VASSERT( signal(SIGPIPE,SIG_DFL) != SIG_ERR );
278 #endif
279 }
280 
281 /*
282  * ***************************************************************************
283  * Routine:  VIOsigHand
284  *
285  * Purpose:  Handle events such as SIGPIPE.
286  *
287  * Author:   Michael Holst
288  * ***************************************************************************
289  */
VIOsigHand(int num)290 VPRIVATE void VIOsigHand(int num)
291 {
292     /* some i/o */
293     fprintf(stderr,"VIOsigHand: yow! caught a hot SIGPIPE....diffused it.\n");
294 
295     /* just re-register interrupt handler in case it was cleared by default */
296     VIOregHand();
297 }
298 
299 /*
300  * ***************************************************************************
301  * Routine:  VIOgethostname
302  *
303  * Purpose:  Get the hostname of this machine.
304  *           Returns 0 on success.  Returns -1 on error.
305  *
306  * Author:   Michael Holst
307  * ***************************************************************************
308  */
VIOgethostname(char * name,unsigned int len)309 VPRIVATE int VIOgethostname(char *name, unsigned int len)
310 {
311 #if defined(HAVE_WINSOCK_H)
312     return gethostname(name,(int)len);
313 #else
314     return gethostname(name,len);
315 #endif
316 }
317 
318 /*
319  * ***************************************************************************
320  * Routine:  VIOstrerrno
321  *
322  * Purpose:  Return the error string corresponding to the error number.
323  *
324  * Notes:    This is a partial implementation of the "iberty" library
325  *           function "strerrno" that exists on most Linux boxes.  It is
326  *           simply a mapping of error number to error string.  It is
327  *           very useful for debugging UNIX and INET socket code.
328  *
329  * Author:   Michael Holst
330  * ***************************************************************************
331  */
VIOstrerrno(int err)332 VPRIVATE const char *VIOstrerrno(int err)
333 {
334     static char errstr[VMAX_ARGLEN];
335 
336     if      (err == EFAULT           ) strcpy(errstr,"EFAULT");
337     else if (err == EINTR            ) strcpy(errstr,"EINTR");
338     else if (err == EINVAL           ) strcpy(errstr,"EINVAL");
339     else if (err == ENOENT           ) strcpy(errstr,"ENOENT");
340     else if (err == EPIPE            ) strcpy(errstr,"EPIPE");
341     else if (err == ENOMEM           ) strcpy(errstr,"ENOMEM");
342     else if (err == EAGAIN           ) strcpy(errstr,"EAGAIN");
343     else if (err == EBADF            ) strcpy(errstr,"EBADF");
344 
345 #if defined(HAVE_WINSOCK_H)
346     else if (err == WSAENETDOWN      ) strcpy(errstr,"WSAENETDOWN");
347     else if (err == WSAEFAULT        ) strcpy(errstr,"WSAEFAULT");
348     else if (err == WSAENOTCONN      ) strcpy(errstr,"WSAENOTCONN");
349     else if (err == WSAEINTR         ) strcpy(errstr,"WSAEINTR");
350     else if (err == WSAEINPROGRESS   ) strcpy(errstr,"WSAEINPROGRESS");
351     else if (err == WSAENETRESET     ) strcpy(errstr,"WSAENETRESET");
352     else if (err == WSAENOTSOCK      ) strcpy(errstr,"WSAENOTSOCK");
353     else if (err == WSAEOPNOTSUPP    ) strcpy(errstr,"WSAEOPNOTSUPP");
354     else if (err == WSAESHUTDOWN     ) strcpy(errstr,"WSAESHUTDOWN");
355     else if (err == WSAEWOULDBLOCK   ) strcpy(errstr,"WSAEWOULDBLOCK");
356     else if (err == WSAEMSGSIZE      ) strcpy(errstr,"WSAEMSGSIZE");
357     else if (err == WSAEINVAL        ) strcpy(errstr,"WSAEINVAL");
358     else if (err == WSAETIMEDOUT     ) strcpy(errstr,"WSAETIMEDOUT");
359     else if (err == WSAECONNABORTED  ) strcpy(errstr,"WSAECONNABORTED");
360     else if (err == WSAECONNREFUSED  ) strcpy(errstr,"WSAECONNREFUSED");
361     else if (err == WSAECONNRESET    ) strcpy(errstr,"WSAECONNRESET");
362     else if (err == WSANOTINITIALISED) strcpy(errstr,"WSANOTINITIALISED");
363 #else
364     else if (err == ENETDOWN         ) strcpy(errstr,"ENETDOWN");
365     else if (err == ENOTCONN         ) strcpy(errstr,"ENOTCONN");
366     else if (err == EINPROGRESS      ) strcpy(errstr,"EINPROGRESS");
367     else if (err == ENETRESET        ) strcpy(errstr,"ENETRESET");
368     else if (err == ENOTSOCK         ) strcpy(errstr,"ENOTSOCK");
369     else if (err == EOPNOTSUPP       ) strcpy(errstr,"EOPNOTSUPP");
370     else if (err == ESHUTDOWN        ) strcpy(errstr,"ESHUTDOWN");
371     else if (err == EWOULDBLOCK      ) strcpy(errstr,"EWOULDBLOCK");
372     else if (err == EMSGSIZE         ) strcpy(errstr,"EMSGSIZE");
373     else if (err == ETIMEDOUT        ) strcpy(errstr,"ETIMEDOUT");
374     else if (err == ECONNABORTED     ) strcpy(errstr,"ECONNABORTED");
375     else if (err == ECONNREFUSED     ) strcpy(errstr,"ECONNREFUSED");
376     else if (err == ECONNRESET       ) strcpy(errstr,"ECONNRESET");
377     else if (err == ENOBUFS          ) strcpy(errstr,"ENOBUFS");
378 #endif
379 
380     else sprintf(errstr,"VIO_UNKNOWN_ERROR(%d)",err);
381     return errstr;
382 }
383 
384 /*
385  * ***************************************************************************
386  * Routine:  Vio_ctor
387  *
388  * Purpose:  Construct the [sdio/file/buff/unix/inet] container object.
389  *
390  * Author:   Michael Holst
391  * ***************************************************************************
392  */
Vio_ctor(const char * socktype,const char * datafrmt,const char * hostname,const char * filename,const char * rwkey)393 VPUBLIC Vio* Vio_ctor(const char *socktype, const char *datafrmt,
394     const char *hostname, const char *filename, const char *rwkey)
395 {
396     Vio *thee = VNULL;
397 
398     /* make sure Vio was started */
399     VJMPERR1( VIOstarted );
400 
401     thee = (Vio*)calloc( 1, sizeof(Vio) );
402     VJMPERR2( thee != VNULL );
403     VJMPERR3( Vio_ctor2(thee, socktype, datafrmt, hostname, filename, rwkey) );
404 
405     /* normal return */
406     return thee;
407 
408   VERROR1:
409     fprintf(stderr,"Vio_ctor: Vio library has not been started.\n");
410     return VNULL;
411 
412   VERROR2:
413     fprintf(stderr,"Vio_ctor: malloc of Vio structure failed.\n");
414     return VNULL;
415 
416   VERROR3:
417     fprintf(stderr,"Vio_ctor: Vio_ctor2() failed.\n");
418     Vio_dtor(&thee);
419     return VNULL;
420 }
421 
422 /*
423  * ***************************************************************************
424  * Routine:  Vio_ctor2
425  *
426  * Purpose:  Construct the [sdio/file/buff/unix/inet] container object.
427  *
428  * Author:   Michael Holst
429  * ***************************************************************************
430  */
Vio_ctor2(Vio * thee,const char * socktype,const char * datafrmt,const char * hostname,const char * filename,const char * rwkey)431 VPUBLIC int Vio_ctor2(Vio *thee, const char *socktype, const char *datafrmt,
432     const char *hostname, const char *filename, const char *rwkey)
433 {
434     int n, ival;
435     char host[VMAX_ARGLEN];
436     struct linger ling;
437     unsigned int len;
438     struct hostent *hpTmp;
439 #if defined(HAVE_WINSOCK_H)
440     WSADATA wsaData;
441 #endif
442 #if defined(HAVE_SYS_UN_H)
443     char username[VMAX_ARGLEN];
444 #endif
445 
446     /* make sure Vio was started */
447     VJMPERR1( VIOstarted );
448 
449     /* initialize all Vio fields */
450     thee->type     = VIO_NO_TYPE;
451     thee->frmt     = VIO_NO_FRMT;
452     thee->rwkey    = VIO_NO_RW;
453     thee->error    = 0;
454     thee->dirty    = 0;
455     thee->fp       = VNULL;
456     thee->axdr     = VNULL;
457     thee->so       = -1;
458     thee->soc      = -1;
459     thee->name     = VNULL;
460 
461     /* initialize the internal buffer (for BUFF datatype) */
462     thee->VIObuffer = VNULL;
463     thee->VIObufferLen = 0;
464     thee->VIObufferPtr = 0;
465 
466     /* initialize the socktype field */
467     if (!strcmp(socktype,"SDIO")) {
468         thee->type = VIO_SDIO;
469     } else if (!strcmp(socktype,"FILE")) {
470         thee->type = VIO_FILE;
471     } else if (!strcmp(socktype,"BUFF")) {
472         thee->type = VIO_BUFF;
473     } else if (!strcmp(socktype,"UNIX")) {
474         thee->type = VIO_UNIX;
475     } else if (!strcmp(socktype,"INET")) {
476         thee->type = VIO_INET;
477     } else {
478         fprintf(stderr,"Vio_ctor2: Incorrect socktype given <%s>\n",socktype);
479         VJMPERR2( 0 );
480     }
481 
482     /* initialize the datafrmt field */
483     if (!strcmp(datafrmt,"ASC")) {
484         thee->frmt = VIO_ASC;
485     } else if (!strcmp(datafrmt,"XDR")) {
486         thee->frmt = VIO_XDR;
487     } else {
488         fprintf(stderr,"Vio_ctor2: Incorrect datafrmt given <%s>\n", datafrmt);
489         VJMPERR2( 0 );
490     }
491 
492     /* initialize the r/w field */
493     if (!strcmp(rwkey,"r")) {
494         thee->rwkey = VIO_R;
495     } else if (!strcmp(rwkey,"w")) {
496         thee->rwkey = VIO_W;
497     } else {
498         fprintf(stderr,"Vio_ctor2: Incorrect rwkey given <%s>\n", rwkey);
499         VJMPERR2( 0 );
500     }
501 
502     /* need to call this stupid Win32 function before gethostname... */
503 #if defined(HAVE_WINSOCK_H)
504     if ( WSAStartup(0x0101, &wsaData) != 0 ) {
505         fprintf(stderr, "Vio_ctor2: WSAStartup fail INET sock <%s>"
506             " dueto <%s>\n", thee->file,VIOstrerrno(errno));
507         VJMPERR2( 0 );
508     }
509 #endif
510 
511     /* get "my" local hostname */
512     if ((VIOgethostname(thee->lhost,sizeof(thee->lhost))) < 0) {
513         fprintf(stderr,
514             "Vio_ctor2: Gethostname fail INET sock <%s> dueto <%s>\n",
515             thee->file, VIOstrerrno(errno));
516         strcpy(thee->lhost,"unknown");
517     } else if ((hpTmp=gethostbyname(thee->lhost))==VNULL) {
518         fprintf(stderr,
519             "Vio_ctor2: Gethostbyname fail INET sock <%s> dueto <%s>\n",
520             thee->file, VIOstrerrno(errno));
521         strcpy(thee->lhost,"unknown");
522     } else strcpy(thee->lhost,hpTmp->h_name);
523 
524     /* default remote hostname */
525     strcpy(thee->rhost,"unknown");
526 
527     /* initialize the buffer space */
528     Vio_initIoPutBuffers(thee);
529 
530     /* SDIO READ/WRITE SETUP */
531     if (thee->type==VIO_SDIO) {
532 
533         if (thee->rwkey==VIO_R) {
534             thee->fp = stdin;
535         } else { /* (thee->rwkey==VIO_W) */
536             thee->fp = stdout;
537         }
538         VJMPERR2( thee->fp != VNULL );
539 
540     /* FILE READ/WRITE SETUP */
541     } else if (thee->type==VIO_FILE) {
542 
543         /* filename is the i/o file name */
544         if (strlen(filename) >= VMAX_ARGLEN) {
545             fprintf(stderr, "Vio_ctor2: Filename <%d> exceeds max <%d>!\n",
546                 (int)strlen(filename), VMAX_ARGLEN);
547             VJMPERR2( 0 );
548         }
549         strncpy(thee->file, filename, VMAX_ARGLEN);
550         if (thee->rwkey==VIO_R) {
551             thee->fp = fopen(thee->file, "r");
552         } else { /* (thee->rwkey==VIO_W) */
553             thee->fp = fopen(thee->file, "w");
554         }
555         VJMPERR2( thee->fp != VNULL );
556 
557     /* BUFF READ/WRITE SETUP */
558     } else if (thee->type==VIO_BUFF) {
559 
560         /* filename is the internal buffer number for the buffer */
561         thee->VIObufferPtr = 0;
562 
563     /* UNIX SOCKET READ/WRITE SETUP */
564     } else if (thee->type==VIO_UNIX) {
565 
566 #if defined(HAVE_SYS_UN_H)
567 
568         /* filename is socketName-userName in the directory /tmp */
569 
570         VASSERT( Vnm_getuser(username, sizeof(username)) );
571         sprintf(thee->file, "/tmp/%s-%s", filename, username);
572 
573         /* create the socket address structure */
574         thee->name = (struct sockaddr_un *)
575             calloc( 1, sizeof(struct sockaddr_un) );
576         VJMPERR2( thee->name != VNULL );
577 
578         /* Get a socket structure */
579         if ((thee->so=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
580             fprintf(stderr,"Vio_ctor2: fail to find UNIX sock dueto <%s>.\n",
581                 VIOstrerrno(errno));
582             VJMPERR2( 0 );
583         } else {
584 
585             /* set REUSEADDR so sockets can be closed and reopened */
586             ival = 1;  /* just need a nonzero value */
587             if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
588               (void*)&ival,sizeof(ival)) < 0 ) {
589                 fprintf(stderr, "Vio_ctor2: Setsockopt1 fail UNIX sock <%s>"
590                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
591                 VJMPERR2( 0 );
592             }
593 
594             /* turn on LINGER so WRITES complete before socks close */
595             ling.l_onoff  = 1;   /* just need a nonzero value */
596             ling.l_linger = 30;  /* linger time in seconds */
597             if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
598               (void*)&ling,sizeof(ling)) < 0) {
599                 fprintf(stderr, "Vio_ctor2: Setsockopt2 fail UNIX sock <%s>"
600                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
601                 VJMPERR2( 0 );
602             }
603 
604             /* Setup for the socket */
605             memset(thee->name, '\0', sizeof(struct sockaddr_un));
606             ((struct sockaddr_un *)(thee->name))->sun_family = AF_UNIX;
607             strcpy(((struct sockaddr_un *)(thee->name))->sun_path,
608                 thee->file);
609 
610             /* if we are reader, WE are responsible for creating socket */
611             /* the reader must do: (unlink/)setsockopt/bind/listen */
612             if (thee->rwkey==VIO_R) {
613 
614                 /* define socket file; remove previous socket */
615                 unlink(thee->file);
616 
617                 /* determine structure size; AF_UNIX is variable length */
618                 len = sizeof(((struct sockaddr_un *)
619                               (thee->name))->sun_family)
620                     + strlen(((struct sockaddr_un *)
621                               (thee->name))->sun_path);
622 
623                 /* Bind socket to address (must setsockopts before bind) */
624                 if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
625                     fprintf(stderr,
626                         "Vio_ctor2: Bind fail UNIX sock <%s> dueto <%s>\n",
627                         thee->file, VIOstrerrno(errno));
628                     VJMPERR2( 0 );
629                 } else {
630 
631                     /* Tell socket to start listening for connections */
632                     if (listen(thee->so,5) < 0) {
633                         fprintf(stderr,
634                         "Vio_ctor2: List fail UNIX sock <%s> dueto <%s>\n",
635                         thee->file, VIOstrerrno(errno));
636                         VJMPERR2( 0 );
637                     }
638                 }
639             /*
640              * if we got to here, we can assume reader has done
641              * all of: (unlink/)setsockopt/bind/listen
642              */
643             }
644         }
645 #endif
646 
647     /* INET SOCKET READ/WRITE SETUP */
648     } else if (thee->type==VIO_INET) {
649 
650         /* filename is the port number for the socket */
651         if (strlen(filename) >= VMAX_ARGLEN) {
652             fprintf(stderr, "Vio_ctor2: Filename <%d> exceeds max <%d>!\n",
653                 (int)strlen(filename), VMAX_ARGLEN);
654             VJMPERR2( 0 );
655         }
656         strncpy(thee->file, filename, VMAX_ARGLEN);
657 
658         /* create the socket address structure */
659         thee->name = (struct sockaddr_in *)
660             calloc( 1, sizeof(struct sockaddr_in) );
661         VJMPERR2( thee->name != VNULL );
662 
663         /* Look for sockets */
664         if ((thee->so=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
665             fprintf(stderr,"Vio_ctor2: fail to find INET sock dueto <%s>\n",
666                 VIOstrerrno(errno));
667             VJMPERR2( 0 );
668         } else {
669 
670             /* set REUSEADDR so sockets can be closed and reopened */
671             ival = 1;  /* just need a nonzero value */
672             if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
673               (void*)&ival,sizeof(ival)) < 0 ) {
674                 fprintf(stderr, "Vio_ctor2: Setsockopt3 fail INET sock <%s>"
675                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
676                 VJMPERR2( 0 );
677             }
678 
679             /* turn on LINGER so WRITES complete before sockets close */
680             ling.l_onoff  = 1;   /* just need a nonzero value */
681             ling.l_linger = 30;  /* linger time in seconds */
682             if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
683               (void*)&ling,sizeof(ling)) < 0 ) {
684                 fprintf(stderr, "Vio_ctor2: Setsockopt4 fail INET sock <%s>"
685                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
686                 VJMPERR2( 0 );
687             }
688 
689             /* Setup for the socket */
690             memset(thee->name, '\0', sizeof(struct sockaddr_in));
691             ((struct sockaddr_in *)(thee->name))->sin_family = AF_INET;
692             ((struct sockaddr_in *)(thee->name))->sin_port
693                 = htons( (unsigned short) (VPORTNUMBER + atoi(thee->file)) );
694 
695             /* if we are the reader, WE must create the socket */
696             /* the reader must do: setsockopt/bind/listen */
697             if (thee->rwkey==VIO_R) {
698 
699                 /* use wildcard address */
700                 n = INADDR_ANY;
701                 memcpy(&((struct sockaddr_in *)(thee->name))->sin_addr,
702                     &n, sizeof(long));
703 
704                 /* determine structure size; AF_INET is fixed length */
705                 len = sizeof(struct sockaddr_in);
706 
707                 /* Bind socket to address (must setsockopts before bind) */
708                 if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
709                     fprintf(stderr,
710                         "Vio_ctor2: Bind fail INET sock <%s> dueto <%s>\n",
711                         thee->file, VIOstrerrno(errno));
712                     VJMPERR2( 0 );
713                 } else {
714 
715                     /* Tell socket to start listening for connections */
716                     if (listen(thee->so,5) < 0) {
717                         fprintf(stderr,
718                             "Vio_ctor2: List fail INET sock <%s> dueto <%s>\n",
719                             thee->file, VIOstrerrno(errno));
720                         VJMPERR2( 0 );
721                     }
722                 }
723 
724             /* assume reader has done: setsockopt/bind/listen */
725             } else {
726 
727                 /* network address of port -- "localhost" means WE have port */
728                 if (!strcmp(hostname,"localhost")) {
729                     strcpy(host,thee->lhost);
730                 } else {
731                     strcpy(host,hostname);
732                 }
733 
734                 /* get IP address corresponding to this server hostname */
735                 if ((hpTmp=gethostbyname(host))==VNULL) {
736                     fprintf(stderr,
737                         "Vio_ctor2: Gethostbyname fail INET sock <%s>"
738                         " dueto <%s>\n", thee->file, VIOstrerrno(errno));
739                     VJMPERR2( 0 );
740                 } else {
741 
742                     /* just need to save address of host that has socket */
743                     memcpy(
744                         &(((struct sockaddr_in *)(thee->name))->sin_addr),
745                         hpTmp->h_addr_list[0], (unsigned int)hpTmp->h_length);
746 
747                     /* save the hostname for the port for later i/o */
748                     strcpy(thee->rhost,hpTmp->h_name);
749                 }
750             }
751         }
752     }
753 
754     /* initialize <asc,xdr> datastructures; must do almost at the end */
755     if (thee->frmt==VIO_ASC) {
756         thee->axdr = (ASC*)calloc( 1, sizeof(ASC) );
757         VJMPERR2( thee->axdr != VNULL );
758         if (thee->rwkey==VIO_R) {
759             ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_DECODE);
760         } else { /* if (thee->rwkey==VIO_W) */
761             ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_ENCODE);
762         }
763     } else if (thee->frmt==VIO_XDR) {
764         thee->axdr = (XDR*)calloc( 1, sizeof(XDR) );
765         VJMPERR2( thee->axdr != VNULL );
766         if (thee->rwkey==VIO_R) {
767             xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_DECODE);
768         } else { /* if (thee->rwkey==VIO_W) */
769             xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_ENCODE);
770         }
771     }
772 
773     /* lastly: default white/comment char sets (careful! propogates to axdr) */
774     Vio_setWhiteChars(thee, VIOwhiteChars);
775     Vio_setCommChars(thee,  VIOcommChars);
776 
777     /* return without error */
778     return 1;
779 
780   VERROR1:
781     fprintf(stderr,"Vio_ctor2: Vio library has not been started.\n");
782     return 0;
783 
784   VERROR2:
785     fprintf(stderr,"Vio_ctor2: some error occurred.\n");
786     return 0;
787 }
788 
789 /*
790  * ***************************************************************************
791  * Routine:  Vio_dtor
792  *
793  * Purpose:  Destroy the [sdio/file/buff/unix/inet] container object.
794  *
795  * Author:   Michael Holst
796  * ***************************************************************************
797  */
Vio_dtor(Vio ** thee)798 VPUBLIC void Vio_dtor(Vio **thee)
799 {
800     if ((*thee) != VNULL) {
801         if ((*thee)->VIObuffer != VNULL) {
802             free( (*thee)->VIObuffer );
803             (*thee)->VIObuffer = VNULL;
804         }
805         Vio_dtor2(*thee);
806         free( (*thee) );
807         (*thee) = VNULL;
808     }
809 }
810 
811 /*
812  * ***************************************************************************
813  * Routine:  Vio_dtor2
814  *
815  * Purpose:  Destroy the [sdio/file/buff/unix/inet] container object.
816  *
817  * Author:   Michael Holst
818  * ***************************************************************************
819  */
Vio_dtor2(Vio * thee)820 VPUBLIC void Vio_dtor2(Vio *thee)
821 {
822     if (thee != VNULL) {
823 
824         /* free the <ASC,XDR> structures */
825         if ( thee->axdr != VNULL ) {
826             if ( thee->frmt == VIO_ASC ) {
827                 asc_destroy( (ASC*)(thee->axdr) );
828             } else if ( thee->frmt == VIO_XDR ) {
829                 xdr_destroy( (XDR*)(thee->axdr) );
830             }
831             free( thee->axdr );
832             thee->axdr = VNULL;
833         }
834 
835         /* finish up */
836         if (thee->type==VIO_SDIO) {
837             /* no-op */
838         } else if (thee->type==VIO_FILE) {
839             if ( thee->fp != VNULL ) {
840                 if ( fclose(thee->fp) != 0 ) {
841                     fprintf(stderr, "Vio_dtor2: fclose fail device <%s>"
842                         " dueto <%s>\n", thee->file,VIOstrerrno(errno));
843                 }
844             }
845         } else if (thee->type==VIO_BUFF) {
846             /* CMIKE: WHAT ABOUT FREEING THE BUFFER SPACE??? */
847             thee->VIObufferPtr = 0;
848         } else if ( (thee->type==VIO_UNIX)
849                  || (thee->type==VIO_INET) ) {
850             if ( thee->soc >= 0 ) {
851 #if defined(HAVE_WINSOCK_H)
852                 if ( closesocket(thee->soc) != 0 ) {
853                     fprintf(stderr, "Vio_dtor2: closesocket1 fail device <%s>"
854                         " dueto <%s>\n", thee->file,
855                         VIOstrerrno(errno));
856                 }
857 #else
858                 if ( close(thee->soc) != 0 ) {
859                     fprintf(stderr, "Vio_dtor2: close1 fail device <%s>"
860                         " dueto <%s>\n", thee->file,
861                     VIOstrerrno(errno));
862                 }
863 #endif
864             }
865             if ( thee->so >= 0 ) {
866 #if defined(HAVE_WINSOCK_H)
867                 if ( closesocket(thee->so) != 0 ) {
868                     fprintf(stderr, "Vio_dtor2: closesocket2 fail device <%s>"
869                         " dueto <%s>\n", thee->file,
870                         VIOstrerrno(errno));
871                 }
872 #else
873                 if ( close(thee->so) != 0 ) {
874                     fprintf(stderr, "Vio_dtor2: close2 fail device <%s>"
875                         " dueto <%s>\n", thee->file,
876                         VIOstrerrno(errno));
877                 }
878 #endif
879             }
880 
881             /* remove the device file for domain sockets */
882             if (thee->type==VIO_UNIX)
883                 if (thee->rwkey==VIO_R)
884                     unlink(thee->file);
885 
886         } else {
887             fprintf(stderr,"Vio_dtor2: Bad type found <%d>\n", thee->type);
888         }
889 
890         if ( (thee->type==VIO_UNIX)
891           || (thee->type==VIO_INET) ) {
892             if (thee->name != VNULL) {
893                 free( thee->name );
894             }
895             thee->name = VNULL;
896         }
897 
898         /* we called WSAStartup() in constructor; must always be paired */
899 #if defined(HAVE_WINSOCK_H)
900         WSACleanup();
901 #endif
902     }
903 }
904 
905 /*
906  * ***************************************************************************
907  * Routine:  Vio_setWhiteChars
908  *
909  * Purpose:  Define the white character set.
910  *
911  * Author:   Michael Holst
912  * ***************************************************************************
913  */
Vio_setWhiteChars(Vio * thee,char * whiteChars)914 VPUBLIC void Vio_setWhiteChars(Vio *thee, char *whiteChars)
915 {
916     if (thee != VNULL) {
917         strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
918 
919         /* propogate the character set down to the ASC structure */
920         VASSERT( thee->axdr != VNULL );
921         if (thee->frmt == VIO_ASC) {
922             asc_setWhiteChars(thee->axdr, whiteChars);
923         } else if (thee->frmt == VIO_XDR) {
924 #if !defined(HAVE_XDR)
925             asc_setWhiteChars(thee->axdr, whiteChars);
926 #endif
927         } else { VASSERT( 0 ); }
928     }
929 }
930 
931 /*
932  * ***************************************************************************
933  * Routine:  Vio_setCommChars
934  *
935  * Purpose:  Define the comment character set.
936  *
937  * Author:   Michael Holst
938  * ***************************************************************************
939  */
Vio_setCommChars(Vio * thee,char * commChars)940 VPUBLIC void Vio_setCommChars(Vio *thee, char *commChars)
941 {
942     if (thee != VNULL) {
943         strncpy(thee->commChars, commChars, VMAX_ARGNUM);
944 
945         /* propogate the character set down to the ASC structure */
946         VASSERT( thee->axdr != VNULL );
947         if (thee->frmt == VIO_ASC) {
948             asc_setCommChars(thee->axdr, commChars);
949         } else if (thee->frmt == VIO_XDR) {
950 #if !defined(HAVE_XDR)
951             asc_setCommChars(thee->axdr, commChars);
952 #endif
953         } else { VASSERT( 0 ); }
954     }
955 }
956 
957 /*
958  * ***************************************************************************
959  * Routine:  Vio_accept
960  *
961  * Purpose:  Accept any waiting connect attempt to our socket on our machine.
962  *
963  * Notes:    The nonblock parameter has the following interpretation:
964  *           (Only for <UNIX/INET>; othewise it is ignored.)
965  *
966  *               nonblock==0  ==> block until a connect is attempted
967  *               nonblock==1  ==> DO NOT block at all
968  *
969  * Author:   Michael Holst
970  * ***************************************************************************
971  */
Vio_accept(Vio * thee,int nonblock)972 VPUBLIC int Vio_accept(Vio *thee, int nonblock)
973 {
974     int rc;
975 
976 #if defined(HAVE_WINSOCK_H)
977     unsigned long  blockKey;
978 #else
979     int flags = 0;
980     struct sockaddr_in peer;
981     struct hostent *hpTmp;
982 #endif
983 
984 #if defined(ACCEPT_USES_ULONG)
985     unsigned long len;
986 #elif defined(ACCEPT_USES_UINT)
987     unsigned int len;
988 #elif defined(ACCEPT_USES_INT)
989     int len;
990 #else
991     unsigned int len;
992 #endif
993 
994     /* reset error tag */
995     thee->error = 0;
996 
997     thee->soc = -1;
998     rc = -1;
999 
1000     Vio_initIoPutBuffers(thee);
1001     VJMPERR2( thee->rwkey == VIO_R );
1002 
1003     if ( (thee->type==VIO_SDIO)
1004       || (thee->type==VIO_FILE)
1005       || (thee->type==VIO_BUFF) ) {
1006 
1007         /* ONLY for file i/o, we need to look at and set the dirty bit */
1008         /* (this keeps us from reading the file twice) */
1009         if (thee->type==VIO_FILE) {
1010             if ((!thee->dirty) && (!feof(thee->fp))) {
1011                 thee->dirty = 1;
1012                 rc = 1;
1013             }
1014         } else {
1015             rc = 1;
1016         }
1017 
1018     } else if (thee->type==VIO_UNIX) {
1019 
1020 #if defined(HAVE_SYS_UN_H)
1021         /* Make this a non-blocking socket just for the accept call */
1022         if (nonblock) {
1023             flags = fcntl( thee->so, F_GETFL, 0 );
1024             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1025         }
1026 
1027         /* accept */
1028         len = sizeof(struct sockaddr_un);
1029         rc = accept(thee->so,(struct sockaddr *)(thee->name),&len);
1030         thee->soc = rc;
1031         if ((!nonblock) && (rc < 0)) {
1032             fprintf(stderr, "Vio_accept: Accept fail UNIX sock <%s>"
1033                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1034             VJMPERR2( 0 );
1035         }
1036 
1037         /* restore blocking -- must nonblock for LINGER to work! */
1038         if (nonblock) {
1039             fcntl( thee->so, F_SETFL, flags );
1040         }
1041 #endif
1042 
1043     } else if (thee->type==VIO_INET) {
1044 
1045         /* Make this non-blocking socket just for accept call */
1046         if (nonblock) {
1047 #if defined(HAVE_WINSOCK_H)
1048             blockKey = 1;
1049             if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
1050                 fprintf(stderr, "Vio_accept: Ioctlsocket1 fail INET sock <%s>"
1051                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1052                 VJMPERR2( 0 );
1053             }
1054 #else
1055             flags = fcntl( thee->so, F_GETFL, 0 );
1056             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1057 #endif
1058         }
1059 
1060         len = sizeof(struct sockaddr_in);
1061         rc = accept(thee->so, (struct sockaddr *)(thee->name), &len);
1062         thee->soc = rc;
1063         if ((!nonblock) && (rc < 0)) {
1064             fprintf(stderr, "Vio_accept: Accept fail INET sock <%s>"
1065                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1066             VJMPERR2( 0 );
1067         }
1068 
1069         /* restore blocking -- must nonblock for LINGER to work! */
1070         if (nonblock) {
1071 #if defined(HAVE_WINSOCK_H)
1072             blockKey = 0;
1073             if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
1074                 fprintf(stderr, "Vio_accept: Ioctlsocket2 fail INET sock <%s>"
1075                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1076                 VJMPERR2( 0 );
1077             }
1078 #else
1079             fcntl( thee->so, F_SETFL, flags );
1080 #endif
1081         }
1082 
1083         /* if we found a writer, get his hostname (just for i/o) */
1084         if (rc >= 0) {
1085 #if defined(HAVE_WINSOCK_H)
1086             strcpy(thee->rhost,"unknown");
1087 #else
1088             len = sizeof(struct sockaddr_in);
1089             if (getpeername(thee->soc,(struct sockaddr *)(&peer),&len)<0) {
1090                 fprintf(stderr, "Vio_accept: Getpeername fail INET <%s>"
1091                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1092                 VJMPERR2( 0 );
1093             } else if (VNULL==(hpTmp=gethostbyname(inet_ntoa(peer.sin_addr)))){
1094                 fprintf(stderr, "Vio_accept: Gethostbyname fail INET <%s>"
1095                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1096                 VJMPERR2( 0 );
1097             } else {
1098                 strcpy(thee->rhost,hpTmp->h_name);
1099             }
1100 #endif
1101         }
1102 
1103     } else {
1104         fprintf(stderr,"Vio_accept: Bad type found <%d>\n", thee->type);
1105         VJMPERR2( 0 );
1106     }
1107 
1108     /* normal return */
1109     return rc;
1110 
1111   VERROR2:
1112     thee->error = 1;
1113     return -1;
1114 }
1115 
1116 /*
1117  * ***************************************************************************
1118  * Routine:  Vio_acceptFree
1119  *
1120  * Purpose:  Free the socket child that was used for the last accept.
1121  *
1122  * Author:   Michael Holst
1123  * ***************************************************************************
1124  */
Vio_acceptFree(Vio * thee)1125 VPUBLIC void Vio_acceptFree(Vio *thee)
1126 {
1127     /* VJMPERR2( !thee->error ); */  /* Need to close the socket... */
1128     VJMPERR2( thee->rwkey == VIO_R );
1129 
1130     if ( (thee->type==VIO_SDIO)
1131       || (thee->type==VIO_FILE)
1132       || (thee->type==VIO_BUFF) ) {
1133         /* no-op */
1134     } else if ( (thee->type==VIO_UNIX)
1135              || (thee->type==VIO_INET) ) {
1136         if ( thee->soc >= 0 ) {
1137 #if defined(HAVE_WINSOCK_H)
1138             if ( closesocket(thee->soc) != 0 ) {
1139                 fprintf(stderr, "Vio_acceptFree: closesocket fail device <%s>"
1140                     " dueto <%s>\n", thee->file,VIOstrerrno(errno));
1141                 VJMPERR2( 0 );
1142             }
1143 #else
1144             if ( close(thee->soc) != 0 ) {
1145                 fprintf(stderr, "Vio_acceptFree: close fail device <%s>"
1146                     " dueto <%s>\n", thee->file,VIOstrerrno(errno));
1147                 VJMPERR2( 0 );
1148             }
1149 #endif
1150         }
1151     } else {
1152         fprintf(stderr,"Vio_acceptFree: Bad type found <%d>\n", thee->type);
1153         VJMPERR2( 0 );
1154     }
1155 
1156     thee->soc = -1;
1157 
1158     /* normal return */
1159     Vio_initIoPutBuffers(thee);
1160     return;
1161 
1162   VERROR2:
1163     Vio_initIoPutBuffers(thee);
1164     thee->error = 1;
1165     return;
1166 }
1167 
1168 /*
1169  * ***************************************************************************
1170  * Routine:  Vio_connect
1171  *
1172  * Purpose:  Connect to some socket on a remote machine (or on our machine).
1173  *
1174  * Notes:    The nonblock parameter has the following interpretation:
1175  *           (Only for <UNIX/INET>; othewise it is ignored.)
1176  *
1177  *               nonblock==0  ==> block until our connection is accepted
1178  *               nonblock==1  ==> DO NOT block at all
1179  *
1180  * Author:   Michael Holst
1181  * ***************************************************************************
1182  */
Vio_connect(Vio * thee,int nonblock)1183 VPUBLIC int Vio_connect(Vio *thee, int nonblock)
1184 {
1185     int rc;
1186 #if defined(HAVE_WINSOCK_H)
1187     unsigned long len;
1188 #else
1189     int len;
1190     int flags = 0;
1191 #endif
1192 
1193     /* reset error tag */
1194     thee->error = 0;
1195 
1196     rc = -1;
1197 
1198     Vio_initIoPutBuffers(thee);
1199     VJMPERR2( thee->rwkey == VIO_W );
1200 
1201     if ( (thee->type==VIO_SDIO)
1202       || (thee->type==VIO_FILE)
1203       || (thee->type==VIO_BUFF) ) {
1204         rc = 1;
1205     } else if (thee->type==VIO_UNIX) {
1206 
1207 #if defined(HAVE_SYS_UN_H)
1208         /* Make this a non-blocking socket just for the connect call */
1209         if (nonblock) {
1210             flags = fcntl( thee->so, F_GETFL, 0 );
1211             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1212         }
1213 
1214         /* blocking connect */
1215         len = sizeof(struct sockaddr_un);
1216         rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
1217         if ((!nonblock) && (rc < 0)) {
1218             fprintf(stderr, "Vio_connect: Conn fail UNIX sock <%s>"
1219                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1220             VJMPERR2( 0 );
1221         }
1222 
1223         /* restore blocking -- must nonblock for LINGER to work! */
1224         if (nonblock) {
1225             fcntl( thee->so, F_SETFL, flags );
1226         }
1227 #endif
1228 
1229     } else if (thee->type==VIO_INET) {
1230 
1231         /* make this a non-blocking socket just for the connect call */
1232         if (nonblock) {
1233 #if defined(HAVE_WINSOCK_H)
1234             len = 1;
1235             if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
1236                 fprintf(stderr, "Vio_connect: Ioctlsocket1 fail INET sock <%s>"
1237                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1238                 VJMPERR2( 0 );
1239             }
1240 #else
1241             flags = fcntl( thee->so, F_GETFL, 0 );
1242             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1243 #endif
1244         }
1245 
1246         /* blocking connect */
1247         len = sizeof(struct sockaddr_in);
1248         rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
1249         if ((!nonblock) && (rc < 0)) {
1250             fprintf(stderr, "Vio_connect: Conn fail INET sock <%s>"
1251                  " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1252             VJMPERR2( 0 );
1253         }
1254 
1255         /* restore blocking -- must nonblock for LINGER to work! */
1256         if (nonblock) {
1257 #if defined(HAVE_WINSOCK_H)
1258             len = 0;
1259             if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
1260                 fprintf(stderr, "Vio_connect: Ioctlsocket2 fail INET sock <%s>"
1261                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1262                 VJMPERR2( 0 );
1263             }
1264 #else
1265             fcntl( thee->so, F_SETFL, flags );
1266 #endif
1267         }
1268 
1269     } else {
1270         fprintf(stderr,"Vio_connect: Bad type found <%d>\n", thee->type);
1271         VJMPERR2( 0 );
1272     }
1273 
1274     /* normal return */
1275     return rc;
1276 
1277   VERROR2:
1278     thee->error = 1;
1279     return -1;
1280 }
1281 
1282 /*
1283  * ***************************************************************************
1284  * Routine:  Vio_connectFree
1285  *
1286  * Purpose:  Purge any output buffers (for <UNIX/INET>, else a no-op).
1287  *
1288  * Author:   Michael Holst
1289  * ***************************************************************************
1290  */
Vio_connectFree(Vio * thee)1291 VPUBLIC void Vio_connectFree(Vio *thee)
1292 {
1293     /* VJMPERR2( !thee->error ); */  /* Need to close the socket... */
1294     VJMPERR2( thee->rwkey == VIO_W );
1295 
1296     if ( (thee->type==VIO_SDIO)
1297       || (thee->type==VIO_FILE)
1298       || (thee->type==VIO_BUFF) ) {
1299         /* no-op */
1300     } else if ( (thee->type==VIO_UNIX)
1301              || (thee->type==VIO_INET) ) {
1302         Vio_purgePutBuffer(thee);
1303     } else {
1304         fprintf(stderr,"Vio_connectFree: Bad type found <%d>\n", thee->type);
1305         VJMPERR2( 0 );
1306     }
1307 
1308     /* normal return */
1309     Vio_initIoPutBuffers(thee);
1310     return;
1311 
1312   VERROR2:
1313     Vio_initIoPutBuffers(thee);
1314     thee->error = 1;
1315     return;
1316 }
1317 
1318 /*
1319  * ***************************************************************************
1320  * Routine:  Vio_findNewline
1321  *
1322  * Purpose:  finds the new line char if any from current position in iobuffer
1323  *
1324  * Author:   Juan Brandi
1325  * ***************************************************************************
1326  */
Vio_findNewLine(Vio * thee)1327 VPUBLIC int Vio_findNewLine(Vio *thee){
1328 
1329 	char nullChar = '\n';
1330 	int pntr = asc_getpos((ASC*)thee->axdr);
1331 	int isNewline = 0;
1332 
1333 	if(thee == VNULL){
1334 		Vnm_print(2, "Vio_findNewLine:  Got NULL pointer!\n");
1335 		return isNewline;
1336 	}
1337 
1338 	char *buf;
1339 	buf = thee->ioBuffer;
1340 
1341 	while(pntr < thee->ioBufferLen && isNewline == 0){
1342 		if(memcmp(&buf[pntr], &nullChar,sizeof(char)) == 0){
1343 			asc_setpos((ASC*)thee->axdr, pntr);
1344 			isNewline = 1;
1345 		}
1346 		pntr++;
1347 	}
1348 
1349 	return isNewline;
1350 
1351 }
1352 
1353 /*
1354  * ***************************************************************************
1355  * Routine:  Vio_scanf
1356  *
1357  * Purpose:  Mimic "scanf" from an arbitrary Vio device.
1358  *
1359  * Author:   Michael Holst
1360  * ***************************************************************************
1361  */
Vio_scanf(Vio * thee,char * parms,...)1362 VPUBLIC int Vio_scanf(Vio *thee, char *parms, ... )
1363 {
1364     va_list ap;
1365     char arg0, arg1, arg2, *cval, *sval, buf[VMAX_BUFSIZE];
1366     int i, len, tokCount, *ival;
1367     float *fval;
1368     double *dval;
1369 
1370     VJMPERR2( !thee->error );
1371     VJMPERR2( thee->rwkey == VIO_R );
1372 
1373     /* get the value of the current pointer that points into the ioBuffer */
1374     len = 0;
1375     if (thee->frmt == VIO_ASC) {
1376         len = asc_getpos((ASC*)thee->axdr);
1377     } else if (thee->frmt == VIO_XDR) {
1378         len = xdr_getpos((XDR*)thee->axdr);
1379     } else { VASSERT( 0 ); }
1380 
1381     /* if the buffer is completely empty (i.e., first time here) fill it up */
1382     if ( thee->ioBufferLen == 0 ) {
1383 
1384         /* read the data */
1385         thee->ioBufferLen = Vio_read( thee, thee->ioBuffer, VMAX_BUFSIZE );
1386 
1387         /* set the buffer point to 0 */
1388         if (thee->frmt == VIO_ASC) {
1389             VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
1390         } else if (thee->frmt == VIO_XDR) {
1391             VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1392         } else { VASSERT( 0 ); }
1393 
1394     /* if current point is more than halfway through buf, read in more data */
1395     } else if ( len > (VMAX_BUFSIZE/2) ) {
1396 
1397         /* sanity check */
1398         VJMPERR1( len <= thee->ioBufferLen );
1399 
1400         /* copy unread part of ioBuffer into temp buf and clear ioBuffer */
1401         for (i=len; i<thee->ioBufferLen; i++)
1402             buf[i-len] = thee->ioBuffer[i];
1403         memset(thee->ioBuffer,  '\0', sizeof(thee->ioBuffer));
1404 
1405         /* read temp buffer back, reseting to the beginning of ioBuffer */
1406         thee->ioBufferLen = thee->ioBufferLen - len;
1407         for (i=0; i<thee->ioBufferLen; i++)
1408             thee->ioBuffer[i] = buf[i];
1409 
1410         /* reset the buffer point to 0 */
1411         if (thee->frmt == VIO_ASC) {
1412             VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
1413         } else if (thee->frmt == VIO_XDR) {
1414             VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1415         } else { VASSERT( 0 ); }
1416 
1417         /* finally, read in the new data, starting at end of current data */
1418         thee->ioBufferLen += Vio_read(thee,
1419             thee->ioBuffer+thee->ioBufferLen, VMAX_BUFSIZE-thee->ioBufferLen );
1420 
1421     /* we (hopefully?) have enough in buffer to work with; do nothing here */
1422     } else {
1423         /* no-op */
1424     }
1425 
1426     /* we ALWAYS have to pick the format specifier apart <ASC,XDR> ... */
1427     tokCount = 0;
1428     len = strlen(parms);
1429     va_start(ap, parms);
1430     i = 0;
1431     while ( i < len ) {
1432         arg0 = parms[i];
1433         if ( arg0 == ' ' ) {
1434             i+=1;
1435         } else if ( arg0 == '\n' ) {
1436             i+=1;
1437         } else if ( i+1 < len ) {
1438             arg1 = parms[i+1];
1439             if ( arg1 == 's' ) {
1440                 sval = va_arg(ap, char*);
1441                 if ((i == len-3) && ( parms[len-1] == '\n' )) {
1442                     if (thee->frmt == VIO_ASC) {
1443                         VASSERT( 0 ); /* is this ever executed??? */
1444                     } else if (thee->frmt == VIO_XDR) {
1445                         VASSERT( 0 ); /* is this ever executed??? */
1446                     } else { VASSERT( 0 ); }
1447                 } else {
1448                     if (thee->frmt == VIO_ASC) {
1449                         VJMPERR1( asc_string(thee->axdr, &sval, VMAX_BUFSIZE) );
1450                     } else if (thee->frmt == VIO_XDR) {
1451                         VJMPERR1( xdr_string(thee->axdr, &sval, VMAX_BUFSIZE) );
1452                     } else { VASSERT( 0 ); }
1453                 }
1454                 tokCount++;
1455                 i+=2;
1456             } else if ( arg1 == 'c' ) {
1457                 cval = va_arg(ap, char*);
1458                 if (thee->frmt == VIO_ASC) {
1459                     VJMPERR1( asc_char( thee->axdr, cval ) );
1460                 } else if (thee->frmt == VIO_XDR) {
1461                     VJMPERR1( xdr_char( thee->axdr, cval ) );
1462                 } else { VASSERT( 0 ); }
1463                 tokCount++;
1464                 i+=2;
1465             } else if ( arg1 == 'd' ) {
1466                 ival = va_arg(ap, int*);
1467                 if (thee->frmt == VIO_ASC) {
1468                     VJMPERR1( asc_int( thee->axdr, ival ) );
1469                 } else if (thee->frmt == VIO_XDR) {
1470                     VJMPERR1( xdr_int( thee->axdr, ival ) );
1471                 } else { VASSERT( 0 ); }
1472                 tokCount++;
1473                 i+=2;
1474             } else if ( arg1 == 'f' ) {
1475                 fval = va_arg(ap, float*);
1476                 if (thee->frmt == VIO_ASC) {
1477                     VJMPERR1( asc_float( thee->axdr, fval ) );
1478                 } else if (thee->frmt == VIO_XDR) {
1479                     VJMPERR1( xdr_float( thee->axdr, fval ) );
1480                 } else { VASSERT( 0 ); }
1481                 tokCount++;
1482                 i+=2;
1483             } else if ( arg1 == 'e' ) {
1484                 fval = va_arg(ap, float*);
1485                 if (thee->frmt == VIO_ASC) {
1486                     VJMPERR1( asc_float( thee->axdr, fval ) );
1487                 } else if (thee->frmt == VIO_XDR) {
1488                     VJMPERR1( xdr_float( thee->axdr, fval ) );
1489                 } else { VASSERT( 0 ); }
1490                 tokCount++;
1491                 i+=2;
1492             } else if (( arg1 == 'l' ) && ( i+2 < len )) {
1493                 arg2 = parms[i+2];
1494                 if ( arg2 == 'e' ) {
1495                     dval = va_arg(ap, double*);
1496                     if (thee->frmt == VIO_ASC) {
1497                         VJMPERR1( asc_double( thee->axdr, dval ) );
1498                     } else if (thee->frmt == VIO_XDR) {
1499                         VJMPERR1( xdr_double( thee->axdr, dval ) );
1500                     } else { VASSERT( 0 ); }
1501                     tokCount++;
1502                     i+=3;
1503                 } else { VJMPERR1( 0 ); }
1504             } else { VJMPERR1( 0 ); }
1505         } else { VJMPERR1( 0 ); }
1506     }
1507     va_end(ap);
1508 
1509     /* return without error */
1510     return tokCount;
1511 
1512   VERROR1:
1513     va_end(ap);
1514     /*
1515      * APBS-KTS: Check to see if we are here because of an EOF condition.  If
1516      * so, then just quietly go away.
1517      */
1518     if (thee->frmt == VIO_ASC && ((ASC *)thee->axdr)->error != EOF)
1519         fprintf(stderr,"Vio_scanf: Format problem with input.\n");
1520   VERROR2:
1521     thee->error = 1;
1522     return 0;
1523 }
1524 
1525 /*
1526  * ***************************************************************************
1527  * Routine:  Vio_printf
1528  *
1529  * Purpose:  Mimic "printf" to an arbitrary Vio device.
1530  *
1531  * Author:   Michael Holst
1532  * ***************************************************************************
1533  */
Vio_printf(Vio * thee,char * parms,...)1534 VPUBLIC int Vio_printf(Vio *thee, char *parms, ... )
1535 {
1536     va_list ap;
1537     char buf[VMAX_BUFSIZE];
1538     int len;
1539 
1540     char arg0, arg1, arg2, cval, *sval;
1541     int i, tokCount, ival;
1542     float fval;
1543     double dval;
1544 
1545     VJMPERR2( !thee->error );
1546     VJMPERR2( thee->rwkey == VIO_W );
1547 
1548     /* if ASCII data then use vsprintf to handle format specifier exactly */
1549     if (thee->frmt == VIO_ASC) {
1550         va_start(ap, parms);
1551         vsprintf(buf, parms, ap);
1552         va_end(ap);
1553         len = strlen(buf);
1554         return Vio_writePutBuffer(thee,buf,len);
1555     }
1556 
1557     /* if XDR data then we have to pick the format specifier apart... */
1558     len = strlen(parms);
1559     va_start(ap, parms);
1560     tokCount = 0;
1561     i = 0;
1562     while ( i < len ) {
1563         arg0 = parms[i];
1564         if ((arg0 == '%') && (i+1 < len)) {
1565             arg1 = parms[i+1];
1566             if ( arg1 == '%' ) {
1567                 i+=2;
1568             } else {
1569                 while (!strchr("scdfel",arg1)) {
1570                     i+=1;
1571                     arg1 = parms[i+1];
1572                     VJMPERR1( i+1 < len );
1573                 }
1574                 if ( arg1 == 's' ) {
1575                     sval = va_arg(ap, char*);
1576                     /* don't put comment strings into xdr files */
1577                     if (!strchr(thee->commChars,sval[0])) {
1578                         VJMPERR1( xdr_string(thee->axdr, &sval, strlen(sval)) );
1579                         tokCount++;
1580                     }
1581                     i+=2;
1582                 } else if ( arg1 == 'c' ) {
1583                     /* are char args always passed as int? ... */
1584                     cval = (char)va_arg(ap, int);  /* CAST FROM INT */
1585                     VJMPERR1( xdr_char( thee->axdr, &cval ) );
1586                     tokCount++;
1587                     i+=2;
1588                 } else if ( arg1 == 'd' ) {
1589                     ival = va_arg(ap, int);
1590                     VJMPERR1( xdr_int( thee->axdr, &ival ) );
1591                     tokCount++;
1592                     i+=2;
1593                 } else if ( arg1 == 'f' ) {
1594                     /* are float args always passed as double? ... */
1595                     fval = (float)va_arg(ap, double);  /* CAST FROM DOUBLE */
1596                     VJMPERR1( xdr_float( thee->axdr, &fval ) );
1597                     tokCount++;
1598                     i+=2;
1599                 } else if ( arg1 == 'e' ) {
1600                     /* are float args always passed as double? ... */
1601                     fval = (float)va_arg(ap, double);  /* CAST FROM DOUBLE */
1602                     VJMPERR1( xdr_float( thee->axdr, &fval ) );
1603                     tokCount++;
1604                     i+=2;
1605                 } else if (( arg1 == 'l' ) && ( i+2 < len )) {
1606                     arg2 = parms[i+2];
1607                     if ( arg2 == 'e' ) {
1608                         dval = va_arg(ap, double);
1609                         VJMPERR1( xdr_double( thee->axdr, &dval ) );
1610                         tokCount++;
1611                         i+=3;
1612                     } else { VJMPERR1( 0 ); }
1613                 } else { VJMPERR1( 0 ); }
1614             }
1615         } else {
1616             i+=1;
1617         }
1618     }
1619     va_end(ap);
1620 
1621     /* finally write out the XDR buffer */
1622     VJMPERR1( 0<=(len=xdr_getpos((XDR*)thee->axdr)) );
1623     VJMPERR1( Vio_writePutBuffer(thee,thee->ioBuffer,len) == len );
1624     VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1625 
1626     /* return without error */
1627     return len;
1628 
1629   VERROR1:
1630     va_end(ap);
1631     fprintf(stderr,"Vio_printf: Format problem with output.\n");
1632 
1633   VERROR2:
1634     thee->error = 1;
1635     return 0;
1636 }
1637 
1638 /*
1639  * ***************************************************************************
1640  * Routine:  Vio_read
1641  *
1642  * Purpose:  Read (up to) bufsize characters into buf from input device.
1643  *
1644  * Notes:    The number of bytes read is returned.
1645  *
1646  *           It is not necessarily an error if the number of bytes read
1647  *           is less than bufsize (EOF may have been encountered).
1648  *
1649  *           Acts exactly like fread() or read().
1650  *
1651  * Author:   Michael Holst
1652  * ***************************************************************************
1653  */
Vio_read(Vio * thee,char * buf,int bufsize)1654 VPUBLIC int Vio_read(Vio *thee, char *buf, int bufsize)
1655 {
1656     int rc, i, ilen;
1657 
1658     VJMPERR2( !thee->error );
1659     VJMPERR2( thee->rwkey == VIO_R );
1660 
1661     rc = 0;
1662     if (bufsize > 0) {
1663         if ( (thee->type==VIO_SDIO)
1664           || (thee->type==VIO_FILE) ) {
1665             rc = fread(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
1666             /* CMIKE: if (rc!=bufsize), make SURE EOF was reached! */
1667         } else if (thee->type==VIO_BUFF) {
1668             ilen = VMIN2( bufsize, thee->VIObufferLen - thee->VIObufferPtr );
1669             for (i=0; i<ilen; i++)
1670                 buf[i] = thee->VIObuffer[thee->VIObufferPtr + i];
1671             thee->VIObufferPtr += ilen;
1672             rc = ilen;
1673         } else if ( (thee->type==VIO_UNIX)
1674                  || (thee->type==VIO_INET) ) {
1675             rc = readn(thee->soc, buf, (unsigned int)bufsize);
1676             /* CMIKE: if (rc!=bufsize), make SURE EOF was reached! */
1677         } else {
1678             fprintf(stderr,"Vio_read: Bad type found <%d>\n", thee->type);
1679             rc = 0;
1680             VJMPERR2( 0 );
1681         }
1682     }
1683 
1684     /* return without error */
1685     return rc;
1686 
1687   VERROR2:
1688     thee->error = 1;
1689     return 0;
1690 }
1691 
1692 /*
1693  * ***************************************************************************
1694  * Routine:  Vio_write
1695  *
1696  * Purpose:  Write bufsize characters from buf to output device.
1697  *
1698  * Notes:    The number of bytes written is returned.
1699  *
1700  *           On success, the returned bytecount is the same as the number
1701  *           of bytes in the input buffer.
1702  *
1703  *           On failure, the returned bytecount is less than the number
1704  *           of bytes in the input buffer.
1705  *
1706  *           Acts exactly like fwrite() or write().
1707  *
1708  * Author:   Michael Holst
1709  * ***************************************************************************
1710  */
Vio_write(Vio * thee,char * buf,int bufsize)1711 VPUBLIC int Vio_write(Vio *thee, char *buf, int bufsize)
1712 {
1713     int rc, i, isize;
1714     char *tmpBuf;
1715 
1716     VJMPERR2( !thee->error );
1717     VJMPERR2( thee->rwkey == VIO_W );
1718 
1719     rc = 0;
1720     if (bufsize > 0) {
1721         if ( (thee->type==VIO_SDIO)
1722           || (thee->type==VIO_FILE) ) {
1723             rc = fwrite(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
1724             VJMPERR1( rc == bufsize );
1725         } else if (thee->type==VIO_BUFF) {
1726             while ( bufsize > (thee->VIObufferLen - thee->VIObufferPtr) ) {
1727                 isize = VMAX2( 1, 2*(thee->VIObufferLen) );
1728                 tmpBuf = (char*)calloc( isize, sizeof(char) );
1729                 VJMPERR1( tmpBuf != VNULL );
1730                 for (i=0; i<thee->VIObufferLen; i++)
1731                     tmpBuf[i] = thee->VIObuffer[i];
1732                 free( thee->VIObuffer );
1733                 thee->VIObuffer = tmpBuf;
1734                 thee->VIObufferLen = isize;
1735             }
1736             for (i=0; i<bufsize; i++)
1737                 thee->VIObuffer[thee->VIObufferPtr + i] = buf[i];
1738             thee->VIObufferPtr += bufsize;
1739             rc = bufsize;
1740             VJMPERR1( rc == bufsize );
1741         } else if ( (thee->type==VIO_UNIX)
1742                  || (thee->type==VIO_INET) ) {
1743             rc = writen(thee->so, buf, (unsigned int)bufsize);
1744             VJMPERR1( rc == bufsize );
1745         } else {
1746             fprintf(stderr,"Vio_write: Bad type found <%d>\n", thee->type);
1747             rc = 0;
1748             VJMPERR2( 0 );
1749         }
1750     }
1751 
1752     /* return without error */
1753     return rc;
1754 
1755   VERROR1:
1756     fprintf(stderr,"Vio_write: Error occurred (bailing out).\n");
1757   VERROR2:
1758     thee->error = 1;
1759     return 0;
1760 }
1761 
1762 /*
1763  * ***************************************************************************
1764  * Routine:  Vio_initIoPutBuffers
1765  *
1766  * Purpose:  Initialize the internal buffer.
1767  *
1768  * Author:   Michael Holst
1769  * ***************************************************************************
1770  */
Vio_initIoPutBuffers(Vio * thee)1771 VPRIVATE void Vio_initIoPutBuffers(Vio *thee)
1772 {
1773     /* initialize the buffer space */
1774     memset(thee->ioBuffer,  '\0', sizeof(thee->ioBuffer));
1775     memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1776     thee->ioBufferLen = 0;
1777     thee->putBufferLen = 0;
1778 }
1779 
1780 /*
1781  * ***************************************************************************
1782  * Routine:  Vio_purgePutBuffer
1783  *
1784  * Purpose:  Purge the internal buffer.
1785  *
1786  * Author:   Michael Holst
1787  * ***************************************************************************
1788  */
Vio_purgePutBuffer(Vio * thee)1789 VPRIVATE void Vio_purgePutBuffer(Vio *thee)
1790 {
1791     int len;
1792 
1793     VJMPERR2( !thee->error );
1794     VJMPERR2( thee->rwkey == VIO_W );
1795 
1796     len = thee->putBufferLen;
1797     if ( (thee->type==VIO_UNIX)
1798       || (thee->type==VIO_INET) ) {
1799         if ( Vio_write(thee,thee->putBuffer,len) != len ) {
1800             fprintf(stderr,
1801                "Vio_purgePutBuffer: Vio_write fail UNIX/INET sock <%s>"
1802                " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1803             VJMPERR2( 0 );
1804         }
1805         memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1806     } else {
1807         fprintf(stderr,"Vio_purgePutBuffer: Bad type found <%d>\n",thee->type);
1808         VJMPERR2( 0 );
1809     }
1810 
1811     /* return without error */
1812     return;
1813 
1814   VERROR2:
1815     thee->error = 1;
1816     return;
1817 }
1818 
1819 /*
1820  * ***************************************************************************
1821  * Routine:  Vio_writePutBuffer
1822  *
1823  * Purpose:  Write bufsize characters from buf to output device.
1824  *
1825  * Notes:    The number of bytes written is returned.
1826  *
1827  *           On success, the returned bytecount is the same as the number
1828  *           of bytes in the input buffer.
1829  *
1830  *           On failure, the returned bytecount is less than the number
1831  *           of bytes in the input buffer.
1832  *
1833  *           Acts exactly like fwrite() or write().
1834  *
1835  * Comment:  This is simply a buffered version of Vio_write().
1836  *           The Vio object maintains the buffer safely internally.
1837  *
1838  * Author:   Michael Holst
1839  * ***************************************************************************
1840  */
Vio_writePutBuffer(Vio * thee,char * buf,int bufsize)1841 VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize)
1842 {
1843     int i, curLen;
1844 
1845     VJMPERR2( !thee->error );
1846     VJMPERR2( thee->rwkey == VIO_W );
1847 
1848     /* attempt to buffer the i/o to get some speed */
1849     if ( (thee->type==VIO_SDIO)
1850       || (thee->type==VIO_FILE)
1851       || (thee->type==VIO_BUFF) ) {
1852 
1853         if ( Vio_write(thee,buf,bufsize) != bufsize ) {
1854             fprintf(stderr,
1855                 "Vio_writePutBuffer: Vio_write(1) fail FILE sock <%s>"
1856                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1857             VJMPERR2( 0 );
1858         }
1859 
1860     } else if ( (thee->type==VIO_UNIX)
1861              || (thee->type==VIO_INET) ) {
1862 
1863         /* incoming data is larger than our buffer */
1864         if (bufsize > (int)sizeof(thee->putBuffer)) {
1865 
1866             /* just do a normal unbuffered socket write */
1867             if ( Vio_write(thee,buf,bufsize) != bufsize ) {
1868                 fprintf(stderr, "Vio_writePutBuffer: Vio_write(2) fail"
1869                     " UNIX/INET sock <%s>"
1870                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1871                 VJMPERR2( 0 );
1872             }
1873 
1874         /* incoming data will fit in our buffer */
1875         } else {
1876 
1877             curLen = thee->putBufferLen;
1878 
1879             /* it fits in now -- just cat it to the end of the buffer */
1880             if ( (curLen + bufsize) <= (int)sizeof(thee->putBuffer) ) {
1881                 for (i=0; i<bufsize; i++)
1882                     thee->putBuffer[curLen+i] = buf[i];
1883                 thee->putBufferLen += bufsize;
1884 
1885             /* it won't fit until we write out the existing buffer */
1886             } else {
1887                 if ( Vio_write(thee,thee->putBuffer,curLen) != curLen ) {
1888                     fprintf(stderr, "Vio_writePutBuffer: Vio_write(3)"
1889                      " fail UNIX/INET sock <%s>"
1890                      " dueto <%s>\n", thee->file, VIOstrerrno(errno));
1891                     VJMPERR2( 0 );
1892                 }
1893                 thee->putBufferLen = 0;
1894                 memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1895                 for (i=0; i<bufsize; i++)
1896                     thee->putBuffer[i] = buf[i];
1897                 thee->putBufferLen += bufsize;
1898             }
1899         }
1900 
1901     } else {
1902         fprintf(stderr,"Vio_writePutBuffer: Bad type found <%d>\n",thee->type);
1903         VJMPERR2( 0 );
1904     }
1905 
1906     /* return without error */
1907     return bufsize;
1908 
1909   VERROR2:
1910     thee->error = 1;
1911     return 0;
1912 }
1913 
1914 /*
1915  * ***************************************************************************
1916  * Routine:  ascmem_create, asc_destroy, asc_getpos, asc_setpos
1917  *           asc_string, asc_char, asc_int, asc_float, asc_double
1918  *           asc_setWhiteChars, asc_setCommChars, asc_getToken
1919  *
1920  * Purpose:  An ASC (i.e. ASCII) dual to the XDR routines.
1921  *
1922  * Notes:    These routines basically function idential to the XDR routines,
1923  *           except that after calling the constructor <ascmem_create>, one
1924  *           must call two additional routines, <asc_setWhiteChars> and
1925  *           <asc_setCommChars>, to specify the strings representing the
1926  *           whitespace in the ASCII stream separating the tokens, and a set
1927  *           of possible comment characters which generate skips to a newline.
1928  *
1929  *           The only complicated routine is <asc_genToken>, on which
1930  *           most of the other things rest.
1931  *
1932  *           Both ASC_ENCODE (write) and ASC_DECODE (read) directions work.
1933  *           In ASC_ENCODE mode, the tokens are separated by a single newline
1934  *           (for lack of anything more intelligent to do...).
1935  *
1936  * Author:   Michael Holst
1937  * ***************************************************************************
1938  */
1939 
1940 /*
1941  * ***************************************************************************
1942  * Routine:  ascmem_create
1943  *
1944  * Purpose:  Create the ASC structure.
1945  *
1946  * Author:   Michael Holst
1947  * ***************************************************************************
1948  */
ascmem_create(ASC * thee,char * buf,int size,ASCmode mode)1949 VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode)
1950 {
1951     thee->mode = mode;
1952     thee->pos  = 0;
1953     thee->size = size;
1954     thee->buf  = buf;
1955     memset(thee->whiteChars, '\0', VMAX_ARGNUM);
1956     memset(thee->commChars,  '\0', VMAX_ARGNUM);
1957     thee->error = 0;     /* APBS-KTS: initialize to "no error" */
1958 }
1959 
1960 /*
1961  * ***************************************************************************
1962  * Routine:  asc_destroy
1963  *
1964  * Purpose:  Destroy the ASC structure.
1965  *
1966  * Author:   Michael Holst
1967  * ***************************************************************************
1968  */
asc_destroy(ASC * thee)1969 VPRIVATE void asc_destroy(ASC *thee)
1970 {
1971     thee->mode = ASC_NO_MODE;
1972     thee->pos  = 0;
1973     thee->size = 0;
1974     thee->buf  = VNULL;
1975     memset(thee->whiteChars, '\0', VMAX_ARGNUM);
1976     memset(thee->commChars,  '\0', VMAX_ARGNUM);
1977     thee->error = 0;     /* APBS-KTS: reset to "no error" */
1978 }
1979 
1980 /*
1981  * ***************************************************************************
1982  * Routine:  asc_getpos
1983  *
1984  * Purpose:  Return the current position in the ASC stream.
1985  *
1986  * Author:   Michael Holst
1987  * ***************************************************************************
1988  */
asc_getpos(ASC * thee)1989 VPRIVATE int asc_getpos(ASC *thee)
1990 {
1991     return thee->pos;
1992 }
1993 
1994 /*
1995  * ***************************************************************************
1996  * Routine:  asc_setpos
1997  *
1998  * Purpose:  Set the current position in the ASC stream.
1999  *
2000  * Author:   Michael Holst
2001  * ***************************************************************************
2002  */
asc_setpos(ASC * thee,int pos)2003 VPRIVATE int asc_setpos(ASC *thee, int pos)
2004 {
2005     thee->pos = pos;
2006     return 1;
2007 }
2008 
2009 /*
2010  * ***************************************************************************
2011  * Routine:  asc_string
2012  *
2013  * Purpose:  DECODE or ENCODE a string.
2014  *
2015  * Author:   Michael Holst
2016  * ***************************************************************************
2017  */
asc_string(ASC * thee,char ** sval,int size)2018 VPRIVATE int asc_string(ASC *thee, char **sval, int size)
2019 {
2020     int i, len;
2021     char tok[VMAX_BUFSIZE];
2022 
2023     if (thee->mode == ASC_DECODE) {
2024         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2025         sscanf(tok,"%s",(*sval));
2026         //memcpy((*sval), tok, strlen(tok));
2027     } else if (thee->mode == ASC_ENCODE) {
2028         sprintf(tok,"%s\n",*sval);
2029         len = strlen(tok);
2030         for (i=0; i<len; i++)
2031             thee->buf[thee->pos+i] = tok[i];
2032         thee->pos += len;
2033     }
2034     return 1;
2035 
2036   VERROR1:
2037     return 0;
2038 }
2039 
2040 /*
2041  * ***************************************************************************
2042  * Routine:  asc_char
2043  *
2044  * Purpose:  DECODE or ENCODE a char.
2045  *
2046  * Author:   Michael Holst
2047  * ***************************************************************************
2048  */
asc_char(ASC * thee,char * cval)2049 VPRIVATE int asc_char(ASC *thee, char *cval)
2050 {
2051     int i, len;
2052     char tok[VMAX_BUFSIZE];
2053 
2054     if (thee->mode == ASC_DECODE) {
2055         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2056         sscanf(tok,"%c",cval);
2057     } else if (thee->mode == ASC_ENCODE) {
2058         sprintf(tok,"%c\n",*cval);
2059         len = strlen(tok);
2060         for (i=0; i<len; i++)
2061             thee->buf[thee->pos+i] = tok[i];
2062         thee->pos += len;
2063     }
2064     return 1;
2065 
2066   VERROR1:
2067     return 0;
2068 }
2069 
2070 /*
2071  * ***************************************************************************
2072  * Routine:  asc_int
2073  *
2074  * Purpose:  DECODE or ENCODE an int.
2075  *
2076  * Author:   Michael Holst
2077  * ***************************************************************************
2078  */
asc_int(ASC * thee,int * ival)2079 VPRIVATE int asc_int(ASC *thee, int *ival)
2080 {
2081     int i, len;
2082     char tok[VMAX_BUFSIZE];
2083 
2084     if (thee->mode == ASC_DECODE) {
2085         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2086         sscanf(tok,"%d",ival);
2087     } else if (thee->mode == ASC_ENCODE) {
2088         sprintf(tok,"%d\n",*ival);
2089         len = strlen(tok);
2090         for (i=0; i<len; i++)
2091             thee->buf[thee->pos+i] = tok[i];
2092         thee->pos += len;
2093     }
2094     return 1;
2095 
2096   VERROR1:
2097     return 0;
2098 }
2099 
2100 /*
2101  * ***************************************************************************
2102  * Routine:  asc_float
2103  *
2104  * Purpose:  DECODE or ENCODE a float.
2105  *
2106  * Author:   Michael Holst
2107  * ***************************************************************************
2108  */
asc_float(ASC * thee,float * fval)2109 VPRIVATE int asc_float(ASC *thee, float *fval)
2110 {
2111     int i, len;
2112     char tok[VMAX_BUFSIZE];
2113 
2114     if (thee->mode == ASC_DECODE) {
2115         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2116         sscanf(tok,"%e",fval);
2117     } else if (thee->mode == ASC_ENCODE) {
2118         sprintf(tok,"%e\n",*fval);
2119         len = strlen(tok);
2120         for (i=0; i<len; i++)
2121             thee->buf[thee->pos+i] = tok[i];
2122         thee->pos += len;
2123     }
2124     return 1;
2125 
2126   VERROR1:
2127     return 0;
2128 }
2129 
2130 /*
2131  * ***************************************************************************
2132  * Routine:  asc_double
2133  *
2134  * Purpose:  DECODE or ENCODE a double.
2135  *
2136  * Author:   Michael Holst
2137  * ***************************************************************************
2138  */
asc_double(ASC * thee,double * dval)2139 VPRIVATE int asc_double(ASC *thee, double *dval)
2140 {
2141     int i, len;
2142     char tok[VMAX_BUFSIZE];
2143 
2144     if (thee->mode == ASC_DECODE) {
2145         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2146         sscanf(tok,"%le",dval);
2147     } else if (thee->mode == ASC_ENCODE) {
2148         sprintf(tok,"%e\n",*dval);
2149         len = strlen(tok);
2150         for (i=0; i<len; i++)
2151             thee->buf[thee->pos+i] = tok[i];
2152         thee->pos += len;
2153     }
2154     return 1;
2155 
2156   VERROR1:
2157     return 0;
2158 }
2159 
2160 /*
2161  * ***************************************************************************
2162  * Routine:  asc_setWhiteChars
2163  *
2164  * Purpose:  Define the white character set.
2165  *
2166  * Author:   Michael Holst
2167  * ***************************************************************************
2168  */
asc_setWhiteChars(ASC * thee,char * whiteChars)2169 VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars)
2170 {
2171     strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
2172 }
2173 
2174 /*
2175  * ***************************************************************************
2176  * Routine:  asc_setCommChars
2177  *
2178  * Purpose:  Define the comment character set.
2179  *
2180  * Author:   Michael Holst
2181  * ***************************************************************************
2182  */
asc_setCommChars(ASC * thee,char * commChars)2183 VPRIVATE void asc_setCommChars(ASC *thee, char *commChars)
2184 {
2185     strncpy(thee->commChars, commChars, VMAX_ARGNUM);
2186 }
2187 
2188 /*
2189  * ***************************************************************************
2190  * Routine:  asc_getToken
2191  *
2192  * Purpose:  Get the next token from the input stream.
2193  *
2194  * Author:   Michael Holst
2195  * ***************************************************************************
2196  */
asc_getToken(ASC * thee,char * tok,int toksize)2197 VPRIVATE char* asc_getToken(ASC *thee, char *tok, int toksize)
2198 {
2199     /*
2200      * APBS-KTS: In general all of the tests that check if we are less than
2201      * thee->size are lame.  It should be checking against the amount of data
2202      * in the buffer, not the size of the buffer.
2203      */
2204     int i, ii, jj, done;
2205     if (thee->mode == ASC_DECODE) {
2206 
2207         /* first clear the token buffer */
2208         memset(tok, '\0', toksize);
2209 
2210         /* set "ii" ptr to the first token character */
2211         ii = thee->pos;
2212         done = 0;
2213         while ( !done ) {
2214 
2215             /* if whiteChar then just skip that character */
2216             if ( strchr(thee->whiteChars,thee->buf[ii]) ) {
2217                 ii++;
2218                 VJMPERR1( ii < thee->size );
2219 
2220             /* if commChar then skip to the next newline and keep going */
2221             } else if ( strchr(thee->commChars,thee->buf[ii]) ) {
2222                 ii++;
2223                 VJMPERR1( ii < thee->size );
2224                 while ( thee->buf[ii] != '\n' ) {
2225                     ii++;
2226                     VJMPERR1( ii < thee->size );
2227                 }
2228 
2229             /* this must be the first token character */
2230             } else {
2231                 done = 1;
2232             }
2233         }
2234 
2235         /* set "jj" ptr to the first character (white or comm) after token */
2236         jj = ii+1;
2237         done = 0;
2238         while ( !done ) {
2239             /*
2240              * APBS-KTS: The below line is sort of dumb.  It has the effect of
2241              * requiring that there be a whiteChar or commChar character after
2242              * the final token.  But only if the file data just happens to
2243              * completely fill up thee->buf.  This would be unlikely, but if it
2244              * did happen, it would be a pain to debug.
2245              */
2246             VJMPERR1( jj < thee->size );
2247 
2248             /* if whiteChar then we are done */
2249             if ( strchr(thee->whiteChars,thee->buf[jj]) ) {
2250                 done = 1;
2251 
2252             /* if commChar then we are done */
2253             } else if ( strchr(thee->commChars,thee->buf[jj]) ) {
2254                 done = 1;
2255 
2256             /* this must be another token character */
2257             } else {
2258                 jj++;
2259             }
2260         }
2261 
2262         /* error control */
2263         VJMPERR1( (jj-ii) <= toksize );
2264         VJMPERR1( jj <= thee->size );
2265 
2266         /* copy the characters between ii and jj to the output string */
2267         for (i=ii; i<jj; i++)
2268             tok[i-ii] = thee->buf[i];
2269 /*        tok[jj] = '\0';
2270  *
2271  * APBS-KTS: Strictly speaking the above line is a bug.  It's also unnecessary.
2272  * It only works, and is redundant, because of the memset on tok above.
2273  * For what it's worth, it should be, assuming you didn't have the memset,
2274  *
2275  * tok[jj-ii] = '\0';
2276  */
2277 
2278         /* update the position pointer */
2279         thee->pos = jj;
2280 
2281     } else if (thee->mode == ASC_ENCODE) {
2282         fprintf(stderr,"asc_getToken: Don't know how to ENCODE yet!\n");
2283     }
2284 
2285     return tok;
2286 
2287   VERROR1:
2288     /*
2289      * APBS-KTS: Getting to the end of the buffer without a token should not be
2290      * a big deal.  It's an EOF condition.  Mark it thus and get on with it.
2291      *
2292      * fprintf(stderr,"asc_getToken: Error occurred (bailing out).\n");
2293      */
2294     thee->error = EOF;
2295     return VNULL;
2296 }
2297 
2298 /*
2299  * ***************************************************************************
2300  * Routine:  readn
2301  *
2302  * Purpose:  A fixed-up file-descriptor read (for UNIX/INET).
2303  *
2304  * Notes:    Fixes the "short read" problem if the operating system
2305  *           is interrupted during the read.  Calls the usual
2306  *           file-descriptor read repeatedly until n characters are
2307  *           actually read in.  Returns the number of characters
2308  *           actually read in.  Returns -1 on error.
2309  *
2310  *           Includes my WINSOCK fixes (err, rather hacks).
2311  *
2312  * Author:   Michael Holst (first of two jewels from Rick Stevens' book)
2313  * ***************************************************************************
2314  */
readn(int fd,void * vptr,unsigned int n)2315 VPRIVATE int readn(int fd, void *vptr, unsigned int n)
2316 {
2317     char *ptr;
2318     unsigned int nleft;
2319     int  nread;
2320 
2321     ptr = vptr;
2322     nleft = n;
2323     while (nleft > 0) {
2324         if ((nread = recv(fd,ptr,nleft,0)) < 0) {
2325 #if defined(HAVE_WINSOCK_H)
2326             if (WSAGetLastError() == WSAEINTR) {
2327                 nread = 0;
2328             } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
2329                 nread = 0;
2330             } else { return(-1); }
2331 #else
2332             if (errno == EINTR) {
2333                 nread = 0;
2334             } else if (errno == EWOULDBLOCK) {
2335                 nread = 0;
2336             } else { return(-1); }
2337 #endif
2338         } else if (nread == 0) {
2339             break;
2340         }
2341         nleft -= nread;
2342         ptr += nread;
2343     }
2344     return (n-nleft);
2345 }
2346 
2347 /*
2348  * ***************************************************************************
2349  * Routine:  writen
2350  *
2351  * Purpose:  A fixed-up file-descriptor write (for UNIX/INET).
2352  *
2353  * Notes:    Fixes the "short write" problem if the operating system
2354  *           has buffer overflow problems.  Calls the usual
2355  *           file-descriptor write repeatedly until the input buffer
2356  *           actually gets written out.  Returns the number of
2357  *           characters actually written out.  Returns -1 on error.
2358  *
2359  * Author:   Michael Holst (second of two jewels from Rick Stevens' book)
2360  * ***************************************************************************
2361  */
writen(int fd,void * vptr,unsigned int n)2362 VPRIVATE int writen(int fd, void *vptr, unsigned int n)
2363 {
2364     char *ptr;
2365     unsigned int nleft;
2366     int  nwritten;
2367 
2368     ptr = vptr;
2369     nleft = n;
2370     while (nleft > 0) {
2371         if ((nwritten = send(fd,ptr,nleft,0)) <= 0) {
2372             if (errno == EINTR) {
2373                 nwritten = 0;
2374             } else {
2375                 return(-1);
2376             }
2377         }
2378         nleft -= nwritten;
2379         ptr += nwritten;
2380     }
2381     return(n);
2382 }
2383 
2384 /*
2385  * ***************************************************************************
2386  * Routine:  Vio_bufTake
2387  *
2388  * Purpose:  Set the pointer to the internal buffer.
2389  *
2390  * Author:   Michael Holst
2391  * ***************************************************************************
2392  */
Vio_bufTake(Vio * thee,char * buf,int bufsize)2393 VPUBLIC void Vio_bufTake(Vio *thee, char *buf, int bufsize)
2394 {
2395     /* make sure Vio was started */
2396     VJMPERR1( VIOstarted );
2397 
2398     /* clear the internal buffer */
2399     if (thee->VIObuffer != VNULL) {
2400         free( thee->VIObuffer );
2401         thee->VIObuffer = VNULL;
2402     }
2403 
2404     /* now set the buffer */
2405     thee->VIObuffer    = buf;
2406     thee->VIObufferLen = bufsize;
2407     thee->VIObufferPtr = 0;
2408 
2409     /* return without error */
2410     return;
2411 
2412   VERROR1:
2413     fprintf(stderr,"Vio_bufTake: Vio library has not been started.\n");
2414     return;
2415 }
2416 
2417 /*
2418  * ***************************************************************************
2419  * Routine:  Vio_bufGive
2420  *
2421  * Purpose:  Return the pointer to the internal buffer.
2422  *
2423  * Author:   Michael Holst
2424  * ***************************************************************************
2425  */
Vio_bufGive(Vio * thee)2426 VPUBLIC char* Vio_bufGive(Vio *thee)
2427 {
2428     char *tmp;
2429 
2430     /* make sure Vio was started */
2431     VJMPERR1( VIOstarted );
2432 
2433     /* grab the pointer */
2434     tmp = thee->VIObuffer;
2435 
2436     /* reset things for the hand-off */
2437     thee->VIObufferLen = 0;
2438     thee->VIObuffer = VNULL;
2439 
2440     /* return without error */
2441     return tmp;
2442 
2443   VERROR1:
2444     fprintf(stderr,"Vio_bufGive: Vio library has not been started.\n");
2445     return VNULL;
2446 }
2447 
2448 /*
2449  * ***************************************************************************
2450  * Routine:  Vio_bufSize
2451  *
2452  * Purpose:  Return the length of the internal buffer.
2453  *
2454  * Author:   Michael Holst
2455  * ***************************************************************************
2456  */
Vio_bufSize(Vio * thee)2457 VPUBLIC int Vio_bufSize(Vio *thee)
2458 {
2459     /* make sure Vio was started */
2460     VJMPERR1( VIOstarted );
2461 
2462     /* return without error */
2463     return thee->VIObufferLen;
2464 
2465   VERROR1:
2466     fprintf(stderr,"Vio_bufSize: Vio library has not been started.\n");
2467     return 0;
2468 }
2469 
2470 /*
2471  * ***************************************************************************
2472  * Routine:  Vio_socketOpen
2473  *
2474  * Purpose:  Socket open for read or write.
2475  *
2476  * Author:   Michael Holst
2477  * ***************************************************************************
2478  */
Vio_socketOpen(char * key,const char * iodev,const char * iofmt,const char * iohost,const char * iofile)2479 VPUBLIC Vio *Vio_socketOpen(char *key,
2480     const char *iodev, const char *iofmt,
2481     const char *iohost, const char *iofile)
2482 {
2483     static Vio *sock;
2484 
2485     /* make sure Vio was started */
2486     VJMPERR1( VIOstarted );
2487 
2488     /* setup for a read */
2489     if (!strcmp("r",key)) {
2490 
2491         /* Open device for READ */
2492         if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"r")) ) {
2493             fprintf(stderr,"Vio_socketOpen: Problem opening(read) <%s>\n",
2494                 iofile);
2495             VJMPERR2( 0 );
2496         }
2497 
2498         /* START READ (blocking accept) */
2499         if ( 0 > Vio_accept(sock,0) ) {
2500             fprintf(stderr,"Vio_socketOpen: Problem accepting(read) <%s>\n",
2501                 iofile);
2502             /* destroy the socket before we return */
2503             Vio_dtor( &sock );
2504             VJMPERR2( 0 );
2505         }
2506 
2507     /* setup for a write */
2508     } else if (!strcmp("w",key)) {
2509 
2510         /* Open device for WRITE */
2511         if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"w")) ) {
2512             fprintf(stderr,"Vio_socketOpen: Problem opening(write) <%s>\n",
2513                 iofile);
2514             VJMPERR2( 0 );
2515         }
2516 
2517         /* START WRITE (blocking connect) */
2518         if ( 0 > Vio_connect(sock,0) ) {
2519             fprintf(stderr,"Vio_socketOpen: Problem connecting(write) <%s>\n",
2520                 iofile);
2521             /* destroy the socket before we return */
2522             Vio_dtor( &sock );
2523             VJMPERR2( 0 );
2524         }
2525 
2526     } else {
2527         fprintf(stderr,"Vio_socketOpen: Internal logic error.\n");
2528         VJMPERR2( 0 );
2529     }
2530 
2531     /* some i/o */
2532 #if 0
2533     fprintf(stderr,"Vio_socketOpen: iodev =<%s>\n", iodev);
2534     fprintf(stderr,"Vio_socketOpen: iofmt =<%s>\n", iofmt);
2535     fprintf(stderr,"Vio_socketOpen: iohost=<%s>\n", iohost);
2536     fprintf(stderr,"Vio_socketOpen: iofile=<%s>\n", iofile);
2537 #endif
2538 
2539     /* return without error */
2540     return sock;
2541 
2542   VERROR1:
2543     fprintf(stderr,"Vio_socketOpen: Vio library has not been started.\n");
2544     return VNULL;
2545 
2546   VERROR2:
2547     fprintf(stderr,"Vio_socketOpen: bailing out.\n");
2548     return VNULL;
2549 }
2550 
2551 /*
2552  * ***************************************************************************
2553  * Routine:  Vio_socketClose
2554  *
2555  * Purpose:  Socket close from read or write.
2556  *
2557  * Author:   Michael Holst
2558  * ***************************************************************************
2559  */
Vio_socketClose(Vio ** sock)2560 VPUBLIC void Vio_socketClose(Vio **sock)
2561 {
2562     /* make sure Vio was started */
2563     VJMPERR1( VIOstarted );
2564 
2565     VJMPERR2( VNULL != *sock );
2566 
2567     /* FINISH READ (release subsocket if we had one) */
2568     if ((*sock)->rwkey == VIO_R) {
2569         Vio_acceptFree(*sock);
2570 
2571     /* FINISH WRITE */
2572     } else if ((*sock)->rwkey == VIO_W) {
2573         Vio_connectFree(*sock);
2574 
2575     /* Problems... */
2576     } else {
2577         VJMPERR2( 0 );
2578     }
2579 
2580     /* return without error */
2581     Vio_dtor(sock);
2582     return;
2583 
2584   VERROR1:
2585     fprintf(stderr,"Vio_socketClose: Vio library has not been started.\n");
2586     return;
2587 
2588   VERROR2:
2589     fprintf(stderr,"Vio_socketClose: bailing out.\n");
2590     return;
2591 }
2592 
2593