source: trunk/src/archiving/wave_serverV/serve_trace.c @ 2883

Revision 2883, 78.2 KB checked in by paulf, 12 years ago (diff)

fixed flags for MACOSX and LINUX

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1
2/*
3 *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
4 *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
5 *
6 *    $Id$
7 *
8 *    Revision history:
9 *     $Log$
10 *     Revision 1.14  2007/03/28 18:02:34  paulf
11 *     fixed flags for MACOSX and LINUX
12 *
13 *     Revision 1.13  2005/07/21 21:05:51  friberg
14 *     Added _LINUX ifdef to roundup to prevent macro use
15 *
16 *     Revision 1.12  2005/03/17 17:30:05  davidk
17 *     Changes to enforce a maximum tanksize of 1GB.
18 *     Non-functional change.
19 *     Added a  Long comment describing the bug in LocateRoughOffset
20 *     that limits WaveServerV tank sizes to 1GB.
21 *
22 *     Revision 1.11  2004/05/18 22:30:19  lombard
23 *     Modified for location code
24 *
25 *     Revision 1.10  2003/01/28 00:42:27  alex
26 *     changed logit message around line 2269. Alex
27 *
28 *     Revision 1.9  2002/10/11 21:44:08  davidk
29 *     Fixed a bulk send fill statement that miscalulated the number
30 *     of fill values.  It sent one too few.  This fixes a fix to the
31 *     same statement, from 08/2001, when the statement was issuing
32 *     one too many fill samples.  The 08/2001 fix removed two(2) samples
33 *     instead of just 1.
34 *
35 *     Revision 1.8  2002/10/11 21:31:29  davidk
36 *     Checking in change from 08/2001.  Change had never been checked in.
37 *     Checking it in, so that I can fix a bug in it.
38 *
39 *     Revision 1.7  2001/08/11 17:16:45  davidk
40 *     modified GRACE_PERIOD code in locating offsets, so that it now
41 *     accomodates sloppy timestamps, instead of doing whatever it
42 *     did before.  The previous GRACE_PERIOD logic was flawed as it
43 *     was based on misunderstandings about the interpretation of
44 *     trace_buf packets by the GRACE_PERIOD author(me).
45 *
46 *     Modified SendReqDataAscii().  Moved the bulk of the code out
47 *     into a separate function SendReqDataAscii_AndThisTimeWeMeanIt().
48 *     Fixed ascii reply code so that it better handled sloppy timestamps
49 *     and fill values.
50 *     See wave_serverV/README.changes for more detailed info.
51 *
52 *     Revision 1.6  2001/06/29 22:23:59  lucky
53 *     Implemented multi-level debug scheme where the user can specify how detailed
54 *     (and large) the log files should be. If no Debug is specified, only
55 *     errors are reported and logged.
56 *
57 *     Revision 1.5  2001/01/17 21:44:25  davidk
58 *     Added code to report hard(disk) read/write errors via status messages.
59 *
60 *     Revision 1.4  2000/10/02 18:06:48  lombard
61 *     Fixed two places where unnecessary calls to fseek() could cause an
62 *     endless loop if fseek() failed, such as the tank file having been
63 *     closed by the main thread. The fseek() was intended to restore the
64 *     tank file position to that needed by the main thread.
65 *
66 *     Revision 1.3  2000/07/08 19:01:07  lombard
67 *     Numerous bug fies from Chris Wood
68 *
69 *     Revision 1.2  2000/06/28 23:45:27  lombard
70 *     added signal handler for graceful shutdowns; numerous bug fixes
71 *     See README.changes for complete list
72 *
73 *     Revision 1.1  2000/02/14 19:58:27  lucky
74 *     Initial revision
75 *
76 *
77 */
78
79
80/* serve_trace.c: created April 25, 1997 */
81
82#include        <stdio.h>
83#include        <stdlib.h>
84#include        <string.h>
85#include        <earthworm.h>
86#include        <transport.h>           /* needed for wave_serverV.h */
87#include        <trace_buf.h>
88#include        <socket_ew.h>
89#include        "wave_serverV.h"
90#include        "server_thread.h"
91
92
93#define FLAG_L    0
94#define FLAG_R    1
95
96#define D_SIZE_I2 2
97#define D_SIZE_I4 4
98
99#define MAX_TRACE_INT_LEN   16
100#define MAX_TRACE_DBL_LEN  128
101#define MAX_TRACE_HDR_LEN  256
102#define MAX_TRACE_SOC_LEN 8192/*4096*/
103#define DBL_FLOAT_NA      ((double) -1.0)
104#define DBL_FLOAT_EPSILON ((double) 0.00010) /* << 100 samples/sec */
105
106#define SPACE_STR (char *) " "
107#define LN_FD_STR (char *) "\n"
108
109#define NO_NEWLINE 0
110#define YES_NEWLINE 1
111
112/* return codes used in SendReqDataAscii() */
113#define SRDA_ABORT     -1
114#define SRDA_MEM_ABORT -2
115
116
117
118/* MINIMUM_GAP_SIZE is the smallest time gap between samples
119   that can be considered to contain a gap in data.  It is
120   given in terms relative to sample rate.  If it is 1.3, then
121   that means there must be atleast a (1.3/SAMPLERATE) second
122   difference between the last sample and the next before a
123   GAP can be declared.  This is not related to GAPSIZE and
124   wave_serverV indexes.
125   DK 08/09/2001
126*/
127#define MINIMUM_GAP_SIZE (1.0 + ACCEPTABLE_TIMESTAMP_SLOP)
128
129
130
131
132int _writeTraceDataRaw( int, TANK*, CLIENT_MSG* );
133int _writeTraceDataAscii( int, TANK*, CLIENT_MSG* );
134
135static int SendReqDataRaw( int, TANK*, double, double, double, double,
136                           double, double,
137                           char*, long int, char* );
138static int SendReqDataAscii( int, TANK*, double, double, double, double,
139                             double, double, char*,
140                             char*, long int, char* );
141
142static int GetOffsetLeft( TANK*, double, long int*, double* );
143static int GetOffsetRight( TANK*, double, long int*, double* );
144static int LocateExactOffset( TANK*, DATA_CHUNK*, double, int,
145                              long int*, double*, DATA_CHUNK * );
146static int LocateRoughOffset( TANK*, double, double, double,
147                              long int, long int, int, long int*, double* );
148static int LocateStartOfTank( TANK*, long int*, double* );
149static int LocateEndOfTank( TANK*, long int*, double* );
150
151static int CopyReqData( TANK*, long int, long int, char**, long int* );
152static int ReadBlockData( FILE*, long int, long int, char* );
153static int FreeReqData( char* );
154
155static int BulkSendFill( int, char*, long int );
156static int SendHeader( int soc, TANK* t, char* reqid, char* flag, double tS,
157                       double tE, int binSize, int flagNewLine);
158static int SendStrData( int soc, char* str );
159
160
161
162static int _fDBG = -1;  /* equal to -1 upon first entry to ws_client.c */
163static int _fSUB = 2;
164static int _fALG = 16;
165static int _fPRT = 32;
166
167/* set _fDBG to be non-zero for extended debug logit() */
168static int _fINI = 0;
169static char _pSYSTEM[32] = "ew_debug.ini";
170static char _pMODULE[32] = "serve_trace";
171
172static int ewInitDebugFlag( char* pModule, int* flagp )
173{
174  FILE *fid = NULL;
175  char buf[128] = "";
176
177  *flagp = _fINI;
178  fid = fopen(_pSYSTEM,"r");
179  if (!fid) goto done;
180
181  while (fgets(buf,127,fid))
182  {
183    if (buf[0] == '#') continue;
184    if (!strstr(buf,pModule)) continue;
185    {
186      char *ptr = buf;
187      int flag = 0;
188
189      while (*ptr && (*ptr != '='))
190        ++ptr;
191      if (*ptr == '=') ++ptr;
192      if (!(*ptr) || (sscanf(ptr,"%d",&flag) != 1))
193      {
194        logit("", "ewInitDebugFlag(): sscanf() failed! buf[%s]\n", buf);
195        goto done;
196      }
197      *flagp = flag;
198      break;
199    }
200  }
201
202 done:
203  if (fid) fclose(fid);
204  if (*flagp) logit("e","ewInitDebugFlag(): %s[%d]\n", pModule, *flagp);
205  return 0;
206}
207
208static int trace_log( TRACE2_HEADER* );
209
210/* function: _writeTraceDataRaw()
211 *    input: int soc, socket descriptor;
212 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
213 *           CLIENT_MSG* msg, which contains the following info:
214 *               double tS, starting time of reqested period;
215 *               double tE, ending time of reqested period;
216 *               char* fill, ascii string that fills sampling gaps
217 *   return: R_SKIP if tE <= tS;
218 *           R_FAIL or R_DONE otherwise
219 *
220 *  purpose: to serve as one of the two entry points from server_thread.c,
221 *           by responding to user requests of raw binary data for a given
222 *           period of time.  In doing so, the following events occur:
223 *           1) tank file is locked,
224 *           2) left and right offsets in tank file are found,
225 *           3) data within this range is copied to memory,
226 *           4) the lock is released,
227 *           5) data is sent to socket with proper header information
228 */
229
230int _writeTraceDataRaw( int soc, TANK* t, CLIENT_MSG* msg )
231{
232  int ret = R_FAIL;
233  long int oS = -1L;          /* starting offset for CopyReqData() */
234  long int oE = -1L;          /* ending offset for CopyReqData() */
235  double tS = 0.0;
236  double tE = 0.0;
237  double acttS = 0.0;         /* actual time stamp at oS */
238  double acttE = 0.0;         /* actual time stamp at oE */
239  long int oL = -1L;          /* starting tank offset for SendReqDataRaw() */
240  long int oR = -1L;          /* ending tank offset for SendReqDataRaw() */
241  double tL = 0.0;            /* time stamp on left edge of the tank */
242  double tR = 0.0;            /* time stamp on right edge of the tank */
243  char* data = (char*) NULL;
244  long int datasize = 0L;
245  int mutexLocked = 0;
246  long int saveOff = 0;      /* saving offset of file */
247
248  if ( _fDBG == -1 )
249    ewInitDebugFlag( _pMODULE, &_fDBG );
250
251  if ( !t || !(t->tfp) ) goto abort;
252  if ( !msg ) goto abort;
253  tS = msg->starttime;
254  tE = msg->endtime;
255  if ( tS < 0.0 ) goto abort;
256  if ( tS + DBL_FLOAT_EPSILON >= tE ) goto skip;
257
258  if ( _fDBG & _fSUB )
259    logit( "","\n--------------------------------\n" );
260
261  RequestSpecificMutex(&(t->mutex));
262  mutexLocked = 1;
263  if ( (saveOff = ftell(  t->tfp )) < 0 )
264  {
265    logit( "","_writeTraceDataRaw(): ftell[%ld] failed for tank %s\n",
266           saveOff, t->tankName );
267    goto abort;
268  }
269   
270  /* safe to get delimiters of tank once mutex is locked */
271  if ( LocateStartOfTank( t, &oL, &tL ) )
272    goto abort;
273  if ( LocateEndOfTank( t, &oR, &tR ) )
274    goto abort;
275   
276  if ( _fDBG & _fSUB )
277  {
278    logit( "","_writeTraceDataRaw(): [tS,tE] [%f,%f]\n",tS,tE );
279    logit( "","                      [tL,tR] [%f,%f]\n",tL,tR );
280    logit( "","                      [oL,oR] [%ld,%ld]\n",oL,oR );
281  }
282   
283  if ( GetOffsetLeft( t, tS, &oS, &acttS ) != R_DONE ) goto abort;
284  if ( GetOffsetRight( t, tE, &oE, &acttE ) != R_DONE ) goto abort;
285
286  /* SendReqDataRaw() will, if necessary, set FL, FR or FG based on
287   * acttS and acttE in comparison with tS and tE,
288   * hence don't goto skip here even if ( acttE <= acttS );
289   *
290   * however, since the wrapping nature of the tank, it is likely
291   * oS > oE, hence CopyReqData() need be guarded by the comparison
292   * of acctS and acctE;
293   *
294   * when [tS,tE] falls entirely in a gap, acttE < tS < tE < acttS,
295   * it is clear that acttE < acttS, and CopyReqData() need not be called
296   *
297   * when [tS,tE] falls entirely in index range, or when there is an
298   * overlap of [tS,tE] and [acttS,acttE], one of following is true:
299   *   1) acttS < tS < tE < acttE,
300   *   2) tS < acttS < acttE < tE,
301   *   3) acttS < tS < acttE < tE,
302   *   4) tS < acttS < tE < acttE,
303   * which is equivalent to ( acttS < tE && tS < acttE );
304   *
305   */
306
307  if ( ( acttS < tE && tS < acttE ) &&
308       ( acttS + DBL_FLOAT_EPSILON > acttE ) )
309  {
310    logit( "","_writeTraceDataRaw(): warning! acttS[%f] acttE[%f] for tank %s\n",
311           acttS,acttE, t->tankName );
312  }
313
314  if ( ( acttS < tE && tS < acttE ) &&
315       ( acttS + DBL_FLOAT_EPSILON <= acttE) )
316  {
317    if ( CopyReqData( t, oS, oE, (char**) &data, &datasize ) == R_FAIL )
318      goto abort;
319  }
320   
321  ReleaseSpecificMutex(&(t->mutex));
322  mutexLocked = 0;
323
324  if ( SendReqDataRaw( soc, t, tS, tE, tL, tR, acttS, acttE,
325                       data, datasize, msg->reqId ) != R_DONE)
326    goto abort;
327  ret = R_DONE;
328 skip:
329  if ( ret != R_DONE)
330  {
331    ret = R_SKIP;
332    if ( _fDBG & _fSUB )
333      logit( "","_writeTraceDataRaw(): skips processing\n" );
334  }
335 abort:
336  if ( ret == R_FAIL )
337  {
338    logit( "","_writeTraceDataRaw(): failed\n" );
339  }
340  if ( mutexLocked ) 
341    ReleaseSpecificMutex(&(t->mutex));
342
343  if ( data )
344    FreeReqData( data );
345  return ret;
346}
347
348/* function: _writeTraceDataAscii()
349 *    input: int soc, socket descriptor;
350 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
351 *           CLIENT_MSG* msg, which contains the following info:
352 *               double tS, starting time of reqested period;
353 *               double tE, ending time of reqested period;
354 *               char* fill, ascii string that fills sampling gaps;
355 *           char* reqid, the client's request ID
356 *   return: R_SKIP if tE <= tS;
357 *           R_FAIL or R_DONE otherwise
358 *
359 *  purpose: to serve as one of the two entry points from server_thread.c,
360 *           by responding to user requests of raw ASCII data for a given
361 *           period of time.  In doing so, the following events occur:
362 *           1) tank file is locked,
363 *           2) left and right offsets in tank file are found,
364 *           3) data within this range is copied to memory,
365 *           4) the lock is released,
366 *           5) data is sent to socket with proper header information
367 */
368
369int _writeTraceDataAscii( int soc, TANK* t, CLIENT_MSG* msg )
370{
371  int ret = R_FAIL;
372  long int oS = -1L;          /* starting offset for CopyReqData() */
373  long int oE = -1L;          /* ending offset for CopyReqData() */
374  double tS = 0.0;
375  double tE = 0.0;
376  char* fill = (char*) NULL;
377  double acttS = 0.0;         /* actual time stamp at oS */
378  double acttE = 0.0;         /* actual time stamp at oE */
379  long int oL = -1L;          /* starting tank offset for SendReqDataAscii() */
380  long int oR = -1L;          /* ending tank offset for SendReqDataAscii() */
381  double tL = 0.0;            /* time stamp on left edge of the tank */
382  double tR = 0.0;            /* time stamp on right edge of the tank */
383  char* data = (char*) NULL;
384  long int datasize = 0L;
385  int mutexLocked = 0;
386  long int saveOff = 0;      /* saving offset of file */
387
388  if ( _fDBG == -1 )
389    ewInitDebugFlag( _pMODULE, &_fDBG );
390
391  if ( !t || !(t->tfp) ) goto abort;
392  if ( !msg ) goto abort;
393  tS = msg->starttime;
394  tE = msg->endtime;
395  fill = msg->fillvalue;
396  if ( tS < 0.0 ) goto abort;
397  if ( tS + DBL_FLOAT_EPSILON >= tE ) goto skip;
398
399  if ( _fDBG & _fSUB )
400    logit( "","\n================================\n" );
401
402  RequestSpecificMutex(&(t->mutex));
403  mutexLocked = 1;
404  if( (saveOff = ftell( t->tfp )) < 0 )
405  {
406    logit( "","_writeTraceDataAscii(): ftell[%ld] failed for tank %s\n",
407           saveOff, t->tankName );
408    goto abort;
409  }
410   
411  /* safe to get delimiters of tank once mutex is locked */
412  if ( LocateStartOfTank( t, &oL, &tL ) )
413    goto abort;
414  if ( LocateEndOfTank( t, &oR, &tR ) )
415    goto abort;
416   
417  if ( _fDBG & _fSUB )
418  {
419    logit( "","_writeTraceDataAscii(): [tS,tE] [%f,%f]\n",tS,tE );
420    logit( "","                   [tL,tR] [%f,%f]\n",tL,tR );
421    logit( "","                   [oL,oR] [%ld,%ld]\n",oL,oR );
422  }
423   
424  if ( GetOffsetLeft( t, tS, &oS, &acttS ) != R_DONE ) goto abort;
425  if ( GetOffsetRight( t, tE, &oE, &acttE ) != R_DONE ) goto abort;
426
427  /* SendReqDataAscii() will, if necessary, set FL or FR based on
428   * acttS and acttE in comparison with tS and tE,
429   * hence don't goto skip here even if ( acttE <= acttS );
430   *
431   * however, since the wrapping nature of the tank, it is likely
432   * oS > oE, hence CopyReqData() need be guarded by the comparison
433   * of acctS and acctE;
434   *
435   * when [tS,tE] falls entirely in a gap, acttE < tS < tE < acttS,
436   * it is clear that acttE < acttS, and CopyReqData() need not be called
437   *
438   * when [tS,tE] falls entirely in index range, or when there is an
439   * overlap of [tS,tE] and [acttS,acttE], one of following is true:
440   *   1) acttS < tS < tE < acttE,
441   *   2) tS < acttS < acttE < tE,
442   *   3) acttS < tS < acttE < tE,
443   *   4) tS < acttS < tE < acttE,
444   * which is equivalent to ( acttS < tE && tS < acttE );
445   *
446   */
447
448  if ( ( acttS < tE && tS < acttE ) &&
449       ( acttS + DBL_FLOAT_EPSILON > acttE ) )
450  {
451    logit( "","_writeTraceDataAscii(): warning! acttS[%f] acttE[%f], no data available for request in tank %s\n",
452           acttS,acttE,t->tankName );
453  }
454
455  if ( ( acttS < tE && tS < acttE ) &&
456       ( acttS + DBL_FLOAT_EPSILON <= acttE) )
457  {
458    if ( CopyReqData( t, oS, oE, (char**) &data, &datasize ) == R_FAIL )
459      goto abort;
460  }
461   
462  ReleaseSpecificMutex(&(t->mutex));
463  mutexLocked = 0;
464
465  if ( SendReqDataAscii( soc, t, tS, tE, tL, tR, acttS, acttE,
466                         fill, data, datasize, msg->reqId ) != R_DONE)
467    goto abort;
468  ret = R_DONE;
469 skip:
470  if ( ret != R_DONE)
471  {
472    ret = R_SKIP;
473    if ( _fDBG & _fSUB )
474      logit( "","_writeTraceDataAscii(): skips processing\n" );
475  }
476 abort:
477  if ( ret == R_FAIL )
478  {
479    logit( "","_writeTraceDataAscii(): failed\n" );
480  }
481  if ( mutexLocked ) 
482    ReleaseSpecificMutex(&(t->mutex));
483   
484  if ( data )
485    FreeReqData( data );
486  return ret;
487}
488
489
490/* function: GetOffset()
491 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
492 *           double reqtS, starting time of reqested period
493 *   output: long int* offp, the offset that covers reqtS, which is set
494 *               to the start of next index when reqtS falls in a gap;
495 *           double* acttp, actual time that matches *offp;
496 *   return: R_FAIL or R_DONE
497 *
498 *  purpose: to find  offset in tank file (including associated
499 *           time stamp) for the requested time period;
500 *           called  from GetOffsetLeft() and GetOffsetRight();
501 *           Used to illiminate redundancy between Left() and Right()
502 *           Could improve performance by using #defines
503 */
504static int GetOffset( TANK* t, double reqTime,
505                      long int *offp, double *acttp,
506                      int DirectionFlag)
507{
508  int ret = -1;
509  int curr = -1;  /* iterator */
510  int prev = -1;  /* look back */
511  int next = -1;  /* look forward */
512  DATA_CHUNK * pCurr = (DATA_CHUNK *) 0;
513  DATA_CHUNK * pNext = (DATA_CHUNK *) 0;
514  char szFuncName[2][20] = {"GetOffsetLeft", "GetOffsetRight"}; 
515
516  *offp = -1L;
517  *acttp = 0.0;
518
519  if ( !t || !( t->tfp ) || t->samprate < DBL_FLOAT_EPSILON )
520  {
521    logit( "","%s(): bad parameters\n",szFuncName[DirectionFlag] );
522    logit( "","%s(): failed\n",szFuncName[DirectionFlag] );
523    ret=R_FAIL;
524  }
525
526  /* We are not using pointers now, we are using array indexes.  This seems kind
527     of messy, because the list is not encapsulated.  It would probably be a
528     good idea to encapsulate the list, and use GetNextChunk(TANK *,DATA_CHUNK *),
529     but for now, I will just code the index. Cleanup:
530  */
531
532  /* Make sure the tank is not empty */
533  if ( IndexOldest( t )->tEnd == 0.0 )
534  {
535    logit( "","%s(): Empty tank %s\n",szFuncName[DirectionFlag], t->tankName);
536    logit( "","%s(): failed\n",szFuncName[DirectionFlag]);
537    ret=R_FAIL;
538  }
539
540  /* Set curr and next */
541  curr=t->indxStart;
542  if(t->indxStart >= ((unsigned int)t->indxMaxChnks)) /* t->indxStart is an unsigned int and cannot be <0 */
543  {
544    /* t->indxStart is out of whack */
545    logit("et","wave_serverV.GetOffset(): Bad t->indxStart %d, for tank %s\n",
546          t->indxStart, t->tankName );
547  }
548
549  /* Make sure there is a next */
550  if(curr != (int)t->indxFinish)
551  {
552    next=curr+1;
553    if(next == t->indxMaxChnks)
554    {
555      next=0;
556    }
557  }
558
559  while(prev != (int)t->indxFinish && ret != R_DONE  && ret !=R_FAIL)
560  {
561    pCurr=&((t->chunkIndex)[curr]);
562    /* check to see if the current index doesn't contain data that is too young.
563       Remember to allow for timestamp slop. */
564    if( (reqTime < (pCurr->tEnd + GRACE_PERIOD)  && 
565        DirectionFlag == FLAG_L) 
566       ||
567        (reqTime <= (pCurr->tEnd + GRACE_PERIOD) && 
568        DirectionFlag == FLAG_R)
569      )
570    {
571      /* We've found a piece of trace that is not too young */
572      /* check to see if the current index doesn't isn't too old
573         Remember to allow for timestamp slop. */
574      if( (reqTime <= (pCurr->tStart - GRACE_PERIOD) && 
575          DirectionFlag == FLAG_L) 
576         ||
577          (reqTime < (pCurr->tStart - GRACE_PERIOD) && 
578          DirectionFlag == FLAG_R)
579        )
580      { 
581        /* !!oops, either too young, or in the gap just before this junk */
582        /* set the offset to here, and note that it occured in GAP */
583        if (Debug > 1)
584        {
585             logit("t","Found gap, or too young at curr=%d, setting offset %d\n",
586                                                                                                                                curr,pCurr->offset);
587             logit("t","Curr-Start %f,Curr->End %f,reqTime %f!\n",
588                                                                                                        pCurr->tStart,pCurr->tEnd,reqTime);
589             logit("t","Tank %s  ",t->tankName );
590             if(DirectionFlag == FLAG_L) 
591                logit("","Called for start of request.\n***************************\n");
592             else
593                logit("","Called for end of request.\n***************************\n");
594        }
595
596        if(DirectionFlag == FLAG_L)
597        {
598          *offp = pCurr->offset;
599          *acttp = pCurr->tStart;
600        }
601        else
602        {
603          *offp = pCurr->offset;
604          if(prev < 0)
605          {
606            /* DK Cleanup:  logit("t","Wave_serverV.GetOffset():  Requested trace is left of tank.\n");
607             */
608            *acttp = 0.0;
609          }
610          else
611          {
612            *acttp=t->chunkIndex[prev].tEnd;
613          }
614        }
615         
616        if ( _fDBG & _fALG )
617        {
618          if ( prev == -1 )
619            logit( "","  %s(GAP): no prev!\n",szFuncName[DirectionFlag]);
620          else
621            logit("","  %s(GAP): previous tEnd[%f]\n",
622                  szFuncName[DirectionFlag], t->chunkIndex[prev].tEnd);
623          logit( "","                      off[%ld] actt[%f]\n",*offp,*acttp );
624        }
625        ret = R_DONE;
626      }
627      else
628      {
629        /* OK, it's in this chunk somewhere, sick LocateExactOffset on it */
630        if ( _fDBG & _fALG )
631          logit( "","  %s(): tS in   [%f,%f]\n", szFuncName[DirectionFlag],
632                 pCurr->tStart, pCurr->tEnd );
633        /* First, create a pNext */
634        if(curr != (int)t->indxFinish)
635        {
636          next=curr+1;
637          if(next == t->indxMaxChnks)
638          {
639            next=0;
640          }
641          pNext=&(t->chunkIndex[next]);
642        }
643        else
644        {
645          pNext=0;
646        }
647        /* Then call LocateExactOffset */
648        ret = LocateExactOffset( t, pCurr, reqTime, DirectionFlag, offp, acttp,
649                                 pNext );
650        if(ret == R_FAIL)
651        {
652          logit("et","LocateExactOffset failed for tank %s.\n Reqt %f,Start %f, Finish %f,offset %d, InsrtPt %d,FLAG_L %d, GRACE_PERIOD %f\n",
653                t->tankName, reqTime,pCurr->tStart,pCurr->tEnd,pCurr->offset,t->inPtOffset,DirectionFlag==FLAG_L,GRACE_PERIOD);
654        }
655      }
656    }
657    else
658    {
659      /* Not there yet, keep going */
660      prev = curr;
661      curr+=1;
662      if(curr == t->indxMaxChnks)
663      {
664        curr=0;
665      }
666    }
667  }  /* End of while() not finished loop */
668  if(prev == (int)t->indxFinish)
669  {
670    /* Request was too young, crap out, or do something to indicate failure */
671    if ( _fDBG & _fALG )
672      logit( "","  %s(): tS requested too young\n", szFuncName[DirectionFlag]);
673    ret = LocateEndOfTank( t,offp,acttp );
674  }
675  return(ret);
676}
677
678/* function: GetOffsetLeft()
679 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
680 *           double reqtS, starting time of reqested period
681 *   output: long int* offp, the offset that covers reqtS, which is set
682 *               to the start of next index when reqtS falls in a gap;
683 *           double* acttp, actual time that matches *offp;
684 *   return: R_FAIL or R_DONE
685 *
686 *  purpose: to find left offset in tank file (including associated
687 *           time stamp) for the requested time period;
688 *           called only once from _writeTraceDate();
689 *           see also symmetric function GetOffsetRight()
690 */
691static int GetOffsetLeft( TANK* t, double reqtE,
692                          long int *offp, double *acttp )
693{
694  return(GetOffset(t,reqtE,offp,acttp,FLAG_L));
695}
696
697
698/* function: GetOffsetRight()
699 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
700 *           double reqtE, ending time of reqested period;
701 *   output: long int* offp, the offset that covers reqtE, which is set
702 *               to the end of previous index when reqtE falls in a gap;
703 *           double* acttp, actual time that matches *offp;
704 *   return: R_FAIL or R_DONE
705 *
706 *  purpose: to find right offset in tank file (including associated
707 *           time stamp) for the requested time period;
708 *           called only once from _writeTraceDate();
709 *           see also symmetric function GetOffsetLeft()
710 */
711
712static int GetOffsetRight( TANK* t, double reqtE,
713                           long int *offp, double *acttp )
714{
715  return(GetOffset(t,reqtE,offp,acttp,FLAG_R));
716}
717
718/* function: LocateExactOffset()
719 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
720 *           DATA_CHUNK* idx, which meets both conditions listed below:
721 *             1) idx->tStart <= reqt,
722 *             2) idx->tEnd >= reqt;
723 *           double reqt, requested time;
724 *           int flag, either FLAG_L or FLAG_R;
725 *   output: long int* offp, offset located within idx;
726 *           double* acttp, actual time that matches *offp;
727 *   return: R_FAIL or R_DONE
728 *
729 *  purpose: to find exact offset in a given index structure that is
730 *           to the immediate left/right of the requested time;
731 *           could be called no more than once from GetOffsetLeft() or
732 *           GetOffsetRight() respectively (denoted by FLAG_L or FLAG_R)
733 */
734
735static int LocateExactOffset( TANK* t, DATA_CHUNK* idx, double reqt, int flag,
736                              long int* offp, double* acttp, DATA_CHUNK* next )
737{
738  int ret = R_FAIL;
739  long int off = -1L;
740  double actt = 0.0;
741  long int oE = -1L;
742  FILE* tfp = (FILE*) NULL;
743  TRACE2_HEADER trace_h = { 0 };
744  int rsz = 0;
745  int tsz = 0;
746  int DFIP;
747  int tmp_point;
748  int RoughOff;
749  double RoughActt;
750
751  /* Variables to handle recording of File I/O errors */
752  int iFileOffset, iFileBlockSize;
753  char * szFileTankName;
754  char szFileFunction[15];
755
756  *offp = off;
757  *acttp = actt;
758   
759  if ( !t || !( tfp = t->tfp ) || !( rsz = t->recSize ) || 
760       !( tsz = t->tankSize) || !idx )
761  {
762    logit( "","LocateExactOffset(): t[%0x] tfp[%0x] tsz[%0x] idx[%0x]\n",
763           t, tfp, tsz, idx );
764    goto abort;
765  }
766   
767  if ( _fDBG & _fALG )
768  {
769    logit( "","    LocateExactOffset(%c):  [%f,%f]\n",
770           flag == FLAG_L ? 'L':'R', idx->tStart, idx->tEnd );
771    logit( "","                           [%f]\n", reqt );
772  }
773
774  if ( next )
775  {
776    oE = next->offset;
777  }
778  else
779  {
780    double tE = 0.0;
781    if ( LocateEndOfTank( t, &oE, &tE ) != R_DONE )
782      goto abort;
783  }
784  if ( LocateRoughOffset( t, idx->tStart, idx->tEnd, reqt,
785                          idx->offset, oE, flag, &off, &actt ) != R_DONE )
786  {
787    logit("et","Wave_serverV:LocateRoughOffset failed for tank %s within LocateExactOffset\n",
788          t->tankName );
789    goto abort;
790  }
791   
792  RoughOff=off;
793  RoughActt=actt;
794  /* wrap oE for ease of processing in the following while loop */
795  if ( oE == tsz )
796    oE = 0L;
797
798  /* FLAG_L and FLAG_R are distinguished by LocateRoughOffset();
799   * off and actt both mark the beginning of a record with FLAG_L,
800   * and they mark the end of a record with FLAG_R
801   */
802   
803  /* Calculate the distance from the current offset to the insertion point
804     and then monitor it as to prevent us from crossing it forwards or backwards.
805  */
806  /* First adjust to middle of the current record as opposed to the front or end */
807  if(flag == FLAG_L)
808  {
809    tmp_point=off+(int)(0.5*rsz);
810  }
811  else
812  {
813    tmp_point=off-(int)(0.5*rsz);
814  }
815
816  /* Next Calculate the Distance From Insertion Point */
817  DFIP=t->inPtOffset-tmp_point;
818  while(DFIP < 0)
819  {
820    DFIP+=tsz;
821  }
822  while(DFIP >tsz)
823  {
824    DFIP-=tsz;
825  }
826  /* Now, everytime the offset is moved, adjust the DFIP */
827
828
829  /*  Okay, here's the new plan.  We're gonna overhaul this, so that we start checking
830      time windows for each record, instead of just checking the start or
831      end of the record.
832
833      The logic is:
834      starting with the record that is returned from LocateRoughOffset(), read
835      the start and end times of the current record.  If the reqt is within
836      the record start and endtime (non-inclusive), then we're done, ship the
837      starttime and offset for that record (for FLAG_L, for FLAG_R, ship the
838      endtime and offset+recsz).  If the record does not contain the reqt, then
839      if the reqt < the starttime of the record, throw the search engine in reverse,
840      keeping track of the current offset and starttime or offset and endtime.
841      While the reqt is greater or equal to the endtime of the record, keep going
842      until we hit the index or tank wall(Insertion point).  If we hit the wall,
843      blow up, and goto OHCRAP!!!
844
845      Reverse:
846      Go back the other direction until we pass the reqt going the other way.
847      Then return the previous offset and Start or EndTime depending on L or R
848  */
849
850  /* need search back and forth */
851  if ( flag == FLAG_L )
852  {
853    if ( ReadBlockData(tfp, off, (long int) sizeof(TRACE2_HEADER),
854                       (char*) &trace_h ) != R_DONE )
855    {
856      strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
857      szFileFunction[sizeof(szFileFunction)]= 0;
858      iFileOffset     = off;
859      iFileBlockSize  = sizeof(TRACE2_HEADER);
860      szFileTankName  = t->tankName;   /* don't copy just point */
861      goto ReadBlockDataFailed;
862    }
863    /* if reqt is to the right keep going */
864    while ((trace_h.endtime + GRACE_PERIOD) < reqt) 
865    {
866      off += rsz;
867      DFIP-=rsz;
868      if(DFIP <= 0 || DFIP >= tsz)
869      {
870        logit("t","Failed DFIP comparison #1\n");
871        goto OHCRAP;
872      }
873
874      /* for the left boundary, set off = 0 if off == tsz */
875      if ( off >= tsz )
876        off =0;
877
878      if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
879                          (char*) &trace_h ) != R_DONE )
880      {
881        strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
882        szFileFunction[sizeof(szFileFunction)]= 0;
883        iFileOffset     = off;
884        iFileBlockSize  = sizeof(TRACE2_HEADER);
885        szFileTankName  = t->tankName;   /* don't copy just point */
886        goto ReadBlockDataFailed;
887      }
888    }  /* End while(acct < reqt) */
889
890    if(trace_h.starttime  - GRACE_PERIOD <= reqt)
891    {
892      /* We've found our spot.  trace_h.starttime <= reqt <= trace_h.endtime.
893         Pack it up and go home */
894      *acttp=trace_h.starttime;
895      *offp=off;
896    }
897    else
898    {
899      /* There was some sort of a minor snaffu.  Throw it in reverse,
900         but keep track of what we've got.
901      */
902      int tempOff=-1;
903      double tempStart=-1.0;
904
905      while (trace_h.starttime - GRACE_PERIOD > reqt )
906        /* Use GRACE_PERIOD to account for sloppy timestamps */
907      {
908        /* Keep going backwards until we hit the wall, or get to a good time */
909        tempOff=off;
910        tempStart=trace_h.starttime;
911        off -= rsz;
912        DFIP += rsz;
913        if(DFIP <= 0 || DFIP >= tsz)
914        {
915          logit("t","Failed DFIP comparison #2\n");
916          goto OHCRAP;
917        }
918        if ( off < 0L )
919          off += tsz;
920        if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
921                            (char*) &trace_h ) != R_DONE )
922        {
923          strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
924          szFileFunction[sizeof(szFileFunction)]= 0;
925          iFileOffset     = off;
926          iFileBlockSize  = sizeof(TRACE2_HEADER);
927          szFileTankName  = t->tankName;   /* don't copy just point */
928          goto ReadBlockDataFailed;
929        }
930      }
931      /* OK, we're here, I guess */
932      if(trace_h.starttime - GRACE_PERIOD <= reqt && 
933         reqt <= tempStart - GRACE_PERIOD)
934      {
935        /* OK, we are definitely here now.
936           We just need to figure out where we are.
937        */
938        if(reqt < trace_h.endtime + GRACE_PERIOD )
939        {
940          /* We can get atleast one sample from this rec, so
941             use it.
942          */
943          *offp=off;
944          *acttp=trace_h.starttime;
945        }
946        else
947        {
948          /* We can't get any data out of this sample, so let's
949             go back to the one where we just were.
950          */
951          *offp=tempOff;
952          *acttp=tempStart;
953        }
954      }
955      else  /* if(trace_h.starttime - GRACE_PERIOD < reqt 
956               && reqt <= tempStart - GRACE_PERIOD) */
957      {
958        /* Anything that lands here would be a bug */
959        logit("t","Lost in LocateExactOffset for tank %s\n", t->tankName );
960        logit("t","th.start %f th.end %f off %d tempOff %d tempStart %f reqt %f\n",
961              trace_h.starttime,trace_h.endtime,off,tempOff,tempStart,reqt);
962      }
963    } /* End else from if(trace_h.starttime <= reqt) */
964  }  /* End   if ( flag == FLAG_L ) */
965  else  /*  flag == FLAG_R */
966  {
967    long int tmp = off-rsz;
968
969    if(tmp < 0)
970      tmp+=tsz;
971
972    if ( ReadBlockData(tfp, tmp, (long int) sizeof(TRACE2_HEADER),
973                       (char*) &trace_h ) != R_DONE )
974    {
975      strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
976      szFileFunction[sizeof(szFileFunction)]= 0;
977      iFileOffset     = tmp;
978      iFileBlockSize  = sizeof(TRACE2_HEADER);
979      szFileTankName  = t->tankName;   /* don't copy just point */
980      goto ReadBlockDataFailed;
981    }
982    while (trace_h.starttime > reqt)  /* if reqt is to the left keep going */
983    {
984      off=tmp;
985      tmp-=rsz;
986      DFIP+=rsz;
987      if(DFIP <= 0 || DFIP >= tsz)
988      {
989        logit("t","Failed DFIP comparison #3\n");
990        goto OHCRAP;
991      }
992
993      /* for the left boundary, set off = 0 if off == tsz */
994      if ( tmp < 0 )
995        tmp += tsz;
996     
997      if ( ReadBlockData( tfp, tmp, (long int) sizeof(TRACE2_HEADER),
998                          (char*) &trace_h ) != R_DONE )
999      {
1000        strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1001        szFileFunction[sizeof(szFileFunction)]= 0;
1002        iFileOffset     = tmp;
1003        iFileBlockSize  = sizeof(TRACE2_HEADER);
1004        szFileTankName  = t->tankName;   /* don't copy just point */
1005        goto ReadBlockDataFailed;
1006      }
1007    }  /* End while(acct < reqt) */
1008
1009    if(trace_h.endtime + GRACE_PERIOD >= reqt)
1010    {
1011      /* We've found our spot.  trace_h.starttime < reqt <= trace_h.endtime.
1012         Pack it up and go home */
1013      *acttp=trace_h.endtime;
1014      *offp=off;
1015    }
1016    else
1017    {
1018      /* There was some sort of a minor snaffu.  Throw it in reverse,
1019         but keep track of what we've got.
1020      */
1021      double tempEnd=trace_h.endtime;
1022
1023      while (trace_h.endtime + GRACE_PERIOD < reqt)
1024        /* Use GRACE_PERIOD to account for sloppy timestamps */
1025      {
1026        /* Keep going backwards until we hit the wall, or get to a good time */
1027        tmp=off;
1028        off += rsz;
1029        DFIP -= rsz;
1030        if(DFIP <= 0 || DFIP >= tsz)
1031        {
1032          logit("t","Failed DFIP comparison #4\n");
1033          goto OHCRAP;
1034        }
1035        if ( off >=tsz )
1036          off=0;
1037        tempEnd=trace_h.endtime;
1038        if ( ReadBlockData( tfp, tmp, (long int) sizeof(TRACE2_HEADER),
1039                            (char*) &trace_h ) != R_DONE )
1040        {
1041          strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1042          szFileFunction[sizeof(szFileFunction)]= 0;
1043          iFileOffset     = tmp;
1044          iFileBlockSize  = sizeof(TRACE2_HEADER);
1045          szFileTankName  = t->tankName;   /* don't copy just point */
1046          goto ReadBlockDataFailed;
1047        }
1048      }
1049      /* OK, we're here, I guess */
1050      if(tempEnd + GRACE_PERIOD <= reqt && reqt <= trace_h.endtime + GRACE_PERIOD)
1051      {
1052        /* OK, we are definitely here now.
1053           We just need to figure out where we are.
1054        */
1055        if(reqt >= trace_h.starttime + GRACE_PERIOD)
1056        {
1057          /* We can get atleast one sample from this rec, so
1058             use it.
1059          */
1060          *offp=off;
1061          *acttp=trace_h.endtime;
1062        }
1063        else
1064        {
1065          /* We can't get any data out of this record, so let's
1066             go back to the one where we just were.
1067          */
1068          *offp=tmp;
1069          *acttp=tempEnd;
1070        }
1071      }
1072      else  /* if(tempEnd < reqt && reqt < trace_h.endtime + GRACE_PERIOD) */
1073      {
1074        /* Anything that lands here would be a bug */
1075        logit("t","Lost in LocateExactOffset for tank %s\n", t->tankName);
1076        logit("t","th.start %f th.end %f off %d tempOff %d tempEnd %f\n",
1077              trace_h.starttime,trace_h.endtime,off,tmp,tempEnd);
1078      }
1079    } /* End else from if(trace_h.endtime >= reqt) */
1080  }  /* end else from if FLAG_L */
1081
1082  ret = R_DONE;
1083
1084 ReadBlockDataFailed:
1085  if ( ret != R_DONE )
1086  {
1087    IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1088    goto abort;
1089  }
1090 OHCRAP:
1091  if ( ret != R_DONE )
1092  {
1093    logit("t","Wave_server: LocateExactOffset(): reached the index boundary without reaching reqt.\n reqt %f off %d oE %d inspt %d idxofst %d\n",
1094          reqt,off,oE,t->inPtOffset,idx->offset);
1095    logit("t","Wave_server: LocateExactOffset(): DFIP %d,tsz %d, RoughOff %d, RoughActt %f, Tank %s\n",DFIP,tsz,RoughOff,RoughActt,t->tankName);
1096  }
1097 abort:
1098  if ( ret != R_DONE )
1099    logit( "","LocateExactOffset(): failed\n" );
1100  return ret;
1101}
1102
1103/* function: LocateRoughOffset()
1104 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
1105 *           double tS, starting time denoting beginning of range,
1106 *           double tE, ending time denoting end of range,
1107 *           double reqt, user requested time,
1108 *           long int oS, starting offset corresponding to tS,
1109 *           long int oE, ending offset corresponding to tE;
1110 *           int flag, either FLAG_L or FLAG_R;
1111 *   output: long int* offp, offset located within the range of [oS,oE],
1112 *           double* acttp, actual time that matches *offp;
1113 *   return: R_FAIL or R_DONE
1114 *
1115 *  purpose: to find rough offset in a given index structure that is
1116 *           close to the requested time, so that sequential search
1117 *           in this neighborhood would be inexpensive;
1118 *           called only by GetExactOffset() or GetExactOffset(), and
1119 *           FLAG_L or FLAG_R is passed as flag for differentiation
1120 *
1121 *     note: tanksize is multiple of record size, otherwise disastous
1122 *           alignment of block data read error ensues;
1123 */
1124
1125/*******************************************************************************
1126*******************************************************************************
1127WARNING!!! BUG IN LocateRoughOffset()
1128
1129 At first glance, there appears to be a bug in wave_serverV that affects tank
1130files over 1,073,741,823 bytes in size.  Code within LocateRoughOffset() in
1131serve_trace.c, does a buffer calculation, that potentially overflows a signed
1132integer value when the tanksize is >= 1 GB.
1133
1134The error affects only data retrieval, and only when the offset of the
1135chronological-start of the tank is near the end of the tank.  Specifically,
1136if  TankSize + oS (offset of chronological-start) >= 2GB, then an error
1137will result, and no data will be returned for the tank.  (Once the offset
1138wraps around to the beginning of the tank again, everything should
1139function normally)
1140
1141Since your tank is just barely over 1 GB, you are seeing the errors only
1142when the chronological-start offset gets near the end of the tank.  If you
1143were using tank sizes ~ 2GB, you would experience the problem
1144constantly.
1145
1146The problem appears to result from a signed integer overflow of tmpoE
1147at Line 1155 of serve_trace.c  (LocateRoughOffset()).
1148An example from your logfile:
1149
1150> LocateRoughOffset(): warning! oE[1029091392] tmpoE[-2145876160] off[2145508992] for tank i:\nano1_MDH1_EP1_NC.tnk
1151>    ==> offset == [-2145877024] < 0
1152
1153
1154oE = the chronological-end of the tank  (once the tank has wrapped, the chronological-end and chronological-start are adjacent.)
1155tmpoE = the chronological-end of the tank + the tanksize
1156tmpoE = 1029091392(oE) + 1,119,999,744 (tanksize) =   0x801883E0 which as an unsigned int = -2145877024
1157which is < 0. This is treated as an error, and an error flag is returned to the client instead of the requested data.
1158
1159
1160This is my analysis based upon 30 minutes of inspection.  Besides the error that I describe here,
1161there may be other issues with tanksizes > 1 GB.  A reliable code fix would require further inspection
1162and thorough testing.  Also, I may have mis-analyzed the code and error, and the problem could
1163potentially be something different.
1164
1165An immediate fix, would be to limit your tank files to < 1 GB.  (This may be impractical for you, if
1166you have a good deal of data in the current tanks that you do not wish to lose, and have no way
1167to transfer it.)
1168
1169Unless someone disagrees with my diagnosis, or wishes to immeidately have the problem investigated
1170further, it would probably be a good idea to send a message out to the EW list, warning against
1171using tanksizes >= 1GB.
1172
1173DK 2005/03/09  (comment from email 2004/01/29)
1174*******************************************************************************
1175*******************************************************************************/
1176
1177static int LocateRoughOffset( TANK* t, double tS, double tE, double reqt,
1178                              long int oS, long int oE, int flag,
1179                              long int* offp, double* acttp )
1180{
1181  int ret = R_FAIL;
1182  long int off = -1L;
1183  double actt = 0.0;
1184  long int tmpoS = oS;
1185  long int tmpoE = oE;
1186  FILE* tfp = (FILE*) NULL;
1187  TRACE2_HEADER trace_h = { 0 };
1188  long int nRec = 0L;
1189
1190  /* Variables to handle recording of File I/O errors */
1191  int iFileOffset, iFileBlockSize;
1192  char * szFileTankName;
1193  char szFileFunction[15];
1194  int  bIssueIOStatusError = FALSE;
1195
1196  *offp = off;
1197  *acttp = actt;
1198  if ( !t || !( tfp = t->tfp ) || !( t->recSize ) )
1199  {
1200    logit( "","LocateRoughOffset(): t[%0x] tfp[%0x] recSize[%d]\n",
1201           t, t?t->tfp:0, t?t->recSize:0 );
1202    goto abort;
1203  }
1204  if ( tE - tS < DBL_FLOAT_EPSILON )
1205  {
1206    logit( "","LocateRoughOffset(): [tE,tS] range too small for tank %s\n",
1207           t->tankName );
1208    goto abort;
1209  }
1210  if ( ( reqt < tS - GRACE_PERIOD) || ( reqt > tE + GRACE_PERIOD) )
1211  {
1212    logit( "","LocateRoughOffset(): reqt[%f] out of range for tank %s\n",
1213           reqt, t->tankName );
1214    goto abort;
1215  }
1216   
1217  if ( oS == t->tankSize ) tmpoS = 0L;
1218  if ( oE <= oS ) tmpoE += t->tankSize;
1219  nRec = (long int)( ( tmpoE-tmpoS ) / t->recSize * ( reqt-tS ) / ( tE-tS ) );
1220  off = tmpoS + nRec * t->recSize;
1221  if ( off > tmpoE )
1222  {
1223    logit( "","LocateRoughOffset(): warning! oE[%ld] tmpoE[%ld] off[%ld] for tank %s\n",
1224           oE, tmpoE, off, t->tankName );
1225    off = tmpoE - t->recSize;
1226  }
1227  if ( off >= t->tankSize ) off -= t->tankSize;
1228
1229  if ( _fDBG & _fALG ) logit( "","      LocateRoughOffset( ): " );
1230  if ( ReadBlockData( tfp, off, (long int) sizeof(TRACE2_HEADER),
1231                      (char*) &trace_h ) != R_DONE )
1232  {
1233    logit( "","LocateRoughOffset(): ERROR ReadBlockData() failed\n" );
1234    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1235    szFileFunction[sizeof(szFileFunction)]= 0;
1236    iFileOffset     = off;
1237    iFileBlockSize  = sizeof(TRACE2_HEADER);
1238    szFileTankName  = t->tankName;   /* don't copy just point */
1239    bIssueIOStatusError = TRUE;
1240    goto abort;
1241  }
1242  if ( _fDBG & _fALG ) logit( "","                            off[%ld], tS[%f]\n",
1243                              off,trace_h.starttime );
1244
1245  if (flag == FLAG_L)
1246  {
1247    *offp = off;
1248    *acttp = trace_h.starttime;
1249  }
1250  else
1251  {
1252    *offp = off + t->recSize;
1253    *acttp = trace_h.endtime;
1254  }
1255
1256  ret = R_DONE;
1257 abort:
1258  if ( ret != R_DONE )
1259  {
1260    if(bIssueIOStatusError)
1261    {
1262      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1263      bIssueIOStatusError = FALSE;
1264    }
1265
1266    logit( "","LocateRoughOffset(): failed\n" );
1267  }
1268  return ret;
1269}
1270
1271/* function: LocateStartOfTank()
1272 *  purpose: get offset and time stamp at the start of oldest index
1273 *    input: TANK* t
1274 *   output: long int* offp, which is set to t->indxStart->offset;
1275 *           double* acttp, which is set to t->indxStart->tStart
1276 *   return: R_FAIL or R_DONE
1277 *
1278 *  purpose: to find offset and timestamp at beginning of tank
1279 *           called by various functions
1280 */
1281
1282static int LocateStartOfTank( TANK* t, long int* offp, double* acttp )
1283{
1284  int ret = R_FAIL;
1285  DATA_CHUNK* idx = NULL;
1286   
1287  *offp = -1L;
1288  *acttp = 0.0;
1289
1290  if ( !t || !( idx = IndexOldest( t ) ) ) goto abort;
1291
1292  *offp = idx->offset;
1293  *acttp = idx->tStart;
1294
1295  if ( _fDBG & _fPRT )
1296    logit( "","    LocateStartOfTank():    indxS->off[%ld] indxS->sT[%f]\n",
1297           *offp, *acttp );
1298  ret = R_DONE;
1299 abort:
1300  if ( ret != R_DONE )
1301    logit( "","LocateStartOfTank(): failed\n" );
1302  return ret;
1303}
1304
1305/* function: LocateEndOfTank()
1306 *  purpose: get offset and time stamp at the end of youngest index
1307 *    input: TANK* t, with following assumptions:
1308 *               t->tfp opened in "+br" mode;
1309 *               t->inPtOffset is valid insertion point;
1310 *   output: long int* offp, which is set to t->inPtOffset;
1311 *           double* acttp, which is set to t->indxStart->tStart
1312 *   return: R_FAIL or R_DONE
1313 *
1314 *  purpose: to find offset and timestamp at end of tank;
1315 *           called by various functions
1316 */
1317
1318static int LocateEndOfTank( TANK* t, long int* offp, double* acttp )
1319{
1320  int ret = R_FAIL;
1321  FILE* tfp = (FILE*) NULL;
1322  TRACE2_HEADER trace_h = { 0 };
1323  long int off = -1L;
1324  double actt = 0.0;
1325
1326  /* Variables to handle recording of File I/O errors */
1327  int iFileOffset, iFileBlockSize;
1328  char * szFileTankName;
1329  char szFileFunction[15];
1330  int  bIssueIOStatusError = FALSE;
1331 
1332  *offp = off;
1333  *acttp = actt;
1334
1335  if ( !t || !( tfp = t->tfp ) ) goto abort;
1336
1337  if ( _fDBG & _fPRT )
1338    logit( "","    LocateEndOfTank():      ");
1339  off = t->inPtOffset;
1340  /* in the case off == 0L, the tank has just wrapped to 0L, it is
1341   * convenient to set off = t->tankSize for subsequent processing
1342   */
1343  if ( !off ) off = t->tankSize;
1344  if ( off % t->recSize )
1345  {
1346    logit( "","LocateEndOfTank(): misaligned TRACE2_HEADER records for tank %s\n",
1347           t->tankName );
1348    goto abort;
1349  }
1350
1351  if ( ReadBlockData( tfp, off - t->recSize, (long int) sizeof(TRACE2_HEADER),
1352                      (char*) &trace_h ) != R_DONE )
1353  {
1354    logit( "","LocateEndOfTank(): ERROR ReadBlockData() failed\n" );
1355    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1356    szFileFunction[sizeof(szFileFunction)]= 0;
1357    iFileOffset     = off - t->recSize;
1358    iFileBlockSize  = sizeof(TRACE2_HEADER);
1359    szFileTankName  = t->tankName;   /* don't copy just point */
1360    bIssueIOStatusError = TRUE;
1361    goto abort;
1362  }
1363
1364  *offp = off;
1365  *acttp = trace_h.endtime;
1366  if ( (_fDBG & _fALG) &&
1367       ( trace_h.endtime + DBL_FLOAT_EPSILON < IndexYoungest( t )->tEnd ||
1368         trace_h.endtime - DBL_FLOAT_EPSILON > IndexYoungest( t )->tEnd ) )
1369  {
1370    logit( "","LocateEndOfTank(): warning! young->tEnd[%f] != eT[%f] for tank %s\n", 
1371           IndexOldest( t )->tEnd, *acttp, t->tankName );
1372  }
1373
1374  if ( _fDBG & _fPRT )
1375    logit( "","                            inPt [%ld] endtime[%f]\n",
1376           off, *acttp );
1377  ret = R_DONE;
1378
1379 abort:
1380  if ( ret != R_DONE )
1381  {
1382    if(bIssueIOStatusError)
1383    {
1384      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1385      bIssueIOStatusError = FALSE;
1386    }
1387
1388    logit( "","LocateEndOfTank(): failed\n" );
1389  }
1390  return ret;
1391}
1392
1393/* function: CopyReqData()
1394 *    input: TANK* t, with the assumption t->tfp opened in "br+" mode;
1395 *           long int oS, starting offset for reqested period;
1396 *           long int oE, ending offset for reqested period,
1397 *             due to the bias flag in GetOffset, oE extends beyond
1398 *             the message with ending time tE in _writeTraceData{Raw|Ascii}(),
1399 *             i.e. even if [tS,tE] is very small, oS != oE,
1400 *             in other words, if tS == tE, the entire tank need be copied;
1401 *   output: char** data, records of t->recSize bytes each;
1402 *   return: R_FAIL or R_DONE
1403 *
1404 *  purpose: to copy data from specified range in tank to memory;
1405 *           called only once from main _writeTraceData{Raw|Ascii}()
1406 */
1407
1408static int CopyReqData( TANK* t, long int oS, long int oE,
1409                        char** datap, long int* sizep )
1410{
1411  int ret = R_FAIL;
1412  long int tsz = 0;          /* tank size */
1413  long int sz1 = 0, sz2 = 0; /* 2 fread()'s needed when oS >= oE */
1414  FILE* tfp = (FILE*) NULL;
1415
1416  /* Variables to handle recording of File I/O errors */
1417  int iFileOffset, iFileBlockSize;
1418  char * szFileTankName;
1419  char szFileFunction[15];
1420  int  bIssueIOStatusError = FALSE;
1421
1422  if ( _fDBG & _fALG )
1423    logit( "","CopyReqData():  offsets[%ld,%ld] for tank %s\n",oS,oE,
1424           t->tankName);
1425
1426  *datap = (char*) NULL;
1427  *sizep = 0;
1428  /* assume tank file already opened in mode "rb+" */
1429  if ( !t || !( tfp = t->tfp ) || !( tsz = t->tankSize ) ) goto abort;
1430  if ( oS < 0 || oE < 0 ) goto abort;
1431  if ( oS > tsz || oE > tsz ) goto abort;
1432   
1433  if ( oS < oE )
1434  {
1435    sz1 = oE - oS;
1436    sz2 = 0;
1437  }
1438  else /* ( oS >= oE ) */
1439  {
1440    sz1 = tsz - oS;
1441    sz2 = oE;
1442  }
1443  if ( !sz1 && !sz2 ) goto mem_abort;
1444  *datap = (char*)malloc( ( sz1 + sz2 ) * sizeof( char ) );
1445  if ( !( *datap ) ) goto mem_abort;
1446
1447  if ( sz1 && ReadBlockData( tfp, oS, sz1, &( (*datap)[0] ) ) != R_DONE )
1448  {
1449    logit( "", "CopyReqData(): read [%ld] bytes failed for tank %s\n",sz1,
1450           t->tankName );
1451    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1452    szFileFunction[sizeof(szFileFunction)]= 0;
1453    iFileOffset     = oS;
1454    iFileBlockSize  = sz1;
1455    szFileTankName  = t->tankName;   /* don't copy just point */
1456    bIssueIOStatusError = TRUE;
1457    goto abort;     
1458  }
1459   
1460  if ( sz2 && ReadBlockData( tfp, 0L, sz2, &( (*datap)[sz1] ) ) != R_DONE )
1461  {
1462    logit( "", "CopyReqData(): read [%ld] bytes failed for tank %s\n",sz1,
1463           t->tankName );
1464    strncpy(szFileFunction,"ReadBlockData",sizeof(szFileFunction));
1465    szFileFunction[sizeof(szFileFunction)]= 0;
1466    iFileOffset     = 0L;
1467    iFileBlockSize  = sz2;
1468    szFileTankName  = t->tankName;   /* don't copy just point */
1469    bIssueIOStatusError = TRUE;
1470    goto abort;     
1471  }
1472
1473  *sizep = sz1 + sz2;
1474  ret = R_DONE;
1475 mem_abort:
1476  if ( ret == R_FAIL )
1477    logit( "","CopyReqData(): failed to malloc [%ld] bytes\n", sz1+sz2 );
1478 abort:
1479  if ( ret != R_DONE ) 
1480  {
1481    if(bIssueIOStatusError)
1482    {
1483      IssueIOStatusError(szFileFunction,iFileOffset,iFileBlockSize,szFileTankName);
1484      bIssueIOStatusError = FALSE;
1485    }
1486
1487    if ( *datap )
1488      FreeReqData( *datap );
1489    logit( "","CopyReqData(): failed\n" );
1490  }
1491  return ret;
1492}
1493
1494/* function: ReadBlockData()
1495 *    input: FILE* file, file opened in "br+" mode
1496 *           long int offset, start of block to be read
1497 *           long int length, size of block to be read
1498 *   output: char* data, data read in from file
1499 *   return: R_SKIP, if length == 0,
1500 *           R_FAIL or R_DONE otherwise
1501 *
1502 *  purpose: to read data in specified range in tank to memory;
1503 *           called by various functions
1504 */
1505
1506static int ReadBlockData( FILE* file, long int offset, long int length,
1507                          char* data )
1508{
1509  int ret = R_FAIL;
1510
1511  if ( _fDBG & _fPRT )
1512    logit( "","ReadBlockData(): offset[%ld] length[%ld]\n",
1513           offset,length );
1514  /* assume tank file already opened in mode "rb+" */
1515  if ( !file )
1516  {
1517    logit( "","    ==> filep == NULL\n" );
1518    goto abort;
1519  }
1520  if ( offset < 0 )
1521  {
1522    logit( "","    ==> offset == [%ld] < 0\n",offset );
1523    goto abort;
1524  }
1525  if ( length <= 0 )
1526  {
1527    logit( "","    ==> length == 0\n" );
1528    goto skip;
1529  }
1530  if ( !data )
1531  {
1532    logit( "","    ==> data == NULL\n" );
1533    goto abort;
1534  }
1535
1536  if ( fseek( file, offset, SEEK_SET ) != 0 )
1537  {
1538    logit( "","ReadBlockData(): fseek failed on offset [%ld]\n",offset );
1539    goto abort;
1540  }
1541  if( fread( (char*)data, length, 1, file ) != 1 ) 
1542  {
1543    logit( "", "ReadBlockData(): fread failed on length [%ld]\n",length );
1544    goto abort;
1545  }
1546
1547  ret = R_DONE;
1548 skip:
1549  if ( ret == R_FAIL )
1550  {
1551    logit( "","ReadBlockData(): warning! skips upon 0 length\n" );
1552    ret = R_SKIP;
1553  }
1554 abort:
1555  if ( ret == R_FAIL )
1556    logit( "","ReadBlockData(): failed\n");
1557
1558  return ret;
1559}
1560
1561/* function: FreeReqData()
1562 *    input: char* data, requested data to be freed
1563 *   output: None
1564 *   return: R_SKIP, upon NULL pointer;
1565 *           R_DONE, otherwise
1566 *
1567 *  purpose: to free memory allocated in CopyReqData();
1568 *           called only once from main _writeTraceData{Raw|Ascii}()
1569 */
1570
1571static int FreeReqData( char* data )
1572{
1573  int ret = R_SKIP;
1574  if ( data ) {
1575    free( data );
1576    ret = R_DONE;
1577  }
1578  return ret;
1579}
1580
1581
1582
1583#if defined(_LINUX) || defined(_MACOSX)
1584#undef roundup
1585#else
1586static
1587#endif
1588
1589int roundup(double dIn)
1590{
1591  if(dIn < 0)
1592    return((int)(dIn - 0.5));
1593  else
1594    return((int)(dIn + 0.5));
1595}  /* end roundup() */
1596
1597int SendReqDataAscii_AndThisTimeWeMeanIt(char * data, int iDataByteLen, 
1598                                         double tReqStart, double tReqEnd,
1599                                         double tTankStart, double tTankEnd,
1600                                         int iRecordSize, TANK * t, int soc,
1601                                         char * reqid, char * fill,
1602                                         double acttS, double acttE)
1603{
1604  /* We know we have data, so now we need to process the data.
1605         * First find the start time.
1606  */
1607
1608  double dActStartTime;
1609  double dSampRate;
1610  int    iNumSamplesApart;
1611  int    bFirstBlock;
1612  double tLastSample;
1613  int    iDataSize;
1614  int    iLastSample;
1615  int    iFirstSample;
1616  int    samp_pos;
1617  int    hsz = sizeof(TRACE2_HEADER);
1618  char*  blk_buf = (char*) NULL;
1619  int    blk_pos = 0L;
1620  int    i;
1621  int    ival = 0;
1622  int    retVal;
1623  TRACE2_HEADER * pTH;
1624  char * pCurrentRecord;
1625  int    nsamp;
1626
1627
1628
1629  /* Loop through all the trace_buf in the buffer, sending the samples
1630   * requested plus any fill needed in between */
1631  for(pCurrentRecord = data; 
1632      pCurrentRecord < data+iDataByteLen; 
1633      pCurrentRecord += iRecordSize) 
1634  {
1635    if(pCurrentRecord  == data)
1636      bFirstBlock = TRUE;
1637    else
1638      bFirstBlock = FALSE;
1639
1640    pTH = (TRACE2_HEADER *) pCurrentRecord;
1641
1642
1643    if ( _fDBG & _fPRT ) trace_log( pTH );
1644
1645    if (bFirstBlock) 
1646    {       /* First time through the loop: set values for starttime and
1647             * samplerate for ascii reply header */
1648      dActStartTime = DBL_FLOAT_NA;  /* -1.0 */
1649      dSampRate = pTH->samprate;
1650
1651      /*  THIS CODE ASSUMES THAT THERE WERE NO RECORDS(trace_bufs) BEFORE
1652          THIS ONE WHERE:
1653          pTH->endtime > (tReqStart - MINIMUM_GAP_SIZE/samprate)
1654          GIVEN THIS ASSUMPTION, WE CAN ENFORCE STRICT TIMESTAMPS FOR
1655          DETERMININING IF A FILL SAMPLE SHOULD BE INSERTED BEFORE THE
1656          FIRST SAMPLE IN THE FIRST PACKET
1657          DK 08/10/01
1658       *********************************************************************/
1659
1660     
1661
1662      if ( pTH->samprate < DBL_FLOAT_EPSILON )
1663      {
1664        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): samprate too small for tank %s\n",
1665               t->tankName );
1666        goto abort;
1667      }
1668
1669      /* if the request starts left of the tank */
1670      if ( tReqStart < tTankStart )   
1671        dActStartTime = pTH->starttime;  /* dActStartTime = tank start time */
1672      else
1673      {
1674        /* The requested start time is within the tank */
1675        /* set ActStartTime = [start time of this packet] - (X samples * dSampRate) */
1676        dActStartTime = pTH->starttime;
1677       
1678        iNumSamplesApart = roundup((tReqStart - pTH->starttime) * dSampRate);
1679
1680        dActStartTime += (iNumSamplesApart/dSampRate);
1681      }
1682
1683      tLastSample = dActStartTime;
1684
1685      /* Determine datatype size */
1686      if ( strcmp( pTH->datatype, "i2" ) == 0 ||
1687           strcmp( pTH->datatype, "s2" ) == 0 )
1688      {
1689        iDataSize = D_SIZE_I2;
1690      }
1691      else if ( strcmp( pTH->datatype, "i4" ) == 0 ||
1692                strcmp( pTH->datatype, "s4" ) == 0 )
1693      {
1694        iDataSize = D_SIZE_I4;
1695      }
1696      else
1697      {
1698        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): unexpected data type for tank %s\n",
1699               t->tankName );
1700        goto abort;
1701      }
1702
1703      /* Send the header */
1704      if ( SendHeader( soc, t, reqid, "F", dActStartTime, dSampRate, 0,
1705                       NO_NEWLINE ) != R_DONE )
1706      {
1707        logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): SendHeader #4 failed for tank %s\n",
1708              t->tankName );
1709        goto abort;
1710      }
1711    }  /*end if (bFirstBlock)*/
1712
1713    /* make sure the trace_buf is not unreasonably sized */
1714    if((hsz + pTH->nsamp * iDataSize) > iRecordSize)
1715    {
1716      logit("t","ERROR: SendReqDataAscii_ATWMI(): The following tracebuf exceeded the "
1717                "maximum record size[%d] for this tank! Returning!\n",
1718            iRecordSize);
1719      trace_log( pTH );
1720      goto abort;
1721    }
1722
1723
1724    /* Check for fill, unless this is the first record AND the request is
1725       left of the tank.  So if the first requested sample is in a GAP, we
1726       will issue fill as the first sample. DK 08/09/2001 */
1727    if (bFirstBlock) 
1728    {
1729      if (tLastSample + (1.0/pTH->samprate ) <= 
1730          pTH->starttime ) 
1731      {
1732        if ( fill )
1733        {
1734         nsamp = roundup( pTH->samprate *
1735                           ( pTH->starttime - tLastSample ));
1736          if ( BulkSendFill( soc, fill,nsamp ) != R_DONE )
1737          {
1738            logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #2 failed for tank %s\n",
1739                  t->tankName );
1740            goto abort;
1741          }
1742        }
1743      }
1744    }
1745    else
1746    {
1747      if (tLastSample + ( MINIMUM_GAP_SIZE / pTH->samprate ) <= 
1748          pTH->starttime ) 
1749      {
1750        if ( fill )
1751        {
1752          /* We need to set nsamp to the number of samples between
1753             the last sampletime and the next sampletime, but remember
1754             to take into account that there should always be a
1755             1/samprate gap between samples.  This fixes a bug
1756             that caused 1 extra fill value to be inserted.
1757             DavidK 08/24/01 */
1758          /* Removed (-1) from end of statement.  The 08/24/01 fix was
1759             done because we were ending up with one(1) too many samples
1760             of fill when we missed a tracebuf and had to fill it in.
1761             Unfotunately that fix removed 2 samples of fill, instead of
1762             just one(1).  It removed MINIMUM_GAP_SIZE(~1.3) and then removed
1763             one(1) additional at the end of the statement.  The (-1) is now
1764             removed so that we theoretically end up with the correct number
1765             of samples.
1766             This fix was made in response to a complaint by Carol Bryant
1767             about problems with 99.7 Hz data.
1768             DavidK 10/11/02 */
1769          nsamp = roundup(pTH->samprate *
1770                          (pTH->starttime -
1771                           (tLastSample + ( MINIMUM_GAP_SIZE / pTH->samprate ))
1772                          )
1773                         );
1774          if ( BulkSendFill( soc, fill,nsamp ) != R_DONE )
1775          {
1776            logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #4 failed for tank %s\n",
1777                  t->tankName );
1778            goto abort;
1779          }
1780        }
1781      }
1782    }
1783
1784    iFirstSample = 0;
1785
1786    if ( bFirstBlock && tReqStart > pTH->starttime)
1787    {
1788      /* we may need to skip forward when pCurrentRecord is the first record */
1789      /* Round iFirstSample up to next sample as we did for dActStartTime above */
1790      iFirstSample = roundup(pTH->samprate * (tReqStart - pTH->starttime ));
1791      if ( _fDBG & _fPRT ) logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): adj leading iFirstSample to [%ld]\n",iFirstSample );
1792    }
1793
1794    iLastSample = (long int) pTH->nsamp;
1795    /* if the length of this record excedes our databuffer, or
1796       the current record ends after the requested endtime, then
1797       chomp some records off at the end.  */
1798    if ((pCurrentRecord + iRecordSize) > (data + iDataByteLen)) 
1799    {
1800      /* may need cut trailing samples when trace_h is the last record */
1801     iLastSample -= ((pCurrentRecord + iRecordSize) - (data + iDataByteLen) 
1802                + iDataSize - 1)/iDataSize;
1803      if ( _fDBG & _fPRT ) 
1804        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): WARNING!: record goes past end of buffer\n");
1805    }
1806    if (pTH->endtime > tReqEnd) 
1807    {
1808      /* may need cut trailing samples when trace_h is the last record */
1809      iLastSample -= roundup( pTH->samprate * ( pTH->endtime - tReqEnd ));
1810      if ( _fDBG & _fPRT ) 
1811        logit( "","SendReqDataAscii_AndThisTimeWeMeanIt(): adj trailing nsamp to [%ld]\n",iLastSample );
1812    }
1813    /* update to what we are about to send */
1814    tLastSample = pTH->starttime + (iLastSample - 1)/pTH->samprate;
1815
1816    /* Added by davidk 3/12/98, to prevent a fatal error from occuring, when
1817       SendReqDataAscii_AndThisTimeWeMeanIt() gets a wrong starting record, such that the actual
1818       requested starttime occurs after tEnd for the first record in <data>.
1819    */
1820    if (iFirstSample > iLastSample)
1821    {
1822      int temp_pCurrentRecord;
1823      TRACE2_HEADER * tempHP;
1824      logit("t","SendReqDataAscii_AndThisTimeWeMeanIt handed premature starting record.  Requested start time is past the end of current record\n");
1825      logit( "","SendReqDataAscii_AndThisTimeWeMeanIt() tank %s\n", t->tankName );
1826      logit( "","               tReqStart[%f]    tReqEnd[%f]\n", tReqStart, tReqEnd );
1827      logit( "","               tTankStart[%f]    tTankEnd[%f]\n", tTankStart, tTankEnd );
1828      logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
1829      logit( "","              len[%ld]\n", iDataByteLen );
1830      logit( "","             fill[%s]\n", fill );
1831      logit(""," thp->nsamp %d,thp->samprate %f, thp->et %f, thp->st %f\n",
1832            pTH->nsamp,pTH->samprate,pTH->endtime,pTH->starttime);
1833      for ( temp_pCurrentRecord = 0; temp_pCurrentRecord < iDataByteLen; temp_pCurrentRecord += iRecordSize )
1834      {
1835        tempHP=(TRACE2_HEADER *)(data+temp_pCurrentRecord);
1836        logit("","Record # %d :\n",temp_pCurrentRecord/iRecordSize + 1);
1837        logit("","StartTime  %f      EndTime %f\n",tempHP->starttime,tempHP->endtime);
1838        logit("","Samples    %d      SampleRate %f\n",tempHP->nsamp,tempHP->samprate);
1839      }
1840      continue;
1841    }
1842
1843
1844    blk_pos = 0L;
1845    blk_buf = (char*)malloc( (iLastSample - iFirstSample ) * ( MAX_TRACE_INT_LEN ) + 1 );
1846    if ( !blk_buf ) 
1847    {
1848      logit("et","Wave_server:Memory allocation failed in SendReqDataAscii_AndThisTimeWeMeanIt\n");
1849      logit("et","Begin SendReqDataAscii_AndThisTimeWeMeanIt dump from wave_server\n");
1850      logit("et","Nsamp = %d, iFirstSample=%d,MAX_TRACE_INT_LEN=%d\n",
1851           iLastSample,iFirstSample,MAX_TRACE_INT_LEN);
1852      logit( "","SendReqDataAscii_AndThisTimeWeMeanIt() for tank %s\n", t->tankName );
1853      logit( "","               tReqStart[%f]    tReqEnd[%f]\n", tReqStart, tReqEnd );
1854      logit( "","               tTankStart[%f]    tTankEnd[%f]\n", tTankStart, tTankEnd );
1855      logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
1856      logit( "","              len[%ld]\n", iDataByteLen );
1857      logit( "","             fill[%s]\n", fill );
1858      logit(""," thp->nsamp %d,thp->samprate %f, thp->et %f, thp->st %f\n",
1859            pTH->nsamp,pTH->samprate,pTH->endtime,pTH->starttime);
1860      goto mem_abort;
1861    }
1862    /* Finally, we convert the requested samples to ascii */
1863    for (i=iFirstSample; i<iLastSample; i++)
1864    {
1865      samp_pos = hsz + i * iDataSize;
1866      if ( iDataSize == D_SIZE_I2 )
1867        ival = (long int) *((short int*)&pCurrentRecord[samp_pos]);
1868      else /* iDataSize == D_DIZE_I4 */
1869        ival = *((long int*)&pCurrentRecord[samp_pos]);
1870      sprintf( &blk_buf[ blk_pos ], "%d ", ival );
1871      blk_pos = strlen( blk_buf );
1872    }
1873
1874    if ( _fDBG & _fPRT ) 
1875      logit("","Record being transmitted, Start %f End %f, length %d\n",pTH->starttime,pTH->endtime,blk_pos);
1876
1877    if ( (retVal=send_ew( soc, blk_buf, blk_pos, 0, SocketTimeoutLength )) != blk_pos )
1878    {
1879      logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): send_ew was not able to send %d bytes.  send_ew() returned %d. Treated as failure.\n",blk_pos,retVal);
1880      goto abort;         
1881    }
1882    free( blk_buf );
1883    blk_buf = (char*) NULL;
1884
1885    /* Need to fill in gaps at the end of last record,
1886     * but not end of tank */
1887
1888  } /* end of loop though data buffer */
1889  /* Final fill: pulled out of above loop, since it only is used when the
1890   * loop is completed: PNL, 6/25/00 */
1891  if ( (MINIMUM_GAP_SIZE / pTH->samprate ) < tReqEnd - pTH->endtime && tReqEnd < tTankEnd )
1892  {
1893    nsamp = (long) ( pTH->samprate * ( tReqEnd - tLastSample ) ); 
1894    /* sampt replaces pTH->starttime above, to get rid of
1895     * excess fill values: PNL 6/25/00 */
1896    if ( fill )
1897    {
1898      if ( BulkSendFill( soc, fill, nsamp ) != R_DONE )
1899      {
1900        logit("et","SendReqDataAscii_AndThisTimeWeMeanIt(): BulkSendFill #3 failed for tank %s\n",
1901              t->tankName );
1902        goto abort;         
1903      }
1904    }
1905  }
1906  if ( _fDBG & _fPRT ) 
1907    logit("","SRDA: dActStartTime, tLastSample [%.3f - %.3f]\n",
1908          dActStartTime, tLastSample);
1909  return(0);
1910mem_abort:
1911  return(SRDA_MEM_ABORT);
1912abort:
1913  if ( blk_buf )
1914    free( blk_buf );
1915  return(SRDA_ABORT);
1916}  /* end SendReqDataAscii_AndThisTimeWeMeanIt() */
1917
1918
1919/* function: SendReqDataAscii()
1920 *    input: int soc, socket descriptor supplied by caller
1921 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
1922 *           double tS, starting time of reqested period;
1923 *           double tE, ending time of reqested period;
1924 *           double tL, starting time of tank;
1925 *           double tR, ending time of tank;
1926 *           double acttS, starting time of period where data is available;
1927 *           double acttE, ending time of period where data is available;
1928 *           char* fill, fill value for sampling gaps;
1929 *           char* data, records of t->recSize bytes each
1930 *     note: upon entering SendReqDataAscii(), acttS == trace_h.starttime,
1931 *           where trace_h is the header record located at &data[0];
1932 *           upon leaving SendReqDataAscii(), acttE == trace_h.endtime,
1933 *           where trace_h is the header record located at &data[datasize-rsz]
1934 *   output: None
1935 *   return: R_FAIL or R_DONE
1936 *
1937 *  purpose: to send data retrieved in CopyReqData() to socket;
1938 *           called only once from main _writeTraceData{Raw|Ascii}()
1939 */
1940
1941static int SendReqDataAscii( int soc, TANK* t, double tS, double tE,
1942                             double tL, double tR,
1943                             double acttS, double acttE, char* fill,
1944                             char* data, long int datasize, char* reqid )
1945{
1946  int ret = R_FAIL;
1947  long int rsz = 0;
1948  int rc;
1949/* 
1950  long int hsz = sizeof(TRACE2_HEADER);
1951  long int rec_pos = 0L;
1952  long int nsamp = 0; /* need long int for possibly numerous fill values * /
1953  int dsz = 0;
1954  long int itr = 0;   /* need iterate through nsamp of fill values * /
1955  long int samp_pos = 0L;
1956  double sampt = tS;  /* time stamp when the last sample was sent * /
1957  long int ival = 0;
1958  char* blk_buf = (char*) NULL;
1959  long int blk_pos = 0L;
1960  int BadFirstRecord=0;
1961  int retVal;
1962  TRACE2_HEADER* trace_hp;
1963*/ 
1964
1965  if ( _fDBG & _fSUB ) 
1966  {
1967    logit( "","SendReqDataAscii()\n" );
1968    logit( "","               tS[%f]    tE[%f]\n", tS, tE );
1969    logit( "","               tL[%f]    tR[%f]\n", tL, tR );
1970    logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
1971    logit( "","              len[%ld]\n", datasize );
1972    logit( "","             fill[%s]\n", fill );
1973  }
1974
1975  if ( _fDBG & _fPRT ) 
1976    logit("","SRDA: tS,tE [%.3f,%.3f], acttS, acctE[%.3f,%.3f]\n",
1977          tS,tE,acttS,acttE);
1978
1979  if ( !t || !( rsz = t->recSize ) )
1980  {
1981    logit("et","SendReqDataAscii(): Tank  or Tank->recSize is NULL.  t=%d, t->recSize=%d\n",t,t->recSize);
1982    goto abort;
1983  }
1984
1985
1986  if ( !data && !datasize )
1987  {
1988    if ( tE <= tL - GRACE_PERIOD )      /* Davidk 3/27/98 added GRACE_PERIOD */
1989    {
1990      /* this is when request falls entirely left of tank range [tL,tR],
1991       * and acttS is the time stamp that marks beginning of tank at tL
1992       */
1993      if ( SendHeader( soc, t, reqid, "FL", acttS, DBL_FLOAT_NA,
1994                       0, YES_NEWLINE ) != R_DONE )
1995      {
1996        logit("et","SendReqDataAscii(): SendHeader #1 failed for tank %s\n",
1997              t->tankName );
1998        goto abort;          /* Line added by WMK  971108 */
1999      }
2000      goto done;
2001    }  /* end if tE < tL */
2002    else if ( tS >= tR + GRACE_PERIOD ) /* Davidk 3/27/98 added GRACE_PERIOD */
2003    {
2004      /* this is when request falls entirely right of tank range [tL,tR],
2005       * and acttE is the time stamp that marks end of tank at tR
2006       */
2007      if ( SendHeader( soc, t, reqid, "FR", DBL_FLOAT_NA, acttE,
2008                       0, YES_NEWLINE ) != R_DONE )
2009      {
2010        logit("et","SendReqDataAscii(): SendHeader #2 failed for tank %s\n",
2011              t->tankName );
2012        goto abort;          /* Line added by WMK  971108 */
2013      }
2014      goto done;
2015    }  /* end else if tS > tR */
2016    else
2017    {
2018      /* this is when the request falls entirely in a gap,
2019       * note the difference between SendReqData{Ascii|Raw()}:
2020       * here in SendReqDataAscii() tS is the 1st double, and
2021       * t->samprate is the 2nd double passed to SendFlgData();
2022       * while in SendReqDataRaw() neither acttS nor acttE is passed
2023       */
2024      double dbl_2 = t->samprate;
2025
2026      if ( _fDBG & _fALG )
2027        logit( "","SendReqDataAscii(): entirely in a gap\n" );
2028      if ( SendHeader( soc, t, reqid, "FG", tS, dbl_2, 0, 
2029                       NO_NEWLINE ) != R_DONE )
2030      {
2031        logit("et","SendReqDataAscii(): SendHeader #3 failed for tank %s\n",
2032              t->tankName );
2033        goto abort;         
2034      }
2035      if ( fill )
2036      {
2037        long int fill_cnt = (long int) (( tE - tS )*( t->samprate ));
2038
2039        if ( BulkSendFill( soc, fill, fill_cnt ) != R_DONE )
2040        {
2041          logit("et","SendReqDataAscii(): BulkSendFill #1 failed for tank %s\n",
2042                t->tankName );
2043          goto abort;         
2044        }
2045      }
2046      goto terminate;
2047    }  /* end else (! tS > tR && ! tE < tL) */
2048  }     /* end if ( !data && !datasize ) */
2049
2050  if ( !data || !datasize || ( datasize % rsz != 0 ) )
2051  {
2052    logit( "","SendReqDataAscii(): data[0x%x] size[%ld]\n", data, datasize );
2053    goto abort;
2054  }
2055   
2056
2057
2058  rc =SendReqDataAscii_AndThisTimeWeMeanIt(data, datasize, 
2059                                           tS, tE, tL, tR,
2060                                           rsz, t, soc, 
2061                                           reqid, fill, acttS, acttE);
2062
2063  if(rc)
2064  {
2065    if(rc == SRDA_ABORT)
2066      goto abort;
2067    else if(rc == SRDA_MEM_ABORT)
2068      goto mem_abort;
2069    else
2070    {
2071      logit("","SendReqDataAscii(): unexpected return code[%d] from %s\n",
2072            rc, "SendReqDataAscii_AndThisTimeWeMeanIt()");
2073      goto abort;
2074    }
2075  }
2076
2077 terminate:
2078  if ( SendStrData( soc, LN_FD_STR ) != R_DONE )
2079  {
2080    logit("et","SendReqDataAscii(): SendStrData failed for tank %s\n", t->tankName );
2081    goto abort;         
2082  }
2083 done:
2084  ret = R_DONE;
2085 mem_abort:
2086  if ( ret != R_DONE )
2087    logit( "","SendReqDataAscii(): out of memory!\n" );
2088 abort:
2089  if ( ret != R_DONE )
2090    logit( "","SendReqDataAscii(): failed\n" );
2091  return(ret);
2092}
2093
2094/* function: SendStrData()
2095 *    input: int soc, socket descriptor supplied by caller,
2096 *           char* str, string value to be sent
2097 *   return: R_FAIL or R_DONE
2098 *
2099 *  purpose: to send string to socket, called from various places
2100 */
2101
2102static int SendStrData( int soc, char* str )
2103{
2104  int ret = R_FAIL;
2105  long int slen = 0L;
2106
2107  if ( !str || !( slen = strlen( str ) ) )
2108    goto abort;
2109  if ( send_ew(soc, str, slen, 0, SocketTimeoutLength) != slen )
2110    goto abort;
2111   
2112  if ( _fDBG & _fPRT ) logit( "","%s",str );
2113
2114  ret = R_DONE;
2115 abort:
2116  if ( ret != R_DONE )
2117    logit( "","SendStrData(): failed\n" );
2118  return ret;
2119}
2120
2121/* function: trace_log()
2122 *    input: int soc, socket descriptor supplied by caller,
2123 *           char* str, string value to be sent
2124 *   return: R_FAIL or R_DONE
2125 *
2126 *  purpose: for debug use only, called only from SendReqData()
2127 */
2128
2129static int trace_log( TRACE2_HEADER* trace_hp )
2130{
2131  int ret = R_FAIL;
2132
2133  if ( !trace_hp ) goto abort;
2134
2135  logit( "","\n--------------------------------\n" );
2136  logit( "","starttime<%f>\n",trace_hp->starttime );
2137  logit( "","    nsamp<%d>\n",    trace_hp->nsamp );
2138  logit( "","    pinno<%d>\n",    trace_hp->pinno );
2139  logit( "","      sta<%s>\n",      trace_hp->sta );
2140  logit( "","     chan<%s>\n",     trace_hp->chan );
2141  logit( "","      net<%s>\n",      trace_hp->net );
2142  logit( "","      loc<%s>\n",      trace_hp->loc );
2143  logit( ""," datatype<%s>\n", trace_hp->datatype );
2144  logit( ""," samprate<%f>\n", trace_hp->samprate );
2145  logit( "","\n--------------------------------\n" );
2146  ret = R_DONE;
2147 abort:
2148  return ret;
2149}
2150
2151static const char fakeFillValue[20] = "20";
2152
2153static int BulkSendFill( int soc, char* fill, long int fill_cnt )
2154{
2155  int ret = R_FAIL;
2156  char fill_buf[kFILLVALUE_LEN + 2];
2157  char* blk_buf = (char*)NULL;
2158  long int blk_pos = 0;
2159  long int ii = 0;
2160  int len;
2161 
2162#ifdef FAKE_FILL
2163  fill = fakeFillValue;
2164#endif
2165
2166  if (!strlen(fill))
2167    goto abort;
2168  blk_buf = (char*)malloc( fill_cnt * ( strlen(fill) + 1 ) + 1 );
2169  if ( !blk_buf ) goto abort;
2170  blk_pos = 0L;
2171
2172  strcpy(fill_buf, fill);
2173  strcat(fill_buf, " ");
2174  len = strlen(fill_buf);
2175 
2176  for ( ii = 0; ii < fill_cnt; ii++)
2177  {
2178    memcpy( &blk_buf[blk_pos], fill_buf, len);
2179    blk_pos += len;
2180  }
2181  blk_buf[blk_pos] = '\0';  /* was blk_pos++, but we don't want to send
2182                               the null character to the client: PNL 6/23/00 */
2183 
2184  if ( send_ew( soc, blk_buf, blk_pos, 0, SocketTimeoutLength ) != blk_pos )
2185    goto abort;
2186  ret = R_DONE;
2187 
2188 abort:
2189  if ( blk_buf )
2190    free( blk_buf );
2191  if ( ret != R_DONE )
2192    logit( "","BulkSendFill(): failed\n" );
2193  return ret;
2194}
2195
2196/* function: SendHeader()
2197 *    input: int soc, socket descriptor supplied by caller;
2198 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
2199 *           char* reqid, ascii string from the client;
2200 *           char* flag, "FL"/"FR"/"FG";
2201 *           double tS, starting time, negative DBL_FLOAT_NA when N/A;
2202 *           double tE, ending time, negative DBL_FLOAT_NA when N/A;
2203 *           int binSize, size in bytes for binary header; 0 otherwise;
2204 *           int flagNewLine, 1 to end header with newline; 0 otherwise;
2205 *   output: None
2206 *   return: R_FAIL or R_DONE
2207 *
2208 *  purpose: to send the header preceeding binary and ascii trace data.
2209 *           called from _SendReqData{Raw|Ascii}()
2210 */
2211
2212static int SendHeader( int soc, TANK* t, char* reqid, char* flag, double tS,
2213                       double tE, int binSize, int flagNewLine)
2214{
2215  size_t len;
2216  char buffer[kMAX_CLIENT_MSG_LEN];
2217   
2218  if ( !t || !flag ) return R_FAIL;
2219   
2220  if (sizeof(int) == D_SIZE_I4)
2221    sprintf( buffer, "%s %ld %s %s %s %s %s %s ", reqid, t->pin, t->sta, t->chan,
2222             t->net, t->loc, flag, t->datatype);
2223  else  /* sizeof(int) == D_SIZE_I2 */
2224    sprintf( buffer, "%s %d %s %s %s %s %s %s ", reqid, t->pin, t->sta, t->chan,
2225             t->net, t->loc, flag, t->datatype);
2226  if ( tS > DBL_FLOAT_NA + DBL_FLOAT_EPSILON )
2227    sprintf( &buffer[strlen(buffer)], "%f ", tS);
2228  if ( tE > DBL_FLOAT_NA + DBL_FLOAT_EPSILON )
2229    sprintf( &buffer[strlen(buffer)], "%f ", tE);
2230  if (binSize > 0)
2231    sprintf( &buffer[strlen(buffer)], "%d", binSize); /* no space after size */
2232  if (flagNewLine)
2233    strcat(buffer, "\n");
2234 
2235  len = strlen(buffer);
2236  if ( send_ew(soc, buffer, len, 0, SocketTimeoutLength) != (int)len )
2237  {
2238    logit("et", "SendHeader: failed for tank %s\n", t->tankName );
2239    return R_FAIL;
2240  }
2241  return R_DONE;
2242}
2243
2244
2245/* function: SendReqDataRaw()
2246 *    input: int soc, socket descriptor supplied by caller;
2247 *           TANK* t, with the assumption t->tfp opened in "br+" mode;
2248 *           double tS, starting time of reqested period;
2249 *           double tE, ending time of reqested period;
2250 *           double tL, starting time of tank;
2251 *           double tR, ending time of tank;
2252 *           double acttS, starting time of period where data is available;
2253 *           double acttE, ending time of period where data is available;
2254 *           char* data, records of t->recSize bytes each;
2255 *           char* reqid, the client's request ID
2256 *     note: upon entering SendReqDataRaw(), acttS == trace_hp->starttime,
2257 *           where trace_hp is pointer to header record located at &data[0];
2258 *           upon leaving SendReqDataRaw(), acttE == trace_hp->endtime,
2259 *           where trace_hp is pointer to header record located at &data[datasize-rsz]
2260 *   output: None
2261 *   return: R_FAIL or R_DONE
2262 *
2263 *  purpose: to send data retrieved in CopyReqData() to socket;
2264 *           called only once from main _writeTraceDataRaw()
2265 */
2266
2267static int SendReqDataRaw( int soc, TANK* t, double tS, double tE,
2268                           double tL, double tR,
2269                           double acttS, double acttE,
2270                           char* data, long int datasize, char* reqid )
2271{
2272  int ret = R_FAIL;
2273  long int rsz = 0;
2274  long int hsz = sizeof(TRACE2_HEADER);
2275  long int rec_pos = 0L;
2276  TRACE2_HEADER* trace_hp;
2277  long int nsamp = 0; /* total count of sample data */
2278  int size;
2279  int dsz = 0;
2280
2281  if ( _fDBG & _fSUB ) {
2282    logit( "","SendReqDataRaw()\n" );
2283    logit( "","               tS[%f]    tE[%f]\n", tS, tE );
2284    logit( "","               tL[%f]    tR[%f]\n", tL, tR );
2285    logit( "","            acttS[%f] acttE[%f]\n", acttS, acttE );
2286    logit( "","              len[%ld]\n", datasize );
2287  }
2288
2289  if ( !t || !( rsz = t->recSize ) ) goto abort;
2290  if ( !data && !datasize )
2291  {
2292    if ( tE < tL )
2293    {
2294      /* this is when request falls entirely left of tank range [tL,tR],
2295       * and acttS is the time stamp that marks beginning of tank at tL
2296       */
2297      if ( SendHeader( soc, t, reqid, "FL", acttS, DBL_FLOAT_NA, 0,
2298                       YES_NEWLINE) != R_DONE )
2299        goto abort;
2300    }
2301    else if ( tS > tR )
2302    {
2303      /* this is when request entirely right of tank range [tL,tR],
2304       * and acttE is the time stamp that marks end of tank at tR
2305       */
2306      if ( SendHeader( soc, t, reqid, "FR", DBL_FLOAT_NA, acttE, 0,
2307                       YES_NEWLINE ) != R_DONE )
2308        goto abort;
2309    }
2310    else
2311    {
2312      /* this is when the request falls entirely in a gap */
2313      if ( SendHeader( soc, t, reqid, "FG", DBL_FLOAT_NA, DBL_FLOAT_NA,
2314                       0, YES_NEWLINE) !=
2315           R_DONE )
2316        goto abort;
2317    }
2318    goto done;
2319  }
2320
2321  if ( !data || !datasize || ( datasize % rsz != 0 ) )
2322  {
2323    logit( "","SendReqDataRaw(): data[0x%x] size[%ld] for tank %s\n", data,
2324           datasize, t->tankName );
2325    goto abort;
2326  }
2327   
2328  for ( rec_pos = 0; rec_pos < datasize; rec_pos += rsz )
2329  {
2330    trace_hp = (TRACE2_HEADER* ) &data[rec_pos];
2331    if ( _fDBG & _fPRT ) trace_log( trace_hp );
2332    nsamp += (long int) trace_hp->nsamp;
2333  }
2334
2335  /* since datasize != 0 && datasize % rsz == 0, we know that
2336   * trace_h now is the last record copied from data
2337   */
2338  if ( strcmp( trace_hp->datatype, "i2" ) == 0 ||
2339       strcmp( trace_hp->datatype, "s2" ) == 0 )
2340    dsz = D_SIZE_I2;
2341  else if ( strcmp( trace_hp->datatype, "i4" ) == 0 ||
2342            strcmp( trace_hp->datatype, "s4" ) == 0 )
2343    dsz = D_SIZE_I4;
2344  else
2345  {
2346    logit( "","SendReqData(): unexpected data type for tank %s[%s] - datasize %d\n", t->tankName, trace_hp->datatype, datasize );
2347    goto abort;
2348  }
2349
2350  if ( SendHeader( soc, t, reqid, "F", acttS, acttE,
2351                   datasize/rsz*hsz+dsz*nsamp, YES_NEWLINE) != R_DONE )
2352    goto abort;
2353
2354  for ( rec_pos = 0; rec_pos < datasize; rec_pos += rsz )
2355  {
2356    trace_hp = (TRACE2_HEADER *) &data[rec_pos];
2357    size = hsz + dsz * trace_hp->nsamp;
2358         
2359    if ( send_ew( soc, &data[rec_pos], size, 0, SocketTimeoutLength ) !=
2360         size )
2361      goto abort;
2362  }
2363
2364 done:
2365  ret = R_DONE;
2366 abort:
2367  if ( ret != R_DONE )
2368    logit( "","SendReqDataRaw(): failed\n" );
2369  return ret;
2370}
2371
2372int serve_trace_c_init()
2373{
2374  if (Debug > 1)
2375      logit("t","serve_trace.c:Version 1084816782\n");
2376  return(0);
2377}
Note: See TracBrowser for help on using the repository browser.