Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
aed626bf
Commit
aed626bf
authored
Jan 28, 2012
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added GOAWAY handling
parent
cb58e6e8
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
247 additions
and
3 deletions
+247
-3
lib/includes/spdylay/spdylay.h
lib/includes/spdylay/spdylay.h
+7
-0
lib/spdylay_frame.c
lib/spdylay_frame.c
+41
-0
lib/spdylay_frame.h
lib/spdylay_frame.h
+21
-0
lib/spdylay_session.c
lib/spdylay_session.c
+96
-3
lib/spdylay_session.h
lib/spdylay_session.h
+23
-0
tests/main.c
tests/main.c
+4
-0
tests/spdylay_frame_test.c
tests/spdylay_frame_test.c
+22
-0
tests/spdylay_frame_test.h
tests/spdylay_frame_test.h
+1
-0
tests/spdylay_session_test.c
tests/spdylay_session_test.c
+31
-0
tests/spdylay_session_test.h
tests/spdylay_session_test.h
+1
-0
No files found.
lib/includes/spdylay/spdylay.h
View file @
aed626bf
...
...
@@ -125,6 +125,12 @@ typedef struct {
uint32_t
unique_id
;
}
spdylay_ping
;
typedef
struct
{
spdylay_ctrl_hd
hd
;
int32_t
last_good_stream_id
;
uint32_t
status_code
;
}
spdylay_goaway
;
typedef
union
{
int
fd
;
void
*
ptr
;
...
...
@@ -150,6 +156,7 @@ typedef union {
spdylay_syn_reply
syn_reply
;
spdylay_rst_stream
rst_stream
;
spdylay_ping
ping
;
spdylay_goaway
goaway
;
spdylay_headers
headers
;
spdylay_data
data
;
}
spdylay_frame
;
...
...
lib/spdylay_frame.c
View file @
aed626bf
...
...
@@ -399,6 +399,19 @@ void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id)
void
spdylay_frame_ping_free
(
spdylay_ping
*
frame
)
{}
void
spdylay_frame_goaway_init
(
spdylay_goaway
*
frame
,
int32_t
last_good_stream_id
)
{
memset
(
frame
,
0
,
sizeof
(
spdylay_goaway
));
frame
->
hd
.
version
=
SPDYLAY_PROTO_VERSION
;
frame
->
hd
.
type
=
SPDYLAY_GOAWAY
;
frame
->
hd
.
length
=
4
;
frame
->
last_good_stream_id
=
last_good_stream_id
;
}
void
spdylay_frame_goaway_free
(
spdylay_goaway
*
frame
)
{}
void
spdylay_frame_headers_init
(
spdylay_headers
*
frame
,
uint8_t
flags
,
int32_t
stream_id
,
char
**
nv
)
{
...
...
@@ -551,6 +564,34 @@ int spdylay_frame_unpack_ping(spdylay_ping *frame,
return
0
;
}
ssize_t
spdylay_frame_pack_goaway
(
uint8_t
**
buf_ptr
,
spdylay_goaway
*
frame
)
{
uint8_t
*
framebuf
=
NULL
;
ssize_t
framelen
=
12
;
framebuf
=
malloc
(
framelen
);
if
(
framebuf
==
NULL
)
{
return
SPDYLAY_ERR_NOMEM
;
}
memset
(
framebuf
,
0
,
framelen
);
spdylay_frame_pack_ctrl_hd
(
framebuf
,
&
frame
->
hd
);
spdylay_put_uint32be
(
&
framebuf
[
8
],
frame
->
last_good_stream_id
);
*
buf_ptr
=
framebuf
;
return
framelen
;
}
int
spdylay_frame_unpack_goaway
(
spdylay_goaway
*
frame
,
const
uint8_t
*
head
,
size_t
headlen
,
const
uint8_t
*
payload
,
size_t
payloadlen
)
{
if
(
payloadlen
<
4
)
{
return
SPDYLAY_ERR_INVALID_FRAME
;
}
spdylay_frame_unpack_ctrl_hd
(
&
frame
->
hd
,
head
);
frame
->
last_good_stream_id
=
spdylay_get_uint32
(
payload
)
&
SPDYLAY_STREAM_ID_MASK
;
return
0
;
}
#define SPDYLAY_HEADERS_NV_OFFSET 14
ssize_t
spdylay_frame_pack_headers
(
uint8_t
**
buf_ptr
,
...
...
lib/spdylay_frame.h
View file @
aed626bf
...
...
@@ -101,6 +101,22 @@ int spdylay_frame_unpack_ping(spdylay_ping *frame,
const
uint8_t
*
head
,
size_t
headlen
,
const
uint8_t
*
payload
,
size_t
payloadlen
);
/*
* Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
* store given |frame|. This function returns the size of packed frame
* if it succeeds, or negative error code.
*/
ssize_t
spdylay_frame_pack_goaway
(
uint8_t
**
buf_ptr
,
spdylay_goaway
*
frame
);
/*
* Unpacks GOAWAY wire format into |frame|. This function returns 0 if
* it succeeds, or negative error code.
*/
int
spdylay_frame_unpack_goaway
(
spdylay_goaway
*
frame
,
const
uint8_t
*
head
,
size_t
headlen
,
const
uint8_t
*
payload
,
size_t
payloadlen
);
/*
* Packs HEADERS frame |frame| in wire format and store it in
* |*buf_ptr|. This function allocates enough memory in |*buf_ptr| to
...
...
@@ -181,6 +197,11 @@ void spdylay_frame_ping_init(spdylay_ping *frame, uint32_t unique_id);
void
spdylay_frame_ping_free
(
spdylay_ping
*
frame
);
void
spdylay_frame_goaway_init
(
spdylay_goaway
*
frame
,
int32_t
last_good_stream_id
);
void
spdylay_frame_goaway_free
(
spdylay_goaway
*
frame
);
void
spdylay_frame_headers_init
(
spdylay_headers
*
frame
,
uint8_t
flags
,
int32_t
stream_id
,
char
**
nv
);
...
...
lib/spdylay_session.c
View file @
aed626bf
...
...
@@ -80,6 +80,9 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
(
*
session_ptr
)
->
last_ping_unique_id
=
0
;
memset
(
&
(
*
session_ptr
)
->
last_ping_time
,
0
,
sizeof
(
struct
timespec
));
(
*
session_ptr
)
->
goaway_flags
=
SPDYLAY_GOAWAY_NONE
;
(
*
session_ptr
)
->
last_good_stream_id
=
0
;
r
=
spdylay_zlib_deflate_hd_init
(
&
(
*
session_ptr
)
->
hd_deflater
);
if
(
r
!=
0
)
{
free
(
*
session_ptr
);
...
...
@@ -144,6 +147,9 @@ static void spdylay_outbound_item_free(spdylay_outbound_item *item)
case
SPDYLAY_PING
:
spdylay_frame_ping_free
(
&
item
->
frame
->
ping
);
break
;
case
SPDYLAY_GOAWAY
:
spdylay_frame_goaway_free
(
&
item
->
frame
->
goaway
);
break
;
case
SPDYLAY_HEADERS
:
spdylay_frame_headers_free
(
&
item
->
frame
->
headers
);
break
;
...
...
@@ -215,6 +221,9 @@ int spdylay_session_add_frame(spdylay_session *session,
/* Ping has "height" priority. Give it -1. */
item
->
pri
=
-
1
;
break
;
case
SPDYLAY_GOAWAY
:
/* Should GOAWAY have higher priority? */
break
;
case
SPDYLAY_HEADERS
:
/* Currently we don't have any API to send HEADERS frame, so this
is unreachable. */
...
...
@@ -328,6 +337,11 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
int
r
;
switch
(
item
->
frame_type
)
{
case
SPDYLAY_SYN_STREAM
:
{
if
(
session
->
goaway_flags
)
{
/* When GOAWAY is sent or received, peer must not send new
SYN_STREAM. */
return
SPDYLAY_ERR_INVALID_FRAME
;
}
item
->
frame
->
syn_stream
.
stream_id
=
session
->
next_stream_id
;
session
->
next_stream_id
+=
2
;
framebuflen
=
spdylay_frame_pack_syn_stream
(
&
framebuf
,
...
...
@@ -373,6 +387,19 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
/* Currently we don't have any API to send HEADERS frame, so this
is unreachable. */
abort
();
case
SPDYLAY_GOAWAY
:
if
(
session
->
goaway_flags
&
SPDYLAY_GOAWAY_SEND
)
{
/* TODO The spec does not mandate that both endpoints have to
exchange GOAWAY. This implementation allows receiver of first
GOAWAY can sent its own GOAWAY to tell the remote peer that
last-good-stream-id. */
return
SPDYLAY_ERR_INVALID_FRAME
;
}
framebuflen
=
spdylay_frame_pack_goaway
(
&
framebuf
,
&
item
->
frame
->
goaway
);
if
(
framebuflen
<
0
)
{
return
framebuflen
;
}
break
;
case
SPDYLAY_DATA
:
{
if
(
!
spdylay_session_is_data_allowed
(
session
,
item
->
frame
->
data
.
stream_id
))
{
return
SPDYLAY_ERR_INVALID_FRAME
;
...
...
@@ -454,6 +481,9 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
/* TODO If clock_gettime() fails, what should we do? */
clock_gettime
(
CLOCK_MONOTONIC
,
&
session
->
last_ping_time
);
break
;
case
SPDYLAY_GOAWAY
:
session
->
goaway_flags
|=
SPDYLAY_GOAWAY_SEND
;
break
;
case
SPDYLAY_HEADERS
:
/* Currently we don't have any API to send HEADERS frame, so this
is unreachable. */
...
...
@@ -530,7 +560,11 @@ int spdylay_session_send(spdylay_session *session)
/* TODO Call error callback? */
spdylay_outbound_item_free
(
item
);
free
(
item
);
continue
;;
if
(
framebuflen
<=
SPDYLAY_ERR_FATAL
)
{
return
framebuflen
;
}
else
{
continue
;;
}
}
session
->
aob
.
item
=
item
;
session
->
aob
.
framebuf
=
framebuf
;
...
...
@@ -686,6 +720,10 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
spdylay_frame
*
frame
)
{
int
r
;
if
(
session
->
goaway_flags
)
{
/* We don't accept SYN_STREAM after GOAWAY is sent or received. */
return
0
;
}
if
(
spdylay_session_validate_syn_stream
(
session
,
&
frame
->
syn_stream
)
==
0
)
{
uint8_t
flags
=
frame
->
syn_stream
.
hd
.
flags
;
if
((
flags
&
SPDYLAY_FLAG_FIN
)
&&
(
flags
&
SPDYLAY_FLAG_UNIDIRECTIONAL
))
{
...
...
@@ -786,6 +824,25 @@ int spdylay_session_on_ping_received(spdylay_session *session,
return
r
;
}
int
spdylay_session_on_goaway_received
(
spdylay_session
*
session
,
spdylay_frame
*
frame
)
{
int
r
;
session
->
last_good_stream_id
=
frame
->
goaway
.
last_good_stream_id
;
session
->
goaway_flags
|=
SPDYLAY_GOAWAY_RECV
;
if
(
!
(
session
->
goaway_flags
&
SPDYLAY_GOAWAY_SEND
))
{
/* TODO The spec does not mandate to send back GOAWAY. I think the
remote endpoint does not expect this, but sending GOAWAY does
not harm. */
r
=
spdylay_session_add_goaway
(
session
,
session
->
last_recv_stream_id
);
if
(
r
!=
0
)
{
return
r
;
}
}
spdylay_session_call_on_ctrl_frame_received
(
session
,
SPDYLAY_GOAWAY
,
frame
);
return
0
;
}
int
spdylay_session_on_headers_received
(
spdylay_session
*
session
,
spdylay_frame
*
frame
)
{
...
...
@@ -895,6 +952,17 @@ int spdylay_session_process_ctrl_frame(spdylay_session *session)
spdylay_frame_ping_free
(
&
frame
.
ping
);
}
break
;
case
SPDYLAY_GOAWAY
:
r
=
spdylay_frame_unpack_goaway
(
&
frame
.
goaway
,
session
->
iframe
.
headbuf
,
sizeof
(
session
->
iframe
.
headbuf
),
session
->
iframe
.
buf
,
session
->
iframe
.
len
);
if
(
r
==
0
)
{
r
=
spdylay_session_on_goaway_received
(
session
,
&
frame
);
spdylay_frame_goaway_free
(
&
frame
.
goaway
);
}
break
;
case
SPDYLAY_HEADERS
:
r
=
spdylay_frame_unpack_headers
(
&
frame
.
headers
,
session
->
iframe
.
headbuf
,
...
...
@@ -1025,12 +1093,19 @@ int spdylay_session_recv(spdylay_session *session)
int
spdylay_session_want_read
(
spdylay_session
*
session
)
{
return
1
;
/* If GOAWAY is not sent or received, we always want to read
incoming frames. After GOAWAY is sent or received, we are only
interested in existing streams. */
return
!
(
session
->
goaway_flags
&
SPDYLAY_GOAWAY_SEND
)
||
spdylay_map_size
(
&
session
->
streams
)
==
0
;
}
int
spdylay_session_want_write
(
spdylay_session
*
session
)
{
return
session
->
aob
.
item
!=
NULL
||
!
spdylay_pq_empty
(
&
session
->
ob_pq
);
uint8_t
goaway_sent
=
session
->
goaway_flags
&
SPDYLAY_GOAWAY_SEND
;
return
(
!
goaway_sent
&&
(
session
->
aob
.
item
!=
NULL
||
!
spdylay_pq_empty
(
&
session
->
ob_pq
)))
||
(
goaway_sent
&&
spdylay_map_size
(
&
session
->
streams
)
==
0
);
}
int
spdylay_session_add_ping
(
spdylay_session
*
session
,
uint32_t
unique_id
)
...
...
@@ -1050,6 +1125,24 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
return
r
;
}
int
spdylay_session_add_goaway
(
spdylay_session
*
session
,
int32_t
last_good_stream_id
)
{
int
r
;
spdylay_frame
*
frame
;
frame
=
malloc
(
sizeof
(
spdylay_frame
));
if
(
frame
==
NULL
)
{
return
SPDYLAY_ERR_NOMEM
;
}
spdylay_frame_goaway_init
(
&
frame
->
goaway
,
last_good_stream_id
);
r
=
spdylay_session_add_frame
(
session
,
SPDYLAY_GOAWAY
,
frame
);
if
(
r
!=
0
)
{
spdylay_frame_goaway_free
(
&
frame
->
goaway
);
free
(
frame
);
}
return
r
;
}
int
spdylay_submit_ping
(
spdylay_session
*
session
)
{
return
spdylay_session_add_ping
(
session
,
...
...
lib/spdylay_session.h
View file @
aed626bf
...
...
@@ -79,6 +79,14 @@ typedef struct {
uint8_t
ign
;
}
spdylay_inbound_frame
;
typedef
enum
{
SPDYLAY_GOAWAY_NONE
=
0
,
/* Flag means GOAWAY frame is sent to the remote peer. */
SPDYLAY_GOAWAY_SEND
=
0x1
,
/* Flag means GOAWAY frame is received from the remote peer. */
SPDYLAY_GOAWAY_RECV
=
0x2
}
spdylay_goaway_flag
;
typedef
struct
spdylay_session
{
uint8_t
server
;
int32_t
next_stream_id
;
...
...
@@ -103,6 +111,12 @@ typedef struct spdylay_session {
/* Time stamp when last ping is sent. */
struct
timespec
last_ping_time
;
/* Flags indicating GOAWAY is sent and/or recieved. The flags are
composed by bitwise OR-ing spdylay_goaway_flag. */
uint8_t
goaway_flags
;
/* This is the value in GOAWAY frame sent by remote endpoint. */
int32_t
last_good_stream_id
;
spdylay_session_callbacks
callbacks
;
void
*
user_data
;
}
spdylay_session
;
...
...
@@ -118,6 +132,9 @@ int spdylay_session_add_rst_stream(spdylay_session *session,
int
spdylay_session_add_ping
(
spdylay_session
*
session
,
uint32_t
unique_id
);
int
spdylay_session_add_goaway
(
spdylay_session
*
session
,
int32_t
last_good_stream_id
);
/*
* Creates new stream in |session| with stream ID |stream_id|,
* priority |pri| and flags |flags|. Currently, |flags| &
...
...
@@ -167,6 +184,12 @@ int spdylay_session_on_rst_stream_received(spdylay_session *session,
int
spdylay_session_on_ping_received
(
spdylay_session
*
session
,
spdylay_frame
*
frame
);
/*
* Called when GOAWAY is received. Received frame is |frame|.
*/
int
spdylay_session_on_goaway_received
(
spdylay_session
*
session
,
spdylay_frame
*
frame
);
/*
* Called when HEADERS is recieved. Received frame is |frame|.
*/
...
...
tests/main.c
View file @
aed626bf
...
...
@@ -86,10 +86,14 @@ int main()
test_spdylay_session_on_headers_received
)
||
!
CU_add_test
(
pSuite
,
"session_on_ping_received"
,
test_spdylay_session_on_ping_received
)
||
!
CU_add_test
(
pSuite
,
"session_on_goaway_received"
,
test_spdylay_session_on_goaway_received
)
||
!
CU_add_test
(
pSuite
,
"frame_unpack_nv"
,
test_spdylay_frame_unpack_nv
)
||
!
CU_add_test
(
pSuite
,
"frame_count_nv_space"
,
test_spdylay_frame_count_nv_space
)
||
!
CU_add_test
(
pSuite
,
"frame_pack_ping"
,
test_spdylay_frame_pack_ping
)
||
!
CU_add_test
(
pSuite
,
"frame_pack_goaway"
,
test_spdylay_frame_pack_goaway
)
||
!
CU_add_test
(
pSuite
,
"frame_pack_headers"
,
test_spdylay_frame_pack_headers
)
||
!
CU_add_test
(
pSuite
,
"frame_nv_sort"
,
test_spdylay_frame_nv_sort
))
{
...
...
tests/spdylay_frame_test.c
View file @
aed626bf
...
...
@@ -71,6 +71,28 @@ void test_spdylay_frame_pack_ping()
spdylay_frame_ping_free
(
&
frame
.
ping
);
}
void
test_spdylay_frame_pack_goaway
()
{
spdylay_frame
frame
,
oframe
;
uint8_t
*
buf
;
ssize_t
buflen
;
spdylay_frame_goaway_init
(
&
frame
.
goaway
,
1000000007
);
buflen
=
spdylay_frame_pack_goaway
(
&
buf
,
&
frame
.
goaway
);
CU_ASSERT
(
0
==
spdylay_frame_unpack_goaway
(
&
oframe
.
goaway
,
&
buf
[
0
],
SPDYLAY_FRAME_HEAD_LENGTH
,
&
buf
[
SPDYLAY_FRAME_HEAD_LENGTH
],
buflen
-
SPDYLAY_FRAME_HEAD_LENGTH
));
CU_ASSERT
(
1000000007
==
oframe
.
goaway
.
last_good_stream_id
);
CU_ASSERT
(
SPDYLAY_PROTO_VERSION
==
oframe
.
headers
.
hd
.
version
);
CU_ASSERT
(
SPDYLAY_GOAWAY
==
oframe
.
headers
.
hd
.
type
);
CU_ASSERT
(
SPDYLAY_FLAG_NONE
==
oframe
.
headers
.
hd
.
flags
);
CU_ASSERT
(
buflen
-
SPDYLAY_FRAME_HEAD_LENGTH
==
oframe
.
ping
.
hd
.
length
);
free
(
buf
);
spdylay_frame_goaway_free
(
&
oframe
.
goaway
);
spdylay_frame_goaway_free
(
&
frame
.
goaway
);
}
void
test_spdylay_frame_pack_headers
()
{
spdylay_zlib
deflater
,
inflater
;
...
...
tests/spdylay_frame_test.h
View file @
aed626bf
...
...
@@ -28,6 +28,7 @@
void
test_spdylay_frame_unpack_nv
();
void
test_spdylay_frame_count_nv_space
();
void
test_spdylay_frame_pack_ping
();
void
test_spdylay_frame_pack_goaway
();
void
test_spdylay_frame_pack_headers
();
void
test_spdylay_frame_nv_sort
();
...
...
tests/spdylay_session_test.c
View file @
aed626bf
...
...
@@ -579,3 +579,34 @@ void test_spdylay_session_on_ping_received()
spdylay_frame_ping_free
(
&
frame
.
ping
);
spdylay_session_del
(
session
);
}
void
test_spdylay_session_on_goaway_received
()
{
spdylay_session
*
session
;
spdylay_session_callbacks
callbacks
=
{
NULL
,
NULL
,
on_ctrl_recv_callback
,
on_invalid_ctrl_recv_callback
,
};
my_user_data
user_data
;
spdylay_frame
frame
;
spdylay_outbound_item
*
top
;
int32_t
stream_id
=
1000000007
;
user_data
.
valid
=
0
;
user_data
.
invalid
=
0
;
spdylay_session_client_new
(
&
session
,
&
callbacks
,
&
user_data
);
spdylay_frame_goaway_init
(
&
frame
.
goaway
,
stream_id
);
CU_ASSERT
(
0
==
spdylay_session_on_goaway_received
(
session
,
&
frame
));
CU_ASSERT
(
1
==
user_data
.
valid
);
CU_ASSERT
(
session
->
goaway_flags
==
SPDYLAY_GOAWAY_RECV
);
top
=
spdylay_session_get_ob_pq_top
(
session
);
CU_ASSERT
(
SPDYLAY_GOAWAY
==
top
->
frame_type
);
CU_ASSERT
(
0
==
top
->
frame
->
goaway
.
last_good_stream_id
);
spdylay_frame_goaway_free
(
&
frame
.
goaway
);
spdylay_session_del
(
session
);
}
tests/spdylay_session_test.h
View file @
aed626bf
...
...
@@ -36,5 +36,6 @@ void test_spdylay_submit_response();
void
test_spdylay_session_reply_fail
();
void
test_spdylay_session_on_headers_received
();
void
test_spdylay_session_on_ping_received
();
void
test_spdylay_session_on_goaway_received
();
#endif // SPDYLAY_SESSION_TEST_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment