Esempio n. 1
0
/***************************************************************************
 * sl_setuniparams:
 *
 * Set the parameters for a uni-station mode connection for the
 * given SLCD struct.  If the stream entry already exists, overwrite
 * the previous settings.
 * Also sets the multistation flag to 0 (false).
 *
 *  - selectors should be 0 if there are none to use
 *  - seqnum should be -1 to start at the next data
 *  - timestamp should be 0 if it should not be used
 *
 * Returns 0 if successfully added or -1 on error.
 ***************************************************************************/
int
sl_setuniparams (SLCD * slconn, const char * selectors,
		 int seqnum, const char * timestamp)
{
  SLstream *newstream;

  newstream = slconn->streams;

  if ( newstream == NULL )
    {
      newstream = (SLstream *) malloc (sizeof(SLstream));

      if ( newstream == NULL )
	{
	  sl_log_r (slconn, 2, 0, "sl_setuniparams(): error allocating memory\n");
	  return -1;
	}
    }
  else if ( strcmp (newstream->net, UNINETWORK) != 0 ||
	    strcmp (newstream->sta, UNISTATION) != 0)
    {
      sl_log_r (slconn, 2, 0, "sl_setuniparams(): multi-station mode already configured!\n");
      return -1;
    }

  newstream->net = UNINETWORK;
  newstream->sta = UNISTATION;

  if ( selectors == 0 || selectors == NULL )
    newstream->selectors = 0;
  else
    newstream->selectors = strdup(selectors);

  newstream->seqnum = seqnum;

  if ( timestamp == 0 || timestamp == NULL )
    newstream->timestamp[0] = '\0';
  else
    strncpy(newstream->timestamp, timestamp, 20);

  newstream->next = NULL;
  
  slconn->streams = newstream;
  
  slconn->multistation = 0;

  return 0;
}  /* End of sl_setuniparams() */
Esempio n. 2
0
/***************************************************************************
 * sl_terminate:
 *
 * Set the terminate flag in the SLCD.
 ***************************************************************************/
void
sl_terminate (SLCD * slconn)
{
  sl_log_r (slconn, 1, 1, "Terminating connection\n");

  slconn->terminate = 1;
}  /* End of sl_terminate() */
Esempio n. 3
0
/***************************************************************************
 * sl_request_info:
 *
 * Add an INFO request to the SeedLink Connection Description.
 *
 * Returns 0 if successful and -1 if error.
 ***************************************************************************/
int
sl_request_info (SLCD * slconn, const char * infostr)
{
  if ( slconn->info != NULL )
    {
      sl_log_r (slconn, 2, 0, "Cannot make '%.15s' INFO request, one is already pending\n",
		infostr);
      return -1;
    }
  else
    {
      slconn->info = infostr;
      return 0;
    }
}  /* End of sl_request_info() */
/***************************************************************************
 * slp_dtime:
 *
 * Get the current time from the system as Unix/POSIX epoch time with double
 * precision.  On the WIN32 platform this function has millisecond
 * resulution, on *nix platforms this function has microsecond resolution.
 *
 * Return a double precision Unix/POSIX epoch time.
 ***************************************************************************/
double
slp_dtime (void)
{
#if defined(SLP_WIN32)

  static const __int64 SECS_BETWEEN_EPOCHS = 11644473600;
  static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */

  __int64 UnixTime;
  SYSTEMTIME SystemTime;
  FILETIME FileTime;
  double depoch;

  GetSystemTime(&SystemTime);
  SystemTimeToFileTime(&SystemTime, &FileTime);

  /* Get the full win32 epoch value, in 100ns */
  UnixTime = ((__int64)FileTime.dwHighDateTime << 32) + 
    FileTime.dwLowDateTime;

  /* Convert to the Unix epoch */
  UnixTime -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS);
  
  UnixTime /= SECS_TO_100NS; /* now convert to seconds */
  
  if ( (double)UnixTime != UnixTime )
    {
      sl_log_r (NULL, 2, 0, "slp_dtime(): resulting value is too big for a double value\n");
    }
  
  depoch = (double) UnixTime + ((double) SystemTime.wMilliseconds / 1000.0);

  return depoch;

#else

  struct timeval tv;
  
  gettimeofday (&tv, (struct timezone *) 0);
  return ((double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0));

#endif
}  /* End of slp_dtime() */
Esempio n. 5
0
/***************************************************************************
 * sl_read_streamlist:
 *
 * Read a list of streams and selectors from a file and add them to the 
 * stream chain for configuring a multi-station connection.
 *
 * If 'defselect' is not NULL or 0 it will be used as the default selectors
 * for entries will no specific selectors indicated.
 *
 * The file is expected to be repeating lines of the form:
 *   <NET> <STA> [selectors]
 * For example:
 * --------
 * # Comment lines begin with a '#' or '*'
 * GE ISP  BH?.D
 * NL HGN
 * MN AQU  BH?  HH?
 * -------- 
 *
 * Returns the number of streams configured or -1 on error.
 ***************************************************************************/
int
sl_read_streamlist (SLCD * slconn, const char * streamfile,
		    const char * defselect)
{
  char net[3];
  char sta[6];
  char selectors[100];
  char line[100];
  int streamfd;
  int fields;
  int count;
  int stacount;
  int addret;
  
  net[0] = '\0';
  sta[0] = '\0';
  selectors[0] = '\0';
  
  /* Open the stream list file */
  if ( (streamfd = slp_openfile (streamfile, 'r')) < 0 )
    {
      if (errno == ENOENT)
	{
	  sl_log_r (slconn, 2, 0, "could not find stream list file: %s\n", streamfile);
	  return -1;
	}
      else
	{
	  sl_log_r (slconn, 2, 0, "opening stream list file, %s\n", strerror (errno));
	  return -1;
	}
    }
  
  sl_log_r (slconn, 1, 1, "Reading stream list from %s\n", streamfile);
  
  count = 1;
  stacount = 0;
  
  while ( (sl_readline (streamfd, line, sizeof(line))) >= 0 )
    {
      fields = sscanf (line, "%2s %5s %99[a-zA-Z0-9!?. ]\n",
		       net, sta, selectors);
      
      /* Ignore blank or comment lines */
      if ( fields < 0 || net[0] == '#' || net[0] == '*' )
	continue;

      if ( fields < 2 )
	{
	  sl_log_r (slconn, 2, 0, "cannot parse line %d of stream list\n", count);
	}
      
      /* Add this stream to the stream chain */
      if ( fields == 3 )
	{
	  sl_addstream (slconn, net, sta, selectors, -1, NULL);
	  stacount++;
	}
      else
	{
	  addret = sl_addstream (slconn, net, sta, defselect, -1, NULL);
	  stacount++;
	}
      
	count++;
    }
  
  if ( stacount == 0 )
    {
      sl_log_r (slconn, 2, 0, "no streams defined in %s\n", streamfile);
    }
  else if ( stacount > 0 )
    {
      sl_log_r (slconn, 1, 2, "Read %d streams from %s\n", stacount, streamfile);
    }

  if ( close (streamfd) )
    {
      sl_log_r (slconn, 2, 0, "closing stream list file, %s\n", strerror (errno));
      return -1;
    }
  
  return count;
}  /* End of sl_read_streamlist() */
Esempio n. 6
0
/***************************************************************************
 * sl_parse_streamlist:
 *
 * Parse a string of streams and selectors and add them to the stream
 * chain for configuring a multi-station connection.
 *
 * The string should be of the following form:
 * "stream1[:selectors1],stream2[:selectors2],..."
 *
 * For example:
 * "IU_KONO:BHE BHN,GE_WLF,MN_AQU:HH?.D"
 * 
 * Returns the number of streams configured or -1 on error.
 ***************************************************************************/
int
sl_parse_streamlist (SLCD * slconn, const char * streamlist,
		     const char * defselect)
{
  int count = 0;
  int fields;

  const char *staselect;
  char *net;
  char *sta;

  SLstrlist *ringlist   = NULL;       /* split streamlist on ',' */
  SLstrlist *reqlist    = NULL;       /* split ringlist on ':' */
  SLstrlist *netstalist = NULL;       /* split reqlist[0] on "_" */

  SLstrlist *ringptr    = NULL;
  SLstrlist *reqptr     = NULL;
  SLstrlist *netstaptr  = NULL;

  /* Parse the streams and selectors */
  sl_strparse (streamlist, ",", &ringlist);
  ringptr = ringlist;

  while (ringptr != 0)
    {
      net = NULL;
      sta = NULL;
      staselect = NULL;
      
      fields = sl_strparse (ringptr->element, ":", &reqlist);
      reqptr = reqlist;

      /* Fill in the NET and STA fields */
      if (sl_strparse (reqptr->element, "_", &netstalist) != 2)
	{
	  sl_log_r (slconn, 2, 0, "not in NET_STA format: %s\n", reqptr->element);
	  count = -1;
	}
      else
	{
	  /* Point to the first element, should be a network code */
	  netstaptr = netstalist;
	  if (strlen (netstaptr->element) == 0)
	    {
	      sl_log_r (slconn, 2, 0, "not in NET_STA format: %s\n",
		      reqptr->element);
	      count = -1;
	    }
	  net = netstaptr->element;
	  
	  /* Point to the second element, should be a station code */
	  netstaptr = netstaptr->next;
	  if (strlen (netstaptr->element) == 0)
	    {
	      sl_log_r (slconn, 2, 0, "not in NET_STA format: %s\n",
		      reqptr->element);
	      count = -1;
	    }
	  sta = netstaptr->element;
	}

      if (fields > 1)
	{                   /* Selectors were included */
	  /* Point to the second element of reqptr, should be selectors */
	  reqptr = reqptr->next;
	  if (strlen (reqptr->element) == 0)
	    {
	      sl_log_r (slconn, 2, 0, "empty selector: %s\n", reqptr->element);
	      count = -1;
	    }
	  staselect = reqptr->element;
	}
      else  /* If no specific selectors, use the default */
	{
	  staselect = defselect;
	}
      
      /* Add this to the stream chain */
      if ( count != -1 )
        {
          sl_addstream(slconn, net, sta, staselect, -1, 0);
      	  count++;
	}

      /* Free the netstalist (the 'NET_STA' part) */
      sl_strparse (NULL, NULL, &netstalist);
      
      /* Free the reqlist (the 'NET_STA:selector' part) */
      sl_strparse (NULL, NULL, &reqlist);
      
      ringptr = ringptr->next;
    }

  if ( netstalist != NULL )
    {
      sl_strparse (NULL, NULL, &netstalist);
    }
  if ( reqlist != NULL )
    {
      sl_strparse (NULL, NULL, &reqlist);
    }
  
  if ( count == 0 )
    {
      sl_log_r (slconn, 2, 0, "no streams defined in stream list\n");
    }
  else if ( count > 0 )
    {
      sl_log_r (slconn, 1, 2, "Parsed %d streams from stream list\n", count);
    }

  /* Free the ring list */
  sl_strparse (NULL, NULL, &ringlist);
  
  return count;
}  /* End of sl_parse_streamlist() */
Esempio n. 7
0
/***************************************************************************
 * sl_addstream:
 *
 * Add a new stream entry to the stream chain for the given SLCD
 * struct.  No checking is done for duplicate streams.
 *
 *  - selectors should be 0 if there are none to use
 *  - seqnum should be -1 to start at the next data
 *  - timestamp should be 0 if it should not be used
 *
 * Returns 0 if successfully added or -1 on error.
 ***************************************************************************/
int
sl_addstream (SLCD * slconn, const char * net, const char * sta,
	      const char * selectors, int seqnum,
	      const char * timestamp)
{
  SLstream *curstream;
  SLstream *newstream;
  SLstream *laststream = NULL;
  
  curstream = slconn->streams;
  
  /* Sanity, check for a uni-station mode entry */
  if ( curstream )
    {
      if ( strcmp (curstream->net, UNINETWORK) == 0 &&
	   strcmp (curstream->sta, UNISTATION) == 0 )
	{
	  sl_log_r (slconn, 2, 0, "sl_addstream(): uni-station mode already configured!\n");
	  return -1;
	}
    }
  
  /* Search the stream chain */
  while ( curstream != NULL )
    {
      laststream = curstream;
      curstream = curstream->next;
    }
  
  newstream = (SLstream *) malloc (sizeof(SLstream));
  
  if ( newstream == NULL )
    {
      sl_log_r (slconn, 2, 0, "sl_addstream(): error allocating memory\n");
      return -1;
    }
  
  newstream->net = strdup(net);
  newstream->sta = strdup(sta);

  if ( selectors == 0 || selectors == NULL )
    newstream->selectors = 0;
  else
    newstream->selectors = strdup(selectors);

  newstream->seqnum = seqnum;

  if ( timestamp == 0 || timestamp == NULL )
    newstream->timestamp[0] = '\0';
  else
    strncpy(newstream->timestamp, timestamp, 20);

  newstream->next = NULL;
  
  if ( slconn->streams == NULL )
    {
      slconn->streams = newstream;
    }
  else if ( laststream )
    {
      laststream->next = newstream;
    }  

  slconn->multistation = 1;

  return 0;
}  /* End of sl_addstream() */
Esempio n. 8
0
/***************************************************************************
 * sl_newslcd:
 *
 * Allocate, initialze and return a pointer to a new SLCD struct.
 *
 * Returns allocated SLCD struct on success, NULL on error.
 ***************************************************************************/
