Mercurial > hg > freeDiameter
comparison libfdcore/sctp3436.c @ 1344:a5c072798f1a
Increase two buffer sizes to avoid truncation.
Remove trailing whitespace while here.
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Fri, 12 Apr 2019 13:15:04 +0200 |
parents | 6a1042d8075b |
children | 3cbe458fbfa9 |
comparison
equal
deleted
inserted
replaced
1343:0c25bfa3660e | 1344:a5c072798f1a |
---|---|
48 - we have several fifo queues (1 per stream pairs). | 48 - we have several fifo queues (1 per stream pairs). |
49 GnuTLS is configured to use custom push / pull functions: | 49 GnuTLS is configured to use custom push / pull functions: |
50 - the pull function retrieves the data from the fifo queue corresponding to a stream #. | 50 - the pull function retrieves the data from the fifo queue corresponding to a stream #. |
51 - the push function sends the data on a certain stream. | 51 - the push function sends the data on a certain stream. |
52 We also have a demux thread that reads the socket and store received data in the appropriate fifo | 52 We also have a demux thread that reads the socket and store received data in the appropriate fifo |
53 | 53 |
54 We have one gnutls_session per stream pair, and as many threads that read the gnutls records and save incoming data to the target queue. | 54 We have one gnutls_session per stream pair, and as many threads that read the gnutls records and save incoming data to the target queue. |
55 | 55 |
56 This complexity is required because we cannot read a socket for a given stream only; we can only get the next message and find its stream. | 56 This complexity is required because we cannot read a socket for a given stream only; we can only get the next message and find its stream. |
57 */ | 57 */ |
58 | 58 |
59 /* Note that this mechanism is replaced by DTLS in RFC6733 */ | 59 /* Note that this mechanism is replaced by DTLS in RFC6733 */ |
60 | 60 |
68 struct cnxctx * conn = arg; | 68 struct cnxctx * conn = arg; |
69 uint8_t * buf; | 69 uint8_t * buf; |
70 size_t bufsz; | 70 size_t bufsz; |
71 int event; | 71 int event; |
72 uint16_t strid; | 72 uint16_t strid; |
73 | 73 |
74 TRACE_ENTRY("%p", arg); | 74 TRACE_ENTRY("%p", arg); |
75 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); | 75 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); |
76 | 76 |
77 /* Set the thread name */ | 77 /* Set the thread name */ |
78 { | 78 { |
79 char buf[48]; | 79 char buf[100]; |
80 snprintf(buf, sizeof(buf), "Demuxer (%d:%s)", conn->cc_socket, conn->cc_remid); | 80 snprintf(buf, sizeof(buf), "Demuxer (%d:%s)", conn->cc_socket, conn->cc_remid); |
81 fd_log_threadname ( buf ); | 81 fd_log_threadname ( buf ); |
82 } | 82 } |
83 | 83 |
84 ASSERT( conn->cc_proto == IPPROTO_SCTP ); | 84 ASSERT( conn->cc_proto == IPPROTO_SCTP ); |
85 ASSERT( fd_cnx_target_queue(conn) ); | 85 ASSERT( fd_cnx_target_queue(conn) ); |
86 ASSERT( conn->cc_sctp3436_data.array ); | 86 ASSERT( conn->cc_sctp3436_data.array ); |
87 | 87 |
88 do { | 88 do { |
89 CHECK_FCT_DO( fd_sctp_recvmeta(conn, &strid, &buf, &bufsz, &event), goto fatal ); | 89 CHECK_FCT_DO( fd_sctp_recvmeta(conn, &strid, &buf, &bufsz, &event), goto fatal ); |
90 switch (event) { | 90 switch (event) { |
91 case FDEVP_CNX_MSG_RECV: | 91 case FDEVP_CNX_MSG_RECV: |
92 /* Demux this message to the appropriate fifo, another thread will pull, gnutls process, and send to target queue */ | 92 /* Demux this message to the appropriate fifo, another thread will pull, gnutls process, and send to target queue */ |
95 } else { | 95 } else { |
96 TRACE_DEBUG(INFO, "Received packet (%zd bytes) on out-of-range stream #%d from %s, discarded.", bufsz, strid, conn->cc_remid); | 96 TRACE_DEBUG(INFO, "Received packet (%zd bytes) on out-of-range stream #%d from %s, discarded.", bufsz, strid, conn->cc_remid); |
97 free(buf); | 97 free(buf); |
98 } | 98 } |
99 break; | 99 break; |
100 | 100 |
101 case FDEVP_CNX_EP_CHANGE: | 101 case FDEVP_CNX_EP_CHANGE: |
102 /* Send this event to the target queue */ | 102 /* Send this event to the target queue */ |
103 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal ); | 103 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal ); |
104 break; | 104 break; |
105 | 105 |
106 case FDEVP_CNX_ERROR: | 106 case FDEVP_CNX_ERROR: |
107 goto out; | 107 goto out; |
108 | 108 |
109 case FDEVP_CNX_SHUTDOWN: | 109 case FDEVP_CNX_SHUTDOWN: |
110 /* Just ignore the notification for now, we will get another error later anyway */ | 110 /* Just ignore the notification for now, we will get another error later anyway */ |
111 continue; | 111 continue; |
112 | 112 |
113 default: | 113 default: |
114 goto fatal; | 114 goto fatal; |
115 } | 115 } |
116 | 116 |
117 } while (conn->cc_loop); | 117 } while (conn->cc_loop); |
118 | 118 |
119 out: | 119 out: |
120 /* Signal termination of the connection to all decipher threads */ | 120 /* Signal termination of the connection to all decipher threads */ |
121 for (strid = 0; strid < conn->cc_sctp_para.pairs; strid++) { | 121 for (strid = 0; strid < conn->cc_sctp_para.pairs; strid++) { |
122 if (conn->cc_sctp3436_data.array[strid].raw_recv) { | 122 if (conn->cc_sctp3436_data.array[strid].raw_recv) { |
123 CHECK_FCT_DO(fd_event_send(conn->cc_sctp3436_data.array[strid].raw_recv, FDEVP_CNX_ERROR, 0, NULL), goto fatal ); | 123 CHECK_FCT_DO(fd_event_send(conn->cc_sctp3436_data.array[strid].raw_recv, FDEVP_CNX_ERROR, 0, NULL), goto fatal ); |
124 } | 124 } |
125 } | 125 } |
126 fd_cnx_markerror(conn); | 126 fd_cnx_markerror(conn); |
127 TRACE_DEBUG(FULL, "Thread terminated"); | 127 TRACE_DEBUG(FULL, "Thread terminated"); |
128 return NULL; | 128 return NULL; |
129 | 129 |
130 fatal: | 130 fatal: |
131 /* An unrecoverable error occurred, stop the daemon */ | 131 /* An unrecoverable error occurred, stop the daemon */ |
132 CHECK_FCT_DO(fd_core_shutdown(), ); | 132 CHECK_FCT_DO(fd_core_shutdown(), ); |
133 goto out; | 133 goto out; |
134 } | 134 } |
136 /* Decrypt the data received in this stream pair and store it in the target queue */ | 136 /* Decrypt the data received in this stream pair and store it in the target queue */ |
137 static void * decipher(void * arg) | 137 static void * decipher(void * arg) |
138 { | 138 { |
139 struct sctp3436_ctx * ctx = arg; | 139 struct sctp3436_ctx * ctx = arg; |
140 struct cnxctx *cnx; | 140 struct cnxctx *cnx; |
141 | 141 |
142 TRACE_ENTRY("%p", arg); | 142 TRACE_ENTRY("%p", arg); |
143 CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error); | 143 CHECK_PARAMS_DO(ctx && ctx->raw_recv && ctx->parent, goto error); |
144 cnx = ctx->parent; | 144 cnx = ctx->parent; |
145 ASSERT( fd_cnx_target_queue(cnx) ); | 145 ASSERT( fd_cnx_target_queue(cnx) ); |
146 | 146 |
147 /* Set the thread name */ | 147 /* Set the thread name */ |
148 { | 148 { |
149 char buf[48]; | 149 char buf[100]; |
150 snprintf(buf, sizeof(buf), "Decipher (%hu@%d:%s)", ctx->strid, cnx->cc_socket, cnx->cc_remid); | 150 snprintf(buf, sizeof(buf), "Decipher (%hu@%d:%s)", ctx->strid, cnx->cc_socket, cnx->cc_remid); |
151 fd_log_threadname ( buf ); | 151 fd_log_threadname ( buf ); |
152 } | 152 } |
153 | 153 |
154 /* The next function loops while there is no error */ | 154 /* The next function loops while there is no error */ |
155 CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */); | 155 CHECK_FCT_DO(fd_tls_rcvthr_core(cnx, ctx->strid ? ctx->session : cnx->cc_tls_para.session), /* continue */); |
156 error: | 156 error: |
157 fd_cnx_markerror(cnx); | 157 fd_cnx_markerror(cnx); |
158 TRACE_DEBUG(FULL, "Thread terminated"); | 158 TRACE_DEBUG(FULL, "Thread terminated"); |
159 return NULL; | 159 return NULL; |
160 } | 160 } |
161 | 161 |
162 /*************************************************************/ | 162 /*************************************************************/ |
163 /* push / pull */ | 163 /* push / pull */ |
168 static int sctp3436_pull_timeout(gnutls_transport_ptr_t tr, unsigned int ms) | 168 static int sctp3436_pull_timeout(gnutls_transport_ptr_t tr, unsigned int ms) |
169 { | 169 { |
170 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; | 170 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; |
171 struct timespec tsstore, *ts = NULL; | 171 struct timespec tsstore, *ts = NULL; |
172 int ret; | 172 int ret; |
173 | 173 |
174 TRACE_ENTRY("%p %d", tr, ms); | 174 TRACE_ENTRY("%p %d", tr, ms); |
175 | 175 |
176 if (ctx->partial.buf) | 176 if (ctx->partial.buf) |
177 return 1; /* data is already available for pull */ | 177 return 1; /* data is already available for pull */ |
178 | 178 |
179 if (ms) { | 179 if (ms) { |
180 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &tsstore), return -1 ); | 180 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &tsstore), return -1 ); |
181 tsstore.tv_nsec += (long)ms * 1000000; | 181 tsstore.tv_nsec += (long)ms * 1000000; |
182 tsstore.tv_sec += tsstore.tv_nsec / 1000000000L; | 182 tsstore.tv_sec += tsstore.tv_nsec / 1000000000L; |
183 tsstore.tv_nsec %= 1000000000L; | 183 tsstore.tv_nsec %= 1000000000L; |
184 ts = &tsstore; | 184 ts = &tsstore; |
185 } | 185 } |
186 | 186 |
187 ret = fd_fifo_select ( ctx->raw_recv, ts ); | 187 ret = fd_fifo_select ( ctx->raw_recv, ts ); |
188 if (ret < 0) { | 188 if (ret < 0) { |
189 errno = -ret; | 189 errno = -ret; |
190 ret = -1; | 190 ret = -1; |
191 } | 191 } |
192 | 192 |
193 return ret; | 193 return ret; |
194 } | 194 } |
195 #endif /* GNUTLS_VERSION_300 */ | 195 #endif /* GNUTLS_VERSION_300 */ |
196 | 196 |
197 /* Send data over the connection, called by gnutls */ | 197 /* Send data over the connection, called by gnutls */ |
198 #ifndef GNUTLS_VERSION_212 | 198 #ifndef GNUTLS_VERSION_212 |
199 static ssize_t sctp3436_push(gnutls_transport_ptr_t tr, const void * data, size_t len) | 199 static ssize_t sctp3436_push(gnutls_transport_ptr_t tr, const void * data, size_t len) |
200 { | 200 { |
201 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; | 201 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; |
202 struct iovec iov; | 202 struct iovec iov; |
203 | 203 |
204 TRACE_ENTRY("%p %p %zd", tr, data, len); | 204 TRACE_ENTRY("%p %p %zd", tr, data, len); |
205 CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } ); | 205 CHECK_PARAMS_DO( tr && data, { errno = EINVAL; return -1; } ); |
206 | 206 |
207 iov.iov_base = (void *)data; | 207 iov.iov_base = (void *)data; |
208 iov.iov_len = len; | 208 iov.iov_len = len; |
209 | 209 |
210 return fd_sctp_sendstrv(ctx->parent, ctx->strid, &iov, 1); | 210 return fd_sctp_sendstrv(ctx->parent, ctx->strid, &iov, 1); |
211 } | 211 } |
212 #else /* GNUTLS_VERSION_212 */ | 212 #else /* GNUTLS_VERSION_212 */ |
213 static ssize_t sctp3436_pushv(gnutls_transport_ptr_t tr, const giovec_t * iov, int iovcnt) | 213 static ssize_t sctp3436_pushv(gnutls_transport_ptr_t tr, const giovec_t * iov, int iovcnt) |
214 { | 214 { |
215 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; | 215 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; |
216 | 216 |
217 TRACE_ENTRY("%p %p %d", tr, iov, iovcnt); | 217 TRACE_ENTRY("%p %p %d", tr, iov, iovcnt); |
218 CHECK_PARAMS_DO( tr && iov, { errno = EINVAL; return -1; } ); | 218 CHECK_PARAMS_DO( tr && iov, { errno = EINVAL; return -1; } ); |
219 | 219 |
220 return fd_sctp_sendstrv(ctx->parent, ctx->strid, (const struct iovec *)iov, iovcnt); | 220 return fd_sctp_sendstrv(ctx->parent, ctx->strid, (const struct iovec *)iov, iovcnt); |
221 } | 221 } |
222 #endif /* GNUTLS_VERSION_212 */ | 222 #endif /* GNUTLS_VERSION_212 */ |
223 | 223 |
224 /* Retrieve data received on a stream and already demultiplexed */ | 224 /* Retrieve data received on a stream and already demultiplexed */ |
225 static ssize_t sctp3436_pull(gnutls_transport_ptr_t tr, void * buf, size_t len) | 225 static ssize_t sctp3436_pull(gnutls_transport_ptr_t tr, void * buf, size_t len) |
226 { | 226 { |
227 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; | 227 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) tr; |
228 size_t pulled = 0; | 228 size_t pulled = 0; |
229 int emptied; | 229 int emptied; |
230 | 230 |
231 TRACE_ENTRY("%p %p %zd", tr, buf, len); | 231 TRACE_ENTRY("%p %p %zd", tr, buf, len); |
232 CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } ); | 232 CHECK_PARAMS_DO( tr && buf, { errno = EINVAL; goto error; } ); |
233 | 233 |
234 /* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */ | 234 /* If we don't have data available now, pull new message from the fifo -- this is blocking (until the queue is destroyed) */ |
235 if (!ctx->partial.buf) { | 235 if (!ctx->partial.buf) { |
236 int ev; | 236 int ev; |
237 CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), goto error ); | 237 CHECK_FCT_DO( errno = fd_event_get(ctx->raw_recv, &ev, &ctx->partial.bufsz, (void *)&ctx->partial.buf), goto error ); |
238 if (ev == FDEVP_CNX_ERROR) { | 238 if (ev == FDEVP_CNX_ERROR) { |
239 /* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */ | 239 /* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */ |
240 return -1; | 240 return -1; |
241 } | 241 } |
242 } | 242 } |
243 | 243 |
244 pulled = ctx->partial.bufsz - ctx->partial.offset; | 244 pulled = ctx->partial.bufsz - ctx->partial.offset; |
245 if (pulled <= len) { | 245 if (pulled <= len) { |
246 emptied = 1; | 246 emptied = 1; |
247 } else { | 247 } else { |
248 /* limit to the capacity of destination buffer */ | 248 /* limit to the capacity of destination buffer */ |
261 ctx->partial.offset += pulled; | 261 ctx->partial.offset += pulled; |
262 } | 262 } |
263 | 263 |
264 /* We are done */ | 264 /* We are done */ |
265 return pulled; | 265 return pulled; |
266 | 266 |
267 error: | 267 error: |
268 gnutls_transport_set_errno (ctx->session, errno); | 268 gnutls_transport_set_errno (ctx->session, errno); |
269 return -1; | 269 return -1; |
270 } | 270 } |
271 | 271 |
275 #endif /* !GNUTLS_VERSION_300 */ | 275 #endif /* !GNUTLS_VERSION_300 */ |
276 static void set_sess_transport(gnutls_session_t session, struct sctp3436_ctx *ctx) | 276 static void set_sess_transport(gnutls_session_t session, struct sctp3436_ctx *ctx) |
277 { | 277 { |
278 /* Set the transport pointer passed to push & pull callbacks */ | 278 /* Set the transport pointer passed to push & pull callbacks */ |
279 GNUTLS_TRACE( gnutls_transport_set_ptr( session, (gnutls_transport_ptr_t) ctx ) ); | 279 GNUTLS_TRACE( gnutls_transport_set_ptr( session, (gnutls_transport_ptr_t) ctx ) ); |
280 | 280 |
281 /* Reset the low water value, since we don't use sockets */ | 281 /* Reset the low water value, since we don't use sockets */ |
282 #ifndef GNUTLS_VERSION_300 | 282 #ifndef GNUTLS_VERSION_300 |
283 /* starting version 2.12, this call is not needed */ | 283 /* starting version 2.12, this call is not needed */ |
284 GNUTLS_TRACE( gnutls_transport_set_lowat( session, 0 ) ); | 284 GNUTLS_TRACE( gnutls_transport_set_lowat( session, 0 ) ); |
285 #else /* GNUTLS_VERSION_300 */ | 285 #else /* GNUTLS_VERSION_300 */ |
286 /* but in 3.0 we have to provide the pull_timeout callback */ | 286 /* but in 3.0 we have to provide the pull_timeout callback */ |
287 GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( session, sctp3436_pull_timeout ) ); | 287 GNUTLS_TRACE( gnutls_transport_set_pull_timeout_function( session, sctp3436_pull_timeout ) ); |
288 #endif /* GNUTLS_VERSION_300 */ | 288 #endif /* GNUTLS_VERSION_300 */ |
289 | 289 |
290 /* Set the push and pull callbacks */ | 290 /* Set the push and pull callbacks */ |
291 GNUTLS_TRACE( gnutls_transport_set_pull_function(session, sctp3436_pull) ); | 291 GNUTLS_TRACE( gnutls_transport_set_pull_function(session, sctp3436_pull) ); |
292 #ifndef GNUTLS_VERSION_212 | 292 #ifndef GNUTLS_VERSION_212 |
293 GNUTLS_TRACE( gnutls_transport_set_push_function(session, sctp3436_push) ); | 293 GNUTLS_TRACE( gnutls_transport_set_push_function(session, sctp3436_push) ); |
294 #else /* GNUTLS_VERSION_212 */ | 294 #else /* GNUTLS_VERSION_212 */ |
322 /* Initialize the store area for a connection */ | 322 /* Initialize the store area for a connection */ |
323 static int store_init(struct cnxctx * conn) | 323 static int store_init(struct cnxctx * conn) |
324 { | 324 { |
325 TRACE_ENTRY("%p", conn); | 325 TRACE_ENTRY("%p", conn); |
326 CHECK_PARAMS( conn && !conn->cc_sctp3436_data.sess_store ); | 326 CHECK_PARAMS( conn && !conn->cc_sctp3436_data.sess_store ); |
327 | 327 |
328 CHECK_MALLOC( conn->cc_sctp3436_data.sess_store = malloc(sizeof(struct sr_store)) ); | 328 CHECK_MALLOC( conn->cc_sctp3436_data.sess_store = malloc(sizeof(struct sr_store)) ); |
329 memset(conn->cc_sctp3436_data.sess_store, 0, sizeof(struct sr_store)); | 329 memset(conn->cc_sctp3436_data.sess_store, 0, sizeof(struct sr_store)); |
330 | 330 |
331 fd_list_init(&conn->cc_sctp3436_data.sess_store->list, NULL); | 331 fd_list_init(&conn->cc_sctp3436_data.sess_store->list, NULL); |
332 CHECK_POSIX( pthread_rwlock_init(&conn->cc_sctp3436_data.sess_store->lock, NULL) ); | 332 CHECK_POSIX( pthread_rwlock_init(&conn->cc_sctp3436_data.sess_store->lock, NULL) ); |
333 conn->cc_sctp3436_data.sess_store->parent = conn; | 333 conn->cc_sctp3436_data.sess_store->parent = conn; |
334 | 334 |
335 return 0; | 335 return 0; |
336 } | 336 } |
337 | 337 |
338 /* Destroy the store area for a connection, and all its content */ | 338 /* Destroy the store area for a connection, and all its content */ |
339 static void store_destroy(struct cnxctx * conn) | 339 static void store_destroy(struct cnxctx * conn) |
340 { | 340 { |
341 /* Del all list entries */ | 341 /* Del all list entries */ |
342 TRACE_ENTRY("%p", conn); | 342 TRACE_ENTRY("%p", conn); |
343 CHECK_PARAMS_DO( conn, return ); | 343 CHECK_PARAMS_DO( conn, return ); |
344 | 344 |
345 if (!conn->cc_sctp3436_data.sess_store) | 345 if (!conn->cc_sctp3436_data.sess_store) |
346 return; | 346 return; |
347 | 347 |
348 CHECK_POSIX_DO( pthread_rwlock_destroy(&conn->cc_sctp3436_data.sess_store->lock), /* continue */ ); | 348 CHECK_POSIX_DO( pthread_rwlock_destroy(&conn->cc_sctp3436_data.sess_store->lock), /* continue */ ); |
349 | 349 |
350 while (!FD_IS_LIST_EMPTY(&conn->cc_sctp3436_data.sess_store->list)) { | 350 while (!FD_IS_LIST_EMPTY(&conn->cc_sctp3436_data.sess_store->list)) { |
351 struct sr_data * sr = (struct sr_data *) conn->cc_sctp3436_data.sess_store->list.next; | 351 struct sr_data * sr = (struct sr_data *) conn->cc_sctp3436_data.sess_store->list.next; |
352 fd_list_unlink( &sr->chain ); | 352 fd_list_unlink( &sr->chain ); |
353 free(sr->key.data); | 353 free(sr->key.data); |
354 free(sr->data.data); | 354 free(sr->data.data); |
355 free(sr); | 355 free(sr); |
356 } | 356 } |
357 | 357 |
358 free(conn->cc_sctp3436_data.sess_store); | 358 free(conn->cc_sctp3436_data.sess_store); |
359 conn->cc_sctp3436_data.sess_store = NULL; | 359 conn->cc_sctp3436_data.sess_store = NULL; |
360 return; | 360 return; |
361 } | 361 } |
362 | 362 |
363 /* Search the position (or next if not found) of a key in a store */ | 363 /* Search the position (or next if not found) of a key in a store */ |
364 static struct fd_list * find_or_next(struct sr_store * sto, gnutls_datum_t key, int * match) | 364 static struct fd_list * find_or_next(struct sr_store * sto, gnutls_datum_t key, int * match) |
365 { | 365 { |
366 struct fd_list * ret; | 366 struct fd_list * ret; |
367 *match = 0; | 367 *match = 0; |
368 | 368 |
369 for (ret = sto->list.next; ret != &sto->list; ret = ret->next) { | 369 for (ret = sto->list.next; ret != &sto->list; ret = ret->next) { |
370 int cmp = 0; | 370 int cmp = 0; |
371 struct sr_data * sr = (struct sr_data *)ret; | 371 struct sr_data * sr = (struct sr_data *)ret; |
372 | 372 |
373 cmp = fd_os_cmp(key.data, key.size, sr->key.data, sr->key.size); | 373 cmp = fd_os_cmp(key.data, key.size, sr->key.data, sr->key.size); |
374 if (cmp > 0) | 374 if (cmp > 0) |
375 continue; | 375 continue; |
376 | 376 |
377 if (cmp == 0) | 377 if (cmp == 0) |
378 *match = 1; | 378 *match = 1; |
379 | 379 |
380 break; | 380 break; |
381 } | 381 } |
382 | 382 |
383 return ret; | 383 return ret; |
384 } | 384 } |
385 | 385 |
386 /* Callbacks for the TLS server side of the connection, called during gnutls_handshake */ | 386 /* Callbacks for the TLS server side of the connection, called during gnutls_handshake */ |
387 static int sr_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data) | 387 static int sr_store (void *dbf, gnutls_datum_t key, gnutls_datum_t data) |
389 struct sr_store * sto = (struct sr_store *)dbf; | 389 struct sr_store * sto = (struct sr_store *)dbf; |
390 struct fd_list * li; | 390 struct fd_list * li; |
391 struct sr_data * sr; | 391 struct sr_data * sr; |
392 int match = 0; | 392 int match = 0; |
393 int ret = 0; | 393 int ret = 0; |
394 | 394 |
395 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); | 395 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); |
396 CHECK_PARAMS_DO( sto && key.data && data.data, return -1 ); | 396 CHECK_PARAMS_DO( sto && key.data && data.data, return -1 ); |
397 | 397 |
398 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); | 398 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); |
399 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session store [key ", key.data, key.size, "]"); | 399 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session store [key ", key.data, key.size, "]"); |
400 | 400 |
401 li = find_or_next(sto, key, &match); | 401 li = find_or_next(sto, key, &match); |
402 if (match) { | 402 if (match) { |
403 sr = (struct sr_data *)li; | 403 sr = (struct sr_data *)li; |
404 | 404 |
405 /* Check the data is the same */ | 405 /* Check the data is the same */ |
406 if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) { | 406 if ((data.size != sr->data.size) || memcmp(data.data, sr->data.data, data.size)) { |
407 TRACE_DEBUG(INFO, "GnuTLS tried to store a session with same key and different data!"); | 407 TRACE_DEBUG(INFO, "GnuTLS tried to store a session with same key and different data!"); |
408 TRACE_BUFFER(FD_LOG_DEBUG, INFO, "Session store [key ", key.data, key.size, "]"); | 408 TRACE_BUFFER(FD_LOG_DEBUG, INFO, "Session store [key ", key.data, key.size, "]"); |
409 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- old data [", sr->data.data, sr->data.size, "]"); | 409 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- old data [", sr->data.data, sr->data.size, "]"); |
410 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- new data [", data.data, data.size, "]"); | 410 TRACE_BUFFER(FD_LOG_DEBUG, INFO, " -- new data [", data.data, data.size, "]"); |
411 | 411 |
412 ret = -1; | 412 ret = -1; |
413 } else { | 413 } else { |
414 TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GnuTLS tried to store a session with same key and same data, skipped."); | 414 TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GnuTLS tried to store a session with same key and same data, skipped."); |
415 } | 415 } |
416 goto out; | 416 goto out; |
417 } | 417 } |
418 | 418 |
419 /* Create a new entry */ | 419 /* Create a new entry */ |
420 CHECK_MALLOC_DO( sr = malloc(sizeof(struct sr_data)), { ret = -1; goto out; } ); | 420 CHECK_MALLOC_DO( sr = malloc(sizeof(struct sr_data)), { ret = -1; goto out; } ); |
421 memset(sr, 0, sizeof(struct sr_data)); | 421 memset(sr, 0, sizeof(struct sr_data)); |
422 | 422 |
423 fd_list_init(&sr->chain, sr); | 423 fd_list_init(&sr->chain, sr); |
427 memcpy(sr->key.data, key.data, key.size); | 427 memcpy(sr->key.data, key.data, key.size); |
428 | 428 |
429 CHECK_MALLOC_DO( sr->data.data = malloc(data.size), { ret = -1; goto out; } ); | 429 CHECK_MALLOC_DO( sr->data.data = malloc(data.size), { ret = -1; goto out; } ); |
430 sr->data.size = data.size; | 430 sr->data.size = data.size; |
431 memcpy(sr->data.data, data.data, data.size); | 431 memcpy(sr->data.data, data.data, data.size); |
432 | 432 |
433 /* Save this new entry in the list, we are done */ | 433 /* Save this new entry in the list, we are done */ |
434 fd_list_insert_before(li, &sr->chain); | 434 fd_list_insert_before(li, &sr->chain); |
435 | 435 |
436 out: | 436 out: |
437 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); | 437 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); |
438 return ret; | 438 return ret; |
439 } | 439 } |
440 | 440 |
441 static int sr_remove (void *dbf, gnutls_datum_t key) | 441 static int sr_remove (void *dbf, gnutls_datum_t key) |
443 struct sr_store * sto = (struct sr_store *)dbf; | 443 struct sr_store * sto = (struct sr_store *)dbf; |
444 struct fd_list * li; | 444 struct fd_list * li; |
445 struct sr_data * sr; | 445 struct sr_data * sr; |
446 int match = 0; | 446 int match = 0; |
447 int ret = 0; | 447 int ret = 0; |
448 | 448 |
449 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); | 449 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); |
450 CHECK_PARAMS_DO( sto && key.data, return -1 ); | 450 CHECK_PARAMS_DO( sto && key.data, return -1 ); |
451 | 451 |
452 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); | 452 CHECK_POSIX_DO( pthread_rwlock_wrlock(&sto->lock), return -1 ); |
453 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session delete [key ", key.data, key.size, "]"); | 453 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session delete [key ", key.data, key.size, "]"); |
454 | 454 |
455 li = find_or_next(sto, key, &match); | 455 li = find_or_next(sto, key, &match); |
456 if (match) { | 456 if (match) { |
457 sr = (struct sr_data *)li; | 457 sr = (struct sr_data *)li; |
458 | 458 |
459 /* Destroy this data */ | 459 /* Destroy this data */ |
460 fd_list_unlink(li); | 460 fd_list_unlink(li); |
461 free(sr->key.data); | 461 free(sr->key.data); |
462 free(sr->data.data); | 462 free(sr->data.data); |
463 free(sr); | 463 free(sr); |
464 } else { | 464 } else { |
465 /* It was not found */ | 465 /* It was not found */ |
466 ret = -1; | 466 ret = -1; |
467 } | 467 } |
468 | 468 |
469 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); | 469 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return -1 ); |
470 return ret; | 470 return ret; |
471 } | 471 } |
472 | 472 |
473 static gnutls_datum_t sr_fetch (void *dbf, gnutls_datum_t key) | 473 static gnutls_datum_t sr_fetch (void *dbf, gnutls_datum_t key) |
482 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); | 482 TRACE_DEBUG( GNUTLS_DBG_LEVEL, "GNUTLS Callback: %s", __PRETTY_FUNCTION__ ); |
483 CHECK_PARAMS_DO( sto && key.data, return error ); | 483 CHECK_PARAMS_DO( sto && key.data, return error ); |
484 | 484 |
485 CHECK_POSIX_DO( pthread_rwlock_rdlock(&sto->lock), return error ); | 485 CHECK_POSIX_DO( pthread_rwlock_rdlock(&sto->lock), return error ); |
486 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session fetch [key ", key.data, key.size, "]"); | 486 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Session fetch [key ", key.data, key.size, "]"); |
487 | 487 |
488 li = find_or_next(sto, key, &match); | 488 li = find_or_next(sto, key, &match); |
489 if (match) { | 489 if (match) { |
490 sr = (struct sr_data *)li; | 490 sr = (struct sr_data *)li; |
491 GNUTLS_TRACE( CHECK_MALLOC_DO(res.data = gnutls_malloc(sr->data.size), goto out ) ); | 491 GNUTLS_TRACE( CHECK_MALLOC_DO(res.data = gnutls_malloc(sr->data.size), goto out ) ); |
492 res.size = sr->data.size; | 492 res.size = sr->data.size; |
493 memcpy(res.data, sr->data.data, res.size); | 493 memcpy(res.data, sr->data.data, res.size); |
494 } | 494 } |
495 out: | 495 out: |
496 TRACE_DEBUG(GNUTLS_DBG_LEVEL, "Fetched (%p, %d) from store %p", res.data, res.size, sto); | 496 TRACE_DEBUG(GNUTLS_DBG_LEVEL, "Fetched (%p, %d) from store %p", res.data, res.size, sto); |
497 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return error); | 497 CHECK_POSIX_DO( pthread_rwlock_unlock(&sto->lock), return error); |
498 return res; | 498 return res; |
499 } | 499 } |
500 | 500 |
501 /* Set the session pointer in a session object */ | 501 /* Set the session pointer in a session object */ |
502 static void set_resume_callbacks(gnutls_session_t session, struct cnxctx * conn) | 502 static void set_resume_callbacks(gnutls_session_t session, struct cnxctx * conn) |
503 { | 503 { |
504 TRACE_ENTRY("%p", conn); | 504 TRACE_ENTRY("%p", conn); |
505 | 505 |
506 GNUTLS_TRACE( gnutls_db_set_retrieve_function(session, sr_fetch)); | 506 GNUTLS_TRACE( gnutls_db_set_retrieve_function(session, sr_fetch)); |
507 GNUTLS_TRACE( gnutls_db_set_remove_function (session, sr_remove)); | 507 GNUTLS_TRACE( gnutls_db_set_remove_function (session, sr_remove)); |
508 GNUTLS_TRACE( gnutls_db_set_store_function (session, sr_store)); | 508 GNUTLS_TRACE( gnutls_db_set_store_function (session, sr_store)); |
509 GNUTLS_TRACE( gnutls_db_set_ptr (session, conn->cc_sctp3436_data.sess_store)); | 509 GNUTLS_TRACE( gnutls_db_set_ptr (session, conn->cc_sctp3436_data.sess_store)); |
510 | 510 |
511 return; | 511 return; |
512 } | 512 } |
513 | 513 |
514 /* The handshake is made in parallel in several threads to speed up */ | 514 /* The handshake is made in parallel in several threads to speed up */ |
515 static void * handshake_resume_th(void * arg) | 515 static void * handshake_resume_th(void * arg) |
516 { | 516 { |
517 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) arg; | 517 struct sctp3436_ctx * ctx = (struct sctp3436_ctx *) arg; |
518 int resumed; | 518 int resumed; |
519 | 519 |
520 TRACE_ENTRY("%p", arg); | 520 TRACE_ENTRY("%p", arg); |
521 | 521 |
522 /* Set the thread name */ | 522 /* Set the thread name */ |
523 { | 523 { |
524 char buf[48]; | 524 char buf[48]; |
525 snprintf(buf, sizeof(buf), "Handshake resume (%hu@%d)", ctx->strid, ctx->parent->cc_socket); | 525 snprintf(buf, sizeof(buf), "Handshake resume (%hu@%d)", ctx->strid, ctx->parent->cc_socket); |
526 fd_log_threadname ( buf ); | 526 fd_log_threadname ( buf ); |
527 } | 527 } |
528 | 528 |
529 TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid); | 529 TRACE_DEBUG(FULL, "Starting TLS resumed handshake on stream %hu", ctx->strid); |
530 | 530 |
531 CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL); | 531 CHECK_GNUTLS_DO( gnutls_handshake( ctx->session ), return NULL); |
532 | 532 |
533 GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) ); | 533 GNUTLS_TRACE( resumed = gnutls_session_is_resumed(ctx->session) ); |
534 #ifndef GNUTLS_VERSION_300 | 534 #ifndef GNUTLS_VERSION_300 |
535 if (!resumed) { | 535 if (!resumed) { |
536 /* Check the credentials here also */ | 536 /* Check the credentials here also */ |
537 CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent, 0), return NULL ); | 537 CHECK_FCT_DO( fd_tls_verify_credentials(ctx->session, ctx->parent, 0), return NULL ); |
542 fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent)); | 542 fd_log_debug("Session was resumed successfully on stream %hu (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent)); |
543 } else { | 543 } else { |
544 fd_log_debug("Session was NOT resumed on stream %hu (full handshake) (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent)); | 544 fd_log_debug("Session was NOT resumed on stream %hu (full handshake) (conn: '%s')", ctx->strid, fd_cnx_getid(ctx->parent)); |
545 } | 545 } |
546 } | 546 } |
547 | 547 |
548 /* Finished, OK */ | 548 /* Finished, OK */ |
549 return arg; | 549 return arg; |
550 } | 550 } |
551 | 551 |
552 | 552 |
556 | 556 |
557 /* Initialize the wrapper for the connection */ | 557 /* Initialize the wrapper for the connection */ |
558 int fd_sctp3436_init(struct cnxctx * conn) | 558 int fd_sctp3436_init(struct cnxctx * conn) |
559 { | 559 { |
560 uint16_t i; | 560 uint16_t i; |
561 | 561 |
562 TRACE_ENTRY("%p", conn); | 562 TRACE_ENTRY("%p", conn); |
563 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && (!conn->cc_sctp3436_data.array) ); | 563 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && (!conn->cc_sctp3436_data.array) ); |
564 | 564 |
565 /* First, alloc the array and initialize the non-TLS data */ | 565 /* First, alloc the array and initialize the non-TLS data */ |
566 CHECK_MALLOC( conn->cc_sctp3436_data.array = calloc(conn->cc_sctp_para.pairs, sizeof(struct sctp3436_ctx)) ); | 566 CHECK_MALLOC( conn->cc_sctp3436_data.array = calloc(conn->cc_sctp_para.pairs, sizeof(struct sctp3436_ctx)) ); |
567 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { | 567 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { |
568 conn->cc_sctp3436_data.array[i].parent = conn; | 568 conn->cc_sctp3436_data.array[i].parent = conn; |
569 conn->cc_sctp3436_data.array[i].strid = i; | 569 conn->cc_sctp3436_data.array[i].strid = i; |
570 CHECK_FCT( fd_fifo_new(&conn->cc_sctp3436_data.array[i].raw_recv, 10) ); | 570 CHECK_FCT( fd_fifo_new(&conn->cc_sctp3436_data.array[i].raw_recv, 10) ); |
571 } | 571 } |
572 | 572 |
573 /* Set push/pull functions in the master session, using fifo in array[0] */ | 573 /* Set push/pull functions in the master session, using fifo in array[0] */ |
574 set_sess_transport(conn->cc_tls_para.session, &conn->cc_sctp3436_data.array[0]); | 574 set_sess_transport(conn->cc_tls_para.session, &conn->cc_sctp3436_data.array[0]); |
575 | 575 |
576 /* For server side, we also initialize the resuming capabilities */ | 576 /* For server side, we also initialize the resuming capabilities */ |
577 if (conn->cc_tls_para.mode == GNUTLS_SERVER) { | 577 if (conn->cc_tls_para.mode == GNUTLS_SERVER) { |
578 | 578 |
579 /* Prepare the store for sessions data */ | 579 /* Prepare the store for sessions data */ |
580 CHECK_FCT( store_init(conn) ); | 580 CHECK_FCT( store_init(conn) ); |
581 | 581 |
582 /* Set the callbacks for resuming in the master session */ | 582 /* Set the callbacks for resuming in the master session */ |
583 set_resume_callbacks(conn->cc_tls_para.session, conn); | 583 set_resume_callbacks(conn->cc_tls_para.session, conn); |
584 } | 584 } |
585 | 585 |
586 /* Start the demux thread */ | 586 /* Start the demux thread */ |
587 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, demuxer, conn ) ); | 587 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, demuxer, conn ) ); |
588 | 588 |
589 return 0; | 589 return 0; |
590 } | 590 } |
591 | 591 |
592 /* Handshake other streams, after full handshake on the master session */ | 592 /* Handshake other streams, after full handshake on the master session */ |
593 int fd_sctp3436_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds) | 593 int fd_sctp3436_handshake_others(struct cnxctx * conn, char * priority, void * alt_creds) |
594 { | 594 { |
595 uint16_t i; | 595 uint16_t i; |
596 int errors = 0; | 596 int errors = 0; |
597 gnutls_datum_t master_data; | 597 gnutls_datum_t master_data; |
598 | 598 |
599 TRACE_ENTRY("%p %p", conn, priority); | 599 TRACE_ENTRY("%p %p", conn, priority); |
600 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && conn->cc_sctp3436_data.array ); | 600 CHECK_PARAMS( conn && (conn->cc_sctp_para.pairs > 1) && conn->cc_sctp3436_data.array ); |
601 | 601 |
602 /* Server side: we set all the parameters, the resume callback will take care of resuming the session */ | 602 /* Server side: we set all the parameters, the resume callback will take care of resuming the session */ |
603 /* Client side: we duplicate the parameters of the master session, then set the transport pointer */ | 603 /* Client side: we duplicate the parameters of the master session, then set the transport pointer */ |
604 | 604 |
605 /* For client side, retrieve the master session parameters */ | 605 /* For client side, retrieve the master session parameters */ |
606 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { | 606 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { |
607 CHECK_GNUTLS_DO( gnutls_session_get_data2(conn->cc_tls_para.session, &master_data), return ENOMEM ); | 607 CHECK_GNUTLS_DO( gnutls_session_get_data2(conn->cc_tls_para.session, &master_data), return ENOMEM ); |
608 /* For debug: */ | 608 /* For debug: */ |
609 if (TRACE_BOOL(GNUTLS_DBG_LEVEL)) { | 609 if (TRACE_BOOL(GNUTLS_DBG_LEVEL)) { |
611 size_t ids = sizeof(id); | 611 size_t ids = sizeof(id); |
612 CHECK_GNUTLS_DO( gnutls_session_get_id(conn->cc_tls_para.session, id, &ids), /* continue */ ); | 612 CHECK_GNUTLS_DO( gnutls_session_get_id(conn->cc_tls_para.session, id, &ids), /* continue */ ); |
613 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Master session id: [", id, ids, "]"); | 613 TRACE_BUFFER(FD_LOG_DEBUG, GNUTLS_DBG_LEVEL, "Master session id: [", id, ids, "]"); |
614 } | 614 } |
615 } | 615 } |
616 | 616 |
617 /* Initialize the session objects and start the handshake in a separate thread */ | 617 /* Initialize the session objects and start the handshake in a separate thread */ |
618 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { | 618 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { |
619 /* Set credentials and priority */ | 619 /* Set credentials and priority */ |
620 CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, 0, priority, alt_creds) ); | 620 CHECK_FCT( fd_tls_prepare(&conn->cc_sctp3436_data.array[i].session, conn->cc_tls_para.mode, 0, priority, alt_creds) ); |
621 | 621 |
622 /* additional initialization for gnutls 3.x */ | 622 /* additional initialization for gnutls 3.x */ |
623 #ifdef GNUTLS_VERSION_300 | 623 #ifdef GNUTLS_VERSION_300 |
624 /* the verify function has already been set in the global initialization in config.c */ | 624 /* the verify function has already been set in the global initialization in config.c */ |
625 | 625 |
626 /* fd_tls_verify_credentials_2 uses the connection */ | 626 /* fd_tls_verify_credentials_2 uses the connection */ |
641 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { | 641 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { |
642 CHECK_GNUTLS_DO( gnutls_session_set_data(conn->cc_sctp3436_data.array[i].session, master_data.data, master_data.size), return ENOMEM ); | 642 CHECK_GNUTLS_DO( gnutls_session_set_data(conn->cc_sctp3436_data.array[i].session, master_data.data, master_data.size), return ENOMEM ); |
643 } else { | 643 } else { |
644 set_resume_callbacks(conn->cc_sctp3436_data.array[i].session, conn); | 644 set_resume_callbacks(conn->cc_sctp3436_data.array[i].session, conn); |
645 } | 645 } |
646 | 646 |
647 /* Set transport parameters */ | 647 /* Set transport parameters */ |
648 set_sess_transport(conn->cc_sctp3436_data.array[i].session, &conn->cc_sctp3436_data.array[i]); | 648 set_sess_transport(conn->cc_sctp3436_data.array[i].session, &conn->cc_sctp3436_data.array[i]); |
649 | 649 |
650 /* Start the handshake thread */ | 650 /* Start the handshake thread */ |
651 CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, handshake_resume_th, &conn->cc_sctp3436_data.array[i] ) ); | 651 CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, handshake_resume_th, &conn->cc_sctp3436_data.array[i] ) ); |
652 } | 652 } |
653 | 653 |
654 /* We can now release the memory of master session data if any */ | 654 /* We can now release the memory of master session data if any */ |
655 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { | 655 if (conn->cc_tls_para.mode == GNUTLS_CLIENT) { |
656 GNUTLS_TRACE( gnutls_free(master_data.data) ); | 656 GNUTLS_TRACE( gnutls_free(master_data.data) ); |
657 } | 657 } |
658 | 658 |
659 /* Now wait for all handshakes to finish */ | 659 /* Now wait for all handshakes to finish */ |
660 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { | 660 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { |
661 void * ret; | 661 void * ret; |
662 CHECK_POSIX( pthread_join(conn->cc_sctp3436_data.array[i].thr, &ret) ); | 662 CHECK_POSIX( pthread_join(conn->cc_sctp3436_data.array[i].thr, &ret) ); |
663 conn->cc_sctp3436_data.array[i].thr = (pthread_t) NULL; | 663 conn->cc_sctp3436_data.array[i].thr = (pthread_t) NULL; |
664 if (ret == NULL) { | 664 if (ret == NULL) { |
665 errors++; /* Handshake failed on this stream */ | 665 errors++; /* Handshake failed on this stream */ |
666 } | 666 } |
667 } | 667 } |
668 | 668 |
669 if (errors) { | 669 if (errors) { |
670 TRACE_DEBUG(INFO, "Handshake failed on %d/%hd stream pairs", errors, conn->cc_sctp_para.pairs); | 670 TRACE_DEBUG(INFO, "Handshake failed on %d/%hd stream pairs", errors, conn->cc_sctp_para.pairs); |
671 fd_cnx_markerror(conn); | 671 fd_cnx_markerror(conn); |
672 return ENOTCONN; | 672 return ENOTCONN; |
673 } | 673 } |
674 | 674 |
675 return 0; | 675 return 0; |
676 } | 676 } |
677 | 677 |
678 /* Receive messages from others ? all other stream pairs : the master pair */ | 678 /* Receive messages from others ? all other stream pairs : the master pair */ |
679 int fd_sctp3436_startthreads(struct cnxctx * conn, int others) | 679 int fd_sctp3436_startthreads(struct cnxctx * conn, int others) |
680 { | 680 { |
681 uint16_t i; | 681 uint16_t i; |
682 | 682 |
683 TRACE_ENTRY("%p", conn); | 683 TRACE_ENTRY("%p", conn); |
684 CHECK_PARAMS( conn && conn->cc_sctp3436_data.array ); | 684 CHECK_PARAMS( conn && conn->cc_sctp3436_data.array ); |
685 | 685 |
686 if (others) { | 686 if (others) { |
687 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { | 687 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { |
688 | 688 |
689 /* Start the decipher thread */ | 689 /* Start the decipher thread */ |
690 CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, decipher, &conn->cc_sctp3436_data.array[i] ) ); | 690 CHECK_POSIX( pthread_create( &conn->cc_sctp3436_data.array[i].thr, NULL, decipher, &conn->cc_sctp3436_data.array[i] ) ); |
697 | 697 |
698 /* Initiate a "bye" on all stream pairs */ | 698 /* Initiate a "bye" on all stream pairs */ |
699 void fd_sctp3436_bye(struct cnxctx * conn) | 699 void fd_sctp3436_bye(struct cnxctx * conn) |
700 { | 700 { |
701 uint16_t i; | 701 uint16_t i; |
702 | 702 |
703 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); | 703 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); |
704 | 704 |
705 /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */ | 705 /* End all TLS sessions, in series (not as efficient as paralel, but simpler) */ |
706 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { | 706 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { |
707 if ( ! fd_cnx_teststate(conn, CC_STATUS_ERROR)) { | 707 if ( ! fd_cnx_teststate(conn, CC_STATUS_ERROR)) { |
708 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctp3436_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); | 708 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_sctp3436_data.array[i].session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) ); |
709 } | 709 } |
712 | 712 |
713 /* After "bye" was sent on all streams, read from sessions until an error is received */ | 713 /* After "bye" was sent on all streams, read from sessions until an error is received */ |
714 void fd_sctp3436_waitthreadsterm(struct cnxctx * conn) | 714 void fd_sctp3436_waitthreadsterm(struct cnxctx * conn) |
715 { | 715 { |
716 uint16_t i; | 716 uint16_t i; |
717 | 717 |
718 TRACE_ENTRY("%p", conn); | 718 TRACE_ENTRY("%p", conn); |
719 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); | 719 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); |
720 | 720 |
721 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { | 721 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { |
722 if (conn->cc_sctp3436_data.array[i].thr != (pthread_t)NULL) { | 722 if (conn->cc_sctp3436_data.array[i].thr != (pthread_t)NULL) { |
723 CHECK_POSIX_DO( pthread_join(conn->cc_sctp3436_data.array[i].thr, NULL), /* continue */ ); | 723 CHECK_POSIX_DO( pthread_join(conn->cc_sctp3436_data.array[i].thr, NULL), /* continue */ ); |
724 conn->cc_sctp3436_data.array[i].thr = (pthread_t)NULL; | 724 conn->cc_sctp3436_data.array[i].thr = (pthread_t)NULL; |
725 } | 725 } |
729 | 729 |
730 /* Free gnutls resources of all sessions */ | 730 /* Free gnutls resources of all sessions */ |
731 void fd_sctp3436_gnutls_deinit_others(struct cnxctx * conn) | 731 void fd_sctp3436_gnutls_deinit_others(struct cnxctx * conn) |
732 { | 732 { |
733 uint16_t i; | 733 uint16_t i; |
734 | 734 |
735 TRACE_ENTRY("%p", conn); | 735 TRACE_ENTRY("%p", conn); |
736 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); | 736 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); |
737 | 737 |
738 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { | 738 for (i = 1; i < conn->cc_sctp_para.pairs; i++) { |
739 if (conn->cc_sctp3436_data.array[i].session) { | 739 if (conn->cc_sctp3436_data.array[i].session) { |
740 GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) ); | 740 GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) ); |
741 conn->cc_sctp3436_data.array[i].session = NULL; | 741 conn->cc_sctp3436_data.array[i].session = NULL; |
742 } | 742 } |
746 | 746 |
747 /* Stop all receiver threads */ | 747 /* Stop all receiver threads */ |
748 void fd_sctp3436_stopthreads(struct cnxctx * conn) | 748 void fd_sctp3436_stopthreads(struct cnxctx * conn) |
749 { | 749 { |
750 uint16_t i; | 750 uint16_t i; |
751 | 751 |
752 TRACE_ENTRY("%p", conn); | 752 TRACE_ENTRY("%p", conn); |
753 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); | 753 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); |
754 | 754 |
755 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { | 755 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { |
756 CHECK_FCT_DO( fd_thr_term(&conn->cc_sctp3436_data.array[i].thr), /* continue */ ); | 756 CHECK_FCT_DO( fd_thr_term(&conn->cc_sctp3436_data.array[i].thr), /* continue */ ); |
757 } | 757 } |
758 return; | 758 return; |
759 } | 759 } |
760 | 760 |
761 /* Destroy a wrapper context */ | 761 /* Destroy a wrapper context */ |
762 void fd_sctp3436_destroy(struct cnxctx * conn) | 762 void fd_sctp3436_destroy(struct cnxctx * conn) |
763 { | 763 { |
764 uint16_t i; | 764 uint16_t i; |
765 | 765 |
766 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); | 766 CHECK_PARAMS_DO( conn && conn->cc_sctp3436_data.array, return ); |
767 | 767 |
768 /* Terminate all receiving threads in case we did not do it yet */ | 768 /* Terminate all receiving threads in case we did not do it yet */ |
769 fd_sctp3436_stopthreads(conn); | 769 fd_sctp3436_stopthreads(conn); |
770 | 770 |
771 /* Now, stop the demux thread */ | 771 /* Now, stop the demux thread */ |
772 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); | 772 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); |
773 | 773 |
774 /* Free remaining data in the array */ | 774 /* Free remaining data in the array */ |
775 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { | 775 for (i = 0; i < conn->cc_sctp_para.pairs; i++) { |
776 if (conn->cc_sctp3436_data.array[i].raw_recv) | 776 if (conn->cc_sctp3436_data.array[i].raw_recv) |
777 fd_event_destroy( &conn->cc_sctp3436_data.array[i].raw_recv, free ); | 777 fd_event_destroy( &conn->cc_sctp3436_data.array[i].raw_recv, free ); |
778 free(conn->cc_sctp3436_data.array[i].partial.buf); | 778 free(conn->cc_sctp3436_data.array[i].partial.buf); |
779 if (conn->cc_sctp3436_data.array[i].session) { | 779 if (conn->cc_sctp3436_data.array[i].session) { |
780 GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) ); | 780 GNUTLS_TRACE( gnutls_deinit(conn->cc_sctp3436_data.array[i].session) ); |
781 conn->cc_sctp3436_data.array[i].session = NULL; | 781 conn->cc_sctp3436_data.array[i].session = NULL; |
782 } | 782 } |
783 } | 783 } |
784 | 784 |
785 /* Free the array itself now */ | 785 /* Free the array itself now */ |
786 free(conn->cc_sctp3436_data.array); | 786 free(conn->cc_sctp3436_data.array); |
787 conn->cc_sctp3436_data.array = NULL; | 787 conn->cc_sctp3436_data.array = NULL; |
788 | 788 |
789 /* Delete the store of sessions */ | 789 /* Delete the store of sessions */ |
790 store_destroy(conn); | 790 store_destroy(conn); |
791 | 791 |
792 return ; | 792 return ; |
793 } | 793 } |