1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
/*
This file is part of libmicrospdy
Copyright (C) 2012 Andrey Uzunov
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file session.h
* @brief TCP connection/SPDY session handling
* @author Andrey Uzunov
*/
#ifndef SESSION_H
#define SESSION_H
#include "platform.h"
#include "structures.h"
/**
* Called by the daemon when the socket for the session has available
* data to be read. Reads data from the TLS socket and puts it to the
* session's read buffer. The latte
*
* @param session SPDY_Session for which data will be read.
* @return SPDY_YES if something was read or session's status was
* changed. It is possible that error occurred but was handled
* and the status was therefore changed.
* SPDY_NO if nothing happened, e.g. the subsystem wants read/
* write to be called again.
*/
int
SPDYF_session_read (struct SPDY_Session *session);
/**
* Called by the daemon when the socket for the session is ready for some
* data to be written to it. For one or more objects on the response
* queue tries to fill in the write buffer, based on the frame on the
* queue, and to write data to the TLS socket.
*
* @param session SPDY_Session for which data will be written.
* @return TODO document after changes
* SPDY_YES if something was written, the status was changed or
* response callback was called but did not provide data
* @return SPDY_YES if something was written, session's status was
* changed or response callback was called but did not provide
* data. It is possible that error occurred but was handled
* and the status was therefore changed.
* SPDY_NO if nothing happened, e.g. the subsystem wants read/
* write to be called again. However, it is possible that some
* frames were discarded within the call, e.g. frames belonging
* to a closed stream.
*/
int
SPDYF_session_write (struct SPDY_Session *session, bool only_one_frame);
/**
* Called by the daemon on SPDY_run to handle the data in the read and write
* buffer of a session. Based on the state and the content of the read
* buffer new frames are received and interpreted, appropriate user
* callbacks are called and maybe something is put on the response queue
* ready to be handled by session_write.
*
* @param session SPDY_Session which will be handled.
* @return SPDY_YES if something from the read buffers was processed,
* session's status was changed and/or the session was closed.
* SPDY_NO if nothing happened, e.g. the session is in a state,
* not allowing processing read buffers.
*/
int
SPDYF_session_idle (struct SPDY_Session *session);
/**
* This function shutdowns the socket, moves the session structure to
* daemon's queue for sessions to be cleaned up.
*
* @param session SPDY_Session which will be handled.
*/
void
SPDYF_session_close (struct SPDY_Session *session);
/**
* Called to accept new TCP connection and create SPDY session.
*
* @param daemon SPDY_Daemon whose listening socket is used.
* @return SPDY_NO on any kind of error while accepting new TCP connection
* and initializing new SPDY_Session.
* SPDY_YES otherwise.
*/
int
SPDYF_session_accept(struct SPDY_Daemon *daemon);
/**
* Puts SPDYF_Response_Queue object on the queue to be sent to the
* client later.
*
* @param response_to_queue linked list of objects containing SPDY
* frame and data to be added to the queue
* @param session SPDY session for which the response is sent
* @param consider_priority if SPDY_NO, the list will be added to the
* end of the queue.
* If SPDY_YES, the response will be added after
* the last previously added response with priority of the
* request grater or equal to that of the current one.
* If -1, the object will be put at the head of the queue.
*/
void
SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue,
struct SPDY_Session *session,
int consider_priority);
/**
* Cleans up the TSL context for the session, closes the TCP connection,
* cleans up any data pointed by members of the session structure
* (buffers, queue of responses, etc.) and frees the memory allocated by
* the session itself.
*/
void
SPDYF_session_destroy(struct SPDY_Session *session);
/**
* Prepares GOAWAY frame to tell the client to stop creating new streams.
* The session should be closed soon after this call.
*
* @param session SPDY session
* @param status code for the GOAWAY frame
* @param in_front whether or not to put the frame in front of everything
* on the response queue
* @return SPDY_NO on error (not enough memory) or
* SPDY_YES on success
*/
int
SPDYF_prepare_goaway (struct SPDY_Session *session,
enum SPDY_GOAWAY_STATUS status,
bool in_front);
/**
* Prepares RST_STREAM frame to terminate a stream. This frame may or
* not indicate an error. The frame will be put at the head of the queue.
* This means that frames for this stream which are still in the queue
* will be discarded soon.
*
* @param session SPDY session
* @param stream stream to terminate
* @param status code for the RST_STREAM frame
* @return SPDY_NO on memory error or
* SPDY_YES on success
*/
int
SPDYF_prepare_rst_stream (struct SPDY_Session *session,
struct SPDYF_Stream * stream,
enum SPDY_RST_STREAM_STATUS status);
/**
* Prepares WINDOW_UPDATE frame to tell the other party that more
* data can be sent on the stream. The frame will be put at the head of
* the queue.
*
* @param session SPDY session
* @param stream stream to which the changed window will apply
* @param delta_window_size how much the window grows
* @return SPDY_NO on memory error or
* SPDY_YES on success
*/
int
SPDYF_prepare_window_update (struct SPDY_Session *session,
struct SPDYF_Stream * stream,
int32_t delta_window_size);
/**
* Handler called by session_write to fill the write buffer according to
* the data frame waiting in the response queue.
* When response data is given by user callback, the lib does not know
* how many frames are needed. In such case this call produces
* another ResponseQueue object and puts it on the queue while the the
* user callback says that there will be more data.
*
* @return SPDY_NO on error (not enough memory or the user calback for
* providing response data did something wrong). If
* the error is unrecoverable the handler changes session's
* status.
* SPDY_YES on success
*/
int
SPDYF_handler_write_data (struct SPDY_Session *session);
/**
* Handler called by session_write to fill the write buffer based on the
* control frame (SYN_REPLY) waiting in the response queue.
*
* @param session SPDY session
* @return SPDY_NO on error (zlib state is broken; the session MUST be
* closed). If
* the error is unrecoverable the handler changes session's
* status.
* SPDY_YES on success
*/
int
SPDYF_handler_write_syn_reply (struct SPDY_Session *session);
/**
* Handler called by session_write to fill the write buffer based on the
* control frame (GOAWAY) waiting in the response queue.
*
* @param session SPDY session
* @return SPDY_NO on error (not enough memory; by specification the
* session must be closed
* soon, thus there is no need to handle the error) or
* SPDY_YES on success
*/
int
SPDYF_handler_write_goaway (struct SPDY_Session *session);
/**
* Handler called by session_write to fill the write buffer based on the
* control frame (RST_STREAM) waiting in the response queue.
*
* @param session SPDY session
* @return SPDY_NO on error (not enough memory). If
* the error is unrecoverable the handler changes session's
* status.
* SPDY_YES on success
*/
int
SPDYF_handler_write_rst_stream (struct SPDY_Session *session);
/**
* Handler called by session_write to fill the write buffer based on the
* control frame (WINDOW_UPDATE) waiting in the response queue.
*
* @param session SPDY session
* @return SPDY_NO on error (not enough memory). If
* the error is unrecoverable the handler changes session's
* status.
* SPDY_YES on success
*/
int
SPDYF_handler_write_window_update (struct SPDY_Session *session);
/**
* Carefully ignore the full size of frames which are not yet supported
* by the lib.
* TODO Ignoring frames containing compressed bodies means that the
* compress state will be corrupted on next received frame. According to
* the draft the lib SHOULD try to decompress data also in corrupted
* frames just to keep right compression state.
*
* @param session SPDY_Session whose read buffer is used.
*/
void
SPDYF_handler_ignore_frame (struct SPDY_Session *session);
#endif
|