SLCD *
sl_newslcd (void)
{
  SLCD * slconn;

  slconn = (SLCD *) malloc (sizeof(SLCD));

  if ( slconn == NULL )
    {
      sl_log_r (NULL, 2, 0, "new_slconn(): error allocating memory\n");
      return NULL;
    }

  /* Set defaults */
  slconn->streams        = NULL;
  slconn->sladdr         = NULL;
  slconn->begin_time     = NULL;
  slconn->end_time       = NULL;

  slconn->resume         = 1;
  slconn->multistation   = 0;
  slconn->dialup         = 0;
  slconn->batchmode      = 0;
  slconn->lastpkttime    = 0;
  slconn->terminate      = 0;
  
  slconn->keepalive      = 0;
  slconn->netto          = 600;
  slconn->netdly         = 30;
  
  slconn->link           = -1;
  slconn->info           = NULL;
  slconn->protocol_ver   = 0.0;

  /* Allocate the associated persistent state struct */
  slconn->stat = (SLstat *) malloc (sizeof(SLstat));
  
  if ( slconn->stat == NULL )
    {
      sl_log_r (NULL, 2, 0, "new_slconn(): error allocating memory\n");
      free (slconn);
      return NULL;
    }

  slconn->stat->recptr         = 0;
  slconn->stat->sendptr        = 0;
  slconn->stat->expect_info    = 0;

  slconn->stat->netto_trig     = -1;
  slconn->stat->netdly_trig    = 0;
  slconn->stat->keepalive_trig = -1;

  slconn->stat->netto_time     = 0.0;
  slconn->stat->netdly_time    = 0.0;
  slconn->stat->keepalive_time = 0.0;

  slconn->stat->sl_state       = SL_DOWN;
  slconn->stat->query_mode     = NoQuery;

  slconn->log = NULL;

  return slconn;
}  /* End of sl_newslconn() */
Esempio n. 9
0
/***************************************************************************
 * update_stream:
 *
 * Update the appropriate stream chain entries given a Mini-SEED
 * record.
 *
 * Returns 0 if successfully updated and -1 if not found or error.
 ***************************************************************************/
