Added callback functions for DATA frames. Fixed unpacking length field.
This commit is contained in:
parent
de57b6efea
commit
b35f019811
|
@ -147,9 +147,16 @@ public:
|
||||||
{
|
{
|
||||||
return fd_;
|
return fd_;
|
||||||
}
|
}
|
||||||
int req_submit(const char *path)
|
int submit_request(const char *path)
|
||||||
{
|
{
|
||||||
return spdylay_req_submit(session_, path);
|
const char *nv[] = {
|
||||||
|
"method", "GET",
|
||||||
|
"scheme", "https",
|
||||||
|
"url", path,
|
||||||
|
"version", "HTTP/1.1",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
return spdylay_submit_request(session_, 3, nv);
|
||||||
}
|
}
|
||||||
bool would_block(int r)
|
bool would_block(int r)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +203,54 @@ ssize_t recv_callback(spdylay_session *session,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_nv(char **nv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; nv[i]; i += 2) {
|
||||||
|
printf(" %s: %s\n", nv[i], nv[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_ctrl_recv_callback
|
||||||
|
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
static const char *ctrl_names[] = {
|
||||||
|
"SYN_STREAM",
|
||||||
|
"SYN_REPLY",
|
||||||
|
"RST_STREAM",
|
||||||
|
"SETTINGS",
|
||||||
|
"NOOP",
|
||||||
|
"PING",
|
||||||
|
"GOAWAY",
|
||||||
|
"HEADERS"
|
||||||
|
};
|
||||||
|
printf("recv %s frame ", ctrl_names[type-1]);
|
||||||
|
switch(type) {
|
||||||
|
case SPDYLAY_SYN_REPLY:
|
||||||
|
printf("(stream_id=%d, flags=%d, length=%d)\n",
|
||||||
|
frame->syn_reply.stream_id, frame->syn_reply.hd.flags,
|
||||||
|
frame->syn_reply.hd.length);
|
||||||
|
print_nv(frame->syn_reply.nv);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_data_chunk_recv_callback
|
||||||
|
(spdylay_session *session, int32_t stream_id, uint8_t flags,
|
||||||
|
const uint8_t *data, size_t len, void *user_data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void on_data_recv_callback
|
||||||
|
(spdylay_session *session, int32_t stream_id, uint8_t flags, int32_t length,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
printf("recv DATA frame (stream_id=%d, flags=%d, length=%d)\n",
|
||||||
|
stream_id, flags, length);
|
||||||
|
}
|
||||||
|
|
||||||
void ctl_epollev(int epollfd, int op, SpdylayClient& sc)
|
void ctl_epollev(int epollfd, int op, SpdylayClient& sc)
|
||||||
{
|
{
|
||||||
epoll_event ev;
|
epoll_event ev;
|
||||||
|
@ -293,7 +348,7 @@ int communicate(const char *host, const char *service, const char *path,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.req_submit(path);
|
sc.submit_request(path);
|
||||||
|
|
||||||
ctl_epollev(epollfd, EPOLL_CTL_ADD, sc);
|
ctl_epollev(epollfd, EPOLL_CTL_ADD, sc);
|
||||||
static const size_t MAX_EVENTS = 1;
|
static const size_t MAX_EVENTS = 1;
|
||||||
|
@ -330,10 +385,13 @@ int communicate(const char *host, const char *service, const char *path,
|
||||||
|
|
||||||
int run(const char *host, const char *service, const char *path)
|
int run(const char *host, const char *service, const char *path)
|
||||||
{
|
{
|
||||||
spdylay_session_callbacks callbacks = {
|
spdylay_session_callbacks callbacks;
|
||||||
send_callback,
|
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||||
recv_callback,
|
callbacks.send_callback = send_callback;
|
||||||
};
|
callbacks.recv_callback = recv_callback;
|
||||||
|
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
|
||||||
|
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||||
|
callbacks.on_data_recv_callback = on_data_recv_callback;
|
||||||
return communicate(host, service, path, &callbacks);
|
return communicate(host, service, path, &callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,12 +185,35 @@ typedef void (*spdylay_on_invalid_ctrl_recv_callback)
|
||||||
typedef void (*spdylay_on_ping_recv_callback)
|
typedef void (*spdylay_on_ping_recv_callback)
|
||||||
(spdylay_session *session, const struct timespec *rtt, void *user_data);
|
(spdylay_session *session, const struct timespec *rtt, void *user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback function invoked when data chunk of DATA frame is
|
||||||
|
* received. |stream_id| is the stream ID of this DATA frame belongs
|
||||||
|
* to. |flags| is the flags of DATA frame which this data chunk is
|
||||||
|
* contained. flags & SPDYLAY_FLAG_FIN does not necessarily mean this
|
||||||
|
* chunk of data is the last one in the stream. You should use
|
||||||
|
* spdylay_on_data_recv_callback to know all data frame is received
|
||||||
|
* whose flags contains SPDYLAY_FLAG_FIN.
|
||||||
|
*/
|
||||||
|
typedef void (*spdylay_on_data_chunk_recv_callback)
|
||||||
|
(spdylay_session *session, int32_t stream_id, uint8_t flags,
|
||||||
|
const uint8_t *data, size_t len, void *user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callback function invoked when DATA frame is received. The actual
|
||||||
|
* data it contains are received by spdylay_on_data_recv_callback.
|
||||||
|
*/
|
||||||
|
typedef void (*spdylay_on_data_recv_callback)
|
||||||
|
(spdylay_session *session, int32_t stream_id, uint8_t flags, int32_t length,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spdylay_send_callback send_callback;
|
spdylay_send_callback send_callback;
|
||||||
spdylay_recv_callback recv_callback;
|
spdylay_recv_callback recv_callback;
|
||||||
spdylay_on_ctrl_recv_callback on_ctrl_recv_callback;
|
spdylay_on_ctrl_recv_callback on_ctrl_recv_callback;
|
||||||
spdylay_on_invalid_ctrl_recv_callback on_invalid_ctrl_recv_callback;
|
spdylay_on_invalid_ctrl_recv_callback on_invalid_ctrl_recv_callback;
|
||||||
spdylay_on_ping_recv_callback on_ping_recv_callback;
|
spdylay_on_ping_recv_callback on_ping_recv_callback;
|
||||||
|
spdylay_on_data_chunk_recv_callback on_data_chunk_recv_callback;
|
||||||
|
spdylay_on_data_recv_callback on_data_recv_callback;
|
||||||
} spdylay_session_callbacks;
|
} spdylay_session_callbacks;
|
||||||
|
|
||||||
int spdylay_session_client_new(spdylay_session **session_ptr,
|
int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
|
|
|
@ -57,9 +57,9 @@ static void spdylay_frame_unpack_ctrl_hd(spdylay_ctrl_hd *hd,
|
||||||
const uint8_t* buf)
|
const uint8_t* buf)
|
||||||
{
|
{
|
||||||
hd->version = spdylay_get_uint16(buf) & SPDYLAY_VERSION_MASK;
|
hd->version = spdylay_get_uint16(buf) & SPDYLAY_VERSION_MASK;
|
||||||
hd->type = spdylay_get_uint16(buf+2);
|
hd->type = spdylay_get_uint16(&buf[2]);
|
||||||
hd->flags = buf[4];
|
hd->flags = buf[4];
|
||||||
hd->length = spdylay_get_uint32(buf+5) & SPDYLAY_LENGTH_MASK;
|
hd->length = spdylay_get_uint32(&buf[4]) & SPDYLAY_LENGTH_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
static ssize_t spdylay_frame_alloc_pack_nv(uint8_t **buf_ptr,
|
||||||
|
|
|
@ -717,6 +717,7 @@ int spdylay_session_on_rst_stream_received(spdylay_session *session,
|
||||||
spdylay_frame *frame)
|
spdylay_frame *frame)
|
||||||
{
|
{
|
||||||
spdylay_session_close_stream(session, frame->rst_stream.stream_id);
|
spdylay_session_close_stream(session, frame->rst_stream.stream_id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spdylay_session_on_ping_received(spdylay_session *session,
|
int spdylay_session_on_ping_received(spdylay_session *session,
|
||||||
|
@ -881,10 +882,18 @@ int spdylay_session_process_ctrl_frame(spdylay_session *session)
|
||||||
|
|
||||||
int spdylay_session_process_data_frame(spdylay_session *session)
|
int spdylay_session_process_data_frame(spdylay_session *session)
|
||||||
{
|
{
|
||||||
/* printf("Received data frame, stream_id %d, %zu bytes, fin=%d\n", */
|
if(session->callbacks.on_data_recv_callback) {
|
||||||
/* spdylay_get_uint32(session->iframe.headbuf), */
|
int32_t stream_id;
|
||||||
/* session->iframe.len, */
|
uint8_t flags;
|
||||||
/* session->iframe.headbuf[4] & SPDYLAY_FLAG_FIN); */
|
int32_t length;
|
||||||
|
stream_id = spdylay_get_uint32(session->iframe.headbuf) &
|
||||||
|
SPDYLAY_STREAM_ID_MASK;
|
||||||
|
flags = session->iframe.headbuf[4];
|
||||||
|
length = spdylay_get_uint32(&session->iframe.headbuf[4]) &
|
||||||
|
SPDYLAY_LENGTH_MASK;
|
||||||
|
session->callbacks.on_data_recv_callback
|
||||||
|
(session, stream_id, flags, length, session->user_data);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,7 +918,8 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
session->iframe.state = SPDYLAY_RECV_PAYLOAD;
|
||||||
payloadlen = spdylay_get_uint32(&session->ibuf.mark[4]) & 0xffffff;
|
payloadlen = spdylay_get_uint32(&session->ibuf.mark[4]) &
|
||||||
|
SPDYLAY_LENGTH_MASK;
|
||||||
memcpy(session->iframe.headbuf, session->ibuf.mark, SPDYLAY_HEAD_LEN);
|
memcpy(session->iframe.headbuf, session->ibuf.mark, SPDYLAY_HEAD_LEN);
|
||||||
session->ibuf.mark += SPDYLAY_HEAD_LEN;
|
session->ibuf.mark += SPDYLAY_HEAD_LEN;
|
||||||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
|
@ -921,11 +931,6 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
}
|
}
|
||||||
session->iframe.off = 0;
|
session->iframe.off = 0;
|
||||||
} else {
|
} else {
|
||||||
int32_t stream_id;
|
|
||||||
/* data frame */
|
|
||||||
/* For data frame, We dont' buffer data. Instead, just pass
|
|
||||||
received data to callback function. */
|
|
||||||
stream_id = spdylay_get_uint32(session->iframe.headbuf) & 0x7fffffff;
|
|
||||||
/* TODO validate stream id here */
|
/* TODO validate stream id here */
|
||||||
session->iframe.len = payloadlen;
|
session->iframe.len = payloadlen;
|
||||||
session->iframe.off = 0;
|
session->iframe.off = 0;
|
||||||
|
@ -947,8 +952,21 @@ int spdylay_session_recv(spdylay_session *session)
|
||||||
}
|
}
|
||||||
bufavail = spdylay_inbound_buffer_avail(&session->ibuf);
|
bufavail = spdylay_inbound_buffer_avail(&session->ibuf);
|
||||||
readlen = bufavail < rempayloadlen ? bufavail : rempayloadlen;
|
readlen = bufavail < rempayloadlen ? bufavail : rempayloadlen;
|
||||||
if(session->iframe.buf != NULL) {
|
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||||
memcpy(session->iframe.buf, session->ibuf.mark, readlen);
|
memcpy(session->iframe.buf, session->ibuf.mark, readlen);
|
||||||
|
} else if(session->callbacks.on_data_chunk_recv_callback) {
|
||||||
|
int32_t stream_id;
|
||||||
|
uint8_t flags;
|
||||||
|
/* For data frame, We don't buffer data. Instead, just pass
|
||||||
|
received data to callback function. */
|
||||||
|
stream_id = spdylay_get_uint32(session->iframe.headbuf) &
|
||||||
|
SPDYLAY_STREAM_ID_MASK;
|
||||||
|
flags = session->iframe.headbuf[4];
|
||||||
|
session->callbacks.on_data_chunk_recv_callback(session, stream_id,
|
||||||
|
flags,
|
||||||
|
session->ibuf.mark,
|
||||||
|
readlen,
|
||||||
|
session->user_data);
|
||||||
}
|
}
|
||||||
session->iframe.off += readlen;
|
session->iframe.off += readlen;
|
||||||
session->ibuf.mark += readlen;
|
session->ibuf.mark += readlen;
|
||||||
|
|
Loading…
Reference in New Issue