Example #1
0
static DskIOResult
dsk_client_stream_source_read_buffer  (DskOctetSource *source,
                                       DskBuffer      *read_buffer,
                                       DskError      **error)
{
  int rv;
  DskClientStream *stream;
  if (source->stream == NULL)
    {
      dsk_set_error (error, "read from dead stream");
      return DSK_IO_RESULT_ERROR;
    }
  stream = DSK_CLIENT_STREAM (source->stream);
  if (stream->fd < 0)
    {
      dsk_set_error (error, "read from stream with no file-descriptor");
      return DSK_IO_RESULT_ERROR;
    }
  rv = dsk_buffer_readv (read_buffer, stream->fd);
  if (rv < 0)
    {
      if (errno == EINTR || errno == EAGAIN)
        return DSK_IO_RESULT_AGAIN;
      dsk_set_error (error, "error reading data from fd %u: %s",
                     stream->fd, strerror (errno));
      return DSK_IO_RESULT_ERROR;
    }
  if (rv == 0)
    return DSK_IO_RESULT_EOF;
  ping_idle_disconnect_timer (stream);
  return DSK_IO_RESULT_SUCCESS;
}
static dsk_boolean
resize_mmap (TrivialTableCheckpoint *cp,
             unsigned                min_needed,
             DskError              **error)
{
  unsigned new_size = (min_needed + MMAP_MIN_RESIZE_GROW + MMAP_GRANULARITY - 1)
                    / MMAP_GRANULARITY
                    * MMAP_GRANULARITY;
  void *mmapped;
  if (munmap ((void*) cp->mmapped, cp->mmapped_size) < 0)
    dsk_warning ("error calling munmap(): %s", strerror (errno));
  if (ftruncate (cp->fd, new_size) < 0)
    {
      dsk_set_error (error, "error expanding file to %u bytes: %s",
                     new_size, strerror (errno));
      return DSK_FALSE;
    }
  mmapped = mmap (NULL, new_size, PROT_READ|PROT_WRITE,
                  MAP_SHARED, cp->fd, 0);
  if (mmapped == MAP_FAILED)
    {
      dsk_set_error (error, "mmap of %u bytes failed: %s",
                     new_size, strerror (errno));
      return DSK_FALSE;
    }
  cp->mmapped = mmapped;
  cp->mmapped_size = new_size;
  return DSK_TRUE;
}
Example #3
0
static DskIOResult
dsk_client_stream_sink_write_buffer  (DskOctetSink   *sink,
                                      DskBuffer      *write_buffer,
                                      DskError      **error)
{
  int rv;
  DskClientStream *stream;
  if (sink->stream == NULL)
    {
      dsk_set_error (error, "write to dead stream");
      return DSK_IO_RESULT_ERROR;
    }
  stream = DSK_CLIENT_STREAM (sink->stream);
  if (stream->fd < 0)
    {
      dsk_set_error (error, "write to stream with no file-descriptor");
      return DSK_IO_RESULT_ERROR;
    }
  rv = dsk_buffer_writev (write_buffer, stream->fd);
  if (rv < 0)
    {
      if (errno == EINTR || errno == EAGAIN)
        return DSK_IO_RESULT_AGAIN;
      dsk_set_error (error, "error writing data to fd %u: %s",
                     stream->fd, strerror (errno));
      return DSK_IO_RESULT_ERROR;
    }
  ping_idle_disconnect_timer (stream);
  return DSK_IO_RESULT_SUCCESS;
}
Example #4
0
DskJsonValue * dsk_json_parse           (size_t         len,
                                         const uint8_t *data,
                                         DskError     **error)
{
  DskJsonParser *parser = dsk_json_parser_new ();
  if (!dsk_json_parser_feed (parser, len, data, error)
   || !dsk_json_parser_finish (parser, error))
    {
      dsk_json_parser_destroy (parser);
      return NULL;
    }
  DskJsonValue *rv = dsk_json_parser_pop (parser);
  if (rv == NULL)
    {
      dsk_set_error (error, "json parser did not return any values");
      dsk_json_parser_destroy (parser);
      return NULL;
    }
  DskJsonValue *test = dsk_json_parser_pop (parser);
  if (test != NULL)
    {
      dsk_set_error (error, "json parser returned multiple values, but only one expected");
      dsk_json_parser_destroy (parser);
      dsk_json_value_free (test);
      dsk_json_value_free (rv);
      return NULL;
    }
  dsk_json_parser_destroy (parser);
  return rv;
}
Example #5
0
dsk_boolean    dsk_json_parser_finish   (DskJsonParser *parser,
                                         DskError     **error)
{
  switch (parser->lex_state)
    {
    case JSON_LEX_STATE_INIT:
      return DSK_TRUE;

    case JSON_LEX_STATE_TRUE:
      if (parser->fixed_n_chars == 4)
        {
          if (!handle_token (parser, JSON_TOKEN_TRUE, error))
            return DSK_FALSE;
          break;
        }
      else
        goto bad_lex_state;
    case JSON_LEX_STATE_FALSE:
      if (parser->fixed_n_chars == 5)
        {
          if (!handle_token (parser, JSON_TOKEN_FALSE, error))
            return DSK_FALSE;
          break;
        }
      else
        goto bad_lex_state;
    case JSON_LEX_STATE_NULL:
      if (parser->fixed_n_chars == 4)
        {
          if (!handle_token (parser, JSON_TOKEN_NULL, error))
            return DSK_FALSE;
          break;
        }
      else
        goto bad_lex_state;
    case JSON_LEX_STATE_IN_DQ:
    case JSON_LEX_STATE_IN_DQ_BS:
      goto bad_lex_state;
    case JSON_LEX_STATE_IN_NUMBER:
      if (!handle_token (parser, JSON_TOKEN_NUMBER, error))
        return DSK_FALSE;
      break;
    }
  if (parser->parse_state != PARSE_INIT)
    {
      dsk_set_error (error, "unfinished %s",
                     parser->stack[0].type == STACK_NODE_OBJECT ? "object" : "array");
      return DSK_FALSE;
    }
  return DSK_TRUE;


bad_lex_state:
  dsk_set_error (error, "invalid lex state %s at end-of-file",
                 lex_state_names[parser->lex_state]);
  return DSK_FALSE;
}
Example #6
0
static DskIOResult
dsk_ssl_sink_write (DskOctetSink *sink,
                    unsigned        max_len,
                    const void     *data_out,
                    unsigned       *n_written_out,
                    DskError      **error)
{
  DskSslStream *stream = DSK_SSL_STREAM (sink->stream);
  if (stream->handshaking)
    return DSK_IO_RESULT_AGAIN;
  int rv = SSL_write (stream->ssl, data_out, max_len);
  if (rv > 0)
    {
      *n_written_out = rv;
      return DSK_IO_RESULT_SUCCESS;
    }
  if (rv == 0)
    {
      //dsk_set_error (error, "connection closed");
      return DSK_IO_RESULT_EOF;
    }
  stream->read_needed_to_write = 0;
  switch (rv)
    {
      switch (SSL_get_error (stream->ssl, rv))
	{
	case SSL_ERROR_WANT_READ:
	  stream->read_needed_to_write = 1;
          dsk_ssl_stream_update_traps (stream);
	  return DSK_IO_RESULT_AGAIN;
	case SSL_ERROR_WANT_WRITE:
          dsk_ssl_stream_update_traps (stream);
	  return DSK_IO_RESULT_AGAIN;
	case SSL_ERROR_SYSCALL:
	  dsk_set_error (error, "Gsk-BIO interface had problems writing");
	  break;
	case SSL_ERROR_NONE:
	  dsk_set_error (error, "error writing to ssl stream, but error code set to none");
	  break;
	default:
	  {
	    unsigned long l;
	    l = ERR_peek_error();
	    dsk_set_error (error,
			   "error writing to ssl stream [in the '%s' library]: %s: %s [is-client=%d]",
			   ERR_lib_error_string(l),
			   ERR_func_error_string(l),
			   ERR_reason_error_string(l),
			   stream->is_client);
	    break;
	  }
	}
    }
  return DSK_IO_RESULT_ERROR;
}
Example #7
0
static dsk_boolean
do_handshake (DskSslStream *stream_ssl, DskError **error)
{
  int rv;
  //DEBUG (stream_ssl, ("do_handshake[client=%u]: start", stream_ssl->is_client));
  rv = SSL_do_handshake (stream_ssl->ssl);
  if (rv <= 0)
    {
      int error_code = SSL_get_error (stream_ssl->ssl, rv);
      unsigned long l = ERR_peek_error();
      switch (error_code)
	{
	case SSL_ERROR_NONE:
	  stream_ssl->handshaking = 0;
          dsk_ssl_stream_update_traps (stream_ssl);
	  break;
	case SSL_ERROR_SYSCALL:
          dsk_set_error (error, "error with underlying stream");
          return DSK_FALSE;
          break;
	case SSL_ERROR_WANT_READ:
          stream_ssl->read_needed_to_handshake = 1;
          stream_ssl->write_needed_to_handshake = 0;
          dsk_ssl_stream_update_traps (stream_ssl);
	  break;
	case SSL_ERROR_WANT_WRITE:
          stream_ssl->read_needed_to_handshake = 0;
          stream_ssl->write_needed_to_handshake = 1;
          dsk_ssl_stream_update_traps (stream_ssl);
	  break;
	default:
	  {
	    dsk_set_error (error,
			 "error doing-handshake on SSL socket: %s: %s [code=%08lx (%lu)] [rv=%d]",
			 ERR_func_error_string(l),
			 ERR_reason_error_string(l),
			 l, l, error_code);
	    return DSK_FALSE;
	  }
	}
    }
  else
    {
      stream_ssl->handshaking = 0;
      dsk_ssl_stream_update_traps (stream_ssl);
    }
  return DSK_TRUE;
}
Example #8
0
static DSK_CMDLINE_CALLBACK_DECLARE(handle_make_maze)
{
  unsigned width, height;
  unsigned y;
  Game *game;
  DSK_UNUSED (arg_name); DSK_UNUSED (callback_data);
  if (arg_value == NULL)
    width = height = 10;
  else
    {
      if (sscanf (arg_value, "%ux%u", &width, &height) != 2)
        {
          dsk_set_error (error, "error parsing WIDTHxHEIGHT for --make-maze");
          return DSK_FALSE;
        }
    }


  game = create_game ("name doesn't matter", width, height);
  for (y = 0; y < height; y++)
    {
      render_hwall_line_ascii (width, game->h_walls + width * y);
      render_vwall_line_ascii (width, game->v_walls + width * y);
    }
  render_hwall_line_ascii (width, game->h_walls);
  exit (0);
  return DSK_TRUE;
}
Example #9
0
static dsk_boolean
handle_port (const char *arg_name,
             const char *arg_value,
             void       *callback_data,
             DskError  **error)
{
  DskOctetListenerSocketOptions options
    = DSK_OCTET_LISTENER_SOCKET_OPTIONS_DEFAULT;
  DskOctetListener *listener;
  options.bind_port = strtoul (arg_value, &end, 10);
  if (arg_value == end || *end != 0)
    {
      dsk_set_error (error, "error parsing integer from '%s'", arg_value);
      return DSK_FALSE;
    }

  listener = dsk_octet_listener_socket_new (&options, error);
  if (listener == NULL)
    return DSK_FALSE;
  dsk_hook_trap (&listener->incoming,
                 (DskHookFunc) handle_incoming_connection,
                 NULL,
                 NULL);
  dsk_main_add_object (listener);
  return DSK_TRUE;
}
Example #10
0
static dsk_boolean
dsk_bz2lib_decompressor_finish (DskOctetFilter *filter,
                            DskBuffer      *out,
                            DskError      **error)
{
  DskBz2libDecompressor *decompressor = (DskBz2libDecompressor *) filter;
  DskBufferFragment *prev_last_frag;
  dsk_boolean added_fragment = DSK_FALSE;
  if (decompressor->input_ended)
    return DSK_TRUE;
  prev_last_frag = NULL;                // silence GCC
  for (;;)
    {
      DskBufferFragment *f;
      uint8_t *out_start;
      int zrv;
      if (out->last_frag == NULL
       || !fragment_has_empty_space (out->last_frag))
        {
          added_fragment = DSK_TRUE;
          prev_last_frag = out->last_frag;
          dsk_buffer_append_empty_fragment (out);
        }

      decompressor->bz2lib.next_in = NULL;
      decompressor->bz2lib.avail_in = 0;
      f = out->last_frag;
      out_start = f->buf + f->buf_start + f->buf_length;
      decompressor->bz2lib.next_out = (char*) out_start;
      decompressor->bz2lib.avail_out = f->buf_max_size - f->buf_start - f->buf_length;
      zrv = BZ2_bzDecompress (&decompressor->bz2lib);
      if (zrv == BZ_OK || zrv == BZ_STREAM_END)
        {
          unsigned amt_out = decompressor->bz2lib.next_out - (char*) out_start;
          f->buf_length += amt_out;
          out->size += amt_out;
          if (zrv == BZ_STREAM_END)
            break;
        }
      else
        {
          dsk_set_error (error, "error finishing decompression: %s [%d]",
                         bzrv_to_string (zrv), zrv);
          dsk_buffer_maybe_remove_empty_fragment (out);
          return DSK_FALSE;
        }
    }

  /* If we added a fragment that we didn't use,
     remove it. */
  if (added_fragment && out->last_frag->buf_length == 0)
    {
      dsk_buffer_fragment_free (out->last_frag);
      out->last_frag = prev_last_frag;
      if (out->last_frag == NULL)
        out->first_frag = NULL;
    }
  return DSK_TRUE;
}
Example #11
0
static dsk_boolean
dsk_bz2lib_compressor_process(DskOctetFilter *filter,
                            DskBuffer      *out,
                            unsigned        in_length,
                            const uint8_t  *in_data,
                            DskError      **error)
{
  DskBz2libCompressor *compressor = (DskBz2libCompressor *) filter;
  DskBufferFragment *prev_last_frag;
  dsk_boolean added_fragment = DSK_FALSE;
  while (in_length > 0)
    {
      DskBufferFragment *f;
      uint8_t *out_start;
      int zrv;
      if (out->last_frag == NULL
       || !fragment_has_empty_space (out->last_frag))
        {
          added_fragment = DSK_TRUE;
          prev_last_frag = out->last_frag;
          dsk_buffer_append_empty_fragment (out);
        }

      compressor->bz2lib.next_in = (char*)in_data;
      compressor->bz2lib.avail_in = in_length;

      f = out->last_frag;
      out_start = f->buf + f->buf_start + f->buf_length;
      compressor->bz2lib.next_out = (char *) out_start;
      compressor->bz2lib.avail_out = f->buf_max_size - f->buf_start - f->buf_length;
      zrv = BZ2_bzCompress (&compressor->bz2lib, BZ_RUN);
      if (zrv == BZ_OK)
        {
          unsigned amt_in = compressor->bz2lib.next_in - (char*)in_data;
          unsigned amt_out = compressor->bz2lib.next_out - (char*)out_start;
          in_length -= amt_in;
          in_data += amt_in;
          f->buf_length += amt_out;
          out->size += amt_out;
        }
      else
        {
          dsk_set_error (error, "error compressing: %s", bzrv_to_string (zrv));
          dsk_buffer_maybe_remove_empty_fragment (out);
          return DSK_FALSE;
        }
    }

  /* If we added a fragment that we didn't use,
     remove it. */
  if (added_fragment && out->last_frag->buf_length == 0)
    {
      dsk_buffer_fragment_free (out->last_frag);
      out->last_frag = prev_last_frag;
      if (out->last_frag == NULL)
        out->first_frag = NULL;
    }
  return DSK_TRUE;
}
Example #12
0
static DskIOResult
dsk_client_stream_source_read (DskOctetSource *source,
                               unsigned        max_len,
                               void           *data_out,
                               unsigned       *bytes_read_out,
                               DskError      **error)
{
  int n_read;
  DskClientStream *stream;
  if (source->stream == NULL)
    {
      dsk_set_error (error, "write to dead client stream");
      return DSK_IO_RESULT_ERROR;
    }
  stream = DSK_CLIENT_STREAM (source->stream);
  if (stream->fd < 0)
    {
      dsk_set_error (error, "no file-descriptor");
      return DSK_IO_RESULT_ERROR;
    }
  if (stream->is_connecting)
    {
      dsk_set_error (error, "file-descriptor %d not connected yet", stream->fd);
      return DSK_IO_RESULT_ERROR;
    }
  if (max_len == 0)
    {
      *bytes_read_out = 0;
      return DSK_IO_RESULT_SUCCESS;
    }
  n_read = read (stream->fd, data_out, max_len);
  if (n_read < 0)
    {
      if (errno == EINTR || errno == EAGAIN)
        return DSK_IO_RESULT_AGAIN;
      dsk_set_error (error, "error reading from client stream (fd %d): %s",
                     stream->fd, strerror (errno));
      return DSK_IO_RESULT_ERROR;
    }
  if (n_read == 0)
    return DSK_IO_RESULT_EOF;
  *bytes_read_out = n_read;
  ping_idle_disconnect_timer (stream);
  return DSK_IO_RESULT_SUCCESS;
}
Example #13
0
static DskIOResult
dsk_client_stream_sink_write  (DskOctetSink   *sink,
                               unsigned        max_len,
                               const void     *data_out,
                               unsigned       *n_written_out,
                               DskError      **error)
{
  int wrote;
  DskClientStream *stream;
  if (sink->stream == NULL)
    {
      dsk_set_error (error, "write to dead client stream");
      return DSK_IO_RESULT_ERROR;
    }
  stream = DSK_CLIENT_STREAM (sink->stream);
  if (stream->fd < 0)
    {
      dsk_set_error (error, "no file-descriptor");
      return DSK_IO_RESULT_ERROR;
    }
  if (stream->is_connecting)
    {
      dsk_set_error (error, "file-descriptor %d not connected yet", stream->fd);
      return DSK_IO_RESULT_ERROR;
    }
  if (max_len == 0)
    {
      *n_written_out = 0;
      return DSK_IO_RESULT_SUCCESS;
    }
  wrote = write (stream->fd, data_out, max_len);
  if (wrote < 0)
    {
      if (errno == EINTR || errno == EAGAIN)
        return DSK_IO_RESULT_AGAIN;
      dsk_set_error (error, "error writing to client stream (fd %d): %s",
                     stream->fd, strerror (errno));
      return DSK_IO_RESULT_ERROR;
    }
  *n_written_out = wrote;
  ping_idle_disconnect_timer (stream);
  return DSK_IO_RESULT_SUCCESS;
}
Example #14
0
dsk_boolean
dsk_url_scheme_parse (const char   *url,
                      unsigned     *scheme_length_out,
                      DskUrlScheme *scheme_out,
                      DskError    **error)
{
  const char *p = url;
  while (dsk_ascii_isalpha (*p))
    p++;
  if (*p != ':')
    {
      dsk_set_error (error, "missing ':' in URL");
      return DSK_FALSE;
    }
  *scheme_length_out = p + 1 - url;
   if ((url[0] == 'h' || url[0] == 'H')
    && (url[1] == 't' || url[1] == 'T')
    && (url[2] == 't' || url[2] == 'T')
    && (url[3] == 'p' || url[3] == 'P'))
    {
      if (p - url == 4)
        {
          *scheme_out = DSK_URL_SCHEME_HTTP;
          return DSK_TRUE;
        }
      else if (p - url == 5 && (p[4] == 's' || p[4] == 'S'))
        {
          *scheme_out = DSK_URL_SCHEME_HTTPS;
          return DSK_TRUE;
        }
    }
  else if ((url[0] == 'f' || url[0] == 'F')
        && (url[1] == 't' || url[1] == 'T')
        && (url[2] == 'p' || url[2] == 'P')
        && p - url == 3)
    {
      *scheme_out = DSK_URL_SCHEME_FTP;
      return DSK_TRUE;
    }
  dsk_set_error (error, "unknown scheme %.*s", (int)(p - url), url);
  return DSK_FALSE;
}
Example #15
0
static DSK_CMDLINE_CALLBACK_DECLARE(handle_dsk_log_timezone)
{
  char *end;
  DSK_UNUSED (callback_data);
  if (!dsk_date_parse_timezone (arg_value, &end, &dsk_daemon_tzoffset))
    {
      dsk_set_error (error, "bad timezone argument '%s' to --%s",
                     arg_value, arg_name);
      return DSK_FALSE;
    }
  dsk_daemon_tzoffset *= 60;
  return DSK_TRUE;
}
Example #16
0
static dsk_boolean
dsk_hex_decoder_finish(DskOctetFilter *filter,
                       DskBuffer      *out,
                       DskError      **error)
{
  DskHexDecoder *dec = (DskHexDecoder *) filter;
  DSK_UNUSED (out);
  if (dec->has_nibble)
    {
      dsk_set_error (error, "stray nibble encountered- incomplete byte in hex-data");
      return DSK_FALSE;
    }
  return DSK_TRUE;
}
Example #17
0
DskSslContext    *
dsk_ssl_context_new   (DskSslContextOptions *options,
                       DskError            **error)
{
  const SSL_METHOD *method = SSLv3_method ();
  SSL_CTX *ctx = SSL_CTX_new (method);
  DskSslContext *rv = dsk_object_new (&dsk_ssl_context_class);
  rv->ctx = ctx;
  if (options->password)
    {
      rv->password = dsk_strdup (options->password);
      SSL_CTX_set_default_passwd_cb (ctx, set_password_cb);
      SSL_CTX_set_default_passwd_cb_userdata (ctx, rv);
    }
  if (options->cert_filename)
    {
      if (SSL_CTX_use_certificate_file (ctx, options->cert_filename,
                                        SSL_FILETYPE_PEM) != 1)
        {
          dsk_set_error (error, "error using certificate file %s",
                         options->cert_filename);
          dsk_object_unref (rv);
          return NULL;
        }
    }
  if (options->key_filename)
    {
      if (SSL_CTX_use_PrivateKey_file (ctx, options->key_filename, SSL_FILETYPE_PEM) != 1)
        {
          dsk_set_error (error, "error using key file %s",
                         options->key_filename);
          dsk_object_unref (rv);
          return NULL;
        }
    }
  return rv;
}
Example #18
0
dsk_boolean
dsk_ssl_stream_new         (DskSslStreamOptions   *options,
                            DskSslStream         **stream_out,
                            DskOctetSource       **source_out,
                            DskOctetSink         **sink_out,
                            DskError             **error)
{
  DskSslStream *stream;
  DskSslSink *sink;
  DskSslSource *source;

  if (sink_out == NULL || source_out == NULL)
    {
      dsk_set_error (error, "dsk_ssl_stream_new: sink/source");
      return DSK_FALSE;
    }

  sink = dsk_object_new (&dsk_ssl_sink_class);
  source = dsk_object_new (&dsk_ssl_source_class);
  stream = dsk_object_new (&dsk_ssl_stream_class);

  BIO *bio;
  bio = BIO_new (&bio_method__ssl_underlying_stream);
  bio->ptr = stream;
  bio->init = 1;		/// HMM...
  stream->ssl = SSL_new (options->context->ctx);
  stream->context = dsk_object_ref (options->context);
  SSL_set_bio (stream->ssl, bio, bio);
  stream->base_instance.sink = DSK_OCTET_SINK (sink);        /* does not own */
  stream->base_instance.source = DSK_OCTET_SOURCE (source); /* does not own */
  stream->is_client = options->is_client ? 1 : 0;
  stream->handshaking = DSK_TRUE;
  sink->base_instance.stream = dsk_object_ref (stream);
  source->base_instance.stream = dsk_object_ref (stream);

  if (stream->is_client)
    SSL_set_connect_state (stream->ssl);
  else
    SSL_set_accept_state (stream->ssl);

  *sink_out = DSK_OCTET_SINK (sink);
  *source_out = DSK_OCTET_SOURCE (source);

  if (stream_out != NULL)
    *stream_out = stream;
  else
    dsk_object_unref (stream);
  return DSK_TRUE;
}
Example #19
0
static dsk_boolean
dsk_hex_decoder_process (DskOctetFilter *filter,
                            DskBuffer      *out,
                            unsigned        in_length,
                            const uint8_t  *in_data,
                            DskError      **error)
{
  DskHexDecoder *hexdec = (DskHexDecoder *) filter;
  DSK_UNUSED (error);
  while (in_length)
    {
      if (dsk_ascii_isxdigit (*in_data))
        {
          if (hexdec->has_nibble)
            {
              dsk_buffer_append_byte (out,
                                      (hexdec->nibble << 4)
                                      | dsk_ascii_xdigit_value (*in_data));
              hexdec->has_nibble = DSK_FALSE;
            }
          else
            {
              hexdec->nibble = dsk_ascii_xdigit_value (*in_data);
              hexdec->has_nibble = DSK_TRUE;
            }
          in_data++;
          in_length--;
        }
      else if (dsk_ascii_isspace (*in_data))
        {
          in_data++;
          in_length--;
        }
      else
        {
          dsk_set_error (error, "bad character %s in hex-data",
                         dsk_ascii_byte_name (*in_data));
          return DSK_FALSE;
        }
    }
  return DSK_TRUE;
}
Example #20
0
dsk_boolean
dsk_client_stream_new       (DskClientStreamOptions *options,
                             DskClientStream **stream_out,
                             DskOctetSink    **sink_out,
                             DskOctetSource  **source_out,
                             DskError        **error)
{
  DskClientStream *rv;
  dsk_boolean has_address = !ip_address_is_default (&options->address);

  /* check trivial usage considerations */
  dsk_warn_if_fail (!(options->hostname != NULL && has_address),
                    "ignoring ip-address because symbolic name given");
  if (options->hostname != NULL || has_address)
    {
      if (options->port == 0)
        {
          dsk_set_error (error,
                         "port must be non-zero for client (hostname is '%s')",
                         options->hostname);
          return DSK_FALSE;
        }
      dsk_warn_if_fail (options->path == NULL,
                        "cannot decide between tcp and local client");
    }

  rv = dsk_object_new (&dsk_client_stream_class);
  rv->base_instance.sink = dsk_object_new (&dsk_client_stream_sink_class);
  rv->base_instance.source = dsk_object_new (&dsk_client_stream_source_class);
  rv->base_instance.sink->stream = dsk_object_ref (rv);
  rv->base_instance.source->stream = dsk_object_ref (rv);
  rv->reconnect_time_ms = -1;
  rv->idle_disconnect_time_ms = -1;
  rv->fd = -1;

  if (options->hostname != NULL)
    {
      if (dsk_hostname_looks_numeric (options->hostname))
        rv->is_numeric_name = 1;
      rv->name = dsk_strdup (options->hostname);
      rv->port = options->port;
    }
  else if (has_address)
    {
      rv->is_numeric_name = 1;
      rv->name = dsk_ip_address_to_string (&options->address);
      rv->port = options->port;
    }
  else if (options->path != NULL)
    {
      rv->is_local_socket = 1;
      rv->name = dsk_strdup (options->path);
    }
  rv->idle_disconnect_time_ms = options->idle_disconnect_time;
  rv->reconnect_time_ms = options->reconnect_time;
  begin_connecting (rv);
  if (options->idle_disconnect_time >= 0)
    dsk_client_stream_set_max_idle_time (rv, options->idle_disconnect_time);
  if (options->reconnect_time >= 0)
    dsk_client_stream_set_reconnect_time (rv, options->reconnect_time);
  if (source_out)
    *source_out = rv->base_instance.source;
  else if (rv->base_instance.source)
    dsk_object_unref (rv->base_instance.source);
  if (sink_out)
    *sink_out = rv->base_instance.sink;
  else if (rv->base_instance.sink)
    dsk_object_unref (rv->base_instance.sink);
  if (stream_out)
    *stream_out = rv;
  else
    dsk_object_unref (rv);
  return DSK_TRUE;
}
Example #21
0
/* Parse a [] character class expression */
static struct CharClass *
parse_character_class (const char **p_regex,
                       DskMemPool  *pool,
                       DskError   **error)
{
  const char *at = *p_regex;
  dsk_boolean reverse = DSK_FALSE;
  struct CharClass *out = dsk_mem_pool_alloc0 (pool, sizeof (struct CharClass));
  if (*at == '^')
    {
      reverse = DSK_TRUE;
      at++;
    }
  while (*at != 0 && *at != ']')
    {
      /* this muck is structured annoyingly:  we just to the label
         got_range_start_and_dash whenever we encounter a '-' after
         a single character (either literally or as a backslash sequence),
         to handle range expressions. */
      unsigned first_value;

      if (*at == '\\')
        {
          struct CharClass *sub;
          at++;
          if (!get_backslash_char_class (&at, &sub))
            {
              *p_regex = at;    /* for error reporting (maybe?) */
              dsk_set_error (error, "bad \\ expression (at %s)", dsk_ascii_byte_name (*at));
              return NULL;
            }
          if (IS_SINGLE_CHAR_CLASS (sub) && *at == '-')
            {
              first_value = SINGLE_CHAR_CLASS_GET_CHAR (sub);
              at++;
              goto got_range_start_and_dash;
            }
          char_class_union_inplace (out, sub);
        }
      else if (at[1] == '-')
        {
          first_value = *at;
          at += 2;
          goto got_range_start_and_dash;
        }
      else
        {
          /* single character */
          CHAR_CLASS_BITVEC_SET (out, *at);
          at++;
        }

      continue;
got_range_start_and_dash:
      {
        unsigned last_value;
        unsigned code;
        if (*at == '\\')
          {
            struct CharClass *sub;
            const char *start;
            at++;
            start = at;
            if (!get_backslash_char_class (&at, &sub))
              {
                *p_regex = at;    /* for error reporting (maybe?) */
                dsk_set_error (error, "bad \\ expression (at %s)", dsk_ascii_byte_name (*at));
                return NULL;
              }
            if (!IS_SINGLE_CHAR_CLASS (sub))
              {
                dsk_set_error (error, "non-single-byte \\%c encountered - cannot use in range", *start);
                return NULL;
              }
            last_value = SINGLE_CHAR_CLASS_GET_CHAR (sub);
          }
        else if (*at == ']')
          {
            /* syntax error */
            dsk_set_error (error, "unterminated character class range");
            return NULL;
          }
        else
          {
            last_value = *at;
            at++;
          }

        if (first_value > last_value)
          {
            dsk_set_error (error, "character range is not first<last (first=%s, last=%s)",
                           dsk_ascii_byte_name (first_value),
                           dsk_ascii_byte_name (last_value));
            return NULL;
          }
        for (code = first_value; code <= last_value; code++)
          CHAR_CLASS_BITVEC_SET (out, code);
      }
    }
  *p_regex = at;
  if (reverse)
    char_class_reverse_inplace (out);
  return out;
}
Example #22
0
/* --- lexing --- */
dsk_boolean
dsk_json_parser_feed     (DskJsonParser *parser,
                          size_t         n_bytes,
                          const uint8_t *bytes,
                          DskError     **error)
{
  while (n_bytes > 0)
    {
      switch (parser->lex_state)
        {
        case JSON_LEX_STATE_INIT:
          while (n_bytes > 0 && dsk_ascii_isspace (*bytes))
            {
              if (*bytes == '\n')
                parser->line_no++;
              bytes++;
              n_bytes--;
            }
          if (n_bytes == 0)
            break;
          switch (*bytes)
            {
            case 't': case 'T':
              parser->lex_state = JSON_LEX_STATE_TRUE;
              parser->fixed_n_chars = 1;
              bytes++;
              n_bytes--;
              break;
            case 'f': case 'F':
              parser->lex_state = JSON_LEX_STATE_FALSE;
              parser->fixed_n_chars = 1;
              bytes++;
              n_bytes--;
              break;
            case 'n': case 'N':
              parser->lex_state = JSON_LEX_STATE_NULL;
              parser->fixed_n_chars = 1;
              bytes++;
              n_bytes--;
              break;
            case '"':
              parser->lex_state = JSON_LEX_STATE_IN_DQ;
              parser->str_len = 0;
              bytes++;
              n_bytes--;
              break;
            case '-': case '+':
            case '0': case '1': case '2': case '3': case '4': 
            case '5': case '6': case '7': case '8': case '9': 
              parser->lex_state = JSON_LEX_STATE_IN_NUMBER;
              parser->str_len = 0;
              append_to_string_buffer (parser, 1, bytes);
              bytes++;
              n_bytes--;
              break;

#define WRITE_CHAR_TOKEN_CASE(character, SHORTNAME) \
            case character: \
              if (!handle_token (parser, JSON_TOKEN_##SHORTNAME, error)) \
                return DSK_FALSE; \
              n_bytes--; \
              bytes++; \
              break
            WRITE_CHAR_TOKEN_CASE('{', LBRACE);
            WRITE_CHAR_TOKEN_CASE('}', RBRACE);
            WRITE_CHAR_TOKEN_CASE('[', LBRACKET);
            WRITE_CHAR_TOKEN_CASE(']', RBRACKET);
            WRITE_CHAR_TOKEN_CASE(',', COMMA);
            WRITE_CHAR_TOKEN_CASE(':', COLON);
#undef WRITE_CHAR_TOKEN_CASE

            case '\n':
              parser->line_no++;
              n_bytes--;
              bytes++;
              break;
            case '\t': case '\r': case ' ':
              n_bytes--;
              bytes++;
              break;
            default:
              dsk_set_error (error,
                             "unexpected character %s in json (line %u)",
                             dsk_ascii_byte_name (*bytes), parser->line_no);
              return DSK_FALSE;
            }
          break;

#define WRITE_FIXED_BAREWORD_CASE(SHORTNAME, lc, UC, length) \
        case JSON_LEX_STATE_##SHORTNAME: \
          if (parser->fixed_n_chars == length) \
            { \
              /* are we at end of string? */ \
              if (dsk_ascii_isalnum (*bytes)) \
                { \
                  dsk_set_error (error,  \
                                 "got %s after '%s' (line %u)", \
                                 dsk_ascii_byte_name (*bytes), lc, \
                                 parser->line_no); \
                  return DSK_FALSE; \
                } \
              else \
                { \
                  parser->lex_state = JSON_LEX_STATE_INIT; \
                  if (!handle_token (parser, JSON_TOKEN_##SHORTNAME, \
                                     error)) \
                    return DSK_FALSE; \
                } \
            } \
          else if (*bytes == lc[parser->fixed_n_chars] \
                || *bytes == UC[parser->fixed_n_chars]) \
            { \
              parser->fixed_n_chars += 1; \
              n_bytes--; \
              bytes++; \
            } \
          else \
            { \
              dsk_set_error (error, \
                           "unexpected character %s (parsing %s) (line %u)", \
                           dsk_ascii_byte_name (*bytes), UC, parser->line_no); \
              return DSK_FALSE; \
            } \
          break;
        WRITE_FIXED_BAREWORD_CASE(TRUE, "true", "TRUE", 4);
        WRITE_FIXED_BAREWORD_CASE(FALSE, "false", "FALSE", 5);
        WRITE_FIXED_BAREWORD_CASE(NULL, "null", "NULL", 4);
#undef WRITE_FIXED_BAREWORD_CASE

        case JSON_LEX_STATE_IN_DQ:
          if (*bytes == '"')
            {
              // TODO ASSERT utf16_surrogate == 0
              if (!handle_token (parser, JSON_TOKEN_STRING, error))
                return DSK_FALSE;
              bytes++;
              n_bytes--;
              parser->lex_state = JSON_LEX_STATE_INIT;
            }
          else if (*bytes == '\\')
            {
              n_bytes--;
              bytes++;
              parser->bs_sequence_len = 0;
              parser->lex_state = JSON_LEX_STATE_IN_DQ_BS;
            }
          else
            {
              // TODO ASSERT utf16_surrogate == 0
              unsigned i;
              if (*bytes == '\n')
                parser->line_no++;
              for (i = 1; i < n_bytes; i++)
                if (bytes[i] == '"' || bytes[i] == '\\')
                  break;
                else if (bytes[i] == '\n')
                  parser->line_no++;
              append_to_string_buffer (parser, i, bytes);
              n_bytes -= i;
              bytes += i;
            }
          break;
        case JSON_LEX_STATE_IN_DQ_BS:
          if (parser->bs_sequence_len == 0)
            {
              switch (*bytes)
                {
#define WRITE_BS_CHAR_CASE(bschar, cchar) \
                case bschar: \
                  /* TODO ASSERT utf16_surrogate == 0 */ \
                  append_char_to_string_buffer (parser, cchar); \
                  bytes++; \
                  n_bytes--; \
                  parser->lex_state = JSON_LEX_STATE_IN_DQ; \
                  break
                WRITE_BS_CHAR_CASE('b', '\b');
                WRITE_BS_CHAR_CASE('f', '\f');
                WRITE_BS_CHAR_CASE('n', '\n');
                WRITE_BS_CHAR_CASE('r', '\r');
                WRITE_BS_CHAR_CASE('t', '\t');
                WRITE_BS_CHAR_CASE('/', '/');
                WRITE_BS_CHAR_CASE('"', '"');
                WRITE_BS_CHAR_CASE('\\', '\\');
#undef WRITE_BS_CHAR_CASE
                case 'u':
                  parser->bs_sequence[parser->bs_sequence_len++] = *bytes++;
                  n_bytes--;
                  break;
                default:
                  dsk_set_error (error,
                               "invalid character %s after '\\' (line %u)",
                               dsk_ascii_byte_name (*bytes), parser->line_no);
                  return DSK_FALSE;
                }
            }
          else
            {
              /* must be \uxxxx (the only multi-character \ sequence) */
              if (!dsk_ascii_isxdigit (*bytes))
                {
                  dsk_set_error (error,
                               "expected 4 hex digits after \\u, got %s (line %u)",
                               dsk_ascii_byte_name (*bytes), parser->line_no);
                  return DSK_FALSE;
                }
              parser->bs_sequence[parser->bs_sequence_len++] = *bytes++;
              n_bytes--;
              if (parser->bs_sequence_len == 5)
                {
                  char utf8buf[8];
                  unsigned value;
                  parser->bs_sequence[5] = 0;
                  value = strtoul (parser->bs_sequence + 1, NULL, 16);
                  if (DSK_UTF16_LO_SURROGATE_START <= value
                   && value <= DSK_UTF16_LO_SURROGATE_END)
                    {
                      if (parser->utf16_surrogate == 0)
                        {
                          dsk_set_error (error,
                                       "low (second) half of surrogate pair was encountered without high-half, line %u",
                                       parser->line_no);
                          return DSK_FALSE;
                        }
                      uint32_t code = dsk_utf16_surrogate_pair_to_codepoint (parser->utf16_surrogate, value);
                      append_to_string_buffer (parser,
                                               dsk_utf8_encode_unichar (utf8buf, code),
                                               (const uint8_t *) utf8buf);
                      parser->utf16_surrogate = 0;
                    }
                  else if (DSK_UTF16_HI_SURROGATE_START <= value
                        && value <= DSK_UTF16_HI_SURROGATE_END)
                    {
                      if (parser->utf16_surrogate != 0)
                        {
                          dsk_set_error (error,
                                       "got two first-half surrogate pairs (UTF16 surrogate \\u%04u was followed by \\%04u), line %u",
                                       parser->utf16_surrogate, value, parser->line_no);
                          return DSK_FALSE;
                        }
                      parser->utf16_surrogate = value;
                    }
                  else
                    {
                      if (parser->utf16_surrogate != 0)
                        {
                          dsk_set_error (error,
                                       "second half of UTF16 surrogate \\u%04u was not preceded by utf16, line %u", 
                                       parser->utf16_surrogate, parser->line_no);
                          return DSK_FALSE;
                        }
                      append_to_string_buffer (parser,
                                               dsk_utf8_encode_unichar (utf8buf, value),
                                               (const uint8_t *) utf8buf);
                      parser->utf16_surrogate = 0;
                    }
                  parser->lex_state = JSON_LEX_STATE_IN_DQ;
                }
#if 0
              else
                {
                  dsk_set_error (error,
                               "internal error: expected 4 hex digits (line %u)",
                               parser->line_no);
                  return DSK_FALSE;
                }
#endif
            }
          break;
        case JSON_LEX_STATE_IN_NUMBER:
          if (dsk_ascii_isdigit (*bytes)
           || *bytes == '.'
           || *bytes == 'e'
           || *bytes == 'E'
           || *bytes == '+'
           || *bytes == '-')
            {
              append_to_string_buffer (parser, 1, bytes);
              bytes++;
              n_bytes--;
            }
          else
            {
              /* append the number token */
              if (!handle_token (parser, JSON_TOKEN_NUMBER, error))
                return DSK_FALSE;

              /* go back to init state (do not consume character) */
              parser->lex_state = JSON_LEX_STATE_INIT;
            }
          break;
        default:
          dsk_error ("unhandled lex state %u", parser->lex_state);
        }
    }
  return DSK_TRUE;
}
Example #23
0
static dsk_boolean
handle_token (DskJsonParser *parser,
              JsonTokenType  token,
              DskError     **error)
{
  switch (parser->parse_state)
    {
    case PARSE_INIT:                           /* expecting value */
    case PARSE_GOT_MEMBER_COLON:               /* expecting subvalue */
      if (!is_allowed_subvalue_token (token))
        goto bad_token;
      handle_expected_subvalue (parser, token);
      break;
    case PARSE_EXPECTING_ELEMENT:              /* expecting subvalue */
      if (token == JSON_TOKEN_RBRACKET)
        array_finished (parser);
      else if (!is_allowed_subvalue_token (token))
        goto bad_token;
      else
        handle_expected_subvalue (parser, token);
      break;
    case PARSE_EXPECTING_MEMBER:
      if (token == JSON_TOKEN_STRING)
        {
          /* add new member; copy string */
          char *name;
          DskJsonMember *member;
          if (STACK_TOP (parser).n_subs == STACK_TOP (parser).subs_alloced)
            stack_increase_subs_alloced (&STACK_TOP (parser));
          name = dsk_strndup (parser->str_len, parser->str);
          member = &STACK_TOP (parser).u.members[STACK_TOP (parser).n_subs++];
          member->name = name;
          member->value = NULL;

          parser->parse_state = PARSE_GOT_MEMBER_NAME;
        }
      else if (token == JSON_TOKEN_RBRACE)
        object_finished (parser);
      else
        goto bad_token;
      break;
    case PARSE_GOT_MEMBER_NAME:
      if (token != JSON_TOKEN_COLON)
        goto bad_token;
      else
        parser->parse_state = PARSE_GOT_MEMBER_COLON;
      break;
    case PARSE_GOT_MEMBER:                     /* expecting , or } */
      if (token == JSON_TOKEN_COMMA)
        parser->parse_state = PARSE_EXPECTING_MEMBER;
      else if (token == JSON_TOKEN_RBRACE)
        {
          object_finished (parser);
        }
      else
        goto bad_token;
      break;
    case PARSE_GOT_ELEMENT:                    /* expecting , or ] */
      if (token == JSON_TOKEN_COMMA)
        parser->parse_state = PARSE_EXPECTING_ELEMENT;
      else if (token == JSON_TOKEN_RBRACKET)
        {
          /* create array */
          DskJsonValue *array;
          array = dsk_json_value_new_array (STACK_TOP(parser).n_subs,
                                            STACK_TOP(parser).u.values);

          /* pop the stack */
          parser->stack_size--;

          /* deal with the new array */
          handle_subvalue (parser, array);
        }
      else
        goto bad_token;
      break;
    }
  parser->str_len = 0;
  return DSK_TRUE;

bad_token:
  dsk_set_error (error, "got unexpected token %s: %s (line %u)",
                 token_names[token],
                 parse_state_expecting_strings[parser->parse_state],
                 parser->line_no);
  parser->str_len = 0;
  return DSK_FALSE;
}
Example #24
0
static dsk_boolean
tokenize (const char   *regex,
          struct Token **token_list_out,
          DskMemPool   *pool,
          DskError    **error)
{
  struct Token *last = NULL;
  *token_list_out = NULL;
  while (*regex)
    {
      struct Token *t = dsk_mem_pool_alloc (pool, sizeof (struct Token));
      switch (*regex)
        {
        case '*':
          t->type = TOKEN_STAR;
          regex++;
          break;
        case '+':
          t->type = TOKEN_PLUS;
          regex++;
          break;
        case '?':
          t->type = TOKEN_QUESTION_MARK;
          regex++;
          break;
        case '(':
          t->type = TOKEN_LPAREN;
          regex++;
          break;
        case ')':
          t->type = TOKEN_RPAREN;
          regex++;
          break;
        case '|':
          t->type = TOKEN_ALTER;
          regex++;
          break;
        case '[':
          {
            struct CharClass *cclass;
            /* parse character class */
            regex++;
            cclass = parse_character_class (&regex, pool, error);
            if (cclass == NULL || *regex != ']')
              return DSK_FALSE;
            regex++;
            t->type = TOKEN_PATTERN;
            t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
            t->pattern->type = PATTERN_LITERAL;
            t->pattern->info.literal = cclass;
            break;
          }
        case '\\':
          {
            /* parse either char class or special literal */
            struct CharClass *cclass;
            regex++;
            if (get_backslash_char_class (&regex, &cclass))
              {
                t->type = TOKEN_PATTERN;
                t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
                t->pattern->type = PATTERN_LITERAL;
                t->pattern->info.literal = cclass;
              }
            else
              {
                if (regex[1] == 0)
                  dsk_set_error (error, "unexpected backslash sequence in regex");
                else
                  dsk_set_error (error, "bad char %s after backslash", dsk_ascii_byte_name (regex[1]));
                return DSK_FALSE;
              }
            break;
          }
        case '.':
          t->type = TOKEN_PATTERN;
          t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
          t->pattern->type = PATTERN_LITERAL;
          t->pattern->info.literal = &char_class_dot;
          regex++;
          break;
        default:
          /* character literal */
          t->type = TOKEN_PATTERN;
          t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
          t->pattern->type = PATTERN_LITERAL;
          t->pattern->info.literal = MK_LITERAL_CHAR_CLASS (regex[0]);
          regex++;
          break;
        }

      /* append to list */
      t->prev = last;
      t->next = NULL;
      if (last)
        last->next = t;
      else
        *token_list_out = last = t;
      last = t;
    }
  return DSK_TRUE;
}
Example #25
0
static struct Pattern *
parse_pattern (unsigned      pattern_index,
               struct Token *token_list,
               DskMemPool   *pool,
               DskError    **error)
{
  dsk_boolean last_was_alter;
  dsk_boolean accept_empty;

  /* Handle parens */
  struct Token *token;
  for (token = token_list; token; token = token->next)
    if (token->type == TOKEN_LPAREN)
      {
        /* find matching rparen (or error) */
        struct Token *rparen = token->next;
        int balance = 1;
        struct Pattern *subpattern;
        while (rparen)
          {
            if (rparen->type == TOKEN_LPAREN)
              balance++;
            else if (rparen->type == TOKEN_RPAREN)
              {
                balance--;
                if (balance == 0)
                  break;
              }
            rparen = rparen->next;
          }
        if (balance)
          {
            /* missing right-paren */
            dsk_set_error (error, "missing right-paren in regex");
            return NULL;
          }

        /* recurse */
        rparen->prev->next = NULL;
        subpattern = parse_pattern (pattern_index, token->next, pool, error);
        if (subpattern == NULL)
          return NULL;

        /* replace parenthesized expr with subpattern; slice out remainder of list */
        token->type = TOKEN_PATTERN;
        token->pattern = subpattern;
        token->next = rparen->next;
        if (rparen->next)
          token->next->prev = token;
      }
    else if (token->type == TOKEN_RPAREN)
      {
        dsk_set_error (error, "unexpected right-paren in regex");
        return NULL;
      }

  /* Handle star/plus/qm */
  for (token = token_list; token; token = token->next)
    if (token->type == TOKEN_QUESTION_MARK
     || token->type == TOKEN_STAR
     || token->type == TOKEN_PLUS)
      {
        struct Pattern *new_pattern;
        if (token->prev == NULL || token->prev->type != TOKEN_PATTERN)
          {
            dsk_set_error (error, "'%c' must be precede by pattern",
                           token->type == TOKEN_QUESTION_MARK ? '?' 
                           : token->type == TOKEN_STAR ? '*'
                           : '+');
            return NULL;
          }
        new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
        switch (token->type)
          {
          case TOKEN_QUESTION_MARK:
            new_pattern->type = PATTERN_OPTIONAL;
            new_pattern->info.optional = token->prev->pattern;
            break;
          case TOKEN_STAR:
            new_pattern->type = PATTERN_STAR;
            new_pattern->info.star = token->prev->pattern;
            break;
          case TOKEN_PLUS:
            new_pattern->type = PATTERN_PLUS;
            new_pattern->info.plus = token->prev->pattern;
            break;
          default:
            dsk_assert_not_reached ();
          }
        token->prev->pattern = new_pattern;

        /* remove token */
        if (token->prev)
          token->prev->next = token->next;
        else
          token_list = token->next;
        if (token->next)
          token->next->prev = token->prev;
        /* token isn't in the list now!  but it doesn't matter b/c token->next is still correct */
      }

  /* Handle concatenation */
  for (token = token_list; token && token->next; )
    {
      if (token->type == TOKEN_PATTERN
       && token->next->type == TOKEN_PATTERN)
        {
          /* concat */
          struct Pattern *new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
          struct Token *kill;
          new_pattern->type = PATTERN_CONCAT;
          new_pattern->info.concat.a = token->pattern;
          new_pattern->info.concat.b = token->next->pattern;
          token->pattern = new_pattern;

          /* remove token->next */
          kill = token->next;
          token->next = kill->next;
          if (kill->next)
            kill->next->prev = token;
        }
      else
        token = token->next;
    }

  /* At this point we consist of nothing but alternations and
     patterns.  Scan through, discarding TOKEN_ALTER,
     and keeping track of whether the empty pattern matches */
  last_was_alter = DSK_TRUE;     /* trick the empty pattern detector
                                    into triggering on initial '|' */
  accept_empty = DSK_FALSE;
  for (token = token_list; token; token = token->next)
    if (token->type == TOKEN_ALTER)
      {
        if (last_was_alter)
          accept_empty = DSK_TRUE;
        last_was_alter = DSK_TRUE;

        /* remove token from list */
        if (token->prev)
          token->prev->next = token->next;
        else
          token_list = token->next;
        if (token->next)
          token->next->prev = token->prev;
      }
    else
      {
        last_was_alter = DSK_FALSE;
      }
  if (last_was_alter)
    accept_empty = DSK_TRUE;

  /* if we accept an empty token, toss a PATTERN_EMPTY onto the list of patterns
     in the alternation. */
  if (accept_empty || token_list == NULL)
    {
      struct Token *t = dsk_mem_pool_alloc (pool, sizeof (struct Token));
      t->next = token_list;
      t->prev = NULL;
      if (t->next)
        t->next->prev = t;
      token_list = t;

      t->type = TOKEN_PATTERN;
      t->pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
    }

  /* At this point, token_list!=NULL,
     and it consists entirely of patterns.
     Reduce it to a singleton with the alternation pattern. */
  while (token_list->next != NULL)
    {
      /* create alternation pattern */
      struct Pattern *new_pattern = dsk_mem_pool_alloc (pool, sizeof (struct Pattern));
      new_pattern->type = PATTERN_ALT;
      new_pattern->info.alternation.a = token_list->pattern;
      new_pattern->info.alternation.b = token_list->next->pattern;
      token_list->pattern = new_pattern;

      /* remove token->next */
      {
        struct Token *kill = token_list->next;
        token_list->next = kill->next;
        if (kill->next)
          kill->next->prev = token_list;
      }
    }

  /* Return value consists of merely a single token-list. */
  dsk_assert (token_list != NULL && token_list->next == NULL);
  return token_list->pattern;
}
Example #26
0
static dsk_boolean
dsk_bz2lib_decompressor_process(DskOctetFilter *filter,
                            DskBuffer      *out,
                            unsigned        in_length,
                            const uint8_t  *in_data,
                            DskError      **error)
{
  DskBz2libDecompressor *decompressor = (DskBz2libDecompressor *) filter;
  DskBufferFragment *prev_last_frag;
  dsk_boolean added_fragment = DSK_FALSE;
  if (decompressor->input_ended)
    {
      if (in_length == 0)
        return DSK_TRUE;
      dsk_set_error (error, "garbage after compressed data");
      return DSK_FALSE;
    }
  prev_last_frag = NULL;                // silence GCC
  while (in_length > 0)
    {
      DskBufferFragment *f;
      uint8_t *out_start;
      int zrv;
      if (out->last_frag == NULL
       || !fragment_has_empty_space (out->last_frag))
        {
          added_fragment = DSK_TRUE;
          prev_last_frag = out->last_frag;
          dsk_buffer_append_empty_fragment (out);
        }

      decompressor->bz2lib.next_in = (char *) in_data;
      decompressor->bz2lib.avail_in = in_length;

      f = out->last_frag;
      out_start = f->buf + f->buf_start + f->buf_length;
      decompressor->bz2lib.next_out = (char*) out_start;
      decompressor->bz2lib.avail_out = f->buf_max_size - f->buf_start - f->buf_length;
      zrv = BZ2_bzDecompress (&decompressor->bz2lib);
      if (zrv == BZ_OK || zrv == BZ_STREAM_END)
        {
          unsigned amt_in = decompressor->bz2lib.next_in - (char*) in_data;
          unsigned amt_out = decompressor->bz2lib.next_out - (char*) out_start;
          in_data += amt_in;
          in_length -= amt_in;
          f->buf_length += amt_out;
          out->size += amt_out;
          if (zrv == BZ_STREAM_END)
            {
              decompressor->input_ended = DSK_TRUE;
              if (in_length > 0)
                {
                  dsk_set_error (error, "garbage after compressed data");
                  dsk_buffer_maybe_remove_empty_fragment (out);
                  return DSK_FALSE;
                }
            }
        }
      else
        {
          dsk_set_error (error, "error decompressing: %s [%d]",
                         bzrv_to_string (zrv), zrv);
          dsk_buffer_maybe_remove_empty_fragment (out);
          return DSK_FALSE;
        }
    }

  /* If we added a fragment that we didn't use,
     remove it. */
  if (added_fragment && out->last_frag->buf_length == 0)
    {
      dsk_buffer_fragment_free (out->last_frag);
      out->last_frag = prev_last_frag;
      if (out->last_frag == NULL)
        out->first_frag = NULL;
    }
  return DSK_TRUE;
}
static DskTableCheckpoint *
table_checkpoint_trivial__create (DskTableCheckpointInterface *iface,
                                  DskDir             *dir,
                                  const char         *basename,
                                  unsigned            cp_data_len,
                                  const uint8_t      *cp_data,
                                  DskTableCheckpoint *prior,  /* optional */
                                  DskError          **error)
{
  unsigned mmapped_size;
  int fd;
  void *mmapped;
  TrivialTableCheckpoint *rv;

  DSK_UNUSED (iface);
  
  if (prior == NULL)
    mmapped_size = DEFAULT_MMAP_SIZE;
  else
    {
      dsk_assert (prior->add == table_checkpoint_trivial__add);
      mmapped_size = ((TrivialTableCheckpoint *) prior)->mmapped_size;
    }

  if (mmapped_size < cp_data_len + 32)
    {
      mmapped_size = cp_data_len + 32;
      mmapped_size += MMAP_MIN_RESIZE_GROW;
      mmapped_size += MMAP_GRANULARITY - 1;
      mmapped_size /= MMAP_GRANULARITY;
      mmapped_size *= MMAP_GRANULARITY;
    }

  /* create fd */
  fd = dsk_dir_openfd (dir, basename,
                       DSK_DIR_OPENFD_WRITABLE|DSK_DIR_OPENFD_TRUNCATE|DSK_DIR_OPENFD_MAY_CREATE,
                       0666, error);
  if (fd < 0)
    return NULL;

  /* truncate / fallocate */
  if (ftruncate (fd, mmapped_size) < 0)
    {
      dsk_set_error (error, "error expanding file %s to %u bytes: %s",
                     basename, mmapped_size, strerror (errno));
      close (fd);
      return NULL;
    }

  /* mmap */
  mmapped = mmap (NULL, mmapped_size, PROT_READ|PROT_WRITE,
                  MAP_SHARED, fd, 0);
  if (mmapped == MAP_FAILED)
    {
      dsk_set_error (error, "mmap of %u bytes failed: %s",
                     mmapped_size, strerror (errno));
      return DSK_FALSE;
    }

  rv = DSK_NEW (TrivialTableCheckpoint);
  rv->base = table_checkpoint_trivial__vfuncs;
  rv->fd = fd;
  rv->mmapped = mmapped;
  rv->mmapped_size = mmapped_size;
  rv->cur_size = (12 + cp_data_len + 3) / 4 * 4;

  ((uint32_t *) (mmapped))[0] = UINT32_TO_LE (TRIVIAL_CP_MAGIC);
  ((uint32_t *) (mmapped))[1] = UINT32_TO_LE (1);  /* version */
  ((uint32_t *) (mmapped))[2] = UINT32_TO_LE (cp_data_len);  /* version */
  memcpy (mmapped + 12, cp_data, cp_data_len);
  if (cp_data_len % 4 != 0)
    memset (mmapped + 12 + cp_data_len, 0, 4 - cp_data_len % 4);
  * ((uint32_t *) (mmapped+rv->cur_size)) = 0xffffffff;        /* end-marker */

  return &rv->base;
}
static DskTableCheckpoint *
table_checkpoint_trivial__open   (DskTableCheckpointInterface *iface,
                                  DskDir             *dir,
                                  const char         *basename,
                                  unsigned           *cp_data_len_out,
                                  uint8_t           **cp_data_out,
                                  DskTableCheckpointReplayFunc func,
                                  void               *func_data,
                                  DskError          **error)
{
  int fd = -1;
  struct stat stat_buf;
  void *mmapped = NULL;
  TrivialTableCheckpoint *rv;
  unsigned version, cp_data_len;
  unsigned at;

  DSK_UNUSED (iface);

  /* open fd */
  fd = dsk_dir_openfd (dir, basename,
                       DSK_DIR_OPENFD_WRITABLE, 0, error);
  if (fd < 0)
    return NULL;

  /* fstat */
  if (fstat (fd, &stat_buf) < 0)
    {
      dsk_set_error (error, "fstat of %s failed: %s",
                     basename, strerror (errno));
      goto error_cleanup;
    }

  /* mmap */
  mmapped = mmap (NULL, stat_buf.st_size, PROT_READ|PROT_WRITE,
                  MAP_SHARED, fd, 0);
  if (mmapped == MAP_FAILED)
    {
      dsk_set_error (error, "mmap of %u bytes (file %s) failed: %s",
                     (unsigned) stat_buf.st_size, basename, strerror (errno));
      goto error_cleanup;
    }
  
  /* check format */
  if (((uint32_t*)mmapped)[0] != UINT32_TO_LE (TRIVIAL_CP_MAGIC))
    {
      dsk_set_error (error, "checkpoint file %s has bad magic", basename);
      goto error_cleanup;
    }
  version = UINT32_FROM_LE (((uint32_t*)mmapped)[1]);
  if (version != 1)
    {
      dsk_set_error (error, "checkpoint file %s has bad version %u",
                     basename, version);
      goto error_cleanup;
    }
  cp_data_len = UINT32_FROM_LE (((uint32_t*)mmapped)[2]);

  /* replay */
  at = 12 + (cp_data_len + 3) / 4 * 4;
  if (at + 4 > stat_buf.st_size)
    {
      dsk_set_error (error, "checkpoint data length (%u) too big for file's length (%u)",
                     cp_data_len, (unsigned) stat_buf.st_size);
      goto error_cleanup;
    }
  while (* (uint32_t*) (mmapped+at) != 0xffffffff)
    {
      uint32_t key_len, value_len;
      uint32_t kv_len, kvp_len;
      if (at + 8 > stat_buf.st_size)
        {
          dsk_set_error (error, "checkpoint entry header too long");
          goto error_cleanup;
        }
      key_len = UINT32_FROM_LE (((uint32_t *) (mmapped+at))[0]);
      value_len = UINT32_FROM_LE (((uint32_t *) (mmapped+at))[1]);
      kv_len = key_len + value_len;
      if (kv_len < key_len)
        {
          dsk_set_error (error, "key+value length greater than 4G");
          goto error_cleanup;
        }
      kvp_len = (kv_len + 3) / 4 * 4;
      if (at + 8 + kvp_len + 4 > stat_buf.st_size)
        {
          dsk_set_error (error, "checkpoint entry data too long");
          goto error_cleanup;
        }
      if (!func (key_len, mmapped + at + 8,
                 value_len, mmapped + at + 8 + key_len,
                 func_data, error))
        {
          if (error && !*error)
            dsk_set_error (error, "replay handler returned false but didn't set error");
          goto error_cleanup;
        }
      at += 8 + kvp_len;
    }

  /* copy cp_data */
  if (cp_data_len_out != NULL)
    *cp_data_len_out = cp_data_len;
  if (cp_data_out != NULL)
    {
      *cp_data_out = dsk_malloc (cp_data_len);
      memcpy (*cp_data_out, mmapped + 12, cp_data_len);
    }
  rv = DSK_NEW (TrivialTableCheckpoint);
  rv->base = table_checkpoint_trivial__vfuncs;
  rv->fd = fd;
  rv->mmapped = mmapped;
  rv->mmapped_size = stat_buf.st_size;
  rv->cur_size = at;
  return &rv->base;

error_cleanup:
  if (mmapped != NULL && munmap ((void*) mmapped, stat_buf.st_size) < 0)
    dsk_warning ("error calling munmap(): %s", strerror (errno));
  if (fd >= 0)
    close (fd);
  return NULL;
}
Example #29
0
DskIOResult
dsk_websocket_receive  (DskWebsocket *websocket,
                        unsigned     *length_out,
                        uint8_t     **data_out,
                        DskError    **error)
{
  uint8_t header[9];
  uint64_t length;
restart:
  maybe_discard_data (websocket);
  if (websocket->incoming.size < 9)
    return DSK_IO_RESULT_AGAIN;
  dsk_buffer_peek (&websocket->incoming, 9, header);
  length = dsk_uint64be_parse (header + 1);
  if (length > websocket->max_length)
    {
      switch (websocket->too_long_mode)
        {
        case DSK_WEBSOCKET_MODE_DROP:
          websocket->to_discard = length + 9;
          goto restart;
        case DSK_WEBSOCKET_MODE_SHUTDOWN:
          do_deferred_shutdown (websocket);
          return DSK_IO_RESULT_ERROR;
        case DSK_WEBSOCKET_MODE_RETURN_ERROR:
          websocket->to_discard = length + 9;
          maybe_discard_data (websocket);
          dsk_set_error (error, "packet too long (%"PRIu64" bytes)", length);
          return DSK_IO_RESULT_ERROR;
        }
    }
  switch (header[0])
    {
    case 0x00:
      /* uh oh - shutdown packet */
      dsk_buffer_discard (&websocket->incoming, 9 + length);
      do_deferred_shutdown (websocket);
      return DSK_IO_RESULT_EOF;
    case 0xff:
      if (websocket->incoming.size - 9 < length)
        return DSK_IO_RESULT_AGAIN;
      *length_out = length;
      *data_out = dsk_malloc (length);
      dsk_buffer_discard (&websocket->incoming, 9);
      *data_out = dsk_malloc (length);
      dsk_buffer_read (&websocket->incoming, length, *data_out);
      update_hooks_with_buffer (websocket);
      return DSK_IO_RESULT_SUCCESS;
    default:
      /* error */
      switch (websocket->bad_packet_type_mode)
        {
        case DSK_WEBSOCKET_MODE_SHUTDOWN:
          do_deferred_shutdown (websocket);
          break;
        case DSK_WEBSOCKET_MODE_RETURN_ERROR:
          dsk_set_error (error, "packet had bad type: 0x%02x", header[0]);
          websocket->to_discard = length + 9;
          maybe_discard_data (websocket);
          return DSK_IO_RESULT_ERROR;
        case DSK_WEBSOCKET_MODE_DROP:
          websocket->to_discard = length + 9;
          goto restart;
        }
    }
  dsk_assert_not_reached ();
  return DSK_IO_RESULT_ERROR;
}
Example #30
0
/* TODO: rewrite this thing! */
dsk_boolean  dsk_url_scan  (const char     *url_string,
                            DskUrlScanned  *out,
                            DskError      **error)
{
  int num_slashes;
  const char *at = url_string;
  DskUrlInterpretation interpretation = DSK_URL_INTERPRETATION_UNKNOWN;
  const char *query_start;
  const char *frag_start;
  const char *end_string;
  out->scheme_start = at;
  /* XXX: use dsk_url_scheme_parse() */
  while (dsk_ascii_isalnum (*at))
    at++;
  if (out->scheme_start == at)
    {
      dsk_set_error (error, "no scheme found in URL");
      return DSK_FALSE;
    }
  if (*at != ':')
    {
      dsk_set_error (error, "missing : after scheme in URL");
      return DSK_FALSE;
    }
  out->scheme_end = at;
  at++;         /* skip : */

  /* Parse scheme */
  out->scheme = DSK_URL_SCHEME_UNKNOWN;
  switch (out->scheme_end - out->scheme_start)
    {
    case 3:
      if (dsk_ascii_strncasecmp (out->scheme_start, "ftp", 3) == 0)
        out->scheme = DSK_URL_SCHEME_FTP;
      break;
    case 4:
      if (dsk_ascii_strncasecmp (out->scheme_start, "http", 4) == 0)
        out->scheme = DSK_URL_SCHEME_HTTP;
      else if (dsk_ascii_strncasecmp (out->scheme_start, "file", 4) == 0)
        out->scheme = DSK_URL_SCHEME_FILE;
      break;
    case 5:
      if (dsk_ascii_strncasecmp (out->scheme_start, "https", 5) == 0)
        out->scheme = DSK_URL_SCHEME_HTTPS;
      break;
    }

  num_slashes = 0;
  while (*at == '/')
    {
      num_slashes++;
      at++;
    }
  if (out->scheme == DSK_URL_SCHEME_FILE)
    interpretation = DSK_URL_INTERPRETATION_ABSOLUTE;
  else
    switch (num_slashes)
      {
	case 0:
	  interpretation = DSK_URL_INTERPRETATION_RELATIVE;
	  break;
	case 1:
	  interpretation = DSK_URL_INTERPRETATION_ABSOLUTE;
	  break;
	case 2:
	  /* ``schemes including a top hierarchical element for a naming
	   *   authority'' (Section 3.2)
	   */
	  interpretation = DSK_URL_INTERPRETATION_REMOTE;
	  break;
	case 3:
	  /* File urls (well those are now handled above so this
	   * is pretty dubious)
	   */
	  interpretation = DSK_URL_INTERPRETATION_ABSOLUTE;
	  break;
	default:
          /* hmm */
	  interpretation = DSK_URL_INTERPRETATION_ABSOLUTE;
	  break;
      }

          out->host_start = out->host_end = NULL;
          out->username_start = out->username_end = NULL;
          out->password_start = out->password_end = NULL;
          out->port_start = out->port_end = NULL;
          out->port = 0;


  if (interpretation == DSK_URL_INTERPRETATION_REMOTE)
    {
      /* rfc 2396, section 3.2.2. */
      const char *end_hostport;
      const char *at_sign;
      const char *colon;
      /* basically the syntax is:
       *    USER@HOST:PORT/
       *        ^    |    ^
       *     at_sign ^  end_hostport
       *            colon
       */             
      end_hostport = strchr (at, '/');
      if (end_hostport == NULL)
        end_hostport = strchr (at, 0);
      at_sign = memchr (at, '@', end_hostport - at);
      out->host_start = at_sign != NULL ? (at_sign + 1) : at;
      colon = memchr (out->host_start, ':', end_hostport - out->host_start);
      if (at_sign != NULL)
        {
          const char *password_sep = memchr (at, ':', at_sign - at);
          if (password_sep)
            {
              out->username_start = at;
              out->username_end = password_sep;
              out->password_start = password_sep + 1;
              out->password_end = at_sign;
            }
          else
            {
              out->username_start = at;
              out->username_end = at_sign;
              out->password_start = NULL;
              out->password_end = NULL;
            }
          /* XXX: should validate username against 
           *         GSK_URL_USERNAME_CHARSET
           */
        }
      else
        {
          out->username_start = NULL;
          out->username_end = NULL;
          out->password_start = NULL;
          out->password_end = NULL;
        }
      out->host_end = colon != NULL ? colon : end_hostport;

      if (colon != NULL)
        {
          out->port_start = colon + 1;
          out->port_end = end_hostport;
          out->port = atoi (out->port_start);
        }

      at = end_hostport;
    }
  else if (interpretation == DSK_URL_INTERPRETATION_UNKNOWN)
    {
      dsk_set_error (error, "cannot guess how to interpret %.*s URL",
                     (int)(out->scheme_end - out->scheme_start), out->scheme_start);
      return DSK_FALSE;
    }


  if (num_slashes > 0
   && interpretation == DSK_URL_INTERPRETATION_ABSOLUTE)
    at--;
  query_start = strchr (at, '?');
  frag_start = strchr (query_start != NULL ? query_start : at, '#');
  end_string = strchr (at, 0);
  out->path_start = at;
  if (query_start != NULL)
    out->path_end = query_start;
  else if (frag_start != NULL)
    out->path_end = frag_start;
  else
    out->path_end = end_string;
  if (query_start != NULL)
    {
      out->query_start = query_start + 1;
      out->query_end = frag_start ? frag_start : end_string;
    }
  else
    out->query_start = out->query_end = NULL;
  if (frag_start != NULL)
    {
      out->fragment_start = frag_start + 1;
      out->fragment_end = end_string;
    }
  else
    out->fragment_start = out->fragment_end = NULL;

#define CHECK(base, function)                                 \
  if (out->base##_start != NULL                               \
   && !function (out->base##_start, out->base##_end))         \
    {                                                         \
      dsk_set_error (error, "invalid character in %s", #base);\
      return DSK_FALSE;                                       \
    }
  CHECK (host, is_valid_hostname)
  CHECK (path, is_valid_generic_component)
  CHECK (query, is_valid_generic_component)
#undef CHECK
  return DSK_TRUE;
}