int
update_stream (SLCD * slconn, SLpacket * slpack)
{
  SLstream *curstream;
  struct sl_fsdh_s fsdh;
  int seqnum;
  int swapflag = 0;
  int updates = 0;
  char net[3];
  char sta[6];
  
  if ( (seqnum = sl_sequence (slpack)) == -1 )
    {
      sl_log_r (slconn, 2, 0, "update_stream(): could not determine sequence number\b");
      return -1;
    }
  
  /* Copy fixed header */
  memcpy (&fsdh, &slpack->msrecord, sizeof(struct sl_fsdh_s));
  
  /* Check to see if byte swapping is needed (bogus year makes good test) */
  if ((fsdh.start_time.year < 1900) || (fsdh.start_time.year > 2050))
    swapflag = 1;
  
  /* Change byte order? */
  if ( swapflag )
    {
      sl_gswap2 (&fsdh.start_time.year);
      sl_gswap2 (&fsdh.start_time.day);
    }
  
  curstream = slconn->streams;
  
  /* Generate some "clean" net and sta strings */
  if ( curstream != NULL )
    {
      sl_strncpclean (net, fsdh.network, 2);
      sl_strncpclean (sta, fsdh.station, 5);
    }
  
  /* For uni-station mode */
  if ( curstream != NULL )
    {
      if ( strcmp (curstream->net, UNINETWORK) == 0 &&
	   strcmp (curstream->sta, UNISTATION) == 0 )
	{
	  int month = 0;
	  int mday = 0;
	  
	  sl_doy2md (fsdh.start_time.year,
		     fsdh.start_time.day,
		     &month, &mday);
	  
	  curstream->seqnum = seqnum;
	  
	  snprintf (curstream->timestamp, 20,
		    "%04d,%02d,%02d,%02d,%02d,%02d",
		    fsdh.start_time.year,
		    month,
		    mday,
		    fsdh.start_time.hour,
		    fsdh.start_time.min,
		    fsdh.start_time.sec);
	  
	  return 0;
	}
    }
  
  /* For multi-station mode, search the stream chain and update all matching entries */
  while ( curstream != NULL )
    {
      /* Use glob matching to match wildcarded network and station codes */
      if ( sl_globmatch (net, curstream->net) &&
	   sl_globmatch (sta, curstream->sta) )
        {
	  int month = 0;
	  int mday = 0;
	  
	  sl_doy2md (fsdh.start_time.year,
		     fsdh.start_time.day,
		     &month, &mday);
	  
	  curstream->seqnum = seqnum;
	  
	  snprintf (curstream->timestamp, 20,
		    "%04d,%02d,%02d,%02d,%02d,%02d",
		    fsdh.start_time.year,
		    month,
		    mday,
		    fsdh.start_time.hour,
		    fsdh.start_time.min,
		    fsdh.start_time.sec);
	  
	  updates++;
        }
      
      curstream = curstream->next;
    }
  
  /* If no updates then no match was found */
  if ( updates == 0 )
    sl_log_r (slconn, 2, 0, "unexpected data received: %.2s %.6s\n", net, sta);
  
  return (updates == 0) ? -1 : 0;
}  /* End of update_stream() */
Esempio n. 10
0
/***************************************************************************
 * sl_collect_nb:
 *
 * Routine to manage a connection to a SeedLink server based on the values
 * given in the slconn struct and collect data.
 *
 * Designed to run in a tight loop at the heart of a client program, this
 * function is a non-blocking version sl_collect().  SLNOPACKET will be
 * returned when no data is available.
 *
 * Returns SLPACKET when something is received and sets the slpack
 * pointer to the received packet.  Returns SLNOPACKET when no packets
 * have been received, slpack is set to NULL.  When the connection was
 * closed by the server or the termination sequence completed
 * SLTERMINATE is returned and the slpack pointer is set to NULL.
 ***************************************************************************/
