END_TEST

START_TEST (test_spdy_control_frame_parse)
{
	spdy_zlib_context zlib_ctx;
	spdy_control_frame frame;
	spdy_data data;
	int ret;

	spdy_zlib_inflate_init(&zlib_ctx);

	spdy_control_frame_init(&frame);
	ret = spdy_control_frame_parse(
			&frame,
			spdy_data_use(&data, test_control_syn_stream_frame, 296),
			&zlib_ctx);
	fail_unless(ret == SPDY_ERROR_NONE, "spdy_control_frame_parse failed.");
	fail_unless(data.cursor - data.data == 296, "data_used is incorrect.");
	fail_unless(frame.version == 2, "Version failed.");
	fail_unless(frame.type == SPDY_CTRL_SYN_STREAM, "Type failed.");
	fail_unless(frame.flags == 1, "Flag failed.");
	fail_unless(frame.length == 288, "Length failed.");
        spdy_control_frame_destroy(&frame);
        spdy_zlib_inflate_end(&zlib_ctx);
}
END_TEST

START_TEST (test_spdy_syn_stream_parse)
{
#if 0
	int ret;
	spdy_syn_stream syn_stream;
	spdy_data data;
        struct hash *hash = NULL;
        spdy_data_use(&data, test_control_syn_stream_frame+8, 288);
	ret = spdy_syn_stream_parse(&syn_stream, hash, &data, 288);
	fail_unless(ret == 0, "spdy_syn_stream_parse failed.");
        spdy_syn_stream_destroy(&syn_stream);
#endif
}
END_TEST

START_TEST (test_spdy_control_frame_parse_pack_header)
{
	spdy_control_frame frame;
	char out[8];
	spdy_data data;
	int ret;
        size_t got;
	spdy_control_frame_init(&frame);
	ret = spdy_control_frame_parse_header(&frame,
			spdy_data_use(&data, test_control_syn_stream_frame, 8));
	fail_unless(ret == 0, "spdy_control_frame_parse_header failed.");
	ret = spdy_control_frame_pack_header(out, sizeof(out), &got, &frame);
	fail_unless(ret == 0, "spdy_control_frame_pack_header failed.");
	fail_unless(memcmp(out, test_control_syn_stream_frame, 8) == 0, "Input is different than repacked frame.");
        fail_unless(got == 8);
}
END_TEST

START_TEST (test_spdy_syn_stream_parse)
{
    int ret;
    spdy_zlib_context zlib_ctx;
    spdy_syn_stream syn_stream;
    spdy_data data;
    ret = spdy_zlib_inflate_init(&zlib_ctx);
    fail_unless(ret == 0, "spdy_zlib_inflate_init failed.");
    ret = spdy_syn_stream_parse(
              &syn_stream,
              spdy_data_use(&data, test_control_syn_stream_frame+8, 288),
              288,
              &zlib_ctx);
    fail_unless(ret == 0, "spdy_syn_stream_parse failed.");
    spdy_syn_stream_destroy(&syn_stream);
    spdy_zlib_inflate_end(&zlib_ctx);
}
END_TEST

START_TEST (test_spdy_syn_reply_parse)
{
	int ret;
	spdy_zlib_context zlib_ctx;
	spdy_syn_reply syn_reply;
	spdy_data data;
	ret = spdy_zlib_inflate_init(&zlib_ctx);
	fail_unless(ret == 0, "spdy_zlib_inflate_init failed.");
	ret = spdy_syn_reply_parse(
			&syn_reply,
			spdy_data_use(&data, test_control_syn_reply_frame+8, 55),
			55,
			&zlib_ctx);
	fail_unless(ret == 0, "spdy_syn_reply_parse failed.");
        spdy_syn_reply_destroy(&syn_reply);
        spdy_zlib_inflate_end(&zlib_ctx);
}
Example #6
0
static int parse_append(struct spindly_phys *phys, bool *more)
{
  /* the existing data is too small, merge it with the next in the malloc'ed
     buffer */
  struct list_node *n = _spindly_list_first(&phys->inq);
  struct list_node *next = _spindly_list_next(n);
  struct spindly_indata *in= (struct spindly_indata *)next;
  spdy_data *data = &phys->data;
  size_t needed;
  size_t copylen;

  if(in) {
    *more = true;

    needed = data->needed + in->datalen;
    copylen = data->data_end - data->cursor;

    if(phys->parsealloc < needed) {
      char *newp = realloc(phys->parse, needed);
      if(!newp)
        return SPINDLYE_NOMEM;
      phys->parsealloc = needed;
    }

    /* the buffer might already be used by the first chunk, so we either copy
     * new data to it or we move the trailing piece to the start of the
     * buffer */
    memmove(phys->parse, data->cursor, copylen);
    phys->parselen = copylen;

    /* append the entire next chunk */
    memcpy(&phys->parse[copylen], in->data, in->datalen);

    /* now store the combined data amount */
    spdy_data_use(&phys->data, phys->parse, needed);
  }
  else
    *more = false;

  return SPINDLYE_OK;
}
Example #7
0
/*
 * Create a handle for a single duplex physical connection, SIDE is either
 * client or server - what side the handle is made to handle. PROTVER is the
 * specific SPDY protocol version.
 *
 * TODO: provide a means to replace the memory functions
 */
struct spindly_phys *spindly_phys_init(spindly_side_t side,
                                       spindly_spdyver_t protver,
                                       struct spindly_phys_config *config)
{
  struct spindly_phys *phys;
  int rc;
  struct spindly_outdata *od;

