Changes in / [30:bca243c65b56:20:277ec00d793e] in freeDiameter
- Files:
-
- 5 deleted
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
contrib/ca_script/Makefile
r29 r19 32 32 O = WIDE 33 33 OU = "AAA WG" 34 35 #Default lifetime36 DAYS = 36537 34 38 35 #Values for the CA … … 133 130 @openssl ca $(CONFIG) -in $(DIR)/clients/csr/$(name).csr \ 134 131 -out $(DIR)/clients/certs/$(name).cert \ 135 -days $(DAYS) \136 132 -batch 137 133 @ln -s $(DIR)/clients/certs/$(name).cert $(DIR)/certs/`openssl x509 -noout -hash < $(DIR)/clients/certs/$(name).cert`.0 -
doc/freediameter.conf.sample
r24 r20 68 68 #ListenOn = "202.249.37.5"; 69 69 #ListenOn = "2001:200:903:2::202:1"; 70 #ListenOn = "fe80::21c:5ff:fe98:7d62%eth0";71 70 72 71 ############################################################## … … 185 184 # No_TLS; # assume transparent security instead of TLS 186 185 # Port = 3868; # The port to connect to 186 # SCTP_streams = 30; 187 187 # TcTimer = 30; 188 188 # TwTimer = 30; 189 189 # ConnectTo = "202.249.37.5"; 190 190 # ConnectTo = "2001:200:903:2::202:1"; 191 # TLS_Prio = "NORMAL";192 191 # Examples: 193 192 #ConnectPeer = "aaa.wide.ad.jp"; … … 202 201 SecPort = 3867; 203 202 TLS_old_method; 203 No_IP; 204 Prefer_TCP; 204 205 SCTP_streams = 50; 206 ListenOn = "202.249.37.5"; 207 ListenOn = "2001:200:903:2::202:1"; 205 208 TcTimer = 60; 206 209 TwTimer = 6; 207 #ListenOn = "133.243.146.201";208 #ListenOn = "fe80::21d:9ff:fe89:7d68%eth0";209 210 NoRelay; 210 211 LoadExtension = "extensions/dbg_monitor.fdx"; … … 212 213 LoadExtension = "extensions/dict_eap.fdx"; 213 214 ConnectPeer = "jules.nautilus6.org" ; 214 ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; } ;215 TLS_Cred = "/etc/openssl-ca/clients/certs/ test.cert" , "/etc/openssl-ca/clients/privkeys/test.key.pem";215 ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ; 216 TLS_Cred = "/etc/openssl-ca/clients/certs/fdtest.cert" , "/etc/openssl-ca/clients/privkeys/fdtest.key.pem"; 216 217 TLS_CA = "/etc/openssl-ca/public-www/cacert.pem"; 217 218 # TLS_CRL = "/etc/openssl-ca/public-www/crl.pem"; -
extensions/dbg_monitor/monitor.c
r25 r11 49 49 static void got_sig(int signal) 50 50 { 51 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, 0,NULL), /* continue */);52 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, 0,NULL), /* continue */);53 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, 0,NULL), /* continue */);51 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, NULL), /* continue */); 52 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, NULL), /* continue */); 53 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, NULL), /* continue */); 54 54 } 55 55 /* Thread to display periodical debug information */ … … 77 77 #endif /* DEBUG */ 78 78 TRACE_DEBUG(NONE, "Monitor information"); 79 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, 0, NULL), /* continue */); 80 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_SERV, 0, NULL), /* continue */); 81 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, 0, NULL), /* continue */); 79 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, NULL), /* continue */); 80 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */); 82 81 pthread_testcancel(); 83 82 } -
freeDiameter/CMakeLists.txt
r25 r20 10 10 SET(FD_COMMON_SRC 11 11 fD.h 12 cnxctx.h13 12 config.c 14 13 cnxctx.c 15 14 dispatch.c 16 endpoints.c17 15 extensions.c 18 16 dict_base_proto.c … … 23 21 p_psm.c 24 22 server.c 25 tcp.c26 23 ) 27 24 28 25 IF(NOT DISABLE_SCTP) 29 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c)26 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c) 30 27 ENDIF(NOT DISABLE_SCTP) 31 28 -
freeDiameter/cnxctx.c
r30 r20 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h"38 37 39 /* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */ 40 #ifndef DIAMETER_MSG_SIZE_MAX 41 #define DIAMETER_MSG_SIZE_MAX 65535 /* in bytes */ 42 #endif /* DIAMETER_MSG_SIZE_MAX */ 43 44 /* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations . 45 * They are used to hide the details of the processing to the higher layers of the daemon. 46 * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported. 47 */ 48 49 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */ 50 51 /* Lifetime of a cnxctx object: 52 * 1) Creation 53 * a) a server socket: 54 * - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp 55 * - start listening incoming connections: fd_cnx_serv_listen 56 * - accept new clients with fd_cnx_serv_accept. 57 * b) a client socket: 58 * - connect to a remote server with fd_cnx_cli_connect 59 * 60 * 2) Initialization 61 * - if TLS is started first, call fd_cnx_handshake 62 * - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later. 63 * 64 * 3) Usage 65 * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not, but blocking). 66 * - 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. 67 * - fd_cnx_getid : retrieve a descriptive string for the connection (for debug) 68 * - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn) 69 * - fd_cnx_getcred : get the remote peer TLS credentials, after handshake 70 * - fd_cnx_getendpoints : get the endpoints (IP) of the connection 71 * 72 * 4) End 73 * - fd_cnx_destroy 74 */ 75 76 77 /*******************************************/ 78 /* Creation of a connection object */ 79 /*******************************************/ 80 81 /* Initialize a context structure */ 82 static struct cnxctx * fd_cnx_init(int full) 38 /* Initialize a connection context */ 39 struct cnxctx * fd_cnx_init(int sock, int proto) 83 40 { 84 41 struct cnxctx * conn = NULL; 85 86 TRACE_ENTRY("%d", full); 87 42 43 TRACE_ENTRY("%d %d", sock, proto); 44 CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL); 45 88 46 CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL ); 89 47 memset(conn, 0, sizeof(struct cnxctx)); 90 91 if (full) { 92 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL ); 48 49 conn->cc_socket = sock; 50 conn->cc_proto = proto; 51 52 fd_list_init(&conn->cc_ep_remote, conn); 53 fd_list_init(&conn->cc_ep_local, conn); 54 55 if (proto == IPPROTO_SCTP) { 56 #ifndef DISABLE_SCTP 57 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ), 58 { free(conn); return NULL; } ); 59 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; 60 #else /* DISABLE_SCTP */ 61 ASSERT(0); 62 #endif /* DISABLE_SCTP */ 93 63 } 94 64 95 65 return conn; 96 66 } 97 67 98 /* Create and bind a server socket to the given endpoint and port */ 99 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep) 100 { 101 struct cnxctx * cnx = NULL; 102 sSS dummy; 103 sSA * sa = (sSA *) &dummy; 104 105 TRACE_ENTRY("%hu %d %p", port, family, ep); 106 107 CHECK_PARAMS_DO( port, return NULL ); 108 CHECK_PARAMS_DO( ep || family, return NULL ); 109 CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL ); 110 CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL ); 111 112 /* The connection object */ 113 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); 114 115 /* Prepare the socket address information */ 116 if (ep) { 117 memcpy(sa, &ep->ss, sizeof(sSS)); 118 } else { 119 memset(&dummy, 0, sizeof(dummy)); 120 sa->sa_family = family; 121 } 122 if (sa->sa_family == AF_INET) { 123 ((sSA4 *)sa)->sin_port = htons(port); 124 } else { 125 ((sSA6 *)sa)->sin6_port = htons(port); 126 } 127 128 /* Create the socket */ 129 CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sizeof(sSS) ), goto error ); 130 131 /* Generate the name for the connection object */ 132 { 133 char addrbuf[INET6_ADDRSTRLEN]; 134 int rc; 135 rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 136 if (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); 139 } 140 141 cnx->cc_proto = IPPROTO_TCP; 142 143 return cnx; 144 145 error: 146 fd_cnx_destroy(cnx); 147 return NULL; 148 } 149 150 /* Same function for SCTP, with a list of local endpoints to bind to */ 151 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list) 152 { 153 #ifdef DISABLE_SCTP 154 TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled..."); 155 ASSERT(0); 156 CHECK_FCT_DO( ENOTSUP, return NULL); 157 #else /* DISABLE_SCTP */ 158 struct cnxctx * cnx = NULL; 159 sSS dummy; 160 sSA * sa = (sSA *) &dummy; 161 162 TRACE_ENTRY("%hu %p", port, ep_list); 163 164 CHECK_PARAMS_DO( port, return NULL ); 165 166 /* The connection object */ 167 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); 168 169 /* Create the socket */ 170 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error ); 171 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); 174 175 cnx->cc_proto = IPPROTO_SCTP; 176 177 return cnx; 178 179 error: 180 fd_cnx_destroy(cnx); 181 return NULL; 182 #endif /* DISABLE_SCTP */ 183 } 184 185 /* Allow clients to connect on the server socket */ 186 int fd_cnx_serv_listen(struct cnxctx * conn) 187 { 188 CHECK_PARAMS( conn ); 189 190 switch (conn->cc_proto) { 191 case IPPROTO_TCP: 192 CHECK_FCT(fd_tcp_listen(conn->cc_socket)); 193 break; 194 195 #ifndef DISABLE_SCTP 196 case IPPROTO_SCTP: 197 CHECK_FCT(fd_sctp_listen(conn->cc_socket)); 198 break; 199 #endif /* DISABLE_SCTP */ 200 201 default: 202 CHECK_PARAMS(0); 203 } 204 205 return 0; 206 } 207 208 /* Accept a client (blocking until a new client connects) -- cancelable */ 209 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv) 210 { 211 struct cnxctx * cli = NULL; 212 sSS ss; 213 socklen_t ss_len = sizeof(ss); 214 int cli_sock = 0; 215 struct fd_endpoint * ep; 216 217 TRACE_ENTRY("%p", serv); 218 CHECK_PARAMS_DO(serv, return NULL); 219 220 /* Accept the new connection -- this is blocking until new client enters or cancellation */ 221 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); 222 223 if (TRACE_BOOL(INFO)) { 224 fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv)); 225 sSA_DUMP_NODE( &ss, NI_NUMERICHOST ); 226 fd_log_debug("].\n"); 227 } 228 229 CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } ); 230 cli->cc_socket = cli_sock; 231 cli->cc_proto = serv->cc_proto; 232 233 /* Generate the name for the connection object */ 234 { 235 char addrbuf[INET6_ADDRSTRLEN]; 236 char portbuf[10]; 237 int rc; 238 239 /* Numeric values for debug */ 240 rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 241 if (rc) { 242 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 243 portbuf[0] = '\0'; 244 } 245 246 snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)", 247 IPPROTO_NAME(cli->cc_proto), 248 addrbuf, portbuf, 249 cli->cc_socket, serv->cc_socket); 250 251 /* Name for log messages */ 252 rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0); 253 if (rc) 254 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); 255 } 256 257 #ifndef DISABLE_SCTP 258 /* SCTP-specific handlings */ 259 if (cli->cc_proto == IPPROTO_SCTP) { 260 /* Retrieve the number of streams */ 261 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), goto error ); 262 if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in) 263 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; 264 else 265 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in; 266 } 267 #endif /* DISABLE_SCTP */ 268 269 return cli; 270 error: 271 fd_cnx_destroy(cli); 272 return NULL; 273 } 274 275 /* Client side: connect to a remote server -- cancelable */ 276 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen) 277 { 278 int sock; 279 struct cnxctx * cnx = NULL; 280 281 TRACE_ENTRY("%p %d", sa, addrlen); 282 CHECK_PARAMS_DO( sa && addrlen, return NULL ); 283 284 /* Create the socket and connect, which can take some time and/or fail */ 285 CHECK_FCT_DO( fd_tcp_client( &sock, sa, addrlen ), return NULL ); 286 287 if (TRACE_BOOL(INFO)) { 288 fd_log_debug("Connection established to server '"); 289 sSA_DUMP_NODE_SERV( sa, NI_NUMERICSERV); 290 fd_log_debug("' (TCP:%d).\n", sock); 291 } 292 293 /* Once the socket is created successfuly, prepare the remaining of the cnx */ 294 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } ); 295 296 cnx->cc_socket = sock; 297 cnx->cc_proto = IPPROTO_TCP; 298 299 /* Generate the names for the object */ 300 { 301 char addrbuf[INET6_ADDRSTRLEN]; 302 char portbuf[10]; 303 int rc; 304 305 /* Numeric values for debug */ 306 rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 307 if (rc) { 308 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 309 portbuf[0] = '\0'; 310 } 311 312 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of TCP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 313 314 /* Name for log messages */ 315 rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 316 if (rc) 317 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); 318 } 319 320 return cnx; 321 322 error: 323 fd_cnx_destroy(cnx); 324 return NULL; 325 } 326 327 /* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx for how they are used) */ 328 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list) 329 { 330 #ifdef DISABLE_SCTP 331 TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled..."); 332 ASSERT(0); 333 CHECK_FCT_DO( ENOTSUP, return NULL); 334 #else /* DISABLE_SCTP */ 335 int sock; 336 struct cnxctx * cnx = NULL; 337 sSS primary; 338 339 TRACE_ENTRY("%p", list); 340 CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL ); 341 342 CHECK_FCT_DO( fd_sctp_client( &sock, no_ip6, port, list ), return NULL ); 343 344 /* Once the socket is created successfuly, prepare the remaining of the cnx */ 345 CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } ); 346 347 cnx->cc_socket = sock; 348 cnx->cc_proto = IPPROTO_SCTP; 349 350 /* Retrieve the number of streams and primary address */ 351 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error ); 352 if (cnx->cc_sctp_para.str_out > cnx->cc_sctp_para.str_in) 353 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out; 354 else 355 cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in; 356 357 if (TRACE_BOOL(INFO)) { 358 fd_log_debug("Connection established to server '"); 359 sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV); 360 fd_log_debug("' (SCTP:%d, %d/%d streams).\n", sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out); 361 } 362 363 /* Generate the names for the object */ 364 { 365 char addrbuf[INET6_ADDRSTRLEN]; 366 char portbuf[10]; 367 int rc; 368 369 /* Numeric values for debug */ 370 rc = getnameinfo((sSA *)&primary, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 371 if (rc) { 372 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 373 portbuf[0] = '\0'; 374 } 375 376 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of SCTP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket); 377 378 /* Name for log messages */ 379 rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0); 380 if (rc) 381 snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc)); 382 } 383 384 return cnx; 385 386 error: 387 fd_cnx_destroy(cnx); 388 return NULL; 389 #endif /* DISABLE_SCTP */ 390 } 391 392 /* Return a string describing the connection, for debug */ 393 char * fd_cnx_getid(struct cnxctx * conn) 394 { 395 CHECK_PARAMS_DO( conn, return "" ); 396 return conn->cc_id; 397 } 398 399 /* Return the protocol of a connection */ 400 int fd_cnx_getproto(struct cnxctx * conn) 401 { 402 CHECK_PARAMS_DO( conn, return 0 ); 403 return conn->cc_proto; 404 } 405 406 /* Return the TLS state of a connection */ 407 int fd_cnx_getTLS(struct cnxctx * conn) 408 { 409 CHECK_PARAMS_DO( conn, return 0 ); 410 return conn->cc_tls; 411 } 412 413 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */ 414 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) 415 { 416 TRACE_ENTRY("%p %p %p", conn, local, remote); 417 CHECK_PARAMS(conn); 418 419 if (local) { 420 /* Retrieve the local endpoint(s) of the connection */ 421 switch (conn->cc_proto) { 422 case IPPROTO_TCP: { 423 sSS ss; 424 socklen_t sl; 425 CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl)); 426 CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY)); 427 } 428 break; 429 430 #ifndef DISABLE_SCTP 431 case IPPROTO_SCTP: { 432 CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local)); 433 } 434 break; 435 #endif /* DISABLE_SCTP */ 436 437 default: 438 CHECK_PARAMS(0); 439 } 440 } 441 442 if (remote) { 443 /* Check we have a full connection object, not a listening socket (with no remote) */ 444 CHECK_PARAMS( conn->cc_incoming ); 445 446 /* Retrieve the peer endpoint(s) of the connection */ 447 switch (conn->cc_proto) { 448 case IPPROTO_TCP: { 449 sSS ss; 450 socklen_t sl; 451 CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl)); 452 CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY )); 453 } 454 break; 455 456 #ifndef DISABLE_SCTP 457 case IPPROTO_SCTP: { 458 CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote)); 459 } 460 break; 461 #endif /* DISABLE_SCTP */ 462 463 default: 464 CHECK_PARAMS(0); 465 } 466 } 467 468 return 0; 469 } 470 471 472 /* Get a string describing the remote peer address (ip address or fqdn) */ 473 char * fd_cnx_getremoteid(struct cnxctx * conn) 474 { 475 CHECK_PARAMS_DO( conn, return "" ); 476 return conn->cc_remid; 477 } 478 479 480 /**************************************/ 481 /* Use of a connection object */ 482 /**************************************/ 483 484 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */ 485 static void * rcvthr_notls_tcp(void * arg) 486 { 487 struct cnxctx * conn = arg; 488 489 TRACE_ENTRY("%p", arg); 490 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 491 492 /* Set the thread name */ 493 { 494 char buf[48]; 495 snprintf(buf, sizeof(buf), "Receiver (%d) TCP/noTLS)", conn->cc_socket); 496 fd_log_threadname ( buf ); 497 } 498 499 ASSERT( conn->cc_proto == IPPROTO_TCP ); 500 ASSERT( conn->cc_tls == 0 ); 501 ASSERT( Target_Queue(conn) ); 502 503 /* Receive from a TCP connection: we have to rebuild the message boundaries */ 504 do { 505 uint8_t header[4]; 506 uint8_t * newmsg; 507 size_t length; 508 ssize_t ret = 0; 509 size_t received = 0; 510 511 do { 512 ret = recv(conn->cc_socket, &header[received], sizeof(header) - received, 0); 513 if (ret <= 0) { 514 CHECK_SYS_DO(ret, /* continue */); 515 goto error; /* Stop the thread, the recipient of the event will cleanup */ 516 } 517 518 received += ret; 519 } while (received < sizeof(header)); 520 521 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 522 523 /* Check the received word is a valid begining of a Diameter message */ 524 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 525 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 526 /* The message is suspect */ 527 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length); 528 goto error; /* Stop the thread, the recipient of the event will cleanup */ 529 } 530 531 /* Ok, now we can really receive the data */ 532 CHECK_MALLOC_DO( newmsg = malloc( length ), goto error ); 533 memcpy(newmsg, header, sizeof(header)); 534 535 while (received < length) { 536 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 537 ret = recv(conn->cc_socket, newmsg + received, length - received, 0); 538 pthread_cleanup_pop(0); 539 540 if (ret <= 0) { 541 CHECK_SYS_DO(ret, /* continue */); 542 free(newmsg); 543 goto error; /* Stop the thread, the recipient of the event will cleanup */ 544 } 545 received += ret; 546 } 547 548 /* We have received a complete message, send it */ 549 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 550 551 } while (conn->cc_loop); 552 553 out: 554 TRACE_DEBUG(FULL, "Thread terminated"); 555 return NULL; 556 error: 557 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 558 goto out; 559 } 560 561 #ifndef DISABLE_SCTP 562 /* Receiver thread (SCTP & noTLS) : incoming message is directly saved into cc_incoming, no need to care for the stream ID */ 563 static void * rcvthr_notls_sctp(void * arg) 564 { 565 struct cnxctx * conn = arg; 566 uint8_t * buf; 567 size_t bufsz; 568 int event; 569 570 TRACE_ENTRY("%p", arg); 571 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto out); 572 573 /* Set the thread name */ 574 { 575 char buf[48]; 576 snprintf(buf, sizeof(buf), "Receiver (%d) SCTP/noTLS)", conn->cc_socket); 577 fd_log_threadname ( buf ); 578 } 579 580 ASSERT( conn->cc_proto == IPPROTO_SCTP ); 581 ASSERT( conn->cc_tls == 0 ); 582 ASSERT( Target_Queue(conn) ); 583 584 do { 585 CHECK_FCT_DO( fd_sctp_recvmeta(conn->cc_socket, NULL, &buf, &bufsz, &event), goto error ); 586 if (event == FDEVP_CNX_ERROR) { 587 goto error; 588 } 589 590 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), event, bufsz, buf), goto error ); 591 592 } while (conn->cc_loop); 593 594 out: 595 TRACE_DEBUG(FULL, "Thread terminated"); 596 return NULL; 597 error: 598 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 599 goto out; 600 } 601 #endif /* DISABLE_SCTP */ 602 603 /* Returns 0 on error, received data size otherwise (always >= 0) */ 604 static ssize_t fd_tls_recv_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz) 605 { 606 ssize_t ret; 607 again: 608 CHECK_GNUTLS_DO( ret = gnutls_record_recv(session, data, sz), 609 { 610 switch (ret) { 611 case GNUTLS_E_REHANDSHAKE: 612 CHECK_GNUTLS_DO( ret = gnutls_handshake(session), 613 { 614 if (TRACE_BOOL(INFO)) { 615 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 616 } 617 ret = 0; 618 goto end; 619 } ); 620 621 case GNUTLS_E_AGAIN: 622 case GNUTLS_E_INTERRUPTED: 623 goto again; 624 625 default: 626 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error"); 627 ret = 0; 628 } 629 } ); 630 end: 631 return ret; 632 } 633 634 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */ 635 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session) 636 { 637 /* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */ 638 do { 639 uint8_t header[4]; 640 uint8_t * newmsg; 641 size_t length; 642 ssize_t ret = 0; 643 size_t received = 0; 644 645 do { 646 ret = fd_tls_recv_handle_error(conn, session, &header[received], sizeof(header) - received); 647 if (ret == 0) { 648 /* The connection is closed */ 649 goto out; 650 } 651 received += ret; 652 } while (received < sizeof(header)); 653 654 length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3]; 655 656 /* Check the received word is a valid beginning of a Diameter message */ 657 if ((header[0] != DIAMETER_VERSION) /* defined in <libfreeDiameter.h> */ 658 || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */ 659 /* The message is suspect */ 660 TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length); 661 goto out; 662 } 663 664 /* Ok, now we can really receive the data */ 665 CHECK_MALLOC( newmsg = malloc( length ) ); 666 memcpy(newmsg, header, sizeof(header)); 667 668 while (received < length) { 669 pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */ 670 ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received); 671 pthread_cleanup_pop(0); 672 673 if (ret == 0) { 674 free(newmsg); 675 goto out; /* Stop the thread, the recipient of the event will cleanup */ 676 } 677 received += ret; 678 } 679 680 /* We have received a complete message, send it */ 681 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */); 682 683 } while (1); 684 out: 685 return ENOTCONN; 686 } 687 688 /* Receiver thread (TLS & 1 stream SCTP or TCP) : gnutls directly handles the socket, save records into the target queue */ 689 static void * rcvthr_tls_single(void * arg) 690 { 691 struct cnxctx * conn = arg; 692 693 TRACE_ENTRY("%p", arg); 694 CHECK_PARAMS_DO(conn && (conn->cc_socket > 0), goto error); 695 696 /* Set the thread name */ 697 { 698 char buf[48]; 699 snprintf(buf, sizeof(buf), "Receiver (%d) TLS/ single stream)", conn->cc_socket); 700 fd_log_threadname ( buf ); 701 } 702 703 ASSERT( conn->cc_tls == 1 ); 704 ASSERT( Target_Queue(conn) ); 705 706 CHECK_FCT_DO(fd_tls_rcvthr_core(conn, conn->cc_tls_para.session), /* continue */); 707 error: 708 CHECK_FCT_DO( fd_event_send( Target_Queue(conn), FDEVP_CNX_ERROR, 0, NULL), /* continue or destroy everything? */); 709 TRACE_DEBUG(FULL, "Thread terminated"); 710 return NULL; 711 } 712 713 /* Start receving messages in clear (no TLS) on the connection */ 714 int fd_cnx_start_clear(struct cnxctx * conn, int loop) 715 { 716 TRACE_ENTRY("%p %i", conn, loop); 717 718 CHECK_PARAMS( conn && Target_Queue(conn) && (!conn->cc_tls) && (!conn->cc_loop)); 719 720 /* Save the loop request */ 721 conn->cc_loop = loop; 722 723 /* Release resources in case of a previous call was already made */ 724 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */); 725 726 switch (conn->cc_proto) { 727 case IPPROTO_TCP: 728 /* Start the tcp_notls thread */ 729 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_tcp, conn ) ); 730 break; 731 #ifndef DISABLE_SCTP 732 case IPPROTO_SCTP: 733 /* Start the tcp_notls thread */ 734 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_notls_sctp, conn ) ); 735 break; 736 #endif /* DISABLE_SCTP */ 737 default: 738 TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto); 739 return ENOTSUP; 740 } 741 742 return 0; 743 } 744 745 /* Prepare a gnutls session object for handshake */ 746 int fd_tls_prepare(gnutls_session_t * session, int mode, char * priority, void * alt_creds) 747 { 748 /* Create the master session context */ 749 CHECK_GNUTLS_DO( gnutls_init (session, mode), return ENOMEM ); 750 751 /* Set the algorithm suite */ 752 if (priority) { 753 const char * errorpos; 754 CHECK_GNUTLS_DO( gnutls_priority_set_direct( *session, priority, &errorpos ), 755 { TRACE_DEBUG(INFO, "Error in priority string '%s' at position: '%s'\n", priority, errorpos); return EINVAL; } ); 756 } else { 757 CHECK_GNUTLS_DO( gnutls_priority_set( *session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); 758 } 759 760 /* Set the credentials of this side of the connection */ 761 CHECK_GNUTLS_DO( gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, alt_creds ?: fd_g_config->cnf_sec_data.credentials), return EINVAL ); 762 763 /* Request the remote credentials as well */ 764 if (mode == GNUTLS_SERVER) { 765 gnutls_certificate_server_set_request (*session, GNUTLS_CERT_REQUIRE); 766 } 767 768 return 0; 769 } 770 771 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ 772 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds) 68 /* TLS handshake the connection */ 69 int fd_cnx_handshake(struct cnxctx * conn, int mode) 773 70 { 774 71 TRACE_ENTRY( "%p %d", conn, mode); 775 CHECK_PARAMS( conn && ( !conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) );776 72 CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) ); 73 777 74 /* Save the mode */ 778 75 conn->cc_tls_para.mode = mode; 779 76 780 /* C ancel receiving thread if any -- it should already be terminated anyway, we just release the resources*/781 CHECK_ FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */);77 /* Create the master session context */ 78 CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); 782 79 783 /* Once TLS handshake is done, we don't stop after the first message */784 conn->cc_loop = 1;80 /* Set the algorithm suite */ 81 CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); 785 82 786 /* Prepare the master session credentials and priority */ 787 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) ); 83 /* Set the credentials of this side of the connection */ 84 CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); 85 86 /* Request the remote credentials as well */ 87 if (mode == GNUTLS_SERVER) { 88 gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE); 89 } 90 91 /* Set the socket info in the session */ 92 gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket); 788 93 789 94 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ 790 if (conn->cc_sctp_para.pairs > 1) { 791 #ifdef DISABLE_SCTP 95 if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { 96 #ifndef DISABLE_SCTP 97 TODO("Initialize the SCTP TLS wrapper"); 98 TODO("Set the lowat, push and pull functions"); 99 #else /* DISABLE_SCTP */ 792 100 ASSERT(0); 793 CHECK_FCT( ENOTSUP );794 #else /* DISABLE_SCTP */795 /* Initialize the wrapper, start the demux thread */796 CHECK_FCT( fd_sctps_init(conn) );797 101 #endif /* DISABLE_SCTP */ 798 } else {799 /* Set the socket info in the session */800 gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);801 102 } 802 103 803 104 /* Handshake master session */ 804 105 { … … 807 108 { 808 109 if (TRACE_BOOL(INFO)) { 809 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));110 fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret)); 810 111 } 811 112 return EINVAL; 812 113 } ); 813 114 814 115 /* Now verify the remote credentials are valid -- only simple test here */ 815 116 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL ); 816 117 if (ret) { 817 118 if (TRACE_BOOL(INFO)) { 818 fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id);119 fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket); 819 120 if (ret & GNUTLS_CERT_INVALID) 820 121 fd_log_debug(" - The certificate is not trusted (unknown CA?)\n"); … … 831 132 } 832 133 } 833 834 /* Multi-stream TLS: handshake other streams as well*/835 if ( conn->cc_sctp_para.pairs > 1) {134 135 /* Other sessions in case of multi-stream SCTP are resumed from the master */ 136 if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { 836 137 #ifndef DISABLE_SCTP 837 /* Resume all additional sessions from the master one. */ 838 CHECK_FCT(fd_sctps_handshake_others(conn, priority, alt_creds)); 839 840 /* Mark the connection as protected from here */ 841 conn->cc_tls = 1; 842 843 /* Start decrypting the messages from all threads and queuing them in target queue */ 844 CHECK_FCT(fd_sctps_startthreads(conn)); 138 TODO("Init and resume all additional sessions from the master one."); 845 139 #endif /* DISABLE_SCTP */ 846 } else {847 /* Mark the connection as protected from here */848 conn->cc_tls = 1;849 850 /* Start decrypting the data */851 CHECK_POSIX( pthread_create( &conn->cc_rcvthr, NULL, rcvthr_tls_single, conn ) );852 140 } 853 141 854 142 return 0; 855 143 } 856 857 /* Retrieve TLS credentials of the remote peer, after handshake */858 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size)859 {860 TRACE_ENTRY("%p %p %p", conn, cert_list, cert_list_size);861 CHECK_PARAMS( conn && (conn->cc_tls) && cert_list && cert_list_size );862 863 /* This function only works for X.509 certificates. */864 CHECK_PARAMS( gnutls_certificate_type_get (conn->cc_tls_para.session) == GNUTLS_CRT_X509 );865 866 *cert_list = gnutls_certificate_get_peers (conn->cc_tls_para.session, cert_list_size);867 if (*cert_list == NULL) {868 TRACE_DEBUG(INFO, "No certificate was provided by remote peer / an error occurred.");869 return EINVAL;870 }871 872 TRACE_DEBUG( FULL, "Remote peer provided %d certificates.\n", *cert_list_size);873 874 return 0;875 }876 877 /* 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. */878 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len)879 {880 int ev;881 size_t ev_sz;882 void * ev_data;883 884 TRACE_ENTRY("%p %p %p %p", conn, timeout, buf, len);885 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);886 CHECK_PARAMS(conn->cc_rcvthr != (pthread_t)NULL);887 CHECK_PARAMS(conn->cc_alt == NULL);888 889 /* Now, pull the first event */890 get_next:891 if (timeout) {892 CHECK_FCT( fd_event_timedget(conn->cc_incoming, timeout, FDEVP_PSM_TIMEOUT, &ev, &ev_sz, &ev_data) );893 } else {894 CHECK_FCT( fd_event_get(conn->cc_incoming, &ev, &ev_sz, &ev_data) );895 }896 897 switch (ev) {898 case FDEVP_CNX_MSG_RECV:899 /* We got one */900 *len = ev_sz;901 *buf = ev_data;902 return 0;903 904 case FDEVP_PSM_TIMEOUT:905 TRACE_DEBUG(FULL, "Timeout event received");906 return ETIMEDOUT;907 908 case FDEVP_CNX_EP_CHANGE:909 /* We ignore this event */910 goto get_next;911 912 case FDEVP_CNX_ERROR:913 TRACE_DEBUG(FULL, "Received ERROR event on the connection");914 return ENOTCONN;915 }916 917 TRACE_DEBUG(INFO, "Received unexpected event %d (%s)", ev, fd_pev_str(ev));918 return EINVAL;919 }920 921 /* Set an alternate FIFO list to send FDEVP_CNX_* events to */922 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)923 {924 TRACE_ENTRY( "%p %p", conn, alt_fifo );925 CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );926 927 /* The magic function does it all */928 CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) );929 930 return 0;931 }932 933 /* Wrapper around gnutls_record_recv to handle some error codes */934 static ssize_t fd_tls_send_handle_error(struct cnxctx * conn, gnutls_session_t session, void * data, size_t sz)935 {936 ssize_t ret;937 again:938 CHECK_GNUTLS_DO( ret = gnutls_record_send(session, data, sz),939 {940 switch (ret) {941 case GNUTLS_E_REHANDSHAKE:942 CHECK_GNUTLS_DO( ret = gnutls_handshake(session),943 {944 if (TRACE_BOOL(INFO)) {945 fd_log_debug("TLS re-handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret));946 }947 goto end;948 } );949 950 case GNUTLS_E_AGAIN:951 case GNUTLS_E_INTERRUPTED:952 goto again;953 954 default:955 TRACE_DEBUG(INFO, "This TLS error is not handled, assume unrecoverable error");956 }957 } );958 end:959 return ret;960 }961 962 963 964 /* Send function when no multi-stream is involved, or sending on stream #0 (send() always use stream 0)*/965 static int send_simple(struct cnxctx * conn, unsigned char * buf, size_t len)966 {967 ssize_t ret;968 size_t sent = 0;969 TRACE_ENTRY("%p %p %zd", conn, buf, len);970 do {971 if (conn->cc_tls) {972 CHECK_GNUTLS_DO( ret = fd_tls_send_handle_error(conn, conn->cc_tls_para.session, buf + sent, len - sent), return ENOTCONN );973 } else {974 CHECK_SYS( ret = send(conn->cc_socket, buf + sent, len - sent, 0) ); /* better to replace with sendmsg for atomic sending? */975 }976 sent += ret;977 } while ( sent < len );978 return 0;979 }980 981 /* 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. */982 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)983 {984 TRACE_ENTRY("%p %p %zd", conn, buf, len);985 986 CHECK_PARAMS(conn && (conn->cc_socket > 0) && buf && len);987 988 TRACE_DEBUG(FULL, "Sending %zdb %sdata on connection %s", len, conn->cc_tls ? "TLS-protected ":"", conn->cc_id);989 990 switch (conn->cc_proto) {991 case IPPROTO_TCP:992 CHECK_FCT( send_simple(conn, buf, len) );993 break;994 995 #ifndef DISABLE_SCTP996 case IPPROTO_SCTP: {997 int multistr = 0;998 999 if ((conn->cc_sctp_para.str_out > 1) && ((! conn->cc_tls) || (conn->cc_sctp_para.pairs > 1))) {1000 /* Update the id of the stream we will send this message on */1001 conn->cc_sctp_para.next += 1;1002 conn->cc_sctp_para.next %= (conn->cc_tls ? conn->cc_sctp_para.pairs : conn->cc_sctp_para.str_out);1003 multistr = 1;1004 }1005 1006 if ((!multistr) || (conn->cc_sctp_para.next == 0)) {1007 CHECK_FCT( send_simple(conn, buf, len) );1008 } else {1009 if (!conn->cc_tls) {1010 CHECK_FCT( fd_sctp_sendstr(conn->cc_socket, conn->cc_sctp_para.next, buf, len) );1011 } else {1012 /* push the record to the appropriate session */1013 ssize_t ret;1014 size_t sent = 0;1015 ASSERT(conn->cc_sctps_data.array != NULL);1016 do {1017 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 );1018 sent += ret;1019 } while ( sent < len );1020 }1021 }1022 }1023 break;1024 #endif /* DISABLE_SCTP */1025 1026 default:1027 TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);1028 return ENOTSUP; /* or EINVAL... */1029 }1030 1031 return 0;1032 }1033 1034 1035 /**************************************/1036 /* Destruction of connection */1037 /**************************************/1038 1039 /* Destroy a conn structure, and shutdown the socket */1040 void fd_cnx_destroy(struct cnxctx * conn)1041 {1042 TRACE_ENTRY("%p", conn);1043 1044 CHECK_PARAMS_DO(conn, return);1045 1046 /* In case of TLS, stop receiver thread, then close properly the gnutls session */1047 if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) {1048 #ifndef DISABLE_SCTP1049 /* Multi-stream TLS: Stop all decipher threads, but not the demux thread */1050 fd_sctps_stopthreads(conn);1051 #endif /* DISABLE_SCTP */1052 } else {1053 /* Stop the decoding thread */1054 CHECK_FCT_DO( fd_thr_term(&conn->cc_rcvthr), /* continue */ );1055 }1056 1057 /* Terminate properly the TLS session(s) */1058 if (conn->cc_tls) {1059 /* Master session */1060 CHECK_GNUTLS_DO( gnutls_bye(conn->cc_tls_para.session, GNUTLS_SHUT_RDWR), /* Continue */ );1061 gnutls_deinit(conn->cc_tls_para.session);1062 1063 #ifndef DISABLE_SCTP1064 if (conn->cc_sctp_para.pairs > 1) {1065 /* Multi-stream TLS: destroy the wrapper and stop the demux thread */1066 fd_sctps_destroy(conn);1067 }1068 #endif /* DISABLE_SCTP */1069 1070 }1071 1072 /* Shut the connection down */1073 if (conn->cc_socket > 0) {1074 shutdown(conn->cc_socket, SHUT_RDWR);1075 }1076 1077 /* Empty and destroy FIFO list */1078 if (conn->cc_incoming) {1079 fd_event_destroy( &conn->cc_incoming, free );1080 }1081 1082 /* Free the object */1083 free(conn);1084 1085 /* Done! */1086 return;1087 } -
freeDiameter/config.c
r24 r20 100 100 struct fd_endpoint * ep = (struct fd_endpoint *)li; 101 101 if (li != fd_g_config->cnf_endpoints.next) fd_log_debug(" "); 102 sSA_DUMP_NODE( &ep->s a, NI_NUMERICHOST );102 sSA_DUMP_NODE( &ep->ss, NI_NUMERICHOST ); 103 103 fd_log_debug("\n"); 104 104 li = li->next; … … 229 229 } 230 230 231 /* Validate local endpoints */232 if ((!FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) && (fd_g_config->cnf_flags.no_ip4 || fd_g_config->cnf_flags.no_ip6)) {233 struct fd_list * li;234 for ( li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {235 struct fd_endpoint * ep = (struct fd_endpoint *)li;236 if ( (fd_g_config->cnf_flags.no_ip4 && (ep->sa.sa_family == AF_INET))237 ||(fd_g_config->cnf_flags.no_ip6 && (ep->sa.sa_family == AF_INET6)) ) {238 li = li->prev;239 fd_list_unlink(&ep->chain);240 if (TRACE_BOOL(INFO)) {241 fd_log_debug("Info: Removing local address conflicting with the flags no_IP / no_IP6 : ");242 sSA_DUMP_NODE( &ep->sa, AI_NUMERICHOST );243 fd_log_debug("\n");244 }245 free(ep);246 }247 }248 }249 250 231 /* Configure TLS default parameters */ 251 232 if (! fd_g_config->cnf_sec_data.prio_string) { … … 258 239 } 259 240 if (! fd_g_config->cnf_sec_data.dh_bits) { 260 if (TRACE_BOOL(INFO)) { 261 fd_log_debug("Generating Diffie-Hellman parameters of size %d (this takes a few seconds)... ", GNUTLS_DEFAULT_DHBITS); 262 } 241 TRACE_DEBUG(FULL, "Generating DH parameters..."); 263 242 CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 264 243 fd_g_config->cnf_sec_data.dh_cache, 265 244 GNUTLS_DEFAULT_DHBITS), 266 245 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); 267 if (TRACE_BOOL(INFO)) { 268 fd_log_debug("Done!\n"); 269 } 270 } 246 TRACE_DEBUG(FULL, "DH parameters generated."); 247 } 248 271 249 272 250 return 0; -
freeDiameter/fD.h
r29 r20 152 152 enum { 153 153 /* Dump all info about this peer in the debug log */ 154 FDEVP_DUMP_ALL = 1500154 FDEVP_DUMP_ALL = 2000 155 155 156 156 /* request to terminate this peer : disconnect, requeue all messages */ 157 157 ,FDEVP_TERMINATE 158 158 159 /* A connection object has received a message. (data contains the buffer) */ 160 ,FDEVP_CNX_MSG_RECV 161 162 /* A connection object has encountered an error (disconnected). */ 163 ,FDEVP_CNX_ERROR 164 165 /* Endpoints of a connection have been changed (multihomed SCTP). */ 166 ,FDEVP_CNX_EP_CHANGE 167 168 /* A new connection has been established (data contains the appropriate info) */ 169 ,FDEVP_CNX_INCOMING 159 /* A message was received in the peer */ 160 ,FDEVP_MSG_INCOMING 170 161 171 162 /* The PSM state is expired */ 172 163 ,FDEVP_PSM_TIMEOUT 173 174 164 }; 175 165 const char * fd_pev_str(int event); 176 166 #define CHECK_EVENT( _e ) \ 177 167 (((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT)) 178 179 /* The data structure for FDEVP_CNX_INCOMING events */180 struct cnx_incoming {181 struct msg * cer; /* the CER message received on this connection */182 struct cnxctx * cnx; /* The connection context */183 int validate; /* The peer is new, it must be validated (by an extension) or error CEA to be sent */184 };185 168 186 169 /* Structure to store a sent request */ … … 190 173 }; 191 174 175 /* The connection context structure */ 176 struct cnxctx { 177 int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */ 178 179 struct fifo **cc_events; /* Location of the events list to send connection events */ 180 181 int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 182 int cc_tls; /* Is TLS already started ? */ 183 184 uint16_t cc_port; /* Remote port of the connection, when we are client */ 185 struct fd_list cc_ep_remote; /* The remote address(es) of the connection */ 186 struct fd_list cc_ep_local; /* The local address(es) of the connection */ 187 188 /* If cc_proto == SCTP */ 189 struct { 190 int str_out;/* Out streams */ 191 int str_in; /* In streams */ 192 int pairs; /* max number of pairs ( = min(in, out)) */ 193 int next; /* # of stream the next message will be sent to */ 194 } cc_sctp_para; 195 196 /* If cc_tls == true */ 197 struct { 198 int mode; /* GNUTLS_CLIENT / GNUTLS_SERVER */ 199 gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ 200 } cc_tls_para; 201 202 /* If both conditions */ 203 struct { 204 gnutls_session_t *res_sessions; /* Sessions of other pairs of streams, resumed from the first */ 205 /* Buffers, threads, ... */ 206 } cc_sctp_tls_para; 207 }; 192 208 193 209 /* Functions */ 194 int 210 int fd_peer_fini(); 195 211 void fd_peer_dump_list(int details); 196 212 void fd_peer_dump(struct fd_peer * peer, int details); 197 int fd_peer_alloc(struct fd_peer ** ptr); 198 int fd_peer_free(struct fd_peer ** ptr); 199 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx ); 213 int fd_peer_alloc(struct fd_peer ** ptr); 214 int fd_peer_free(struct fd_peer ** ptr); 200 215 /* fd_peer_add declared in freeDiameter.h */ 201 int fd_peer_validate( struct fd_peer * peer );202 216 203 217 /* Peer expiry */ … … 207 221 208 222 /* Peer state machine */ 209 int 210 int 211 int 223 int fd_psm_start(); 224 int fd_psm_begin(struct fd_peer * peer ); 225 int fd_psm_terminate(struct fd_peer * peer ); 212 226 void fd_psm_abord(struct fd_peer * peer ); 213 227 214 228 /* Server sockets */ 215 229 void fd_servers_dump(); 216 int fd_servers_start(); 217 int fd_servers_stop(); 218 219 /* Connection contexts -- there are also definitions in cnxctx.h for the relevant files */ 220 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep); 221 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list); 222 int fd_cnx_serv_listen(struct cnxctx * conn); 223 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv); 224 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen); 225 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list); 226 int fd_cnx_start_clear(struct cnxctx * conn, int loop); 227 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority, void * alt_creds); 228 char * fd_cnx_getid(struct cnxctx * conn); 229 int fd_cnx_getproto(struct cnxctx * conn); 230 int fd_cnx_getTLS(struct cnxctx * conn); 231 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size); 232 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote); 233 char * fd_cnx_getremoteid(struct cnxctx * conn); 234 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len); 235 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */ 236 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len); 237 void fd_cnx_destroy(struct cnxctx * conn); 230 int fd_servers_start(); 231 void fd_servers_stop(); 232 233 /* Connection contexts */ 234 struct cnxctx * fd_cnx_init(int sock, int proto); 235 int fd_cnx_handshake(struct cnxctx * conn, int mode); 236 237 /* SCTP */ 238 #ifndef DISABLE_SCTP 239 int fd_sctp_create_bind_server( int * socket, uint16_t port ); 240 int fd_sctp_get_str_info( int socket, int *in, int *out ); 241 242 #endif /* DISABLE_SCTP */ 243 238 244 239 245 -
freeDiameter/fdd.y
r24 r20 212 212 listenon: LISTENON '=' QSTRING ';' 213 213 { 214 struct fd_endpoint * ep; 214 215 struct addrinfo hints, *ai; 215 216 int ret; 217 218 CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)), 219 { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } ); 220 memset(ep, 0, sizeof(struct fd_endpoint)); 221 fd_list_init(&ep->chain, NULL); 222 ep->meta.conf = 1; 216 223 217 224 memset(&hints, 0, sizeof(hints)); 218 225 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 219 226 ret = getaddrinfo($3, NULL, &hints, &ai); 220 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } 221 CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR ); 227 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; } 228 ASSERT( ai->ai_addrlen <= sizeof(sSS) ); 229 memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); 230 free($3); 222 231 freeaddrinfo(ai); 223 f ree($3);232 fd_list_insert_before(&conf->cnf_endpoints, &ep->chain); 224 233 } 225 234 ; … … 327 336 /* Now destroy any content in the structure */ 328 337 free(fddpi.pi_diamid); 329 free(fddpi.pi_sec_data.priority);330 338 while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) { 331 339 struct fd_list * li = fddpi.pi_endpoints.next; … … 407 415 fddpi.pi_port = (uint16_t)$4; 408 416 } 417 | peerparams SCTPSTREAMS '=' INTEGER ';' 418 { 419 CHECK_PARAMS_DO( ($4 > 0) && ($4 < 1<<16), 420 { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); 421 fddpi.pi_streams = (uint16_t)$4; 422 } 409 423 | peerparams TCTIMER '=' INTEGER ';' 410 424 { 411 425 fddpi.pi_tctimer = $4; 412 426 } 413 | peerparams TLS_PRIO '=' QSTRING ';'414 {415 fddpi.pi_sec_data.priority = $4;416 }417 427 | peerparams TWTIMER '=' INTEGER ';' 418 428 { … … 421 431 | peerparams CONNTO '=' QSTRING ';' 422 432 { 433 struct fd_endpoint * ep; 423 434 struct addrinfo hints, *ai; 424 435 int ret; 425 int disc = 0;426 436 437 CHECK_MALLOC_DO( ep = malloc(sizeof(struct fd_endpoint)), 438 { yyerror (&yylloc, conf, "Out of memory"); YYERROR; } ); 439 memset(ep, 0, sizeof(struct fd_endpoint)); 440 fd_list_init(&ep->chain, NULL); 441 ep->meta.conf = 1; 427 442 memset(&hints, 0, sizeof(hints)); 428 443 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; … … 430 445 if (ret == EAI_NONAME) { 431 446 /* The name was maybe not numeric, try again */ 432 disc = EP_FL_DISC;447 ep->meta.disc = 1; 433 448 hints.ai_flags &= ~ AI_NUMERICHOST; 434 449 ret = getaddrinfo($4, NULL, &hints, &ai); 435 450 } 436 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }451 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; } 437 452 438 CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR);453 memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); 439 454 free($4); 440 455 freeaddrinfo(ai); 456 fd_list_insert_before(&fddpi.pi_endpoints, &ep->chain); 441 457 } 442 458 ; -
freeDiameter/main.c
r25 r20 51 51 struct fd_config * fd_g_config = &conf; 52 52 53 /* gcrypt functions to support posix threads */54 53 GCRY_THREAD_OPTION_PTHREAD_IMPL; 55 54 … … 106 105 CHECK_FCT( fd_ext_load() ); 107 106 108 fd_conf_dump();109 110 /* Start the servers */111 CHECK_FCT( fd_servers_start() );112 113 107 /* Start the peer state machines */ 114 108 CHECK_FCT( fd_psm_start() ); … … 116 110 /* Now, just wait for events */ 117 111 TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); 112 fd_conf_dump(); 118 113 while (1) { 119 int code; size_t sz; void * data;120 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data), break );114 int code; 115 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break ); 121 116 switch (code) { 122 117 case FDEV_DUMP_DICT: … … 159 154 160 155 /* cleanups */ 161 CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ );162 156 TODO("Stop dispatch thread(s) properly (no cancel yet)"); 163 157 CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ ); … … 339 333 340 334 TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); 341 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0,NULL), exit(2) );335 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) ); 342 336 return NULL; 343 337 } -
freeDiameter/p_expiry.c
r25 r16 47 47 static void * gc_th_fct(void * arg) 48 48 { 49 fd_log_threadname ( "Peers/garb . col." );50 TRACE_ENTRY( " %p", arg);49 fd_log_threadname ( "Peers/garbage" ); 50 TRACE_ENTRY( "" ); 51 51 52 52 do { 53 53 struct fd_list * li, purge = FD_LIST_INITIALIZER(purge); 54 54 55 sleep(GC_TIME); /* sleep is a cancellation point */ 55 pthread_testcancel(); 56 sleep(GC_TIME); 56 57 57 58 /* Now check in the peers list if any peer can be deleted */ … … 87 88 TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating..."); 88 89 ASSERT(0); 89 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0,NULL), );90 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 90 91 return NULL; 91 92 } … … 95 96 { 96 97 fd_log_threadname ( "Peers/expire" ); 97 TRACE_ENTRY( " %p", arg);98 TRACE_ENTRY( "" ); 98 99 99 100 CHECK_POSIX_DO( pthread_mutex_lock(&exp_mtx), goto error ); … … 123 124 124 125 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &exp_mtx, &first->p_exp_timer ), 125 ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */,126 ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */, 126 127 /* on other error, */ goto error ); 127 128 … … 132 133 /* Now, the first peer in the list is expired; signal it */ 133 134 fd_list_unlink( &first->p_expiry ); 134 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0,NULL), goto error );135 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error ); 135 136 136 137 } while (1); … … 140 141 TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating..."); 141 142 ASSERT(0); 142 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0,NULL), );143 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 143 144 return NULL; 144 145 } -
freeDiameter/p_psm.c
r29 r20 55 55 #define case_str( _val )\ 56 56 case _val : return #_val 57 case_str(FDEVP_TERMINATE); 57 58 case_str(FDEVP_DUMP_ALL); 58 case_str(FDEVP_TERMINATE); 59 case_str(FDEVP_CNX_MSG_RECV); 60 case_str(FDEVP_CNX_ERROR); 61 case_str(FDEVP_CNX_EP_CHANGE); 62 case_str(FDEVP_CNX_INCOMING); 59 case_str(FDEVP_MSG_INCOMING); 63 60 case_str(FDEVP_PSM_TIMEOUT); 64 61 … … 128 125 } 129 126 127 /* Wait for the next event in the PSM, or timeout */ 128 static int psm_ev_timedget(struct fd_peer * peer, int *code, void ** data) 129 { 130 struct fd_event * ev; 131 int ret = 0; 132 133 TRACE_ENTRY("%p %p %p", peer, code, data); 134 135 ret = fd_fifo_timedget(peer->p_events, &ev, &peer->p_psm_timer); 136 if (ret == ETIMEDOUT) { 137 *code = FDEVP_PSM_TIMEOUT; 138 *data = NULL; 139 } else { 140 CHECK_FCT( ret ); 141 *code = ev->code; 142 *data = ev->data; 143 free(ev); 144 } 145 146 return 0; 147 } 148 130 149 /* The state machine thread (controler) */ 131 150 static void * p_psm_th( void * arg ) … … 134 153 int created_started = started; 135 154 int event; 136 size_t ev_sz;137 155 void * ev_data; 138 156 … … 163 181 psm_loop: 164 182 /* Get next event */ 165 CHECK_FCT_DO( fd_event_timedget(peer->p_events, &peer->p_psm_timer, FDEVP_PSM_TIMEOUT, &event, &ev_sz, &ev_data), goto psm_end );166 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p ,%zd)\t'%s'",183 CHECK_FCT_DO( psm_ev_timedget(peer, &event, &ev_data), goto psm_end ); 184 TRACE_DEBUG(FULL, "'%s'\t<-- '%s'\t(%p)\t'%s'", 167 185 STATE_STR(peer->p_hdr.info.pi_state), 168 fd_pev_str(event), ev_data, ev_sz,186 fd_pev_str(event), ev_data, 169 187 peer->p_hdr.info.pi_diamid); 170 188 … … 209 227 } 210 228 211 /* A new connection was established and CER containing this peer id was received */212 if (event == FDEVP_CNX_INCOMING) {213 struct cnx_incoming * params = ev_data;214 ASSERT(params);215 216 switch (peer->p_hdr.info.pi_state) {217 case STATE_CLOSED:218 TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state");219 break;220 221 case STATE_WAITCNXACK:222 case STATE_WAITCEA:223 TODO("Election");224 break;225 226 default:227 TODO("Reply with error CEA");228 TODO("Close the connection");229 /* reject_incoming_connection */230 231 }232 233 free(ev_data);234 goto psm_loop;235 }236 237 229 /* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */ 238 230 /* If timeout or OPEN : call cb if defined */ … … 249 241 psm_end: 250 242 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ 251 peer->p_psm = (pthread_t)NULL;252 pthread_detach(pthread_self());253 243 return NULL; 254 244 } 245 246 247 255 248 256 249 /* Create the PSM thread of one peer structure */ … … 274 267 TRACE_ENTRY("%p", peer); 275 268 CHECK_PARAMS( CHECK_PEER(peer) ); 276 277 269 if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { 278 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0,NULL) );270 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) ); 279 271 } else { 280 272 TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); -
freeDiameter/peers.c
r29 r20 101 101 102 102 p->p_hdr.info.pi_lft = info->pi_lft; 103 p->p_hdr.info.pi_streams = info->pi_streams; 103 104 p->p_hdr.info.pi_port = info->pi_port; 104 105 p->p_hdr.info.pi_tctimer = info->pi_tctimer; 105 106 p->p_hdr.info.pi_twtimer = info->pi_twtimer; 106 107 if (info->pi_sec_data.priority) {108 CHECK_MALLOC( p->p_hdr.info.pi_sec_data.priority = strdup(info->pi_sec_data.priority) );109 }110 107 111 108 /* Move the items from one list to the other */ … … 117 114 } 118 115 119 120 116 /* The internal data */ 121 117 if (orig_dbg) { … … 131 127 132 128 for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { 133 struct fd_peer * next= (struct fd_peer *)li;134 int cmp = strcasecmp( p->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamid );135 if (cmp >0)129 struct fd_peer * prev = (struct fd_peer *)li; 130 int cmp = strcasecmp( p->p_hdr.info.pi_diamid, prev->p_hdr.info.pi_diamid ); 131 if (cmp < 0) 136 132 continue; 137 133 if (cmp == 0) … … 233 229 234 230 if (p->p_cnxctx) { 235 fd_cnx_destroy(p->p_cnxctx);231 TODO("destroy p->p_cnxctx"); 236 232 } 237 233 … … 297 293 list_empty = FD_IS_LIST_EMPTY(&fd_g_peers); 298 294 CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ ); 299 CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) );300 295 } 301 296 … … 375 370 } 376 371 377 /* Handle an incoming CER request on a new connection */378 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx )379 {380 struct msg * msg;381 struct dict_object *avp_oh_model;382 avp_code_t code = AC_ORIGIN_HOST;383 struct avp *avp_oh;384 struct avp_hdr * avp_hdr;385 struct fd_list * li;386 int found = 0;387 int ret = 0;388 struct fd_peer * peer;389 struct cnx_incoming * ev_data;390 391 TRACE_ENTRY("%p %p", cer, cnx);392 CHECK_PARAMS(cer && *cer && cnx && *cnx);393 394 msg = *cer;395 396 /* Find the Diameter Identity of the remote peer in the message */397 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT) );398 CHECK_FCT( fd_msg_search_avp ( msg, avp_oh_model, &avp_oh ) );399 CHECK_FCT( fd_msg_avp_hdr ( avp_oh, &avp_hdr ) );400 401 /* Search if we already have this peer id in our list */402 CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );403 404 for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {405 peer = (struct fd_peer *)li;406 int cmp = strncasecmp( avp_hdr->avp_value->os.data, peer->p_hdr.info.pi_diamid, avp_hdr->avp_value->os.len );407 if (cmp > 0)408 continue;409 if (cmp == 0)410 found = 1;411 break;412 }413 414 if (!found) {415 /* Create a new peer entry for this new remote peer */416 peer = NULL;417 CHECK_FCT_DO( ret = fd_peer_alloc(&peer), goto out );418 419 /* Set the peer Diameter Id and the responder flag parameters */420 CHECK_MALLOC_DO( peer->p_hdr.info.pi_diamid = malloc(avp_hdr->avp_value->os.len + 1), { ret = ENOMEM; goto out; } );421 CHECK_MALLOC_DO( peer->p_dbgorig = strdup(fd_cnx_getid(*cnx)), { ret = ENOMEM; goto out; } );422 peer->p_flags.pf_responder = 1;423 424 /* Upgrade the lock to write lock */425 CHECK_POSIX_DO( ret = pthread_rwlock_wrlock(&fd_g_peers_rw), goto out );426 427 /* Insert the new peer in the list (the PSM will take care of setting the expiry after validation) */428 fd_list_insert_before( li, &peer->p_hdr.chain );429 430 /* Release the write lock */431 CHECK_POSIX_DO( ret = pthread_rwlock_unlock(&fd_g_peers_rw), goto out );432 433 /* Start the PSM, which will receive the event bellow */434 CHECK_FCT_DO( ret = fd_psm_begin(peer), goto out );435 }436 437 /* Send the new connection event to the PSM */438 CHECK_MALLOC_DO( ev_data = malloc(sizeof(struct cnx_incoming)), { ret = ENOMEM; goto out; } );439 memset(ev_data, 0, sizeof(ev_data));440 441 ev_data->cer = msg;442 ev_data->cnx = *cnx;443 ev_data->validate = !found;444 445 CHECK_FCT_DO( ret = fd_event_send(peer->p_events, FDEVP_CNX_INCOMING, sizeof(ev_data), ev_data), goto out );446 447 out:448 CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );449 450 if (ret == 0) {451 /* Reset the "out" parameters, so that they are not cleanup on function return. */452 *cer = NULL;453 *cnx = NULL;454 }455 456 return ret;457 }458 459 /* Save a callback to accept / reject incoming unknown peers */460 int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) )461 {462 463 TODO("...");464 return ENOTSUP;465 }466 467 /* Validate a peer by calling the callbacks in turn -- return 0 if the peer is validated, ! 0 in case of error or if the peer is rejected */468 int fd_peer_validate( struct fd_peer * peer )469 {470 TODO("Default to reject");471 TODO("Call all callbacks in turn");472 TODO("Save cb2 in the peer if needed");473 return ENOTSUP;474 } -
freeDiameter/sctp.c
r29 r20 35 35 36 36 #include "fD.h" 37 #include "cnxctx.h"38 37 39 #include <netinet/sctp.h> 40 #include <sys/uio.h> 41 42 /* Size of buffer to receive ancilliary data. May need to be enlarged if more sockopt are set... */ 43 #ifndef CMSG_BUF_LEN 44 #define CMSG_BUF_LEN 1024 45 #endif /* CMSG_BUF_LEN */ 46 47 /* Level of SCTP-specific traces */ 48 #ifdef DEBUG_SCTP 49 #define SCTP_LEVEL FULL 50 #else /* DEBUG_SCTP */ 51 #define SCTP_LEVEL ANNOYING 52 #endif /* DEBUG_SCTP */ 53 54 /* Pre-binding socket options -- # streams read in config */ 55 static int fd_setsockopt_prebind(int sk) 38 int fd_sctp_create_bind_server( int * socket, uint16_t port ) 56 39 { 57 socklen_t sz;40 TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); 58 41 59 TRACE_ENTRY( "%d", sk); 60 61 CHECK_PARAMS( sk > 0 ); 62 63 /* Subscribe to some notifications */ 64 { 65 struct sctp_event_subscribe event; 66 67 memset(&event, 0, sizeof(event)); 68 event.sctp_data_io_event = 1; /* to receive the stream ID in SCTP_SNDRCV ancilliary data on message reception */ 69 event.sctp_association_event = 0; /* new or closed associations (mostly for one-to-many style sockets) */ 70 event.sctp_address_event = 1; /* address changes */ 71 event.sctp_send_failure_event = 1; /* delivery failures */ 72 event.sctp_peer_error_event = 1; /* remote peer sends an error */ 73 event.sctp_shutdown_event = 1; /* peer has sent a SHUTDOWN */ 74 event.sctp_partial_delivery_event = 1; /* a partial delivery is aborted, probably indicating the connection is being shutdown */ 75 // event.sctp_adaptation_layer_event = 0; /* adaptation layer notifications */ 76 // event.sctp_authentication_event = 0; /* when new key is made active */ 77 78 /* Set the option to the socket */ 79 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) ); 80 81 if (TRACE_BOOL(SCTP_LEVEL)) { 82 sz = sizeof(event); 83 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_EVENTS, &event, &sz) ); 84 if (sz != sizeof(event)) 85 { 86 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(event)); 87 return ENOTSUP; 88 } 89 90 fd_log_debug( "SCTP_EVENTS : sctp_data_io_event : %hhu\n", event.sctp_data_io_event); 91 fd_log_debug( " sctp_association_event : %hhu\n", event.sctp_association_event); 92 fd_log_debug( " sctp_address_event : %hhu\n", event.sctp_address_event); 93 fd_log_debug( " sctp_send_failure_event : %hhu\n", event.sctp_send_failure_event); 94 fd_log_debug( " sctp_peer_error_event : %hhu\n", event.sctp_peer_error_event); 95 fd_log_debug( " sctp_shutdown_event : %hhu\n", event.sctp_shutdown_event); 96 fd_log_debug( " sctp_partial_delivery_event : %hhu\n", event.sctp_partial_delivery_event); 97 fd_log_debug( " sctp_adaptation_layer_event : %hhu\n", event.sctp_adaptation_layer_event); 98 // fd_log_debug( " sctp_authentication_event : %hhu\n", event.sctp_authentication_event); 99 } 100 101 } 102 103 /* Set the INIT parameters, such as number of streams */ 104 { 105 struct sctp_initmsg init; 106 memset(&init, 0, sizeof(init)); 107 108 if (TRACE_BOOL(SCTP_LEVEL)) { 109 sz = sizeof(init); 110 111 /* Read socket defaults */ 112 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); 113 if (sz != sizeof(init)) 114 { 115 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(init)); 116 return ENOTSUP; 117 } 118 fd_log_debug( "Def SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); 119 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); 120 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); 121 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); 122 } 123 124 /* Set the init options -- need to receive SCTP_COMM_UP to confirm the requested parameters */ 125 init.sinit_num_ostreams = fd_g_config->cnf_sctp_str; /* desired number of outgoing streams */ 126 init.sinit_max_init_timeo = CNX_TIMEOUT * 1000; 127 128 /* Set the option to the socket */ 129 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init)) ); 130 131 if (TRACE_BOOL(SCTP_LEVEL)) { 132 /* Check new values */ 133 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz) ); 134 fd_log_debug( "New SCTP_INITMSG : sinit_num_ostreams : %hu\n", init.sinit_num_ostreams); 135 fd_log_debug( " sinit_max_instreams : %hu\n", init.sinit_max_instreams); 136 fd_log_debug( " sinit_max_attempts : %hu\n", init.sinit_max_attempts); 137 fd_log_debug( " sinit_max_init_timeo : %hu\n", init.sinit_max_init_timeo); 138 } 139 } 140 141 /* Set the SCTP_DISABLE_FRAGMENTS option, required for TLS */ 142 #ifdef SCTP_DISABLE_FRAGMENTS 143 { 144 int nofrag; 145 146 if (TRACE_BOOL(SCTP_LEVEL)) { 147 sz = sizeof(nofrag); 148 /* Read socket defaults */ 149 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); 150 if (sz != sizeof(nofrag)) 151 { 152 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nofrag)); 153 return ENOTSUP; 154 } 155 fd_log_debug( "Def SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); 156 } 157 158 nofrag = 0; /* We turn ON the fragmentation */ 159 160 /* Set the option to the socket */ 161 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, sizeof(nofrag)) ); 162 163 if (TRACE_BOOL(SCTP_LEVEL)) { 164 /* Check new values */ 165 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS, &nofrag, &sz) ); 166 fd_log_debug( "New SCTP_DISABLE_FRAGMENTS value : %s\n", nofrag ? "true" : "false"); 167 } 168 } 169 #else /* SCTP_DISABLE_FRAGMENTS */ 170 # error "TLS requires support of SCTP_DISABLE_FRAGMENTS" 171 #endif /* SCTP_DISABLE_FRAGMENTS */ 172 173 174 /* Set the RETRANSMIT parameters */ 175 #ifdef SCTP_RTOINFO 176 { 177 struct sctp_rtoinfo rtoinfo; 178 memset(&rtoinfo, 0, sizeof(rtoinfo)); 179 180 if (TRACE_BOOL(SCTP_LEVEL)) { 181 sz = sizeof(rtoinfo); 182 /* Read socket defaults */ 183 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); 184 if (sz != sizeof(rtoinfo)) 185 { 186 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(rtoinfo)); 187 return ENOTSUP; 188 } 189 fd_log_debug( "Def SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); 190 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); 191 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); 192 } 193 194 rtoinfo.srto_max = fd_g_config->cnf_timer_tw * 500 - 1000; /* Maximum retransmit timer (in ms) (set to Tw / 2 - 1) */ 195 196 /* Set the option to the socket */ 197 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, sizeof(rtoinfo)) ); 198 199 if (TRACE_BOOL(SCTP_LEVEL)) { 200 /* Check new values */ 201 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz) ); 202 fd_log_debug( "New SCTP_RTOINFO : srto_initial : %u\n", rtoinfo.srto_initial); 203 fd_log_debug( " srto_max : %u\n", rtoinfo.srto_max); 204 fd_log_debug( " srto_min : %u\n", rtoinfo.srto_min); 205 } 206 } 207 #else /* SCTP_RTOINFO */ 208 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_RTOINFO"); 209 #endif /* SCTP_RTOINFO */ 210 211 /* Set the ASSOCIATION parameters */ 212 #ifdef SCTP_ASSOCINFO 213 { 214 struct sctp_assocparams assoc; 215 memset(&assoc, 0, sizeof(assoc)); 216 217 if (TRACE_BOOL(SCTP_LEVEL)) { 218 sz = sizeof(assoc); 219 /* Read socket defaults */ 220 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); 221 if (sz != sizeof(assoc)) 222 { 223 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(assoc)); 224 return ENOTSUP; 225 } 226 fd_log_debug( "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); 227 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); 228 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); 229 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); 230 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); 231 } 232 233 assoc.sasoc_asocmaxrxt = 5; /* Maximum retransmission attempts: we want fast detection of errors */ 234 235 /* Set the option to the socket */ 236 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, sizeof(assoc)) ); 237 238 if (TRACE_BOOL(SCTP_LEVEL)) { 239 /* Check new values */ 240 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz) ); 241 fd_log_debug( "New SCTP_ASSOCINFO : sasoc_asocmaxrxt : %hu\n", assoc.sasoc_asocmaxrxt); 242 fd_log_debug( " sasoc_number_peer_destinations : %hu\n", assoc.sasoc_number_peer_destinations); 243 fd_log_debug( " sasoc_peer_rwnd : %u\n" , assoc.sasoc_peer_rwnd); 244 fd_log_debug( " sasoc_local_rwnd : %u\n" , assoc.sasoc_local_rwnd); 245 fd_log_debug( " sasoc_cookie_life : %u\n" , assoc.sasoc_cookie_life); 246 } 247 } 248 #else /* SCTP_ASSOCINFO */ 249 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_ASSOCINFO"); 250 #endif /* SCTP_ASSOCINFO */ 251 252 253 /* The SO_LINGER option will be re-set if we want to perform SCTP ABORT */ 254 #ifdef SO_LINGER 255 { 256 struct linger linger; 257 memset(&linger, 0, sizeof(linger)); 258 259 if (TRACE_BOOL(SCTP_LEVEL)) { 260 sz = sizeof(linger); 261 /* Read socket defaults */ 262 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); 263 if (sz != sizeof(linger)) 264 { 265 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(linger)); 266 return ENOTSUP; 267 } 268 fd_log_debug( "Def SO_LINGER : l_onoff : %d\n", linger.l_onoff); 269 fd_log_debug( " l_linger : %d\n", linger.l_linger); 270 } 271 272 linger.l_onoff = 0; /* Do not activate the linger */ 273 linger.l_linger = 0; /* Return immediately when closing (=> abort) */ 274 275 /* Set the option */ 276 CHECK_SYS( setsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)) ); 277 278 if (TRACE_BOOL(SCTP_LEVEL)) { 279 /* Check new values */ 280 CHECK_SYS( getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz) ); 281 fd_log_debug( "New SO_LINGER : l_onoff : %d\n", linger.l_onoff); 282 fd_log_debug( " l_linger : %d\n", linger.l_linger); 283 } 284 } 285 #else /* SO_LINGER */ 286 TRACE_DEBUG(SCTP_LEVEL, "Skipping SO_LINGER"); 287 #endif /* SO_LINGER */ 288 289 /* Set the NODELAY option (Nagle-like algorithm) */ 290 #ifdef SCTP_NODELAY 291 { 292 int nodelay; 293 294 if (TRACE_BOOL(SCTP_LEVEL)) { 295 sz = sizeof(nodelay); 296 /* Read socket defaults */ 297 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); 298 if (sz != sizeof(nodelay)) 299 { 300 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(nodelay)); 301 return ENOTSUP; 302 } 303 fd_log_debug( "Def SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); 304 } 305 306 nodelay = 0; /* We turn ON the Nagle algorithm (probably the default already) */ 307 308 /* Set the option to the socket */ 309 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay)) ); 310 311 if (TRACE_BOOL(SCTP_LEVEL)) { 312 /* Check new values */ 313 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, &sz) ); 314 fd_log_debug( "New SCTP_NODELAY value : %s\n", nodelay ? "true" : "false"); 315 } 316 } 317 #else /* SCTP_NODELAY */ 318 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_NODELAY"); 319 #endif /* SCTP_NODELAY */ 320 321 /* Set the interleaving option */ 322 #ifdef SCTP_FRAGMENT_INTERLEAVE 323 { 324 int interleave; 325 326 if (TRACE_BOOL(SCTP_LEVEL)) { 327 sz = sizeof(interleave); 328 /* Read socket defaults */ 329 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); 330 if (sz != sizeof(interleave)) 331 { 332 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(interleave)); 333 return ENOTSUP; 334 } 335 fd_log_debug( "Def SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave); 336 } 337 338 #if 0 339 interleave = 2; /* Allow partial delivery on several streams at the same time, since we are stream-aware in our security modules */ 340 #else /* 0 */ 341 interleave = 1; /* hmmm actually, we are not yet capable of handling this, and we don t need it. */ 342 #endif /* 0 */ 343 344 /* Set the option to the socket */ 345 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, sizeof(interleave)) ); 346 347 if (TRACE_BOOL(SCTP_LEVEL)) { 348 /* Check new values */ 349 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE, &interleave, &sz) ); 350 fd_log_debug( "New SCTP_FRAGMENT_INTERLEAVE value : %d\n", interleave); 351 } 352 } 353 #else /* SCTP_FRAGMENT_INTERLEAVE */ 354 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_FRAGMENT_INTERLEAVE"); 355 #endif /* SCTP_FRAGMENT_INTERLEAVE */ 356 357 /* Set the v4 mapped addresses option */ 358 #ifdef SCTP_I_WANT_MAPPED_V4_ADDR 359 { 360 int v4mapped; 361 362 if (TRACE_BOOL(SCTP_LEVEL)) { 363 sz = sizeof(v4mapped); 364 /* Read socket defaults */ 365 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); 366 if (sz != sizeof(v4mapped)) 367 { 368 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(v4mapped)); 369 return ENOTSUP; 370 } 371 fd_log_debug( "Def SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); 372 } 373 374 #ifndef SCTP_USE_MAPPED_ADDRESSES 375 v4mapped = 0; /* We don't want v4 mapped addresses */ 376 #else /* SCTP_USE_MAPPED_ADDRESSES */ 377 v4mapped = 1; /* but we may have to, otherwise the bind fails in some environments */ 378 #endif /* SCTP_USE_MAPPED_ADDRESSES */ 379 380 /* Set the option to the socket */ 381 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, sizeof(v4mapped)) ); 382 383 if (TRACE_BOOL(SCTP_LEVEL)) { 384 /* Check new values */ 385 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_I_WANT_MAPPED_V4_ADDR, &v4mapped, &sz) ); 386 fd_log_debug( "New SCTP_I_WANT_MAPPED_V4_ADDR value : %s\n", v4mapped ? "true" : "false"); 387 } 388 } 389 #else /* SCTP_I_WANT_MAPPED_V4_ADDR */ 390 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_I_WANT_MAPPED_V4_ADDR"); 391 #endif /* SCTP_I_WANT_MAPPED_V4_ADDR */ 392 393 394 /* Other settable options (draft-ietf-tsvwg-sctpsocket-17): 395 SO_RCVBUF size of receiver window 396 SO_SNDBUF size of pending data to send 397 SCTP_AUTOCLOSE for one-to-many only 398 SCTP_SET_PEER_PRIMARY_ADDR ask remote peer to use this local address as primary 399 SCTP_PRIMARY_ADDR use this address as primary locally 400 SCTP_ADAPTATION_LAYER set adaptation layer indication 401 SCTP_PEER_ADDR_PARAMS control heartbeat per peer address 402 SCTP_DEFAULT_SEND_PARAM parameters for the sendto() call 403 SCTP_MAXSEG max size of fragmented segments -- bound to PMTU 404 SCTP_AUTH_CHUNK request authentication of some type of chunk 405 SCTP_HMAC_IDENT authentication algorithms 406 SCTP_AUTH_KEY set a shared key 407 SCTP_AUTH_ACTIVE_KEY set the active key 408 SCTP_AUTH_DELETE_KEY remove a key 409 SCTP_AUTH_DEACTIVATE_KEY will not use that key anymore 410 SCTP_DELAYED_SACK control delayed acks 411 SCTP_PARTIAL_DELIVERY_POINT control partial delivery size 412 SCTP_USE_EXT_RCVINFO use extended receive info structure (information about the next message if available) 413 SCTP_MAX_BURST number of packets that can be burst emitted 414 SCTP_CONTEXT save a context information along with the association. 415 SCTP_EXPLICIT_EOR enable sending one message across several send calls 416 SCTP_REUSE_PORT share one listening port with several sockets 417 418 read-only options: 419 SCTP_STATUS retrieve info such as number of streams, pending packets, state, ... 420 SCTP_GET_PEER_ADDR_INFO get information about a specific peer address of the association. 421 SCTP_PEER_AUTH_CHUNKS list of chunks the remote peer wants authenticated 422 SCTP_LOCAL_AUTH_CHUNKS list of chunks the local peer wants authenticated 423 SCTP_GET_ASSOC_NUMBER number of associations in a one-to-many socket 424 SCTP_GET_ASSOC_ID_LIST list of these associations 425 */ 426 427 /* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */ 428 #ifdef IPV6_V6ONLY 429 if (fd_g_config->cnf_flags.no_ip4) { 430 int opt = 1; 431 CHECK_SYS(setsockopt(sk, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt))); 432 } 433 #endif /* IPV6_V6ONLY */ 434 435 return 0; 42 return ENOTSUP; 436 43 } 437 44 438 439 /* Post-binding socket options */ 440 static int fd_setsockopt_postbind(int sk, int bound_to_default) 45 int fd_sctp_get_str_info( int socket, int *in, int *out ) 441 46 { 442 T RACE_ENTRY( "%d %d", sk, bound_to_default);47 TODO("Retrieve streams info from the socket"); 443 48 444 CHECK_PARAMS( (sk > 0) ); 445 446 /* Set the ASCONF option */ 447 #ifdef SCTP_AUTO_ASCONF 448 { 449 int asconf; 450 451 if (TRACE_BOOL(SCTP_LEVEL)) { 452 socklen_t sz; 453 454 sz = sizeof(asconf); 455 /* Read socket defaults */ 456 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); 457 if (sz != sizeof(asconf)) 458 { 459 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %d", sz, (socklen_t)sizeof(asconf)); 460 return ENOTSUP; 461 } 462 fd_log_debug( "Def SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false"); 463 } 464 465 asconf = bound_to_default ? 1 : 0; /* allow automatic use of added or removed addresses in the association (for bound-all sockets) */ 466 467 /* Set the option to the socket */ 468 CHECK_SYS( setsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, sizeof(asconf)) ); 469 470 if (TRACE_BOOL(SCTP_LEVEL)) { 471 socklen_t sz = sizeof(asconf); 472 /* Check new values */ 473 CHECK_SYS( getsockopt(sk, IPPROTO_SCTP, SCTP_AUTO_ASCONF, &asconf, &sz) ); 474 fd_log_debug( "New SCTP_AUTO_ASCONF value : %s\n", asconf ? "true" : "false"); 475 } 476 } 477 #else /* SCTP_AUTO_ASCONF */ 478 TRACE_DEBUG(SCTP_LEVEL, "Skipping SCTP_AUTO_ASCONF"); 479 #endif /* SCTP_AUTO_ASCONF */ 480 481 return 0; 49 return ENOTSUP; 482 50 } 483 484 /* Create a socket server and bind it according to daemon s configuration */485 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port )486 {487 int family;488 int bind_default;489 490 TRACE_ENTRY("%p %p %hu", sock, list, port);491 CHECK_PARAMS(sock);492 493 if (fd_g_config->cnf_flags.no_ip6) {494 family = AF_INET;495 } else {496 family = AF_INET6; /* can create socket for both IP and IPv6 */497 }498 499 /* Create the socket */500 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );501 502 /* Set pre-binding socket options, including number of streams etc... */503 CHECK_FCT( fd_setsockopt_prebind(*sock) );504 505 bind_default = (! list) || (FD_IS_LIST_EMPTY(list)) ;506 redo:507 if ( bind_default ) {508 /* Implicit endpoints : bind to default addresses */509 union {510 sSS ss;511 sSA sa;512 sSA4 sin;513 sSA6 sin6;514 } s;515 516 /* 0.0.0.0 and [::] are all zeros */517 memset(&s, 0, sizeof(s));518 519 s.sa.sa_family = family;520 521 if (family == AF_INET)522 s.sin.sin_port = htons(port);523 else524 s.sin6.sin6_port = htons(port);525 526 CHECK_SYS( bind(*sock, &s.sa, sizeof(s)) );527 528 } else {529 /* Explicit endpoints to bind to from config */530 531 union {532 sSA * sa;533 sSA4 *sin;534 sSA6 *sin6;535 uint8_t *buf;536 } ptr;537 union {538 sSA * sa;539 uint8_t * buf;540 } sar;541 int count = 0; /* number of sock addr in sar array */542 size_t offset = 0;543 struct fd_list * li;544 545 sar.buf = NULL;546 547 /* Create a flat array from the list of configured addresses */548 for (li = list->next; li != list; li = li->next) {549 struct fd_endpoint * ep = (struct fd_endpoint *)li;550 size_t sz = 0;551 552 if (! (ep->flags & EP_FL_CONF))553 continue;554 555 count++;556 557 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */558 #ifndef SCTP_USE_MAPPED_ADDRESSES559 if (ep->sa.sa_family == AF_INET6)560 #else /* SCTP_USE_MAPPED_ADDRESSES */561 if (family == AF_INET6)562 #endif /* SCTP_USE_MAPPED_ADDRESSES */563 sz = sizeof(sSA6);564 else565 sz = sizeof(sSA4);566 567 /* augment sar to contain the additional info */568 CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz) );569 570 ptr.buf = sar.buf + offset; /* place of the new SA */571 offset += sz; /* update to end of sar */572 573 if (sz == sizeof(sSA4)) {574 memcpy(ptr.buf, &ep->sin, sz);575 ptr.sin->sin_port = htons(port);576 } else {577 if (ep->sa.sa_family == AF_INET) { /* We must map the address */578 memset(ptr.buf, 0, sz);579 ptr.sin6->sin6_family = AF_INET6;580 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );581 } else {582 memcpy(ptr.sin6, &ep->sin6, sz);583 }584 ptr.sin6->sin6_port = htons(port);585 }586 }587 588 if (!count) {589 /* None of the addresses in the list came from configuration, we bind to default */590 bind_default = 1;591 goto redo;592 }593 594 if (TRACE_BOOL(SCTP_LEVEL)) {595 int i;596 ptr.buf = sar.buf;597 fd_log_debug("Calling sctp_bindx with the following address array:\n");598 for (i = 0; i < count; i++) {599 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );600 ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ;601 }602 }603 604 /* Bind to this array */605 CHECK_SYS( sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR) );606 607 /* We don't need sar anymore */608 free(sar.buf);609 }610 611 /* Now, the server is bound, set remaining sockopt */612 CHECK_FCT( fd_setsockopt_postbind(*sock, bind_default) );613 614 /* Debug: show all local listening addresses */615 if (TRACE_BOOL(SCTP_LEVEL)) {616 sSA *sar;617 union {618 sSA *sa;619 uint8_t *buf;620 } ptr;621 int sz;622 623 CHECK_SYS( sz = sctp_getladdrs(*sock, 0, &sar) );624 625 fd_log_debug("SCTP server bound on :\n");626 for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) {627 TRACE_DEBUG_sSA(FULL, " - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );628 }629 sctp_freeladdrs(sar);630 }631 632 return 0;633 }634 635 /* Allow clients connections on server sockets */636 int fd_sctp_listen( int sock )637 {638 TRACE_ENTRY("%d", sock);639 CHECK_SYS( listen(sock, 5) );640 return 0;641 }642 643 /* Create a client socket and connect to remote server */644 int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )645 {646 int family;647 int count = 0;648 size_t offset = 0, sz;649 union {650 uint8_t *buf;651 sSA *sa;652 } sar;653 union {654 uint8_t *buf;655 sSA *sa;656 sSA4 *sin;657 sSA6 *sin6;658 } ptr;659 struct fd_list * li;660 int ret;661 662 sar.buf = NULL;663 664 TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);665 CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );666 667 if (no_ip6) {668 family = AF_INET;669 } else {670 family = AF_INET6;671 }672 673 /* Create the socket */674 CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );675 676 /* Cleanup if we are cancelled */677 pthread_cleanup_push(fd_cleanup_socket, sock);678 679 /* Set the socket options */680 CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );681 682 /* Create the array of addresses for sctp_connectx */683 for (li = list->next; li != list; li = li->next) {684 struct fd_endpoint * ep = (struct fd_endpoint *) li;685 686 count++;687 688 /* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */689 #ifndef SCTP_USE_MAPPED_ADDRESSES690 if (ep->sa.sa_family == AF_INET6)691 #else /* SCTP_USE_MAPPED_ADDRESSES */692 if (family == AF_INET6)693 #endif /* SCTP_USE_MAPPED_ADDRESSES */694 sz = sizeof(sSA6);695 else696 sz = sizeof(sSA4);697 698 /* augment sar to contain the additional info */699 CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; } );700 701 ptr.buf = sar.buf + offset; /* place of the new SA */702 offset += sz; /* update to end of sar */703 704 if (sz == sizeof(sSA4)) {705 memcpy(ptr.buf, &ep->sin, sz);706 ptr.sin->sin_port = htons(port);707 } else {708 if (ep->sa.sa_family == AF_INET) { /* We must map the address */709 memset(ptr.buf, 0, sz);710 ptr.sin6->sin6_family = AF_INET6;711 IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );712 } else {713 memcpy(ptr.sin6, &ep->sin6, sz);714 }715 ptr.sin6->sin6_port = htons(port);716 }717 }718 719 /* Try connecting */720 TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted)...", count);721 CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } );722 free(sar.buf); sar.buf = NULL;723 724 /* Set the remaining sockopts */725 CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail );726 727 /* Done! */728 pthread_cleanup_pop(0);729 return 0;730 731 fail:732 if (*sock > 0) {733 shutdown(*sock, SHUT_RDWR);734 *sock = -1;735 }736 free(sar.buf);737 return ret;738 }739 740 /* Retrieve streams information from a connected association -- optionaly provide the primary address */741 int fd_sctp_get_str_info( int sock, uint16_t *in, uint16_t *out, sSS *primary )742 {743 struct sctp_status status;744 socklen_t sz = sizeof(status);745 746 TRACE_ENTRY("%d %p %p %p", sock, in, out, primary);747 CHECK_PARAMS( (sock > 0) && in && out );748 749 /* Read the association parameters */750 memset(&status, 0, sizeof(status));751 CHECK_SYS( getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) );752 if (sz != sizeof(status))753 {754 TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %zd", sz, sizeof(status));755 return ENOTSUP;756 }757 if (TRACE_BOOL(SCTP_LEVEL)) {758 fd_log_debug( "SCTP_STATUS : sstat_state : %i\n" , status.sstat_state);759 fd_log_debug( " sstat_rwnd : %u\n" , status.sstat_rwnd);760 fd_log_debug( " sstat_unackdata : %hu\n", status.sstat_unackdata);761 fd_log_debug( " sstat_penddata : %hu\n", status.sstat_penddata);762 fd_log_debug( " sstat_instrms : %hu\n", status.sstat_instrms);763 fd_log_debug( " sstat_outstrms : %hu\n", status.sstat_outstrms);764 fd_log_debug( " sstat_fragmentation_point : %u\n" , status.sstat_fragmentation_point);765 fd_log_debug( " sstat_primary.spinfo_address : ");766 sSA_DUMP_NODE_SERV(&status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV );767 fd_log_debug( "\n" );768 fd_log_debug( " sstat_primary.spinfo_state : %d\n" , status.sstat_primary.spinfo_state);769 fd_log_debug( " sstat_primary.spinfo_cwnd : %u\n" , status.sstat_primary.spinfo_cwnd);770 fd_log_debug( " sstat_primary.spinfo_srtt : %u\n" , status.sstat_primary.spinfo_srtt);771 fd_log_debug( " sstat_primary.spinfo_rto : %u\n" , status.sstat_primary.spinfo_rto);772 fd_log_debug( " sstat_primary.spinfo_mtu : %u\n" , status.sstat_primary.spinfo_mtu);773 }774 775 *in = status.sstat_instrms;776 *out = status.sstat_outstrms;777 778 if (primary)779 memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS));780 781 return 0;782 }783 784 /* Get the list of local endpoints of the socket */785 int fd_sctp_get_local_ep(int sock, struct fd_list * list)786 {787 union {788 sSA *sa;789 uint8_t *buf;790 } ptr;791 792 sSA * data;793 int count;794 795 TRACE_ENTRY("%d %p", sock, list);796 CHECK_PARAMS(list);797 798 /* Read the list on the socket */799 CHECK_SYS( count = sctp_getladdrs(sock, 0, &data) );800 ptr.sa = data;801 802 while (count) {803 socklen_t sl;804 switch (ptr.sa->sa_family) {805 case AF_INET: sl = sizeof(sSA4); break;806 case AF_INET6: sl = sizeof(sSA6); break;807 default:808 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);809 }810 811 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );812 ptr.buf += sl;813 count --;814 }815 816 /* Free the list */817 sctp_freeladdrs(data);818 819 /* Now get the primary address, the add function will take care of merging with existing entry */820 {821 822 struct sctp_status status;823 socklen_t sz = sizeof(status);824 int ret;825 826 memset(&status, 0, sizeof(status));827 /* Attempt to use SCTP_STATUS message to retrieve the primary address */828 ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz);829 if (sz != sizeof(status))830 ret = -1;831 sz = sizeof(sSS);832 if (ret < 0)833 {834 /* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */835 CHECK_SYS(getsockname(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz));836 }837 838 CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) );839 }840 841 return 0;842 }843 844 /* Get the list of remote endpoints of the socket */845 int fd_sctp_get_remote_ep(int sock, struct fd_list * list)846 {847 union {848 sSA *sa;849 uint8_t *buf;850 } ptr;851 852 sSA * data;853 int count;854 855 TRACE_ENTRY("%d %p", sock, list);856 CHECK_PARAMS(list);857 858 /* Read the list on the socket */859 CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data) );860 ptr.sa = data;861 862 while (count) {863 socklen_t sl;864 switch (ptr.sa->sa_family) {865 case AF_INET: sl = sizeof(sSA4); break;866 case AF_INET6: sl = sizeof(sSA6); break;867 default:868 TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d", ptr.sa->sa_family);869 }870 871 CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );872 ptr.buf += sl;873 count --;874 }875 876 /* Free the list */877 sctp_freepaddrs(data);878 879 /* Now get the primary address, the add function will take care of merging with existing entry */880 {881 sSS ss;882 socklen_t sl = sizeof(sSS);883 884 CHECK_SYS(getpeername(sock, (sSA *)&ss, &sl));885 CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) );886 }887 888 /* Done! */889 return 0;890 }891 892 /* Send a buffer over a specified stream */893 int fd_sctp_sendstr(int sock, uint16_t strid, uint8_t * buf, size_t len)894 {895 struct msghdr mhdr;896 struct iovec iov;897 struct {898 struct cmsghdr hdr;899 struct sctp_sndrcvinfo sndrcv;900 } anci;901 ssize_t ret;902 903 TRACE_ENTRY("%d %hu %p %zd", sock, strid, buf, len);904 905 memset(&mhdr, 0, sizeof(mhdr));906 memset(&iov, 0, sizeof(iov));907 memset(&anci, 0, sizeof(anci));908 909 /* IO Vector: message data */910 iov.iov_base = buf;911 iov.iov_len = len;912 913 /* Anciliary data: specify SCTP stream */914 anci.hdr.cmsg_len = sizeof(anci);915 anci.hdr.cmsg_level = IPPROTO_SCTP;916 anci.hdr.cmsg_type = SCTP_SNDRCV;917 anci.sndrcv.sinfo_stream = strid;918 /* note : we could store other data also, for example in .sinfo_ppid for remote peer or in .sinfo_context for errors. */919 920 /* We don't use mhdr.msg_name here; it could be used to specify an address different from the primary */921 922 mhdr.msg_iov = &iov;923 mhdr.msg_iovlen = 1;924 925 mhdr.msg_control = &anci;926 mhdr.msg_controllen = sizeof(anci);927 928 TRACE_DEBUG(FULL, "Sending %db data on stream %hu of socket %d", len, strid, sock);929 930 CHECK_SYS( ret = sendmsg(sock, &mhdr, 0) );931 ASSERT( ret == len ); /* There should not be partial delivery with sendmsg... */932 933 return 0;934 }935 936 /* Receive the next data from the socket, or next notification */937 int fd_sctp_recvmeta(int sock, uint16_t * strid, uint8_t ** buf, size_t * len, int *event)938 {939 ssize_t ret = 0;940 struct msghdr mhdr;941 char ancidata[ CMSG_BUF_LEN ];942 struct iovec iov;943 uint8_t *data = NULL;944 size_t bufsz = 0, datasize = 0;945 size_t mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */946 947 TRACE_ENTRY("%d %p %p %p %p", sock, strid, buf, len, event);948 CHECK_PARAMS( (sock > 0) && buf && len && event );949 950 /* Cleanup out parameters */951 *buf = NULL;952 *len = 0;953 *event = 0;954 955 /* Prepare header for receiving message */956 memset(&mhdr, 0, sizeof(mhdr));957 mhdr.msg_iov = &iov;958 mhdr.msg_iovlen = 1;959 mhdr.msg_control = &ancidata;960 mhdr.msg_controllen = sizeof(ancidata);961 962 /* We will loop while all data is not received. */963 incomplete:964 if (datasize == bufsz) {965 /* The buffer is full, enlarge it */966 bufsz += mempagesz;967 CHECK_MALLOC( data = realloc(data, bufsz) );968 }969 /* the new data will be received following the preceding */970 memset(&iov, 0, sizeof(iov));971 iov.iov_base = data + datasize ;972 iov.iov_len = bufsz - datasize;973 974 /* Receive data from the socket */975 pthread_cleanup_push(free, data);976 ret = recvmsg(sock, &mhdr, 0);977 pthread_cleanup_pop(0);978 979 /* Handle errors */980 if (ret <= 0) { /* Socket is closed, or an error occurred */981 CHECK_SYS_DO(ret, /* to log in case of error */);982 free(data);983 *event = FDEVP_CNX_ERROR;984 return 0;985 }986 987 /* Update the size of data we received */988 datasize += ret;989 990 /* SCTP provides an indication when we received a full record; loop if it is not the case */991 if ( ! (mhdr.msg_flags & MSG_EOR) ) {992 goto incomplete;993 }994 995 TRACE_DEBUG(FULL, "Received %db data on socket %d", datasize, sock);996 997 /* Handle the case where the data received is a notification */998 if (mhdr.msg_flags & MSG_NOTIFICATION) {999 union sctp_notification * notif = (union sctp_notification *) data;1000 1001 switch (notif->sn_header.sn_type) {1002 1003 case SCTP_ASSOC_CHANGE:1004 TRACE_DEBUG(FULL, "Received SCTP_ASSOC_CHANGE notification");1005 TRACE_DEBUG(SCTP_LEVEL, " state : %hu", notif->sn_assoc_change.sac_state);1006 TRACE_DEBUG(SCTP_LEVEL, " error : %hu", notif->sn_assoc_change.sac_error);1007 TRACE_DEBUG(SCTP_LEVEL, " instr : %hu", notif->sn_assoc_change.sac_inbound_streams);1008 TRACE_DEBUG(SCTP_LEVEL, " outstr : %hu", notif->sn_assoc_change.sac_outbound_streams);1009 1010 *event = FDEVP_CNX_EP_CHANGE;1011 break;1012 1013 case SCTP_PEER_ADDR_CHANGE:1014 TRACE_DEBUG(FULL, "Received SCTP_PEER_ADDR_CHANGE notification");1015 TRACE_DEBUG_sSA(SCTP_LEVEL, " intf_change : ", &(notif->sn_paddr_change.spc_aaddr), NI_NUMERICHOST | NI_NUMERICSERV, "" );1016 TRACE_DEBUG(SCTP_LEVEL, " state : %d", notif->sn_paddr_change.spc_state);1017 TRACE_DEBUG(SCTP_LEVEL, " error : %d", notif->sn_paddr_change.spc_error);1018 1019 *event = FDEVP_CNX_EP_CHANGE;1020 break;1021 1022 case SCTP_SEND_FAILED:1023 TRACE_DEBUG(FULL, "Received SCTP_SEND_FAILED notification");1024 TRACE_DEBUG(SCTP_LEVEL, " len : %hu", notif->sn_send_failed.ssf_length);1025 TRACE_DEBUG(SCTP_LEVEL, " err : %d", notif->sn_send_failed.ssf_error);1026 1027 *event = FDEVP_CNX_ERROR;1028 break;1029 1030 case SCTP_REMOTE_ERROR:1031 TRACE_DEBUG(FULL, "Received SCTP_REMOTE_ERROR notification");1032 TRACE_DEBUG(SCTP_LEVEL, " err : %hu", ntohs(notif->sn_remote_error.sre_error));1033 TRACE_DEBUG(SCTP_LEVEL, " len : %hu", ntohs(notif->sn_remote_error.sre_length));1034 1035 *event = FDEVP_CNX_ERROR;1036 break;1037 1038 case SCTP_SHUTDOWN_EVENT:1039 TRACE_DEBUG(FULL, "Received SCTP_SHUTDOWN_EVENT notification");1040 1041 *event = FDEVP_CNX_ERROR;1042 break;1043 1044 default:1045 TRACE_DEBUG(FULL, "Received unknown notification %d, assume error", notif->sn_header.sn_type);1046 *event = FDEVP_CNX_ERROR;1047 }1048 1049 free(data);1050 return 0;1051 }1052 1053 /* From this point, we have received a message */1054 *event = FDEVP_CNX_MSG_RECV;1055 *buf = data;1056 *len = datasize;1057 1058 if (strid) {1059 struct cmsghdr *hdr;1060 struct sctp_sndrcvinfo *sndrcv;1061 1062 /* Handle the anciliary data */1063 for (hdr = CMSG_FIRSTHDR(&mhdr); hdr; hdr = CMSG_NXTHDR(&mhdr, hdr)) {1064 1065 /* We deal only with anciliary data at SCTP level */1066 if (hdr->cmsg_level != IPPROTO_SCTP) {1067 TRACE_DEBUG(FULL, "Received some anciliary data at level %d, skipped", hdr->cmsg_level);1068 continue;1069 }1070 1071 /* Also only interested in SCTP_SNDRCV message for the moment */1072 if (hdr->cmsg_type != SCTP_SNDRCV) {1073 TRACE_DEBUG(FULL, "Anciliary block IPPROTO_SCTP / %d, skipped", hdr->cmsg_type);1074 continue;1075 }1076 1077 sndrcv = (struct sctp_sndrcvinfo *) CMSG_DATA(hdr);1078 if (TRACE_BOOL(SCTP_LEVEL)) {1079 fd_log_debug( "Anciliary block IPPROTO_SCTP / SCTP_SNDRCV\n");1080 fd_log_debug( " sinfo_stream : %hu\n", sndrcv->sinfo_stream);1081 fd_log_debug( " sinfo_ssn : %hu\n", sndrcv->sinfo_ssn);1082 fd_log_debug( " sinfo_flags : %hu\n", sndrcv->sinfo_flags);1083 /* fd_log_debug( " sinfo_pr_policy : %hu\n", sndrcv->sinfo_pr_policy); */1084 fd_log_debug( " sinfo_ppid : %u\n" , sndrcv->sinfo_ppid);1085 fd_log_debug( " sinfo_context : %u\n" , sndrcv->sinfo_context);1086 /* fd_log_debug( " sinfo_pr_value : %u\n" , sndrcv->sinfo_pr_value); */1087 fd_log_debug( " sinfo_tsn : %u\n" , sndrcv->sinfo_tsn);1088 fd_log_debug( " sinfo_cumtsn : %u\n" , sndrcv->sinfo_cumtsn);1089 }1090 1091 *strid = sndrcv->sinfo_stream;1092 }1093 }1094 1095 return 0;1096 } -
freeDiameter/server.c
r29 r20 36 36 #include "fD.h" 37 37 38 /* Server (listening) part of the daemon */39 40 struct fd_list FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS); /* The list of all server objects */41 /* We don't need to protect this list, it is only accessed from the main daemonthread. */42 43 /* Server sinformation */38 /* This file contains the server (listening) part of the daemon */ 39 40 struct fd_list FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS); /* The list of all server sockets */ 41 /* We don't need to protect this list, it is only accessed from the main thread. */ 42 43 /* Server (listening socket) information */ 44 44 struct server { 45 45 struct fd_list chain; /* link in the FD_SERVERS list */ 46 46 47 struct cnxctx * conn; /* server connection context (listening socket) */ 47 int socket; /* server socket, or <= 0 */ 48 48 49 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 49 50 int secur; /* TLS is started immediatly after connection ? */ 50 51 51 pthread_t thr; /* The thread listening for new connections */ 52 int status; /* 0 : not created; 1 : running; 2 : terminated */ 53 54 struct fd_list clients; /* List of clients connected to this server, not yet identified */ 55 pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients */ 52 pthread_t serv_thr; /* The thread listening for new connections */ 53 int serv_status; /* 0 : not created; 1 : running; 2 : terminated */ 54 55 pthread_mutex_t clients_mtx; /* Mutex to protect the list of clients connected to the thread */ 56 struct fd_list clients; /* The list of clients connecting to this server, which information is not yet known */ 57 58 char * serv_name; /* A string to identify this server */ 56 59 }; 57 60 58 /* Client information (connecting peer for which we don't have the CER yet)*/61 /* Client (connected remote endpoint, not received CER yet) information */ 59 62 struct client { 60 63 struct fd_list chain; /* link in the server's list of clients */ 61 struct cnxctx *conn; /* Parameters of the connection */ 62 struct timespec ts; /* Deadline for receiving CER (after INCNX_TIMEOUT) */ 63 pthread_t thr; /* connection state machine */ 64 65 struct cnxctx *conn; /* Parameters of the connection; sends its events to the ev fifo bellow */ 66 67 struct timespec ts; /* Delay for receiving CER: INCNX_TIMEOUT */ 68 struct fifo *ev; /* Events of the connection -- allowed: TIMEOUT, ERROR (cnx, tls), MSG_RCV (CER, other=>error) */ 69 70 pthread_t cli_thr; /* connection state machine (simplified PSM) */ 64 71 }; 65 72 66 67 /* Dump all servers information */ 68 void fd_servers_dump() 69 { 70 struct fd_list * li, *cli; 71 72 fd_log_debug("Dumping servers list :\n"); 73 for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { 74 struct server * s = (struct server *)li; 75 fd_log_debug(" Serv %p '%s': %s, %s, %s\n", 76 s, fd_cnx_getid(s->conn), 77 IPPROTO_NAME( s->proto ), 78 s->secur ? "Secur" : "NotSecur", 79 (s->status == 0) ? "Thread not created" : 80 ((s->status == 1) ? "Thread running" : 81 ((s->status == 2) ? "Thread terminated" : 82 "Thread status unknown"))); 83 /* Dump the client list of this server */ 84 (void) pthread_mutex_lock(&s->clients_mtx); 85 for (cli = s->clients.next; cli != &s->clients; cli = cli->next) { 86 struct client * c = (struct client *)cli; 87 char bufts[128]; 88 fd_log_debug(" Connected: '%s' (timeout: %s)\n", 89 fd_cnx_getid(c->conn), 90 fd_log_time(&c->ts, bufts, sizeof(bufts))); 73 /* Parameter for the thread handling the new connected client, to avoid bloking the server thread */ 74 struct cli_fast { 75 struct server * serv; 76 int sock; 77 sSS ss; 78 socklen_t sslen; 79 }; 80 81 82 /* This thread is called when a new client had just connected */ 83 static void * handle_client_fast(void * arg) 84 { 85 struct cli_fast * cf = arg; 86 struct client * c = NULL; 87 88 /* Name the current thread */ 89 ASSERT(arg); 90 { 91 char addr[128]; 92 int offset = snprintf(addr, sizeof(addr), "Srv %d/Cli %d : ", cf->serv->socket, cf->sock); 93 int rc = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0); 94 if (rc) 95 memcpy(addr + offset, gai_strerror(rc), sizeof(addr) - offset); 96 97 if (TRACE_BOOL(INFO)) { 98 fd_log_debug( "New connection %s, sock %d, from '%s'\n", cf->serv->serv_name, cf->sock, addr + offset); 91 99 } 92 (void) pthread_mutex_unlock(&s->clients_mtx); 93 } 94 } 95 96 97 /* The state machine to handle incoming connection before the remote peer is identified */ 98 static void * client_sm(void * arg) 99 { 100 struct client * c = arg; 101 struct server * s = NULL; 102 uint8_t * buf = NULL; 103 size_t bufsz; 104 struct msg * msg = NULL; 105 struct msg_hdr *hdr = NULL; 106 107 TRACE_ENTRY("%p", c); 108 109 CHECK_PARAMS_DO(c && c->conn && c->chain.head, goto fatal_error ); 110 111 s = c->chain.head->o; 112 113 /* Name the current thread */ 114 fd_log_threadname ( fd_cnx_getid(c->conn) ); 115 116 /* Handshake if we are a secure server port, or start clear otherwise */ 117 if (s->secur) { 118 int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL, NULL); 119 if (ret != 0) { 120 if (TRACE_BOOL(INFO)) { 121 fd_log_debug("TLS handshake failed for client '%s', connection aborted.\n", fd_cnx_getid(c->conn)); 122 } 123 goto cleanup; 124 } 125 } else { 126 CHECK_FCT_DO( fd_cnx_start_clear(c->conn, 0), goto cleanup ); 127 } 128 129 /* Set the timeout to receive the first message */ 130 CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &c->ts), goto fatal_error ); 131 c->ts.tv_sec += INCNX_TIMEOUT; 132 133 /* Receive the first Diameter message on the connection -- cleanup in case of timeout */ 134 CHECK_FCT_DO( fd_cnx_receive(c->conn, &c->ts, &buf, &bufsz), goto cleanup ); 135 136 TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", bufsz, fd_cnx_getid(c->conn)); 137 138 /* Try parsing this message */ 139 CHECK_FCT_DO( fd_msg_parse_buffer( &buf, bufsz, &msg ), /* Parsing failed */ goto cleanup ); 140 141 /* We expect a CER, it must parse with our dictionary and rules */ 142 CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, NULL ), /* Parsing failed -- trace details ? */ goto cleanup ); 143 144 if (TRACE_BOOL(FULL)) { 145 fd_log_debug("Received Diameter message from new client '%s':\n", fd_cnx_getid(c->conn)); 146 fd_msg_dump_walk(FULL, msg); 147 } 148 149 /* Now check we received a CER */ 150 CHECK_FCT_DO( fd_msg_hdr ( msg, &hdr ), goto fatal_error ); 151 CHECK_PARAMS_DO( (hdr->msg_appl == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) && (hdr->msg_code == CC_CAPABILITIES_EXCHANGE), 152 { fd_log_debug("Connection '%s', expecting CER, received something else, closing...\n", fd_cnx_getid(c->conn)); goto cleanup; } ); 153 154 /* Finally, pass the information to the peers module which will handle it next */ 155 pthread_cleanup_push((void *)fd_cnx_destroy, c->conn); 156 pthread_cleanup_push((void *)fd_msg_free, msg); 157 CHECK_FCT_DO( fd_peer_handle_newCER( &msg, &c->conn ), goto cleanup ); 158 pthread_cleanup_pop(0); 159 pthread_cleanup_pop(0); 160 161 /* The end, we cleanup the client structure */ 162 cleanup: 163 /* Unlink the client structure */ 164 CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), goto fatal_error ); 165 fd_list_unlink( &c->chain ); 166 CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), goto fatal_error ); 167 168 /* Destroy the connection object if present */ 169 if (c->conn) 170 fd_cnx_destroy(c->conn); 171 172 /* Cleanup the received buffer if any */ 173 free(buf); 174 175 /* Cleanup the parsed message if any */ 176 if (msg) { 177 CHECK_FCT_DO( fd_msg_free(msg), /* continue */); 178 } 179 180 /* Detach the thread, cleanup the client structure */ 100 101 fd_log_threadname ( addr ); 102 } 103 104 /* Create a client structure */ 105 CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto early_error ); 106 memset(c, 0, sizeof(struct client)); 107 fd_list_init(&c->chain, c); 108 c->cli_thr = pthread_self(); 109 110 /* Create the connection context */ 111 CHECK_MALLOC_DO( c->conn = fd_cnx_init(cf->sock, cf->serv->proto), goto early_error ); 112 113 /* In case we are a secure server, handshake now */ 114 if (cf->serv->secur) { 115 116 TODO("Continue"); 117 } 118 119 /* Save the client in the list */ 120 CHECK_POSIX_DO( pthread_mutex_lock( &cf->serv->clients_mtx ), goto early_error ); 121 fd_list_insert_before(&cf->serv->clients, &c->chain); 122 CHECK_POSIX_DO( pthread_mutex_unlock( &cf->serv->clients_mtx ), goto error ); 123 124 125 126 127 early_error: 128 TRACE_DEBUG(INFO, "Thread is detaching to die"); 181 129 pthread_detach(pthread_self()); 130 shutdown(cf->sock, SHUT_RDWR); 131 free(cf); 182 132 free(c); 133 error: 134 TRACE_DEBUG(INFO, "Thread is terminating"); 135 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 183 136 return NULL; 184 185 fatal_error: /* This has effect to terminate the daemon */ 186 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 187 return NULL; 188 } 189 190 /* The thread managing a server */ 137 } 138 139 /* The thread for the server */ 191 140 static void * serv_th(void * arg) 192 141 { 193 struct server *s = (struct server *)arg; 194 195 CHECK_PARAMS_DO(s, goto error); 196 fd_log_threadname ( fd_cnx_getid(s->conn) ); 197 s->status = 1; 142 struct server *sv = (struct server *)arg; 143 struct cli_fast cf; 144 145 CHECK_PARAMS_DO(sv, goto error); 146 fd_log_threadname ( sv->serv_name ); 147 sv->serv_status = 1; 148 149 memset(&cf, 0, sizeof(struct cli_fast)); 150 cf.serv = sv; 151 198 152 199 153 /* Accept incoming connections */ 200 CHECK_ FCT_DO( fd_cnx_serv_listen(s->conn), goto error );154 CHECK_SYS_DO( listen(sv->socket, 5), goto error ); 201 155 202 156 do { 203 struct client * c = NULL; 204 struct cnxctx * conn = NULL; 157 struct cli_fast * ncf; 158 pthread_t thr; 159 160 /* Re-init socket size */ 161 cf.sslen = sizeof(sSS); 205 162 206 163 /* Wait for a new client */ 207 CHECK_ MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error );164 CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error ); 208 165 209 166 TRACE_DEBUG(FULL, "New connection accepted"); 210 167 211 /* Create a client structure */ 212 CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto error ); 213 memset(c, 0, sizeof(struct client)); 214 fd_list_init(&c->chain, c); 215 c->conn = conn; 216 217 /* Save the client in the list */ 218 CHECK_POSIX_DO( pthread_mutex_lock( &s->clients_mtx ), goto error ); 219 fd_list_insert_before(&s->clients, &c->chain); 220 CHECK_POSIX_DO( pthread_mutex_unlock( &s->clients_mtx ), goto error ); 221 222 /* Start the client thread */ 223 CHECK_POSIX_DO( pthread_create( &c->thr, NULL, client_sm, c ), goto error ); 168 /* Create the copy for the client thread */ 169 CHECK_MALLOC_DO( ncf = malloc(sizeof(struct cli_fast)), goto error ); 170 memcpy(ncf, &cf, sizeof(struct cli_fast)); 171 172 /* Create the thread to handle the new incoming connection */ 173 CHECK_POSIX_DO( pthread_create( &thr /* we don't use it, but NULL is not standard */, NULL, handle_client_fast, ncf), goto error ); 224 174 225 175 } while (1); 226 176 227 177 error: 228 if (s )229 s ->status = 2;178 if (sv) 179 sv->serv_status = 2; 230 180 /* Send error signal to the daemon */ 231 181 TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); 232 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0,NULL), );182 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 233 183 234 184 return NULL; … … 237 187 238 188 /* Create a new server structure */ 239 static struct server * new_serv( int proto, int secur ) 240 { 189 static struct server * new_serv( int proto, int secur, int socket ) 190 { 191 char buf[32]; 192 char * sn = NULL; 241 193 struct server * new; 194 195 /* Create the server debug name */ 196 buf[sizeof(buf) - 1] = '\0'; 197 snprintf(buf, sizeof(buf) - 1, "Serv %d (%s%s)", socket, IPPROTO_NAME( proto ), secur ? "s" : ""); 198 CHECK_MALLOC_DO( sn = strdup(buf), return NULL ); 242 199 243 200 /* New server structure */ … … 246 203 memset(new, 0, sizeof(struct server)); 247 204 fd_list_init(&new->chain, new); 205 new->socket = socket; 248 206 new->proto = proto; 249 207 new->secur = secur; … … 251 209 fd_list_init(&new->clients, new); 252 210 211 new->serv_name = sn; 212 253 213 return new; 214 } 215 216 /* Dump all servers information */ 217 void fd_servers_dump() 218 { 219 struct fd_list * li; 220 221 fd_log_debug("Dumping servers list :\n"); 222 for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) { 223 struct server * sv = (struct server *)li; 224 fd_log_debug(" Serv '%s': %s(%d), %s, %s, %s\n", 225 sv->serv_name, 226 (sv->socket > 0) ? "Open" : "Closed", sv->socket, 227 IPPROTO_NAME( sv->proto ), 228 sv->secur ? "Secur" : "NotSecur", 229 (sv->serv_status == 0) ? "Thread not created" : 230 ((sv->serv_status == 1) ? "Thread running" : 231 ((sv->serv_status == 2) ? "Thread terminated" : 232 "Thread status unknown"))); 233 /* Dump the endpoints ? */ 234 /* Dump the client list ? */ 235 } 254 236 } 255 237 … … 257 239 int fd_servers_start() 258 240 { 259 struct server * s; 260 261 int empty_conf_ep = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints); 241 int socket; 242 struct server * sv; 262 243 263 244 /* SCTP */ … … 268 249 269 250 /* Create the server on default port */ 270 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 0) ); 271 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) ); 272 fd_list_insert_before( &FD_SERVERS, &s->chain ); 273 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 274 275 /* Retrieve the list of endpoints if it was empty */ 276 if (empty_conf_ep) { 277 (void) fd_cnx_getendpoints(s->conn, &fd_g_config->cnf_endpoints, NULL); 278 } 279 280 /* Create the server on secure port */ 281 CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) ); 282 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) ); 283 fd_list_insert_before( &FD_SERVERS, &s->chain ); 284 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 251 CHECK_FCT( fd_sctp_create_bind_server( &socket, fd_g_config->cnf_port ) ); 252 CHECK_MALLOC( sv = new_serv(IPPROTO_SCTP, 0, socket) ); 253 254 255 285 256 286 257 #endif /* DISABLE_SCTP */ … … 290 261 if (!fd_g_config->cnf_flags.no_tcp) { 291 262 292 if (empty_conf_ep) { 293 /* Bind TCP servers on [0.0.0.0] */ 294 if (!fd_g_config->cnf_flags.no_ip4) { 295 296 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); 297 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET, NULL) ); 298 fd_list_insert_before( &FD_SERVERS, &s->chain ); 299 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 300 301 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); 302 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET, NULL) ); 303 fd_list_insert_before( &FD_SERVERS, &s->chain ); 304 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 305 } 306 /* Bind TCP servers on [::] */ 307 if (!fd_g_config->cnf_flags.no_ip6) { 308 309 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); 310 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, AF_INET6, NULL) ); 311 fd_list_insert_before( &FD_SERVERS, &s->chain ); 312 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 313 314 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); 315 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, AF_INET6, NULL) ); 316 fd_list_insert_before( &FD_SERVERS, &s->chain ); 317 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 318 } 319 } else { 320 /* Create all endpoints -- check flags */ 321 struct fd_list * li; 322 for (li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) { 323 struct fd_endpoint * ep = (struct fd_endpoint *)li; 324 sSA * sa = (sSA *) &ep->ss; 325 if (! (ep->flags & EP_FL_CONF)) 326 continue; 327 if (fd_g_config->cnf_flags.no_ip4 && (sa->sa_family == AF_INET)) 328 continue; 329 if (fd_g_config->cnf_flags.no_ip6 && (sa->sa_family == AF_INET6)) 330 continue; 331 332 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 0) ); 333 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port, sa->sa_family, ep) ); 334 fd_list_insert_before( &FD_SERVERS, &s->chain ); 335 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 336 337 CHECK_MALLOC( s = new_serv(IPPROTO_TCP, 1) ); 338 CHECK_MALLOC( s->conn = fd_cnx_serv_tcp(fd_g_config->cnf_port_tls, sa->sa_family, ep) ); 339 fd_list_insert_before( &FD_SERVERS, &s->chain ); 340 CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) ); 341 } 342 } 263 343 264 } 344 265 … … 347 268 348 269 /* Terminate all the servers */ 349 int fd_servers_stop() 350 { 351 TODO("Not implemented"); 352 353 /* Loop on all servers */ 354 /* cancel thread */ 355 /* destroy server connection context */ 356 /* cancel and destroy all clients */ 357 } 270 void fd_servers_stop() 271 { 272 273 } -
freeDiameter/tests/CMakeLists.txt
r29 r10 18 18 testsess 19 19 testdisp 20 testcnx21 20 ) 22 21 -
freeDiameter/tests/tests.h
r29 r10 46 46 #include <pthread.h> 47 47 #include <errno.h> 48 #include <gcrypt.h>49 48 50 49 /* Test timeout duration, unless -n is passed on the command line */ 51 50 #ifndef TEST_TIMEOUT 52 #define TEST_TIMEOUT 30 /* inseconds */51 #define TEST_TIMEOUT 5 /* 5 seconds */ 53 52 #endif /* TEST_TIMEOUT */ 54 53 … … 79 78 struct fd_config * fd_g_config = &conf; 80 79 81 /* gcrypt functions to support posix threads */82 GCRY_THREAD_OPTION_PTHREAD_IMPL;83 84 80 /* Define the standard check routines */ 85 81 #define CHECK( _val, _assert ){ \ … … 103 99 104 100 /* Minimum inits */ 105 #define INIT_FD() { \ 106 memset(fd_g_config, 0, sizeof(struct fd_config)); \ 107 CHECK( 0, fd_lib_init() ); \ 108 fd_log_threadname(basename(__FILE__)); \ 109 (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); \ 110 (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); \ 111 CHECK( 0, gnutls_global_init()); \ 112 CHECK( 0, fd_conf_init() ); \ 113 CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) ); \ 114 parse_cmdline(argc, argv); \ 101 #define INIT_FD() { \ 102 memset(fd_g_config, 0, sizeof(struct fd_config)); \ 103 CHECK( 0, fd_lib_init() ); \ 104 fd_log_threadname(basename(__FILE__)); \ 105 CHECK( 0, fd_conf_init() ); \ 106 CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) ); \ 107 parse_cmdline(argc, argv); \ 115 108 } 116 109 -
include/freeDiameter/CMakeLists.txt
r24 r17 10 10 11 11 # Disable SCTP support completly ? 12 OPTION(DISABLE_SCTP "Disable SCTP support?" OFF) 13 IF (NOT DISABLE_SCTP) 14 OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF) 15 OPTION(SCTP_USE_MAPPED_ADDRESSES "Use v6-mapped v4 addresses in SCTP (workaround some SCTP limitations)?" OFF) 16 ENDIF (NOT DISABLE_SCTP) 12 OPTION(DISABLE_SCTP "Disable SCTP support?") 17 13 18 14 # Find TODO items in the code easily ? -
include/freeDiameter/freeDiameter-host.h.in
r24 r13 45 45 46 46 #cmakedefine DISABLE_SCTP 47 #cmakedefine DEBUG_SCTP48 #cmakedefine SCTP_USE_MAPPED_ADDRESSES49 47 #cmakedefine ERRORS_ON_TODO 50 48 #cmakedefine DEBUG -
include/freeDiameter/freeDiameter.h
r25 r20 118 118 struct fd_endpoint { 119 119 struct fd_list chain; /* link in cnf_endpoints list */ 120 121 union { 122 sSS ss; /* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */ 123 sSA4 sin; 124 sSA6 sin6; 125 sSA sa; 126 }; 127 128 #define EP_FL_CONF (1 << 0) /* This endpoint is statically configured in a configuration file */ 129 #define EP_FL_DISC (1 << 1) /* This endpoint was resolved from the Diameter Identity or other DNS query */ 130 #define EP_FL_ADV (1 << 2) /* This endpoint was advertized in Diameter CER/CEA exchange */ 131 #define EP_FL_LL (1 << 3) /* Lower layer mechanism provided this endpoint */ 132 #define EP_FL_PRIMARY (1 << 4) /* This endpoint is primary in a multihomed SCTP association */ 133 uint32_t flags; /* Additional information about the endpoint */ 134 135 /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */ 120 sSS ss; /* the socket information. List is always ordered by ss value (memcmp) */ 121 struct { 122 unsigned conf : 1; /* This endpoint is statically configured in a configuration file */ 123 unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */ 124 unsigned adv : 1; /* This endpoint was advertized in Diameter CER/CEA exchange */ 125 unsigned ll : 1; /* Lower layer mechanism provided this endpoint */ 126 127 /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */ 128 129 } meta; /* Additional information about the endpoint */ 136 130 }; 137 131 … … 152 146 struct fd_event { 153 147 int code; /* codespace depends on the queue */ 154 size_t size;155 148 void *data; 156 149 }; 157 150 158 /* Daemon's codespace: 1000->1999 */ 151 static __inline__ int fd_event_send(struct fifo *queue, int code, void * data) 152 { 153 struct fd_event * ev; 154 CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) ); 155 ev->code = code; 156 ev->data = data; 157 CHECK_FCT( fd_fifo_post(queue, &ev) ); 158 return 0; 159 } 160 static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data) 161 { 162 struct fd_event * ev; 163 CHECK_FCT( fd_fifo_get(queue, &ev) ); 164 if (code) 165 *code = ev->code; 166 if (data) 167 *data = ev->data; 168 free(ev); 169 return 0; 170 } 171 172 /* Events codespace for fd_g_config->cnf_main_ev */ 159 173 enum { 160 FDEV_TERMINATE 174 FDEV_TERMINATE = 1000 /* request to terminate */ 161 175 ,FDEV_DUMP_DICT /* Dump the content of the dictionary */ 162 176 ,FDEV_DUMP_EXT /* Dump state of extensions */ … … 166 180 ,FDEV_DUMP_PEERS /* Dump the list of peers */ 167 181 }; 168 169 static __inline__ int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data)170 {171 struct fd_event * ev;172 CHECK_MALLOC( ev = malloc(sizeof(struct fd_event)) );173 ev->code = code;174 ev->size = datasz;175 ev->data = data;176 CHECK_FCT( fd_fifo_post(queue, &ev) );177 return 0;178 }179 static __inline__ int fd_event_get(struct fifo *queue, int *code, size_t *datasz, void ** data)180 {181 struct fd_event * ev;182 CHECK_FCT( fd_fifo_get(queue, &ev) );183 if (code)184 *code = ev->code;185 if (datasz)186 *datasz = ev->size;187 if (data)188 *data = ev->data;189 free(ev);190 return 0;191 }192 static __inline__ int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int *code, size_t *datasz, void ** data)193 {194 struct fd_event * ev;195 int ret = 0;196 ret = fd_fifo_timedget(queue, &ev, timeout);197 if (ret == ETIMEDOUT) {198 if (code)199 *code = timeoutcode;200 if (datasz)201 *datasz = 0;202 if (data)203 *data = NULL;204 } else {205 CHECK_FCT( ret );206 if (code)207 *code = ev->code;208 if (datasz)209 *datasz = ev->size;210 if (data)211 *data = ev->data;212 free(ev);213 }214 return 0;215 }216 static __inline__ void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data))217 {218 struct fd_event * ev;219 /* Purge all events, and free the associated data if any */220 while (fd_fifo_tryget( *queue, &ev ) == 0) {221 (*free_cb)(ev->data);222 free(ev);223 }224 CHECK_FCT_DO( fd_fifo_del(queue), /* continue */ );225 return ;226 }227 182 const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */ 228 183 … … 301 256 /* Additional parameters */ 302 257 uint32_t pi_lft; /* lifetime of this peer when inactive (see pi_flags.exp definition) */ 258 uint16_t pi_streams; /* number of streams for SCTP. 0 = default */ 303 259 uint16_t pi_port; /* port to connect to. 0: default. */ 304 260 int pi_tctimer; /* use this value for TcTimer instead of global, if != 0 */ … … 315 271 struct fd_list pi_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ 316 272 struct { 317 char *priority; /* In case the default priority is not appropriate */318 273 /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo */ 319 274 const gnutls_datum_t *cert_list; /* The (valid) credentials that the peer has presented */ … … 505 460 506 461 507 /***************************************/508 /* Endpoints lists helpers */509 /***************************************/510 511 int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );512 int fd_ep_filter( struct fd_list * list, uint32_t flags );513 int fd_ep_clearflags( struct fd_list * list, uint32_t flags );514 515 516 517 462 #endif /* _FREEDIAMETER_H */ -
include/freeDiameter/libfreeDiameter.h
r29 r20 120 120 * 121 121 * PARAMETERS: 122 * ts : The timestamp to log, or NULL for "now"123 122 * buf : An array where the time must be stored 124 123 * len : size of the buffer 125 124 * 126 125 * DESCRIPTION: 127 * Writes the timestamp (in human readable format) in a buffer.126 * Writes the current timestamp (in human readable format) in a buffer. 128 127 * 129 128 * RETURN VALUE: 130 129 * pointer to buf. 131 130 */ 132 char * fd_log_time ( struct timespec * ts,char * buf, size_t len );131 char * fd_log_time ( char * buf, size_t len ); 133 132 134 133 … … 174 173 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ 175 174 "\t%s|%*s" format "\n", \ 176 __thn, fd_log_time( NULL,__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \175 __thn, fd_log_time(__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \ 177 176 (level < FULL)?"@":" ",level, "", ## args); \ 178 177 } \ … … 181 180 /* Helper for function entry -- for very detailed trace of the execution */ 182 181 #define TRACE_ENTRY(_format,_args... ) \ 183 TRACE_DEBUG(FCTS, " [enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );182 TRACE_DEBUG(FCTS, "->%s (" #_args ") = (" _format ") >", __PRETTY_FUNCTION__, ##_args ); 184 183 185 184 /* Helper for debugging by adding traces -- for debuging a specific location of the code */ … … 329 328 flag); \ 330 329 if (__rc) \ 331 fd_log_debug( "%s",(char *)gai_strerror(__rc)); \330 fd_log_debug((char *)gai_strerror(__rc)); \ 332 331 else \ 333 fd_log_debug( "%s", &__addrbuf[0]);\332 fd_log_debug(&__addrbuf[0]); \ 334 333 } else { \ 335 334 fd_log_debug("(NULL / ANY)"); \ 336 335 } \ 337 336 } 338 /* Same but with the port (service) also */ 339 #define sSA_DUMP_NODE_SERV( sa, flag ) { \ 340 sSA * __sa = (sSA *)(sa); \ 341 char __addrbuf[INET6_ADDRSTRLEN]; \ 342 char __servbuf[32]; \ 343 if (__sa) { \ 344 int __rc = getnameinfo(__sa, \ 345 sizeof(sSS), \ 346 __addrbuf, \ 347 sizeof(__addrbuf), \ 348 __servbuf, \ 349 sizeof(__servbuf), \ 350 flag); \ 351 if (__rc) \ 352 fd_log_debug("%s", (char *)gai_strerror(__rc)); \ 353 else \ 354 fd_log_debug("[%s]:%s", &__addrbuf[0],&__servbuf[0]); \ 355 } else { \ 356 fd_log_debug("(NULL / ANY)"); \ 357 } \ 358 } 359 /* Inside a debug trace */ 360 #define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) { \ 361 if ( TRACE_BOOL(level) ) { \ 362 char __buf[25]; \ 363 char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \ 364 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ 365 "\t%s|%*s" prefix , \ 366 __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\ 367 (level < FULL)?"@":" ",level, ""); \ 368 sSA_DUMP_NODE_SERV( sa, flags ); \ 369 fd_log_debug(suffix "\n"); \ 370 } \ 371 } 372 337 /* if needed, add sSA_DUMP_SERVICE */ 373 338 374 339 /* A l4 protocol name (TCP / SCTP) */ … … 425 390 ( ((ts1)->tv_sec < (ts2)->tv_sec ) \ 426 391 || (((ts1)->tv_sec == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) )) 427 428 429 /* Trace a binary buffer content */430 #define TRACE_DEBUG_BUFFER(level, prefix, buf, bufsz, suffix ) { \431 if ( TRACE_BOOL(level) ) { \432 int __i; \433 size_t __sz = (size_t)(bufsz); \434 uint8_t * __buf = (uint8_t *)(buf); \435 char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \436 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \437 "\t%s|%*s" prefix , \438 __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\439 (level < FULL)?"@":" ",level, ""); \440 for (__i = 0; __i < __sz; __i++) { \441 fd_log_debug("%02.2hhx", __buf[__i]); \442 } \443 fd_log_debug(suffix "\n"); \444 } \445 }446 447 392 448 393 … … 470 415 471 416 if (th_ret != NULL) { 472 TRACE_DEBUG( ANNOYING, "The thread returned the following value: %p (ignored)", th_ret);417 TRACE_DEBUG(FULL, "The thread returned the following value: %p (ignored)", th_ret); 473 418 } 474 419 … … 494 439 free(buffer); 495 440 } 496 static __inline__ void fd_cleanup_socket(void * sockptr)497 {498 if (sockptr) {499 shutdown(*(int *)sockptr, SHUT_RDWR);500 *(int *)sockptr = 0;501 }502 }503 504 441 505 442 /*============================================================*/ … … 528 465 void fd_list_insert_after ( struct fd_list * ref, struct fd_list * item ); 529 466 void fd_list_insert_before ( struct fd_list * ref, struct fd_list * item ); 530 531 /* Move a list at the end of another */532 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti);533 467 534 468 /* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */ … … 2408 2342 2409 2343 /* 2410 * FUNCTION: fd_fifo_move2411 *2412 * PARAMETERS:2413 * old : Location of a FIFO that is to be emptied and deleted.2414 * new : A FIFO that will receive the old data.2415 * loc_update : if non NULL, a place to store the pointer to new FIFO atomically with the move.2416 *2417 * DESCRIPTION:2418 * Delete a queue and move its content to another one atomically.2419 *2420 * RETURN VALUE:2421 * 0 : The queue has been destroyed successfully.2422 * EINVAL : A parameter is invalid.2423 */2424 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update );2425 2426 /*2427 2344 * FUNCTION: fd_fifo_length 2428 2345 * -
libfreeDiameter/fifo.c
r25 r14 136 136 } 137 137 138 /* Delete a queue. It must be empty. */138 /* Delete a queue. It must be unused. */ 139 139 int fd_fifo_del ( struct fifo ** queue ) 140 140 { 141 141 struct fifo * q; 142 int loops = 0;143 142 144 143 TRACE_ENTRY( "%p", queue ); … … 150 149 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); 151 150 152 if ((q->count != 0) || (q-> data != NULL)) {153 TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, % p)", q->count, q->data);151 if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) { 152 TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data); 154 153 CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); 155 154 return EINVAL; 156 155 } 157 156 157 /* sanity check */ 158 ASSERT(FD_IS_LIST_EMPTY(&q->list)); 159 158 160 /* Ok, now invalidate the queue */ 159 161 q->eyec = 0xdead; 160 162 161 while (q->thrs) {162 CHECK_POSIX( pthread_cond_signal(&q->cond) );163 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ));164 pthread_yield();165 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) );166 ASSERT( ++loops < 10 ); /* detect infinite loops */167 }168 169 /* sanity check */170 ASSERT(FD_IS_LIST_EMPTY(&q->list));171 172 163 /* And destroy it */ 173 164 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); … … 179 170 free(q); 180 171 *queue = NULL; 181 182 return 0;183 }184 185 /* Move the content of old into new, and update loc_update atomically */186 int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update )187 {188 struct fifo * q;189 int loops = 0;190 191 TRACE_ENTRY("%p %p %p", old, new, loc_update);192 CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new ));193 194 q = *old;195 CHECK_PARAMS( ! q->data );196 if (new->high) {197 TODO("Implement support for thresholds in fd_fifo_move...");198 }199 200 /* Update loc_update */201 *old = NULL;202 if (loc_update)203 *loc_update = new;204 205 /* Lock the queues */206 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) );207 CHECK_POSIX( pthread_mutex_lock( &new->mtx ) );208 209 /* Any waiting thread on the old queue returns an error */210 q->eyec = 0xdead;211 while (q->thrs) {212 CHECK_POSIX( pthread_cond_signal(&q->cond) );213 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ));214 pthread_yield();215 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) );216 ASSERT( ++loops < 10 ); /* detect infinite loops */217 }218 219 /* Move all data from old to new */220 fd_list_move_end( &new->list, &q->list );221 if (q->count && (!new->count)) {222 CHECK_POSIX( pthread_cond_signal(&new->cond) );223 }224 new->count += q->count;225 226 /* Destroy old */227 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) );228 CHECK_POSIX( pthread_cond_destroy( &q->cond ) );229 CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) );230 free(q);231 232 /* Unlock new, we're done */233 CHECK_POSIX( pthread_mutex_unlock( &new->mtx ) );234 172 235 173 return 0; … … 441 379 awaken: 442 380 /* Check queue status */ 443 if (!CHECK_FIFO( queue )) {444 /* The queue is being destroyed */445 CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) );446 TRACE_DEBUG(FULL, "The queue is being destroyed -> EPIPE");447 return EPIPE;448 }449 450 381 if (queue->count > 0) { 451 382 /* There are items in the queue, so pick the first one */ -
libfreeDiameter/lists.c
r25 r14 70 70 ASSERT(ref->head != item); 71 71 list_insert_after(ref, item); 72 }73 74 /* Move all elements of list senti at the end of list ref */75 void fd_list_move_end(struct fd_list * ref, struct fd_list * senti)76 {77 ASSERT(ref->head == ref);78 ASSERT(senti->head == senti);79 80 if (senti->next == senti)81 return;82 83 senti->next->prev = ref->prev;84 ref->prev->next = senti->next;85 senti->prev->next = ref;86 ref->prev = senti->prev;87 senti->prev = senti;88 senti->next = senti;89 90 72 } 91 73 -
libfreeDiameter/log.c
r22 r2 87 87 } 88 88 89 /* Write time into a buffer */90 char * fd_log_time ( struct timespec * ts,char * buf, size_t len )89 /* Write current time into a buffer */ 90 char * fd_log_time ( char * buf, size_t len ) 91 91 { 92 92 int ret; … … 96 96 97 97 /* Get current time */ 98 if (!ts) { 99 ret = clock_gettime(CLOCK_REALTIME, &tp); 100 if (ret != 0) { 101 snprintf(buf, len, "%s", strerror(ret)); 102 return buf; 103 } 104 ts = &tp; 98 ret = clock_gettime(CLOCK_REALTIME, &tp); 99 if (ret != 0) { 100 snprintf(buf, len, "%s", strerror(ret)); 101 return buf; 105 102 } 106 103 107 offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &t s->tv_sec , &tm ));108 offset += snprintf(buf + offset, len - offset, ".%6.6ld", t s->tv_nsec / 1000);104 offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &tp.tv_sec , &tm )); 105 offset += snprintf(buf + offset, len - offset, ".%6.6ld", tp.tv_nsec / 1000); 109 106 110 107 return buf;
Note: See TracChangeset
for help on using the changeset viewer.