• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/maloc/src/vsys/vio.c

00001 /*
00002  * ***************************************************************************
00003  * MALOC = < Minimal Abstraction Layer for Object-oriented C >
00004  * Copyright (C) 1994--2008 Michael Holst
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00019  *
00020  * rcsid="$Id: vio.c,v 1.31 2008/03/12 05:13:59 fetk Exp $"
00021  * ***************************************************************************
00022  */
00023 
00024 /*
00025  * ***************************************************************************
00026  * File:     vio.c
00027  *
00028  * Purpose:  Class Vio: methods.
00029  *
00030  * Author:   Michael Holst
00031  * ***************************************************************************
00032  */
00033 
00034 #include "vio_p.h"
00035 
00036 VEMBED(rcsid="$Id: vio.c,v 1.31 2008/03/12 05:13:59 fetk Exp $")
00037 
00038 #if defined(HAVE_UNISTD_H)
00039 #   include <unistd.h>
00040 #endif
00041 
00042 #if defined(HAVE_SYS_TYPES_H)
00043 #   include <sys/types.h> 
00044 #endif
00045 
00046 #if defined(HAVE_SYS_STAT_H)
00047 #   include <sys/stat.h> 
00048 #endif
00049 
00050 #if defined(HAVE_FCNTL_H)
00051 #   include <fcntl.h>
00052 #endif
00053 
00054 #if defined(HAVE_SYS_SOCKET_H)
00055 #   include <sys/socket.h>
00056 #endif
00057 
00058 #if defined(HAVE_SYS_UN_H)
00059 #   include <sys/un.h>
00060 #endif
00061 
00062 #if defined(HAVE_NETINET_IN_H)
00063 #   include <netinet/in.h> 
00064 #endif
00065 
00066 #if defined(HAVE_ARPA_INET_H)
00067 #   include <arpa/inet.h> 
00068 #endif
00069 
00070 #if defined(HAVE_NETDB_H)
00071 #   include <netdb.h> 
00072 #endif
00073 
00074 #if defined(HAVE_RPC_RPC_H)
00075 #   include <rpc/rpc.h> 
00076 #elif defined(HAVE_RPC_H)
00077 #   include <rpc.h> 
00078 #endif
00079 
00080 #if defined(HAVE_WINSOCK_H)
00081 #   include <winsock.h>
00082 #endif
00083 
00084 #if defined(HAVE_IO_H)
00085 #   include <io.h>
00086 #endif
00087 
00088 /* ASC modes as dual to the XDR modes */
00089 typedef enum ASCmode {
00090     ASC_NO_MODE,
00091     ASC_DECODE,
00092     ASC_ENCODE
00093 } ASCmode;
00094 
00095 /* ASC structure as dual to the XDR structure */
00096 typedef struct ASC {
00097     ASCmode mode;                    /* ASC_DECODE or ASC_ENCODE            */
00098     int     pos;                     /* position of next character in buf   */
00099     int     size;                    /* size of buf                         */
00100     char    *buf;                    /* the character buffer                */
00101     char    whiteChars[VMAX_ARGNUM]; /* white space character set           */
00102     char    commChars[VMAX_ARGNUM];  /* comment character set               */
00103 } ASC;
00104 
00105 /* use ASC in place of XDR if XDR does not exist */
00106 #if !defined(HAVE_XDR)
00107 #   define XDR           ASC
00108 #   define XDR_DECODE    ASC_DECODE
00109 #   define XDR_ENCODE    ASC_ENCODE
00110 #   define xdrmem_create ascmem_create
00111 #   define xdr_destroy   asc_destroy
00112 #   define xdr_getpos    asc_getpos
00113 #   define xdr_setpos    asc_setpos
00114 #   define xdr_string    asc_string
00115 #   define xdr_char      asc_char
00116 #   define xdr_int       asc_int
00117 #   define xdr_float     asc_float
00118 #   define xdr_double    asc_double
00119 #endif
00120 
00121 /* communication startup */
00122 VPRIVATE int VIOstarted = 0;
00123 
00124 /* default comment char set and white space char set */
00125 VPRIVATE char *VIOwhiteChars = " \t\n";
00126 VPRIVATE char *VIOcommChars  = "";
00127 
00128 /* initialization, signals, and other tools */
00129 VPRIVATE void VIOregHand(void);
00130 VPRIVATE void VIOunregHand(void);
00131 VPRIVATE void VIOsigHand(int num);
00132 VPRIVATE int VIOgethostname(char *name, unsigned int len);
00133 VPRIVATE const char *VIOstrerrno(int err);
00134 
00135 /* buffer management */
00136 VPRIVATE void Vio_initIoPutBuffers(Vio *thee);
00137 VPRIVATE void Vio_purgePutBuffer(Vio *thee);
00138 VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize);
00139 
00140 /* ASC analogs to the core XDR routines */
00141 VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode);
00142 VPRIVATE void asc_destroy(ASC *thee);
00143 VPRIVATE int asc_getpos(ASC *thee);
00144 VPRIVATE int asc_setpos(ASC *thee, int pos);
00145 VPRIVATE int asc_string(ASC *thee, char **sval, int size);
00146 VPRIVATE int asc_char(ASC *thee, char *cval);
00147 VPRIVATE int asc_int(ASC *thee, int *ival);
00148 VPRIVATE int asc_float(ASC *thee, float *fval);
00149 VPRIVATE int asc_double(ASC *thee, double *dval);
00150 
00151 /* some additional ASC routines (no analogs in XDR) */
00152 VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars);
00153 VPRIVATE void asc_setCommChars(ASC *thee, char *commChars);
00154 VPRIVATE char *asc_getToken(ASC *thee, char *tok, int toksize);
00155 
00156 /* two low-level file-descriptor i/o jewels from Rick Steven's book */
00157 VPRIVATE int readn(int fd, void *vptr, unsigned int n);
00158 VPRIVATE int writen(int fd, void *vptr, unsigned int n) ;
00159 
00160 /*
00161  * ***************************************************************************
00162  * Class Vio: Inlineable methods
00163  * ***************************************************************************
00164  */
00165 #if !defined(VINLINE_MALOC)
00166 
00167 #endif /* if !defined(VINLINE_MALOC) */
00168 /*
00169  * ***************************************************************************
00170  * Class Vio: Non-inlineable methods
00171  * ***************************************************************************
00172  */
00173 
00174 /*
00175  * ***************************************************************************
00176  * Routine:  Vio_start
00177  *
00178  * Purpose:  Startup the Vio communication layer.
00179  *
00180  * Notes:    This routine initializes some internal variables and buffers.
00181  *           This routine also deals with the interception of fatal
00182  *           SIGPIPE signals which are generated on some systems when a
00183  *           socket connection is broken by one of the send/receive pair.
00184  *
00185  *           We don't want to abort in this situation, but rather do some
00186  *           damage control.  Hence we register our own SIGPIPE interrupt
00187  *           handler in Vio_start(), and re-register it every time a SIGPIPE
00188  *           is intercepted.  We re-register it because some systems reset
00189  *           the interrupt mask after a single interrupt is generated.
00190  *           We un-register the SIGPIPE handler in Vio_stop().
00191  *
00192  *           To use the Vio library, you need to call Vio_start() before
00193  *           you make any calls to the Vio_ctor().  Calling the Vio_ctor() 
00194  *           (or any other Vio method) before Vio_start() generates an error.
00195  *           For example, you can call this routine as follows:
00196  *
00197  *               Vio_start()
00198  *
00199  * Author:   Michael Holst
00200  * ***************************************************************************
00201  */
00202 VPUBLIC void Vio_start(void)
00203 {
00204     /* repeated initializations ARE legal (no error; possibly frees memory) */
00205     /* VASSERT( !VIOstarted ); */
00206 
00207     /* mark as initialized */
00208     VIOstarted = 1;
00209 
00210     /* register the SIGPIPE handler to avoid aborts on a SIGPIPE */
00211     VIOregHand();
00212 
00213     /* normal return */
00214     return;
00215 }
00216 
00217 /*
00218  * ***************************************************************************
00219  * Routine:  Vio_stop
00220  *
00221  * Purpose:  Shutdown the Vio communication layer.
00222  *
00223  * Notes:    This routine was written primarily to deal with some
00224  *           communication runtime environments which require a shutdown.
00225  *
00226  * Author:   Michael Holst
00227  * ***************************************************************************
00228  */
00229 VPUBLIC void Vio_stop(void)
00230 {
00231     /* repeated de-initializations ARE legal (no error; just a no-op) */
00232     /* VASSERT( VIOstarted ); */
00233 
00234     /* un-initialize us */
00235     VIOstarted = 0;
00236 
00237     /* un-register the SIGPIPE handler */
00238     VIOunregHand();
00239 
00240     /* normal return */
00241     return;
00242 }
00243 
00244 /*
00245  * ***************************************************************************
00246  * Routine:  VIOregHand
00247  *
00248  * Purpose:  Register the signal handler with the operating system.
00249  *
00250  * Author:   Michael Holst
00251  * ***************************************************************************
00252  */
00253 VPRIVATE void VIOregHand(void)
00254 {
00255 #if !defined(HAVE_WINSOCK_H)
00256     VASSERT( signal(SIGPIPE,&VIOsigHand) != SIG_ERR );
00257 #endif
00258 }
00259 
00260 /*
00261  * ***************************************************************************
00262  * Routine:  VIOunregHand
00263  *
00264  * Purpose:  Un-Register the signal handler with the operating system.
00265  *
00266  * Author:   Michael Holst
00267  * ***************************************************************************
00268  */
00269 VPRIVATE void VIOunregHand(void)
00270 {
00271 #if !defined(HAVE_WINSOCK_H)
00272     VASSERT( signal(SIGPIPE,SIG_DFL) != SIG_ERR );
00273 #endif
00274 }
00275 
00276 /*
00277  * ***************************************************************************
00278  * Routine:  VIOsigHand
00279  *
00280  * Purpose:  Handle events such as SIGPIPE.
00281  *
00282  * Author:   Michael Holst
00283  * ***************************************************************************
00284  */
00285 VPRIVATE void VIOsigHand(int num)
00286 {
00287     /* some i/o */
00288     fprintf(stderr,"VIOsigHand: yow! caught a hot SIGPIPE....diffused it.\n");
00289 
00290     /* just re-register interrupt handler in case it was cleared by default */
00291     VIOregHand();
00292 }
00293 
00294 /*
00295  * ***************************************************************************
00296  * Routine:  VIOgethostname
00297  *
00298  * Purpose:  Get the hostname of this machine.
00299  *           Returns 0 on success.  Returns -1 on error.
00300  *
00301  * Author:   Michael Holst
00302  * ***************************************************************************
00303  */
00304 VPRIVATE int VIOgethostname(char *name, unsigned int len)
00305 {
00306 #if defined(HAVE_WINSOCK_H)
00307     return gethostname(name,(int)len);
00308 #else
00309     return gethostname(name,len);
00310 #endif
00311 }
00312 
00313 /*
00314  * ***************************************************************************
00315  * Routine:  VIOstrerrno
00316  *
00317  * Purpose:  Return the error string corresponding to the error number.
00318  *
00319  * Notes:    This is a partial implementation of the "iberty" library
00320  *           function "strerrno" that exists on most Linux boxes.  It is
00321  *           simply a mapping of error number to error string.  It is
00322  *           very useful for debugging UNIX and INET socket code.
00323  *
00324  * Author:   Michael Holst
00325  * ***************************************************************************
00326  */
00327 VPRIVATE const char *VIOstrerrno(int err)
00328 {
00329     static char errstr[VMAX_ARGLEN];
00330 
00331     if      (err == EFAULT           ) strcpy(errstr,"EFAULT");
00332     else if (err == EINTR            ) strcpy(errstr,"EINTR");
00333     else if (err == EINVAL           ) strcpy(errstr,"EINVAL");
00334     else if (err == ENOENT           ) strcpy(errstr,"ENOENT");
00335     else if (err == EPIPE            ) strcpy(errstr,"EPIPE");
00336     else if (err == ENOMEM           ) strcpy(errstr,"ENOMEM");
00337     else if (err == EAGAIN           ) strcpy(errstr,"EAGAIN");
00338     else if (err == EBADF            ) strcpy(errstr,"EBADF");
00339 
00340 #if defined(HAVE_WINSOCK_H)
00341     else if (err == WSAENETDOWN      ) strcpy(errstr,"WSAENETDOWN");
00342     else if (err == WSAEFAULT        ) strcpy(errstr,"WSAEFAULT");
00343     else if (err == WSAENOTCONN      ) strcpy(errstr,"WSAENOTCONN");
00344     else if (err == WSAEINTR         ) strcpy(errstr,"WSAEINTR");
00345     else if (err == WSAEINPROGRESS   ) strcpy(errstr,"WSAEINPROGRESS");
00346     else if (err == WSAENETRESET     ) strcpy(errstr,"WSAENETRESET");
00347     else if (err == WSAENOTSOCK      ) strcpy(errstr,"WSAENOTSOCK");
00348     else if (err == WSAEOPNOTSUPP    ) strcpy(errstr,"WSAEOPNOTSUPP");
00349     else if (err == WSAESHUTDOWN     ) strcpy(errstr,"WSAESHUTDOWN");
00350     else if (err == WSAEWOULDBLOCK   ) strcpy(errstr,"WSAEWOULDBLOCK");
00351     else if (err == WSAEMSGSIZE      ) strcpy(errstr,"WSAEMSGSIZE");
00352     else if (err == WSAEINVAL        ) strcpy(errstr,"WSAEINVAL");
00353     else if (err == WSAETIMEDOUT     ) strcpy(errstr,"WSAETIMEDOUT");
00354     else if (err == WSAECONNABORTED  ) strcpy(errstr,"WSAECONNABORTED");
00355     else if (err == WSAECONNREFUSED  ) strcpy(errstr,"WSAECONNREFUSED");
00356     else if (err == WSAECONNRESET    ) strcpy(errstr,"WSAECONNRESET");
00357     else if (err == WSANOTINITIALISED) strcpy(errstr,"WSANOTINITIALISED");
00358 #else
00359     else if (err == ENETDOWN         ) strcpy(errstr,"ENETDOWN");
00360     else if (err == ENOTCONN         ) strcpy(errstr,"ENOTCONN");
00361     else if (err == EINPROGRESS      ) strcpy(errstr,"EINPROGRESS");
00362     else if (err == ENETRESET        ) strcpy(errstr,"ENETRESET");
00363     else if (err == ENOTSOCK         ) strcpy(errstr,"ENOTSOCK");
00364     else if (err == EOPNOTSUPP       ) strcpy(errstr,"EOPNOTSUPP");
00365     else if (err == ESHUTDOWN        ) strcpy(errstr,"ESHUTDOWN");
00366     else if (err == EWOULDBLOCK      ) strcpy(errstr,"EWOULDBLOCK");
00367     else if (err == EMSGSIZE         ) strcpy(errstr,"EMSGSIZE");
00368     else if (err == ETIMEDOUT        ) strcpy(errstr,"ETIMEDOUT");
00369     else if (err == ECONNABORTED     ) strcpy(errstr,"ECONNABORTED");
00370     else if (err == ECONNREFUSED     ) strcpy(errstr,"ECONNREFUSED");
00371     else if (err == ECONNRESET       ) strcpy(errstr,"ECONNRESET");
00372     else if (err == ENOBUFS          ) strcpy(errstr,"ENOBUFS");
00373 #endif
00374 
00375     else sprintf(errstr,"VIO_UNKNOWN_ERROR(%d)",err);
00376     return errstr; 
00377 }
00378 
00379 /*
00380  * ***************************************************************************
00381  * Routine:  Vio_ctor
00382  *
00383  * Purpose:  Construct the [sdio/file/buff/unix/inet] container object.
00384  *
00385  * Author:   Michael Holst
00386  * ***************************************************************************
00387  */
00388 VPUBLIC Vio* Vio_ctor(const char *socktype, const char *datafrmt, 
00389     const char *hostname, const char *filename, const char *rwkey)
00390 {
00391     Vio *thee = VNULL;
00392 
00393     /* make sure Vio was started */
00394     VJMPERR1( VIOstarted );
00395 
00396     thee = (Vio*)calloc( 1, sizeof(Vio) );
00397     VJMPERR2( thee != VNULL );
00398     VJMPERR3( Vio_ctor2(thee, socktype, datafrmt, hostname, filename, rwkey) );
00399 
00400     /* normal return */
00401     return thee;
00402 
00403   VERROR1:
00404     fprintf(stderr,"Vio_ctor: Vio library has not been started.\n");
00405     return VNULL;
00406 
00407   VERROR2:
00408     fprintf(stderr,"Vio_ctor: malloc of Vio structure failed.\n");
00409     return VNULL;
00410 
00411   VERROR3:
00412     fprintf(stderr,"Vio_ctor: Vio_ctor2() failed.\n");
00413     Vio_dtor(&thee);
00414     return VNULL;
00415 }
00416 
00417 /*
00418  * ***************************************************************************
00419  * Routine:  Vio_ctor2
00420  *
00421  * Purpose:  Construct the [sdio/file/buff/unix/inet] container object.
00422  *
00423  * Author:   Michael Holst
00424  * ***************************************************************************
00425  */
00426 VPUBLIC int Vio_ctor2(Vio *thee, const char *socktype, const char *datafrmt, 
00427     const char *hostname, const char *filename, const char *rwkey)
00428 {
00429     int n, ival;
00430     char host[VMAX_ARGLEN];
00431     struct linger ling;
00432     unsigned int len;
00433     struct hostent *hpTmp;
00434 #if defined(HAVE_WINSOCK_H)
00435     WSADATA wsaData;
00436 #endif
00437 #if defined(HAVE_SYS_UN_H)
00438     char username[VMAX_ARGLEN];
00439 #endif
00440 
00441     /* make sure Vio was started */
00442     VJMPERR1( VIOstarted );
00443 
00444     /* initialize all Vio fields */
00445     thee->type     = VIO_NO_TYPE;
00446     thee->frmt     = VIO_NO_FRMT;
00447     thee->rwkey    = VIO_NO_RW;
00448     thee->error    = 0;
00449     thee->dirty    = 0;
00450     thee->fp       = VNULL;
00451     thee->axdr     = VNULL;
00452     thee->so       = -1;
00453     thee->soc      = -1;
00454     thee->name     = VNULL;
00455 
00456     /* initialize the internal buffer (for BUFF datatype) */
00457     thee->VIObuffer = VNULL;
00458     thee->VIObufferLen = 0;
00459     thee->VIObufferPtr = 0;
00460 
00461     /* initialize the socktype field */
00462     if (!strcmp(socktype,"SDIO")) {
00463         thee->type = VIO_SDIO;
00464     } else if (!strcmp(socktype,"FILE")) {
00465         thee->type = VIO_FILE;
00466     } else if (!strcmp(socktype,"BUFF")) {
00467         thee->type = VIO_BUFF;
00468     } else if (!strcmp(socktype,"UNIX")) {
00469         thee->type = VIO_UNIX;
00470     } else if (!strcmp(socktype,"INET")) {
00471         thee->type = VIO_INET;
00472     } else {
00473         fprintf(stderr,"Vio_ctor2: Incorrect socktype given <%s>\n",socktype);
00474         VJMPERR2( 0 );
00475     }
00476 
00477     /* initialize the datafrmt field */
00478     if (!strcmp(datafrmt,"ASC")) {
00479         thee->frmt = VIO_ASC;
00480     } else if (!strcmp(datafrmt,"XDR")) {
00481         thee->frmt = VIO_XDR;
00482     } else {
00483         fprintf(stderr,"Vio_ctor2: Incorrect datafrmt given <%s>\n", datafrmt);
00484         VJMPERR2( 0 );
00485     }
00486 
00487     /* initialize the r/w field */
00488     if (!strcmp(rwkey,"r")) {
00489         thee->rwkey = VIO_R;
00490     } else if (!strcmp(rwkey,"w")) {
00491         thee->rwkey = VIO_W;
00492     } else {
00493         fprintf(stderr,"Vio_ctor2: Incorrect rwkey given <%s>\n", rwkey);
00494         VJMPERR2( 0 );
00495     }
00496 
00497     /* need to call this stupid Win32 function before gethostname... */
00498 #if defined(HAVE_WINSOCK_H)
00499     if ( WSAStartup(0x0101, &wsaData) != 0 ) {
00500         fprintf(stderr, "Vio_ctor2: WSAStartup fail INET sock <%s>"
00501             " dueto <%s>\n", thee->file,VIOstrerrno(errno));
00502         VJMPERR2( 0 );
00503     }
00504 #endif
00505 
00506     /* get "my" local hostname */
00507     if ((VIOgethostname(thee->lhost,sizeof(thee->lhost))) < 0) {
00508         fprintf(stderr,
00509             "Vio_ctor2: Gethostname fail INET sock <%s> dueto <%s>\n",
00510             thee->file, VIOstrerrno(errno));
00511         strcpy(thee->lhost,"unknown");
00512     } else if ((hpTmp=gethostbyname(thee->lhost))==VNULL) {
00513         fprintf(stderr,
00514             "Vio_ctor2: Gethostbyname fail INET sock <%s> dueto <%s>\n",
00515             thee->file, VIOstrerrno(errno));
00516         strcpy(thee->lhost,"unknown");
00517     } else strcpy(thee->lhost,hpTmp->h_name);
00518 
00519     /* default remote hostname */
00520     strcpy(thee->rhost,"unknown");
00521 
00522     /* initialize the buffer space */
00523     Vio_initIoPutBuffers(thee);
00524 
00525     /* SDIO READ/WRITE SETUP */
00526     if (thee->type==VIO_SDIO) {
00527 
00528         if (thee->rwkey==VIO_R) {
00529             thee->fp = stdin;
00530         } else { /* (thee->rwkey==VIO_W) */
00531             thee->fp = stdout;
00532         }
00533         VJMPERR2( thee->fp != VNULL );
00534 
00535     /* FILE READ/WRITE SETUP */
00536     } else if (thee->type==VIO_FILE) {
00537 
00538         /* filename is the i/o file name */
00539         if (strlen(filename) >= VMAX_ARGLEN) {
00540             fprintf(stderr, "Vio_ctor2: Filename <%d> exceeds max <%d>!\n",
00541                 (int)strlen(filename), VMAX_ARGLEN);
00542             VJMPERR2( 0 );
00543         }
00544         strncpy(thee->file, filename, VMAX_ARGLEN);
00545         if (thee->rwkey==VIO_R) {
00546             thee->fp = fopen(thee->file, "r");
00547         } else { /* (thee->rwkey==VIO_W) */
00548             thee->fp = fopen(thee->file, "w");
00549         }
00550         VJMPERR2( thee->fp != VNULL );
00551 
00552     /* BUFF READ/WRITE SETUP */
00553     } else if (thee->type==VIO_BUFF) {
00554 
00555         /* filename is the internal buffer number for the buffer */
00556         thee->VIObufferPtr = 0;
00557 
00558     /* UNIX SOCKET READ/WRITE SETUP */
00559     } else if (thee->type==VIO_UNIX) {
00560 
00561 #if defined(HAVE_SYS_UN_H)
00562 
00563         /* filename is socketName-userName in the directory /tmp */
00564 
00565         VASSERT( Vnm_getuser(username, sizeof(username)) );
00566         sprintf(thee->file, "/tmp/%s-%s", filename, username);
00567 
00568         /* create the socket address structure */
00569         thee->name = (struct sockaddr_un *)
00570             calloc( 1, sizeof(struct sockaddr_un) );
00571         VJMPERR2( thee->name != VNULL );
00572 
00573         /* Get a socket structure */
00574         if ((thee->so=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
00575             fprintf(stderr,"Vio_ctor2: fail to find UNIX sock dueto <%s>.\n",
00576                 VIOstrerrno(errno));
00577             VJMPERR2( 0 );
00578         } else {
00579 
00580             /* set REUSEADDR so sockets can be closed and reopened */
00581             ival = 1;  /* just need a nonzero value */
00582             if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
00583               (void*)&ival,sizeof(ival)) < 0 ) {
00584                 fprintf(stderr, "Vio_ctor2: Setsockopt1 fail UNIX sock <%s>"
00585                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
00586                 VJMPERR2( 0 );
00587             }
00588 
00589             /* turn on LINGER so WRITES complete before socks close */
00590             ling.l_onoff  = 1;   /* just need a nonzero value */
00591             ling.l_linger = 30;  /* linger time in seconds */
00592             if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
00593               (void*)&ling,sizeof(ling)) < 0) {
00594                 fprintf(stderr, "Vio_ctor2: Setsockopt2 fail UNIX sock <%s>"
00595                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
00596                 VJMPERR2( 0 );
00597             }
00598 
00599             /* Setup for the socket */
00600             memset(thee->name, '\0', sizeof(struct sockaddr_un));
00601             ((struct sockaddr_un *)(thee->name))->sun_family = AF_UNIX;
00602             strcpy(((struct sockaddr_un *)(thee->name))->sun_path,
00603                 thee->file);
00604 
00605             /* if we are reader, WE are responsible for creating socket */
00606             /* the reader must do: (unlink/)setsockopt/bind/listen */
00607             if (thee->rwkey==VIO_R) {
00608 
00609                 /* define socket file; remove previous socket */
00610                 unlink(thee->file);
00611 
00612                 /* determine structure size; AF_UNIX is variable length */
00613                 len = sizeof(((struct sockaddr_un *)
00614                               (thee->name))->sun_family) 
00615                     + strlen(((struct sockaddr_un *)
00616                               (thee->name))->sun_path);
00617 
00618                 /* Bind socket to address (must setsockopts before bind) */
00619                 if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
00620                     fprintf(stderr,
00621                         "Vio_ctor2: Bind fail UNIX sock <%s> dueto <%s>\n",
00622                         thee->file, VIOstrerrno(errno));
00623                     VJMPERR2( 0 );
00624                 } else {
00625 
00626                     /* Tell socket to start listening for connections */
00627                     if (listen(thee->so,5) < 0) {
00628                         fprintf(stderr,
00629                         "Vio_ctor2: List fail UNIX sock <%s> dueto <%s>\n",
00630                         thee->file, VIOstrerrno(errno));
00631                         VJMPERR2( 0 );
00632                     }
00633                 }
00634             /*
00635              * if we got to here, we can assume reader has done
00636              * all of: (unlink/)setsockopt/bind/listen
00637              */
00638             }
00639         }
00640 #endif
00641 
00642     /* INET SOCKET READ/WRITE SETUP */
00643     } else if (thee->type==VIO_INET) {
00644 
00645         /* filename is the port number for the socket */
00646         if (strlen(filename) >= VMAX_ARGLEN) {
00647             fprintf(stderr, "Vio_ctor2: Filename <%d> exceeds max <%d>!\n",
00648                 (int)strlen(filename), VMAX_ARGLEN);
00649             VJMPERR2( 0 );
00650         }
00651         strncpy(thee->file, filename, VMAX_ARGLEN);
00652 
00653         /* create the socket address structure */
00654         thee->name = (struct sockaddr_in *)
00655             calloc( 1, sizeof(struct sockaddr_in) );
00656         VJMPERR2( thee->name != VNULL );
00657 
00658         /* Look for sockets */
00659         if ((thee->so=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00660             fprintf(stderr,"Vio_ctor2: fail to find INET sock dueto <%s>\n",
00661                 VIOstrerrno(errno));
00662             VJMPERR2( 0 );
00663         } else {
00664 
00665             /* set REUSEADDR so sockets can be closed and reopened */
00666             ival = 1;  /* just need a nonzero value */
00667             if ( setsockopt(thee->so,SOL_SOCKET,SO_REUSEADDR,
00668               (void*)&ival,sizeof(ival)) < 0 ) {
00669                 fprintf(stderr, "Vio_ctor2: Setsockopt3 fail INET sock <%s>"
00670                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
00671                 VJMPERR2( 0 );
00672             }
00673 
00674             /* turn on LINGER so WRITES complete before sockets close */
00675             ling.l_onoff  = 1;   /* just need a nonzero value */
00676             ling.l_linger = 30;  /* linger time in seconds */
00677             if ( setsockopt(thee->so,SOL_SOCKET,SO_LINGER,
00678               (void*)&ling,sizeof(ling)) < 0 ) {
00679                 fprintf(stderr, "Vio_ctor2: Setsockopt4 fail INET sock <%s>"
00680                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
00681                 VJMPERR2( 0 );
00682             }
00683 
00684             /* Setup for the socket */
00685             memset(thee->name, '\0', sizeof(struct sockaddr_in));
00686             ((struct sockaddr_in *)(thee->name))->sin_family = AF_INET;
00687             ((struct sockaddr_in *)(thee->name))->sin_port
00688                 = htons( (unsigned short) (VPORTNUMBER + atoi(thee->file)) );
00689 
00690             /* if we are the reader, WE must create the socket */
00691             /* the reader must do: setsockopt/bind/listen */
00692             if (thee->rwkey==VIO_R) {
00693 
00694                 /* use wildcard address */
00695                 n = INADDR_ANY;
00696                 memcpy(&((struct sockaddr_in *)(thee->name))->sin_addr,
00697                     &n, sizeof(long));
00698 
00699                 /* determine structure size; AF_INET is fixed length */
00700                 len = sizeof(struct sockaddr_in);
00701 
00702                 /* Bind socket to address (must setsockopts before bind) */
00703                 if (bind(thee->so,(struct sockaddr *)(thee->name),len)<0) {
00704                     fprintf(stderr,
00705                         "Vio_ctor2: Bind fail INET sock <%s> dueto <%s>\n",
00706                         thee->file, VIOstrerrno(errno));
00707                     VJMPERR2( 0 );
00708                 } else {
00709 
00710                     /* Tell socket to start listening for connections */
00711                     if (listen(thee->so,5) < 0) {
00712                         fprintf(stderr,
00713                             "Vio_ctor2: List fail INET sock <%s> dueto <%s>\n",
00714                             thee->file, VIOstrerrno(errno));
00715                         VJMPERR2( 0 );
00716                     }
00717                 }
00718 
00719             /* assume reader has done: setsockopt/bind/listen */
00720             } else {
00721 
00722                 /* network address of port -- "localhost" means WE have port */
00723                 if (!strcmp(hostname,"localhost")) {
00724                     strcpy(host,thee->lhost);
00725                 } else {
00726                     strcpy(host,hostname);
00727                 }
00728 
00729                 /* get IP address corresponding to this server hostname */
00730                 if ((hpTmp=gethostbyname(host))==VNULL) {
00731                     fprintf(stderr,
00732                         "Vio_ctor2: Gethostbyname fail INET sock <%s>"
00733                         " dueto <%s>\n", thee->file, VIOstrerrno(errno));
00734                     VJMPERR2( 0 );
00735                 } else {
00736 
00737                     /* just need to save address of host that has socket */
00738                     memcpy(
00739                         &(((struct sockaddr_in *)(thee->name))->sin_addr),
00740                         hpTmp->h_addr_list[0], (unsigned int)hpTmp->h_length);
00741 
00742                     /* save the hostname for the port for later i/o */
00743                     strcpy(thee->rhost,hpTmp->h_name);
00744                 }
00745             }
00746         }
00747     }
00748 
00749     /* initialize <asc,xdr> datastructures; must do almost at the end */
00750     if (thee->frmt==VIO_ASC) {
00751         thee->axdr = (ASC*)calloc( 1, sizeof(ASC) );
00752         VJMPERR2( thee->axdr != VNULL );
00753         if (thee->rwkey==VIO_R) {
00754             ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_DECODE);
00755         } else { /* if (thee->rwkey==VIO_W) */
00756             ascmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, ASC_ENCODE);
00757         }
00758     } else if (thee->frmt==VIO_XDR) {
00759         thee->axdr = (XDR*)calloc( 1, sizeof(XDR) );
00760         VJMPERR2( thee->axdr != VNULL );
00761         if (thee->rwkey==VIO_R) {
00762             xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_DECODE);
00763         } else { /* if (thee->rwkey==VIO_W) */
00764             xdrmem_create(thee->axdr, thee->ioBuffer, VMAX_BUFSIZE, XDR_ENCODE);
00765         }
00766     }
00767 
00768     /* lastly: default white/comment char sets (careful! propogates to axdr) */
00769     Vio_setWhiteChars(thee, VIOwhiteChars);
00770     Vio_setCommChars(thee,  VIOcommChars);
00771 
00772     /* return without error */
00773     return 1;
00774 
00775   VERROR1:
00776     fprintf(stderr,"Vio_ctor2: Vio library has not been started.\n");
00777     return 0;
00778 
00779   VERROR2:
00780     fprintf(stderr,"Vio_ctor2: some error occurred.\n");
00781     return 0;
00782 }
00783 
00784 /*
00785  * ***************************************************************************
00786  * Routine:  Vio_dtor
00787  *
00788  * Purpose:  Destroy the [sdio/file/buff/unix/inet] container object.
00789  *
00790  * Author:   Michael Holst
00791  * ***************************************************************************
00792  */
00793 VPUBLIC void Vio_dtor(Vio **thee)
00794 {
00795     if ((*thee) != VNULL) {
00796         if ((*thee)->VIObuffer != VNULL) {
00797             free( (*thee)->VIObuffer );
00798             (*thee)->VIObuffer = VNULL;
00799         }
00800         Vio_dtor2(*thee);
00801         free( (*thee) );
00802         (*thee) = VNULL;
00803     }
00804 }
00805 
00806 /*
00807  * ***************************************************************************
00808  * Routine:  Vio_dtor2
00809  *
00810  * Purpose:  Destroy the [sdio/file/buff/unix/inet] container object.
00811  *
00812  * Author:   Michael Holst
00813  * ***************************************************************************
00814  */
00815 VPUBLIC void Vio_dtor2(Vio *thee)
00816 {
00817     if (thee != VNULL) {
00818 
00819         /* free the <ASC,XDR> structures */
00820         if ( thee->axdr != VNULL ) {
00821             if ( thee->frmt == VIO_ASC ) {
00822                 asc_destroy( (ASC*)(thee->axdr) );
00823             } else if ( thee->frmt == VIO_XDR ) {
00824                 xdr_destroy( (XDR*)(thee->axdr) );
00825             }
00826             free( thee->axdr );
00827             thee->axdr = VNULL;
00828         }
00829 
00830         /* finish up */
00831         if (thee->type==VIO_SDIO) {
00832             /* no-op */
00833         } else if (thee->type==VIO_FILE) {
00834             if ( thee->fp != VNULL ) {
00835                 if ( fclose(thee->fp) != 0 ) {
00836                     fprintf(stderr, "Vio_dtor2: fclose fail device <%s>"
00837                         " dueto <%s>\n", thee->file,VIOstrerrno(errno));
00838                 }
00839             }
00840         } else if (thee->type==VIO_BUFF) {
00841             /* CMIKE: WHAT ABOUT FREEING THE BUFFER SPACE??? */
00842             thee->VIObufferPtr = 0;
00843         } else if ( (thee->type==VIO_UNIX)
00844                  || (thee->type==VIO_INET) ) {
00845             if ( thee->soc >= 0 ) {
00846 #if defined(HAVE_WINSOCK_H)
00847                 if ( closesocket(thee->soc) != 0 ) {
00848                     fprintf(stderr, "Vio_dtor2: closesocket1 fail device <%s>"
00849                         " dueto <%s>\n", thee->file,
00850                         VIOstrerrno(errno));
00851                 }
00852 #else
00853                 if ( close(thee->soc) != 0 ) {
00854                     fprintf(stderr, "Vio_dtor2: close1 fail device <%s>"
00855                         " dueto <%s>\n", thee->file,
00856                     VIOstrerrno(errno));
00857                 }
00858 #endif
00859             }
00860             if ( thee->so >= 0 ) {
00861 #if defined(HAVE_WINSOCK_H)
00862                 if ( closesocket(thee->so) != 0 ) {
00863                     fprintf(stderr, "Vio_dtor2: closesocket2 fail device <%s>"
00864                         " dueto <%s>\n", thee->file,
00865                         VIOstrerrno(errno));
00866                 }
00867 #else
00868                 if ( close(thee->so) != 0 ) {
00869                     fprintf(stderr, "Vio_dtor2: close2 fail device <%s>"
00870                         " dueto <%s>\n", thee->file,
00871                         VIOstrerrno(errno));
00872                 }
00873 #endif
00874             }
00875 
00876             /* remove the device file for domain sockets */
00877             if (thee->type==VIO_UNIX)
00878                 if (thee->rwkey==VIO_R)
00879                     unlink(thee->file);
00880 
00881         } else {
00882             fprintf(stderr,"Vio_dtor2: Bad type found <%d>\n", thee->type);
00883         }
00884 
00885         if ( (thee->type==VIO_UNIX)
00886           || (thee->type==VIO_INET) ) {
00887             if (thee->name != VNULL) {
00888                 free( thee->name );
00889             }
00890             thee->name = VNULL;
00891         }
00892 
00893         /* we called WSAStartup() in constructor; must always be paired */
00894 #if defined(HAVE_WINSOCK_H)
00895         WSACleanup();
00896 #endif
00897     }
00898 }
00899 
00900 /*
00901  * ***************************************************************************
00902  * Routine:  Vio_setWhiteChars
00903  *
00904  * Purpose:  Define the white character set.
00905  *
00906  * Author:   Michael Holst
00907  * ***************************************************************************
00908  */
00909 VPUBLIC void Vio_setWhiteChars(Vio *thee, char *whiteChars)
00910 {
00911     if (thee != VNULL) {
00912         strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
00913 
00914         /* propogate the character set down to the ASC structure */
00915         VASSERT( thee->axdr != VNULL );
00916         if (thee->frmt == VIO_ASC) {
00917             asc_setWhiteChars(thee->axdr, whiteChars);
00918         } else if (thee->frmt == VIO_XDR) {
00919 #if !defined(HAVE_XDR)
00920             asc_setWhiteChars(thee->axdr, whiteChars);
00921 #endif
00922         } else { VASSERT( 0 ); }
00923     }
00924 }
00925 
00926 /*
00927  * ***************************************************************************
00928  * Routine:  Vio_setCommChars
00929  *
00930  * Purpose:  Define the comment character set.
00931  *
00932  * Author:   Michael Holst
00933  * ***************************************************************************
00934  */
00935 VPUBLIC void Vio_setCommChars(Vio *thee, char *commChars)
00936 {
00937     if (thee != VNULL) {
00938         strncpy(thee->commChars, commChars, VMAX_ARGNUM);
00939 
00940         /* propogate the character set down to the ASC structure */
00941         VASSERT( thee->axdr != VNULL );
00942         if (thee->frmt == VIO_ASC) {
00943             asc_setCommChars(thee->axdr, commChars);
00944         } else if (thee->frmt == VIO_XDR) {
00945 #if !defined(HAVE_XDR)
00946             asc_setCommChars(thee->axdr, commChars);
00947 #endif
00948         } else { VASSERT( 0 ); }
00949     }
00950 }
00951 
00952 /*
00953  * ***************************************************************************
00954  * Routine:  Vio_accept
00955  *
00956  * Purpose:  Accept any waiting connect attempt to our socket on our machine.
00957  *
00958  * Notes:    The nonblock parameter has the following interpretation:
00959  *           (Only for <UNIX/INET>; othewise it is ignored.)
00960  *
00961  *               nonblock==0  ==> block until a connect is attempted
00962  *               nonblock==1  ==> DO NOT block at all
00963  *
00964  * Author:   Michael Holst
00965  * ***************************************************************************
00966  */
00967 VPUBLIC int Vio_accept(Vio *thee, int nonblock)
00968 {
00969     int rc;
00970 
00971 #if defined(HAVE_WINSOCK_H)
00972     unsigned long  blockKey;
00973 #else
00974     int flags = 0;
00975     struct sockaddr_in peer;
00976     struct hostent *hpTmp;
00977 #endif
00978 
00979 #if defined(ACCEPT_USES_ULONG)
00980     unsigned long len;
00981 #elif defined(ACCEPT_USES_UINT)
00982     unsigned int len;
00983 #elif defined(ACCEPT_USES_INT)
00984     int len;
00985 #else
00986     unsigned int len;
00987 #endif
00988 
00989     /* reset error tag */
00990     thee->error = 0;
00991 
00992     thee->soc = -1;
00993     rc = -1;
00994 
00995     Vio_initIoPutBuffers(thee);
00996     VJMPERR2( thee->rwkey == VIO_R );
00997 
00998     if ( (thee->type==VIO_SDIO)
00999       || (thee->type==VIO_FILE)
01000       || (thee->type==VIO_BUFF) ) {
01001 
01002         /* ONLY for file i/o, we need to look at and set the dirty bit */
01003         /* (this keeps us from reading the file twice) */
01004         if (thee->type==VIO_FILE) {
01005             if ((!thee->dirty) && (!feof(thee->fp))) {
01006                 thee->dirty = 1;
01007                 rc = 1;
01008             }
01009         } else {
01010             rc = 1;
01011         }
01012 
01013     } else if (thee->type==VIO_UNIX) {
01014 
01015 #if defined(HAVE_SYS_UN_H)
01016         /* Make this a non-blocking socket just for the accept call */
01017         if (nonblock) {
01018             flags = fcntl( thee->so, F_GETFL, 0 );
01019             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
01020         }
01021 
01022         /* accept */
01023         len = sizeof(struct sockaddr_un);
01024         rc = accept(thee->so,(struct sockaddr *)(thee->name),&len);
01025         thee->soc = rc;
01026         if ((!nonblock) && (rc < 0)) {
01027             fprintf(stderr, "Vio_accept: Accept fail UNIX sock <%s>"
01028                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01029             VJMPERR2( 0 );
01030         }
01031 
01032         /* restore blocking -- must nonblock for LINGER to work! */
01033         if (nonblock) {
01034             fcntl( thee->so, F_SETFL, flags );
01035         }
01036 #endif
01037 
01038     } else if (thee->type==VIO_INET) {
01039 
01040         /* Make this non-blocking socket just for accept call */
01041         if (nonblock) {
01042 #if defined(HAVE_WINSOCK_H)
01043             blockKey = 1;
01044             if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
01045                 fprintf(stderr, "Vio_accept: Ioctlsocket1 fail INET sock <%s>"
01046                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01047                 VJMPERR2( 0 );
01048             }
01049 #else
01050             flags = fcntl( thee->so, F_GETFL, 0 );
01051             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
01052 #endif
01053         }
01054 
01055         len = sizeof(struct sockaddr_in);
01056         rc = accept(thee->so, (struct sockaddr *)(thee->name), &len);
01057         thee->soc = rc;
01058         if ((!nonblock) && (rc < 0)) {
01059             fprintf(stderr, "Vio_accept: Accept fail INET sock <%s>"
01060                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01061             VJMPERR2( 0 );
01062         }
01063 
01064         /* restore blocking -- must nonblock for LINGER to work! */
01065         if (nonblock) {
01066 #if defined(HAVE_WINSOCK_H)
01067             blockKey = 0;
01068             if ( ioctlsocket( thee->so, FIONBIO, &blockKey ) != 0 ) {
01069                 fprintf(stderr, "Vio_accept: Ioctlsocket2 fail INET sock <%s>"
01070                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01071                 VJMPERR2( 0 );
01072             }
01073 #else
01074             fcntl( thee->so, F_SETFL, flags );
01075 #endif
01076         }
01077 
01078         /* if we found a writer, get his hostname (just for i/o) */
01079         if (rc >= 0) {
01080 #if defined(HAVE_WINSOCK_H)
01081             strcpy(thee->rhost,"unknown");
01082 #else
01083             len = sizeof(struct sockaddr_in);
01084             if (getpeername(thee->soc,(struct sockaddr *)(&peer),&len)<0) {
01085                 fprintf(stderr, "Vio_accept: Getpeername fail INET <%s>"
01086                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01087                 VJMPERR2( 0 );
01088             } else if (VNULL==(hpTmp=gethostbyname(inet_ntoa(peer.sin_addr)))){
01089                 fprintf(stderr, "Vio_accept: Gethostbyname fail INET <%s>"
01090                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01091                 VJMPERR2( 0 );
01092             } else {
01093                 strcpy(thee->rhost,hpTmp->h_name);
01094             }
01095 #endif
01096         }
01097 
01098     } else {
01099         fprintf(stderr,"Vio_accept: Bad type found <%d>\n", thee->type);
01100         VJMPERR2( 0 );
01101     }
01102 
01103     /* normal return */
01104     return rc;
01105 
01106   VERROR2:
01107     thee->error = 1;
01108     return -1;
01109 }
01110 
01111 /*
01112  * ***************************************************************************
01113  * Routine:  Vio_acceptFree
01114  *
01115  * Purpose:  Free the socket child that was used for the last accept.
01116  *
01117  * Author:   Michael Holst
01118  * ***************************************************************************
01119  */
01120 VPUBLIC void Vio_acceptFree(Vio *thee)
01121 {
01122     /* VJMPERR2( !thee->error ); */  /* Need to close the socket... */
01123     VJMPERR2( thee->rwkey == VIO_R );
01124 
01125     if ( (thee->type==VIO_SDIO)
01126       || (thee->type==VIO_FILE)
01127       || (thee->type==VIO_BUFF) ) {
01128         /* no-op */
01129     } else if ( (thee->type==VIO_UNIX)
01130              || (thee->type==VIO_INET) ) {
01131         if ( thee->soc >= 0 ) {
01132 #if defined(HAVE_WINSOCK_H)
01133             if ( closesocket(thee->soc) != 0 ) {
01134                 fprintf(stderr, "Vio_acceptFree: closesocket fail device <%s>"
01135                     " dueto <%s>\n", thee->file,VIOstrerrno(errno));
01136                 VJMPERR2( 0 );
01137             }
01138 #else
01139             if ( close(thee->soc) != 0 ) {
01140                 fprintf(stderr, "Vio_acceptFree: close fail device <%s>"
01141                     " dueto <%s>\n", thee->file,VIOstrerrno(errno));
01142                 VJMPERR2( 0 );
01143             }
01144 #endif
01145         }
01146     } else {
01147         fprintf(stderr,"Vio_acceptFree: Bad type found <%d>\n", thee->type);
01148         VJMPERR2( 0 );
01149     }
01150 
01151     thee->soc = -1;
01152 
01153     /* normal return */
01154     Vio_initIoPutBuffers(thee);
01155     return;
01156 
01157   VERROR2:
01158     Vio_initIoPutBuffers(thee);
01159     thee->error = 1;
01160     return;
01161 }
01162 
01163 /*
01164  * ***************************************************************************
01165  * Routine:  Vio_connect
01166  *
01167  * Purpose:  Connect to some socket on a remote machine (or on our machine).
01168  *
01169  * Notes:    The nonblock parameter has the following interpretation:
01170  *           (Only for <UNIX/INET>; othewise it is ignored.)
01171  *
01172  *               nonblock==0  ==> block until our connection is accepted
01173  *               nonblock==1  ==> DO NOT block at all
01174  *
01175  * Author:   Michael Holst
01176  * ***************************************************************************
01177  */
01178 VPUBLIC int Vio_connect(Vio *thee, int nonblock)
01179 {
01180     int rc;
01181 #if defined(HAVE_WINSOCK_H)
01182     unsigned long len;
01183 #else
01184     int len;
01185     int flags = 0;
01186 #endif
01187 
01188     /* reset error tag */
01189     thee->error = 0;
01190 
01191     rc = -1;
01192 
01193     Vio_initIoPutBuffers(thee);
01194     VJMPERR2( thee->rwkey == VIO_W );
01195 
01196     if ( (thee->type==VIO_SDIO)
01197       || (thee->type==VIO_FILE)
01198       || (thee->type==VIO_BUFF) ) {
01199         rc = 1;
01200     } else if (thee->type==VIO_UNIX) {
01201 
01202 #if defined(HAVE_SYS_UN_H)
01203         /* Make this a non-blocking socket just for the connect call */
01204         if (nonblock) {
01205             flags = fcntl( thee->so, F_GETFL, 0 );
01206             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
01207         }
01208 
01209         /* blocking connect */
01210         len = sizeof(struct sockaddr_un);
01211         rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
01212         if ((!nonblock) && (rc < 0)) {
01213             fprintf(stderr, "Vio_connect: Conn fail UNIX sock <%s>"
01214                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01215             VJMPERR2( 0 );
01216         }
01217 
01218         /* restore blocking -- must nonblock for LINGER to work! */
01219         if (nonblock) {
01220             fcntl( thee->so, F_SETFL, flags );
01221         }
01222 #endif
01223 
01224     } else if (thee->type==VIO_INET) {
01225 
01226         /* make this a non-blocking socket just for the connect call */
01227         if (nonblock) {
01228 #if defined(HAVE_WINSOCK_H)
01229             len = 1;
01230             if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
01231                 fprintf(stderr, "Vio_connect: Ioctlsocket1 fail INET sock <%s>"
01232                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01233                 VJMPERR2( 0 );
01234             }
01235 #else
01236             flags = fcntl( thee->so, F_GETFL, 0 );
01237             fcntl( thee->so, F_SETFL, flags | VO_NONBLOCK );
01238 #endif
01239         }
01240 
01241         /* blocking connect */
01242         len = sizeof(struct sockaddr_in);
01243         rc = connect(thee->so, (struct sockaddr *)(thee->name),len);
01244         if ((!nonblock) && (rc < 0)) {
01245             fprintf(stderr, "Vio_connect: Conn fail INET sock <%s>"
01246                  " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01247             VJMPERR2( 0 );
01248         }
01249 
01250         /* restore blocking -- must nonblock for LINGER to work! */
01251         if (nonblock) {
01252 #if defined(HAVE_WINSOCK_H)
01253             len = 0;
01254             if ( ioctlsocket( thee->so, FIONBIO, &len ) != 0 ) {
01255                 fprintf(stderr, "Vio_connect: Ioctlsocket2 fail INET sock <%s>"
01256                    " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01257                 VJMPERR2( 0 );
01258             }
01259 #else
01260             fcntl( thee->so, F_SETFL, flags );
01261 #endif
01262         }
01263 
01264     } else {
01265         fprintf(stderr,"Vio_connect: Bad type found <%d>\n", thee->type);
01266         VJMPERR2( 0 );
01267     }
01268 
01269     /* normal return */
01270     return rc;
01271 
01272   VERROR2:
01273     thee->error = 1;
01274     return -1;
01275 }
01276 
01277 /*
01278  * ***************************************************************************
01279  * Routine:  Vio_connectFree
01280  *
01281  * Purpose:  Purge any output buffers (for <UNIX/INET>, else a no-op).
01282  *
01283  * Author:   Michael Holst
01284  * ***************************************************************************
01285  */
01286 VPUBLIC void Vio_connectFree(Vio *thee)
01287 {
01288     /* VJMPERR2( !thee->error ); */  /* Need to close the socket... */
01289     VJMPERR2( thee->rwkey == VIO_W );
01290 
01291     if ( (thee->type==VIO_SDIO)
01292       || (thee->type==VIO_FILE)
01293       || (thee->type==VIO_BUFF) ) {
01294         /* no-op */
01295     } else if ( (thee->type==VIO_UNIX)
01296              || (thee->type==VIO_INET) ) {
01297         Vio_purgePutBuffer(thee);
01298     } else {
01299         fprintf(stderr,"Vio_connectFree: Bad type found <%d>\n", thee->type);
01300         VJMPERR2( 0 );
01301     }
01302 
01303     /* normal return */
01304     Vio_initIoPutBuffers(thee);
01305     return;
01306 
01307   VERROR2:
01308     Vio_initIoPutBuffers(thee);
01309     thee->error = 1;
01310     return;
01311 }
01312 
01313 /*
01314  * ***************************************************************************
01315  * Routine:  Vio_scanf
01316  *
01317  * Purpose:  Mimic "scanf" from an arbitrary Vio device.
01318  *
01319  * Author:   Michael Holst
01320  * ***************************************************************************
01321  */
01322 VPUBLIC int Vio_scanf(Vio *thee, char *parms, ... )
01323 {
01324     va_list ap;
01325     char arg0, arg1, arg2, *cval, *sval, buf[VMAX_BUFSIZE];
01326     int i, len, tokCount, *ival;
01327     float *fval;
01328     double *dval;
01329 
01330     VJMPERR2( !thee->error );
01331     VJMPERR2( thee->rwkey == VIO_R );
01332 
01333     /* get the value of the current pointer that points into the ioBuffer */
01334     len = 0;
01335     if (thee->frmt == VIO_ASC) {
01336         len = asc_getpos((ASC*)thee->axdr);
01337     } else if (thee->frmt == VIO_XDR) {
01338         len = xdr_getpos((XDR*)thee->axdr);
01339     } else { VASSERT( 0 ); }
01340 
01341     /* if the buffer is completely empty (i.e., first time here) fill it up */
01342     if ( thee->ioBufferLen == 0 ) {
01343 
01344         /* read the data */
01345         thee->ioBufferLen = Vio_read( thee, thee->ioBuffer, VMAX_BUFSIZE );
01346 
01347         /* set the buffer point to 0 */
01348         if (thee->frmt == VIO_ASC) {
01349             VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
01350         } else if (thee->frmt == VIO_XDR) {
01351             VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
01352         } else { VASSERT( 0 ); }
01353  
01354     /* if current point is more than halfway through buf, read in more data */
01355     } else if ( len > (VMAX_BUFSIZE/2) ) {
01356 
01357         /* sanity check */
01358         VJMPERR1( len <= thee->ioBufferLen );
01359 
01360         /* copy unread part of ioBuffer into temp buf and clear ioBuffer */
01361         for (i=len; i<thee->ioBufferLen; i++)
01362             buf[i-len] = thee->ioBuffer[i];
01363         memset(thee->ioBuffer,  '\0', sizeof(thee->ioBuffer));
01364 
01365         /* read temp buffer back, reseting to the beginning of ioBuffer */
01366         thee->ioBufferLen = thee->ioBufferLen - len;
01367         for (i=0; i<thee->ioBufferLen; i++)
01368             thee->ioBuffer[i] = buf[i];
01369 
01370         /* reset the buffer point to 0 */
01371         if (thee->frmt == VIO_ASC) {
01372             VJMPERR1( asc_setpos((ASC*)thee->axdr, 0) );
01373         } else if (thee->frmt == VIO_XDR) {
01374             VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
01375         } else { VASSERT( 0 ); }
01376 
01377         /* finally, read in the new data, starting at end of current data */
01378         thee->ioBufferLen += Vio_read(thee,
01379             thee->ioBuffer+thee->ioBufferLen, VMAX_BUFSIZE-thee->ioBufferLen );
01380 
01381     /* we (hopefully?) have enough in buffer to work with; do nothing here */
01382     } else {
01383         /* no-op */
01384     }
01385 
01386     /* we ALWAYS have to pick the format specifier apart <ASC,XDR> ... */
01387     tokCount = 0;
01388     len = strlen(parms);
01389     va_start(ap, parms);
01390     i = 0;
01391     while ( i < len ) {
01392         arg0 = parms[i];
01393         if ( arg0 == ' ' ) {
01394             i+=1;
01395         } else if ( arg0 == '\n' ) {
01396             i+=1;
01397         } else if ( i+1 < len ) {
01398             arg1 = parms[i+1];
01399             if ( arg1 == 's' ) {
01400                 sval = va_arg(ap, char*);
01401                 if ((i == len-3) && ( parms[len-1] == '\n' )) {
01402                     if (thee->frmt == VIO_ASC) {
01403                         VASSERT( 0 ); /* is this ever executed??? */
01404                     } else if (thee->frmt == VIO_XDR) {
01405                         VASSERT( 0 ); /* is this ever executed??? */
01406                     } else { VASSERT( 0 ); }
01407                 } else {
01408                     if (thee->frmt == VIO_ASC) {
01409                         VJMPERR1( asc_string(thee->axdr, &sval, VMAX_BUFSIZE) );
01410                     } else if (thee->frmt == VIO_XDR) {
01411                         VJMPERR1( xdr_string(thee->axdr, &sval, VMAX_BUFSIZE) );
01412                     } else { VASSERT( 0 ); }
01413                 }
01414                 tokCount++;
01415                 i+=2;
01416             } else if ( arg1 == 'c' ) {
01417                 cval = va_arg(ap, char*);
01418                 if (thee->frmt == VIO_ASC) {
01419                     VJMPERR1( asc_char( thee->axdr, cval ) );
01420                 } else if (thee->frmt == VIO_XDR) {
01421                     VJMPERR1( xdr_char( thee->axdr, cval ) );
01422                 } else { VASSERT( 0 ); }
01423                 tokCount++;
01424                 i+=2;
01425             } else if ( arg1 == 'd' ) {
01426                 ival = va_arg(ap, int*);
01427                 if (thee->frmt == VIO_ASC) {
01428                     VJMPERR1( asc_int( thee->axdr, ival ) );
01429                 } else if (thee->frmt == VIO_XDR) {
01430                     VJMPERR1( xdr_int( thee->axdr, ival ) );
01431                 } else { VASSERT( 0 ); }
01432                 tokCount++;
01433                 i+=2;
01434             } else if ( arg1 == 'f' ) {
01435                 fval = va_arg(ap, float*);
01436                 if (thee->frmt == VIO_ASC) {
01437                     VJMPERR1( asc_float( thee->axdr, fval ) );
01438                 } else if (thee->frmt == VIO_XDR) {
01439                     VJMPERR1( xdr_float( thee->axdr, fval ) );
01440                 } else { VASSERT( 0 ); }
01441                 tokCount++;
01442                 i+=2;
01443             } else if ( arg1 == 'e' ) {
01444                 fval = va_arg(ap, float*);
01445                 if (thee->frmt == VIO_ASC) {
01446                     VJMPERR1( asc_float( thee->axdr, fval ) );
01447                 } else if (thee->frmt == VIO_XDR) {
01448                     VJMPERR1( xdr_float( thee->axdr, fval ) );
01449                 } else { VASSERT( 0 ); }
01450                 tokCount++;
01451                 i+=2;
01452             } else if (( arg1 == 'l' ) && ( i+2 < len )) {
01453                 arg2 = parms[i+2];
01454                 if ( arg2 == 'e' ) {
01455                     dval = va_arg(ap, double*);
01456                     if (thee->frmt == VIO_ASC) {
01457                         VJMPERR1( asc_double( thee->axdr, dval ) );
01458                     } else if (thee->frmt == VIO_XDR) {
01459                         VJMPERR1( xdr_double( thee->axdr, dval ) );
01460                     } else { VASSERT( 0 ); }
01461                     tokCount++;
01462                     i+=3;
01463                 } else { VJMPERR1( 0 ); }
01464             } else { VJMPERR1( 0 ); }
01465         } else { VJMPERR1( 0 ); }
01466     }
01467     va_end(ap);
01468 
01469     /* return without error */
01470     return tokCount;
01471 
01472   VERROR1:
01473     va_end(ap);
01474     /* fprintf(stderr,"Vio_scanf: Format problem with input.\n"); */
01475   VERROR2:
01476     thee->error = 1;
01477     return 0;
01478 }
01479 
01480 /*
01481  * ***************************************************************************
01482  * Routine:  Vio_printf
01483  *
01484  * Purpose:  Mimic "printf" to an arbitrary Vio device.
01485  *
01486  * Author:   Michael Holst
01487  * ***************************************************************************
01488  */
01489 VPUBLIC int Vio_printf(Vio *thee, char *parms, ... )
01490 {
01491     va_list ap;
01492     char buf[VMAX_BUFSIZE];
01493     int len;
01494 
01495     char arg0, arg1, arg2, cval, *sval;
01496     int i, tokCount, ival;
01497     float fval;
01498     double dval;
01499 
01500     VJMPERR2( !thee->error );
01501     VJMPERR2( thee->rwkey == VIO_W );
01502 
01503     /* if ASCII data then use vsprintf to handle format specifier exactly */
01504     if (thee->frmt == VIO_ASC) {
01505         va_start(ap, parms);
01506         vsprintf(buf, parms, ap);
01507         va_end(ap);
01508         len = strlen(buf);
01509         return Vio_writePutBuffer(thee,buf,len);
01510     }
01511 
01512     /* if XDR data then we have to pick the format specifier apart... */
01513     len = strlen(parms);
01514     va_start(ap, parms);
01515     tokCount = 0;
01516     i = 0;
01517     while ( i < len ) {
01518         arg0 = parms[i];
01519         if ((arg0 == '%') && (i+1 < len)) {
01520             arg1 = parms[i+1];
01521             if ( arg1 == '%' ) {
01522                 i+=2;
01523             } else {
01524                 while (!strchr("scdfel",arg1)) {
01525                     i+=1;
01526                     arg1 = parms[i+1];
01527                     VJMPERR1( i+1 < len );
01528                 }
01529                 if ( arg1 == 's' ) {
01530                     sval = va_arg(ap, char*);
01531                     /* don't put comment strings into xdr files */
01532                     if (!strchr(thee->commChars,sval[0])) {
01533                         VJMPERR1( xdr_string(thee->axdr, &sval, strlen(sval)) );
01534                         tokCount++;
01535                     }
01536                     i+=2;
01537                 } else if ( arg1 == 'c' ) {
01538                     /* are char args always passed as int? ... */
01539                     cval = (char)va_arg(ap, int);  /* CAST FROM INT */
01540                     VJMPERR1( xdr_char( thee->axdr, &cval ) );
01541                     tokCount++;
01542                     i+=2;
01543                 } else if ( arg1 == 'd' ) {
01544                     ival = va_arg(ap, int);
01545                     VJMPERR1( xdr_int( thee->axdr, &ival ) );
01546                     tokCount++;
01547                     i+=2;
01548                 } else if ( arg1 == 'f' ) {
01549                     /* are float args always passed as double? ... */
01550                     fval = (float)va_arg(ap, double);  /* CAST FROM DOUBLE */
01551                     VJMPERR1( xdr_float( thee->axdr, &fval ) );
01552                     tokCount++;
01553                     i+=2;
01554                 } else if ( arg1 == 'e' ) {
01555                     /* are float args always passed as double? ... */
01556                     fval = (float)va_arg(ap, double);  /* CAST FROM DOUBLE */
01557                     VJMPERR1( xdr_float( thee->axdr, &fval ) );
01558                     tokCount++;
01559                     i+=2;
01560                 } else if (( arg1 == 'l' ) && ( i+2 < len )) {
01561                     arg2 = parms[i+2];
01562                     if ( arg2 == 'e' ) {
01563                         dval = va_arg(ap, double);
01564                         VJMPERR1( xdr_double( thee->axdr, &dval ) );
01565                         tokCount++;
01566                         i+=3;
01567                     } else { VJMPERR1( 0 ); }
01568                 } else { VJMPERR1( 0 ); }
01569             }
01570         } else {
01571             i+=1;
01572         }
01573     }
01574     va_end(ap);
01575 
01576     /* finally write out the XDR buffer */
01577     VJMPERR1( 0<=(len=xdr_getpos((XDR*)thee->axdr)) );
01578     VJMPERR1( Vio_writePutBuffer(thee,thee->ioBuffer,len) == len );
01579     VJMPERR1( xdr_setpos((XDR*)thee->axdr, 0) );
01580 
01581     /* return without error */
01582     return len;
01583 
01584   VERROR1:
01585     va_end(ap);
01586     fprintf(stderr,"Vio_printf: Format problem with output.\n");
01587 
01588   VERROR2:
01589     thee->error = 1;
01590     return 0;
01591 }
01592 
01593 /*
01594  * ***************************************************************************
01595  * Routine:  Vio_read
01596  *
01597  * Purpose:  Read (up to) bufsize characters into buf from input device.
01598  *
01599  * Notes:    The number of bytes read is returned.
01600  *
01601  *           It is not necessarily an error if the number of bytes read
01602  *           is less than bufsize (EOF may have been encountered).
01603  *
01604  *           Acts exactly like fread() or read().
01605  *
01606  * Author:   Michael Holst
01607  * ***************************************************************************
01608  */
01609 VPUBLIC int Vio_read(Vio *thee, char *buf, int bufsize)
01610 {
01611     int rc, i, ilen;
01612 
01613     VJMPERR2( !thee->error );
01614     VJMPERR2( thee->rwkey == VIO_R );
01615 
01616     rc = 0;
01617     if (bufsize > 0) {
01618         if ( (thee->type==VIO_SDIO)
01619           || (thee->type==VIO_FILE) ) {
01620             rc = fread(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
01621             /* CMIKE: if (rc!=bufsize), make SURE EOF was reached! */
01622         } else if (thee->type==VIO_BUFF) {
01623             ilen = VMIN2( bufsize, thee->VIObufferLen - thee->VIObufferPtr );
01624             for (i=0; i<ilen; i++)
01625                 buf[i] = thee->VIObuffer[thee->VIObufferPtr + i];
01626             thee->VIObufferPtr += ilen;
01627             rc = ilen;
01628         } else if ( (thee->type==VIO_UNIX)
01629                  || (thee->type==VIO_INET) ) {
01630             rc = readn(thee->soc, buf, (unsigned int)bufsize);
01631             /* CMIKE: if (rc!=bufsize), make SURE EOF was reached! */
01632         } else {
01633             fprintf(stderr,"Vio_read: Bad type found <%d>\n", thee->type);
01634             rc = 0;
01635             VJMPERR2( 0 );
01636         }
01637     }
01638 
01639     /* return without error */
01640     return rc;
01641 
01642   VERROR2:
01643     thee->error = 1;
01644     return 0;
01645 }
01646 
01647 /*
01648  * ***************************************************************************
01649  * Routine:  Vio_write
01650  *
01651  * Purpose:  Write bufsize characters from buf to output device.
01652  *
01653  * Notes:    The number of bytes written is returned.
01654  *
01655  *           On success, the returned bytecount is the same as the number
01656  *           of bytes in the input buffer.
01657  *
01658  *           On failure, the returned bytecount is less than the number
01659  *           of bytes in the input buffer.
01660  *
01661  *           Acts exactly like fwrite() or write().
01662  *
01663  * Author:   Michael Holst
01664  * ***************************************************************************
01665  */
01666 VPUBLIC int Vio_write(Vio *thee, char *buf, int bufsize)
01667 {
01668     int rc, i, isize;
01669     char *tmpBuf;
01670 
01671     VJMPERR2( !thee->error );
01672     VJMPERR2( thee->rwkey == VIO_W );
01673 
01674     rc = 0;
01675     if (bufsize > 0) {
01676         if ( (thee->type==VIO_SDIO)
01677           || (thee->type==VIO_FILE) ) {
01678             rc = fwrite(buf, sizeof(char), (unsigned int)bufsize, thee->fp);
01679             VJMPERR1( rc == bufsize );
01680         } else if (thee->type==VIO_BUFF) {
01681             while ( bufsize > (thee->VIObufferLen - thee->VIObufferPtr) ) {
01682                 isize = VMAX2( 1, 2*(thee->VIObufferLen) );
01683                 tmpBuf = (char*)calloc( isize, sizeof(char) );
01684                 VJMPERR1( tmpBuf != VNULL );
01685                 for (i=0; i<thee->VIObufferLen; i++)
01686                     tmpBuf[i] = thee->VIObuffer[i];
01687                 free( thee->VIObuffer );
01688                 thee->VIObuffer = tmpBuf;
01689                 thee->VIObufferLen = isize;
01690             }
01691             for (i=0; i<bufsize; i++)
01692                 thee->VIObuffer[thee->VIObufferPtr + i] = buf[i];
01693             thee->VIObufferPtr += bufsize;
01694             rc = bufsize;
01695             VJMPERR1( rc == bufsize );
01696         } else if ( (thee->type==VIO_UNIX)
01697                  || (thee->type==VIO_INET) ) {
01698             rc = writen(thee->so, buf, (unsigned int)bufsize);
01699             VJMPERR1( rc == bufsize );
01700         } else {
01701             fprintf(stderr,"Vio_write: Bad type found <%d>\n", thee->type);
01702             rc = 0;
01703             VJMPERR2( 0 );
01704         }
01705     }
01706 
01707     /* return without error */
01708     return rc;
01709 
01710   VERROR1:
01711     fprintf(stderr,"Vio_write: Error occurred (bailing out).\n");
01712   VERROR2:
01713     thee->error = 1;
01714     return 0;
01715 }
01716 
01717 /*
01718  * ***************************************************************************
01719  * Routine:  Vio_initIoPutBuffers
01720  *
01721  * Purpose:  Initialize the internal buffer.
01722  *
01723  * Author:   Michael Holst
01724  * ***************************************************************************
01725  */
01726 VPRIVATE void Vio_initIoPutBuffers(Vio *thee)
01727 {
01728     /* initialize the buffer space */
01729     memset(thee->ioBuffer,  '\0', sizeof(thee->ioBuffer));
01730     memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
01731     thee->ioBufferLen = 0;
01732     thee->putBufferLen = 0;
01733 }
01734 
01735 /*
01736  * ***************************************************************************
01737  * Routine:  Vio_purgePutBuffer
01738  *
01739  * Purpose:  Purge the internal buffer.
01740  *
01741  * Author:   Michael Holst
01742  * ***************************************************************************
01743  */
01744 VPRIVATE void Vio_purgePutBuffer(Vio *thee)
01745 {
01746     int len;
01747 
01748     VJMPERR2( !thee->error );
01749     VJMPERR2( thee->rwkey == VIO_W );
01750 
01751     len = thee->putBufferLen;
01752     if ( (thee->type==VIO_UNIX)
01753       || (thee->type==VIO_INET) ) {
01754         if ( Vio_write(thee,thee->putBuffer,len) != len ) {
01755             fprintf(stderr,
01756                "Vio_purgePutBuffer: Vio_write fail UNIX/INET sock <%s>"
01757                " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01758             VJMPERR2( 0 );
01759         }
01760         memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
01761     } else {
01762         fprintf(stderr,"Vio_purgePutBuffer: Bad type found <%d>\n",thee->type);
01763         VJMPERR2( 0 );
01764     }
01765 
01766     /* return without error */
01767     return;
01768 
01769   VERROR2:
01770     thee->error = 1;
01771     return;
01772 }
01773 
01774 /*
01775  * ***************************************************************************
01776  * Routine:  Vio_writePutBuffer
01777  *
01778  * Purpose:  Write bufsize characters from buf to output device.
01779  *
01780  * Notes:    The number of bytes written is returned.
01781  *
01782  *           On success, the returned bytecount is the same as the number
01783  *           of bytes in the input buffer.
01784  *
01785  *           On failure, the returned bytecount is less than the number
01786  *           of bytes in the input buffer.
01787  *
01788  *           Acts exactly like fwrite() or write().
01789  *
01790  * Comment:  This is simply a buffered version of Vio_write().
01791  *           The Vio object maintains the buffer safely internally.
01792  *
01793  * Author:   Michael Holst
01794  * ***************************************************************************
01795  */
01796 VPRIVATE int Vio_writePutBuffer(Vio *thee, char *buf, int bufsize)
01797 {
01798     int i, curLen;
01799 
01800     VJMPERR2( !thee->error );
01801     VJMPERR2( thee->rwkey == VIO_W );
01802 
01803     /* attempt to buffer the i/o to get some speed */
01804     if ( (thee->type==VIO_SDIO)
01805       || (thee->type==VIO_FILE)
01806       || (thee->type==VIO_BUFF) ) {
01807 
01808         if ( Vio_write(thee,buf,bufsize) != bufsize ) {
01809             fprintf(stderr,
01810                 "Vio_writePutBuffer: Vio_write(1) fail FILE sock <%s>"
01811                 " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01812             VJMPERR2( 0 );
01813         }
01814 
01815     } else if ( (thee->type==VIO_UNIX)
01816              || (thee->type==VIO_INET) ) {
01817 
01818         /* incoming data is larger than our buffer */
01819         if (bufsize > (int)sizeof(thee->putBuffer)) {
01820 
01821             /* just do a normal unbuffered socket write */
01822             if ( Vio_write(thee,buf,bufsize) != bufsize ) {
01823                 fprintf(stderr, "Vio_writePutBuffer: Vio_write(2) fail"
01824                     " UNIX/INET sock <%s>"
01825                     " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01826                 VJMPERR2( 0 );
01827             }
01828 
01829         /* incoming data will fit in our buffer */
01830         } else {
01831 
01832             curLen = thee->putBufferLen;
01833 
01834             /* it fits in now -- just cat it to the end of the buffer */
01835             if ( (curLen + bufsize) <= (int)sizeof(thee->putBuffer) ) {
01836                 for (i=0; i<bufsize; i++)
01837                     thee->putBuffer[curLen+i] = buf[i];
01838                 thee->putBufferLen += bufsize;
01839 
01840             /* it won't fit until we write out the existing buffer */
01841             } else {
01842                 if ( Vio_write(thee,thee->putBuffer,curLen) != curLen ) {
01843                     fprintf(stderr, "Vio_writePutBuffer: Vio_write(3)"
01844                      " fail UNIX/INET sock <%s>"
01845                      " dueto <%s>\n", thee->file, VIOstrerrno(errno));
01846                     VJMPERR2( 0 );
01847                 }
01848                 thee->putBufferLen = 0;
01849                 memset(thee->putBuffer, '\0', sizeof(thee->putBuffer));
01850                 for (i=0; i<bufsize; i++)
01851                     thee->putBuffer[i] = buf[i];
01852                 thee->putBufferLen += bufsize;
01853             }
01854         }
01855 
01856     } else {
01857         fprintf(stderr,"Vio_writePutBuffer: Bad type found <%d>\n",thee->type);
01858         VJMPERR2( 0 );
01859     }
01860 
01861     /* return without error */
01862     return bufsize;
01863 
01864   VERROR2:
01865     thee->error = 1;
01866     return 0;
01867 }
01868 
01869 /*
01870  * ***************************************************************************
01871  * Routine:  ascmem_create, asc_destroy, asc_getpos, asc_setpos
01872  *           asc_string, asc_char, asc_int, asc_float, asc_double
01873  *           asc_setWhiteChars, asc_setCommChars, asc_getToken
01874  *
01875  * Purpose:  An ASC (i.e. ASCII) dual to the XDR routines.
01876  *
01877  * Notes:    These routines basically function idential to the XDR routines,
01878  *           except that after calling the constructor <ascmem_create>, one
01879  *           must call two additional routines, <asc_setWhiteChars> and
01880  *           <asc_setCommChars>, to specify the strings representing the
01881  *           whitespace in the ASCII stream separating the tokens, and a set
01882  *           of possible comment characters which generate skips to a newline.
01883  *
01884  *           The only complicated routine is <asc_genToken>, on which
01885  *           most of the other things rest.
01886  *
01887  *           Both ASC_ENCODE (write) and ASC_DECODE (read) directions work.
01888  *           In ASC_ENCODE mode, the tokens are separated by a single newline
01889  *           (for lack of anything more intelligent to do...).
01890  *
01891  * Author:   Michael Holst
01892  * ***************************************************************************
01893  */
01894 
01895 /*
01896  * ***************************************************************************
01897  * Routine:  ascmem_create
01898  *
01899  * Purpose:  Create the ASC structure.
01900  *
01901  * Author:   Michael Holst
01902  * ***************************************************************************
01903  */
01904 VPRIVATE void ascmem_create(ASC *thee, char *buf, int size, ASCmode mode)
01905 {
01906     thee->mode = mode;
01907     thee->pos  = 0;
01908     thee->size = size;
01909     thee->buf  = buf;
01910     memset(thee->whiteChars, '\0', VMAX_ARGNUM);
01911     memset(thee->commChars,  '\0', VMAX_ARGNUM);
01912 }
01913 
01914 /*
01915  * ***************************************************************************
01916  * Routine:  asc_destroy
01917  *
01918  * Purpose:  Destroy the ASC structure.
01919  *
01920  * Author:   Michael Holst
01921  * ***************************************************************************
01922  */
01923 VPRIVATE void asc_destroy(ASC *thee)
01924 {
01925     thee->mode = ASC_NO_MODE;
01926     thee->pos  = 0;
01927     thee->size = 0;
01928     thee->buf  = VNULL;
01929     memset(thee->whiteChars, '\0', VMAX_ARGNUM);
01930     memset(thee->commChars,  '\0', VMAX_ARGNUM);
01931 }
01932 
01933 /*
01934  * ***************************************************************************
01935  * Routine:  asc_getpos
01936  *
01937  * Purpose:  Return the current position in the ASC stream.
01938  *
01939  * Author:   Michael Holst
01940  * ***************************************************************************
01941  */
01942 VPRIVATE int asc_getpos(ASC *thee)
01943 {
01944     return thee->pos;
01945 }
01946 
01947 /*
01948  * ***************************************************************************
01949  * Routine:  asc_setpos
01950  *
01951  * Purpose:  Set the current position in the ASC stream.
01952  *
01953  * Author:   Michael Holst
01954  * ***************************************************************************
01955  */
01956 VPRIVATE int asc_setpos(ASC *thee, int pos)
01957 {
01958     thee->pos = pos;
01959     return 1;
01960 }
01961 
01962 /*
01963  * ***************************************************************************
01964  * Routine:  asc_string
01965  *
01966  * Purpose:  DECODE or ENCODE a string.
01967  *
01968  * Author:   Michael Holst
01969  * ***************************************************************************
01970  */
01971 VPRIVATE int asc_string(ASC *thee, char **sval, int size)
01972 {
01973     int i, len;
01974     char tok[VMAX_BUFSIZE];
01975 
01976     if (thee->mode == ASC_DECODE) {
01977         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
01978         sscanf(tok,"%s",(*sval));
01979     } else if (thee->mode == ASC_ENCODE) {
01980         sprintf(tok,"%s\n",*sval);
01981         len = strlen(tok);
01982         for (i=0; i<len; i++)
01983             thee->buf[thee->pos+i] = tok[i];
01984         thee->pos += len;
01985     }
01986     return 1;
01987 
01988   VERROR1:
01989     return 0;
01990 }
01991 
01992 /*
01993  * ***************************************************************************
01994  * Routine:  asc_char
01995  *
01996  * Purpose:  DECODE or ENCODE a char.
01997  *
01998  * Author:   Michael Holst
01999  * ***************************************************************************
02000  */
02001 VPRIVATE int asc_char(ASC *thee, char *cval)
02002 {
02003     int i, len;
02004     char tok[VMAX_BUFSIZE];
02005 
02006     if (thee->mode == ASC_DECODE) {
02007         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
02008         sscanf(tok,"%c",cval);
02009     } else if (thee->mode == ASC_ENCODE) {
02010         sprintf(tok,"%c\n",*cval);
02011         len = strlen(tok);
02012         for (i=0; i<len; i++)
02013             thee->buf[thee->pos+i] = tok[i];
02014         thee->pos += len;
02015     }
02016     return 1;
02017 
02018   VERROR1:
02019     return 0;
02020 }
02021 
02022 /*
02023  * ***************************************************************************
02024  * Routine:  asc_int
02025  *
02026  * Purpose:  DECODE or ENCODE an int.
02027  *
02028  * Author:   Michael Holst
02029  * ***************************************************************************
02030  */
02031 VPRIVATE int asc_int(ASC *thee, int *ival)
02032 {
02033     int i, len;
02034     char tok[VMAX_BUFSIZE];
02035 
02036     if (thee->mode == ASC_DECODE) {
02037         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
02038         sscanf(tok,"%d",ival);
02039     } else if (thee->mode == ASC_ENCODE) {
02040         sprintf(tok,"%d\n",*ival);
02041         len = strlen(tok);
02042         for (i=0; i<len; i++)
02043             thee->buf[thee->pos+i] = tok[i];
02044         thee->pos += len;
02045     }
02046     return 1;
02047 
02048   VERROR1:
02049     return 0;
02050 }
02051 
02052 /*
02053  * ***************************************************************************
02054  * Routine:  asc_float
02055  *
02056  * Purpose:  DECODE or ENCODE a float.
02057  *
02058  * Author:   Michael Holst
02059  * ***************************************************************************
02060  */
02061 VPRIVATE int asc_float(ASC *thee, float *fval)
02062 {
02063     int i, len;
02064     char tok[VMAX_BUFSIZE];
02065 
02066     if (thee->mode == ASC_DECODE) {
02067         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
02068         sscanf(tok,"%e",fval);
02069     } else if (thee->mode == ASC_ENCODE) {
02070         sprintf(tok,"%e\n",*fval);
02071         len = strlen(tok);
02072         for (i=0; i<len; i++)
02073             thee->buf[thee->pos+i] = tok[i];
02074         thee->pos += len;
02075     }
02076     return 1;
02077 
02078   VERROR1:
02079     return 0;
02080 }
02081 
02082 /*
02083  * ***************************************************************************
02084  * Routine:  asc_double
02085  *
02086  * Purpose:  DECODE or ENCODE a double.
02087  *
02088  * Author:   Michael Holst
02089  * ***************************************************************************
02090  */
02091 VPRIVATE int asc_double(ASC *thee, double *dval)
02092 {
02093     int i, len;
02094     char tok[VMAX_BUFSIZE];
02095 
02096     if (thee->mode == ASC_DECODE) {
02097         VJMPERR1( VNULL != asc_getToken(thee, tok, VMAX_BUFSIZE) );
02098         sscanf(tok,"%le",dval);
02099     } else if (thee->mode == ASC_ENCODE) {
02100         sprintf(tok,"%e\n",*dval);
02101         len = strlen(tok);
02102         for (i=0; i<len; i++)
02103             thee->buf[thee->pos+i] = tok[i];
02104         thee->pos += len;
02105     }
02106     return 1;
02107 
02108   VERROR1:
02109     return 0;
02110 }
02111 
02112 /*
02113  * ***************************************************************************
02114  * Routine:  asc_setWhiteChars
02115  *
02116  * Purpose:  Define the white character set.
02117  *
02118  * Author:   Michael Holst
02119  * ***************************************************************************
02120  */
02121 VPRIVATE void asc_setWhiteChars(ASC *thee, char *whiteChars)
02122 {
02123     strncpy(thee->whiteChars, whiteChars, VMAX_ARGNUM);
02124 }
02125 
02126 /*
02127  * ***************************************************************************
02128  * Routine:  asc_setCommChars
02129  *
02130  * Purpose:  Define the comment character set.
02131  *
02132  * Author:   Michael Holst
02133  * ***************************************************************************
02134  */
02135 VPRIVATE void asc_setCommChars(ASC *thee, char *commChars)
02136 {
02137     strncpy(thee->commChars, commChars, VMAX_ARGNUM);
02138 }
02139 
02140 /*
02141  * ***************************************************************************
02142  * Routine:  asc_getToken
02143  *
02144  * Purpose:  Get the next token from the input stream.
02145  *
02146  * Author:   Michael Holst
02147  * ***************************************************************************
02148  */
02149 VPRIVATE char* asc_getToken(ASC *thee, char *tok, int toksize)
02150 {
02151     int i, ii, jj, done;
02152     if (thee->mode == ASC_DECODE) {
02153 
02154         /* first clear the token buffer */
02155         memset(tok, '\0', toksize);
02156 
02157         /* set "ii" ptr to the first token character */
02158         ii = thee->pos;
02159         done = 0;
02160         while ( !done ) {
02161 
02162             /* if whiteChar then just skip that character */
02163             if ( strchr(thee->whiteChars,thee->buf[ii]) ) {
02164                 ii++;
02165                 VJMPERR1( ii < thee->size );
02166 
02167             /* if commChar then skip to the next newline and keep going */
02168             } else if ( strchr(thee->commChars,thee->buf[ii]) ) {
02169                 ii++;
02170                 VJMPERR1( ii < thee->size );
02171                 while ( thee->buf[ii] != '\n' ) {
02172                     ii++;
02173                     VJMPERR1( ii < thee->size );
02174                 }
02175 
02176             /* this must be the first token character */
02177             } else {
02178                 done = 1;
02179             }
02180         }
02181 
02182         /* set "jj" ptr to the first character (white or comm) after token */
02183         jj = ii+1;
02184         done = 0;
02185         while ( !done ) {
02186             VJMPERR1( jj < thee->size );
02187 
02188             /* if whiteChar then we are done */
02189             if ( strchr(thee->whiteChars,thee->buf[jj]) ) {
02190                 done = 1;
02191 
02192             /* if commChar then we are done */
02193             } else if ( strchr(thee->commChars,thee->buf[jj]) ) {
02194                 done = 1;
02195 
02196             /* this must be another token character */
02197             } else {
02198                 jj++;
02199             }
02200         }
02201 
02202         /* error control */
02203         VJMPERR1( (jj-ii) <= toksize );
02204         VJMPERR1( jj <= thee->size );
02205 
02206         /* copy the characters between ii and jj to the output string */
02207         for (i=ii; i<jj; i++)
02208             tok[i-ii] = thee->buf[i];
02209         tok[jj] = '\0';
02210 
02211         /* update the position pointer */
02212         thee->pos = jj;
02213 
02214     } else if (thee->mode == ASC_ENCODE) {
02215         fprintf(stderr,"asc_getToken: Don't know how to ENCODE yet!\n");
02216     }
02217 
02218     return tok;
02219 
02220   VERROR1:
02221     /* fprintf(stderr,"asc_getToken: Error occurred (bailing out).\n"); */
02222     return VNULL;
02223 }
02224 
02225 /*
02226  * ***************************************************************************
02227  * Routine:  readn
02228  *
02229  * Purpose:  A fixed-up file-descriptor read (for UNIX/INET).
02230  *
02231  * Notes:    Fixes the "short read" problem if the operating system
02232  *           is interrupted during the read.  Calls the usual 
02233  *           file-descriptor read repeatedly until n characters are 
02234  *           actually read in.  Returns the number of characters 
02235  *           actually read in.  Returns -1 on error.
02236  *
02237  *           Includes my WINSOCK fixes (err, rather hacks).
02238  *
02239  * Author:   Michael Holst (first of two jewels from Rick Stevens' book)
02240  * ***************************************************************************
02241  */
02242 VPRIVATE int readn(int fd, void *vptr, unsigned int n)
02243 {
02244     char *ptr;
02245     unsigned int nleft;
02246     int  nread;
02247 
02248     ptr = vptr;
02249     nleft = n;
02250     while (nleft > 0) {
02251         if ((nread = recv(fd,ptr,nleft,0)) < 0) {
02252 #if defined(HAVE_WINSOCK_H)
02253             if (WSAGetLastError() == WSAEINTR) {
02254                 nread = 0;
02255             } else if (WSAGetLastError() == WSAEWOULDBLOCK) {
02256                 nread = 0;
02257             } else { return(-1); }
02258 #else
02259             if (errno == EINTR) {
02260                 nread = 0;
02261             } else if (errno == EWOULDBLOCK) {
02262                 nread = 0;
02263             } else { return(-1); }
02264 #endif
02265         } else if (nread == 0) {
02266             break;
02267         }
02268         nleft -= nread;
02269         ptr += nread;
02270     }
02271     return (n-nleft);
02272 }
02273 
02274 /*
02275  * ***************************************************************************
02276  * Routine:  writen
02277  *
02278  * Purpose:  A fixed-up file-descriptor write (for UNIX/INET).
02279  *
02280  * Notes:    Fixes the "short write" problem if the operating system
02281  *           has buffer overflow problems.  Calls the usual 
02282  *           file-descriptor write repeatedly until the input buffer 
02283  *           actually gets written out.  Returns the number of 
02284  *           characters actually written out.  Returns -1 on error.
02285  *
02286  * Author:   Michael Holst (second of two jewels from Rick Stevens' book)
02287  * ***************************************************************************
02288  */
02289 VPRIVATE int writen(int fd, void *vptr, unsigned int n)
02290 {
02291     char *ptr;
02292     unsigned int nleft;
02293     int  nwritten;
02294 
02295     ptr = vptr;
02296     nleft = n;
02297     while (nleft > 0) {
02298         if ((nwritten = send(fd,ptr,nleft,0)) <= 0) {
02299             if (errno == EINTR) {
02300                 nwritten = 0;
02301             } else {
02302                 return(-1);
02303             }
02304         }
02305         nleft -= nwritten;
02306         ptr += nwritten;
02307     }
02308     return(n);
02309 }
02310 
02311 /*
02312  * ***************************************************************************
02313  * Routine:  Vio_bufTake
02314  *
02315  * Purpose:  Set the pointer to the internal buffer.
02316  *
02317  * Author:   Michael Holst
02318  * ***************************************************************************
02319  */
02320 VPUBLIC void Vio_bufTake(Vio *thee, char *buf, int bufsize)
02321 {
02322     /* make sure Vio was started */
02323     VJMPERR1( VIOstarted );
02324 
02325     /* clear the internal buffer */
02326     if (thee->VIObuffer != VNULL) {
02327         free( thee->VIObuffer );
02328         thee->VIObuffer = VNULL;
02329     }
02330 
02331     /* now set the buffer */
02332     thee->VIObuffer    = buf;
02333     thee->VIObufferLen = bufsize;
02334     thee->VIObufferPtr = 0;
02335 
02336     /* return without error */
02337     return;
02338 
02339   VERROR1:
02340     fprintf(stderr,"Vio_bufTake: Vio library has not been started.\n");
02341     return;
02342 }
02343 
02344 /*
02345  * ***************************************************************************
02346  * Routine:  Vio_bufGive
02347  *
02348  * Purpose:  Return the pointer to the internal buffer.
02349  *
02350  * Author:   Michael Holst
02351  * ***************************************************************************
02352  */
02353 VPUBLIC char* Vio_bufGive(Vio *thee)
02354 {
02355     char *tmp;
02356 
02357     /* make sure Vio was started */
02358     VJMPERR1( VIOstarted );
02359 
02360     /* grab the pointer */
02361     tmp = thee->VIObuffer;
02362 
02363     /* reset things for the hand-off */
02364     thee->VIObufferLen = 0;
02365     thee->VIObuffer = VNULL;
02366 
02367     /* return without error */
02368     return tmp;
02369 
02370   VERROR1:
02371     fprintf(stderr,"Vio_bufGive: Vio library has not been started.\n");
02372     return VNULL;
02373 }
02374 
02375 /*
02376  * ***************************************************************************
02377  * Routine:  Vio_bufSize
02378  *
02379  * Purpose:  Return the length of the internal buffer.
02380  *
02381  * Author:   Michael Holst
02382  * ***************************************************************************
02383  */
02384 VPUBLIC int Vio_bufSize(Vio *thee)
02385 {
02386     /* make sure Vio was started */
02387     VJMPERR1( VIOstarted );
02388 
02389     /* return without error */
02390     return thee->VIObufferLen;
02391 
02392   VERROR1:
02393     fprintf(stderr,"Vio_bufSize: Vio library has not been started.\n");
02394     return 0;
02395 }
02396 
02397 /*
02398  * ***************************************************************************
02399  * Routine:  Vio_socketOpen
02400  *
02401  * Purpose:  Socket open for read or write.
02402  *
02403  * Author:   Michael Holst
02404  * ***************************************************************************
02405  */
02406 VPUBLIC Vio *Vio_socketOpen(char *key,
02407     const char *iodev, const char *iofmt,
02408     const char *iohost, const char *iofile)
02409 {
02410     static Vio *sock;
02411 
02412     /* make sure Vio was started */
02413     VJMPERR1( VIOstarted );
02414 
02415     /* setup for a read */
02416     if (!strcmp("r",key)) {
02417 
02418         /* Open device for READ */
02419         if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"r")) ) {
02420             fprintf(stderr,"Vio_socketOpen: Problem opening(read) <%s>\n",
02421                 iofile);
02422             VJMPERR2( 0 );
02423         }
02424 
02425         /* START READ (blocking accept) */
02426         if ( 0 > Vio_accept(sock,0) ) {
02427             fprintf(stderr,"Vio_socketOpen: Problem accepting(read) <%s>\n",
02428                 iofile);
02429             /* destroy the socket before we return */
02430             Vio_dtor( &sock );
02431             VJMPERR2( 0 );
02432         }
02433 
02434     /* setup for a write */
02435     } else if (!strcmp("w",key)) {
02436 
02437         /* Open device for WRITE */
02438         if ( VNULL == (sock=Vio_ctor(iodev,iofmt,iohost,iofile,"w")) ) {
02439             fprintf(stderr,"Vio_socketOpen: Problem opening(write) <%s>\n",
02440                 iofile);
02441             VJMPERR2( 0 );
02442         }
02443 
02444         /* START WRITE (blocking connect) */
02445         if ( 0 > Vio_connect(sock,0) ) {
02446             fprintf(stderr,"Vio_socketOpen: Problem connecting(write) <%s>\n",
02447                 iofile);
02448             /* destroy the socket before we return */
02449             Vio_dtor( &sock );
02450             VJMPERR2( 0 );
02451         }
02452 
02453     } else {
02454         fprintf(stderr,"Vio_socketOpen: Internal logic error.\n");
02455         VJMPERR2( 0 );
02456     }
02457 
02458     /* some i/o */
02459 #if 0
02460     fprintf(stderr,"Vio_socketOpen: iodev =<%s>\n", iodev);
02461     fprintf(stderr,"Vio_socketOpen: iofmt =<%s>\n", iofmt);
02462     fprintf(stderr,"Vio_socketOpen: iohost=<%s>\n", iohost);
02463     fprintf(stderr,"Vio_socketOpen: iofile=<%s>\n", iofile);
02464 #endif
02465 
02466     /* return without error */
02467     return sock;
02468 
02469   VERROR1:
02470     fprintf(stderr,"Vio_socketOpen: Vio library has not been started.\n");
02471     return VNULL;
02472 
02473   VERROR2: 
02474     fprintf(stderr,"Vio_socketOpen: bailing out.\n");
02475     return VNULL; 
02476 }
02477 
02478 /*
02479  * ***************************************************************************
02480  * Routine:  Vio_socketClose
02481  *
02482  * Purpose:  Socket close from read or write.
02483  *
02484  * Author:   Michael Holst
02485  * ***************************************************************************
02486  */
02487 VPUBLIC void Vio_socketClose(Vio **sock)
02488 {
02489     /* make sure Vio was started */
02490     VJMPERR1( VIOstarted );
02491 
02492     VJMPERR2( VNULL != *sock );
02493 
02494     /* FINISH READ (release subsocket if we had one) */
02495     if ((*sock)->rwkey == VIO_R) {
02496         Vio_acceptFree(*sock);
02497 
02498     /* FINISH WRITE */
02499     } else if ((*sock)->rwkey == VIO_W) {
02500         Vio_connectFree(*sock);
02501 
02502     /* Problems... */
02503     } else {
02504         VJMPERR2( 0 );
02505     }
02506 
02507     /* return without error */
02508     Vio_dtor(sock);
02509     return;
02510 
02511   VERROR1:
02512     fprintf(stderr,"Vio_socketClose: Vio library has not been started.\n");
02513     return;
02514 
02515   VERROR2: 
02516     fprintf(stderr,"Vio_socketClose: bailing out.\n");
02517     return; 
02518 }
02519 

Generated on Wed Oct 20 2010 11:12:15 for APBS by  doxygen 1.7.2