Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

ws_clientII.c

Go to the documentation of this file.
00001 
00002 /*
00003  *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
00004  *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
00005  *
00006  *    $Id: ws__clientII_8c-source.html 2161 2006-05-19 16:55:03Z paulf $
00007  *
00008  *    Revision history:
00009  *     $Log$
00009  *     Revision 1.1  2006/05/19 16:55:03  paulf
00009  *     first inclusion
00009  *
00010  *     Revision 1.5  2002/03/19 22:15:15  davidk
00011  *     Fixed bug reported by IlyaDricker in wsGetTraceBin() where the function
00012  *     was not correctly handling the return code from wsParseBinHeaderReply().
00013  *
00014  *     Revision 1.4  2001/04/17 17:31:41  davidk
00015  *     Added explicit (SOCKET) typecasts in FD_SET to get rid of compiler warnings on NT.
00016  *
00017  *     Revision 1.3  2000/09/17 18:37:57  lombard
00018  *     wsSearchSCN now really returns the first menu with matching scn.
00019  *     wsGetTraceBin will now try another server if the first returns a gap.
00020  *
00021  *     Revision 1.2  2000/03/08 18:14:06  luetgert
00022  *     fixed memmove problem in wsParseAsciiHeaderReply.
00023  *
00024  *     Revision 1.1  2000/02/14 18:51:48  lucky
00025  *     Initial revision
00026  *
00027  *
00028  */
00029 
00030 /* Version II of WaveServerIV client utility routines. This file contains
00031  * various routines useful for dealing with WaveServerIV and beyond. */
00032 
00033 /* 5/17/98: Fixed bug in wsWaitAscii: it would fill reply buffer but never
00034  * report overflow. PNL */
00035 
00036 /* The philosophy behind the version II changes is:
00037  * - Leave sockets open unless there is an error on the socket; calling 
00038  *   progam should ensure all sockets are closed before it quits.
00039  * - Routines are thread-safe. However, the calling thread must ensure its
00040  *   socket descriptors are unique or mutexed so that requests and replies
00041  *   can't overlap.
00042  * - Routines are layered on top of Dave Kragness's socket wrappers and thus
00043  *   do no timing themselves. Exceptions to this are wsWaitAscii and 
00044  *   wsWaitBinHeader which need special timing of recv().
00045  * Pete Lombard, University of Washington Geophysics; 1/4/98
00046  */
00047 
00048 #include <stdio.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <time.h>
00052 #include <errno.h>
00053 #include <earthworm.h>
00054 #include <ws_clientII.h>
00055 #include <socket_ew.h>
00056 #include <time_ew.h>
00057 
00058 #define WS_MAX_RECV_BUF_LEN 4096
00059 
00060 static int menu_reqid = 0;
00061 int WS_CL_DEBUG = 0;
00062 
00063 extern int recv_all (SOCKET, char FAR*,int,int,int);
00064 
00065 
00066 /* Protoypes for internal functions */
00067 static int  wsWaitAscii( WS_MENU, char*, int, int );
00068 static int  wsWaitBinHeader( WS_MENU, char*, int, int );
00069 static int  wsParseMenuReply( WS_MENU, char* );
00070 static int  wsParseBinHeaderReply( TRACE_REQ*, char* );
00071 static int  wsParseAsciiHeaderReply( TRACE_REQ*, char* );
00072 static void wsSkipN( char*, int, int* );
00073 struct timeval FAR * resetTimeout(struct timeval FAR *);
00074 Time_ew adjustTimeoutLength(int timeout_msec);
00075 
00076 /**************************************************************************
00077  *      wsAppendMenu: builds a combined menu from many waveservers.       *
00078  *      Called with the address and port of one waveserver.               *
00079  *      On the first call it creates a linked list to store the 'menu'    *
00080  *      reply from the indicated waveserver.                              *
00081  *      On subsequent calls, it appends the menu replies to the list.     *
00082  **************************************************************************/
00083 
00084 int wsAppendMenu( char* ipAdr, char* port, WS_MENU_QUEUE_REC* menu_queue, 
00085                   int timeout )
00086      /*
00087 Arguments:
00088          ipAdr:  is the dot form of the IP address as a char string.
00089           port:  TCP port number as a char string.
00090     menu_queue:  caller-supplied pointer to the list of menus.
00091        timeout:  timeout interval in milliseconds,
00092         return:  WS_ERR_NONE:  if all went well.
00093                  WS_ERR_NO_CONNECTION: if we could not get a connection.
00094                  WS_ERR_SOCKET: if we could not create a socket.
00095                  WS_ERR_BROKEN_CONNECTION:  if the connection broke.
00096                  WS_ERR_TIMEOUT: if a timeout occured.
00097                  WS_ERR_MEMORY: if out of memory.
00098                  WS_ERR_INPUT: if bad input parameters.
00099                  WS_ERR_PARSE: if parser failed.
00100 */
00101 {
00102   int ret, len, err;
00103   WS_MENU menu = NULL;
00104   char request[wsREQLEN];
00105   char* reply = NULL;
00106 
00107   if ( !ipAdr || !port ||
00108        (strlen(ipAdr) >= wsADRLEN) || (strlen(port) >= wsADRLEN) )
00109     {
00110       ret = WS_ERR_INPUT;
00111       if (WS_CL_DEBUG) logit("e","wsAppendMenu: bad address: %s port: %s\n",
00112                              ipAdr, port);
00113       goto Abort;
00114     }
00115 
00116   menu = ( WS_MENU_REC* )calloc(sizeof(WS_MENU_REC),1);
00117   reply = ( char* )malloc( wsREPLEN );
00118   if ( !menu || !reply )
00119     {
00120       ret = WS_ERR_MEMORY;
00121       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: memory allocation error\n");
00122       goto Abort;
00123     }
00124 
00125   strcpy( menu->addr, ipAdr );
00126   strcpy( menu->port, port );
00127   if ( wsAttachServer( menu, timeout ) != WS_ERR_NONE )
00128     {
00129       ret = WS_ERR_NO_CONNECTION;
00130       goto Abort;
00131     }
00132 
00133   sprintf( request, "MENU: %d \n", menu_reqid++ );
00134   len = strlen(request);
00135   if ( ( ret =  send_ew( menu->sock, request, len, 0, timeout ) ) != len ) {
00136     if (ret < 0 )
00137     {
00138       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: connection broke to server %s:%s\n",
00139                              ipAdr, port);
00140       ret = WS_ERR_BROKEN_CONNECTION;
00141     } else {
00142       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: server %s:%s timed out\n",
00143                              ipAdr, port);
00144       ret = WS_ERR_TIMEOUT;
00145     }
00146     goto Abort;
00147   }
00148 
00149   ret = wsWaitAscii( menu, reply, wsREPLEN, timeout );
00150   if ( ret != WS_ERR_NONE && ret != WS_ERR_BUFFER_OVERFLOW )
00151     /* we might have received some useful data in spite of the overflow */
00152     {
00153       goto Abort;
00154     }
00155 
00156   if ( ( err = wsParseMenuReply( menu, reply ) ) != WS_ERR_NONE )
00157     {
00158       if ( ret == WS_ERR_BUFFER_OVERFLOW && err == WS_ERR_PARSE )
00159         {
00160           if (WS_CL_DEBUG) logit("e", "wsAppendMenu: buffer overflow; parse failure\n");
00161         } 
00162       else
00163         {
00164           ret = err;
00165         }
00166       goto Abort;
00167     }
00168 
00169   if ( menu->pscn == NULL )
00170     {
00171       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: no SCN at server %s:%s\n",
00172                              menu->addr, menu->port);
00173       ret = WS_ERR_EMPTY_MENU;
00174       goto Abort;
00175     }
00176   
00177   /* Add the menu to the possibly empty menu queue */
00178   if ( !menu_queue->head )
00179     {
00180       menu_queue->head = menu_queue->tail = menu;
00181     }
00182   else
00183     {
00184       menu_queue->tail->next = menu;
00185       menu_queue->tail = menu;
00186     }
00187   if ( reply ) free( reply );
00188   return WS_ERR_NONE;
00189 
00190 Abort:
00191   /* An error occured, so clean up the mess */
00192   wsDetachServer( menu );
00193   if ( reply ) free( reply );
00194   if ( menu )
00195     {
00196       wsKillPSCN( menu->pscn );
00197       free( menu );
00198     }
00199   return ret;
00200 }
00201 
00202 
00203 /************************************************************************** 
00204  * wsKillMenu: Gracefully closes all the server sockets and releases the  *
00205  *             linked list of menus created by wsAppendMenu               *
00206  **************************************************************************/
00207 void wsKillMenu( WS_MENU_QUEUE_REC* menu_queue )
00208      /*
00209 Arguments:
00210     menu_queue:  caller-supplied pointer to the list of menus.
00211     */
00212 {
00213   WS_MENU menu = menu_queue->head;
00214 
00215   while ( menu )
00216     {
00217       WS_MENU next = menu->next;
00218 
00219       if ( menu->sock != -1 )
00220         closesocket_ew( menu->sock, SOCKET_CLOSE_GRACEFULLY_EW );
00221       wsKillPSCN( menu->pscn );
00222       free( menu );
00223       menu = next;
00224     }
00225   menu_queue->head = menu_queue->tail = NULL;
00226   menu_reqid = 0;
00227 
00228   return;
00229 }
00230 
00231 
00232 /*********************************************************************
00233  * wsGetTraceBin: retrieves the piece of raw trace data specified in *
00234  * the structure 'getThis': The current menu list, as built by the   *
00235  * routines above will be searched for a matching SCN. If a match    *
00236  * is found, the associated wave server will be contacted, and a     *
00237  * request for the trace snippet will be made.                       *
00238  *********************************************************************/
00239 int wsGetTraceBin( TRACE_REQ* getThis, WS_MENU_QUEUE_REC* menu_queue,
00240                    int timeout )
00241      /*
00242 Arguments:
00243         getThis:   a TRACE_REQ structure (see ws_client.h), with the
00244                    request portion filled in.
00245      menu_queue:   pointer to the list of server menus.
00246         timeout:   Time in milliseconds to wait for reply
00247          return:   WS_ERR_NONE: all went well.
00248                    WS_WRN_FLAGGED: wave server returned error flag instead
00249                       of trace data.
00250                    WS_ERR_EMPTY_MENU: No menu list found.
00251                    WS_ERR_SCN_NOT_IN_MENU: SCN not found in menu list.
00252                    WS_ERR_NO_CONNECTION: if socket was already closed
00253           The socket will be closed for the following:
00254                    WS_ERR_BUFFER_OVERFLOW: trace buffer supplied too small.
00255                    WS_ERR_TIMEOUT: if a timeout occured
00256                    WS_ERR_BROKEN_CONNECTION: if a connection broke.
00257                    WS_ERR_SOCKET: problem changing socket options.
00258      */
00259 {
00260   int ret, len, err = WS_ERR_NONE;
00261   WS_MENU menu = NULL;
00262   WS_PSCN pscn = NULL;
00263   char request[wsREQLEN];
00264 
00265   if ( menu_queue->head == NULL )
00266     {
00267       if (WS_CL_DEBUG) logit("e", "wsGetTraceBin: empty menu\n");
00268       return WS_ERR_EMPTY_MENU;
00269     }
00270 
00271  next_menu:
00272   if ( ( ret = wsSearchSCN( getThis, &menu, &pscn, menu_queue )) != WS_ERR_NONE )
00273     {
00274       if (err != WS_ERR_NONE)
00275         return err;
00276       else
00277         return ret;  /* WS_ERR_SCN_NOT_IN_MENU */
00278     }
00279 
00280   if (menu->sock < 0) 
00281     {
00282       if (WS_CL_DEBUG) logit("e", "wsGetTraceBin: no socket for %s:%s\n", 
00283                              menu->addr, menu->port );
00284       return WS_ERR_NO_CONNECTION;
00285     }
00286 
00287   sprintf( request, "GETSCNRAW: %d %s %s %s %lf %lf\n",
00288            menu_reqid++, pscn->sta, pscn->chan, pscn->net,
00289            getThis->reqStarttime, getThis->reqEndtime );
00290 
00291   len = strlen(request);
00292   if ( (ret = send_ew( menu->sock, request, len, 0, timeout )) != len )
00293     {
00294       if (ret < 0 )
00295         {
00296           ret = WS_ERR_BROKEN_CONNECTION;
00297         } else {
00298           ret = WS_ERR_TIMEOUT;
00299         }
00300       goto Abort;
00301     }
00302 
00303   ret = wsWaitBinHeader( menu, getThis->pBuf, getThis->bufLen, timeout );
00304   switch (ret) {
00305   case WS_ERR_INPUT:
00306     return ret;
00307     break;
00308   case WS_ERR_NONE:
00309     break;
00310   default:
00311     /* buffer overflow, timeout, socket error, or broken connection */
00312       goto Abort;
00313   }
00314 
00315   err = wsParseBinHeaderReply( getThis, getThis->pBuf );
00316   switch (err) {
00317   case WS_ERR_INPUT:
00318   case WS_WRN_FLAGGED:  /* no trace data to get */
00319     goto next_menu;
00320     break;
00321   case WS_ERR_PARSE:  /* can't get pending trace data, so close socket */
00322     /* DK 03192002 setting ret due to bug reported by Ilya Dricker */
00323     if(ret == WS_ERR_NONE)
00324       ret = err;
00325     /* end DK 0319 change */
00326     goto Abort;
00327     break;
00328   default:  /* no error, so continue */
00329     break;
00330   }
00331   
00332   if ( getThis->actLen )
00333     {
00334       long int binLen = getThis->actLen;
00335       
00336       if ( (int)getThis->bufLen < binLen )
00337         binLen = (int)getThis->bufLen;
00338       ret = recv_all( menu->sock, getThis->pBuf, binLen, 0, timeout );
00339       
00340       if ( ret != binLen ) 
00341         {
00342           if ( ret < 0 )
00343             {
00344               ret = WS_ERR_BROKEN_CONNECTION;
00345             } 
00346           else 
00347             {
00348               ret = WS_ERR_TIMEOUT;
00349             }
00350           goto Abort;
00351         }
00352       
00353       if ( binLen < getThis->actLen ) 
00354         {
00355           getThis->actLen = binLen;
00356           ret = WS_ERR_BUFFER_OVERFLOW;
00357           if (WS_CL_DEBUG) logit ( "e", "wsGetTraceBin(): buffer full, trace truncated\n" );
00358           goto Abort;
00359         }
00360     }
00361   return WS_ERR_NONE;
00362   
00363 Abort:
00364   wsDetachServer( menu );
00365   if (WS_CL_DEBUG) 
00366     {
00367       if  ( ret == WS_ERR_TIMEOUT ) {
00368         logit( "e","wsGetTraceBin(): server %s:%s timed out\n", menu->addr,
00369                menu->sock );
00370       } else if ( ret == WS_ERR_BROKEN_CONNECTION ) {
00371         logit( "e","wsGetTraceBin(): broken connection to server %s:%s\n",
00372                menu->addr, menu->port);
00373       }
00374     }
00375   
00376   return ret;
00377 }
00378 
00379 /**************************************************************************
00380  *      wsGetTraceAscii: retrieves the ascii trace data specified in      *
00381  *      the structure 'getThis': The current menu list, as buit by the    *
00382  *      routines above will be searched for a matching SCN. If a match    *
00383  *      is found, the associated wave server will be contacted, and a     *
00384  *      request for the trace snippet will be made.                       *
00385  **************************************************************************/
00386 
00387 int wsGetTraceAscii( TRACE_REQ* getThis, WS_MENU_QUEUE_REC* menu_queue, 
00388                      int timeout )
00389      /*
00390 Arguments:
00391         getThis:   a TRACE_REQ structure (see ws_client.h), with the
00392                    request portion filled in.
00393      menu_queue:   pointer to list of menues.
00394         timeout:   timeout interval in milliseconds.
00395         return:    WS_ERR_NONE: all went well.
00396                    WS_ERR_EMPTY_MENU: No menu list found.
00397                    WS_ERR_SCN_NOT_IN_MENU: SCN not found in menu list.
00398                    WS_ERR_BUFFER_OVERFLOW: buffer too small for reply
00399                    WS_ERR_BROKEN_CONNECTION: couldn't talk to server
00400                    WS_ERR_TIMEOUT: if a timeout occured
00401                    WS_ERR_NO_CONNECTION: There was no connection for the server
00402                    WS_WRN_FLAGGED: wave server returned flag warning.
00403                      the flag character is in the TRACE_REQ structure.
00404                      */
00405 {
00406   int ret, len, err;
00407   WS_MENU menu = NULL;
00408   WS_PSCN pscn = NULL;
00409   char request[wsREQLEN];
00410   double expire = (double) 0.0;
00411   
00412   if ( menu_queue->head == NULL )
00413     {
00414       if (WS_CL_DEBUG) logit("e", "wsGetTraceAscii: empty menu\n");
00415       return WS_ERR_EMPTY_MENU;
00416     }
00417   
00418   if ( (ret = wsSearchSCN( getThis, &menu, &pscn, menu_queue  )) != WS_ERR_NONE )
00419     {
00420       return ret; /* WS_ERR_SCN_NOT_IN_MENU */
00421     }
00422                      
00423   if ( menu->sock < 0 )
00424     {
00425       if (WS_CL_DEBUG) logit("e", "wsGetTraceAscii: no socket for %s:%s\n",
00426                              menu->addr, menu->port );
00427       return WS_ERR_NO_CONNECTION;
00428     }
00429   
00430   sprintf( request, "GETSCN: %d %s %s %s %lf %lf %d\n",
00431            menu_reqid++, pscn->sta, pscn->chan, pscn->net,
00432            getThis->reqStarttime, getThis->reqEndtime, getThis->fill );
00433   len = strlen( request );
00434   
00435   if ( ( ret = send_ew( menu->sock, request, len, 0, timeout )) != len )
00436     {
00437       if (ret < 0 )
00438         {
00439           if (WS_CL_DEBUG) 
00440             logit("e", "wsGetTraceAscii: connection broke to server %s:%s\n", 
00441                   menu->addr, menu->port );
00442           ret = WS_ERR_BROKEN_CONNECTION;
00443         } else {
00444           if (WS_CL_DEBUG)
00445             logit("e", "wsGetTraceAscii: server %s:%s timed out\n", 
00446                   menu->addr, menu->port );
00447           ret = WS_ERR_TIMEOUT;
00448         }
00449       goto Abort;
00450     }
00451   
00452   ret = wsWaitAscii( menu, getThis->pBuf, getThis->bufLen, timeout );
00453   if ( ret != WS_ERR_NONE && ret != WS_ERR_BUFFER_OVERFLOW )
00454     {
00455       goto Abort;
00456     }
00457   else
00458     {
00459     err = wsParseAsciiHeaderReply( getThis, getThis->pBuf );
00460     if ( err < WS_ERR_NONE )
00461         {
00462           if ( ( ret == WS_ERR_BUFFER_OVERFLOW ) && WS_CL_DEBUG )
00463             logit ( "e", "wsGetTraceAscii(): buffer overflow; parse error\n" );
00464           return err;
00465         }
00466     }
00467   /* wsParseAsciiReply puts the trace data into getThis, so now we're done */
00468   return WS_ERR_NONE;
00469   
00470 Abort:
00471   wsDetachServer( menu );
00472   return ret;
00473 }
00474 
00475 /*******************************************
00476  *  wsKillPSCN: Deallocates the PSCN list  *
00477  *******************************************/
00478 void wsKillPSCN( WS_PSCN pscn )
00479      /*
00480 Arguments:
00481        pscn: pointer to a list of scn structures
00482        */
00483 {
00484   while ( pscn )
00485     {
00486       WS_PSCN next = pscn->next;
00487 
00488       free( pscn );
00489       pscn = next;
00490     }
00491   return;
00492 }
00493 
00494 /*****************************************************************************
00495  * wsGetServerPSCN: Return the pscn list for this server from the menu queue *
00496  *****************************************************************************/
00497 int wsGetServerPSCN( char* addr, char* port, WS_PSCN* pscnp,
00498                      WS_MENU_QUEUE_REC* menu_queue )
00499      /*
00500 Arguments: 
00501        addr: IP address of the server
00502        port: port number of the server
00503       pscnp: pointer to the pscn list to be returned
00504  menu_queue: pointer to list of menus.
00505      return: WS_ERR_NONE: all went well
00506              WS_ERR_EMPTY_MENU: no menu in the queue
00507              WS_ERR_SERVER_NOT_IN_MENU: server's menu not in the queue
00508              */
00509 {
00510   int ret = menu_queue->head ? WS_ERR_SERVER_NOT_IN_MENU : WS_ERR_EMPTY_MENU;
00511   WS_MENU menu = menu_queue->head;
00512 
00513   *pscnp = NULL;
00514   while ( menu )
00515     {
00516       if ( strcmp( addr, menu->addr ) == 0 &&
00517            strcmp( port, menu->port ) == 0 )
00518         {
00519           ret = WS_ERR_NONE;
00520           *pscnp = menu->pscn;
00521           break;
00522         }
00523       menu = menu->next;
00524     }
00525 
00526     if (WS_CL_DEBUG) 
00527       {
00528         if ( ret == WS_ERR_SERVER_NOT_IN_MENU )
00529           logit( "e","wsGetServerPSCN(): WS_ERR_SERVER_NOT_IN_MENU\n" );
00530         else if ( ret == WS_ERR_EMPTY_MENU )
00531           logit( "e","wsGetServerPSCN(): WS_ERR_EMPTY_MENU\n" );
00532       }
00533     
00534   return ret;
00535 }
00536 
00537 
00538 /***********************************************************************
00539  * wsSearchSCN: Find menu and PSCN in queue which will serve this scn  *
00540  *              If menup points to a menu in the menu_queue, search    *
00541  *              starts at the next menu after *menup; otherwise,       *
00542  *              search starts at menu_queue->head.                     *
00543  *              If the SCN is listed more than once in the queue, only *
00544  *              the first menu and PSCN will be returned.              *
00545  ***********************************************************************/
00546 int wsSearchSCN( TRACE_REQ* getThis, WS_MENU* menup, WS_PSCN* pscnp,
00547                         WS_MENU_QUEUE_REC* menu_queue )
00548      /*
00549 Arguments:
00550       getThis: a TRACE_REQ structure with the SCN to search for.
00551         menup: pointer to the menu to return.
00552         pscnp: pointer to the pscn list to return.
00553       returns: WS_ERR_NONE: if all went well
00554                WS_ERR_EMPTY_MENU: no menus in the queue
00555                WS_ERR_SERVER_NOT_IN_MENU: scn not in the queue
00556                */
00557 {
00558   int ret;
00559   WS_MENU menu;
00560 
00561   if ( *menup != NULL)
00562     menu = (*menup)->next;
00563   else
00564     menu  = menu_queue->head;
00565   ret = menu ? WS_ERR_SCN_NOT_IN_MENU : WS_ERR_EMPTY_MENU;
00566   *pscnp = NULL;
00567 
00568   while ( menu )
00569     {
00570       WS_PSCN pscn = menu->pscn;
00571       while ( pscn )
00572         {
00573           if ( strcmp( getThis->sta, pscn->sta ) == 0 &&
00574                strcmp( getThis->chan, pscn->chan ) == 0 &&
00575                strcmp( getThis->net, pscn->net ) == 0 )
00576             {
00577               ret = WS_ERR_NONE;
00578               *menup = menu;
00579               *pscnp = pscn;
00580               goto exit;
00581             }
00582           pscn = pscn->next;
00583         }
00584       menu = menu->next;
00585     }
00586 
00587  exit:
00588   if (WS_CL_DEBUG) 
00589     {
00590       if ( ret == WS_ERR_SCN_NOT_IN_MENU )
00591         logit( "e","wsSearchSCN(): WS_ERR_SCN_NOT_IN_MENU\n" );
00592       else if ( ret == WS_ERR_EMPTY_MENU )
00593         logit( "e","wsSearchSCN(): WS_ERR_EMPTY_MENU\n" );
00594     }
00595   
00596   return ret;
00597 }
00598 
00599 /***********************************************************************
00600  *  wsAttachServer: Open a connection to a server. The timeout starts  *
00601  *    when connect() is called by connect_ew() in socket_ew_common.c   *
00602  ***********************************************************************/
00603 int wsAttachServer( WS_MENU menu, int timeout )
00604      /*
00605 Arguemnts:
00606        menu: pointer to the menu of the server
00607     timeout: time interval in milliseconds; use -1 for no timeout.
00608     returns: WS_ERR_NONE: if all went well.
00609              WS_ERR_INPUT: if menu is missing.
00610              WS_ERR_SOCKET: if a socket error occurred.
00611              WS_ERR_NO_CONNECTION: if a connection could not be established
00612              */
00613 {
00614   int                ret = WS_ERR_NONE;
00615   int                sock = 0;   /* Socket descriptor                  */
00616   struct sockaddr_in s_in ;      /* Server's socket address stucture   */
00617 
00618   if ( !menu )
00619     {
00620       ret = WS_ERR_INPUT;
00621       if (WS_CL_DEBUG) logit( "e", "wsAttachServer(): WS_ERR_INPUT\n");
00622       goto Abort;
00623     }
00624   if ( menu->sock > 0 )  /* maybe already connected, so disconnect first */
00625     {
00626       wsDetachServer( menu );
00627     }
00628 
00629   /* open a non_blocking socket
00630   *****************************/
00631   if ( ( sock = socket_ew( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
00632     {
00633       ret = WS_ERR_SOCKET;
00634       if (WS_CL_DEBUG) 
00635         logit( "e", "wsAttachServer(): socket_ew() call failed\n" );
00636       goto Abort;
00637     }
00638 
00639   /* Stuff address and port into socket structure
00640   ********************************************/
00641   memset( (char *)&s_in, '\0', sizeof(s_in) );
00642   s_in.sin_family = AF_INET;
00643   s_in.sin_port   = htons( (short)atoi(menu->port) );
00644 
00645 #ifdef _LINUX
00646   if ((int)(s_in.sin_addr.s_addr = inet_addr(menu->addr)) == -1)
00647 #else
00648   if ((int)(s_in.sin_addr.S_un.S_addr = inet_addr(menu->addr)) == -1)
00649 #endif
00650     {
00651       ret = WS_ERR_NO_CONNECTION;
00652       if (WS_CL_DEBUG) 
00653         logit( "e", "wsAttachServer(): inet_addr failed on <%s>\n",
00654                menu->addr );
00655       goto Abort;
00656     }
00657 
00658   if ( connect_ew( sock, (struct sockaddr *)&s_in, sizeof(s_in), timeout) == -1 )
00659     {
00660       ret = WS_ERR_NO_CONNECTION;
00661       if (WS_CL_DEBUG) 
00662         logit( "e", "wsAttachServer(): connect() call failed\n" );
00663       goto Abort;
00664     }
00665   menu->sock = sock;
00666 
00667   ret = WS_ERR_NONE;
00668   return ret;
00669 
00670   /* An error occured;
00671    * don't blab about here since we already did earlier. */
00672 Abort:
00673   menu->sock = -1; /* mark the socket as dead */
00674   return ret;
00675 }
00676 
00677 
00678 /*********************************************************************
00679  * wsDetachServer: Immediately disconnect from a socket if it's open *
00680  *********************************************************************/
00681 void wsDetachServer( WS_MENU menu )
00682      /*  
00683 Arguments:
00684            menu: menu of server to be detached
00685       */
00686 {
00687   if ( !menu || menu->sock == -1 )
00688     return;
00689   closesocket_ew( menu->sock, SOCKET_CLOSE_IMMEDIATELY_EW );
00690   menu->sock = -1;
00691 }
00692 
00693 
00694 /*********************************************************************
00695  * wsWaitBinHeader: Retrieve the ASCII header of a binary message.   *
00696  * The header will be terminated by a newline, but binary characters *
00697  * will follow in the same message. Thus this routine must read one  *
00698  * character at a time. Since the header is relatively short, this   *
00699  * should not be much a performance hit.                             *
00700  * Returns after newline is read, when timeout expires if set,       *
00701  * or on error.                                                      *
00702  *********************************************************************/
00703 static int wsWaitBinHeader( WS_MENU menu, char* buf, int buflen,
00704                             int timeout_msec )
00705      /*  
00706 Arguments:
00707            menu: menu of server from which message is received
00708             buf: buffer in which to place the message, terminated by null.
00709          buflen: number of bytes in the buffer.
00710    timeout_msec: timout interval in milliseconds. 
00711          return: WS_ERR_NONE: all went well.
00712                  WS_ERR_BUFFER_OVERFLOW: ran out of space before the message
00713                   end; calling program will have to decide how serious this is.
00714                  WS_ERR_INPUT: missing input parameters.
00715                  WS_ERR_SOCKET: error setting socket options.
00716                  WS_ERR_TIMEOUT: time expired before we read everything.
00717                  WS_ERR_BROKEN_CONNECTION: if the connection failed.
00718                  */
00719 {
00720   int ir = 0;
00721   int nr = 0;
00722   char c = '\0';
00723   int ret, ioctl_ret;
00724   fd_set ReadableSockets;
00725   Time_ew StartTime;
00726   struct timeval SelectTimeout;
00727   Time_ew timeout = adjustTimeoutLength(timeout_msec);
00728   long lOnOff;
00729     
00730   if ( !buf || buflen <= 0 )
00731     {
00732       if (WS_CL_DEBUG) logit( "e", "wsWaitBinHeader(): no input buffer\n");
00733       return WS_ERR_INPUT;
00734     }
00735   
00736   /* If there is no timeout, make the socket blocking */
00737   if (timeout_msec == -1)
00738     {
00739       timeout = 0;
00740       lOnOff = 0;
00741       ioctl_ret = ioctlsocket(menu->sock, FIONBIO, &lOnOff);
00742       if (ioctl_ret == SOCKET_ERROR)
00743         {
00744           ret = WS_ERR_SOCKET;
00745           if (WS_CL_DEBUG) 
00746             logit("et", "wsWaitBinHeader: error %s occurred during change to blocking\n",
00747                 socketGetError_ew());
00748           goto Done;
00749         }
00750     }
00751 
00752   StartTime = GetTime_ew(); /* the timer starts here */
00753   /* Start reading the socket, one character at a time */
00754   while ( c != '\n' )
00755     {
00756       if ((timeout) && (GetTime_ew() - timeout) > StartTime )
00757         {
00758           ret = WS_ERR_TIMEOUT;
00759           if (WS_CL_DEBUG) logit("et", "wsWaitBinHeader timed out\n");
00760           goto Done;
00761         }
00762       if ( ir == buflen - 1 )
00763         {
00764           /* stop if there's no more room  */
00765           if (WS_CL_DEBUG) 
00766             logit( "e", "wsWaitBinHeader(): reply buffer overflows\n" );
00767           ret = WS_ERR_BUFFER_OVERFLOW;
00768           goto Done;
00769         }
00770 
00771       /* try to get a char from socket */
00772       nr = recv( menu->sock, &c, 1, 0 );
00773       if ( nr == -1 && socketGetError_ew() == WOULDBLOCK_EW ) 
00774         {
00775           FD_ZERO( &ReadableSockets );
00776           FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
00777           while (( !select(menu->sock + 1, &ReadableSockets, 0, 0,
00778                            resetTimeout( &SelectTimeout)))) 
00779             {
00780               if ((timeout) && (GetTime_ew() - timeout) > StartTime ) 
00781                 {
00782                   ret = WS_ERR_TIMEOUT;
00783                   if (WS_CL_DEBUG) logit("et", "wsWaitBinHeader timed out\n");
00784                   goto Done;
00785                 }
00786               FD_ZERO( &ReadableSockets );
00787               FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
00788               sleep_ew(100); /* wait a little and try again */
00789             }
00790           /* select() says won't block */
00791           nr = recv( menu->sock, &c, 1, 0 ); 
00792         }
00793       if ( nr == 1 && c != 0 )
00794         {
00795           /* got a character; save it      */
00796           buf[ir++] = c;
00797         }
00798       else if ( nr == -1 )
00799         {
00800           /* trouble reading socket        */
00801           ret = WS_ERR_BROKEN_CONNECTION;
00802           if (WS_CL_DEBUG) 
00803             logit( "e", "wsWaitBinHeader(): Error on socket recv()\n" );
00804           goto Done;
00805         }
00806     }
00807   buf[ir] = '\0';                   /* null-terminate the buf      */
00808 
00809   ret = WS_ERR_NONE;
00810 
00811 Done:
00812   buf[ir] = '\0';                 /* null-terminate the buf      */
00813   /* If there was no timeout, then change the socket back to non-blocking */
00814   if (timeout_msec == -1) 
00815     {
00816       lOnOff = 1;
00817       ioctl_ret = ioctlsocket( menu->sock, FIONBIO, &lOnOff);
00818       if (ioctl_ret == SOCKET_ERROR)
00819         {
00820           
00821           if (WS_CL_DEBUG) 
00822             logit("et","wsWaitBinHeader: error %s occurred during change to non-blocking\n", 
00823               socketGetError_ew() );
00824           ret = WS_ERR_SOCKET;
00825         }
00826     }
00827   return ret;
00828 }
00829 
00830 
00831 /*******************************************************************
00832  * wsWaitAscii: Retrieve an ASCII message.                         *
00833  * The message will be terminated by a newline; nothing else is    *
00834  * expected after the newline, so we can read several characters   *
00835  * at a time without fear of reading past the newline.             *
00836  * This message may have internal nulls which will be converted to *
00837  * spaces.                                                         *
00838  * Returns after newline is read, when timeout expires if set,     *
00839  * or on error.                                                    *
00840  *******************************************************************/
00841 static int wsWaitAscii( WS_MENU menu, char* buf, int buflen, int timeout_msec )
00842      /*
00843 Arguments:
00844            menu: menu of server from which message is received
00845             buf: buffer in which to place the message, terminated by null.
00846          buflen: number of bytes in the buffer.
00847    timeout_msec: timout interval in milliseconds. 
00848          return: WS_ERR_NONE: all went well.
00849                  WS_ERR_BUFFER_OVERFLOW: ran out of space before the message
00850                   end; calling program will have to decide how serious this is.
00851                  WS_ERR_INPUT: missing input parameters.
00852                  WS_ERR_SOCKET: error setting socket options.
00853                  WS_ERR_TIMEOUT: time expired before we read everything.
00854                  WS_ERR_BROKEN_CONNECTION: if the connection failed.
00855                  */
00856 {
00857   int ii, ir = 0;  /* character counters */
00858   int nr = 0;
00859   char c = '\0';
00860   int len = 0;
00861   int ret, ioctl_ret;
00862   fd_set ReadableSockets;
00863   Time_ew StartTime;
00864   struct timeval SelectTimeout;
00865   Time_ew timeout = adjustTimeoutLength(timeout_msec);
00866   long lOnOff;
00867   
00868   if ( !buf || buflen <= 0 )
00869     {
00870       if (WS_CL_DEBUG) logit( "e", "wsWaitAscii(): no input buffer\n");
00871       return WS_ERR_INPUT;
00872     }
00873 
00874   /* If there is no timeout, make the socket blocking */
00875   if (timeout_msec == -1)
00876     {
00877       timeout = 0;
00878       lOnOff = 0;
00879       ioctl_ret = ioctlsocket(menu->sock, FIONBIO, &lOnOff);
00880       if (ioctl_ret == SOCKET_ERROR)
00881         {
00882           ret = WS_ERR_SOCKET;
00883           if (WS_CL_DEBUG) logit("et",
00884                 "wsWaitAscii: error %s occurred during change to blocking\n",
00885                                  socketGetError_ew());
00886         goto Done;
00887         }
00888     }
00889 
00890   StartTime = GetTime_ew(); /* the timer starts here */
00891   while ( c != '\n' )
00892     {
00893       if ((timeout) && (GetTime_ew() - timeout) > StartTime ) 
00894         {
00895           ret = WS_ERR_TIMEOUT;
00896           if (WS_CL_DEBUG) logit("et", "wsWaitAscii timed out\n");
00897           goto Done;
00898         }
00899       if ( ir >= buflen - 2 )
00900         {
00901           if (WS_CL_DEBUG)
00902             logit( "e", "wsWaitAscii(): reply buffer overflows\n" );
00903           ret = WS_ERR_BUFFER_OVERFLOW;
00904           goto Done;
00905         }
00906       len = WS_MAX_RECV_BUF_LEN;
00907       if ( ir + len >= buflen - 1 )
00908         len = buflen - ir - 2; /* leave room for the terminating null */
00909       nr = recv( menu->sock, &buf[ir], len, 0 );
00910       if ( nr == -1 && socketGetError_ew() == WOULDBLOCK_EW ) 
00911         {
00912           FD_ZERO( &ReadableSockets );
00913           FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
00914           while (( !select(menu->sock + 1, &ReadableSockets, 0, 0,
00915                            resetTimeout( &SelectTimeout)))) 
00916             {
00917               if ((timeout) && (GetTime_ew() - timeout) > StartTime ) 
00918                 {
00919                   ret = WS_ERR_TIMEOUT;
00920                   if (WS_CL_DEBUG) logit("et", "wsWaitAscii timed out\n");
00921                   goto Done;
00922                 }
00923               FD_ZERO( &ReadableSockets );
00924               FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
00925               sleep_ew(100); /* wait a little and try again */
00926             }
00927           /* poll() says won't block */
00928           nr = recv( menu->sock, &buf[ir], len, 0 ); 
00929         }
00930       
00931       if ( nr == -1 || nr > len )
00932         {
00933           /* trouble reading socket        */
00934           ret = WS_ERR_BROKEN_CONNECTION;
00935           if (WS_CL_DEBUG) logit( "e", "wsWaitAscii(): Error on socket recv()\n" );
00936           goto Done;
00937         }
00938       if ( nr > 0 )
00939         {
00940           ii = 0;
00941           /* got something, adjust ir and c  */
00942           ir += nr;
00943           c = buf[ir-1];
00944           
00945           /* replace NULL char in ascii string with SPACE char */
00946           while ( ii < nr ) 
00947             {
00948               if ( !buf[ir-nr+ii] ) buf[ir-nr+ii] = ' ';
00949               ++ii;
00950             }
00951         }
00952     }
00953   
00954   ret = WS_ERR_NONE;
00955 Done:
00956   buf[ir] = '\0';                 /* null-terminate the reply      */
00957   /* If there was no timeout, then change the socket back to non-blocking */
00958   if (timeout_msec == -1) 
00959     {
00960       lOnOff = 1;
00961       ioctl_ret = ioctlsocket( menu->sock, FIONBIO, &lOnOff);
00962       if (ioctl_ret == SOCKET_ERROR) 
00963         {
00964           
00965           if (WS_CL_DEBUG) logit("et", "wsWaitAScii: error %s occurred during change to non-blocking\n", 
00966                                  socketGetError_ew() );
00967           ret = WS_ERR_SOCKET;
00968         }
00969     }
00970   return ret;
00971 }
00972 
00973 /***********************************************************************
00974  * wsParseMenuReply: parse the reply we got from the waveserver into   *
00975  * a menu list. Handles replies to MENU, MENUPIN and MENUSCN requests. *
00976  ***********************************************************************/
00977 static int wsParseMenuReply( WS_MENU menu, char* reply )
00978 {
00979   /* Arguments:
00980    *       menu: pointer to menu structure to be allocated and filled in.
00981    *      reply: pointer to reply to be parsed.
00982    *   Returns: WS_ERR_NONE:  if all went well
00983    *            WS_ERR_INPUT: if bad input parameters
00984    *            WS_ERR_PARSE: if we couldn't parse the reply
00985    *            WS_ERR_MEMORY: if out of memory
00986    */
00987   int reqid = 0;
00988   int pinno = 0;
00989   char sta[7];
00990   char chan[9];
00991   char net[9];
00992   double tankStarttime = 0.0, tankEndtime = 0.0;
00993   char datatype[3];
00994   int scn_pos = 0;
00995 
00996   if ( !reply || !menu )
00997     {
00998       if (WS_CL_DEBUG) logit("e", "wsParseMenuReply: WS_ERR_INPUT\n");
00999       return WS_ERR_INPUT;
01000     }
01001 
01002   if ( sscanf( &reply[scn_pos], "%d", &reqid ) < 1 )
01003     {
01004       if (WS_CL_DEBUG)
01005         logit( "e","wsParseMenuReply(): error parsing reqid\n" );
01006       return WS_ERR_PARSE;
01007     }
01008   wsSkipN( reply, 1, &scn_pos );
01009   while ( reply[scn_pos] && reply[scn_pos] != '\n' )
01010     {
01011       WS_PSCN pscn = NULL;
01012       if ( sscanf( &reply[scn_pos], "%d %s %s %s %lf %lf %s",
01013                    &pinno, sta, chan, net,
01014                    &tankStarttime, &tankEndtime, datatype ) < 7 )
01015         {
01016           if (WS_CL_DEBUG)
01017             logit( "e","wsParseMenuReply(): error decoding reply<%s>\n",
01018                  &reply[scn_pos] );
01019           return WS_ERR_PARSE;
01020         }
01021       pscn = ( WS_PSCN_REC* )calloc(sizeof(WS_PSCN_REC),1);
01022       if ( !pscn )
01023         {
01024           if (WS_CL_DEBUG)
01025             logit("e", "wsParseMenuReply(): error allocating memory\n");
01026           return WS_ERR_MEMORY;
01027         }
01028 
01029       pscn->next = menu->pscn;
01030       pscn->pinno = pinno;
01031       strcpy( pscn->sta, sta );
01032       strcpy( pscn->chan, chan );
01033       strcpy( pscn->net, net );
01034       pscn->tankStarttime = tankStarttime;
01035       pscn->tankEndtime = tankEndtime;
01036       menu->pscn = pscn;
01037       wsSkipN( reply, 7, &scn_pos );
01038     }
01039 
01040   return WS_ERR_NONE;
01041 }
01042 
01043 /***********************************************************************
01044  * wsParseBinHeaderReply: parse the reply we got from the waveserver   *
01045  * into a TRACE_REQ structure. Handles the header for replies reply to *
01046  * GETSCNRAW requests.                                                 *
01047  ***********************************************************************/
01048 static int wsParseBinHeaderReply( TRACE_REQ* getThis, char* reply )
01049 {
01050   /* Arguments:
01051    *    getThis: pointer to TRACE_REQ structure to be filled with reply info
01052    *      reply: pointer to reply to be parsed.
01053    *   Returns: WS_ERR_NONE:  if all went well
01054    *            WS_ERR_INPUT: if bad input parameters
01055    *            WS_ERR_PARSE: if we couldn't parse part of the reply
01056    *            WS_WRN_FLAGGED: server sent us a no-data flag
01057    */
01058   int reqid = 0;
01059   int pinno = 0;
01060   char sta[7];
01061   char chan[9];
01062   char net[9];
01063   char flag[9];
01064   char datatype[3];
01065   double tankStarttime = 0.0, tankEndtime = 0.0;
01066   int bin_len = 0;
01067   int scn_pos = 0;
01068   char *buf = NULL;
01069 
01070   if ( !reply || !getThis )
01071     {
01072       if (WS_CL_DEBUG)
01073         logit( "e", "wsParseBinHeaderReply(): bad input parameters\n");
01074       return WS_ERR_INPUT;
01075     }
01076 
01077   if ( sscanf( &reply[scn_pos], "%d %d", &reqid, &pinno ) < 2 )
01078     {
01079       if (WS_CL_DEBUG)
01080         logit( "e","wsParseBinHeaderReply(): error parsing reqid/pinno\n" );
01081       return WS_ERR_PARSE;
01082     }
01083   wsSkipN( reply, 2, &scn_pos );
01084 
01085   if ( sscanf( &reply[scn_pos], "%s %s %s", sta, chan, net ) < 3 )
01086     {
01087       if (WS_CL_DEBUG) logit( "e","wsParseBinHeaderReply(): error parsing SCN\n" );
01088       return WS_ERR_PARSE;
01089     }
01090   wsSkipN( reply, 3, &scn_pos );
01091 
01092   if ( sscanf( &reply[scn_pos], "%s %s", flag, datatype ) < 2 )
01093     {
01094       if (WS_CL_DEBUG)
01095         logit( "e","wsParseBinHeaderReply(): error parsing flag/datatype\n" );
01096       return WS_ERR_PARSE;
01097     }
01098   wsSkipN( reply, 2, &scn_pos );
01099 
01100   if ( strlen(flag) == 1 )
01101     {
01102       if ( sscanf( &reply[scn_pos], "%lf %lf", &tankStarttime, 
01103                    &tankEndtime ) < 2 )
01104         {
01105           if (WS_CL_DEBUG) 
01106             logit( "e","wsParseBinHeaderReply(): error parsing starttime/endtime\n" );
01107           return WS_ERR_PARSE;
01108         }
01109       wsSkipN( reply, 2, &scn_pos );
01110 
01111       if ( sscanf( &reply[scn_pos], "%d", &bin_len ) < 1 )
01112         {
01113           if (WS_CL_DEBUG) 
01114             logit( "e","wsParseBinHeaderReply(): error parsing bin_len\n" );
01115           return WS_ERR_PARSE;
01116         }
01117       wsSkipN( reply, 1, &scn_pos );
01118 
01119     }
01120   else if ( strlen(flag) == 2 )
01121     {
01122       tankStarttime = 0.0;
01123       tankEndtime = 0.0;
01124       bin_len = 0;
01125       if ( strcmp(flag,"FL") == 0 )
01126         {
01127           if ( sscanf( &reply[scn_pos], "%lf", &tankStarttime) < 1 )
01128             {
01129               if (WS_CL_DEBUG) 
01130                 logit( "e","wsParseBinHeaderReply(): error parsing starttime\n" );
01131               return WS_ERR_PARSE;
01132             }
01133           wsSkipN( reply, 1, &scn_pos );
01134         }
01135       else if ( strcmp(flag,"FR") == 0 )
01136         {
01137           if ( sscanf( &reply[scn_pos], "%lf", &tankEndtime) < 1 )
01138             {
01139               if (WS_CL_DEBUG) 
01140                 logit( "e","wsParseBinHeaderReply(): error parsing endtime\n" );
01141               return WS_ERR_PARSE;
01142             }
01143           wsSkipN( reply, 1, &scn_pos );
01144         }
01145     }
01146   else
01147     {
01148       if (WS_CL_DEBUG) 
01149         logit( "e","wsParseBinHeaderReply(): bad flag[%s]\n", flag );
01150       return WS_ERR_PARSE;
01151     }
01152 
01153   getThis->pinno = pinno;
01154   getThis->actStarttime = tankStarttime;
01155   getThis->actEndtime = tankEndtime;
01156   getThis->samprate = (double) 0.0; /* server doesn't send this */
01157   getThis->actLen = bin_len;
01158   if ( strlen( flag ) >= 2 ) {
01159     getThis->retFlag = flag[1];
01160     return WS_WRN_FLAGGED;
01161   } else {
01162     getThis->retFlag = '\0';
01163     return WS_ERR_NONE;
01164   }
01165 }
01166 
01167 
01168 /***********************************************************************
01169  * wsParseAsciiHeaderReply: parse the reply we got from the waveserver *
01170  * into a TRACE_REQ structure. Handles the header for replies reply to *
01171  * GETSCN and GETPIN requests.                                         *
01172  ***********************************************************************/
01173 static int wsParseAsciiHeaderReply( TRACE_REQ* getThis, char* reply )
01174 {
01175   /* Arguments:
01176    *    getThis: pointer to TRACE_REQ structure to be filled with reply info
01177    *      reply: pointer to reply to be parsed.
01178    *   Returns: WS_ERR_NONE:  if all went well
01179    *            WS_ERR_INPUT: if bad input parameters
01180    *            WS_ERR_PARSE: if we couldn't parse part of the reply
01181    *            WS_WRN_FLAGGED: server sent us a no-data flag
01182    */
01183   int reqid = 0;
01184   int pinno = 0;
01185   char sta[7];
01186   char chan[9];
01187   char net[9];
01188   char flag[9];
01189   char datatype[3];
01190   double tankStarttime = 0.0, samprate = 0.0;
01191   int scn_pos = 0;
01192 
01193   if ( !reply )
01194     {
01195       if (WS_CL_DEBUG) 
01196         logit( "e", "wsParseAsciiHeaderReply(): bad input parameters\n");
01197       return WS_ERR_INPUT;
01198     }
01199 
01200   if ( sscanf( &reply[scn_pos], "%d %d", &reqid, &pinno ) < 2 )
01201     {
01202       if (WS_CL_DEBUG) 
01203         logit( "e","wsParseAsciiHeaderReply(): error parsing reqid/pinno\n" );
01204       return WS_ERR_PARSE;
01205     }
01206   wsSkipN( reply, 2, &scn_pos );
01207 
01208   if ( sscanf( &reply[scn_pos], "%s %s %s", sta, chan, net ) < 3 )
01209     {
01210       if (WS_CL_DEBUG) 
01211         logit( "e","wsParseAsciiHeaderReply(): error parsing SCN\n" );
01212       return WS_ERR_PARSE;
01213     }
01214   wsSkipN( reply, 3, &scn_pos );
01215 
01216   if ( sscanf( &reply[scn_pos], "%s %s", flag, datatype ) < 2 )
01217     {
01218       if (WS_CL_DEBUG) 
01219         logit( "e","wsParseAsciiHeaderReply(): error parsing flag/datatype\n" );
01220       return WS_ERR_PARSE;
01221     }
01222   wsSkipN( reply, 2, &scn_pos );
01223 
01224   if ( strlen(flag) == 1 || strcmp(flag,"FG") == 0 )
01225     {
01226       if ( sscanf( &reply[scn_pos], "%lf %lf", &tankStarttime, &samprate ) < 2 )
01227         {
01228           if (WS_CL_DEBUG)
01229             logit( "e","wsParseAsciiHeaderReply(): error parsing startT/samprate\n" );
01230           return WS_ERR_PARSE;
01231         }
01232       wsSkipN( reply, 2, &scn_pos );
01233     }
01234   else if ( strlen(flag) == 2 )
01235     {
01236       tankStarttime = 0.0;
01237       samprate = 0.0;
01238       if ( strcmp(flag,"FL") == 0 )
01239         {
01240           if ( sscanf( &reply[scn_pos], "%lf", &tankStarttime) < 1 )
01241             {
01242               if (WS_CL_DEBUG)
01243                 logit( "e","wsParseAsciiHeaderReply(): error parsing startTime\n" );
01244               return WS_ERR_PARSE;
01245             }
01246           wsSkipN( reply, 1, &scn_pos );
01247         }
01248       else if ( strcmp(flag,"FR") == 0 )
01249         {
01250           if ( sscanf( &reply[scn_pos], "%lf", &samprate) < 1 )
01251             {
01252               if (WS_CL_DEBUG)
01253                 logit( "e","wsParseAsciiHeaderReply(): error parsing samprate\n" );
01254               return WS_ERR_PARSE;
01255             }
01256           wsSkipN( reply, 1, &scn_pos );
01257         }
01258     }
01259 
01260   getThis->pinno = pinno;
01261   getThis->actStarttime = tankStarttime;
01262   getThis->actEndtime = (double) 0.0;
01263   getThis->samprate = samprate;
01264   getThis->actLen = strlen( reply ) - scn_pos;
01265   memmove(reply, &reply[scn_pos], getThis->actLen);
01266   reply[getThis->actLen] = 0;
01267   
01268   if ( strlen( flag ) >= 2 ) {
01269     getThis->retFlag = flag[1];
01270     return WS_WRN_FLAGGED;
01271   } else {
01272     getThis->retFlag = '\0';
01273     return WS_ERR_NONE;
01274   }
01275 }
01276 
01277 
01278 /**************************************************************************
01279  *      wsSkipN: moves forward the pointer *posp in buf by moving forward *
01280  *      cnt words.  Words are delimited by either space or horizontal     *
01281  *      tabs; newline marks the end of the buffer.                        *
01282  **************************************************************************/
01283 static void wsSkipN( char* buf, int cnt, int* posp )
01284 {
01285   int pos = *posp;
01286 
01287   while ( cnt )
01288     {
01289       while ( buf[pos] != ' ' && buf[pos] != '\t' )
01290         {
01291           if ( !buf[pos] )
01292             {
01293               goto done;
01294             }
01295           if ( buf[pos] == '\n' )
01296             {
01297               ++pos;
01298               goto done;
01299             }
01300           ++pos;
01301         }
01302       --cnt;
01303       while ( buf[pos] == ' ' || buf[pos] == '\t' )
01304         {
01305           ++pos;
01306         }
01307     }
01308 done:
01309   *posp = pos;
01310 }
01311 
01312 int setWsClient_ewDebug(int debug)
01313 {
01314   /* setWsClient_ewDebug() turns debugging on or off for 
01315      the ws_clientII routines
01316      */
01317   WS_CL_DEBUG=debug;
01318   return(0);
01319 }

Generated on Tue May 6 09:16:13 2003 for Earthworm Libs by doxygen1.3-rc3