2
* ***************************************************************************
3
* MALOC = < Minimal Abstraction Layer for Object-oriented C >
4
* Copyright (C) 1994--2000 Michael Holst
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation; either version 2 of the License, or (at your
9
* option) any later version.
11
* This program 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.
14
* See the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program; if not, write to the Free Software Foundation, Inc.,
18
* 675 Mass Ave, Cambridge, MA 02139, USA.
20
* rcsid="$Id: vio.c,v 1.28 2004/02/18 01:10:56 mholst Exp $"
21
* ***************************************************************************
25
* ***************************************************************************
28
* Purpose: Class Vio: methods.
30
* Author: Michael Holst
31
* ***************************************************************************
36
VEMBED(rcsid="$Id: vio.c,v 1.28 2004/02/18 01:10:56 mholst Exp $")
38
#if defined(HAVE_UNISTD_H)
42
#if defined(HAVE_SYS_TYPES_H)
43
# include <sys/types.h>
46
#if defined(HAVE_SYS_STAT_H)
47
# include <sys/stat.h>
50
#if defined(HAVE_FCNTL_H)
54
#if defined(HAVE_SYS_SOCKET_H)
55
# include <sys/socket.h>
58
#if defined(HAVE_SYS_UN_H)
62
#if defined(HAVE_NETINET_IN_H)
63
# include <netinet/in.h>
66
#if defined(HAVE_ARPA_INET_H)
67
# include <arpa/inet.h>
70
#if defined(HAVE_NETDB_H)
74
#if defined(HAVE_RPC_RPC_H)
76
#elif defined(HAVE_RPC_H)
80
#if defined(HAVE_WINSOCK_H)
84
#if defined(HAVE_IO_H)
88
/* ASC modes as dual to the XDR modes */
89
typedef enum ASCmode {
95
/* ASC structure as dual to the XDR structure */
97
ASCmode mode; /* ASC_DECODE or ASC_ENCODE */
98
int pos; /* position of next character in buf */
99
int size; /* size of buf */
100
char *buf; /* the character buffer */
101
char whiteChars[VMAX_ARGNUM]; /* white space character set */
102
char commChars[VMAX_ARGNUM]; /* comment character set */
105
/* use ASC in place of XDR if XDR does not exist */
106
#if !defined(HAVE_XDR)
108
# define XDR_DECODE ASC_DECODE
109
# define XDR_ENCODE ASC_ENCODE
110
# define xdrmem_create ascmem_create
111
# define xdr_destroy asc_destroy
112
# define xdr_getpos asc_getpos
113
# define xdr_setpos asc_setpos
114
# define xdr_string asc_string
115
# define xdr_char asc_char
116
# define xdr_int asc_int
117
# define xdr_float asc_float
118
# define xdr_double asc_double
121
/* communication startup */
122
VPRIVATE int VIOstarted = 0;
124
/* default comment char set and white space char set */
125
VPRIVATE char *VIOwhiteChars = " \t\n";
126
VPRIVATE char *VIOcommChars = "";
128
/* initialization, signals, and other tools */
129
VPRIVATE void VIOregHand(void);
130
VPRIVATE void VIOunregHand(void);
131
VPRIVATE void VIOsigHand(int num);
132
VPRIVATE int VIOgethostname(char *name, unsigned int len);
133
VPRIVATE const char *VIOstrerrno(int err);
135
/* buffer management */
136
VPRIVATE void Vio_initIoPutBuffers(Vio *thee);
137
VPRIVATE void Vio_purgePutBuffer(Vio *thee);
138
VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize);
140
/* ASC analogs to the core XDR routines */
141
VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode);
142
VPRIVATE void asc_destroy(ASC *thee);
143
VPRIVATE int asc_getpos(ASC *thee);
144
VPRIVATE int asc_setpos(ASC *thee, int pos);
145
VPRIVATE int asc_string(ASC *thee, char **sval, int size);
146
VPRIVATE int asc_char(ASC *thee, char *cval);
147
VPRIVATE int asc_int(ASC *thee, int *ival);
148
VPRIVATE int asc_float(ASC *thee, float *fval);
149
VPRIVATE int asc_double(ASC *thee, double *dval);
151
/* some additional ASC routines (no analogs in XDR) */
152
VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars);
153
VPRIVATE void asc_setCommChars(ASC *thee, char *commChars);
154
VPRIVATE char *asc_getToken(ASC *thee, char *tok, int toksize);
156
/* two low-level file-descriptor i/o jewels from Rick Steven's book */
157
VPRIVATE int readn(int fd, void *vptr, unsigned int n);
158
VPRIVATE int writen(int fd, void *vptr, unsigned int n) ;
161
* ***************************************************************************
162
* Class Vio: Inlineable methods
163
* ***************************************************************************
165
#if !defined(VINLINE_MALOC)
167
#endif /* if !defined(VINLINE_MALOC) */
169
* ***************************************************************************
170
* Class Vio: Non-inlineable methods
171
* ***************************************************************************
175
* ***************************************************************************
178
* Purpose: Startup the Vio communication layer.
180
* Notes: This routine initializes some internal variables and buffers.
181
* This routine also deals with the interception of fatal
182
* SIGPIPE signals which are generated on some systems when a
183
* socket connection is broken by one of the send/receive pair.
185
* We don't want to abort in this situation, but rather do some
186
* damage control. Hence we register our own SIGPIPE interrupt
187
* handler in Vio_start(), and re-register it every time a SIGPIPE
188
* is intercepted. We re-register it because some systems reset
189
* the interrupt mask after a single interrupt is generated.
190
* We un-register the SIGPIPE handler in Vio_stop().
192
* To use the Vio library, you need to call Vio_start() before
193
* you make any calls to the Vio_ctor(). Calling the Vio_ctor()
194
* (or any other Vio method) before Vio_start() generates an error.
195
* For example, you can call this routine as follows:
199
* Author: Michael Holst
200
* ***************************************************************************
202
VPUBLIC void Vio_start(void)
204
/* repeated initializations ARE legal (no error; possibly frees memory) */
205
/* VASSERT( !VIOstarted ); */
207
/* mark as initialized */
210
/* register the SIGPIPE handler to avoid aborts on a SIGPIPE */
218
* ***************************************************************************
221
* Purpose: Shutdown the Vio communication layer.
223
* Notes: This routine was written primarily to deal with some
224
* communication runtime environments which require a shutdown.
226
* Author: Michael Holst
227
* ***************************************************************************
229
VPUBLIC void Vio_stop(void)
231
/* repeated de-initializations ARE legal (no error; just a no-op) */
232
/* VASSERT( VIOstarted ); */
234
/* un-initialize us */
237
/* un-register the SIGPIPE handler */
245
* ***************************************************************************
246
* Routine: VIOregHand
248
* Purpose: Register the signal handler with the operating system.
250
* Author: Michael Holst
251
* ***************************************************************************
253
VPRIVATE void VIOregHand(void)
255
#if !defined(HAVE_WINSOCK_H)
256
VASSERT( signal(SIGPIPE,&VIOsigHand) != SIG_ERR );
261
* ***************************************************************************
262
* Routine: VIOunregHand
264
* Purpose: Un-Register the signal handler with the operating system.
266
* Author: Michael Holst
267
* ***************************************************************************
269
VPRIVATE void VIOunregHand(void)
271
#if !defined(HAVE_WINSOCK_H)
272
VASSERT( signal(SIGPIPE,SIG_DFL) != SIG_ERR );
277
* ***************************************************************************
278
* Routine: VIOsigHand
280
* Purpose: Handle events such as SIGPIPE.
282
* Author: Michael Holst
283
* ***************************************************************************
285
VPRIVATE void VIOsigHand(int num)
288
fprintf(stderr,"VIOsigHand: yow! caught a hot SIGPIPE....diffused it.\n");
290
/* just re-register interrupt handler in case it was cleared by default */
295
* ***************************************************************************
296
* Routine: VIOgethostname
298
* Purpose: Get the hostname of this machine.
299
* Returns 0 on success. Returns -1 on error.
301
* Author: Michael Holst
302
* ***************************************************************************
304
VPRIVATE int VIOgethostname(char *name, unsigned int len)
306
#if defined(HAVE_WINSOCK_H)
307
return gethostname(name,(int)len);
309
return gethostname(name,len);
314
* ***************************************************************************
315
* Routine: VIOstrerrno
317
* Purpose: Return the error string corresponding to the error number.
319
* Notes: This is a partial implementation of the "iberty" library
320
* function "strerrno" that exists on most Linux boxes. It is
321
* simply a mapping of error number to error string. It is
322
* very useful for debugging UNIX and INET socket code.
324
* Author: Michael Holst
325
* ***************************************************************************
327
VPRIVATE const char *VIOstrerrno(int err)
329
static char errstr[80];
331
if (err == EFAULT ) strcpy(errstr,"EFAULT");
332
else if (err == EINTR ) strcpy(errstr,"EINTR");
333
else if (err == EINVAL ) strcpy(errstr,"EINVAL");
334
else if (err == ENOENT ) strcpy(errstr,"ENOENT");
335
else if (err == EPIPE ) strcpy(errstr,"EPIPE");
336
else if (err == ENOMEM ) strcpy(errstr,"ENOMEM");
337
else if (err == EAGAIN ) strcpy(errstr,"EAGAIN");
338
else if (err == EBADF ) strcpy(errstr,"EBADF");
340
#if defined(HAVE_WINSOCK_H)
341
else if (err == WSAENETDOWN ) strcpy(errstr,"WSAENETDOWN");
342
else if (err == WSAEFAULT ) strcpy(errstr,"WSAEFAULT");
343
else if (err == WSAENOTCONN ) strcpy(errstr,"WSAENOTCONN");
344
else if (err == WSAEINTR ) strcpy(errstr,"WSAEINTR");
345
else if (err == WSAEINPROGRESS ) strcpy(errstr,"WSAEINPROGRESS");
346
else if (err == WSAENETRESET ) strcpy(errstr,"WSAENETRESET");
347
else if (err == WSAENOTSOCK ) strcpy(errstr,"WSAENOTSOCK");
348
else if (err == WSAEOPNOTSUPP ) strcpy(errstr,"WSAEOPNOTSUPP");
349
else if (err == WSAESHUTDOWN ) strcpy(errstr,"WSAESHUTDOWN");
350
else if (err == WSAEWOULDBLOCK ) strcpy(errstr,"WSAEWOULDBLOCK");
351
else if (err == WSAEMSGSIZE ) strcpy(errstr,"WSAEMSGSIZE");
352
else if (err == WSAEINVAL ) strcpy(errstr,"WSAEINVAL");
353
else if (err == WSAETIMEDOUT ) strcpy(errstr,"WSAETIMEDOUT");
354
else if (err == WSAECONNABORTED ) strcpy(errstr,"WSAECONNABORTED");
355
else if (err == WSAECONNREFUSED ) strcpy(errstr,"WSAECONNREFUSED");
356
else if (err == WSAECONNRESET ) strcpy(errstr,"WSAECONNRESET");
357
else if (err == WSANOTINITIALISED) strcpy(errstr,"WSANOTINITIALISED");
359
else if (err == ENETDOWN ) strcpy(errstr,"ENETDOWN");
360
else if (err == ENOTCONN ) strcpy(errstr,"ENOTCONN");
361
else if (err == EINPROGRESS ) strcpy(errstr,"EINPROGRESS");
362
else if (err == ENETRESET ) strcpy(errstr,"ENETRESET");
363
else if (err == ENOTSOCK ) strcpy(errstr,"ENOTSOCK");
364
else if (err == EOPNOTSUPP ) strcpy(errstr,"EOPNOTSUPP");
365
else if (err == ESHUTDOWN ) strcpy(errstr,"ESHUTDOWN");
366
else if (err == EWOULDBLOCK ) strcpy(errstr,"EWOULDBLOCK");
367
else if (err == EMSGSIZE ) strcpy(errstr,"EMSGSIZE");
368
else if (err == ETIMEDOUT ) strcpy(errstr,"ETIMEDOUT");
369
else if (err == ECONNABORTED ) strcpy(errstr,"ECONNABORTED");
370
else if (err == ECONNREFUSED ) strcpy(errstr,"ECONNREFUSED");
371
else if (err == ECONNRESET ) strcpy(errstr,"ECONNRESET");
372
else if (err == ENOBUFS ) strcpy(errstr,"ENOBUFS");
375
else sprintf(errstr,"VIO_UNKNOWN_ERROR(%d)",err);
380
* ***************************************************************************
383
* Purpose: Construct the [sdio/file/buff/unix/inet] container object.
385
* Author: Michael Holst
386
* ***************************************************************************
388
VPUBLIC Vio* Vio_ctor(const char *socktype, const char *datafrmt,
389
const char *hostname, const char *filename, const char *rwkey)
393
/* make sure Vio was started */
394
VJMPERR1( VIOstarted );
396
thee = (Vio*)calloc( 1, sizeof(Vio) );
397
VJMPERR2( thee != VNULL );
398
VJMPERR3( Vio_ctor2(thee, socktype, datafrmt, hostname, filename, rwkey) );
404
fprintf(stderr,"Vio_ctor: Vio library has not been started.\n");
408
fprintf(stderr,"Vio_ctor: malloc of Vio structure failed.\n");
412
fprintf(stderr,"Vio_ctor: Vio_ctor2() failed.\n");
418
* ***************************************************************************
421
* Purpose: Construct the [sdio/file/buff/unix/inet] container object.
423
* Author: Michael Holst
424
* ***************************************************************************
426
VPUBLIC int Vio_ctor2(Vio *thee, const char *socktype, const char *datafrmt,
427
const char *hostname, const char *filename, const char *rwkey)
433
struct hostent *hpTmp;
434
#if defined(HAVE_WINSOCK_H)
437
#if defined(HAVE_SYS_UN_H)
441
/* make sure Vio was started */
442
VJMPERR1( VIOstarted );
444
/* initialize all Vio fields */
445
thee->type = VIO_NO_TYPE;
446
thee->frmt = VIO_NO_FRMT;
447
thee->rwkey = VIO_NO_RW;
456
/* initialize the internal buffer (for BUFF datatype) */
457
thee->VIObuffer = VNULL;
458
thee->VIObufferLen = 0;
459
thee->VIObufferPtr = 0;
461
/* initialize the socktype field */
462
if (!strcmp(socktype,"SDIO")) {
463
thee->type = VIO_SDIO;
464
} else if (!strcmp(socktype,"FILE")) {
465
thee->type = VIO_FILE;
466
} else if (!strcmp(socktype,"BUFF")) {
467
thee->type = VIO_BUFF;
468
} else if (!strcmp(socktype,"UNIX")) {
469
thee->type = VIO_UNIX;
470
} else if (!strcmp(socktype,"INET")) {
471
thee->type = VIO_INET;
473
fprintf(stderr,"Vio_ctor2: Incorrect socktype given <%s>\n",socktype);
477
/* initialize the datafrmt field */
478
if (!strcmp(datafrmt,"ASC")) {
479
thee->frmt = VIO_ASC;
480
} else if (!strcmp(datafrmt,"XDR")) {
481
thee->frmt = VIO_XDR;
483
fprintf(stderr,"Vio_ctor2: Incorrect datafrmt given <%s>\n", datafrmt);
487
/* initialize the r/w field */
488
if (!strcmp(rwkey,"r")) {
490
} else if (!strcmp(rwkey,"w")) {
493
fprintf(stderr,"Vio_ctor2: Incorrect rwkey given <%s>\n", rwkey);
497
/* need to call this stupid Win32 function before gethostname... */
498
#if defined(HAVE_WINSOCK_H)
499
if ( WSAStartup(0x0101, &wsaData) != 0 ) {
500
fprintf(stderr, "Vio_ctor2: WSAStartup fail INET sock <%s>"
501
" dueto <%s>\n", thee->file,VIOstrerrno(errno));
506
/* get "my" local hostname */
507
if ((VIOgethostname(thee->lhost,sizeof(thee->lhost))) < 0) {
509
"Vio_ctor2: Gethostname fail INET sock <%s> dueto <%s>\n",
510
thee->file, VIOstrerrno(errno));
511
strcpy(thee->lhost,"unknown");
512
} else if ((hpTmp=gethostbyname(thee->lhost))==VNULL) {
514
"Vio_ctor2: Gethostbyname fail INET sock <%s> dueto <%s>\n",
515
thee->file, VIOstrerrno(errno));
516
strcpy(thee->lhost,"unknown");
517
} else strcpy(thee->lhost,hpTmp->h_name);
519
/* default remote hostname */
520
strcpy(thee->rhost,"unknown");
522
/* initialize the buffer space */
523
Vio_initIoPutBuffers(thee);
525
/* SDIO READ/WRITE SETUP */
526
if (thee->type==VIO_SDIO) {
528
if (thee->rwkey==VIO_R) {
530
} else { /* (thee->rwkey==VIO_W) */
533
VJMPERR2( thee->fp != VNULL );
535
/* FILE READ/WRITE SETUP */
536
} else if (thee->type==VIO_FILE) {
538
/* filename is the i/o file name */
539
strncpy(thee->file, filename, 80);
540
if (thee->rwkey==VIO_R) {
541
thee->fp = fopen(thee->file, "r");
542
} else { /* (thee->rwkey==VIO_W) */
543
thee->fp = fopen(thee->file, "w");
545
VJMPERR2( thee->fp != VNULL );
547
/* BUFF READ/WRITE SETUP */
548
} else if (thee->type==VIO_BUFF) {
550
/* filename is the internal buffer number for the buffer */
551
thee->VIObufferPtr = 0;
553
/* UNIX SOCKET READ/WRITE SETUP */
554
} else if (thee->type==VIO_UNIX) {
556
#if defined(HAVE_SYS_UN_H)
558
/* filename is socketName-userName in the directory /tmp */
560
VASSERT( Vnm_getuser(username, sizeof(username)) );
561
sprintf(thee->file, "/tmp/%s-%s", filename, username);
563
/* create the socket address structure */
564
thee->name = (struct sockaddr_un *)
565
calloc( 1, sizeof(struct sockaddr_un) );
566
VJMPERR2( thee->name != VNULL );
568
/* Get a socket structure */
569
if ((thee->so=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
570
fprintf(stderr,"Vio_ctor2: fail to find UNIX sock dueto <%s>.\n",
575
/* set REUSEADDR so sockets can be closed and reopened */
576
ival = 1; /* just need a nonzero value */
577
if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
578
(void*)&ival,sizeof(ival)) < 0 ) {
579
fprintf(stderr, "Vio_ctor2: Setsockopt1 fail UNIX sock <%s>"
580
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
584
/* turn on LINGER so WRITES complete before socks close */
585
ling.l_onoff = 1; /* just need a nonzero value */
586
ling.l_linger = 30; /* linger time in seconds */
587
if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
588
(void*)&ling,sizeof(ling)) < 0) {
589
fprintf(stderr, "Vio_ctor2: Setsockopt2 fail UNIX sock <%s>"
590
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
594
/* Setup for the socket */
595
memset(thee->name, '\0', sizeof(struct sockaddr_un));
596
((struct sockaddr_un *)(thee->name))->sun_family = AF_UNIX;
597
strcpy(((struct sockaddr_un *)(thee->name))->sun_path,
600
/* if we are reader, WE are responsible for creating socket */
601
/* the reader must do: (unlink/)setsockopt/bind/listen */
602
if (thee->rwkey==VIO_R) {
604
/* define socket file; remove previous socket */
607
/* determine structure size; AF_UNIX is variable length */
608
len = sizeof(((struct sockaddr_un *)
609
(thee->name))->sun_family)
610
+ strlen(((struct sockaddr_un *)
611
(thee->name))->sun_path);
613
/* Bind socket to address (must setsockopts before bind) */
614
if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
616
"Vio_ctor2: Bind fail UNIX sock <%s> dueto <%s>\n",
617
thee->file, VIOstrerrno(errno));
621
/* Tell socket to start listening for connections */
622
if (listen(thee->so,5) < 0) {
624
"Vio_ctor2: List fail UNIX sock <%s> dueto <%s>\n",
625
thee->file, VIOstrerrno(errno));
630
* if we got to here, we can assume reader has done
631
* all of: (unlink/)setsockopt/bind/listen
637
/* INET SOCKET READ/WRITE SETUP */
638
} else if (thee->type==VIO_INET) {
640
/* filename is the port number for the socket */
641
strncpy(thee->file, filename, 80);
643
/* create the socket address structure */
644
thee->name = (struct sockaddr_in *)
645
calloc( 1, sizeof(struct sockaddr_in) );
646
VJMPERR2( thee->name != VNULL );
648
/* Look for sockets */
649
if ((thee->so=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
650
fprintf(stderr,"Vio_ctor2: fail to find INET sock dueto <%s>\n",
655
/* set REUSEADDR so sockets can be closed and reopened */
656
ival = 1; /* just need a nonzero value */
657
if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
658
(void*)&ival,sizeof(ival)) < 0 ) {
659
fprintf(stderr, "Vio_ctor2: Setsockopt3 fail INET sock <%s>"
660
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
664
/* turn on LINGER so WRITES complete before sockets close */
665
ling.l_onoff = 1; /* just need a nonzero value */
666
ling.l_linger = 30; /* linger time in seconds */
667
if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
668
(void*)&ling,sizeof(ling)) < 0 ) {
669
fprintf(stderr, "Vio_ctor2: Setsockopt4 fail INET sock <%s>"
670
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
674
/* Setup for the socket */
675
memset(thee->name, '\0', sizeof(struct sockaddr_in));
676
((struct sockaddr_in *)(thee->name))->sin_family = AF_INET;
677
((struct sockaddr_in *)(thee->name))->sin_port
678
= htons( (unsigned short) (VPORTNUMBER + atoi(thee->file)) );
680
/* if we are the reader, WE must create the socket */
681
/* the reader must do: setsockopt/bind/listen */
682
if (thee->rwkey==VIO_R) {
684
/* use wildcard address */
686
memcpy(&((struct sockaddr_in *)(thee->name))->sin_addr,
689
/* determine structure size; AF_INET is fixed length */
690
len = sizeof(struct sockaddr_in);
692
/* Bind socket to address (must setsockopts before bind) */
693
if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
695
"Vio_ctor2: Bind fail INET sock <%s> dueto <%s>\n",
696
thee->file, VIOstrerrno(errno));
700
/* Tell socket to start listening for connections */
701
if (listen(thee->so,5) < 0) {
703
"Vio_ctor2: List fail INET sock <%s> dueto <%s>\n",
704
thee->file, VIOstrerrno(errno));
709
/* assume reader has done: setsockopt/bind/listen */
712
/* network address of port -- "localhost" means WE have port */
713
if (!strcmp(hostname,"localhost")) {
714
strcpy(host,thee->lhost);
716
strcpy(host,hostname);
719
/* get IP address corresponding to this server hostname */
720
if ((hpTmp=gethostbyname(host))==VNULL) {
722
"Vio_ctor2: Gethostbyname fail INET sock <%s>"
723
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
727
/* just need to save address of host that has socket */
729
&(((struct sockaddr_in *)(thee->name))->sin_addr),
730
hpTmp->h_addr_list[0], (unsigned int)hpTmp->h_length);
732
/* save the hostname for the port for later i/o */
733
strcpy(thee->rhost,hpTmp->h_name);
739
/* initialize <asc,xdr> datastructures; must do almost at the end */
740
if (thee->frmt==VIO_ASC) {
741
thee->axdr = (ASC*)calloc( 1, sizeof(ASC) );
742
VJMPERR2( thee->axdr != VNULL );
743
if (thee->rwkey==VIO_R) {
744
ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_DECODE);
745
} else { /* if (thee->rwkey==VIO_W) */
746
ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_ENCODE);
748
} else if (thee->frmt==VIO_XDR) {
749
thee->axdr = (XDR*)calloc( 1, sizeof(XDR) );
750
VJMPERR2( thee->axdr != VNULL );
751
if (thee->rwkey==VIO_R) {
752
xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_DECODE);
753
} else { /* if (thee->rwkey==VIO_W) */
754
xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_ENCODE);
758
/* lastly: default white/comment char sets (careful! propogates to axdr) */
759
Vio_setWhiteChars(thee, VIOwhiteChars);
760
Vio_setCommChars(thee, VIOcommChars);
762
/* return without error */
766
fprintf(stderr,"Vio_ctor2: Vio library has not been started.\n");
770
fprintf(stderr,"Vio_ctor2: some error occurred.\n");
775
* ***************************************************************************
778
* Purpose: Destroy the [sdio/file/buff/unix/inet] container object.
780
* Author: Michael Holst
781
* ***************************************************************************
783
VPUBLIC void Vio_dtor(Vio **thee)
785
if ((*thee) != VNULL) {
786
if ((*thee)->VIObuffer != VNULL) {
787
free( (*thee)->VIObuffer );
788
(*thee)->VIObuffer = VNULL;
797
* ***************************************************************************
800
* Purpose: Destroy the [sdio/file/buff/unix/inet] container object.
802
* Author: Michael Holst
803
* ***************************************************************************
805
VPUBLIC void Vio_dtor2(Vio *thee)
809
/* free the <ASC,XDR> structures */
810
if ( thee->axdr != VNULL ) {
811
if ( thee->frmt == VIO_ASC ) {
812
asc_destroy( (ASC*)(thee->axdr) );
813
} else if ( thee->frmt == VIO_XDR ) {
814
xdr_destroy( (XDR*)(thee->axdr) );
821
if (thee->type==VIO_SDIO) {
823
} else if (thee->type==VIO_FILE) {
824
if ( thee->fp != VNULL ) {
825
if ( fclose(thee->fp) != 0 ) {
826
fprintf(stderr, "Vio_dtor2: fclose fail device <%s>"
827
" dueto <%s>\n", thee->file,VIOstrerrno(errno));
830
} else if (thee->type==VIO_BUFF) {
831
/* CMIKE: WHAT ABOUT FREEING THE BUFFER SPACE??? */
832
thee->VIObufferPtr = 0;
833
} else if ( (thee->type==VIO_UNIX)
834
|| (thee->type==VIO_INET) ) {
835
if ( thee->soc >= 0 ) {
836
#if defined(HAVE_WINSOCK_H)
837
if ( closesocket(thee->soc) != 0 ) {
838
fprintf(stderr, "Vio_dtor2: closesocket1 fail device <%s>"
839
" dueto <%s>\n", thee->file,
843
if ( close(thee->soc) != 0 ) {
844
fprintf(stderr, "Vio_dtor2: close1 fail device <%s>"
845
" dueto <%s>\n", thee->file,
850
if ( thee->so >= 0 ) {
851
#if defined(HAVE_WINSOCK_H)
852
if ( closesocket(thee->so) != 0 ) {
853
fprintf(stderr, "Vio_dtor2: closesocket2 fail device <%s>"
854
" dueto <%s>\n", thee->file,
858
if ( close(thee->so) != 0 ) {
859
fprintf(stderr, "Vio_dtor2: close2 fail device <%s>"
860
" dueto <%s>\n", thee->file,
866
/* remove the device file for domain sockets */
867
if (thee->type==VIO_UNIX)
868
if (thee->rwkey==VIO_R)
872
fprintf(stderr,"Vio_dtor2: Bad type found <%d>\n", thee->type);
875
if ( (thee->type==VIO_UNIX)
876
|| (thee->type==VIO_INET) ) {
877
if (thee->name != VNULL) {
883
/* we called WSAStartup() in constructor; must always be paired */
884
#if defined(HAVE_WINSOCK_H)
891
* ***************************************************************************
892
* Routine: Vio_setWhiteChars
894
* Purpose: Define the white character set.
896
* Author: Michael Holst
897
* ***************************************************************************
899
VPUBLIC void Vio_setWhiteChars(Vio *thee, char *whiteChars)
902
strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
904
/* propogate the character set down to the ASC structure */
905
VASSERT( thee->axdr != VNULL );
906
if (thee->frmt == VIO_ASC) {
907
asc_setWhiteChars(thee->axdr, whiteChars);
908
} else if (thee->frmt == VIO_XDR) {
909
#if !defined(HAVE_XDR)
910
asc_setWhiteChars(thee->axdr, whiteChars);
912
} else { VASSERT( 0 ); }
917
* ***************************************************************************
918
* Routine: Vio_setCommChars
920
* Purpose: Define the comment character set.
922
* Author: Michael Holst
923
* ***************************************************************************
925
VPUBLIC void Vio_setCommChars(Vio *thee, char *commChars)
928
strncpy(thee->commChars, commChars, VMAX_ARGNUM);
930
/* propogate the character set down to the ASC structure */
931
VASSERT( thee->axdr != VNULL );
932
if (thee->frmt == VIO_ASC) {
933
asc_setCommChars(thee->axdr, commChars);
934
} else if (thee->frmt == VIO_XDR) {
935
#if !defined(HAVE_XDR)
936
asc_setCommChars(thee->axdr, commChars);
938
} else { VASSERT( 0 ); }
943
* ***************************************************************************
944
* Routine: Vio_accept
946
* Purpose: Accept any waiting connect attempt to our socket on our machine.
948
* Notes: The nonblock parameter has the following interpretation:
949
* (Only for <UNIX/INET>; othewise it is ignored.)
951
* nonblock==0 ==> block until a connect is attempted
952
* nonblock==1 ==> DO NOT block at all
954
* Author: Michael Holst
955
* ***************************************************************************
957
VPUBLIC int Vio_accept(Vio *thee, int nonblock)
961
#if defined(HAVE_WINSOCK_H)
962
unsigned long blockKey;
965
struct sockaddr_in peer;
966
struct hostent *hpTmp;
969
#if defined(ACCEPT_USES_ULONG)
971
#elif defined(ACCEPT_USES_UINT)
973
#elif defined(ACCEPT_USES_INT)
979
/* reset error tag */
985
Vio_initIoPutBuffers(thee);
986
VJMPERR2( thee->rwkey == VIO_R );
988
if ( (thee->type==VIO_SDIO)
989
|| (thee->type==VIO_FILE)
990
|| (thee->type==VIO_BUFF) ) {
992
/* ONLY for file i/o, we need to look at and set the dirty bit */
993
/* (this keeps us from reading the file twice) */
994
if (thee->type==VIO_FILE) {
995
if ((!thee->dirty) && (!feof(thee->fp))) {
1003
} else if (thee->type==VIO_UNIX) {
1005
#if defined(HAVE_SYS_UN_H)
1006
/* Make this a non-blocking socket just for the accept call */
1008
flags = fcntl( thee->so, F_GETFL, 0 );
1009
fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1013
len = sizeof(struct sockaddr_un);
1014
rc = accept(thee->so,(struct sockaddr *)(thee->name),&len);
1016
if ((!nonblock) && (rc < 0)) {
1017
fprintf(stderr, "Vio_accept: Accept fail UNIX sock <%s>"
1018
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1022
/* restore blocking -- must nonblock for LINGER to work! */
1024
fcntl( thee->so, F_SETFL, flags );
1028
} else if (thee->type==VIO_INET) {
1030
/* Make this non-blocking socket just for accept call */
1032
#if defined(HAVE_WINSOCK_H)
1034
if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
1035
fprintf(stderr, "Vio_accept: Ioctlsocket1 fail INET sock <%s>"
1036
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1040
flags = fcntl( thee->so, F_GETFL, 0 );
1041
fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1045
len = sizeof(struct sockaddr_in);
1046
rc = accept(thee->so, (struct sockaddr *)(thee->name), &len);
1048
if ((!nonblock) && (rc < 0)) {
1049
fprintf(stderr, "Vio_accept: Accept fail INET sock <%s>"
1050
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1054
/* restore blocking -- must nonblock for LINGER to work! */
1056
#if defined(HAVE_WINSOCK_H)
1058
if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
1059
fprintf(stderr, "Vio_accept: Ioctlsocket2 fail INET sock <%s>"
1060
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1064
fcntl( thee->so, F_SETFL, flags );
1068
/* if we found a writer, get his hostname (just for i/o) */
1070
#if defined(HAVE_WINSOCK_H)
1071
strcpy(thee->rhost,"unknown");
1073
len = sizeof(struct sockaddr_in);
1074
if (getpeername(thee->soc,(struct sockaddr *)(&peer),&len)<0) {
1075
fprintf(stderr, "Vio_accept: Getpeername fail INET <%s>"
1076
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1078
} else if (VNULL==(hpTmp=gethostbyname(inet_ntoa(peer.sin_addr)))){
1079
fprintf(stderr, "Vio_accept: Gethostbyname fail INET <%s>"
1080
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1083
strcpy(thee->rhost,hpTmp->h_name);
1089
fprintf(stderr,"Vio_accept: Bad type found <%d>\n", thee->type);
1102
* ***************************************************************************
1103
* Routine: Vio_acceptFree
1105
* Purpose: Free the socket child that was used for the last accept.
1107
* Author: Michael Holst
1108
* ***************************************************************************
1110
VPUBLIC void Vio_acceptFree(Vio *thee)
1112
/* VJMPERR2( !thee->error ); */ /* Need to close the socket... */
1113
VJMPERR2( thee->rwkey == VIO_R );
1115
if ( (thee->type==VIO_SDIO)
1116
|| (thee->type==VIO_FILE)
1117
|| (thee->type==VIO_BUFF) ) {
1119
} else if ( (thee->type==VIO_UNIX)
1120
|| (thee->type==VIO_INET) ) {
1121
if ( thee->soc >= 0 ) {
1122
#if defined(HAVE_WINSOCK_H)
1123
if ( closesocket(thee->soc) != 0 ) {
1124
fprintf(stderr, "Vio_acceptFree: closesocket fail device <%s>"
1125
" dueto <%s>\n", thee->file,VIOstrerrno(errno));
1129
if ( close(thee->soc) != 0 ) {
1130
fprintf(stderr, "Vio_acceptFree: close fail device <%s>"
1131
" dueto <%s>\n", thee->file,VIOstrerrno(errno));
1137
fprintf(stderr,"Vio_acceptFree: Bad type found <%d>\n", thee->type);
1144
Vio_initIoPutBuffers(thee);
1148
Vio_initIoPutBuffers(thee);
1154
* ***************************************************************************
1155
* Routine: Vio_connect
1157
* Purpose: Connect to some socket on a remote machine (or on our machine).
1159
* Notes: The nonblock parameter has the following interpretation:
1160
* (Only for <UNIX/INET>; othewise it is ignored.)
1162
* nonblock==0 ==> block until our connection is accepted
1163
* nonblock==1 ==> DO NOT block at all
1165
* Author: Michael Holst
1166
* ***************************************************************************
1168
VPUBLIC int Vio_connect(Vio *thee, int nonblock)
1171
#if defined(HAVE_WINSOCK_H)
1178
/* reset error tag */
1183
Vio_initIoPutBuffers(thee);
1184
VJMPERR2( thee->rwkey == VIO_W );
1186
if ( (thee->type==VIO_SDIO)
1187
|| (thee->type==VIO_FILE)
1188
|| (thee->type==VIO_BUFF) ) {
1190
} else if (thee->type==VIO_UNIX) {
1192
#if defined(HAVE_SYS_UN_H)
1193
/* Make this a non-blocking socket just for the connect call */
1195
flags = fcntl( thee->so, F_GETFL, 0 );
1196
fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1199
/* blocking connect */
1200
len = sizeof(struct sockaddr_un);
1201
rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
1202
if ((!nonblock) && (rc < 0)) {
1203
fprintf(stderr, "Vio_connect: Conn fail UNIX sock <%s>"
1204
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1208
/* restore blocking -- must nonblock for LINGER to work! */
1210
fcntl( thee->so, F_SETFL, flags );
1214
} else if (thee->type==VIO_INET) {
1216
/* make this a non-blocking socket just for the connect call */
1218
#if defined(HAVE_WINSOCK_H)
1220
if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
1221
fprintf(stderr, "Vio_connect: Ioctlsocket1 fail INET sock <%s>"
1222
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1226
flags = fcntl( thee->so, F_GETFL, 0 );
1227
fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
1231
/* blocking connect */
1232
len = sizeof(struct sockaddr_in);
1233
rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
1234
if ((!nonblock) && (rc < 0)) {
1235
fprintf(stderr, "Vio_connect: Conn fail INET sock <%s>"
1236
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1240
/* restore blocking -- must nonblock for LINGER to work! */
1242
#if defined(HAVE_WINSOCK_H)
1244
if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
1245
fprintf(stderr, "Vio_connect: Ioctlsocket2 fail INET sock <%s>"
1246
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1250
fcntl( thee->so, F_SETFL, flags );
1255
fprintf(stderr,"Vio_connect: Bad type found <%d>\n", thee->type);
1268
* ***************************************************************************
1269
* Routine: Vio_connectFree
1271
* Purpose: Purge any output buffers (for <UNIX/INET>, else a no-op).
1273
* Author: Michael Holst
1274
* ***************************************************************************
1276
VPUBLIC void Vio_connectFree(Vio *thee)
1278
/* VJMPERR2( !thee->error ); */ /* Need to close the socket... */
1279
VJMPERR2( thee->rwkey == VIO_W );
1281
if ( (thee->type==VIO_SDIO)
1282
|| (thee->type==VIO_FILE)
1283
|| (thee->type==VIO_BUFF) ) {
1285
} else if ( (thee->type==VIO_UNIX)
1286
|| (thee->type==VIO_INET) ) {
1287
Vio_purgePutBuffer(thee);
1289
fprintf(stderr,"Vio_connectFree: Bad type found <%d>\n", thee->type);
1294
Vio_initIoPutBuffers(thee);
1298
Vio_initIoPutBuffers(thee);
1304
* ***************************************************************************
1305
* Routine: Vio_scanf
1307
* Purpose: Mimic "scanf" from an arbitrary Vio device.
1309
* Author: Michael Holst
1310
* ***************************************************************************
1312
VPUBLIC int Vio_scanf(Vio *thee, char *parms, ... )
1315
char arg0, arg1, arg2, *cval, *sval, buf[VMAX_BUFSIZE];
1316
int i, len, tokCount, *ival;
1320
VJMPERR2( !thee->error );
1321
VJMPERR2( thee->rwkey == VIO_R );
1323
/* get the value of the current pointer that points into the ioBuffer */
1325
if (thee->frmt == VIO_ASC) {
1326
len = asc_getpos((ASC*)thee->axdr);
1327
} else if (thee->frmt == VIO_XDR) {
1328
len = xdr_getpos((XDR*)thee->axdr);
1329
} else { VASSERT( 0 ); }
1331
/* if the buffer is completely empty (i.e., first time here) fill it up */
1332
if ( thee->ioBufferLen == 0 ) {
1335
thee->ioBufferLen = Vio_read( thee, thee->ioBuffer, VMAX_BUFSIZE );
1337
/* set the buffer point to 0 */
1338
if (thee->frmt == VIO_ASC) {
1339
VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
1340
} else if (thee->frmt == VIO_XDR) {
1341
VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1342
} else { VASSERT( 0 ); }
1344
/* if current point is more than halfway through buf, read in more data */
1345
} else if ( len > (VMAX_BUFSIZE/2) ) {
1348
VJMPERR1( len <= thee->ioBufferLen );
1350
/* copy unread part of ioBuffer into temp buf and clear ioBuffer */
1351
for (i=len; i<thee->ioBufferLen; i++)
1352
buf[i-len] = thee->ioBuffer[i];
1353
memset(thee->ioBuffer, '\0', sizeof(thee->ioBuffer));
1355
/* read temp buffer back, reseting to the beginning of ioBuffer */
1356
thee->ioBufferLen = thee->ioBufferLen - len;
1357
for (i=0; i<thee->ioBufferLen; i++)
1358
thee->ioBuffer[i] = buf[i];
1360
/* reset the buffer point to 0 */
1361
if (thee->frmt == VIO_ASC) {
1362
VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
1363
} else if (thee->frmt == VIO_XDR) {
1364
VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1365
} else { VASSERT( 0 ); }
1367
/* finally, read in the new data, starting at end of current data */
1368
thee->ioBufferLen += Vio_read(thee,
1369
thee->ioBuffer+thee->ioBufferLen, VMAX_BUFSIZE-thee->ioBufferLen );
1371
/* we (hopefully?) have enough in buffer to work with; do nothing here */
1376
/* we ALWAYS have to pick the format specifier apart <ASC,XDR> ... */
1378
len = strlen(parms);
1379
va_start(ap, parms);
1383
if ( arg0 == ' ' ) {
1385
} else if ( arg0 == '\n' ) {
1387
} else if ( i+1 < len ) {
1389
if ( arg1 == 's' ) {
1390
sval = va_arg(ap, char*);
1391
if ((i == len-3) && ( parms[len-1] == '\n' )) {
1392
if (thee->frmt == VIO_ASC) {
1393
VASSERT( 0 ); /* is this ever executed??? */
1394
} else if (thee->frmt == VIO_XDR) {
1395
VASSERT( 0 ); /* is this ever executed??? */
1396
} else { VASSERT( 0 ); }
1398
if (thee->frmt == VIO_ASC) {
1399
VJMPERR1( asc_string(thee->axdr, &sval, VMAX_BUFSIZE) );
1400
} else if (thee->frmt == VIO_XDR) {
1401
VJMPERR1( xdr_string(thee->axdr, &sval, VMAX_BUFSIZE) );
1402
} else { VASSERT( 0 ); }
1406
} else if ( arg1 == 'c' ) {
1407
cval = va_arg(ap, char*);
1408
if (thee->frmt == VIO_ASC) {
1409
VJMPERR1( asc_char( thee->axdr, cval ) );
1410
} else if (thee->frmt == VIO_XDR) {
1411
VJMPERR1( xdr_char( thee->axdr, cval ) );
1412
} else { VASSERT( 0 ); }
1415
} else if ( arg1 == 'd' ) {
1416
ival = va_arg(ap, int*);
1417
if (thee->frmt == VIO_ASC) {
1418
VJMPERR1( asc_int( thee->axdr, ival ) );
1419
} else if (thee->frmt == VIO_XDR) {
1420
VJMPERR1( xdr_int( thee->axdr, ival ) );
1421
} else { VASSERT( 0 ); }
1424
} else if ( arg1 == 'f' ) {
1425
fval = va_arg(ap, float*);
1426
if (thee->frmt == VIO_ASC) {
1427
VJMPERR1( asc_float( thee->axdr, fval ) );
1428
} else if (thee->frmt == VIO_XDR) {
1429
VJMPERR1( xdr_float( thee->axdr, fval ) );
1430
} else { VASSERT( 0 ); }
1433
} else if ( arg1 == 'e' ) {
1434
fval = va_arg(ap, float*);
1435
if (thee->frmt == VIO_ASC) {
1436
VJMPERR1( asc_float( thee->axdr, fval ) );
1437
} else if (thee->frmt == VIO_XDR) {
1438
VJMPERR1( xdr_float( thee->axdr, fval ) );
1439
} else { VASSERT( 0 ); }
1442
} else if (( arg1 == 'l' ) && ( i+2 < len )) {
1444
if ( arg2 == 'e' ) {
1445
dval = va_arg(ap, double*);
1446
if (thee->frmt == VIO_ASC) {
1447
VJMPERR1( asc_double( thee->axdr, dval ) );
1448
} else if (thee->frmt == VIO_XDR) {
1449
VJMPERR1( xdr_double( thee->axdr, dval ) );
1450
} else { VASSERT( 0 ); }
1453
} else { VJMPERR1( 0 ); }
1454
} else { VJMPERR1( 0 ); }
1455
} else { VJMPERR1( 0 ); }
1459
/* return without error */
1464
fprintf(stderr,"Vio_scanf: Format problem with input.\n");
1471
* ***************************************************************************
1472
* Routine: Vio_printf
1474
* Purpose: Mimic "printf" to an arbitrary Vio device.
1476
* Author: Michael Holst
1477
* ***************************************************************************
1479
VPUBLIC int Vio_printf(Vio *thee, char *parms, ... )
1482
char buf[VMAX_BUFSIZE];
1485
char arg0, arg1, arg2, cval, *sval;
1486
int i, tokCount, ival;
1490
VJMPERR2( !thee->error );
1491
VJMPERR2( thee->rwkey == VIO_W );
1493
/* if ASCII data then use vsprintf to handle format specifier exactly */
1494
if (thee->frmt == VIO_ASC) {
1495
va_start(ap, parms);
1496
vsprintf(buf, parms, ap);
1499
return Vio_writePutBuffer(thee,buf,len);
1502
/* if XDR data then we have to pick the format specifier apart... */
1503
len = strlen(parms);
1504
va_start(ap, parms);
1509
if ((arg0 == '%') && (i+1 < len)) {
1511
if ( arg1 == '%' ) {
1514
while (!strchr("scdfel",arg1)) {
1517
VJMPERR1( i+1 < len );
1519
if ( arg1 == 's' ) {
1520
sval = va_arg(ap, char*);
1521
/* don't put comment strings into xdr files */
1522
if (!strchr(thee->commChars,sval[0])) {
1523
VJMPERR1( xdr_string(thee->axdr, &sval, strlen(sval)) );
1527
} else if ( arg1 == 'c' ) {
1528
/* are char args always passed as int? ... */
1529
cval = (char)va_arg(ap, int); /* CAST FROM INT */
1530
VJMPERR1( xdr_char( thee->axdr, &cval ) );
1533
} else if ( arg1 == 'd' ) {
1534
ival = va_arg(ap, int);
1535
VJMPERR1( xdr_int( thee->axdr, &ival ) );
1538
} else if ( arg1 == 'f' ) {
1539
/* are float args always passed as double? ... */
1540
fval = (float)va_arg(ap, double); /* CAST FROM DOUBLE */
1541
VJMPERR1( xdr_float( thee->axdr, &fval ) );
1544
} else if ( arg1 == 'e' ) {
1545
/* are float args always passed as double? ... */
1546
fval = (float)va_arg(ap, double); /* CAST FROM DOUBLE */
1547
VJMPERR1( xdr_float( thee->axdr, &fval ) );
1550
} else if (( arg1 == 'l' ) && ( i+2 < len )) {
1552
if ( arg2 == 'e' ) {
1553
dval = va_arg(ap, double);
1554
VJMPERR1( xdr_double( thee->axdr, &dval ) );
1557
} else { VJMPERR1( 0 ); }
1558
} else { VJMPERR1( 0 ); }
1566
/* finally write out the XDR buffer */
1567
VJMPERR1( 0<=(len=xdr_getpos((XDR*)thee->axdr)) );
1568
VJMPERR1( Vio_writePutBuffer(thee,thee->ioBuffer,len) == len );
1569
VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
1571
/* return without error */
1576
fprintf(stderr,"Vio_printf: Format problem with output.\n");
1584
* ***************************************************************************
1587
* Purpose: Read (up to) bufsize characters into buf from input device.
1589
* Notes: The number of bytes read is returned.
1591
* It is not necessarily an error if the number of bytes read
1592
* is less than bufsize (EOF may have been encountered).
1594
* Acts exactly like fread() or read().
1596
* Author: Michael Holst
1597
* ***************************************************************************
1599
VPUBLIC int Vio_read(Vio *thee, char *buf, int bufsize)
1603
VJMPERR2( !thee->error );
1604
VJMPERR2( thee->rwkey == VIO_R );
1608
if ( (thee->type==VIO_SDIO)
1609
|| (thee->type==VIO_FILE) ) {
1610
rc = fread(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
1611
/* MIKE: if (rc!=bufsize), make SURE EOF was reached! */
1612
} else if (thee->type==VIO_BUFF) {
1613
ilen = VMIN2( bufsize, thee->VIObufferLen - thee->VIObufferPtr );
1614
for (i=0; i<ilen; i++)
1615
buf[i] = thee->VIObuffer[thee->VIObufferPtr + i];
1616
thee->VIObufferPtr += ilen;
1618
} else if ( (thee->type==VIO_UNIX)
1619
|| (thee->type==VIO_INET) ) {
1620
rc = readn(thee->soc, buf, (unsigned int)bufsize);
1621
/* MIKE: if (rc!=bufsize), make SURE EOF was reached! */
1623
fprintf(stderr,"Vio_read: Bad type found <%d>\n", thee->type);
1629
/* return without error */
1638
* ***************************************************************************
1639
* Routine: Vio_write
1641
* Purpose: Write bufsize characters from buf to output device.
1643
* Notes: The number of bytes written is returned.
1645
* On success, the returned bytecount is the same as the number
1646
* of bytes in the input buffer.
1648
* On failure, the returned bytecount is less than the number
1649
* of bytes in the input buffer.
1651
* Acts exactly like fwrite() or write().
1653
* Author: Michael Holst
1654
* ***************************************************************************
1656
VPUBLIC int Vio_write(Vio *thee, char *buf, int bufsize)
1661
VJMPERR2( !thee->error );
1662
VJMPERR2( thee->rwkey == VIO_W );
1666
if ( (thee->type==VIO_SDIO)
1667
|| (thee->type==VIO_FILE) ) {
1668
rc = fwrite(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
1669
VJMPERR1( rc == bufsize );
1670
} else if (thee->type==VIO_BUFF) {
1671
while ( bufsize > (thee->VIObufferLen - thee->VIObufferPtr) ) {
1672
isize = VMAX2( 1, 2*(thee->VIObufferLen) );
1673
tmpBuf = (char*)calloc( isize, sizeof(char) );
1674
VJMPERR1( tmpBuf != VNULL );
1675
for (i=0; i<thee->VIObufferLen; i++)
1676
tmpBuf[i] = thee->VIObuffer[i];
1677
free( thee->VIObuffer );
1678
thee->VIObuffer = tmpBuf;
1679
thee->VIObufferLen = isize;
1681
for (i=0; i<bufsize; i++)
1682
thee->VIObuffer[thee->VIObufferPtr + i] = buf[i];
1683
thee->VIObufferPtr += bufsize;
1685
VJMPERR1( rc == bufsize );
1686
} else if ( (thee->type==VIO_UNIX)
1687
|| (thee->type==VIO_INET) ) {
1688
rc = writen(thee->so, buf, (unsigned int)bufsize);
1689
VJMPERR1( rc == bufsize );
1691
fprintf(stderr,"Vio_write: Bad type found <%d>\n", thee->type);
1697
/* return without error */
1701
fprintf(stderr,"Vio_write: Error occurred (bailing out).\n");
1708
* ***************************************************************************
1709
* Routine: Vio_initIoPutBuffers
1711
* Purpose: Initialize the internal buffer.
1713
* Author: Michael Holst
1714
* ***************************************************************************
1716
VPRIVATE void Vio_initIoPutBuffers(Vio *thee)
1718
/* initialize the buffer space */
1719
memset(thee->ioBuffer, '\0', sizeof(thee->ioBuffer));
1720
memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1721
thee->ioBufferLen = 0;
1722
thee->putBufferLen = 0;
1726
* ***************************************************************************
1727
* Routine: Vio_purgePutBuffer
1729
* Purpose: Purge the internal buffer.
1731
* Author: Michael Holst
1732
* ***************************************************************************
1734
VPRIVATE void Vio_purgePutBuffer(Vio *thee)
1738
VJMPERR2( !thee->error );
1739
VJMPERR2( thee->rwkey == VIO_W );
1741
len = thee->putBufferLen;
1742
if ( (thee->type==VIO_UNIX)
1743
|| (thee->type==VIO_INET) ) {
1744
if ( Vio_write(thee,thee->putBuffer,len) != len ) {
1746
"Vio_purgePutBuffer: Vio_write fail UNIX/INET sock <%s>"
1747
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1750
memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1752
fprintf(stderr,"Vio_purgePutBuffer: Bad type found <%d>\n",thee->type);
1756
/* return without error */
1765
* ***************************************************************************
1766
* Routine: Vio_writePutBuffer
1768
* Purpose: Write bufsize characters from buf to output device.
1770
* Notes: The number of bytes written is returned.
1772
* On success, the returned bytecount is the same as the number
1773
* of bytes in the input buffer.
1775
* On failure, the returned bytecount is less than the number
1776
* of bytes in the input buffer.
1778
* Acts exactly like fwrite() or write().
1780
* Comment: This is simply a buffered version of Vio_write().
1781
* The Vio object maintains the buffer safely internally.
1783
* Author: Michael Holst
1784
* ***************************************************************************
1786
VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize)
1790
VJMPERR2( !thee->error );
1791
VJMPERR2( thee->rwkey == VIO_W );
1793
/* attempt to buffer the i/o to get some speed */
1794
if ( (thee->type==VIO_SDIO)
1795
|| (thee->type==VIO_FILE)
1796
|| (thee->type==VIO_BUFF) ) {
1798
if ( Vio_write(thee,buf,bufsize) != bufsize ) {
1800
"Vio_writePutBuffer: Vio_write(1) fail FILE sock <%s>"
1801
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1805
} else if ( (thee->type==VIO_UNIX)
1806
|| (thee->type==VIO_INET) ) {
1808
/* incoming data is larger than our buffer */
1809
if (bufsize > (int)sizeof(thee->putBuffer)) {
1811
/* just do a normal unbuffered socket write */
1812
if ( Vio_write(thee,buf,bufsize) != bufsize ) {
1813
fprintf(stderr, "Vio_writePutBuffer: Vio_write(2) fail"
1814
" UNIX/INET sock <%s>"
1815
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1819
/* incoming data will fit in our buffer */
1822
curLen = thee->putBufferLen;
1824
/* it fits in now -- just cat it to the end of the buffer */
1825
if ( (curLen + bufsize) <= (int)sizeof(thee->putBuffer) ) {
1826
for (i=0; i<bufsize; i++)
1827
thee->putBuffer[curLen+i] = buf[i];
1828
thee->putBufferLen += bufsize;
1830
/* it won't fit until we write out the existing buffer */
1832
if ( Vio_write(thee,thee->putBuffer,curLen) != curLen ) {
1833
fprintf(stderr, "Vio_writePutBuffer: Vio_write(3)"
1834
" fail UNIX/INET sock <%s>"
1835
" dueto <%s>\n", thee->file, VIOstrerrno(errno));
1838
thee->putBufferLen = 0;
1839
memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
1840
for (i=0; i<bufsize; i++)
1841
thee->putBuffer[i] = buf[i];
1842
thee->putBufferLen += bufsize;
1847
fprintf(stderr,"Vio_writePutBuffer: Bad type found <%d>\n",thee->type);
1851
/* return without error */
1860
* ***************************************************************************
1861
* Routine: ascmem_create, asc_destroy, asc_getpos, asc_setpos
1862
* asc_string, asc_char, asc_int, asc_float, asc_double
1863
* asc_setWhiteChars, asc_setCommChars, asc_getToken
1865
* Purpose: An ASC (i.e. ASCII) dual to the XDR routines.
1867
* Notes: These routines basically function idential to the XDR routines,
1868
* except that after calling the constructor <ascmem_create>, one
1869
* must call two additional routines, <asc_setWhiteChars> and
1870
* <asc_setCommChars>, to specify the strings representing the
1871
* whitespace in the ASCII stream separating the tokens, and a set
1872
* of possible comment characters which generate skips to a newline.
1874
* The only complicated routine is <asc_genToken>, on which
1875
* most of the other things rest.
1877
* Both ASC_ENCODE (write) and ASC_DECODE (read) directions work.
1878
* In ASC_ENCODE mode, the tokens are separated by a single newline
1879
* (for lack of anything more intelligent to do...).
1881
* Author: Michael Holst
1882
* ***************************************************************************
1886
* ***************************************************************************
1887
* Routine: ascmem_create
1889
* Purpose: Create the ASC structure.
1891
* Author: Michael Holst
1892
* ***************************************************************************
1894
VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode)
1900
memset(thee->whiteChars, '\0', VMAX_ARGNUM);
1901
memset(thee->commChars, '\0', VMAX_ARGNUM);
1905
* ***************************************************************************
1906
* Routine: asc_destroy
1908
* Purpose: Destroy the ASC structure.
1910
* Author: Michael Holst
1911
* ***************************************************************************
1913
VPRIVATE void asc_destroy(ASC *thee)
1915
thee->mode = ASC_NO_MODE;
1919
memset(thee->whiteChars, '\0', VMAX_ARGNUM);
1920
memset(thee->commChars, '\0', VMAX_ARGNUM);
1924
* ***************************************************************************
1925
* Routine: asc_getpos
1927
* Purpose: Return the current position in the ASC stream.
1929
* Author: Michael Holst
1930
* ***************************************************************************
1932
VPRIVATE int asc_getpos(ASC *thee)
1938
* ***************************************************************************
1939
* Routine: asc_setpos
1941
* Purpose: Set the current position in the ASC stream.
1943
* Author: Michael Holst
1944
* ***************************************************************************
1946
VPRIVATE int asc_setpos(ASC *thee, int pos)
1953
* ***************************************************************************
1954
* Routine: asc_string
1956
* Purpose: DECODE or ENCODE a string.
1958
* Author: Michael Holst
1959
* ***************************************************************************
1961
VPRIVATE int asc_string(ASC *thee, char **sval, int size)
1964
char tok[VMAX_BUFSIZE];
1966
if (thee->mode == ASC_DECODE) {
1967
VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
1968
sscanf(tok,"%s",(*sval));
1969
} else if (thee->mode == ASC_ENCODE) {
1970
sprintf(tok,"%s\n",*sval);
1972
for (i=0; i<len; i++)
1973
thee->buf[thee->pos+i] = tok[i];
1983
* ***************************************************************************
1986
* Purpose: DECODE or ENCODE a char.
1988
* Author: Michael Holst
1989
* ***************************************************************************
1991
VPRIVATE int asc_char(ASC *thee, char *cval)
1994
char tok[VMAX_BUFSIZE];
1996
if (thee->mode == ASC_DECODE) {
1997
VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
1998
sscanf(tok,"%c",cval);
1999
} else if (thee->mode == ASC_ENCODE) {
2000
sprintf(tok,"%c\n",*cval);
2002
for (i=0; i<len; i++)
2003
thee->buf[thee->pos+i] = tok[i];
2013
* ***************************************************************************
2016
* Purpose: DECODE or ENCODE an int.
2018
* Author: Michael Holst
2019
* ***************************************************************************
2021
VPRIVATE int asc_int(ASC *thee, int *ival)
2024
char tok[VMAX_BUFSIZE];
2026
if (thee->mode == ASC_DECODE) {
2027
VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2028
sscanf(tok,"%d",ival);
2029
} else if (thee->mode == ASC_ENCODE) {
2030
sprintf(tok,"%d\n",*ival);
2032
for (i=0; i<len; i++)
2033
thee->buf[thee->pos+i] = tok[i];
2043
* ***************************************************************************
2044
* Routine: asc_float
2046
* Purpose: DECODE or ENCODE a float.
2048
* Author: Michael Holst
2049
* ***************************************************************************
2051
VPRIVATE int asc_float(ASC *thee, float *fval)
2054
char tok[VMAX_BUFSIZE];
2056
if (thee->mode == ASC_DECODE) {
2057
VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2058
sscanf(tok,"%e",fval);
2059
} else if (thee->mode == ASC_ENCODE) {
2060
sprintf(tok,"%e\n",*fval);
2062
for (i=0; i<len; i++)
2063
thee->buf[thee->pos+i] = tok[i];
2073
* ***************************************************************************
2074
* Routine: asc_double
2076
* Purpose: DECODE or ENCODE a double.
2078
* Author: Michael Holst
2079
* ***************************************************************************
2081
VPRIVATE int asc_double(ASC *thee, double *dval)
2084
char tok[VMAX_BUFSIZE];
2086
if (thee->mode == ASC_DECODE) {
2087
VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
2088
sscanf(tok,"%le",dval);
2089
} else if (thee->mode == ASC_ENCODE) {
2090
sprintf(tok,"%e\n",*dval);
2092
for (i=0; i<len; i++)
2093
thee->buf[thee->pos+i] = tok[i];
2103
* ***************************************************************************
2104
* Routine: asc_setWhiteChars
2106
* Purpose: Define the white character set.
2108
* Author: Michael Holst
2109
* ***************************************************************************
2111
VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars)
2113
strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
2117
* ***************************************************************************
2118
* Routine: asc_setCommChars
2120
* Purpose: Define the comment character set.
2122
* Author: Michael Holst
2123
* ***************************************************************************
2125
VPRIVATE void asc_setCommChars(ASC *thee, char *commChars)
2127
strncpy(thee->commChars, commChars, VMAX_ARGNUM);
2131
* ***************************************************************************
2132
* Routine: asc_getToken
2134
* Purpose: Get the next token from the input stream.
2136
* Author: Michael Holst
2137
* ***************************************************************************
2139
VPRIVATE char* asc_getToken(ASC *thee, char *tok, int toksize)
2141
int i, ii, jj, done;
2142
if (thee->mode == ASC_DECODE) {
2144
/* first clear the token buffer */
2145
memset(tok, '\0', toksize);
2147
/* set "ii" ptr to the first token character */
2152
/* if whiteChar then just skip that character */
2153
if ( strchr(thee->whiteChars,thee->buf[ii]) ) {
2155
VJMPERR1( ii < thee->size );
2157
/* if commChar then skip to the next newline and keep going */
2158
} else if ( strchr(thee->commChars,thee->buf[ii]) ) {
2160
VJMPERR1( ii < thee->size );
2161
while ( thee->buf[ii] != '\n' ) {
2163
VJMPERR1( ii < thee->size );
2166
/* this must be the first token character */
2172
/* set "jj" ptr to the first character (white or comm) after token */
2176
VJMPERR1( jj < thee->size );
2178
/* if whiteChar then we are done */
2179
if ( strchr(thee->whiteChars,thee->buf[jj]) ) {
2182
/* if commChar then we are done */
2183
} else if ( strchr(thee->commChars,thee->buf[jj]) ) {
2186
/* this must be another token character */
2193
VJMPERR1( (jj-ii) <= toksize );
2194
VJMPERR1( jj <= thee->size );
2196
/* copy the characters between ii and jj to the output string */
2197
for (i=ii; i<jj; i++)
2198
tok[i-ii] = thee->buf[i];
2201
/* update the position pointer */
2204
} else if (thee->mode == ASC_ENCODE) {
2205
fprintf(stderr,"asc_getToken: Don't know how to ENCODE yet!\n");
2211
fprintf(stderr,"asc_getToken: Error occurred (bailing out).\n");
2216
* ***************************************************************************
2219
* Purpose: A fixed-up file-descriptor read (for UNIX/INET).
2221
* Notes: Fixes the "short read" problem if the operating system
2222
* is interrupted during the read. Calls the usual
2223
* file-descriptor read repeatedly until n characters are
2224
* actually read in. Returns the number of characters
2225
* actually read in. Returns -1 on error.
2227
* Includes my WINSOCK fixes (err, rather hacks).
2229
* Author: Michael Holst (first of two jewels from Rick Stevens' book)
2230
* ***************************************************************************
2232
VPRIVATE int readn(int fd, void *vptr, unsigned int n)
2241
if ((nread = recv(fd,ptr,nleft,0)) < 0) {
2242
#if defined(HAVE_WINSOCK_H)
2243
if (WSAGetLastError() == WSAEINTR) {
2245
} else if (WSAGetLastError() == WSAEWOULDBLOCK) {
2247
} else { return(-1); }
2249
if (errno == EINTR) {
2251
} else if (errno == EWOULDBLOCK) {
2253
} else { return(-1); }
2255
} else if (nread == 0) {
2265
* ***************************************************************************
2268
* Purpose: A fixed-up file-descriptor write (for UNIX/INET).
2270
* Notes: Fixes the "short write" problem if the operating system
2271
* has buffer overflow problems. Calls the usual
2272
* file-descriptor write repeatedly until the input buffer
2273
* actually gets written out. Returns the number of
2274
* characters actually written out. Returns -1 on error.
2276
* Author: Michael Holst (second of two jewels from Rick Stevens' book)
2277
* ***************************************************************************
2279
VPRIVATE int writen(int fd, void *vptr, unsigned int n)
2288
if ((nwritten = send(fd,ptr,nleft,0)) <= 0) {
2289
if (errno == EINTR) {
2302
* ***************************************************************************
2303
* Routine: Vio_bufTake
2305
* Purpose: Set the pointer to the internal buffer.
2307
* Author: Michael Holst
2308
* ***************************************************************************
2310
VPUBLIC void Vio_bufTake(Vio *thee, char *buf, int bufsize)
2312
/* make sure Vio was started */
2313
VJMPERR1( VIOstarted );
2315
/* clear the internal buffer */
2316
if (thee->VIObuffer != VNULL) {
2317
free( thee->VIObuffer );
2318
thee->VIObuffer = VNULL;
2321
/* now set the buffer */
2322
thee->VIObuffer = buf;
2323
thee->VIObufferLen = bufsize;
2324
thee->VIObufferPtr = 0;
2326
/* return without error */
2330
fprintf(stderr,"Vio_bufTake: Vio library has not been started.\n");
2335
* ***************************************************************************
2336
* Routine: Vio_bufGive
2338
* Purpose: Return the pointer to the internal buffer.
2340
* Author: Michael Holst
2341
* ***************************************************************************
2343
VPUBLIC char* Vio_bufGive(Vio *thee)
2347
/* make sure Vio was started */
2348
VJMPERR1( VIOstarted );
2350
/* grab the pointer */
2351
tmp = thee->VIObuffer;
2353
/* reset things for the hand-off */
2354
thee->VIObufferLen = 0;
2355
thee->VIObuffer = VNULL;
2357
/* return without error */
2361
fprintf(stderr,"Vio_bufGive: Vio library has not been started.\n");
2366
* ***************************************************************************
2367
* Routine: Vio_bufSize
2369
* Purpose: Return the length of the internal buffer.
2371
* Author: Michael Holst
2372
* ***************************************************************************
2374
VPUBLIC int Vio_bufSize(Vio *thee)
2376
/* make sure Vio was started */
2377
VJMPERR1( VIOstarted );
2379
/* return without error */
2380
return thee->VIObufferLen;
2383
fprintf(stderr,"Vio_bufSize: Vio library has not been started.\n");
2388
* ***************************************************************************
2389
* Routine: Vio_socketOpen
2391
* Purpose: Socket open for read or write.
2393
* Author: Michael Holst
2394
* ***************************************************************************
2396
VPUBLIC Vio *Vio_socketOpen(char *key,
2397
const char *iodev, const char *iofmt,
2398
const char *iohost, const char *iofile)
2402
/* make sure Vio was started */
2403
VJMPERR1( VIOstarted );
2405
/* setup for a read */
2406
if (!strcmp("r",key)) {
2408
/* Open device for READ */
2409
if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"r")) ) {
2410
fprintf(stderr,"Vio_socketOpen: Problem opening(read) <%s>\n",
2415
/* START READ (blocking accept) */
2416
if ( 0 > Vio_accept(sock,0) ) {
2417
fprintf(stderr,"Vio_socketOpen: Problem accepting(read) <%s>\n",
2419
/* destroy the socket before we return */
2424
/* setup for a write */
2425
} else if (!strcmp("w",key)) {
2427
/* Open device for WRITE */
2428
if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"w")) ) {
2429
fprintf(stderr,"Vio_socketOpen: Problem opening(write) <%s>\n",
2434
/* START WRITE (blocking connect) */
2435
if ( 0 > Vio_connect(sock,0) ) {
2436
fprintf(stderr,"Vio_socketOpen: Problem connecting(write) <%s>\n",
2438
/* destroy the socket before we return */
2444
fprintf(stderr,"Vio_socketOpen: Internal logic error.\n");
2450
fprintf(stderr,"Vio_socketOpen: iodev =<%s>\n", iodev);
2451
fprintf(stderr,"Vio_socketOpen: iofmt =<%s>\n", iofmt);
2452
fprintf(stderr,"Vio_socketOpen: iohost=<%s>\n", iohost);
2453
fprintf(stderr,"Vio_socketOpen: iofile=<%s>\n", iofile);
2456
/* return without error */
2460
fprintf(stderr,"Vio_socketOpen: Vio library has not been started.\n");
2464
fprintf(stderr,"Vio_socketOpen: bailing out.\n");
2469
* ***************************************************************************
2470
* Routine: Vio_socketClose
2472
* Purpose: Socket close from read or write.
2474
* Author: Michael Holst
2475
* ***************************************************************************
2477
VPUBLIC void Vio_socketClose(Vio **sock)
2479
/* make sure Vio was started */
2480
VJMPERR1( VIOstarted );
2482
VJMPERR2( VNULL != *sock );
2484
/* FINISH READ (release subsocket if we had one) */
2485
if ((*sock)->rwkey == VIO_R) {
2486
Vio_acceptFree(*sock);
2489
} else if ((*sock)->rwkey == VIO_W) {
2490
Vio_connectFree(*sock);
2497
/* return without error */
2502
fprintf(stderr,"Vio_socketClose: Vio library has not been started.\n");
2506
fprintf(stderr,"Vio_socketClose: bailing out.\n");