Mercurial > hg > freeDiameter
changeset 22:0b3b46da2c12
Progress on server code
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Mon, 19 Oct 2009 18:43:09 +0900 |
parents | bef197f6826f |
children | db6c40b8b307 |
files | doc/freediameter.conf.sample freeDiameter/CMakeLists.txt freeDiameter/cnxctx.c freeDiameter/config.c freeDiameter/fD.h freeDiameter/fdd.y freeDiameter/main.c freeDiameter/p_expiry.c freeDiameter/p_psm.c freeDiameter/peers.c freeDiameter/sctp.c freeDiameter/server.c freeDiameter/tcp.c include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h libfreeDiameter/log.c |
diffstat | 16 files changed, 689 insertions(+), 262 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/freediameter.conf.sample Thu Oct 08 20:05:16 2009 +0900 +++ b/doc/freediameter.conf.sample Mon Oct 19 18:43:09 2009 +0900 @@ -183,11 +183,11 @@ # No_TCP; No_SCTP; No_IP; No_IPv6; Prefer_TCP; TLS_old_method; # No_TLS; # assume transparent security instead of TLS # Port = 3868; # The port to connect to -# SCTP_streams = 30; # TcTimer = 30; # TwTimer = 30; # ConnectTo = "202.249.37.5"; # ConnectTo = "2001:200:903:2::202:1"; +# TLS_Prio = "NORMAL"; # Examples: #ConnectPeer = "aaa.wide.ad.jp"; #ConnectPeer = "old.diameter.serv" { TcTimer = 60; TLS_old_method; No_SCTP; } ; @@ -200,11 +200,11 @@ Port = 3866; SecPort = 3867; TLS_old_method; -No_IP; +No_SCTP; Prefer_TCP; SCTP_streams = 50; -ListenOn = "202.249.37.5"; -ListenOn = "2001:200:903:2::202:1"; +#ListenOn = "202.249.37.5"; +#ListenOn = "2001:200:903:2::202:1"; TcTimer = 60; TwTimer = 6; NoRelay; @@ -212,7 +212,7 @@ LoadExtension = "extensions/dict_nasreq.fdx"; LoadExtension = "extensions/dict_eap.fdx"; ConnectPeer = "jules.nautilus6.org" ; -ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ; +ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; } ; TLS_Cred = "/etc/openssl-ca/clients/certs/test.cert" , "/etc/openssl-ca/clients/privkeys/test.key.pem"; TLS_CA = "/etc/openssl-ca/public-www/cacert.pem"; # TLS_CRL = "/etc/openssl-ca/public-www/crl.pem";
--- a/freeDiameter/CMakeLists.txt Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Mon Oct 19 18:43:09 2009 +0900 @@ -20,6 +20,7 @@ p_expiry.c p_psm.c server.c + tcp.c ) IF(NOT DISABLE_SCTP)
--- a/freeDiameter/cnxctx.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/cnxctx.c Mon Oct 19 18:43:09 2009 +0900 @@ -35,21 +35,53 @@ #include "fD.h" +/* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations . + * They are used to hide the details of the processing to the higher layers of the daemon. + * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported. + */ + +/* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */ + +/* Lifetime of a cnxctx object: + * 1) Creation + * a) a server socket: + * - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp + * - start listening incoming connections: fd_cnx_serv_listen + * - accept new clients with fd_cnx_serv_accept. + * b) a client socket: + * - connect to a remote server with fd_cnx_cli_connect + * + * 2) Initialization + * - if TLS is started first, call fd_cnx_handshake + * - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later. + * + * 3) Usage + * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not). + * - fd_cnx_recv_setaltfifo : when a message is received, the event is sent to an external fifo list. fd_cnx_receive does not work when the alt_fifo is set. + * - fd_cnx_getid : retrieve a descriptive string for the connection (for debug) + * - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn) + * - fd_cnx_getcred : get the remote peer TLS credentials, after handshake + * - fd_cnx_getendpoints : get the endpoints (IP) of the connection + * + * 4) End + * - fd_cnx_destroy + */ + /* The connection context structure */ struct cnxctx { + char cc_id[60]; /* The name of this connection */ + char cc_remid[60]; /* Id of remote peer */ + int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */ - + int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ int cc_tls; /* Is TLS already started ? */ - + struct fifo * cc_events; /* Events occuring on the connection */ pthread_t cc_mgr; /* manager thread for the connection */ struct fifo * cc_incoming; /* FIFO queue of messages received on the connection */ - - uint16_t cc_port; /* Remote port of the connection, when we are client */ - struct fd_list cc_ep_remote; /* The remote address(es) of the connection */ - struct fd_list cc_ep_local; /* The local address(es) of the connection */ - + struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_MSG_RECV events to. */ + /* If cc_proto == SCTP */ struct { int str_out;/* Out streams */ @@ -57,13 +89,13 @@ int pairs; /* max number of pairs ( = min(in, out)) */ int next; /* # of stream the next message will be sent to */ } cc_sctp_para; - + /* If cc_tls == true */ struct { int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */ gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ } cc_tls_para; - + /* If both conditions */ struct { gnutls_session_t *res_sessions; /* Sessions of other pairs of streams, resumed from the first */ @@ -72,62 +104,232 @@ }; -/* Initialize a context structure from a socket */ -struct cnxctx * fd_cnx_init(int sock, int proto) +/* Initialize a context structure */ +static struct cnxctx * fd_cnx_init(int full) { struct cnxctx * conn = NULL; - - TRACE_ENTRY("%d %d", sock, proto); - CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL); - + + TRACE_ENTRY("%d", full); + CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL ); memset(conn, 0, sizeof(struct cnxctx)); - - conn->cc_socket = sock; - conn->cc_proto = proto; - - fd_list_init(&conn->cc_ep_remote, conn); - fd_list_init(&conn->cc_ep_local, conn); + + if (full) { + CHECK_FCT_DO( fd_fifo_new ( &conn->cc_events ), return NULL ); + CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL ); + } + + return conn; +} + +/* Create and bind a server socket to the given endpoint and port */ +struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep) +{ + struct cnxctx * cnx = NULL; + sSS dummy; + sSA * sa = (sSA *) &dummy; + + TRACE_ENTRY("%hu %d %p", port, family, ep); + + CHECK_PARAMS_DO( port, return NULL ); + CHECK_PARAMS_DO( ep || family, return NULL ); + CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL ); + CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL ); + + /* The connection object */ + CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); + + /* Prepare the socket address information */ + if (ep) { + memcpy(sa, &ep->ss, sizeof(sSS)); + } else { + memset(&dummy, 0, sizeof(dummy)); + sa->sa_family = family; + } + if (sa->sa_family == AF_INET) { + ((sSA4 *)sa)->sin_port = htons(port); + } else { + ((sSA6 *)sa)->sin6_port = htons(port); + } + + /* Create the socket */ + CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sizeof(sSS) ), goto error ); + + /* Generate the name for the connection object */ + { + char addrbuf[INET6_ADDRSTRLEN]; + int rc; + rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); + if (rc) + snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); + snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv TCP [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); + } + + cnx->cc_proto = IPPROTO_TCP; + + return cnx; + +error: + fd_cnx_destroy(cnx); + return NULL; +} +#ifndef DISABLE_SCTP +struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list) +{ + struct cnxctx * cnx = NULL; + sSS dummy; + sSA * sa = (sSA *) &dummy; + + TRACE_ENTRY("%hu %p", port, ep_list); + + CHECK_PARAMS_DO( port, return NULL ); + + /* The connection object */ + CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); + + /* Create the socket */ + CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error ); + + /* Generate the name for the connection object */ + snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv SCTP :%hu (%d)", port, cnx->cc_socket); + + cnx->cc_proto = IPPROTO_SCTP; + + return cnx; + +error: + fd_cnx_destroy(cnx); + return NULL; +} +#endif /* DISABLE_SCTP */ + +/* Allow clients to connect on the server socket */ +int fd_cnx_serv_listen(struct cnxctx * conn) +{ + CHECK_PARAMS( conn ); + + switch (conn->cc_proto) { + case IPPROTO_TCP: + CHECK_FCT(fd_tcp_listen(conn->cc_socket)); + break; + + case IPPROTO_SCTP: + CHECK_FCT(fd_sctp_listen(conn->cc_socket)); + break; + + default: + CHECK_PARAMS(0); + } + + return 0; +} + +/* Accept a client (blocking until a new client connects) -- cancelable */ +struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv) +{ + struct cnxctx * cli = NULL; + sSS ss; + socklen_t ss_len = sizeof(ss); + int cli_sock = 0; + struct fd_endpoint * ep; + + TRACE_ENTRY("%p", serv); + CHECK_PARAMS_DO(serv, return NULL); - if (proto == IPPROTO_SCTP) { -#ifndef DISABLE_SCTP - CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ), - { free(conn); return NULL; } ); - conn->cc_sctp_para.pairs = (conn->cc_sctp_para.str_out < conn->cc_sctp_para.str_in) ? conn->cc_sctp_para.str_out : conn->cc_sctp_para.str_in; -#else /* DISABLE_SCTP */ - ASSERT(0); -#endif /* DISABLE_SCTP */ + CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); + + if (TRACE_BOOL(INFO)) { + fd_log_debug("%s - new client [", fd_cnx_getid(serv)); + sSA_DUMP_NODE( &ss, AI_NUMERICHOST ); + fd_log_debug("] connected.\n"); } - return conn; + CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } ); + cli->cc_socket = cli_sock; + cli->cc_proto = serv->cc_proto; + + /* Generate the name for the connection object */ + { + char addrbuf[INET6_ADDRSTRLEN]; + char portbuf[10]; + int rc; + + /* Numeric values for debug */ + rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); + if (rc) + snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); + + snprintf(cli->cc_id, sizeof(cli->cc_id), "Client %s [%s]:%s (%d) / serv (%d)", + IPPROTO_NAME(cli->cc_proto), + addrbuf, portbuf, + cli->cc_socket, serv->cc_socket); + + /* Textual value for log messages */ + rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, NI_NUMERICHOST); + if (rc) + snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); + } + + /* SCTP-specific handlings */ +#ifndef DISABLE_SCTP + if (cli->cc_proto == IPPROTO_SCTP) { + /* Retrieve the number of streams */ + CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out ), goto error ); + if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in) + cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; + else + cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in; + } +#endif /* DISABLE_SCTP */ + + return cli; +error: + fd_cnx_destroy(cli); + return NULL; +} + +/* Client side: connect to a remote server */ +struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa, socklen_t addrlen) +{ + + TODO("..."); + return NULL; +} + +/* Return a string describing the connection, for debug */ +char * fd_cnx_getid(struct cnxctx * conn) +{ + CHECK_PARAMS_DO( conn, return "" ); + return conn->cc_id; } /* Start receving messages in clear (no TLS) on the connection */ int fd_cnx_start_clear(struct cnxctx * conn) { - + TODO("..."); return ENOTSUP; } /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ -int fd_cnx_handshake(struct cnxctx * conn, int mode) +int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority) { TRACE_ENTRY( "%p %d", conn, mode); CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) ); - + /* Save the mode */ conn->cc_tls_para.mode = mode; - + /* Create the master session context */ CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); - + /* Set the algorithm suite */ + TODO("Use overwrite priority if non NULL"); CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); - + /* Set the credentials of this side of the connection */ CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); - + /* Request the remote credentials as well */ if (mode == GNUTLS_SERVER) { gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE); @@ -145,23 +347,23 @@ ASSERT(0); #endif /* DISABLE_SCTP */ } - + /* Handshake master session */ { int ret; CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session), { if (TRACE_BOOL(INFO)) { - fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret)); + fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); } return EINVAL; } ); - + /* Now verify the remote credentials are valid -- only simple test here */ CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL ); if (ret) { if (TRACE_BOOL(INFO)) { - fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket); + fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id); if (ret & GNUTLS_CERT_INVALID) fd_log_debug(" - The certificate is not trusted (unknown CA?)\n"); if (ret & GNUTLS_CERT_REVOKED) @@ -176,30 +378,46 @@ return EINVAL; } } - + /* Other sessions in case of multi-stream SCTP are resumed from the master */ if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { #ifndef DISABLE_SCTP TODO("Init and resume all additional sessions from the master one."); #endif /* DISABLE_SCTP */ } - + + TODO("Start the connection state machine thread"); + return 0; } /* Retrieve TLS credentials of the remote peer, after handshake */ int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) { - + TODO("..."); return ENOTSUP; } -/* Get the list of endpoints (IP addresses) of the remote peer on this object */ -int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * senti) +/* Get the list of endpoints (IP addresses) of the local and remote peers on this conenction */ +int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) { + TRACE_ENTRY("%p %p %p", conn, local, remote); + CHECK_PARAMS(conn); - TODO("..."); + if (local) { + /* Retrieve the local endpoint(s) of the connection */ + TODO("TCP : getsockname"); + TODO("SCTP: sctp_getladdrs / _sctp_getboundaddrs (waaad)"); + } + + if (remote) { + /* Retrieve the peer endpoint(s) of the connection */ + TODO("TCP : getpeername"); + TODO("SCTP: sctp_getpaddrs"); + + } + return ENOTSUP; } @@ -207,25 +425,35 @@ /* Get a string describing the remote peer address (ip address or fqdn) */ char * fd_cnx_getremoteid(struct cnxctx * conn) { - - TODO("..."); - return NULL; + CHECK_PARAMS_DO( conn, return "" ); + return conn->cc_remid; } /* Receive next message. if timeout is not NULL, wait only until timeout */ int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) { - + TODO("..."); return ENOTSUP; } +/* Set / reset alternate FIFO list to send FDEVP_CNX_MSG_RECV to when message is received */ +int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) +{ + TRACE_ENTRY( "%p %p", conn, alt_fifo ); + CHECK_PARAMS( conn ); + + /* Let's cross fingers that there is no race condition here... */ + conn->cc_alt = alt_fifo; + + return 0; +} /* Send a message */ int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) { - + TODO("..."); return ENOTSUP; } @@ -234,8 +462,31 @@ /* Destroy a conn structure, and shutdown the socket */ void fd_cnx_destroy(struct cnxctx * conn) { + TRACE_ENTRY("%p", conn); - TODO("..."); + CHECK_PARAMS_DO(conn, return); + + TODO("End TLS session(s) if started"); + + TODO("Stop manager thread if running"); + + /* Shut the connection down */ + if (conn->cc_socket > 0) { + shutdown(conn->cc_socket, SHUT_RDWR); + } + + TODO("Empty FIFO queues"); + + /* Destroy FIFO lists */ + if (conn->cc_events) + CHECK_FCT_DO( fd_fifo_del ( &conn->cc_events ), /* continue */ ); + if (conn->cc_incoming) + CHECK_FCT_DO( fd_fifo_del ( &conn->cc_incoming ), /* continue */ ); + + /* Free the object */ + free(conn); + + /* Done! */ return; }
--- a/freeDiameter/config.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/config.c Mon Oct 19 18:43:09 2009 +0900 @@ -228,6 +228,25 @@ return EINVAL; } + /* Validate local endpoints */ + if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) { + struct fd_list * li; + for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + if ( (fd_g_config->cnf_flags.no_ip4 && (ep->ss.ss_family == AF_INET)) + ||(fd_g_config->cnf_flags.no_ip6 && (ep->ss.ss_family == AF_INET6)) ) { + li = li->prev; + fd_list_unlink(&ep->chain); + if (TRACE_BOOL(INFO)) { + fd_log_debug("Info: Removing local address conflicting with the flags no_IP / no_IP6 : "); + sSA_DUMP_NODE( &ep->ss, AI_NUMERICHOST ); + fd_log_debug("\n"); + } + free(ep); + } + } + } + /* Configure TLS default parameters */ if (! fd_g_config->cnf_sec_data.prio_string) { const char * err_pos = NULL; @@ -238,14 +257,17 @@ { TRACE_DEBUG(INFO, "Error in priority string at position : %s", err_pos); return EINVAL; } ); } if (! fd_g_config->cnf_sec_data.dh_bits) { - TRACE_DEBUG(FULL, "Generating DH parameters..."); + if (TRACE_BOOL(INFO)) { + fd_log_debug("Generating Diffie-Hellman parameters of size %d (this takes a few seconds)... ", GNUTLS_DEFAULT_DHBITS); + } CHECK_GNUTLS_DO( gnutls_dh_params_generate2( fd_g_config->cnf_sec_data.dh_cache, GNUTLS_DEFAULT_DHBITS), { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); - TRACE_DEBUG(FULL, "DH parameters generated."); + if (TRACE_BOOL(INFO)) { + fd_log_debug("Done!\n"); + } } - return 0; }
--- a/freeDiameter/fD.h Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/fD.h Mon Oct 19 18:43:09 2009 +0900 @@ -156,11 +156,15 @@ /* request to terminate this peer : disconnect, requeue all messages */ ,FDEVP_TERMINATE + /* A connection object has received a message -- stored in event->data */ + ,FDEVP_CNX_MSG_RECV + /* A message was received in the peer */ ,FDEVP_MSG_INCOMING /* The PSM state is expired */ ,FDEVP_PSM_TIMEOUT + }; const char * fd_pev_str(int event); #define CHECK_EVENT( _e ) \ @@ -195,22 +199,34 @@ /* Server sockets */ void fd_servers_dump(); int fd_servers_start(); -void fd_servers_stop(); +int fd_servers_stop(); /* Connection contexts */ -struct cnxctx * fd_cnx_init(int sock, int proto); +struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep); +struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list); +int fd_cnx_serv_listen(struct cnxctx * conn); +struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv); +struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa, socklen_t addrlen); +char * fd_cnx_getid(struct cnxctx * conn); int fd_cnx_start_clear(struct cnxctx * conn); -int fd_cnx_handshake(struct cnxctx * conn, int mode); +int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority); int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size); -int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * senti); +int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote); char * fd_cnx_getremoteid(struct cnxctx * conn); int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len); +int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */ int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len); void fd_cnx_destroy(struct cnxctx * conn); +/* TCP */ +int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen ); +int fd_tcp_listen( int sock ); + /* SCTP */ #ifndef DISABLE_SCTP -int fd_sctp_create_bind_server( int * socket, uint16_t port ); +int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ); +int fd_sctp_listen( int sock ); + int fd_sctp_get_str_info( int socket, int *in, int *out ); #endif /* DISABLE_SCTP */
--- a/freeDiameter/fdd.y Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/fdd.y Mon Oct 19 18:43:09 2009 +0900 @@ -335,6 +335,7 @@ /* Now destroy any content in the structure */ free(fddpi.pi_diamid); + free(fddpi.pi_sec_data.priority); while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) { struct fd_list * li = fddpi.pi_endpoints.next; fd_list_unlink(li); @@ -414,16 +415,14 @@ { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); fddpi.pi_port = (uint16_t)$4; } - | peerparams SCTPSTREAMS '=' INTEGER ';' - { - CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16), - { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - fddpi.pi_streams = (uint16_t)$4; - } | peerparams TCTIMER '=' INTEGER ';' { fddpi.pi_tctimer = $4; } + | peerparams TLS_PRIO '=' QSTRING ';' + { + fddpi.pi_sec_data.priority = $4; + } | peerparams TWTIMER '=' INTEGER ';' { fddpi.pi_twtimer = $4;
--- a/freeDiameter/main.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/main.c Mon Oct 19 18:43:09 2009 +0900 @@ -50,6 +50,7 @@ static struct fd_config conf; struct fd_config * fd_g_config = &conf; +/* gcrypt functions to support posix threads */ GCRY_THREAD_OPTION_PTHREAD_IMPL; /* freeDiameter starting point */ @@ -104,6 +105,9 @@ /* Load the dynamic extensions */ CHECK_FCT( fd_ext_load() ); + /* Start the servers */ + CHECK_FCT( fd_servers_start() ); + /* Start the peer state machines */ CHECK_FCT( fd_psm_start() ); @@ -153,6 +157,7 @@ TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon is stopping..."); /* cleanups */ + CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ ); TODO("Stop dispatch thread(s) properly (no cancel yet)"); CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ ); TODO("Stop dispatch & routing threads");
--- a/freeDiameter/p_expiry.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/p_expiry.c Mon Oct 19 18:43:09 2009 +0900 @@ -46,14 +46,13 @@ static void * gc_th_fct(void * arg) { - fd_log_threadname ( "Peers/garbage" ); - TRACE_ENTRY( "" ); + fd_log_threadname ( "Peers/garb. col." ); + TRACE_ENTRY( "%p", arg ); do { struct fd_list * li, purge = FD_LIST_INITIALIZER(purge); - pthread_testcancel(); - sleep(GC_TIME); + sleep(GC_TIME); /* sleep is a cancellation point */ /* Now check in the peers list if any peer can be deleted */ CHECK_FCT_DO( pthread_rwlock_wrlock(&fd_g_peers_rw), goto error ); @@ -95,7 +94,7 @@ static void * exp_th_fct(void * arg) { fd_log_threadname ( "Peers/expire" ); - TRACE_ENTRY( "" ); + TRACE_ENTRY( "%p", arg ); CHECK_POSIX_DO( pthread_mutex_lock(&exp_mtx), goto error ); pthread_cleanup_push( fd_cleanup_mutex, &exp_mtx ); @@ -123,7 +122,7 @@ if ( TS_IS_INFERIOR( &now, &first->p_exp_timer ) ) { CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &exp_mtx, &first->p_exp_timer ), - ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */, + ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */, /* on other error, */ goto error ); /* on wakeup, loop */
--- a/freeDiameter/p_psm.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/p_psm.c Mon Oct 19 18:43:09 2009 +0900 @@ -54,8 +54,9 @@ switch (event) { #define case_str( _val )\ case _val : return #_val + case_str(FDEVP_DUMP_ALL); case_str(FDEVP_TERMINATE); - case_str(FDEVP_DUMP_ALL); + case_str(FDEVP_CNX_MSG_RECV); case_str(FDEVP_MSG_INCOMING); case_str(FDEVP_PSM_TIMEOUT); @@ -240,6 +241,8 @@ psm_end: pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ + pthread_detach(peer->p_psm); + peer->p_psm = (pthread_t)NULL; return NULL; } @@ -266,6 +269,7 @@ { TRACE_ENTRY("%p", peer); CHECK_PARAMS( CHECK_PEER(peer) ); + if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) ); } else {
--- a/freeDiameter/peers.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/peers.c Mon Oct 19 18:43:09 2009 +0900 @@ -100,11 +100,14 @@ p->p_hdr.info.pi_flags.exp = info->pi_flags.exp; p->p_hdr.info.pi_lft = info->pi_lft; - p->p_hdr.info.pi_streams = info->pi_streams; p->p_hdr.info.pi_port = info->pi_port; p->p_hdr.info.pi_tctimer = info->pi_tctimer; p->p_hdr.info.pi_twtimer = info->pi_twtimer; + if (info->pi_sec_data.priority) { + CHECK_MALLOC( p->p_hdr.info.pi_sec_data.priority = strdup(info->pi_sec_data.priority) ); + } + /* Move the items from one list to the other */ if (info->pi_endpoints.next) while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) { @@ -113,6 +116,7 @@ fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li); } + /* The internal data */ if (orig_dbg) { CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) ); @@ -228,7 +232,7 @@ } if (p->p_cnxctx) { - TODO("destroy p->p_cnxctx"); + fd_cnx_destroy(p->p_cnxctx); } if (p->p_cb) @@ -292,6 +296,7 @@ } list_empty = FD_IS_LIST_EMPTY(&fd_g_peers); CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ ); + CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) ); } if (!list_empty) {
--- a/freeDiameter/sctp.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/sctp.c Mon Oct 19 18:43:09 2009 +0900 @@ -35,16 +35,27 @@ #include "fD.h" -int fd_sctp_create_bind_server( int * socket, uint16_t port ) +/* Create a socket server and bind it according to daemon s configuration */ +int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port ) { TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); return ENOTSUP; } +/* Allow clients connections on server sockets */ +int fd_sctp_listen( int sock ) +{ + TRACE_ENTRY("%d", sock); + CHECK_SYS( listen(sock, 5) ); + return 0; +} + +/* Retrieve streams information from a connected association */ int fd_sctp_get_str_info( int socket, int *in, int *out ) { TODO("Retrieve streams info from the socket"); return ENOTSUP; } +
--- a/freeDiameter/server.c Thu Oct 08 20:05:16 2009 +0900 +++ b/freeDiameter/server.c Mon Oct 19 18:43:09 2009 +0900 @@ -35,47 +35,67 @@ #include "fD.h" -/* This file contains the server (listening) part of the daemon */ +/* Server (listening) part of the daemon */ -struct fd_list FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS); /* The list of all server sockets */ -/* We don't need to protect this list, it is only accessed from the main thread. */ +struct fd_list FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS); /* The list of all server objects */ +/* We don't need to protect this list, it is only accessed from the main daemon thread. */ -/* Server (listening socket) information */ +/* Servers information */ struct server { struct fd_list chain; /* link in the FD_SERVERS list */ - int socket; /* server socket, or <= 0 */ - + struct cnxctx * conn; /* server connection context (listening socket) */ int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ int secur; /* TLS is started immediatly after connection ? */ - pthread_t serv_thr; /* The thread listening for new connections */ - int serv_status; /* 0 : not created; 1 : running; 2 : terminated */ + pthread_t thr; /* The thread listening for new connections */ + int status; /* 0 : not created; 1 : running; 2 : terminated */ - pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients connected to the thread */ - struct fd_list clients; /* The list of clients connecting to this server, which information is not yet known */ - - char * serv_name; /* A string to identify this server */ + struct fd_list clients; /* List of clients connected to this server, not yet identified */ + pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients */ }; -/* Client (connected remote endpoint, not received CER yet) information */ +/* Client information (connecting peer for which we don't have the CER yet) */ struct client { struct fd_list chain; /* link in the server's list of clients */ - struct cnxctx *conn; /* Parameters of the connection; sends its events to the ev fifo bellow */ - struct timespec ts; /* Delay for receiving CER: INCNX_TIMEOUT */ - pthread_t cli_thr; /* connection state machine (simplified PSM) */ -}; - -/* Parameter for the thread handling the new connected client, to avoid bloking the server thread */ -struct cli_fast { - struct server * serv; - int sock; - sSS ss; - socklen_t sslen; + struct cnxctx *conn; /* Parameters of the connection */ + struct timespec ts; /* Deadline for receiving CER (after INCNX_TIMEOUT) */ + pthread_t thr; /* connection state machine */ }; -static void * client_simple_psm(void * arg) +/* Dump all servers information */ +void fd_servers_dump() +{ + struct fd_list * li, *cli; + + fd_log_debug("Dumping servers list :\n"); + for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { + struct server * s = (struct server *)li; + fd_log_debug(" Serv %p '%s': %s, %s, %s\n", + s, fd_cnx_getid(s->conn), + IPPROTO_NAME( s->proto ), + s->secur ? "Secur" : "NotSecur", + (s->status == 0) ? "Thread not created" : + ((s->status == 1) ? "Thread running" : + ((s->status == 2) ? "Thread terminated" : + "Thread status unknown"))); + /* Dump the client list of this server */ + (void) pthread_mutex_lock(&s->clients_mtx); + for (cli = s->clients.next; cli != &s->clients; cli = cli->next) { + struct client * c = (struct client *)cli; + char bufts[128]; + fd_log_debug(" Connected: '%s' (timeout: %s)\n", + fd_cnx_getid(c->conn), + fd_log_time(&c->ts, bufts, sizeof(bufts))); + } + (void) pthread_mutex_unlock(&s->clients_mtx); + } +} + + +/* The state machine to handle incoming connection before the remote peer is identified */ +static void * client_sm(void * arg) { struct client * c = arg; struct server * s = NULL; @@ -87,10 +107,19 @@ s = c->chain.head->o; /* Name the current thread */ - { - char addr[128]; - snprintf(addr, sizeof(addr), "Srv %d/Cli %s", s->socket, fd_cnx_getremoteid(c->conn)); - fd_log_threadname ( addr ); + fd_log_threadname ( fd_cnx_getid(c->conn) ); + + /* Handshake if we are a secure server port, or start clear otherwise */ + if (s->secur) { + int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL); + if (ret != 0) { + if (TRACE_BOOL(INFO)) { + fd_log_debug("TLS handshake failed for client '%s', connection aborted.\n", fd_cnx_getid(c->conn)); + } + goto cleanup; + } + } else { + CHECK_FCT_DO( fd_cnx_start_clear(c->conn), goto cleanup ); } /* Set the timeout to receive the first message */ @@ -103,12 +132,22 @@ TODO("Message != CER => close"); TODO("Message == CER : "); TODO("Search matching peer"); - TODO("..."); + TODO("Send event to the peer"); - /* The end: we have freed the client structure already */ - TODO("Unlink the client structure"); - TODO(" pthread_detach(c->cli_thr); "); - TODO(" free(c); "); + /* The end */ +cleanup: + /* Unlink the client structure */ + CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), goto fatal_error ); + fd_list_unlink( &c->chain ); + CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), goto fatal_error ); + + /* Destroy the connection object if present */ + if (c->conn) + fd_cnx_destroy(c->conn); + + /* Detach the thread, cleanup the client structure */ + pthread_detach(pthread_self()); + free(c); return NULL; fatal_error: /* This has effect to terminate the daemon */ @@ -116,112 +155,46 @@ return NULL; } -/* This thread is called when a new client had just connected */ -static void * handle_client_fast(void * arg) -{ - struct cli_fast * cf = arg; - struct client * c = NULL; - - /* Name the current thread */ - ASSERT(arg); - { - char addr[128]; - int offset = snprintf(addr, sizeof(addr), "Srv %d/CliFast %d : ", cf->serv->socket, cf->sock); - int rc = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0); - if (rc) - memcpy(addr + offset, gai_strerror(rc), sizeof(addr) - offset); - - fd_log_threadname ( addr ); - - if (TRACE_BOOL(INFO)) { - fd_log_debug( "New connection %s, sock %d, from '%s'\n", cf->serv->serv_name, cf->sock, addr + offset); - } - } - - /* Create a client structure */ - CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto fatal_error ); - memset(c, 0, sizeof(struct client)); - fd_list_init(&c->chain, c); - - /* Create the connection context */ - CHECK_MALLOC_DO( c->conn = fd_cnx_init(cf->sock, cf->serv->proto), goto fatal_error ); - - /* In case we are a secure server, handshake now */ - if (cf->serv->secur) { - CHECK_FCT_DO( fd_cnx_handshake(c->conn, GNUTLS_CLIENT), goto cleanup ); - } - - - /* Save the client in the list */ - CHECK_POSIX_DO( pthread_mutex_lock( &cf->serv->clients_mtx ), goto fatal_error ); - fd_list_insert_before(&cf->serv->clients, &c->chain); - CHECK_POSIX_DO( pthread_mutex_unlock( &cf->serv->clients_mtx ), goto fatal_error ); - - /* Start the client thread */ - CHECK_POSIX_DO( pthread_create( &c->cli_thr, NULL, client_simple_psm, c ), goto fatal_error ); - - /* We're done here */ - free(cf); - return NULL; - -cleanup: /* Clean all objects and return (minor error on the connection)*/ - if (c && c->conn) { - TODO( "Free the c->conn object & gnutls data" ); - } - - return NULL; - -fatal_error: /* This has effect to terminate the daemon */ - CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); - free(cf); - free(c); - return NULL; -} - -/* The thread for the server */ +/* The thread managing a server */ static void * serv_th(void * arg) { - struct server *sv = (struct server *)arg; - struct cli_fast cf; - pthread_attr_t attr; + struct server *s = (struct server *)arg; - CHECK_PARAMS_DO(sv, goto error); - fd_log_threadname ( sv->serv_name ); - sv->serv_status = 1; - - memset(&cf, 0, sizeof(struct cli_fast)); - cf.serv = sv; - - CHECK_POSIX_DO( pthread_attr_init(&attr), goto error ); - CHECK_POSIX_DO( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED), goto error ); + CHECK_PARAMS_DO(s, goto error); + fd_log_threadname ( fd_cnx_getid(s->conn) ); + s->status = 1; /* Accept incoming connections */ - CHECK_SYS_DO( listen(sv->socket, 5), goto error ); + CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error ); do { - struct cli_fast * ncf; - pthread_t thr; - - /* Re-init socket size */ - cf.sslen = sizeof(sSS); + struct client * c = NULL; + struct cnxctx * conn = NULL; /* Wait for a new client */ - CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error ); + CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error ); TRACE_DEBUG(FULL, "New connection accepted"); - /* Create the copy for the client thread */ - CHECK_MALLOC_DO( ncf = malloc(sizeof(struct cli_fast)), goto error ); - memcpy(ncf, &cf, sizeof(struct cli_fast)); + /* Create a client structure */ + CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto error ); + memset(c, 0, sizeof(struct client)); + fd_list_init(&c->chain, c); + c->conn = conn; - /* Create the thread to handle the new incoming connection */ - CHECK_POSIX_DO( pthread_create( &thr, &attr, handle_client_fast, ncf), goto error ); + /* Save the client in the list */ + CHECK_POSIX_DO( pthread_mutex_lock( &s->clients_mtx ), goto error ); + fd_list_insert_before(&s->clients, &c->chain); + CHECK_POSIX_DO( pthread_mutex_unlock( &s->clients_mtx ), goto error ); + + /* Start the client thread */ + CHECK_POSIX_DO( pthread_create( &c->thr, NULL, client_sm, c ), goto error ); } while (1); error: - if (sv) - sv->serv_status = 2; + if (s) + s->status = 2; /* Send error signal to the daemon */ TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); @@ -231,60 +204,29 @@ /* Create a new server structure */ -static struct server * new_serv( int proto, int secur, int socket ) +static struct server * new_serv( int proto, int secur ) { - char buf[32]; - char * sn = NULL; struct server * new; - /* Create the server debug name */ - buf[sizeof(buf) - 1] = '\0'; - snprintf(buf, sizeof(buf) - 1, "Serv %d (%s%s)", socket, IPPROTO_NAME( proto ), secur ? "s" : ""); - CHECK_MALLOC_DO( sn = strdup(buf), return NULL ); - /* New server structure */ CHECK_MALLOC_DO( new = malloc(sizeof(struct server)), return NULL ); memset(new, 0, sizeof(struct server)); fd_list_init(&new->chain, new); - new->socket = socket; new->proto = proto; new->secur = secur; CHECK_POSIX_DO( pthread_mutex_init(&new->clients_mtx, NULL), return NULL ); fd_list_init(&new->clients, new); - new->serv_name = sn; - return new; } -/* Dump all servers information */ -void fd_servers_dump() -{ - struct fd_list * li; - - fd_log_debug("Dumping servers list :\n"); - for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { - struct server * sv = (struct server *)li; - fd_log_debug(" Serv '%s': %s(%d), %s, %s, %s\n", - sv->serv_name, - (sv->socket > 0) ? "Open" : "Closed", sv->socket, - IPPROTO_NAME( sv->proto ), - sv->secur ? "Secur" : "NotSecur", - (sv->serv_status == 0) ? "Thread not created" : - ((sv->serv_status == 1) ? "Thread running" : - ((sv->serv_status == 2) ? "Thread terminated" : - "Thread status unknown"))); - /* Dump the client list */ - TODO("Dump client list"); - } -} - /* Start all the servers */ int fd_servers_start() { - int socket; - struct server * sv; + struct server * s; + + int empty_conf_ep = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints); /* SCTP */ if (!fd_g_config->cnf_flags.no_sctp) { @@ -293,12 +235,21 @@ #else /* DISABLE_SCTP */ /* Create the server on default port */ - CHECK_FCT( fd_sctp_create_bind_server( &socket, fd_g_config->cnf_port ) ); - CHECK_MALLOC( sv = new_serv(IPPROTO_SCTP, 0, socket) ); - TODO("Link"); - TODO("Start thread"); + CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 0) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + + /* Retrieve the list of endpoints if it was empty */ + if (empty_conf_ep) { + (void) fd_cnx_getendpoints(s->conn, &fd_g_config->cnf_endpoints, NULL); + } /* Create the server on secure port */ + CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); #endif /* DISABLE_SCTP */ } @@ -306,11 +257,56 @@ /* TCP */ if (!fd_g_config->cnf_flags.no_tcp) { - if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) { - /* if not no_IP : create server for 0.0.0.0 */ - /* if not no_IP6 : create server for :: */ + if (empty_conf_ep) { + /* Bind TCP servers on [0.0.0.0] */ + if (!fd_g_config->cnf_flags.no_ip4) { + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET, NULL) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET, NULL) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + } + /* Bind TCP servers on [::] */ + if (!fd_g_config->cnf_flags.no_ip6) { + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET6, NULL) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET6, NULL) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + } } else { /* Create all endpoints -- check flags */ + struct fd_list * li; + for (li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) { + struct fd_endpoint * ep = (struct fd_endpoint *)li; + sSA * sa = (sSA *) &ep->ss; + if (! ep->meta.conf) + continue; + if (fd_g_config->cnf_flags.no_ip4 && (sa->sa_family == AF_INET)) + continue; + if (fd_g_config->cnf_flags.no_ip6 && (sa->sa_family == AF_INET6)) + continue; + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, sa->sa_family, ep) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + + CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); + CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, sa->sa_family, ep) ); + fd_list_insert_before( &FD_SERVERS, &s->chain ); + CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); + } } } @@ -318,10 +314,12 @@ } /* Terminate all the servers */ -void fd_servers_stop() +int fd_servers_stop() { + TODO("Not implemented"); + /* Loop on all servers */ /* cancel thread */ - /* shutdown the socket */ - /* empty list of clients (stop them) */ + /* destroy server connection context */ + /* cancel and destroy all clients */ }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/tcp.c Mon Oct 19 18:43:09 2009 +0900 @@ -0,0 +1,112 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis <sdecugis@nict.go.jp> * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" +#include <netinet/tcp.h> +#include <netinet/ip6.h> + +/* Set the socket options for TCP sockets, before bind is called */ +static int fd_tcp_setsockopt(int family, int sk) +{ + int ret = 0; + int opt; + + /* Clear the NODELAY option in case it was set, as requested by rfc3539#section-3.2 */ + /* Note that this is supposed to be the default, so we could probably remove this call ... */ + opt = 0; + ret = setsockopt(sk, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + if (ret != 0) { + ret = errno; + TRACE_DEBUG(INFO, "Unable to set the socket TCP_NODELAY option: %s", strerror(ret)); + return ret; + } + + /* Under Linux, we may also set the TCP_CONGESTION option to one of the following strings: + - reno (default) + - bic + - cubic + - highspeed + - htcp + - hybla + - illinois + - lp + - scalable + - vegas + - veno + - westwood + - yeah + */ + + /* In case of v6 address, force the v6only option, we use a different socket for v4 */ + #ifdef IPV6_V6ONLY + if (family == AF_INET6) { + opt = 1; + CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); + } + #endif /* IPV6_V6ONLY */ + + + /* There are also others sockopt that can be set, but nothing useful for us AFAICT */ + + return 0; +} + +/* Create a socket server and bind it */ +int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen ) +{ + TRACE_ENTRY("%p %p %d", sock, sa, salen); + + CHECK_PARAMS( sock && sa ); + + /* Create the socket */ + CHECK_SYS( *sock = socket(sa->sa_family, SOCK_STREAM, IPPROTO_TCP) ); + + /* Set the socket options */ + CHECK_FCT( fd_tcp_setsockopt(sa->sa_family, *sock) ); + + /* Bind the socket */ + CHECK_SYS( bind( *sock, sa, salen ) ); + + /* We're done */ + return 0; +} + +/* Allow clients connections on server sockets */ +int fd_tcp_listen( int sock ) +{ + TRACE_ENTRY("%d", sock); + CHECK_SYS( listen(sock, 5) ); + return 0; +}
--- a/include/freeDiameter/freeDiameter.h Thu Oct 08 20:05:16 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Mon Oct 19 18:43:09 2009 +0900 @@ -255,7 +255,6 @@ /* Additional parameters */ uint32_t pi_lft; /* lifetime of this peer when inactive (see pi_flags.exp definition) */ - uint16_t pi_streams; /* number of streams for SCTP. 0 = default */ uint16_t pi_port; /* port to connect to. 0: default. */ int pi_tctimer; /* use this value for TcTimer instead of global, if != 0 */ int pi_twtimer; /* use this value for TwTimer instead of global, if != 0 */ @@ -270,6 +269,7 @@ uint32_t pi_firmrev; /* Content of the Firmware-Revision AVP */ struct fd_list pi_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ struct { + char *priority; /* In case the default priority is not appropriate */ /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo */ const gnutls_datum_t *cert_list; /* The (valid) credentials that the peer has presented */ unsigned int cert_list_size;/* Number of certificates in the list */
--- a/include/freeDiameter/libfreeDiameter.h Thu Oct 08 20:05:16 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Mon Oct 19 18:43:09 2009 +0900 @@ -119,16 +119,17 @@ * FUNCTION: fd_log_time * * PARAMETERS: + * ts : The timestamp to log, or NULL for "now" * buf : An array where the time must be stored * len : size of the buffer * * DESCRIPTION: - * Writes the current timestamp (in human readable format) in a buffer. + * Writes the timestamp (in human readable format) in a buffer. * * RETURN VALUE: * pointer to buf. */ -char * fd_log_time ( char * buf, size_t len ); +char * fd_log_time ( struct timespec * ts, char * buf, size_t len ); /* levels definitions */ @@ -172,7 +173,7 @@ char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \ fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ "\t%s|%*s" format "\n", \ - __thn, fd_log_time(__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \ + __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \ (level < FULL)?"@":" ",level, "", ## args); \ } \ }
--- a/libfreeDiameter/log.c Thu Oct 08 20:05:16 2009 +0900 +++ b/libfreeDiameter/log.c Mon Oct 19 18:43:09 2009 +0900 @@ -86,8 +86,8 @@ return; } -/* Write current time into a buffer */ -char * fd_log_time ( char * buf, size_t len ) +/* Write time into a buffer */ +char * fd_log_time ( struct timespec * ts, char * buf, size_t len ) { int ret; size_t offset = 0; @@ -95,14 +95,17 @@ struct tm tm; /* Get current time */ - ret = clock_gettime(CLOCK_REALTIME, &tp); - if (ret != 0) { - snprintf(buf, len, "%s", strerror(ret)); - return buf; + if (!ts) { + ret = clock_gettime(CLOCK_REALTIME, &tp); + if (ret != 0) { + snprintf(buf, len, "%s", strerror(ret)); + return buf; + } + ts = &tp; } - offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &tp.tv_sec , &tm )); - offset += snprintf(buf + offset, len - offset, ".%6.6ld", tp.tv_nsec / 1000); + offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &ts->tv_sec , &tm )); + offset += snprintf(buf + offset, len - offset, ".%6.6ld", ts->tv_nsec / 1000); return buf; }