Mercurial > hg > freeDiameter
comparison libfdcore/cnxctx.c @ 1419:89cbb08d3189
Remove trailing whitespace.
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Tue, 18 Feb 2020 11:38:37 +0100 |
parents | b68fb21c2f72 |
children | 407e0a889c7e |
comparison
equal
deleted
inserted
replaced
1418:a51f71694121 | 1419:89cbb08d3189 |
---|---|
174 if (fd_g_config->cnf_flags.no_ip6) { | 174 if (fd_g_config->cnf_flags.no_ip6) { |
175 cnx->cc_family = AF_INET; | 175 cnx->cc_family = AF_INET; |
176 } else { | 176 } else { |
177 cnx->cc_family = AF_INET6; /* can create socket for both IP and IPv6 */ | 177 cnx->cc_family = AF_INET6; /* can create socket for both IP and IPv6 */ |
178 } | 178 } |
179 | 179 |
180 /* Create the socket */ | 180 /* Create the socket */ |
181 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, cnx->cc_family, ep_list, port ), goto error ); | 181 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, cnx->cc_family, ep_list, port ), goto error ); |
182 | 182 |
183 /* Generate the name for the connection object */ | 183 /* Generate the name for the connection object */ |
184 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP srv :%hu (%d)", port, cnx->cc_socket); | 184 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP srv :%hu (%d)", port, cnx->cc_socket); |
224 socklen_t ss_len = sizeof(ss); | 224 socklen_t ss_len = sizeof(ss); |
225 int cli_sock = 0; | 225 int cli_sock = 0; |
226 | 226 |
227 TRACE_ENTRY("%p", serv); | 227 TRACE_ENTRY("%p", serv); |
228 CHECK_PARAMS_DO(serv, return NULL); | 228 CHECK_PARAMS_DO(serv, return NULL); |
229 | 229 |
230 /* Accept the new connection -- this is blocking until new client enters or until cancellation */ | 230 /* Accept the new connection -- this is blocking until new client enters or until cancellation */ |
231 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); | 231 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); |
232 | 232 |
233 CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } ); | 233 CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } ); |
234 cli->cc_socket = cli_sock; | 234 cli->cc_socket = cli_sock; |
235 cli->cc_family = serv->cc_family; | 235 cli->cc_family = serv->cc_family; |
236 cli->cc_proto = serv->cc_proto; | 236 cli->cc_proto = serv->cc_proto; |
237 | 237 |
238 /* Set the timeout */ | 238 /* Set the timeout */ |
239 fd_cnx_s_setto(cli->cc_socket); | 239 fd_cnx_s_setto(cli->cc_socket); |
240 | 240 |
241 /* Generate the name for the connection object */ | 241 /* Generate the name for the connection object */ |
242 { | 242 { |
243 char addrbuf[INET6_ADDRSTRLEN]; | 243 char addrbuf[INET6_ADDRSTRLEN]; |
244 char portbuf[10]; | 244 char portbuf[10]; |
245 int rc; | 245 int rc; |
246 | 246 |
247 rc = getnameinfo((sSA *)&ss, ss_len, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); | 247 rc = getnameinfo((sSA *)&ss, ss_len, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); |
248 if (rc) { | 248 if (rc) { |
249 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); | 249 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); |
250 portbuf[0] = '\0'; | 250 portbuf[0] = '\0'; |
251 } | 251 } |
252 | 252 |
253 /* Numeric values for debug... */ | 253 /* Numeric values for debug... */ |
254 snprintf(cli->cc_id, sizeof(cli->cc_id), CC_ID_HDR "%s from [%s]:%s (%d<-%d)", | 254 snprintf(cli->cc_id, sizeof(cli->cc_id), CC_ID_HDR "%s from [%s]:%s (%d<-%d)", |
255 IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket); | 255 IPPROTO_NAME(cli->cc_proto), addrbuf, portbuf, serv->cc_socket, cli->cc_socket); |
256 | 256 |
257 | 257 |
258 /* ...Name for log messages */ | 258 /* ...Name for log messages */ |
259 rc = getnameinfo((sSA *)&ss, ss_len, cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); | 259 rc = getnameinfo((sSA *)&ss, ss_len, cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); |
260 if (rc) | 260 if (rc) |
261 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); | 261 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); |
262 } | 262 } |
263 | 263 |
264 LOG_D("Incoming connection: '%s' <- '%s' {%s}", fd_cnx_getid(serv), cli->cc_remid, cli->cc_id); | 264 LOG_D("Incoming connection: '%s' <- '%s' {%s}", fd_cnx_getid(serv), cli->cc_remid, cli->cc_id); |
265 | 265 |
266 #ifndef DISABLE_SCTP | 266 #ifndef DISABLE_SCTP |
267 /* SCTP-specific handlings */ | 267 /* SCTP-specific handlings */ |
268 if (cli->cc_proto == IPPROTO_SCTP) { | 268 if (cli->cc_proto == IPPROTO_SCTP) { |
270 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), {fd_cnx_destroy(cli); return NULL;} ); | 270 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), {fd_cnx_destroy(cli); return NULL;} ); |
271 if (cli->cc_sctp_para.str_out < cli->cc_sctp_para.str_in) | 271 if (cli->cc_sctp_para.str_out < cli->cc_sctp_para.str_in) |
272 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; | 272 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; |
273 else | 273 else |
274 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in; | 274 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in; |
275 | 275 |
276 LOG_A( "%s : client '%s' (SCTP:%d, %d/%d streams)", fd_cnx_getid(serv), fd_cnx_getid(cli), cli->cc_socket, cli->cc_sctp_para.str_in, cli->cc_sctp_para.str_out); | 276 LOG_A( "%s : client '%s' (SCTP:%d, %d/%d streams)", fd_cnx_getid(serv), fd_cnx_getid(cli), cli->cc_socket, cli->cc_sctp_para.str_in, cli->cc_sctp_para.str_out); |
277 } | 277 } |
278 #endif /* DISABLE_SCTP */ | 278 #endif /* DISABLE_SCTP */ |
279 | 279 |
280 return cli; | 280 return cli; |
284 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen) | 284 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen) |
285 { | 285 { |
286 int sock = 0; | 286 int sock = 0; |
287 struct cnxctx * cnx = NULL; | 287 struct cnxctx * cnx = NULL; |
288 char sa_buf[sSA_DUMP_STRLEN]; | 288 char sa_buf[sSA_DUMP_STRLEN]; |
289 | 289 |
290 TRACE_ENTRY("%p %d", sa, addrlen); | 290 TRACE_ENTRY("%p %d", sa, addrlen); |
291 CHECK_PARAMS_DO( sa && addrlen, return NULL ); | 291 CHECK_PARAMS_DO( sa && addrlen, return NULL ); |
292 | 292 |
293 fd_sa_sdump_numeric(sa_buf, sa); | 293 fd_sa_sdump_numeric(sa_buf, sa); |
294 | 294 |
295 LOG_D("Connecting to TCP %s...", sa_buf); | 295 LOG_D("Connecting to TCP %s...", sa_buf); |
296 | 296 |
297 /* Create the socket and connect, which can take some time and/or fail */ | 297 /* Create the socket and connect, which can take some time and/or fail */ |
298 { | 298 { |
299 int ret = fd_tcp_client( &sock, sa, addrlen ); | 299 int ret = fd_tcp_client( &sock, sa, addrlen ); |
300 if (ret != 0) { | 300 if (ret != 0) { |
301 LOG_D("TCP connection to %s failed: %s", sa_buf, strerror(ret)); | 301 LOG_D("TCP connection to %s failed: %s", sa_buf, strerror(ret)); |
302 return NULL; | 302 return NULL; |
303 } | 303 } |
304 } | 304 } |
305 | 305 |
306 /* Once the socket is created successfuly, prepare the remaining of the cnx */ | 306 /* Once the socket is created successfuly, prepare the remaining of the cnx */ |
307 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } ); | 307 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } ); |
308 | 308 |
309 cnx->cc_socket = sock; | 309 cnx->cc_socket = sock; |
310 cnx->cc_family = sa->sa_family; | 310 cnx->cc_family = sa->sa_family; |
311 cnx->cc_proto = IPPROTO_TCP; | 311 cnx->cc_proto = IPPROTO_TCP; |
312 | 312 |
313 /* Set the timeout */ | 313 /* Set the timeout */ |
314 fd_cnx_s_setto(cnx->cc_socket); | 314 fd_cnx_s_setto(cnx->cc_socket); |
315 | 315 |
316 /* Generate the names for the object */ | 316 /* Generate the names for the object */ |
317 { | 317 { |
318 int rc; | 318 int rc; |
319 | 319 |
320 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP,#%d->%s", cnx->cc_socket, sa_buf); | 320 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "TCP,#%d->%s", cnx->cc_socket, sa_buf); |
321 | 321 |
322 /* ...Name for log messages */ | 322 /* ...Name for log messages */ |
323 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); | 323 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); |
324 if (rc) | 324 if (rc) |
325 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); | 325 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); |
326 } | 326 } |
327 | 327 |
328 LOG_A("TCP connection to %s succeed (socket:%d).", sa_buf, sock); | 328 LOG_A("TCP connection to %s succeed (socket:%d).", sa_buf, sock); |
329 | 329 |
330 return cnx; | 330 return cnx; |
331 } | 331 } |
332 | 332 |
333 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */ | 333 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */ |
334 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list) | 334 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list) |
341 #else /* DISABLE_SCTP */ | 341 #else /* DISABLE_SCTP */ |
342 int sock = 0; | 342 int sock = 0; |
343 struct cnxctx * cnx = NULL; | 343 struct cnxctx * cnx = NULL; |
344 char sa_buf[sSA_DUMP_STRLEN]; | 344 char sa_buf[sSA_DUMP_STRLEN]; |
345 sSS primary; | 345 sSS primary; |
346 | 346 |
347 TRACE_ENTRY("%p", list); | 347 TRACE_ENTRY("%p", list); |
348 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL ); | 348 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL ); |
349 | 349 |
350 fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa); | 350 fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa); |
351 | 351 |
352 LOG_D("Connecting to SCTP %s:%hu...", sa_buf, port); | 352 LOG_D("Connecting to SCTP %s:%hu...", sa_buf, port); |
353 | 353 |
354 { | 354 { |
355 int ret = fd_sctp_client( &sock, no_ip6, port, list ); | 355 int ret = fd_sctp_client( &sock, no_ip6, port, list ); |
356 if (ret != 0) { | 356 if (ret != 0) { |
357 LOG_D("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret)); | 357 LOG_D("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret)); |
358 return NULL; | 358 return NULL; |
359 } | 359 } |
360 } | 360 } |
361 | 361 |
362 /* Once the socket is created successfuly, prepare the remaining of the cnx */ | 362 /* Once the socket is created successfuly, prepare the remaining of the cnx */ |
363 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } ); | 363 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } ); |
364 | 364 |
365 cnx->cc_socket = sock; | 365 cnx->cc_socket = sock; |
366 cnx->cc_family = no_ip6 ? AF_INET : AF_INET6; | 366 cnx->cc_family = no_ip6 ? AF_INET : AF_INET6; |
367 cnx->cc_proto = IPPROTO_SCTP; | 367 cnx->cc_proto = IPPROTO_SCTP; |
368 | 368 |
369 /* Set the timeout */ | 369 /* Set the timeout */ |
370 fd_cnx_s_setto(cnx->cc_socket); | 370 fd_cnx_s_setto(cnx->cc_socket); |
371 | 371 |
372 /* Retrieve the number of streams and primary address */ | 372 /* Retrieve the number of streams and primary address */ |
373 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error ); | 373 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error ); |
374 if (cnx->cc_sctp_para.str_out < cnx->cc_sctp_para.str_in) | 374 if (cnx->cc_sctp_para.str_out < cnx->cc_sctp_para.str_in) |
375 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out; | 375 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out; |
376 else | 376 else |
377 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in; | 377 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in; |
378 | 378 |
379 fd_sa_sdump_numeric(sa_buf, (sSA *)&primary); | 379 fd_sa_sdump_numeric(sa_buf, (sSA *)&primary); |
380 | 380 |
381 /* Generate the names for the object */ | 381 /* Generate the names for the object */ |
382 { | 382 { |
383 int rc; | 383 int rc; |
384 | 384 |
385 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP,#%d->%s", cnx->cc_socket, sa_buf); | 385 snprintf(cnx->cc_id, sizeof(cnx->cc_id), CC_ID_HDR "SCTP,#%d->%s", cnx->cc_socket, sa_buf); |
386 | 386 |
387 /* ...Name for log messages */ | 387 /* ...Name for log messages */ |
388 rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); | 388 rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); |
389 if (rc) | 389 if (rc) |
390 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); | 390 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); |
391 } | 391 } |
392 | 392 |
393 LOG_A("SCTP connection to %s succeed (socket:%d, %d/%d streams).", sa_buf, sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out); | 393 LOG_A("SCTP connection to %s succeed (socket:%d, %d/%d streams).", sa_buf, sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out); |
394 | 394 |
395 return cnx; | 395 return cnx; |
396 | 396 |
397 error: | 397 error: |
398 fd_cnx_destroy(cnx); | 398 fd_cnx_destroy(cnx); |
399 return NULL; | 399 return NULL; |
442 void fd_cnx_update_id(struct cnxctx * conn) { | 442 void fd_cnx_update_id(struct cnxctx * conn) { |
443 if (conn->cc_state & CC_STATUS_CLOSING) | 443 if (conn->cc_state & CC_STATUS_CLOSING) |
444 conn->cc_id[1] = 'C'; | 444 conn->cc_id[1] = 'C'; |
445 else | 445 else |
446 conn->cc_id[1] = '-'; | 446 conn->cc_id[1] = '-'; |
447 | 447 |
448 if (conn->cc_state & CC_STATUS_ERROR) | 448 if (conn->cc_state & CC_STATUS_ERROR) |
449 conn->cc_id[2] = 'E'; | 449 conn->cc_id[2] = 'E'; |
450 else | 450 else |
451 conn->cc_id[2] = '-'; | 451 conn->cc_id[2] = '-'; |
452 | 452 |
453 if (conn->cc_state & CC_STATUS_SIGNALED) | 453 if (conn->cc_state & CC_STATUS_SIGNALED) |
454 conn->cc_id[3] = 'S'; | 454 conn->cc_id[3] = 'S'; |
455 else | 455 else |
456 conn->cc_id[3] = '-'; | 456 conn->cc_id[3] = '-'; |
457 | 457 |
458 if (conn->cc_state & CC_STATUS_TLS) | 458 if (conn->cc_state & CC_STATUS_TLS) |
459 conn->cc_id[4] = 'T'; | 459 conn->cc_id[4] = 'T'; |
460 else | 460 else |
461 conn->cc_id[4] = '-'; | 461 conn->cc_id[4] = '-'; |
462 } | 462 } |
506 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ | 506 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ |
507 int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps) | 507 int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps) |
508 { | 508 { |
509 TRACE_ENTRY("%p %p", conn, eps); | 509 TRACE_ENTRY("%p %p", conn, eps); |
510 CHECK_PARAMS(conn && eps); | 510 CHECK_PARAMS(conn && eps); |
511 | 511 |
512 /* Check we have a full connection object, not a listening socket (with no remote) */ | 512 /* Check we have a full connection object, not a listening socket (with no remote) */ |
513 CHECK_PARAMS( conn->cc_incoming ); | 513 CHECK_PARAMS( conn->cc_incoming ); |
514 | 514 |
515 /* Retrieve the peer endpoint(s) of the connection */ | 515 /* Retrieve the peer endpoint(s) of the connection */ |
516 switch (conn->cc_proto) { | 516 switch (conn->cc_proto) { |
544 } | 544 } |
545 | 545 |
546 static int fd_cnx_may_dtls(struct cnxctx * conn); | 546 static int fd_cnx_may_dtls(struct cnxctx * conn); |
547 | 547 |
548 /* Get a short string representing the connection */ | 548 /* Get a short string representing the connection */ |
549 int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len) | 549 int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len) |
550 { | 550 { |
551 CHECK_PARAMS( conn ); | 551 CHECK_PARAMS( conn ); |
552 | 552 |
553 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { | 553 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { |
554 snprintf(buf, len, "%s,%s,soc#%d", IPPROTO_NAME(conn->cc_proto), fd_cnx_may_dtls(conn) ? "DTLS" : "TLS", conn->cc_socket); | 554 snprintf(buf, len, "%s,%s,soc#%d", IPPROTO_NAME(conn->cc_proto), fd_cnx_may_dtls(conn) ? "DTLS" : "TLS", conn->cc_socket); |
555 } else { | 555 } else { |
556 snprintf(buf, len, "%s,soc#%d", IPPROTO_NAME(conn->cc_proto), conn->cc_socket); | 556 snprintf(buf, len, "%s,soc#%d", IPPROTO_NAME(conn->cc_proto), conn->cc_socket); |
557 } | 557 } |
558 | 558 |
559 return 0; | 559 return 0; |
560 } | 560 } |
561 | 561 |
562 /* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */ | 562 /* Retrieve a list of all IP addresses of the local system from the kernel, using getifaddrs */ |
563 int fd_cnx_get_local_eps(struct fd_list * list) | 563 int fd_cnx_get_local_eps(struct fd_list * list) |
564 { | 564 { |
565 struct ifaddrs *iflist, *cur; | 565 struct ifaddrs *iflist, *cur; |
566 | 566 |
567 CHECK_SYS(getifaddrs(&iflist)); | 567 CHECK_SYS(getifaddrs(&iflist)); |
568 | 568 |
569 for (cur = iflist; cur != NULL; cur = cur->ifa_next) { | 569 for (cur = iflist; cur != NULL; cur = cur->ifa_next) { |
570 if (cur->ifa_flags & IFF_LOOPBACK) | 570 if (cur->ifa_flags & IFF_LOOPBACK) |
571 continue; | 571 continue; |
572 | 572 |
573 if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */ | 573 if (cur->ifa_addr == NULL) /* may happen with ppp interfaces */ |
574 continue; | 574 continue; |
575 | 575 |
576 if (fd_g_config->cnf_flags.no_ip4 && (cur->ifa_addr->sa_family == AF_INET)) | 576 if (fd_g_config->cnf_flags.no_ip4 && (cur->ifa_addr->sa_family == AF_INET)) |
577 continue; | 577 continue; |
578 | 578 |
579 if (fd_g_config->cnf_flags.no_ip6 && (cur->ifa_addr->sa_family == AF_INET6)) | 579 if (fd_g_config->cnf_flags.no_ip6 && (cur->ifa_addr->sa_family == AF_INET6)) |
580 continue; | 580 continue; |
581 | 581 |
582 CHECK_FCT(fd_ep_add_merge( list, cur->ifa_addr, sSAlen(cur->ifa_addr), EP_FL_LL )); | 582 CHECK_FCT(fd_ep_add_merge( list, cur->ifa_addr, sSAlen(cur->ifa_addr), EP_FL_LL )); |
583 } | 583 } |
584 | 584 |
585 freeifaddrs(iflist); | 585 freeifaddrs(iflist); |
586 | 586 |
587 return 0; | 587 return 0; |
588 } | 588 } |
589 | 589 |
590 | 590 |
591 /**************************************/ | 591 /**************************************/ |
595 /* An error occurred on the socket */ | 595 /* An error occurred on the socket */ |
596 void fd_cnx_markerror(struct cnxctx * conn) | 596 void fd_cnx_markerror(struct cnxctx * conn) |
597 { | 597 { |
598 TRACE_ENTRY("%p", conn); | 598 TRACE_ENTRY("%p", conn); |
599 CHECK_PARAMS_DO( conn, goto fatal ); | 599 CHECK_PARAMS_DO( conn, goto fatal ); |
600 | 600 |
601 TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid); | 601 TRACE_DEBUG(FULL, "Error flag set for socket %d (%s, %s)", conn->cc_socket, conn->cc_id, conn->cc_remid); |
602 | 602 |
603 /* Mark the error */ | 603 /* Mark the error */ |
604 fd_cnx_addstate(conn, CC_STATUS_ERROR); | 604 fd_cnx_addstate(conn, CC_STATUS_ERROR); |
605 | 605 |
606 /* Report the error if not reported yet, and not closing */ | 606 /* Report the error if not reported yet, and not closing */ |
607 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING | CC_STATUS_SIGNALED )) { | 607 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING | CC_STATUS_SIGNALED )) { |
608 TRACE_DEBUG(FULL, "Sending FDEVP_CNX_ERROR event"); | 608 TRACE_DEBUG(FULL, "Sending FDEVP_CNX_ERROR event"); |
609 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal); | 609 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal); |
610 fd_cnx_addstate(conn, CC_STATUS_SIGNALED); | 610 fd_cnx_addstate(conn, CC_STATUS_SIGNALED); |
611 } | 611 } |
612 | 612 |
613 return; | 613 return; |
614 fatal: | 614 fatal: |
615 /* An unrecoverable error occurred, stop the daemon */ | 615 /* An unrecoverable error occurred, stop the daemon */ |
616 ASSERT(0); | 616 ASSERT(0); |
617 CHECK_FCT_DO(fd_core_shutdown(), ); | 617 CHECK_FCT_DO(fd_core_shutdown(), ); |
618 } | 618 } |
619 | 619 |
620 /* Set the timeout option on the socket */ | 620 /* Set the timeout option on the socket */ |
621 void fd_cnx_s_setto(int sock) | 621 void fd_cnx_s_setto(int sock) |
622 { | 622 { |
623 struct timeval tv; | 623 struct timeval tv; |
624 | 624 |
625 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */ | 625 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */ |
626 memset(&tv, 0, sizeof(tv)); | 626 memset(&tv, 0, sizeof(tv)); |
627 tv.tv_usec = 100000L; /* 100ms, to react quickly to head-of-the-line blocking. */ | 627 tv.tv_usec = 100000L; /* 100ms, to react quickly to head-of-the-line blocking. */ |
628 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), ); | 628 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), ); |
629 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), ); | 629 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), ); |
634 /* The pull_timeout function for gnutls */ | 634 /* The pull_timeout function for gnutls */ |
635 static int fd_cnx_s_select (struct cnxctx * conn, unsigned int ms) | 635 static int fd_cnx_s_select (struct cnxctx * conn, unsigned int ms) |
636 { | 636 { |
637 fd_set rfds; | 637 fd_set rfds; |
638 struct timeval tv; | 638 struct timeval tv; |
639 | 639 |
640 FD_ZERO (&rfds); | 640 FD_ZERO (&rfds); |
641 FD_SET (conn->cc_socket, &rfds); | 641 FD_SET (conn->cc_socket, &rfds); |
642 | 642 |
643 tv.tv_sec = ms / 1000; | 643 tv.tv_sec = ms / 1000; |
644 tv.tv_usec = (ms * 1000) % 1000000; | 644 tv.tv_usec = (ms * 1000) % 1000000; |
645 | 645 |
646 return select (conn->cc_socket + 1, &rfds, NULL, NULL, &tv); | 646 return select (conn->cc_socket + 1, &rfds, NULL, NULL, &tv); |
647 } | 647 } |
648 #endif /* GNUTLS_VERSION_300 */ | 648 #endif /* GNUTLS_VERSION_300 */ |
649 | 649 |
650 /* A recv-like function, taking a cnxctx object instead of socket as entry. We use it to quickly react to timeouts without traversing GNUTLS wrapper each time */ | 650 /* A recv-like function, taking a cnxctx object instead of socket as entry. We use it to quickly react to timeouts without traversing GNUTLS wrapper each time */ |
651 ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length) | 651 ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length) |
652 { | 652 { |
662 if (!timedout) { | 662 if (!timedout) { |
663 timedout ++; /* allow for one timeout while closing */ | 663 timedout ++; /* allow for one timeout while closing */ |
664 goto again; | 664 goto again; |
665 } | 665 } |
666 } | 666 } |
667 | 667 |
668 /* Mark the error */ | 668 /* Mark the error */ |
669 if (ret <= 0) { | 669 if (ret <= 0) { |
670 CHECK_SYS_DO(ret, /* continue, this is only used to log the error here */); | 670 CHECK_SYS_DO(ret, /* continue, this is only used to log the error here */); |
671 fd_cnx_markerror(conn); | 671 fd_cnx_markerror(conn); |
672 } | 672 } |
673 | 673 |
674 return ret; | 674 return ret; |
675 } | 675 } |
676 | 676 |
677 /* Send */ | 677 /* Send */ |
678 static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt) | 678 static ssize_t fd_cnx_s_sendv(struct cnxctx * conn, const struct iovec * iov, int iovcnt) |
684 ret = writev(conn->cc_socket, iov, iovcnt); | 684 ret = writev(conn->cc_socket, iov, iovcnt); |
685 /* Handle special case of timeout */ | 685 /* Handle special case of timeout */ |
686 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) { | 686 if ((ret < 0) && ((errno == EAGAIN) || (errno == EINTR))) { |
687 ret = -errno; | 687 ret = -errno; |
688 pthread_testcancel(); | 688 pthread_testcancel(); |
689 | 689 |
690 /* Check how much time we were blocked for this sending. */ | 690 /* Check how much time we were blocked for this sending. */ |
691 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 ); | 691 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &now), return -1 ); |
692 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) { | 692 if ( ((now.tv_sec - ts.tv_sec) * 1000 + ((now.tv_nsec - ts.tv_nsec) / 1000000L)) > MAX_HOTL_BLOCKING_TIME) { |
693 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME); | 693 LOG_D("Unable to send any data for %dms, closing the connection", MAX_HOTL_BLOCKING_TIME); |
694 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) { | 694 } else if (! fd_cnx_teststate(conn, CC_STATUS_CLOSING )) { |
695 goto again; /* don't care, just ignore */ | 695 goto again; /* don't care, just ignore */ |
696 } | 696 } |
697 | 697 |
698 /* propagate the error */ | 698 /* propagate the error */ |
699 errno = -ret; | 699 errno = -ret; |
700 ret = -1; | 700 ret = -1; |
701 CHECK_SYS_DO(ret, /* continue */); | 701 CHECK_SYS_DO(ret, /* continue */); |
702 } | 702 } |
703 | 703 |
704 /* Mark the error */ | 704 /* Mark the error */ |
705 if (ret <= 0) | 705 if (ret <= 0) |
706 fd_cnx_markerror(conn); | 706 fd_cnx_markerror(conn); |
707 | 707 |
708 return ret; | 708 return ret; |
709 } | 709 } |
710 | 710 |
711 /* Send, for older GNUTLS */ | 711 /* Send, for older GNUTLS */ |
712 #ifndef GNUTLS_VERSION_212 | 712 #ifndef GNUTLS_VERSION_212 |
728 } | 728 } |
729 | 729 |
730 struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen) | 730 struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen) |
731 { | 731 { |
732 return (struct fd_msg_pmdl *)(buf + PMDL_PADDED(datalen)); | 732 return (struct fd_msg_pmdl *)(buf + PMDL_PADDED(datalen)); |
733 } | 733 } |
734 | 734 |
735 static int fd_cnx_init_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl) | 735 static int fd_cnx_init_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl) |
736 { | 736 { |
737 *pmdl = fd_msg_pmdl_get_inbuf(buffer, expected_len); | 737 *pmdl = fd_msg_pmdl_get_inbuf(buffer, expected_len); |
738 fd_list_init(&(*pmdl)->sentinel, NULL); | 738 fd_list_init(&(*pmdl)->sentinel, NULL); |
741 } | 741 } |
742 | 742 |
743 static uint8_t * fd_cnx_alloc_msg_buffer(size_t expected_len, struct fd_msg_pmdl ** pmdl) | 743 static uint8_t * fd_cnx_alloc_msg_buffer(size_t expected_len, struct fd_msg_pmdl ** pmdl) |
744 { | 744 { |
745 uint8_t * ret = NULL; | 745 uint8_t * ret = NULL; |
746 | 746 |
747 CHECK_MALLOC_DO( ret = malloc( fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL ); | 747 CHECK_MALLOC_DO( ret = malloc( fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL ); |
748 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} ); | 748 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} ); |
749 return ret; | 749 return ret; |
750 } | 750 } |
751 | 751 |
752 #ifndef DISABLE_SCTP /* WE use this function only in SCTP code */ | 752 #ifndef DISABLE_SCTP /* WE use this function only in SCTP code */ |
753 static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl) | 753 static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl) |
754 { | 754 { |
755 uint8_t * ret = NULL; | 755 uint8_t * ret = NULL; |
756 | 756 |
757 CHECK_MALLOC_DO( ret = realloc( buffer, fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL ); | 757 CHECK_MALLOC_DO( ret = realloc( buffer, fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL ); |
758 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} ); | 758 CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} ); |
759 return ret; | 759 return ret; |
760 } | 760 } |
761 #endif /* DISABLE_SCTP */ | 761 #endif /* DISABLE_SCTP */ |
762 | 762 |
763 static void free_rcvdata(void * arg) | 763 static void free_rcvdata(void * arg) |
764 { | 764 { |
765 struct fd_cnx_rcvdata * data = arg; | 765 struct fd_cnx_rcvdata * data = arg; |
766 struct fd_msg_pmdl * pmdl = fd_msg_pmdl_get_inbuf(data->buffer, data->length); | 766 struct fd_msg_pmdl * pmdl = fd_msg_pmdl_get_inbuf(data->buffer, data->length); |
767 (void) pthread_mutex_destroy(&pmdl->lock); | 767 (void) pthread_mutex_destroy(&pmdl->lock); |
768 free(data->buffer); | 768 free(data->buffer); |
770 | 770 |
771 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */ | 771 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */ |
772 static void * rcvthr_notls_tcp(void * arg) | 772 static void * rcvthr_notls_tcp(void * arg) |
773 { | 773 { |
774 struct cnxctx * conn = arg; | 774 struct cnxctx * conn = arg; |
775 | 775 |
776 TRACE_ENTRY("%p", arg); | 776 TRACE_ENTRY("%p", arg); |
777 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); | 777 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); |
778 | 778 |
779 /* Set the thread name */ | 779 /* Set the thread name */ |
780 { | 780 { |
781 char buf[48]; | 781 char buf[48]; |
782 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket); | 782 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket); |
783 fd_log_threadname ( buf ); | 783 fd_log_threadname ( buf ); |
784 } | 784 } |
785 | 785 |
786 ASSERT( conn->cc_proto == IPPROTO_TCP ); | 786 ASSERT( conn->cc_proto == IPPROTO_TCP ); |
787 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) ); | 787 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) ); |
788 ASSERT( fd_cnx_target_queue(conn) ); | 788 ASSERT( fd_cnx_target_queue(conn) ); |
789 | 789 |
790 /* Receive from a TCP connection: we have to rebuild the message boundaries */ | 790 /* Receive from a TCP connection: we have to rebuild the message boundaries */ |
791 do { | 791 do { |
792 uint8_t header[4]; | 792 uint8_t header[4]; |
793 struct fd_cnx_rcvdata rcv_data; | 793 struct fd_cnx_rcvdata rcv_data; |
794 struct fd_msg_pmdl *pmdl=NULL; | 794 struct fd_msg_pmdl *pmdl=NULL; |
800 if (ret <= 0) { | 800 if (ret <= 0) { |
801 goto out; /* Stop the thread, the event was already sent */ | 801 goto out; /* Stop the thread, the event was already sent */ |
802 } | 802 } |
803 | 803 |
804 received += ret; | 804 received += ret; |
805 | 805 |
806 if (header[0] != DIAMETER_VERSION) | 806 if (header[0] != DIAMETER_VERSION) |
807 break; /* No need to wait for 4 bytes in this case */ | 807 break; /* No need to wait for 4 bytes in this case */ |
808 } while (received < sizeof(header)); | 808 } while (received < sizeof(header)); |
809 | 809 |
810 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; | 810 rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; |
831 free_rcvdata(&rcv_data); | 831 free_rcvdata(&rcv_data); |
832 goto out; | 832 goto out; |
833 } | 833 } |
834 received += ret; | 834 received += ret; |
835 } | 835 } |
836 | 836 |
837 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); | 837 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); |
838 | 838 |
839 /* We have received a complete message, pass it to the daemon */ | 839 /* We have received a complete message, pass it to the daemon */ |
840 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), | 840 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), |
841 { | 841 { |
842 free_rcvdata(&rcv_data); | 842 free_rcvdata(&rcv_data); |
843 goto fatal; | 843 goto fatal; |
844 } ); | 844 } ); |
845 | 845 |
846 } while (conn->cc_loop); | 846 } while (conn->cc_loop); |
847 | 847 |
848 out: | 848 out: |
849 TRACE_DEBUG(FULL, "Thread terminated"); | 849 TRACE_DEBUG(FULL, "Thread terminated"); |
850 return NULL; | 850 return NULL; |
851 | 851 |
852 fatal: | 852 fatal: |
853 /* An unrecoverable error occurred, stop the daemon */ | 853 /* An unrecoverable error occurred, stop the daemon */ |
854 CHECK_FCT_DO(fd_core_shutdown(), ); | 854 CHECK_FCT_DO(fd_core_shutdown(), ); |
855 goto out; | 855 goto out; |
856 } | 856 } |
860 static void * rcvthr_notls_sctp(void * arg) | 860 static void * rcvthr_notls_sctp(void * arg) |
861 { | 861 { |
862 struct cnxctx * conn = arg; | 862 struct cnxctx * conn = arg; |
863 struct fd_cnx_rcvdata rcv_data; | 863 struct fd_cnx_rcvdata rcv_data; |
864 int event; | 864 int event; |
865 | 865 |
866 TRACE_ENTRY("%p", arg); | 866 TRACE_ENTRY("%p", arg); |
867 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto fatal); | 867 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto fatal); |
868 | 868 |
869 /* Set the thread name */ | 869 /* Set the thread name */ |
870 { | 870 { |
871 char buf[48]; | 871 char buf[48]; |
872 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket); | 872 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket); |
873 fd_log_threadname ( buf ); | 873 fd_log_threadname ( buf ); |
874 } | 874 } |
875 | 875 |
876 ASSERT( conn->cc_proto == IPPROTO_SCTP ); | 876 ASSERT( conn->cc_proto == IPPROTO_SCTP ); |
877 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) ); | 877 ASSERT( ! fd_cnx_teststate(conn, CC_STATUS_TLS ) ); |
878 ASSERT( fd_cnx_target_queue(conn) ); | 878 ASSERT( fd_cnx_target_queue(conn) ); |
879 | 879 |
880 do { | 880 do { |
881 struct fd_msg_pmdl *pmdl=NULL; | 881 struct fd_msg_pmdl *pmdl=NULL; |
882 CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &rcv_data.buffer, &rcv_data.length, &event), goto fatal ); | 882 CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &rcv_data.buffer, &rcv_data.length, &event), goto fatal ); |
883 if (event == FDEVP_CNX_ERROR) { | 883 if (event == FDEVP_CNX_ERROR) { |
884 fd_cnx_markerror(conn); | 884 fd_cnx_markerror(conn); |
885 goto out; | 885 goto out; |
886 } | 886 } |
887 | 887 |
888 if (event == FDEVP_CNX_SHUTDOWN) { | 888 if (event == FDEVP_CNX_SHUTDOWN) { |
889 /* Just ignore the notification for now, we will get another error later anyway */ | 889 /* Just ignore the notification for now, we will get another error later anyway */ |
890 continue; | 890 continue; |
891 } | 891 } |
892 | 892 |
893 if (event == FDEVP_CNX_MSG_RECV) { | 893 if (event == FDEVP_CNX_MSG_RECV) { |
894 CHECK_MALLOC_DO( rcv_data.buffer = fd_cnx_realloc_msg_buffer(rcv_data.buffer, rcv_data.length, &pmdl), goto fatal ); | 894 CHECK_MALLOC_DO( rcv_data.buffer = fd_cnx_realloc_msg_buffer(rcv_data.buffer, rcv_data.length, &pmdl), goto fatal ); |
895 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); | 895 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); |
896 } | 896 } |
897 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, rcv_data.length, rcv_data.buffer), goto fatal ); | 897 CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, rcv_data.length, rcv_data.buffer), goto fatal ); |
898 | 898 |
899 } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV)); | 899 } while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV)); |
900 | 900 |
901 out: | 901 out: |
902 TRACE_DEBUG(FULL, "Thread terminated"); | 902 TRACE_DEBUG(FULL, "Thread terminated"); |
903 return NULL; | 903 return NULL; |
904 | 904 |
905 fatal: | 905 fatal: |
906 /* An unrecoverable error occurred, stop the daemon */ | 906 /* An unrecoverable error occurred, stop the daemon */ |
907 CHECK_FCT_DO(fd_core_shutdown(), ); | 907 CHECK_FCT_DO(fd_core_shutdown(), ); |
911 | 911 |
912 /* Start receving messages in clear (no TLS) on the connection */ | 912 /* Start receving messages in clear (no TLS) on the connection */ |
913 int fd_cnx_start_clear(struct cnxctx * conn, int loop) | 913 int fd_cnx_start_clear(struct cnxctx * conn, int loop) |
914 { | 914 { |
915 TRACE_ENTRY("%p %i", conn, loop); | 915 TRACE_ENTRY("%p %i", conn, loop); |
916 | 916 |
917 CHECK_PARAMS( conn && fd_cnx_target_queue(conn) && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && (!conn->cc_loop)); | 917 CHECK_PARAMS( conn && fd_cnx_target_queue(conn) && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && (!conn->cc_loop)); |
918 | 918 |
919 /* Release resources in case of a previous call was already made */ | 919 /* Release resources in case of a previous call was already made */ |
920 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); | 920 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); |
921 | 921 |
922 /* Save the loop request */ | 922 /* Save the loop request */ |
923 conn->cc_loop = loop; | 923 conn->cc_loop = loop; |
924 | 924 |
925 switch (conn->cc_proto) { | 925 switch (conn->cc_proto) { |
926 case IPPROTO_TCP: | 926 case IPPROTO_TCP: |
927 /* Start the tcp_notls thread */ | 927 /* Start the tcp_notls thread */ |
928 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) ); | 928 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) ); |
929 break; | 929 break; |
936 default: | 936 default: |
937 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); | 937 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); |
938 ASSERT(0); | 938 ASSERT(0); |
939 return ENOTSUP; | 939 return ENOTSUP; |
940 } | 940 } |
941 | 941 |
942 return 0; | 942 return 0; |
943 } | 943 } |
944 | 944 |
945 | 945 |
946 | 946 |
947 | 947 |
948 /* Returns 0 on error, received data size otherwise (always >= 0). This is not used for DTLS-protected associations. */ | 948 /* Returns 0 on error, received data size otherwise (always >= 0). This is not used for DTLS-protected associations. */ |
949 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) | 949 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) |
950 { | 950 { |
951 ssize_t ret; | 951 ssize_t ret; |
952 again: | 952 again: |
953 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), | 953 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), |
954 { | 954 { |
955 switch (ret) { | 955 switch (ret) { |
956 case GNUTLS_E_REHANDSHAKE: | 956 case GNUTLS_E_REHANDSHAKE: |
957 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) { | 957 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) { |
958 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), | 958 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), |
959 { | 959 { |
960 if (TRACE_BOOL(INFO)) { | 960 if (TRACE_BOOL(INFO)) { |
961 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); | 961 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); |
973 | 973 |
974 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: | 974 case GNUTLS_E_UNEXPECTED_PACKET_LENGTH: |
975 /* The connection is closed */ | 975 /* The connection is closed */ |
976 TRACE_DEBUG(FULL, "Got 0 size while reading the socket, probably connection closed..."); | 976 TRACE_DEBUG(FULL, "Got 0 size while reading the socket, probably connection closed..."); |
977 break; | 977 break; |
978 | 978 |
979 default: | 979 default: |
980 if (gnutls_error_is_fatal (ret) == 0) { | 980 if (gnutls_error_is_fatal (ret) == 0) { |
981 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret)); | 981 LOG_N("Ignoring non-fatal GNU TLS error: %s", gnutls_strerror (ret)); |
982 goto again; | 982 goto again; |
983 } | 983 } |
984 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); | 984 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); |
985 } | 985 } |
986 } ); | 986 } ); |
987 | 987 |
988 if (ret == 0) | 988 if (ret == 0) |
989 CHECK_GNUTLS_DO( gnutls_bye(session, GNUTLS_SHUT_RDWR), ); | 989 CHECK_GNUTLS_DO( gnutls_bye(session, GNUTLS_SHUT_RDWR), ); |
990 | 990 |
991 end: | 991 end: |
992 if (ret <= 0) | 992 if (ret <= 0) |
993 fd_cnx_markerror(conn); | 993 fd_cnx_markerror(conn); |
994 return ret; | 994 return ret; |
995 } | 995 } |
996 | 996 |
998 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) | 998 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) |
999 { | 999 { |
1000 ssize_t ret; | 1000 ssize_t ret; |
1001 struct timespec ts, now; | 1001 struct timespec ts, now; |
1002 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 ); | 1002 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), return -1 ); |
1003 again: | 1003 again: |
1004 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz), | 1004 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz), |
1005 { | 1005 { |
1006 pthread_testcancel(); | 1006 pthread_testcancel(); |
1007 switch (ret) { | 1007 switch (ret) { |
1008 case GNUTLS_E_REHANDSHAKE: | 1008 case GNUTLS_E_REHANDSHAKE: |
1009 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) { | 1009 if (!fd_cnx_teststate(conn, CC_STATUS_CLOSING)) { |
1010 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), | 1010 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), |
1011 { | 1011 { |
1012 if (TRACE_BOOL(INFO)) { | 1012 if (TRACE_BOOL(INFO)) { |
1013 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); | 1013 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); |
1032 goto again; | 1032 goto again; |
1033 } | 1033 } |
1034 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); | 1034 LOG_E("Fatal GNUTLS error: %s", gnutls_strerror (ret)); |
1035 } | 1035 } |
1036 } ); | 1036 } ); |
1037 end: | 1037 end: |
1038 if (ret <= 0) | 1038 if (ret <= 0) |
1039 fd_cnx_markerror(conn); | 1039 fd_cnx_markerror(conn); |
1040 | 1040 |
1041 return ret; | 1041 return ret; |
1042 } | 1042 } |
1043 | 1043 |
1044 | 1044 |
1045 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ | 1045 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ |
1046 /* For the case of DTLS, since we are not using SCTP_UNORDERED, the messages over a single stream are ordered. | 1046 /* For the case of DTLS, since we are not using SCTP_UNORDERED, the messages over a single stream are ordered. |
1047 Furthermore, as long as messages are shorter than the MTU [2^14 = 16384 bytes], they are delivered in a single | 1047 Furthermore, as long as messages are shorter than the MTU [2^14 = 16384 bytes], they are delivered in a single |
1048 record, as far as I understand. | 1048 record, as far as I understand. |
1049 For larger messages, however, it is possible that pieces of messages coming from different streams can get interleaved. | 1049 For larger messages, however, it is possible that pieces of messages coming from different streams can get interleaved. |
1050 As a result, we do not use the following function for DTLS reception, because we use the sequence number to rebuild the | 1050 As a result, we do not use the following function for DTLS reception, because we use the sequence number to rebuild the |
1051 messages. */ | 1051 messages. */ |
1052 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) | 1052 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) |
1053 { | 1053 { |
1054 ssize_t ret = 0; | 1054 ssize_t ret = 0; |
1093 free_rcvdata(&rcv_data); | 1093 free_rcvdata(&rcv_data); |
1094 goto out; | 1094 goto out; |
1095 } | 1095 } |
1096 received += ret; | 1096 received += ret; |
1097 } | 1097 } |
1098 | 1098 |
1099 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); | 1099 fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl); |
1100 | 1100 |
1101 /* We have received a complete message, pass it to the daemon */ | 1101 /* We have received a complete message, pass it to the daemon */ |
1102 CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), | 1102 CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), |
1103 { | 1103 { |
1104 free_rcvdata(&rcv_data); | 1104 free_rcvdata(&rcv_data); |
1105 CHECK_FCT_DO(fd_core_shutdown(), ); | 1105 CHECK_FCT_DO(fd_core_shutdown(), ); |
1106 return ret; | 1106 return ret; |
1107 } ); | 1107 } ); |
1108 | 1108 |
1109 } while (1); | 1109 } while (1); |
1110 | 1110 |
1111 out: | 1111 out: |
1112 return (ret == 0) ? 0 : ENOTCONN; | 1112 return (ret == 0) ? 0 : ENOTCONN; |
1113 } | 1113 } |
1114 | 1114 |
1115 /* Receiver thread (TLS & 1 stream SCTP or TCP) */ | 1115 /* Receiver thread (TLS & 1 stream SCTP or TCP) */ |
1116 static void * rcvthr_tls_single(void * arg) | 1116 static void * rcvthr_tls_single(void * arg) |
1117 { | 1117 { |
1118 struct cnxctx * conn = arg; | 1118 struct cnxctx * conn = arg; |
1119 | 1119 |
1120 TRACE_ENTRY("%p", arg); | 1120 TRACE_ENTRY("%p", arg); |
1121 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), return NULL ); | 1121 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), return NULL ); |
1122 | 1122 |
1123 /* Set the thread name */ | 1123 /* Set the thread name */ |
1124 { | 1124 { |
1125 char buf[48]; | 1125 char buf[48]; |
1126 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket); | 1126 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket); |
1127 fd_log_threadname ( buf ); | 1127 fd_log_threadname ( buf ); |
1128 } | 1128 } |
1129 | 1129 |
1130 ASSERT( fd_cnx_teststate(conn, CC_STATUS_TLS) ); | 1130 ASSERT( fd_cnx_teststate(conn, CC_STATUS_TLS) ); |
1131 ASSERT( fd_cnx_target_queue(conn) ); | 1131 ASSERT( fd_cnx_target_queue(conn) ); |
1132 | 1132 |
1133 /* The next function only returns when there is an error on the socket */ | 1133 /* The next function only returns when there is an error on the socket */ |
1134 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */); | 1134 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */); |
1135 | 1135 |
1136 TRACE_DEBUG(FULL, "Thread terminated"); | 1136 TRACE_DEBUG(FULL, "Thread terminated"); |
1137 return NULL; | 1137 return NULL; |
1138 } | 1138 } |
1139 | 1139 |
1140 /* Prepare a gnutls session object for handshake */ | 1140 /* Prepare a gnutls session object for handshake */ |
1141 int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds) | 1141 int fd_tls_prepare(gnutls_session_t * session, int mode, int dtls, char * priority, void * alt_creds) |
1149 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); | 1149 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); |
1150 | 1150 |
1151 /* Set the algorithm suite */ | 1151 /* Set the algorithm suite */ |
1152 if (priority) { | 1152 if (priority) { |
1153 const char * errorpos; | 1153 const char * errorpos; |
1154 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ), | 1154 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ), |
1155 { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'", priority, errorpos); return EINVAL; } ); | 1155 { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'", priority, errorpos); return EINVAL; } ); |
1156 } else { | 1156 } else { |
1157 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); | 1157 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); |
1158 } | 1158 } |
1159 | 1159 |
1162 | 1162 |
1163 /* Request the remote credentials as well */ | 1163 /* Request the remote credentials as well */ |
1164 if (mode == GNUTLS_SERVER) { | 1164 if (mode == GNUTLS_SERVER) { |
1165 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE); | 1165 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE); |
1166 } | 1166 } |
1167 | 1167 |
1168 return 0; | 1168 return 0; |
1169 } | 1169 } |
1170 | 1170 |
1171 #ifndef GNUTLS_VERSION_300 | 1171 #ifndef GNUTLS_VERSION_300 |
1172 | 1172 |
1177 unsigned int gtret; | 1177 unsigned int gtret; |
1178 const gnutls_datum_t *cert_list; | 1178 const gnutls_datum_t *cert_list; |
1179 unsigned int cert_list_size; | 1179 unsigned int cert_list_size; |
1180 gnutls_x509_crt_t cert; | 1180 gnutls_x509_crt_t cert; |
1181 time_t now; | 1181 time_t now; |
1182 | 1182 |
1183 TRACE_ENTRY("%p %d", conn, verbose); | 1183 TRACE_ENTRY("%p %d", conn, verbose); |
1184 CHECK_PARAMS(conn); | 1184 CHECK_PARAMS(conn); |
1185 | 1185 |
1186 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ | 1186 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ |
1187 #ifdef DEBUG | 1187 #ifdef DEBUG |
1188 if (verbose) { | 1188 if (verbose) { |
1189 const char *tmp; | 1189 const char *tmp; |
1190 gnutls_kx_algorithm_t kx; | 1190 gnutls_kx_algorithm_t kx; |
1191 gnutls_credentials_type_t cred; | 1191 gnutls_credentials_type_t cred; |
1192 | 1192 |
1193 LOG_D("TLS Session information for connection '%s':", conn->cc_id); | 1193 LOG_D("TLS Session information for connection '%s':", conn->cc_id); |
1194 | 1194 |
1195 /* print the key exchange's algorithm name */ | 1195 /* print the key exchange's algorithm name */ |
1196 GNUTLS_TRACE( kx = gnutls_kx_get (session) ); | 1196 GNUTLS_TRACE( kx = gnutls_kx_get (session) ); |
1197 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); | 1197 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); |
1227 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { | 1227 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) { |
1228 LOG_D("\t - Ephemeral DH using prime of %d bits", | 1228 LOG_D("\t - Ephemeral DH using prime of %d bits", |
1229 gnutls_dh_get_prime_bits (session)); | 1229 gnutls_dh_get_prime_bits (session)); |
1230 } | 1230 } |
1231 break; | 1231 break; |
1232 #ifdef ENABLE_SRP | 1232 #ifdef ENABLE_SRP |
1233 case GNUTLS_CRD_SRP: | 1233 case GNUTLS_CRD_SRP: |
1234 LOG_D("\t - SRP session with username %s", | 1234 LOG_D("\t - SRP session with username %s", |
1235 gnutls_srp_server_get_username (session)); | 1235 gnutls_srp_server_get_username (session)); |
1236 break; | 1236 break; |
1237 #endif /* ENABLE_SRP */ | 1237 #endif /* ENABLE_SRP */ |
1261 /* Print the MAC algorithms name. ie SHA1 */ | 1261 /* Print the MAC algorithms name. ie SHA1 */ |
1262 tmp = gnutls_mac_get_name (gnutls_mac_get (session)); | 1262 tmp = gnutls_mac_get_name (gnutls_mac_get (session)); |
1263 LOG_D("\t - MAC: %s", tmp); | 1263 LOG_D("\t - MAC: %s", tmp); |
1264 } | 1264 } |
1265 #endif /* DEBUG */ | 1265 #endif /* DEBUG */ |
1266 | 1266 |
1267 /* First, use built-in verification */ | 1267 /* First, use built-in verification */ |
1268 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, >ret), return EINVAL ); | 1268 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, >ret), return EINVAL ); |
1269 if (gtret) { | 1269 if (gtret) { |
1270 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1270 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1271 if (gtret & GNUTLS_CERT_INVALID) | 1271 if (gtret & GNUTLS_CERT_INVALID) |
1278 LOG_E(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints."); | 1278 LOG_E(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints."); |
1279 if (gtret & GNUTLS_CERT_INSECURE_ALGORITHM) | 1279 if (gtret & GNUTLS_CERT_INSECURE_ALGORITHM) |
1280 LOG_E(" - The certificate signature uses a weak algorithm."); | 1280 LOG_E(" - The certificate signature uses a weak algorithm."); |
1281 return EINVAL; | 1281 return EINVAL; |
1282 } | 1282 } |
1283 | 1283 |
1284 /* Code from http://www.gnu.org/software/gnutls/manual/gnutls.html#Verifying-peer_0027s-certificate */ | 1284 /* Code from http://www.gnu.org/software/gnutls/manual/gnutls.html#Verifying-peer_0027s-certificate */ |
1285 if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) { | 1285 if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) { |
1286 LOG_E("TLS: Remote peer did not present a certificate, other mechanisms are not supported yet. socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1286 LOG_E("TLS: Remote peer did not present a certificate, other mechanisms are not supported yet. socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1287 return EINVAL; | 1287 return EINVAL; |
1288 } | 1288 } |
1289 | 1289 |
1290 GNUTLS_TRACE( cert_list = gnutls_certificate_get_peers (session, &cert_list_size) ); | 1290 GNUTLS_TRACE( cert_list = gnutls_certificate_get_peers (session, &cert_list_size) ); |
1291 if (cert_list == NULL) | 1291 if (cert_list == NULL) |
1292 return EINVAL; | 1292 return EINVAL; |
1293 | 1293 |
1294 now = time(NULL); | 1294 now = time(NULL); |
1295 | 1295 |
1296 #ifdef DEBUG | 1296 #ifdef DEBUG |
1297 char serial[40]; | 1297 char serial[40]; |
1298 char dn[128]; | 1298 char dn[128]; |
1299 size_t size; | 1299 size_t size; |
1300 unsigned int algo, bits; | 1300 unsigned int algo, bits; |
1301 time_t expiration_time, activation_time; | 1301 time_t expiration_time, activation_time; |
1302 | 1302 |
1303 LOG_D("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size); | 1303 LOG_D("TLS Certificate information for connection '%s' (%d certs provided):", conn->cc_id, cert_list_size); |
1304 for (i = 0; i < cert_list_size; i++) | 1304 for (i = 0; i < cert_list_size; i++) |
1305 { | 1305 { |
1306 | 1306 |
1307 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL); | 1307 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL); |
1308 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL); | 1308 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL); |
1309 | 1309 |
1310 LOG_A(" Certificate %d info:", i); | 1310 LOG_A(" Certificate %d info:", i); |
1311 | 1311 |
1312 GNUTLS_TRACE( expiration_time = gnutls_x509_crt_get_expiration_time (cert) ); | 1312 GNUTLS_TRACE( expiration_time = gnutls_x509_crt_get_expiration_time (cert) ); |
1313 GNUTLS_TRACE( activation_time = gnutls_x509_crt_get_activation_time (cert) ); | 1313 GNUTLS_TRACE( activation_time = gnutls_x509_crt_get_activation_time (cert) ); |
1314 | 1314 |
1316 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate expires: %.24s", ctime (&expiration_time)); | 1316 LOG( i ? FD_LOG_ANNOYING : FD_LOG_DEBUG, "\t - Certificate expires: %.24s", ctime (&expiration_time)); |
1317 | 1317 |
1318 /* Print the serial number of the certificate. */ | 1318 /* Print the serial number of the certificate. */ |
1319 size = sizeof (serial); | 1319 size = sizeof (serial); |
1320 gnutls_x509_crt_get_serial (cert, serial, &size); | 1320 gnutls_x509_crt_get_serial (cert, serial, &size); |
1321 | 1321 |
1322 { | 1322 { |
1323 int j; | 1323 int j; |
1324 char buf[1024]; | 1324 char buf[1024]; |
1325 snprintf(buf, sizeof(buf), "\t - Certificate serial number: "); | 1325 snprintf(buf, sizeof(buf), "\t - Certificate serial number: "); |
1326 for (j = 0; j < size; j++) { | 1326 for (j = 0; j < size; j++) { |
1352 | 1352 |
1353 /* Check validity of all the certificates */ | 1353 /* Check validity of all the certificates */ |
1354 for (i = 0; i < cert_list_size; i++) | 1354 for (i = 0; i < cert_list_size; i++) |
1355 { | 1355 { |
1356 time_t deadline; | 1356 time_t deadline; |
1357 | 1357 |
1358 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL); | 1358 CHECK_GNUTLS_DO( gnutls_x509_crt_init (&cert), return EINVAL); |
1359 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL); | 1359 CHECK_GNUTLS_DO( gnutls_x509_crt_import (cert, &cert_list[i], GNUTLS_X509_FMT_DER), return EINVAL); |
1360 | 1360 |
1361 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(cert) ); | 1361 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_expiration_time(cert) ); |
1362 if ((deadline != (time_t)-1) && (deadline < now)) { | 1362 if ((deadline != (time_t)-1) && (deadline < now)) { |
1363 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1363 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1364 LOG_E(" - The certificate %d in the chain is expired", i); | 1364 LOG_E(" - The certificate %d in the chain is expired", i); |
1365 ret = EINVAL; | 1365 ret = EINVAL; |
1366 } | 1366 } |
1367 | 1367 |
1368 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(cert) ); | 1368 GNUTLS_TRACE( deadline = gnutls_x509_crt_get_activation_time(cert) ); |
1369 if ((deadline != (time_t)-1) && (deadline > now)) { | 1369 if ((deadline != (time_t)-1) && (deadline > now)) { |
1370 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1370 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1371 LOG_E(" - The certificate %d in the chain is not yet activated", i); | 1371 LOG_E(" - The certificate %d in the chain is not yet activated", i); |
1372 ret = EINVAL; | 1372 ret = EINVAL; |
1373 } | 1373 } |
1374 | 1374 |
1375 if ((i == 0) && (conn->cc_tls_para.cn)) { | 1375 if ((i == 0) && (conn->cc_tls_para.cn)) { |
1376 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) { | 1376 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) { |
1377 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1377 LOG_E("TLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1378 LOG_E(" - The certificate hostname does not match '%s'", conn->cc_tls_para.cn); | 1378 LOG_E(" - The certificate hostname does not match '%s'", conn->cc_tls_para.cn); |
1379 ret = EINVAL; | 1379 ret = EINVAL; |
1380 } | 1380 } |
1381 } | 1381 } |
1382 | 1382 |
1383 GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) ); | 1383 GNUTLS_TRACE( gnutls_x509_crt_deinit (cert) ); |
1384 } | 1384 } |
1385 | 1385 |
1386 return ret; | 1386 return ret; |
1387 } | 1387 } |
1398 gnutls_x509_crt_t cert; | 1398 gnutls_x509_crt_t cert; |
1399 struct cnxctx * conn; | 1399 struct cnxctx * conn; |
1400 int hostname_verified = 0; | 1400 int hostname_verified = 0; |
1401 | 1401 |
1402 TRACE_ENTRY("%p", session); | 1402 TRACE_ENTRY("%p", session); |
1403 | 1403 |
1404 /* get the associated connection */ | 1404 /* get the associated connection */ |
1405 conn = gnutls_session_get_ptr (session); | 1405 conn = gnutls_session_get_ptr (session); |
1406 | 1406 |
1407 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ | 1407 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ |
1408 #ifdef DEBUG | 1408 #ifdef DEBUG |
1409 const char *tmp; | 1409 const char *tmp; |
1410 gnutls_credentials_type_t cred; | 1410 gnutls_credentials_type_t cred; |
1411 gnutls_kx_algorithm_t kx; | 1411 gnutls_kx_algorithm_t kx; |
1412 int dhe, ecdh; | 1412 int dhe, ecdh; |
1413 | 1413 |
1414 dhe = ecdh = 0; | 1414 dhe = ecdh = 0; |
1415 | 1415 |
1416 LOG_A("TLS Session information for connection '%s':", conn->cc_id); | 1416 LOG_A("TLS Session information for connection '%s':", conn->cc_id); |
1417 | 1417 |
1418 /* print the key exchange's algorithm name | 1418 /* print the key exchange's algorithm name |
1419 */ | 1419 */ |
1420 GNUTLS_TRACE( kx = gnutls_kx_get (session) ); | 1420 GNUTLS_TRACE( kx = gnutls_kx_get (session) ); |
1421 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); | 1421 GNUTLS_TRACE( tmp = gnutls_kx_get_name (kx) ); |
1422 LOG_D("\t- Key Exchange: %s", tmp); | 1422 LOG_D("\t- Key Exchange: %s", tmp); |
1472 */ | 1472 */ |
1473 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) | 1473 if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) |
1474 dhe = 1; | 1474 dhe = 1; |
1475 else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) | 1475 else if (kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) |
1476 ecdh = 1; | 1476 ecdh = 1; |
1477 | 1477 |
1478 /* Now print some info on the remote certificate */ | 1478 /* Now print some info on the remote certificate */ |
1479 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) { | 1479 if (gnutls_certificate_type_get (session) == GNUTLS_CRT_X509) { |
1480 gnutls_datum_t cinfo; | 1480 gnutls_datum_t cinfo; |
1481 | 1481 |
1482 cert_list = gnutls_certificate_get_peers (session, &cert_list_size); | 1482 cert_list = gnutls_certificate_get_peers (session, &cert_list_size); |
1502 if (ret == 0) | 1502 if (ret == 0) |
1503 { | 1503 { |
1504 LOG_D("\t\t%s", cinfo.data); | 1504 LOG_D("\t\t%s", cinfo.data); |
1505 gnutls_free (cinfo.data); | 1505 gnutls_free (cinfo.data); |
1506 } | 1506 } |
1507 | 1507 |
1508 if (conn->cc_tls_para.cn) { | 1508 if (conn->cc_tls_para.cn) { |
1509 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) { | 1509 if (!gnutls_x509_crt_check_hostname (cert, conn->cc_tls_para.cn)) { |
1510 LOG_E("\tTLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); | 1510 LOG_E("\tTLS: Remote certificate invalid on socket %d (Remote: '%s')(Connection: '%s') :", conn->cc_socket, conn->cc_remid, conn->cc_id); |
1511 LOG_E("\t - The certificate hostname does not match '%s'", conn->cc_tls_para.cn); | 1511 LOG_E("\t - The certificate hostname does not match '%s'", conn->cc_tls_para.cn); |
1512 gnutls_x509_crt_deinit (cert); | 1512 gnutls_x509_crt_deinit (cert); |
1513 return GNUTLS_E_CERTIFICATE_ERROR; | 1513 return GNUTLS_E_CERTIFICATE_ERROR; |
1514 } | 1514 } |
1515 | 1515 |
1516 } | 1516 } |
1517 | 1517 |
1518 hostname_verified = 1; | 1518 hostname_verified = 1; |
1519 | 1519 |
1520 gnutls_x509_crt_deinit (cert); | 1520 gnutls_x509_crt_deinit (cert); |
1533 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session))); | 1533 gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session))); |
1534 else if (dhe != 0) | 1534 else if (dhe != 0) |
1535 LOG_D("\t - Ephemeral DH using prime of %d bits", | 1535 LOG_D("\t - Ephemeral DH using prime of %d bits", |
1536 gnutls_dh_get_prime_bits (session)); | 1536 gnutls_dh_get_prime_bits (session)); |
1537 | 1537 |
1538 /* print the protocol's name (ie TLS 1.0) | 1538 /* print the protocol's name (ie TLS 1.0) |
1539 */ | 1539 */ |
1540 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); | 1540 tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); |
1541 LOG_D("\t - Protocol: %s", tmp); | 1541 LOG_D("\t - Protocol: %s", tmp); |
1542 | 1542 |
1543 /* print the certificate type of the peer. | 1543 /* print the certificate type of the peer. |
1555 /* Print the MAC algorithms name. | 1555 /* Print the MAC algorithms name. |
1556 * ie SHA1 | 1556 * ie SHA1 |
1557 */ | 1557 */ |
1558 tmp = gnutls_mac_get_name (gnutls_mac_get (session)); | 1558 tmp = gnutls_mac_get_name (gnutls_mac_get (session)); |
1559 LOG_D("\t - MAC: %s", tmp); | 1559 LOG_D("\t - MAC: %s", tmp); |
1560 | 1560 |
1561 #endif /* DEBUG */ | 1561 #endif /* DEBUG */ |
1562 | 1562 |
1563 /* This verification function uses the trusted CAs in the credentials | 1563 /* This verification function uses the trusted CAs in the credentials |
1564 * structure. So you must have installed one or more CA certificates. | 1564 * structure. So you must have installed one or more CA certificates. |
1565 */ | 1565 */ |
1566 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &status), return GNUTLS_E_CERTIFICATE_ERROR ); | 1566 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (session, &status), return GNUTLS_E_CERTIFICATE_ERROR ); |
1575 if (status & GNUTLS_CERT_EXPIRED) | 1575 if (status & GNUTLS_CERT_EXPIRED) |
1576 LOG_E(" - The certificate has expired."); | 1576 LOG_E(" - The certificate has expired."); |
1577 | 1577 |
1578 if (status & GNUTLS_CERT_NOT_ACTIVATED) | 1578 if (status & GNUTLS_CERT_NOT_ACTIVATED) |
1579 LOG_E(" - The certificate is not yet activated."); | 1579 LOG_E(" - The certificate is not yet activated."); |
1580 } | 1580 } |
1581 if (status & GNUTLS_CERT_INVALID) | 1581 if (status & GNUTLS_CERT_INVALID) |
1582 { | 1582 { |
1583 return GNUTLS_E_CERTIFICATE_ERROR; | 1583 return GNUTLS_E_CERTIFICATE_ERROR; |
1584 } | 1584 } |
1585 | 1585 |
1586 /* Up to here the process is the same for X.509 certificates and | 1586 /* Up to here the process is the same for X.509 certificates and |
1587 * OpenPGP keys. From now on X.509 certificates are assumed. This can | 1587 * OpenPGP keys. From now on X.509 certificates are assumed. This can |
1588 * be easily extended to work with openpgp keys as well. | 1588 * be easily extended to work with openpgp keys as well. |
1589 */ | 1589 */ |
1590 if ((!hostname_verified) && (conn->cc_tls_para.cn)) { | 1590 if ((!hostname_verified) && (conn->cc_tls_para.cn)) { |
1632 | 1632 |
1633 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ | 1633 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ |
1634 int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds) | 1634 int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds) |
1635 { | 1635 { |
1636 int dtls = 0; | 1636 int dtls = 0; |
1637 | 1637 |
1638 TRACE_ENTRY( "%p %d %d %p %p", conn, mode, algo, priority, alt_creds); | 1638 TRACE_ENTRY( "%p %d %d %p %p", conn, mode, algo, priority, alt_creds); |
1639 CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); | 1639 CHECK_PARAMS( conn && (!fd_cnx_teststate(conn, CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); |
1640 | 1640 |
1641 /* Save the mode */ | 1641 /* Save the mode */ |
1642 conn->cc_tls_para.mode = mode; | 1642 conn->cc_tls_para.mode = mode; |
1643 conn->cc_tls_para.algo = algo; | 1643 conn->cc_tls_para.algo = algo; |
1644 | 1644 |
1645 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */ | 1645 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */ |
1646 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); | 1646 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); |
1647 | 1647 |
1648 /* Once TLS handshake is done, we don't stop after the first message */ | 1648 /* Once TLS handshake is done, we don't stop after the first message */ |
1649 conn->cc_loop = 1; | 1649 conn->cc_loop = 1; |
1650 | 1650 |
1651 dtls = fd_cnx_may_dtls(conn); | 1651 dtls = fd_cnx_may_dtls(conn); |
1652 | 1652 |
1653 /* Prepare the master session credentials and priority */ | 1653 /* Prepare the master session credentials and priority */ |
1654 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, dtls, priority, alt_creds) ); | 1654 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, dtls, priority, alt_creds) ); |
1655 | 1655 |
1656 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ | 1656 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ |
1657 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { | 1657 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { |
1680 } else { | 1680 } else { |
1681 TODO("DTLS push/pull functions"); | 1681 TODO("DTLS push/pull functions"); |
1682 return ENOTSUP; | 1682 return ENOTSUP; |
1683 } | 1683 } |
1684 } | 1684 } |
1685 | 1685 |
1686 /* additional initialization for gnutls 3.x */ | 1686 /* additional initialization for gnutls 3.x */ |
1687 #ifdef GNUTLS_VERSION_300 | 1687 #ifdef GNUTLS_VERSION_300 |
1688 /* the verify function has already been set in the global initialization in config.c */ | 1688 /* the verify function has already been set in the global initialization in config.c */ |
1689 | 1689 |
1690 /* fd_tls_verify_credentials_2 uses the connection */ | 1690 /* fd_tls_verify_credentials_2 uses the connection */ |
1691 gnutls_session_set_ptr (conn->cc_tls_para.session, (void *) conn); | 1691 gnutls_session_set_ptr (conn->cc_tls_para.session, (void *) conn); |
1692 | 1692 |
1693 if ((conn->cc_tls_para.cn != NULL) && (mode == GNUTLS_CLIENT)) { | 1693 if ((conn->cc_tls_para.cn != NULL) && (mode == GNUTLS_CLIENT)) { |
1694 /* this might allow virtual hosting on the remote peer */ | 1694 /* this might allow virtual hosting on the remote peer */ |
1695 CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_tls_para.session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */); | 1695 CHECK_GNUTLS_DO( gnutls_server_name_set (conn->cc_tls_para.session, GNUTLS_NAME_DNS, conn->cc_tls_para.cn, strlen(conn->cc_tls_para.cn)), /* ignore failure */); |
1696 } | 1696 } |
1697 | 1697 |
1698 #endif /* GNUTLS_VERSION_300 */ | 1698 #endif /* GNUTLS_VERSION_300 */ |
1699 | 1699 |
1700 #ifdef GNUTLS_VERSION_310 | 1700 #ifdef GNUTLS_VERSION_310 |
1701 GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT)); | 1701 GNUTLS_TRACE( gnutls_handshake_set_timeout( conn->cc_tls_para.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT)); |
1702 #endif /* GNUTLS_VERSION_310 */ | 1702 #endif /* GNUTLS_VERSION_310 */ |
1703 | 1703 |
1704 /* Mark the connection as protected from here, so that the gnutls credentials will be freed */ | 1704 /* Mark the connection as protected from here, so that the gnutls credentials will be freed */ |
1705 fd_cnx_addstate(conn, CC_STATUS_TLS); | 1705 fd_cnx_addstate(conn, CC_STATUS_TLS); |
1706 | 1706 |
1707 /* Handshake master session */ | 1707 /* Handshake master session */ |
1708 { | 1708 { |
1709 int ret; | 1709 int ret; |
1710 | 1710 |
1711 CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session), | 1711 CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session), |
1712 { | 1712 { |
1713 if (TRACE_BOOL(INFO)) { | 1713 if (TRACE_BOOL(INFO)) { |
1714 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); | 1714 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); |
1715 } | 1715 } |
1717 return EINVAL; | 1717 return EINVAL; |
1718 } ); | 1718 } ); |
1719 | 1719 |
1720 #ifndef GNUTLS_VERSION_300 | 1720 #ifndef GNUTLS_VERSION_300 |
1721 /* Now verify the remote credentials are valid -- only simple tests here */ | 1721 /* Now verify the remote credentials are valid -- only simple tests here */ |
1722 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1), | 1722 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1), |
1723 { | 1723 { |
1724 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), ); | 1724 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), ); |
1725 fd_cnx_markerror(conn); | 1725 fd_cnx_markerror(conn); |
1726 return EINVAL; | 1726 return EINVAL; |
1727 }); | 1727 }); |
1728 #endif /* GNUTLS_VERSION_300 */ | 1728 #endif /* GNUTLS_VERSION_300 */ |
1729 } | 1729 } |
1730 | 1730 |
1731 /* Multi-stream TLS: handshake other streams as well */ | 1731 /* Multi-stream TLS: handshake other streams as well */ |
1732 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { | 1732 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { |
1733 #ifndef DISABLE_SCTP | 1733 #ifndef DISABLE_SCTP |
1734 /* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */ | 1734 /* Start reading the messages from the master session. That way, if the remote peer closed, we are not stuck inside handshake */ |
1735 CHECK_FCT(fd_sctp3436_startthreads(conn, 0)); | 1735 CHECK_FCT(fd_sctp3436_startthreads(conn, 0)); |
1748 TODO("Signal the dtls_push function that multiple streams can be used from this point."); | 1748 TODO("Signal the dtls_push function that multiple streams can be used from this point."); |
1749 TODO("Create DTLS rcvthr (must reassembly based on seq numbers & stream id ?)"); | 1749 TODO("Create DTLS rcvthr (must reassembly based on seq numbers & stream id ?)"); |
1750 return ENOTSUP; | 1750 return ENOTSUP; |
1751 } | 1751 } |
1752 } | 1752 } |
1753 | 1753 |
1754 return 0; | 1754 return 0; |
1755 } | 1755 } |
1756 | 1756 |
1757 /* Retrieve TLS credentials of the remote peer, after handshake */ | 1757 /* Retrieve TLS credentials of the remote peer, after handshake */ |
1758 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) | 1758 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) |
1759 { | 1759 { |
1760 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size); | 1760 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size); |
1761 CHECK_PARAMS( conn && fd_cnx_teststate(conn, CC_STATUS_TLS) && cert_list && cert_list_size ); | 1761 CHECK_PARAMS( conn && fd_cnx_teststate(conn, CC_STATUS_TLS) && cert_list && cert_list_size ); |
1762 | 1762 |
1763 /* This function only works for X.509 certificates. */ | 1763 /* This function only works for X.509 certificates. */ |
1764 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 ); | 1764 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 ); |
1765 | 1765 |
1766 GNUTLS_TRACE( *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size) ); | 1766 GNUTLS_TRACE( *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size) ); |
1767 if (*cert_list == NULL) { | 1767 if (*cert_list == NULL) { |
1768 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred."); | 1768 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred."); |
1769 return EINVAL; | 1769 return EINVAL; |
1770 } | 1770 } |
1771 | 1771 |
1772 TRACE_DEBUG( FULL, "Saved certificate chain (%d certificates) in peer structure.", *cert_list_size); | 1772 TRACE_DEBUG( FULL, "Saved certificate chain (%d certificates) in peer structure.", *cert_list_size); |
1773 | 1773 |
1774 return 0; | 1774 return 0; |
1775 } | 1775 } |
1776 | 1776 |
1777 /* Receive next message. if timeout is not NULL, wait only until timeout. This function only pulls from a queue, mgr thread is filling that queue aynchrounously. */ | 1777 /* Receive next message. if timeout is not NULL, wait only until timeout. This function only pulls from a queue, mgr thread is filling that queue aynchrounously. */ |
1778 /* if the altfifo has been set on this conn object, this function must not be called */ | 1778 /* if the altfifo has been set on this conn object, this function must not be called */ |
1779 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) | 1779 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) |
1780 { | 1780 { |
1781 int ev; | 1781 int ev; |
1782 size_t ev_sz; | 1782 size_t ev_sz; |
1783 void * ev_data; | 1783 void * ev_data; |
1784 | 1784 |
1785 TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len); | 1785 TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len); |
1786 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len); | 1786 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len); |
1787 CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL); | 1787 CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL); |
1788 CHECK_PARAMS(conn->cc_alt == NULL); | 1788 CHECK_PARAMS(conn->cc_alt == NULL); |
1789 | 1789 |
1792 if (timeout) { | 1792 if (timeout) { |
1793 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) ); | 1793 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) ); |
1794 } else { | 1794 } else { |
1795 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) ); | 1795 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) ); |
1796 } | 1796 } |
1797 | 1797 |
1798 switch (ev) { | 1798 switch (ev) { |
1799 case FDEVP_CNX_MSG_RECV: | 1799 case FDEVP_CNX_MSG_RECV: |
1800 /* We got one */ | 1800 /* We got one */ |
1801 *len = ev_sz; | 1801 *len = ev_sz; |
1802 *buf = ev_data; | 1802 *buf = ev_data; |
1803 return 0; | 1803 return 0; |
1804 | 1804 |
1805 case FDEVP_PSM_TIMEOUT: | 1805 case FDEVP_PSM_TIMEOUT: |
1806 TRACE_DEBUG(FULL, "Timeout event received"); | 1806 TRACE_DEBUG(FULL, "Timeout event received"); |
1807 return ETIMEDOUT; | 1807 return ETIMEDOUT; |
1808 | 1808 |
1809 case FDEVP_CNX_EP_CHANGE: | 1809 case FDEVP_CNX_EP_CHANGE: |
1810 /* We ignore this event */ | 1810 /* We ignore this event */ |
1811 goto get_next; | 1811 goto get_next; |
1812 | 1812 |
1813 case FDEVP_CNX_ERROR: | 1813 case FDEVP_CNX_ERROR: |
1814 TRACE_DEBUG(FULL, "Received ERROR event on the connection"); | 1814 TRACE_DEBUG(FULL, "Received ERROR event on the connection"); |
1815 return ENOTCONN; | 1815 return ENOTCONN; |
1816 } | 1816 } |
1817 | 1817 |
1818 TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev)); | 1818 TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev)); |
1819 return EINVAL; | 1819 return EINVAL; |
1820 } | 1820 } |
1821 | 1821 |
1822 /* Where the events are sent */ | 1822 /* Where the events are sent */ |
1833 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) | 1833 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) |
1834 { | 1834 { |
1835 int ret; | 1835 int ret; |
1836 TRACE_ENTRY( "%p %p", conn, alt_fifo ); | 1836 TRACE_ENTRY( "%p %p", conn, alt_fifo ); |
1837 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming ); | 1837 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming ); |
1838 | 1838 |
1839 /* The magic function does it all */ | 1839 /* The magic function does it all */ |
1840 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } ); | 1840 CHECK_POSIX_DO( pthread_mutex_lock(&state_lock), { ASSERT(0); } ); |
1841 CHECK_FCT_DO( ret = fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ), ); | 1841 CHECK_FCT_DO( ret = fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ), ); |
1842 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } ); | 1842 CHECK_POSIX_DO( pthread_mutex_unlock(&state_lock), { ASSERT(0); } ); |
1843 | 1843 |
1844 return ret; | 1844 return ret; |
1845 } | 1845 } |
1846 | 1846 |
1847 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/ | 1847 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/ |
1848 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len) | 1848 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len) |
1859 iov.iov_len = len - sent; | 1859 iov.iov_len = len - sent; |
1860 CHECK_SYS_DO( ret = fd_cnx_s_sendv(conn, &iov, 1), ); | 1860 CHECK_SYS_DO( ret = fd_cnx_s_sendv(conn, &iov, 1), ); |
1861 } | 1861 } |
1862 if (ret <= 0) | 1862 if (ret <= 0) |
1863 return ENOTCONN; | 1863 return ENOTCONN; |
1864 | 1864 |
1865 sent += ret; | 1865 sent += ret; |
1866 } while ( sent < len ); | 1866 } while ( sent < len ); |
1867 return 0; | 1867 return 0; |
1868 } | 1868 } |
1869 | 1869 |
1870 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */ | 1870 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time (on the same conn), so we don't protect. */ |
1871 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) | 1871 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) |
1872 { | 1872 { |
1873 TRACE_ENTRY("%p %p %zd", conn, buf, len); | 1873 TRACE_ENTRY("%p %p %zd", conn, buf, len); |
1874 | 1874 |
1875 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len); | 1875 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! fd_cnx_teststate(conn, CC_STATUS_ERROR)) && buf && len); |
1876 | 1876 |
1877 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, fd_cnx_teststate(conn, CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id); | 1877 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, fd_cnx_teststate(conn, CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id); |
1878 | 1878 |
1879 switch (conn->cc_proto) { | 1879 switch (conn->cc_proto) { |
1880 case IPPROTO_TCP: | 1880 case IPPROTO_TCP: |
1881 CHECK_FCT( send_simple(conn, buf, len) ); | 1881 CHECK_FCT( send_simple(conn, buf, len) ); |
1882 break; | 1882 break; |
1883 | 1883 |
1884 #ifndef DISABLE_SCTP | 1884 #ifndef DISABLE_SCTP |
1885 case IPPROTO_SCTP: { | 1885 case IPPROTO_SCTP: { |
1886 int dtls = fd_cnx_uses_dtls(conn); | 1886 int dtls = fd_cnx_uses_dtls(conn); |
1887 if (!dtls) { | 1887 if (!dtls) { |
1888 int stream = 0; | 1888 int stream = 0; |
1890 int limit; | 1890 int limit; |
1891 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) | 1891 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) |
1892 limit = conn->cc_sctp_para.pairs; | 1892 limit = conn->cc_sctp_para.pairs; |
1893 else | 1893 else |
1894 limit = conn->cc_sctp_para.str_out; | 1894 limit = conn->cc_sctp_para.str_out; |
1895 | 1895 |
1896 if (limit > 1) { | 1896 if (limit > 1) { |
1897 conn->cc_sctp_para.next += 1; | 1897 conn->cc_sctp_para.next += 1; |
1898 conn->cc_sctp_para.next %= limit; | 1898 conn->cc_sctp_para.next %= limit; |
1899 stream = conn->cc_sctp_para.next; | 1899 stream = conn->cc_sctp_para.next; |
1900 } | 1900 } |
1901 } | 1901 } |
1902 | 1902 |
1903 if (stream == 0) { | 1903 if (stream == 0) { |
1904 /* We can use default function, it sends over stream #0 */ | 1904 /* We can use default function, it sends over stream #0 */ |
1905 CHECK_FCT( send_simple(conn, buf, len) ); | 1905 CHECK_FCT( send_simple(conn, buf, len) ); |
1906 } else { | 1906 } else { |
1907 if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { | 1907 if (!fd_cnx_teststate(conn, CC_STATUS_TLS)) { |
1908 struct iovec iov; | 1908 struct iovec iov; |
1909 iov.iov_base = buf; | 1909 iov.iov_base = buf; |
1910 iov.iov_len = len; | 1910 iov.iov_len = len; |
1911 | 1911 |
1912 CHECK_SYS_DO( fd_sctp_sendstrv(conn, stream, &iov, 1), { fd_cnx_markerror(conn); return ENOTCONN; } ); | 1912 CHECK_SYS_DO( fd_sctp_sendstrv(conn, stream, &iov, 1), { fd_cnx_markerror(conn); return ENOTCONN; } ); |
1913 } else { | 1913 } else { |
1914 /* push the data to the appropriate session */ | 1914 /* push the data to the appropriate session */ |
1915 ssize_t ret; | 1915 ssize_t ret; |
1916 size_t sent = 0; | 1916 size_t sent = 0; |
1930 CHECK_FCT( send_simple(conn, buf, len) ); | 1930 CHECK_FCT( send_simple(conn, buf, len) ); |
1931 } | 1931 } |
1932 } | 1932 } |
1933 break; | 1933 break; |
1934 #endif /* DISABLE_SCTP */ | 1934 #endif /* DISABLE_SCTP */ |
1935 | 1935 |
1936 default: | 1936 default: |
1937 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); | 1937 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); |
1938 ASSERT(0); | 1938 ASSERT(0); |
1939 return ENOTSUP; /* or EINVAL... */ | 1939 return ENOTSUP; /* or EINVAL... */ |
1940 } | 1940 } |
1941 | 1941 |
1942 return 0; | 1942 return 0; |
1943 } | 1943 } |
1944 | 1944 |
1945 | 1945 |
1946 /**************************************/ | 1946 /**************************************/ |
1949 | 1949 |
1950 /* Destroy a conn structure, and shutdown the socket */ | 1950 /* Destroy a conn structure, and shutdown the socket */ |
1951 void fd_cnx_destroy(struct cnxctx * conn) | 1951 void fd_cnx_destroy(struct cnxctx * conn) |
1952 { | 1952 { |
1953 TRACE_ENTRY("%p", conn); | 1953 TRACE_ENTRY("%p", conn); |
1954 | 1954 |
1955 CHECK_PARAMS_DO(conn, return); | 1955 CHECK_PARAMS_DO(conn, return); |
1956 | 1956 |
1957 fd_cnx_addstate(conn, CC_STATUS_CLOSING); | 1957 fd_cnx_addstate(conn, CC_STATUS_CLOSING); |
1958 | 1958 |
1959 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */ | 1959 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */ |
1960 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { | 1960 if (fd_cnx_teststate(conn, CC_STATUS_TLS)) { |
1961 #ifndef DISABLE_SCTP | 1961 #ifndef DISABLE_SCTP |
1962 int dtls = fd_cnx_uses_dtls(conn); | 1962 int dtls = fd_cnx_uses_dtls(conn); |
1963 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { | 1963 if ((!dtls) && (conn->cc_sctp_para.pairs > 1)) { |
1983 fd_sctp3436_gnutls_deinit_others(conn); | 1983 fd_sctp3436_gnutls_deinit_others(conn); |
1984 if (conn->cc_tls_para.session) { | 1984 if (conn->cc_tls_para.session) { |
1985 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) ); | 1985 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) ); |
1986 conn->cc_tls_para.session = NULL; | 1986 conn->cc_tls_para.session = NULL; |
1987 } | 1987 } |
1988 | 1988 |
1989 /* Destroy the wrapper (also stops the demux thread) */ | 1989 /* Destroy the wrapper (also stops the demux thread) */ |
1990 fd_sctp3436_destroy(conn); | 1990 fd_sctp3436_destroy(conn); |
1991 | 1991 |
1992 } else { | 1992 } else { |
1993 #endif /* DISABLE_SCTP */ | 1993 #endif /* DISABLE_SCTP */ |
2005 } | 2005 } |
2006 } else { | 2006 } else { |
2007 /* Cancel the receiver thread in case it did not already terminate */ | 2007 /* Cancel the receiver thread in case it did not already terminate */ |
2008 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); | 2008 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); |
2009 } | 2009 } |
2010 | 2010 |
2011 /* Free the resources of the TLS session */ | 2011 /* Free the resources of the TLS session */ |
2012 if (conn->cc_tls_para.session) { | 2012 if (conn->cc_tls_para.session) { |
2013 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) ); | 2013 GNUTLS_TRACE( gnutls_deinit(conn->cc_tls_para.session) ); |
2014 conn->cc_tls_para.session = NULL; | 2014 conn->cc_tls_para.session = NULL; |
2015 } | 2015 } |
2016 #ifndef DISABLE_SCTP | 2016 #ifndef DISABLE_SCTP |
2017 } | 2017 } |
2018 #endif /* DISABLE_SCTP */ | 2018 #endif /* DISABLE_SCTP */ |
2019 } | 2019 } |
2020 | 2020 |
2021 /* Terminate the thread in case it is not done yet -- is there any such case left ?*/ | 2021 /* Terminate the thread in case it is not done yet -- is there any such case left ?*/ |
2022 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); | 2022 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); |
2023 | 2023 |
2024 /* Shut the connection down */ | 2024 /* Shut the connection down */ |
2025 if (conn->cc_socket > 0) { | 2025 if (conn->cc_socket > 0) { |
2026 shutdown(conn->cc_socket, SHUT_RDWR); | 2026 shutdown(conn->cc_socket, SHUT_RDWR); |
2027 close(conn->cc_socket); | 2027 close(conn->cc_socket); |
2028 conn->cc_socket = -1; | 2028 conn->cc_socket = -1; |
2029 } | 2029 } |
2030 | 2030 |
2031 /* Empty and destroy FIFO list */ | 2031 /* Empty and destroy FIFO list */ |
2032 if (conn->cc_incoming) { | 2032 if (conn->cc_incoming) { |
2033 fd_event_destroy( &conn->cc_incoming, free ); | 2033 fd_event_destroy( &conn->cc_incoming, free ); |
2034 } | 2034 } |
2035 | 2035 |
2036 /* Free the object */ | 2036 /* Free the object */ |
2037 free(conn); | 2037 free(conn); |
2038 | 2038 |
2039 /* Done! */ | 2039 /* Done! */ |
2040 return; | 2040 return; |
2041 } | 2041 } |