int
sl_collect_nb (SLCD * slconn, SLpacket ** slpack) 
{
  int    bytesread;
  double current_time;
  char   retpacket;

  *slpack = NULL;

  /* Check if the info was set */
  if ( slconn->info != NULL )
    {
      slconn->stat->query_mode = InfoQuery;
    }
  
  /* If the connection is not up check the SLCD and reset the timing variables */
  if ( slconn->link == -1 )
    {
      if ( sl_checkslcd(slconn) )
	{
	  sl_log_r (slconn, 2, 0, "problems with the connection description\n");
	  return SLTERMINATE;
	}

      slconn->stat->netto_trig     = -1;	   /* Init net timeout trigger to reset state */
      slconn->stat->keepalive_trig = -1;	   /* Init keepalive trigger to reset state */
    }

  /* Start the main sequence  */
  if ( ! slconn->terminate )
    {
      if (slconn->link == -1)
	{
	  slconn->stat->sl_state = SL_DOWN;
	}
      
      /* Check for network timeout */
      if (slconn->stat->sl_state == SL_DATA &&
	  slconn->netto && slconn->stat->netto_trig > 0)
	{
	  sl_log_r (slconn, 1, 0, "network timeout (%ds), reconnecting in %ds\n",
		    slconn->netto, slconn->netdly);
	  slconn->link = sl_disconnect (slconn);
	  slconn->stat->sl_state = SL_DOWN;
	  slconn->stat->netto_trig = -1;
	  slconn->stat->netdly_trig = -1;
	}
      
      /* Check if a keepalive packet needs to be sent */
      if (slconn->stat->sl_state == SL_DATA && !slconn->stat->expect_info &&
	  slconn->keepalive && slconn->stat->keepalive_trig > 0)
	{
	  sl_log_r (slconn, 1, 2, "sending keepalive request\n");
	  
	  if ( sl_send_info (slconn, "ID", 3) != -1 )
	    {
	      slconn->stat->query_mode = KeepAliveQuery;
	      slconn->stat->expect_info = 1;
	      slconn->stat->keepalive_trig = -1;
	    }
	}
      
      /* Check if an in-stream INFO request needs to be sent */
      if (slconn->stat->sl_state == SL_DATA &&
	  !slconn->stat->expect_info && slconn->info)
	{
	  if ( sl_send_info (slconn, slconn->info, 1) != -1 )
	    {
	      slconn->stat->query_mode = InfoQuery;
	      slconn->stat->expect_info = 1;
	    }
	  else
	    {
	      slconn->stat->query_mode = NoQuery;
	    }
	  
	  slconn->info = NULL;
	}
      
      /* Throttle the loop while delaying */
      if (slconn->stat->sl_state == SL_DOWN && slconn->stat->netdly_trig > 0)
	{
	  slp_usleep (500000);
	}
      
      /* Connect to remote SeedLink */
      if (slconn->stat->sl_state == SL_DOWN && slconn->stat->netdly_trig == 0)
	{
	  if (sl_connect (slconn, 1) != -1)
	    {
	      slconn->stat->sl_state = SL_UP;
	    }
	  slconn->stat->netto_trig = -1;
	  slconn->stat->netdly_trig = -1;
	  slconn->stat->keepalive_trig = -1;
	}
      
      /* Negotiate/configure the connection */
      if (slconn->stat->sl_state == SL_UP)
	{
	  int slconfret = 0;
	  
	  /* Only send query if a query is set and no streams are defined,
	   * if streams are defined we'll send the query after configuration.
	   */
	  if (slconn->info && slconn->streams == NULL)
	    {
	      if ( sl_send_info (slconn, slconn->info, 1) != -1 )
		{
		  slconn->stat->query_mode = InfoQuery;
		  slconn->stat->expect_info = 1;
		}
	      else
		{
		  slconn->stat->query_mode = NoQuery;
		  slconn->stat->expect_info = 0;
		}
	      
	      slconn->info = NULL;
	    }
	  else
	    {
	      slconfret = sl_configlink (slconn);
	      slconn->stat->expect_info = 0;
	    }
	  
	  if (slconfret != -1)
	    {
	      slconn->stat->recptr   = 0;	/* initialize the data buffer pointers */
	      slconn->stat->sendptr  = 0;
	      slconn->stat->sl_state = SL_DATA;
	    }
	  else
	    {
	      sl_log_r (slconn, 2, 0, "negotiation with remote SeedLink failed\n");
	      slconn->link = sl_disconnect (slconn);
	      slconn->stat->netdly_trig = -1;
	    }
	}
    }
  else /* We are terminating */
    {
      if (slconn->link != -1)
	{
	  slconn->link = sl_disconnect (slconn);
	}

      slconn->stat->sl_state = SL_DATA;
    }

  /* DEBUG
     sl_log_r (slconn, 1, 0, "link: %d, sendptr: %d, recptr: %d, diff: %d\n",
     slconn->link, slconn->stat->sendptr, slconn->stat->recptr,
     (slconn->stat->recptr - slconn->stat->sendptr) );
  */
        
  /* Process data in buffer */
  while (slconn->stat->recptr - slconn->stat->sendptr >= SLHEADSIZE + SLRECSIZE)
    {
      retpacket = 1;
      
      /* Check for an INFO packet */
      if (!strncmp (&slconn->stat->databuf[slconn->stat->sendptr], INFOSIGNATURE, 6))
	{
	  char terminator;
	  
	  terminator = (slconn->stat->databuf[slconn->stat->sendptr + SLHEADSIZE - 1] != '*');
	  
	  if ( !slconn->stat->expect_info )
	    {
	      sl_log_r (slconn, 2, 0, "unexpected INFO packet received, skipping\n");
	    }
	  else
	    {
	      if ( terminator )
		{
		  slconn->stat->expect_info = 0;
		}
	      
	      /* Keep alive packets are not returned */
	      if ( slconn->stat->query_mode == KeepAliveQuery )
		{
		  retpacket = 0;
		  
		  if ( !terminator )
		    {
		      sl_log_r (slconn, 2, 0, "non-terminated keep-alive packet received!?!\n");
		    }
		  else
		    {
		      sl_log_r (slconn, 1, 2, "keepalive packet received\n");
		    }
		}
	    }
	  
	  if ( slconn->stat->query_mode != NoQuery )
	    {
	      slconn->stat->query_mode = NoQuery;
	    }
	}
      else    /* Update the stream chain entry if not an INFO packet */
	{
	  if ( (update_stream (slconn, (SLpacket *) &slconn->stat->databuf[slconn->stat->sendptr])) == -1 )
	    {
	      /* If updating didn't work the packet is broken */
	      retpacket = 0;
	    }
	}
      
      /* Increment the send pointer */
      slconn->stat->sendptr += (SLHEADSIZE + SLRECSIZE);
      
      /* Return packet */
      if ( retpacket )
	{
	  *slpack = (SLpacket *) &slconn->stat->databuf[slconn->stat->sendptr - (SLHEADSIZE + SLRECSIZE)];
	  return SLPACKET;
	}
    }
  
  /* A trap door for terminating, all complete data packets from the buffer
     have been sent to the caller */
  if ( slconn->terminate ) {
    return SLTERMINATE;
  }
  
  /* After processing the packet buffer shift the data */
  if ( slconn->stat->sendptr )
    {
      memmove (slconn->stat->databuf,
	       &slconn->stat->databuf[slconn->stat->sendptr],
	       slconn->stat->recptr - slconn->stat->sendptr);
      
      slconn->stat->recptr -= slconn->stat->sendptr;
      slconn->stat->sendptr = 0;
    }
  
  /* Catch cases where the data stream stopped */
  if ((slconn->stat->recptr - slconn->stat->sendptr) == 7 &&
      !strncmp (&slconn->stat->databuf[slconn->stat->sendptr], "ERROR\r\n", 7))
    {
      sl_log_r (slconn, 2, 0, "SeedLink server reported an error with the last command\n");
      slconn->link = sl_disconnect (slconn);
      return SLTERMINATE;
    }
  
  if ((slconn->stat->recptr - slconn->stat->sendptr) == 3 &&
      !strncmp (&slconn->stat->databuf[slconn->stat->sendptr], "END", 3))
    {
      sl_log_r (slconn, 1, 1, "End of buffer or selected time window\n");
      slconn->link = sl_disconnect (slconn);
      return SLTERMINATE;
    }
  
  /* Process data in our buffer and then read incoming data */
  if (slconn->stat->sl_state == SL_DATA)
    {
      /* Check for more available data from the socket */
      bytesread = 0;
      
      bytesread = sl_recvdata (slconn, (void *) &slconn->stat->databuf[slconn->stat->recptr],
			       BUFSIZE - slconn->stat->recptr, slconn->sladdr);
      
      if (bytesread < 0 && ! slconn->terminate)            /* read() failed */
	{
	  slconn->link = sl_disconnect (slconn);
	  slconn->stat->netdly_trig = -1;
	}
      else if (bytesread > 0)	/* Data is here, process it */
	{
	  slconn->stat->recptr += bytesread;
	  
	  /* Reset the timeout and keepalive timers */
	  slconn->stat->netto_trig     = -1;
	  slconn->stat->keepalive_trig = -1;
	}
    }
  
  /* Update timing variables */
  current_time = sl_dtime ();

  /* Network timeout timing logic */
  if (slconn->netto)
    {
      if (slconn->stat->netto_trig == -1)	/* reset timer */
	{
	  slconn->stat->netto_time = current_time;
	  slconn->stat->netto_trig = 0;
	}
      else if (slconn->stat->netto_trig == 0 &&
	       (current_time - slconn->stat->netto_time) > slconn->netto)
	{
	  slconn->stat->netto_trig = 1;
	}
    }
  
  /* Keepalive/heartbeat interval timing logic */
  if (slconn->keepalive)
    {
      if (slconn->stat->keepalive_trig == -1)	/* reset timer */
	{
	  slconn->stat->keepalive_time = current_time;
	  slconn->stat->keepalive_trig = 0;
	}
      else if (slconn->stat->keepalive_trig == 0 &&
	       (current_time - slconn->stat->keepalive_time) > slconn->keepalive)
	{
	  slconn->stat->keepalive_trig = 1;
	}
    }
  
  /* Network delay timing logic */
  if (slconn->netdly)
    {
      if (slconn->stat->netdly_trig == -1)	/* reset timer */
	{
	  slconn->stat->netdly_time = current_time;
	  slconn->stat->netdly_trig = 1;
	}
      else if (slconn->stat->netdly_trig == 1 &&
	       (current_time - slconn->stat->netdly_time) > slconn->netdly)
	{
	  slconn->stat->netdly_trig = 0;
	}
    }
  
  /* Non-blocking and no data was returned */
  return SLNOPACKET;
  
}  /* End of sl_collect_nb() */