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