comparison freeDiameter/cnxctx.c @ 209:b9f48f2f2a22

Some cleanups in the code
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 16 Feb 2010 15:29:55 +0900
parents e1da03ba112f
children 929513df9024
comparison
equal deleted inserted replaced
208:e1da03ba112f 209:b9f48f2f2a22
133 char addrbuf[INET6_ADDRSTRLEN]; 133 char addrbuf[INET6_ADDRSTRLEN];
134 int rc; 134 int rc;
135 rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 135 rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
136 if (rc) 136 if (rc)
137 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 137 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
138 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv TCP [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); 138 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP srv [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket);
139 } 139 }
140 140
141 cnx->cc_proto = IPPROTO_TCP; 141 cnx->cc_proto = IPPROTO_TCP;
142 142
143 return cnx; 143 return cnx;
168 168
169 /* Create the socket */ 169 /* Create the socket */
170 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error ); 170 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error );
171 171
172 /* Generate the name for the connection object */ 172 /* Generate the name for the connection object */
173 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv SCTP :%hu (%d)", port, cnx->cc_socket); 173 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP srv :%hu (%d)", port, cnx->cc_socket);
174 174
175 cnx->cc_proto = IPPROTO_SCTP; 175 cnx->cc_proto = IPPROTO_SCTP;
176 176
177 return cnx; 177 return cnx;
178 178
215 struct fd_endpoint * ep; 215 struct fd_endpoint * ep;
216 216
217 TRACE_ENTRY("%p", serv); 217 TRACE_ENTRY("%p", serv);
218 CHECK_PARAMS_DO(serv, return NULL); 218 CHECK_PARAMS_DO(serv, return NULL);
219 219
220 /* Accept the new connection -- this is blocking until new client enters or cancellation */ 220 /* Accept the new connection -- this is blocking until new client enters or until cancellation */
221 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); 221 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
222 222
223 if (TRACE_BOOL(INFO)) { 223 if (TRACE_BOOL(INFO)) {
224 fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv)); 224 fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv));
225 sSA_DUMP_NODE( &ss, NI_NUMERICHOST ); 225 sSA_DUMP_NODE( &ss, NI_NUMERICHOST );
244 if (rc) { 244 if (rc) {
245 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 245 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
246 portbuf[0] = '\0'; 246 portbuf[0] = '\0';
247 } 247 }
248 248
249 snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)", 249 snprintf(cli->cc_id, sizeof(cli->cc_id), "{%s} (%d) <- [%s]:%s (%d)",
250 IPPROTO_NAME(cli->cc_proto), 250 IPPROTO_NAME(cli->cc_proto), serv->cc_socket,
251 addrbuf, portbuf, 251 addrbuf, portbuf, cli->cc_socket);
252 cli->cc_socket, serv->cc_socket);
253 252
254 /* Name for log messages */ 253 /* Name for log messages */
255 rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); 254 rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
256 if (rc) 255 if (rc)
257 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); 256 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
313 if (rc) { 312 if (rc) {
314 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 313 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
315 portbuf[0] = '\0'; 314 portbuf[0] = '\0';
316 } 315 }
317 316
318 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of TCP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 317 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{TCP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
319 318
320 /* Name for log messages */ 319 /* Name for log messages */
321 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 320 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
322 if (rc) 321 if (rc)
323 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); 322 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
376 if (rc) { 375 if (rc) {
377 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 376 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
378 portbuf[0] = '\0'; 377 portbuf[0] = '\0';
379 } 378 }
380 379
381 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of SCTP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 380 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "{SCTP} -> [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
382 381
383 /* Name for log messages */ 382 /* Name for log messages */
384 rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 383 rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
385 if (rc) 384 if (rc)
386 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); 385 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
417 416
418 /* Return the TLS state of a connection */ 417 /* Return the TLS state of a connection */
419 int fd_cnx_getTLS(struct cnxctx * conn) 418 int fd_cnx_getTLS(struct cnxctx * conn)
420 { 419 {
421 CHECK_PARAMS_DO( conn, return 0 ); 420 CHECK_PARAMS_DO( conn, return 0 );
422 return conn->cc_tls; 421 return conn->cc_status & CC_STATUS_TLS;
423 } 422 }
424 423
425 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ 424 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
426 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) 425 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
427 { 426 {
491 490
492 /**************************************/ 491 /**************************************/
493 /* Use of a connection object */ 492 /* Use of a connection object */
494 /**************************************/ 493 /**************************************/
495 494
495 /* An error occurred on the socket */
496 void fd_cnx_markerror(struct cnxctx * conn)
497 {
498 TRACE_ENTRY("%p", conn);
499 CHECK_PARAMS_DO( conn, goto fatal );
500
501 /* Mark the error */
502 conn->cc_status |= CC_STATUS_ERROR;
503
504 /* Report the error if not reported yet, and not closing */
505 if ((!(conn->cc_status & CC_STATUS_CLOSING )) && (!(conn->cc_status & CC_STATUS_SIGNALED ))) {
506 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), goto fatal);
507 conn->cc_status |= CC_STATUS_SIGNALED;
508 }
509
510 return;
511 fatal:
512 /* An unrecoverable error occurred, stop the daemon */
513 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
514 }
515
496 /* Set the timeout option on the socket */ 516 /* Set the timeout option on the socket */
497 void fd_cnx_s_setto(int sock) 517 void fd_cnx_s_setto(int sock)
498 { 518 {
499 struct timeval tv; 519 struct timeval tv;
500 520
501 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */ 521 /* Set a timeout on the socket so that in any case we are not stuck waiting for something */
502 memset(&tv, 0, sizeof(tv)); 522 memset(&tv, 0, sizeof(tv));
503 tv.tv_sec = 3; /* allow 3 seconds timeout for TLS session cleanup */ 523 tv.tv_sec = 3; /* allow 3 seconds timeout for TLS session cleanup */
504 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), /* best effort only */ ); 524 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)), /* best effort only */ );
505 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ ); 525 CHECK_SYS_DO( setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)), /* Also timeout for sending, to avoid waiting forever */ );
506 } 526 }
507 527
508 /* A recv-like function, taking a cnxctx object instead of socket as entry. Only used to filter timeouts error (GNUTLS does not like these...) */ 528 /* 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 */
509 ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length) 529 ssize_t fd_cnx_s_recv(struct cnxctx * conn, void *buffer, size_t length)
510 { 530 {
511 ssize_t ret = 0; 531 ssize_t ret = 0;
512 int timedout = 0; 532 int timedout = 0;
513 again: 533 again:
514 ret = recv(conn->cc_socket, buffer, length, 0); 534 ret = recv(conn->cc_socket, buffer, length, 0);
515 /* Handle special case of timeout */ 535 /* Handle special case of timeout */
516 if ((ret < 0) && (errno == EAGAIN)) { 536 if ((ret < 0) && (errno == EAGAIN)) {
517 if (!conn->cc_closing) 537 if (! (conn->cc_status & CC_STATUS_CLOSING))
518 goto again; /* don't care, just ignore */ 538 goto again; /* don't care, just ignore */
519 if (!timedout) { 539 if (!timedout) {
520 timedout ++; /* allow for one timeout while closing */ 540 timedout ++; /* allow for one timeout while closing */
521 goto again; 541 goto again;
522 } 542 }
523 CHECK_SYS_DO(ret, /* continue */); 543 }
524 } 544
545 CHECK_SYS_DO(ret, /* continue */);
525 546
526 /* Mark the error */ 547 /* Mark the error */
527 if (ret <= 0) 548 if (ret <= 0)
528 conn->cc_goterror=1; 549 fd_cnx_markerror(conn);
529 550
530 return ret; 551 return ret;
531 } 552 }
532 553
533 /* Send */ 554 /* Send */
537 int timedout = 0; 558 int timedout = 0;
538 again: 559 again:
539 ret = send(conn->cc_socket, buffer, length, 0); 560 ret = send(conn->cc_socket, buffer, length, 0);
540 /* Handle special case of timeout */ 561 /* Handle special case of timeout */
541 if ((ret < 0) && (errno == EAGAIN)) { 562 if ((ret < 0) && (errno == EAGAIN)) {
542 if (!conn->cc_closing) 563 if (! (conn->cc_status & CC_STATUS_CLOSING))
543 goto again; /* don't care, just ignore */ 564 goto again; /* don't care, just ignore */
544 if (!timedout) { 565 if (!timedout) {
545 timedout ++; /* allow for one timeout while closing */ 566 timedout ++; /* allow for one timeout while closing */
546 goto again; 567 goto again;
547 } 568 }
548 CHECK_SYS_DO(ret, /* continue */); 569 CHECK_SYS_DO(ret, /* continue */);
549 } 570 }
550 571
551 /* Mark the error */ 572 /* Mark the error */
552 if (ret <= 0) 573 if (ret <= 0)
553 conn->cc_goterror=1; 574 fd_cnx_markerror(conn);
554 575
555 return ret; 576 return ret;
556 } 577 }
557 578
558 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */ 579 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */
569 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket); 590 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket);
570 fd_log_threadname ( buf ); 591 fd_log_threadname ( buf );
571 } 592 }
572 593
573 ASSERT( conn->cc_proto == IPPROTO_TCP ); 594 ASSERT( conn->cc_proto == IPPROTO_TCP );
574 ASSERT( conn->cc_tls == 0 ); 595 ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
575 ASSERT( Target_Queue(conn) ); 596 ASSERT( Target_Queue(conn) );
576 597
577 /* Receive from a TCP connection: we have to rebuild the message boundaries */ 598 /* Receive from a TCP connection: we have to rebuild the message boundaries */
578 do { 599 do {
579 uint8_t header[4]; 600 uint8_t header[4];
583 size_t received = 0; 604 size_t received = 0;
584 605
585 do { 606 do {
586 ret = fd_cnx_s_recv(conn, &header[received], sizeof(header) - received); 607 ret = fd_cnx_s_recv(conn, &header[received], sizeof(header) - received);
587 if (ret <= 0) { 608 if (ret <= 0) {
588 CHECK_SYS_DO(ret, /* continue */); 609 goto out; /* Stop the thread, the event was already sent */
589 goto error; /* Stop the thread, the recipient of the event will cleanup */
590 } 610 }
591 611
592 received += ret; 612 received += ret;
593 } while (received < sizeof(header)); 613 } while (received < sizeof(header));
594 614
597 /* Check the received word is a valid begining of a Diameter message */ 617 /* Check the received word is a valid begining of a Diameter message */
598 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 618 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */
599 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 619 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
600 /* The message is suspect */ 620 /* The message is suspect */
601 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length); 621 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
602 goto error; /* Stop the thread, the recipient of the event will cleanup */ 622 fd_cnx_markerror(conn);
623 goto out; /* Stop the thread, the recipient of the event will cleanup */
603 } 624 }
604 625
605 /* Ok, now we can really receive the data */ 626 /* Ok, now we can really receive the data */
606 CHECK_MALLOC_DO( newmsg = malloc( length ), goto error ); 627 CHECK_MALLOC_DO( newmsg = malloc( length ), goto fatal );
607 memcpy(newmsg, header, sizeof(header)); 628 memcpy(newmsg, header, sizeof(header));
608 629
609 while (received < length) { 630 while (received < length) {
610 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 631 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
611 ret = fd_cnx_s_recv(conn, newmsg + received, length - received); 632 ret = fd_cnx_s_recv(conn, newmsg + received, length - received);
612 pthread_cleanup_pop(0); 633 pthread_cleanup_pop(0);
613 634
614 if (ret <= 0) { 635 if (ret <= 0) {
615 CHECK_SYS_DO(ret, /* continue */);
616 free(newmsg); 636 free(newmsg);
617 goto error; /* Stop the thread, the recipient of the event will cleanup */ 637 goto out;
618 } 638 }
619 received += ret; 639 received += ret;
620 } 640 }
621 641
622 /* We have received a complete message, send it */ 642 /* We have received a complete message, pass it to the daemon */
623 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 643 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
624 644
625 } while (conn->cc_loop); 645 } while (conn->cc_loop);
626 646
627 out: 647 out:
628 TRACE_DEBUG(FULL, "Thread terminated"); 648 TRACE_DEBUG(FULL, "Thread terminated");
629 return NULL; 649 return NULL;
630 error: 650
631 if (!conn->cc_closing) { 651 fatal:
632 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 652 /* An unrecoverable error occurred, stop the daemon */
633 } 653 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
634 goto out; 654 goto out;
635 } 655 }
636 656
637 #ifndef DISABLE_SCTP 657 #ifndef DISABLE_SCTP
638 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */ 658 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */
642 uint8_t * buf; 662 uint8_t * buf;
643 size_t bufsz; 663 size_t bufsz;
644 int event; 664 int event;
645 665
646 TRACE_ENTRY("%p", arg); 666 TRACE_ENTRY("%p", arg);
647 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 667 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto fatal);
648 668
649 /* Set the thread name */ 669 /* Set the thread name */
650 { 670 {
651 char buf[48]; 671 char buf[48];
652 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket); 672 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket);
653 fd_log_threadname ( buf ); 673 fd_log_threadname ( buf );
654 } 674 }
655 675
656 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 676 ASSERT( conn->cc_proto == IPPROTO_SCTP );
657 ASSERT( conn->cc_tls == 0 ); 677 ASSERT( ! (conn->cc_status & CC_STATUS_TLS) );
658 ASSERT( Target_Queue(conn) ); 678 ASSERT( Target_Queue(conn) );
659 679
660 do { 680 do {
661 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_closing), goto error ); 681 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event, &conn->cc_status), goto fatal );
662 if (event == FDEVP_CNX_ERROR) { 682 if (event == FDEVP_CNX_ERROR) {
663 conn->cc_goterror = 1; 683 fd_cnx_markerror(conn);
664 goto error; 684 goto out;
665 } 685 }
666 686
667 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error ); 687 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto fatal );
668 688
669 } while (conn->cc_loop); 689 } while (conn->cc_loop);
670 690
671 out: 691 out:
672 TRACE_DEBUG(FULL, "Thread terminated"); 692 TRACE_DEBUG(FULL, "Thread terminated");
673 return NULL; 693 return NULL;
674 error: 694
675 if (!conn->cc_closing) { 695 fatal:
676 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 696 /* An unrecoverable error occurred, stop the daemon */
677 } 697 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
678 goto out; 698 goto out;
679 } 699 }
680 #endif /* DISABLE_SCTP */ 700 #endif /* DISABLE_SCTP */
681
682 /* Returns 0 on error, received data size otherwise (always >= 0) */
683 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
684 {
685 ssize_t ret;
686 again:
687 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
688 {
689 switch (ret) {
690 case GNUTLS_E_REHANDSHAKE:
691 if (!conn->cc_closing)
692 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
693 {
694 if (TRACE_BOOL(INFO)) {
695 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
696 }
697 ret = 0;
698 goto end;
699 } );
700
701 case GNUTLS_E_AGAIN:
702 case GNUTLS_E_INTERRUPTED:
703 if (!conn->cc_closing)
704 goto again;
705 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_recv now.");
706 ret = 0;
707 break;
708
709 default:
710 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
711 ret = 0;
712 }
713 } );
714 end:
715 if (ret <= 0)
716 conn->cc_goterror = 1;
717 return ret;
718 }
719
720 /* Wrapper around gnutls_record_send to handle some error codes */
721 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
722 {
723 ssize_t ret;
724 again:
725 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
726 {
727 switch (ret) {
728 case GNUTLS_E_REHANDSHAKE:
729 if (!conn->cc_closing)
730 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
731 {
732 if (TRACE_BOOL(INFO)) {
733 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
734 }
735 goto end;
736 } );
737
738 case GNUTLS_E_AGAIN:
739 case GNUTLS_E_INTERRUPTED:
740 if (!conn->cc_closing)
741 goto again;
742 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
743 break;
744
745 default:
746 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
747 }
748 } );
749 end:
750 if (ret <= 0)
751 conn->cc_goterror = 1;
752 return ret;
753 }
754
755
756 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
757 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
758 {
759 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
760 do {
761 uint8_t header[4];
762 uint8_t * newmsg;
763 size_t length;
764 ssize_t ret = 0;
765 size_t received = 0;
766
767 do {
768 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);
769 if (ret == 0) {
770 /* The connection is closed */
771 goto out;
772 }
773 received += ret;
774 } while (received < sizeof(header));
775
776 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
777
778 /* Check the received word is a valid beginning of a Diameter message */
779 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */
780 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
781 /* The message is suspect */
782 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
783 goto out;
784 }
785
786 /* Ok, now we can really receive the data */
787 CHECK_MALLOC( newmsg = malloc( length ) );
788 memcpy(newmsg, header, sizeof(header));
789
790 while (received < length) {
791 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
792 ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);
793 pthread_cleanup_pop(0);
794
795 if (ret == 0) {
796 free(newmsg);
797 goto out; /* Stop the thread, the recipient of the event will cleanup */
798 }
799 received += ret;
800 }
801
802 /* We have received a complete message, send it */
803 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
804
805 } while (1);
806 out:
807 return ENOTCONN;
808 }
809
810 /* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */
811 static void * rcvthr_tls_single(void * arg)
812 {
813 struct cnxctx * conn = arg;
814
815 TRACE_ENTRY("%p", arg);
816 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error);
817
818 /* Set the thread name */
819 {
820 char buf[48];
821 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket);
822 fd_log_threadname ( buf );
823 }
824
825 ASSERT( conn->cc_tls == 1 );
826 ASSERT( Target_Queue(conn) );
827
828 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
829 error:
830 if (!conn->cc_closing) {
831 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */);
832 }
833 TRACE_DEBUG(FULL, "Thread terminated");
834 return NULL;
835 }
836 701
837 /* Start receving messages in clear (no TLS) on the connection */ 702 /* Start receving messages in clear (no TLS) on the connection */
838 int fd_cnx_start_clear(struct cnxctx * conn, int loop) 703 int fd_cnx_start_clear(struct cnxctx * conn, int loop)
839 { 704 {
840 TRACE_ENTRY("%p %i", conn, loop); 705 TRACE_ENTRY("%p %i", conn, loop);
841 706
842 CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop)); 707 CHECK_PARAMS( conn && Target_Queue(conn) && (!(conn->cc_status & CC_STATUS_TLS)) && (!conn->cc_loop));
843 708
844 /* Release resources in case of a previous call was already made */ 709 /* Release resources in case of a previous call was already made */
845 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); 710 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);
846 711
847 /* Save the loop request */ 712 /* Save the loop request */
858 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) ); 723 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) );
859 break; 724 break;
860 #endif /* DISABLE_SCTP */ 725 #endif /* DISABLE_SCTP */
861 default: 726 default:
862 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); 727 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
728 ASSERT(0);
863 return ENOTSUP; 729 return ENOTSUP;
864 } 730 }
865 731
866 return 0; 732 return 0;
867 } 733 }
868 734
735
736
737
738 /* Returns 0 on error, received data size otherwise (always >= 0) */
739 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
740 {
741 ssize_t ret;
742 again:
743 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz),
744 {
745 switch (ret) {
746 case GNUTLS_E_REHANDSHAKE:
747 if (!(conn->cc_status & CC_STATUS_CLOSING))
748 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
749 {
750 if (TRACE_BOOL(INFO)) {
751 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
752 }
753 goto end;
754 } );
755
756 case GNUTLS_E_AGAIN:
757 case GNUTLS_E_INTERRUPTED:
758 if (!(conn->cc_status & CC_STATUS_CLOSING))
759 goto again;
760 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_recv now.");
761 break;
762
763 default:
764 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
765 }
766 } );
767 end:
768 if (ret <= 0)
769 fd_cnx_markerror(conn);
770 return ret;
771 }
772
773 /* Wrapper around gnutls_record_send to handle some error codes */
774 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)
775 {
776 ssize_t ret;
777 again:
778 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),
779 {
780 switch (ret) {
781 case GNUTLS_E_REHANDSHAKE:
782 if (!(conn->cc_status & CC_STATUS_CLOSING))
783 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),
784 {
785 if (TRACE_BOOL(INFO)) {
786 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
787 }
788 goto end;
789 } );
790
791 case GNUTLS_E_AGAIN:
792 case GNUTLS_E_INTERRUPTED:
793 if (!(conn->cc_status & CC_STATUS_CLOSING))
794 goto again;
795 TRACE_DEBUG(INFO, "Connection is closing, so abord gnutls_record_send now.");
796 break;
797
798 default:
799 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");
800 }
801 } );
802 end:
803 if (ret <= 0)
804 fd_cnx_markerror(conn);
805
806 return ret;
807 }
808
809
810 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
811 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
812 {
813 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
814 do {
815 uint8_t header[4];
816 uint8_t * newmsg;
817 size_t length;
818 ssize_t ret = 0;
819 size_t received = 0;
820
821 do {
822 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received);
823 if (ret <= 0) {
824 /* The connection is closed */
825 goto out;
826 }
827 received += ret;
828 } while (received < sizeof(header));
829
830 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
831
832 /* Check the received word is a valid beginning of a Diameter message */
833 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */
834 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
835 /* The message is suspect */
836 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
837 fd_cnx_markerror(conn);
838 goto out;
839 }
840
841 /* Ok, now we can really receive the data */
842 CHECK_MALLOC( newmsg = malloc( length ) );
843 memcpy(newmsg, header, sizeof(header));
844
845 while (received < length) {
846 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
847 ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);
848 pthread_cleanup_pop(0);
849
850 if (ret <= 0) {
851 free(newmsg);
852 goto out;
853 }
854 received += ret;
855 }
856
857 /* We have received a complete message, pass it to the daemon */
858 CHECK_FCT_DO( ret = fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg),
859 {
860 free(newmsg);
861 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
862 return ret;
863 } );
864
865 } while (1);
866
867 out:
868 return ENOTCONN;
869 }
870
871 /* Receiver thread (TLS & 1 stream SCTP or TCP) */
872 static void * rcvthr_tls_single(void * arg)
873 {
874 struct cnxctx * conn = arg;
875
876 TRACE_ENTRY("%p", arg);
877 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), return NULL );
878
879 /* Set the thread name */
880 {
881 char buf[48];
882 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/single stream", conn->cc_socket);
883 fd_log_threadname ( buf );
884 }
885
886 ASSERT( conn->cc_status & CC_STATUS_TLS );
887 ASSERT( Target_Queue(conn) );
888
889 /* The next function only returns when there is an error on the socket */
890 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */);
891
892 TRACE_DEBUG(FULL, "Thread terminated");
893 return NULL;
894 }
895
869 /* Prepare a gnutls session object for handshake */ 896 /* Prepare a gnutls session object for handshake */
870 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds) 897 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds)
871 { 898 {
872 /* Create the master session context */ 899 /* Create the session context */
873 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); 900 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM );
874 901
875 /* Set the algorithm suite */ 902 /* Set the algorithm suite */
876 if (priority) { 903 if (priority) {
877 const char * errorpos; 904 const char * errorpos;
898 int ret, i; 925 int ret, i;
899 const gnutls_datum_t *cert_list; 926 const gnutls_datum_t *cert_list;
900 unsigned int cert_list_size; 927 unsigned int cert_list_size;
901 gnutls_x509_crt_t cert; 928 gnutls_x509_crt_t cert;
902 time_t now; 929 time_t now;
930
931 TRACE_ENTRY("%p %d", conn, verbose);
932 CHECK_PARAMS(conn);
903 933
904 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */ 934 /* Trace the session information -- http://www.gnu.org/software/gnutls/manual/gnutls.html#Obtaining-session-information */
905 if (verbose && TRACE_BOOL(FULL)) { 935 if (verbose && TRACE_BOOL(FULL)) {
906 const char *tmp; 936 const char *tmp;
907 gnutls_kx_algorithm_t kx; 937 gnutls_kx_algorithm_t kx;
1104 } 1134 }
1105 1135
1106 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ 1136 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */
1107 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds) 1137 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds)
1108 { 1138 {
1109 TRACE_ENTRY( "%p %d", conn, mode); 1139 TRACE_ENTRY( "%p %d %p %p", conn, mode, priority, alt_creds);
1110 CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); 1140 CHECK_PARAMS( conn && (!(conn->cc_status & CC_STATUS_TLS)) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );
1111 1141
1112 /* Save the mode */ 1142 /* Save the mode */
1113 conn->cc_tls_para.mode = mode; 1143 conn->cc_tls_para.mode = mode;
1114 1144
1115 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */ 1145 /* Cancel receiving thread if any -- it should already be terminated anyway, we just release the resources */
1137 /* Set the push and pull callbacks */ 1167 /* Set the push and pull callbacks */
1138 gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv); 1168 gnutls_transport_set_pull_function(conn->cc_tls_para.session, (void *)fd_cnx_s_recv);
1139 gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send); 1169 gnutls_transport_set_push_function(conn->cc_tls_para.session, (void *)fd_cnx_s_send);
1140 } 1170 }
1141 1171
1172 /* Mark the connection as protected from here, so that the gnutls credentials will be freed */
1173 conn->cc_status |= CC_STATUS_TLS;
1174
1142 /* Handshake master session */ 1175 /* Handshake master session */
1143 { 1176 {
1144 int ret; 1177 int ret;
1145 CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session), 1178 CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session),
1146 { 1179 {
1147 if (TRACE_BOOL(INFO)) { 1180 if (TRACE_BOOL(INFO)) {
1148 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 1181 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));
1149 } 1182 }
1150 conn->cc_goterror = 1; 1183 fd_cnx_markerror(conn);
1151 return EINVAL; 1184 return EINVAL;
1152 } ); 1185 } );
1153 1186
1154 /* Now verify the remote credentials are valid -- only simple tests here */ 1187 /* Now verify the remote credentials are valid -- only simple tests here */
1155 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1), 1188 CHECK_FCT_DO( fd_tls_verify_credentials(conn->cc_tls_para.session, conn, 1),
1156 { 1189 {
1157 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ ); 1190 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), );
1158 gnutls_deinit(conn->cc_tls_para.session); 1191 fd_cnx_markerror(conn);
1159 return EINVAL; 1192 return EINVAL;
1160 }); 1193 });
1161 } 1194 }
1162
1163 /* Mark the connection as protected from here */
1164 conn->cc_tls = 1;
1165 1195
1166 /* Multi-stream TLS: handshake other streams as well */ 1196 /* Multi-stream TLS: handshake other streams as well */
1167 if (conn->cc_sctp_para.pairs > 1) { 1197 if (conn->cc_sctp_para.pairs > 1) {
1168 #ifndef DISABLE_SCTP 1198 #ifndef DISABLE_SCTP
1169 /* Resume all additional sessions from the master one. */ 1199 /* Resume all additional sessions from the master one. */
1182 1212
1183 /* Retrieve TLS credentials of the remote peer, after handshake */ 1213 /* Retrieve TLS credentials of the remote peer, after handshake */
1184 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) 1214 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)
1185 { 1215 {
1186 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size); 1216 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);
1187 CHECK_PARAMS( conn && (conn->cc_tls) && cert_list && cert_list_size ); 1217 CHECK_PARAMS( conn && (conn->cc_status & CC_STATUS_TLS) && cert_list && cert_list_size );
1188 1218
1189 /* This function only works for X.509 certificates. */ 1219 /* This function only works for X.509 certificates. */
1190 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 ); 1220 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 );
1191 1221
1192 *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size); 1222 *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size);
1199 1229
1200 return 0; 1230 return 0;
1201 } 1231 }
1202 1232
1203 /* 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. */ 1233 /* 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. */
1234 /* if the altfifo has been set on this conn object, this function must not be called */
1204 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 1235 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)
1205 { 1236 {
1206 int ev; 1237 int ev;
1207 size_t ev_sz; 1238 size_t ev_sz;
1208 void * ev_data; 1239 void * ev_data;
1261 { 1292 {
1262 ssize_t ret; 1293 ssize_t ret;
1263 size_t sent = 0; 1294 size_t sent = 0;
1264 TRACE_ENTRY("%p %p %zd", conn, buf, len); 1295 TRACE_ENTRY("%p %p %zd", conn, buf, len);
1265 do { 1296 do {
1266 if (conn->cc_tls) { 1297 if (conn->cc_status & CC_STATUS_TLS) {
1267 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN ); 1298 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), );
1268 } else { 1299 } else {
1269 CHECK_SYS( ret = fd_cnx_s_send(conn, buf + sent, len - sent) ); /* better to replace with sendmsg for atomic sending? */ 1300 /* Maybe better to replace this call with sendmsg for atomic sending? */
1270 } 1301 CHECK_SYS_DO( ret = fd_cnx_s_send(conn, buf + sent, len - sent), );
1302 }
1303 if (ret <= 0)
1304 return ENOTCONN;
1305
1271 sent += ret; 1306 sent += ret;
1272 } while ( sent < len ); 1307 } while ( sent < len );
1273 return 0; 1308 return 0;
1274 } 1309 }
1275 1310
1276 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */ 1311 /* Send a message -- this is synchronous -- and we assume it's never called by several threads at the same time, so we don't protect. */
1277 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, int ordered) 1312 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len, int ordered)
1278 { 1313 {
1279 TRACE_ENTRY("%p %p %zd %i", conn, buf, len, ordered); 1314 TRACE_ENTRY("%p %p %zd %i", conn, buf, len, ordered);
1280 1315
1281 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! conn->cc_goterror) && buf && len); 1316 CHECK_PARAMS(conn && (conn->cc_socket > 0) && (! (conn->cc_status & CC_STATUS_ERROR)) && buf && len);
1282 1317
1283 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id); 1318 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, (conn->cc_status & CC_STATUS_TLS) ? "TLS-protected ":"", conn->cc_id);
1284 1319
1285 switch (conn->cc_proto) { 1320 switch (conn->cc_proto) {
1286 case IPPROTO_TCP: 1321 case IPPROTO_TCP:
1287 CHECK_FCT( send_simple(conn, buf, len) ); 1322 CHECK_FCT( send_simple(conn, buf, len) );
1288 break; 1323 break;
1289 1324
1290 #ifndef DISABLE_SCTP 1325 #ifndef DISABLE_SCTP
1291 case IPPROTO_SCTP: { 1326 case IPPROTO_SCTP: {
1292 int multistr = 0; 1327 int multistr = 0;
1293 1328
1294 if ((!ordered) && (conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1))) { 1329 if ((!ordered) && (conn->cc_sctp_para.str_out > 1) && ((! (conn->cc_status & CC_STATUS_TLS)) || (conn->cc_sctp_para.pairs > 1))) {
1295 /* Update the id of the stream we will send this message on */ 1330 /* Update the id of the stream we will send this message on */
1296 conn->cc_sctp_para.next += 1; 1331 conn->cc_sctp_para.next += 1;
1297 conn->cc_sctp_para.next %= (conn->cc_tls ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out); 1332 conn->cc_sctp_para.next %= ((conn->cc_status & CC_STATUS_TLS) ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);
1298 multistr = 1; 1333 multistr = 1;
1299 } 1334 }
1300 1335
1301 if ((!multistr) || (conn->cc_sctp_para.next == 0)) { 1336 if ((!multistr) || (conn->cc_sctp_para.next == 0)) {
1302 CHECK_FCT( send_simple(conn, buf, len) ); 1337 CHECK_FCT( send_simple(conn, buf, len) );
1303 } else { 1338 } else {
1304 if (!conn->cc_tls) { 1339 if (!(conn->cc_status & CC_STATUS_TLS)) {
1305 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_closing), { conn->cc_goterror = 1; return ENOTCONN; } ); 1340 CHECK_FCT_DO( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len, &conn->cc_status), { fd_cnx_markerror(conn); return ENOTCONN; } );
1306 } else { 1341 } else {
1307 /* push the record to the appropriate session */ 1342 /* push the record to the appropriate session */
1308 ssize_t ret; 1343 ssize_t ret;
1309 size_t sent = 0; 1344 size_t sent = 0;
1310 ASSERT(conn->cc_sctps_data.array != NULL); 1345 ASSERT(conn->cc_sctps_data.array != NULL);
1311 do { 1346 do {
1312 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), return ENOTCONN ); 1347 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_sctps_data.array[conn->cc_sctp_para.next].session, buf + sent, len - sent), );
1348 if (ret <= 0)
1349 return ENOTCONN;
1350
1313 sent += ret; 1351 sent += ret;
1314 } while ( sent < len ); 1352 } while ( sent < len );
1315 } 1353 }
1316 } 1354 }
1317 } 1355 }
1318 break; 1356 break;
1319 #endif /* DISABLE_SCTP */ 1357 #endif /* DISABLE_SCTP */
1320 1358
1321 default: 1359 default:
1322 TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto); 1360 TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);
1361 ASSERT(0);
1323 return ENOTSUP; /* or EINVAL... */ 1362 return ENOTSUP; /* or EINVAL... */
1324 } 1363 }
1325 1364
1326 return 0; 1365 return 0;
1327 } 1366 }
1336 { 1375 {
1337 TRACE_ENTRY("%p", conn); 1376 TRACE_ENTRY("%p", conn);
1338 1377
1339 CHECK_PARAMS_DO(conn, return); 1378 CHECK_PARAMS_DO(conn, return);
1340 1379
1341 conn->cc_closing = 1; 1380 conn->cc_status |= CC_STATUS_CLOSING;
1342 1381
1343 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */ 1382 /* Initiate shutdown of the TLS session(s): call gnutls_bye(WR), then read until error */
1344 if (conn->cc_tls) { 1383 if (conn->cc_status & CC_STATUS_TLS) {
1345 #ifndef DISABLE_SCTP 1384 #ifndef DISABLE_SCTP
1346 if (conn->cc_sctp_para.pairs > 1) { 1385 if (conn->cc_sctp_para.pairs > 1) {
1347 if (! conn->cc_goterror ) { 1386 if (! (conn->cc_status & CC_STATUS_ERROR )) {
1348 /* Bye on master session */ 1387 /* Bye on master session */
1349 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ ); 1388 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
1350 1389 }
1390
1391 if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
1351 /* and other stream pairs */ 1392 /* and other stream pairs */
1352 fd_sctps_bye(conn); 1393 fd_sctps_bye(conn);
1353 1394 }
1395
1396 if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
1354 /* Now wait for all decipher threads to terminate */ 1397 /* Now wait for all decipher threads to terminate */
1355 fd_sctps_waitthreadsterm(conn); 1398 fd_sctps_waitthreadsterm(conn);
1356 } else { 1399 } else {
1357 /* Abord the threads, the connection is dead already */ 1400 /* Abord the threads, the connection is dead already */
1358 fd_sctps_stopthreads(conn); 1401 fd_sctps_stopthreads(conn);
1359 } 1402 }
1360 1403
1361 /* Deinit gnutls resources */ 1404 /* Deinit gnutls resources */
1362 fd_sctps_gnutls_deinit_others(conn); 1405 fd_sctps_gnutls_deinit_others(conn);
1363 gnutls_deinit(conn->cc_tls_para.session); 1406 if (conn->cc_tls_para.session) {
1407 gnutls_deinit(conn->cc_tls_para.session);
1408 conn->cc_tls_para.session = NULL;
1409 }
1364 1410
1365 /* Destroy the wrapper (also stops the demux thread) */ 1411 /* Destroy the wrapper (also stops the demux thread) */
1366 fd_sctps_destroy(conn); 1412 fd_sctps_destroy(conn);
1367 1413
1368 } else { 1414 } else {
1369 #endif /* DISABLE_SCTP */ 1415 #endif /* DISABLE_SCTP */
1370 /* We are not using the sctps wrapper layer */ 1416 /* We are not using the sctps wrapper layer */
1371 if (! conn->cc_goterror ) { 1417 if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
1372 /* Master session */ 1418 /* Master session */
1373 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), /* Continue */ ); 1419 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_WR), fd_cnx_markerror(conn) );
1374 1420 }
1421
1422 if (! (conn->cc_status & CC_STATUS_ERROR ) ) {
1375 /* In this case, just wait for thread rcvthr_tls_single to terminate */ 1423 /* In this case, just wait for thread rcvthr_tls_single to terminate */
1376 if (conn->cc_rcvthr != (pthread_t)NULL) { 1424 if (conn->cc_rcvthr != (pthread_t)NULL) {
1377 CHECK_POSIX_DO( pthread_join(conn->cc_rcvthr, NULL), /* continue */ ); 1425 CHECK_POSIX_DO( pthread_join(conn->cc_rcvthr, NULL), /* continue */ );
1378 conn->cc_rcvthr = (pthread_t)NULL; 1426 conn->cc_rcvthr = (pthread_t)NULL;
1379 } 1427 }
1381 /* Cancel the receiver thread in case it did not already terminate */ 1429 /* Cancel the receiver thread in case it did not already terminate */
1382 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ ); 1430 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );
1383 } 1431 }
1384 1432
1385 /* Free the resources of the TLS session */ 1433 /* Free the resources of the TLS session */
1386 gnutls_deinit(conn->cc_tls_para.session); 1434 if (conn->cc_tls_para.session) {
1435 gnutls_deinit(conn->cc_tls_para.session);
1436 conn->cc_tls_para.session = NULL;
1437 }
1387 1438
1388 #ifndef DISABLE_SCTP 1439 #ifndef DISABLE_SCTP
1389 } 1440 }
1390 #endif /* DISABLE_SCTP */ 1441 #endif /* DISABLE_SCTP */
1391 } 1442 }
"Welcome to our mercurial repository"