  /* this is the first malloc, it should use the malloc function provided in
     the config struct if set, but probably cannot use the MALLOC macro */
  phys = malloc(sizeof(struct spindly_phys));
  if(!phys)
    goto fail;
  phys->config = config;
  phys->side = side;
  phys->protver = protver;
  phys->num_streams = 0;
  phys->streamid = side == SPINDLY_SIDE_CLIENT?1:2;
  phys->outgoing = NULL;
  phys->outgoing_tosend = 0;

  /* create zlib contexts for incoming and outgoing data */
  rc = spdy_zlib_inflate_init(&phys->zlib_in);
  if(rc)
    goto fail;

  rc = spdy_zlib_inflate_init(&phys->zlib_out);
  if(rc)
    goto fail;

  _spindly_list_init(&phys->streams);
  _spindly_list_init(&phys->outq);
  _spindly_list_init(&phys->inq);
  _spindly_list_init(&phys->pendq);

  /* now add all outdata nodes to the pending queue */
  for(rc=0; rc < PHYS_NUM_OUTDATA; rc++) {
    od = CALLOC(phys, sizeof(struct spindly_outdata));
    if(!od)
      goto fail;

    _spindly_list_add(&phys->pendq, &od->node);
  }

  /* init receiver variables  */
  spdy_frame_init(&phys->frame);
  spdy_data_use(&phys->data, NULL, 0);

  /* for stream-ID to stream struct lookups */
  _spindly_hash_init(&phys->streamhash, phys);

  return phys;

fail:
  spdy_zlib_inflate_end(&phys->zlib_in);
  spdy_zlib_inflate_end(&phys->zlib_out);

  /* TODO: clean up the pendq list */

  if(phys)
    free(phys);

  return NULL;
}
Example #8
0
/*
 * Returns information about incoming data, split up for consumption.
 * Subsequent calls will return the next result and so on until there's
 * nothing left to demux - until spindly_phys_incoming() is called again to
 * feed it with more data.
 *
 * When this function returns that there is no more message, it may still hold
 * trailing data that forms the beginning of the subsequent message.
 *
 * 'ptr' must point to the correct struct, read the first 'type' field of that
 * to know how to interpret the rest!
 */
spindly_error_t spindly_phys_demux(struct spindly_phys *phys,
                                   struct spindly_demux *ptr)
{
  struct list_node *n = _spindly_list_first(&phys->inq);
  struct spindly_indata *in= (struct spindly_indata *)n;
  int rc = SPINDLYE_OK;

  assert(ptr != NULL);

  ptr->type = SPINDLY_DX_NONE;

  do {

    if(phys->data.data_end <= phys->data.cursor)
      /* if the previously stored data is all consumed then get the
         current queue data */
      spdy_data_use(&phys->data, in->data, in->datalen);

    /*
     * Parse data. The parsing function wants a full frame to be in a
     * contiguous buffer so unless it is, we must create a full frame from the
     * input we have.
     */
    rc = spdy_frame_parse(&phys->frame, phys, &phys->data);

    if(rc == SPDY_ERROR_NONE) {
      if(phys->frame.type == SPDY_CONTROL_FRAME) {
        spdy_syn_stream *syn;
        spdy_syn_reply *rep;
        struct spindly_stream *stream;
        struct hashnode *n;

        switch(phys->frame.frame.control.type) {
        case SPDY_CTRL_SYN_STREAM:
          /*
           * At this point there's a syn_stream struct that needs to be
           * converted to a full spinly_stream struct!
           *
           * phys->frame.frame.control.obj.syn_stream
           */
          syn = &phys->frame.frame.control.obj.syn_stream;

          rc = _spindly_stream_init(phys, syn->priority, &stream, NULL,
                                    NULL, syn->stream_id);
          if(rc)
            /* TODO: how do we deal with a failure here? */
            break;

          ptr->type = SPINDLY_DX_STREAM_REQ;
          ptr->msg.stream.stream = stream;
          break;
        case SPDY_CTRL_SYN_REPLY:
          /*
           * At this point there's a syn_reply struct that needs to be
           * converted to a full spinly_stream struct!
           *
           * phys->frame.frame.control.obj.syn_reply
           */
          rep = &phys->frame.frame.control.obj.syn_reply;

          n = _spindly_hash_get(&phys->streamhash, rep->stream_id);
          if(!n)
            /* received a SYN_REPLY for an unknown streamid */
            rc = SPINDLYE_PROTOCOL;
          else {
            stream = n->ptr;
            stream->state = STREAM_ACKED;
            ptr->type = SPINDLY_DX_STREAM_ACK;
            ptr->msg.stream.stream = stream;
          }
          break;
        case SPDY_CTRL_RST_STREAM:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_SETTINGS:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_NOOP:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_PING:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_GOAWAY:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_HEADERS:
          assert(0); /* not implemented yet! */
          break;
        case SPDY_CTRL_WINDOW_UPDATE:
          assert(0); /* not implemented yet! */
          break;
        default:
          assert(0); /* internal error */
          break;
        }
        spdy_frame_destroy(&phys->frame);
      }
      else { /* data */
        ptr->type = SPINDLY_DX_DATA;
      }

      /* TODO: if the complete inq node was consumed, call the callback */

      return SPINDLYE_OK;
    }

    else if(rc == SPDY_ERROR_INSUFFICIENT_DATA) {
      /* if there's too little data to parse, merge the buffer with the next
       * in the queue and loop and parse the bigger one
       */
      bool more;
      rc = parse_append(phys, &more);

      if(!more)
        /* there's no more right now */
        return SPINDLYE_OK;
    }
  } while(!rc);

  return rc;
}