Changes in / [20:277ec00d793e:30:bca243c65b56] in freeDiameter
- Files:
-
- 5 added
- 23 edited
Legend:
- Unmodified
- Added
- Removed
-
contrib/ca_script/Makefile
r19 r29 32 32 O = WIDE 33 33 OU = "AAA WG" 34 35 #Default lifetime 36 DAYS = 365 34 37 35 38 #Values for the CA … … 130 133 @openssl ca $(CONFIG) -in $(DIR)/clients/csr/$(name).csr \ 131 134 -out $(DIR)/clients/certs/$(name).cert \ 135 -days $(DAYS) \ 132 136 -batch 133 137 @ln -s $(DIR)/clients/certs/$(name).cert $(DIR)/certs/`openssl x509 -noout -hash < $(DIR)/clients/certs/$(name).cert`.0 -
doc/freediameter.conf.sample
r20 r24 68 68 #ListenOn = "202.249.37.5"; 69 69 #ListenOn = "2001:200:903:2::202:1"; 70 #ListenOn = "fe80::21c:5ff:fe98:7d62%eth0"; 70 71 71 72 ############################################################## … … 184 185 # No_TLS; # assume transparent security instead of TLS 185 186 # 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"; 191 192 # Examples: 192 193 #ConnectPeer = "aaa.wide.ad.jp"; … … 201 202 SecPort = 3867; 202 203 TLS_old_method; 203 No_IP;204 Prefer_TCP;205 204 SCTP_streams = 50; 206 ListenOn = "202.249.37.5";207 ListenOn = "2001:200:903:2::202:1";208 205 TcTimer = 60; 209 206 TwTimer = 6; 207 #ListenOn = "133.243.146.201"; 208 #ListenOn = "fe80::21d:9ff:fe89:7d68%eth0"; 210 209 NoRelay; 211 210 LoadExtension = "extensions/dbg_monitor.fdx"; … … 213 212 LoadExtension = "extensions/dict_eap.fdx"; 214 213 ConnectPeer = "jules.nautilus6.org" ; 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";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"; 217 216 TLS_CA = "/etc/openssl-ca/public-www/cacert.pem"; 218 217 # TLS_CRL = "/etc/openssl-ca/public-www/crl.pem"; -
extensions/dbg_monitor/monitor.c
r11 r25 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, 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 */);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 */); 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, NULL), /* continue */); 80 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */); 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 */); 81 82 pthread_testcancel(); 82 83 } -
freeDiameter/CMakeLists.txt
r20 r25 10 10 SET(FD_COMMON_SRC 11 11 fD.h 12 cnxctx.h 12 13 config.c 13 14 cnxctx.c 14 15 dispatch.c 16 endpoints.c 15 17 extensions.c 16 18 dict_base_proto.c … … 21 23 p_psm.c 22 24 server.c 25 tcp.c 23 26 ) 24 27 25 28 IF(NOT DISABLE_SCTP) 26 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c )29 SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c sctps.c) 27 30 ENDIF(NOT DISABLE_SCTP) 28 31 -
freeDiameter/cnxctx.c
r20 r30 35 35 36 36 #include "fD.h" 37 38 /* Initialize a connection context */ 39 struct cnxctx * fd_cnx_init(int sock, int proto) 37 #include "cnxctx.h" 38 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) 40 83 { 41 84 struct cnxctx * conn = NULL; 42 43 TRACE_ENTRY("%d %d", sock, proto); 44 CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL); 45 85 86 TRACE_ENTRY("%d", full); 87 46 88 CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL ); 47 89 memset(conn, 0, sizeof(struct cnxctx)); 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) { 90 91 if (full) { 92 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL ); 93 } 94 95 return conn; 96 } 97 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 56 195 #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; 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); 60 334 #else /* DISABLE_SCTP */ 61 ASSERT(0); 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; 62 389 #endif /* DISABLE_SCTP */ 63 } 64 65 return conn; 66 } 67 68 /* TLS handshake the connection */ 69 int fd_cnx_handshake(struct cnxctx * conn, int mode) 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) 70 773 { 71 774 TRACE_ENTRY( "%p %d", conn, mode); 72 CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER)) );73 775 CHECK_PARAMS( conn && (!conn->cc_tls) && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) && (!conn->cc_loop) ); 776 74 777 /* Save the mode */ 75 778 conn->cc_tls_para.mode = mode; 76 779 77 /* Create the master session context */ 78 CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); 79 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 ); 82 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); 780 /* Cancel 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 */); 782 783 /* Once TLS handshake is done, we don't stop after the first message */ 784 conn->cc_loop = 1; 785 786 /* Prepare the master session credentials and priority */ 787 CHECK_FCT( fd_tls_prepare(&conn->cc_tls_para.session, mode, priority, alt_creds) ); 93 788 94 789 /* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */ 95 if ( (conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {96 #if ndef DISABLE_SCTP97 TODO("Initialize the SCTP TLS wrapper");98 TODO("Set the lowat, push and pull functions");790 if (conn->cc_sctp_para.pairs > 1) { 791 #ifdef DISABLE_SCTP 792 ASSERT(0); 793 CHECK_FCT( ENOTSUP ); 99 794 #else /* DISABLE_SCTP */ 100 ASSERT(0); 795 /* Initialize the wrapper, start the demux thread */ 796 CHECK_FCT( fd_sctps_init(conn) ); 101 797 #endif /* DISABLE_SCTP */ 102 } 103 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 } 802 104 803 /* Handshake master session */ 105 804 { … … 108 807 { 109 808 if (TRACE_BOOL(INFO)) { 110 fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));809 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 111 810 } 112 811 return EINVAL; 113 812 } ); 114 813 115 814 /* Now verify the remote credentials are valid -- only simple test here */ 116 815 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL ); 117 816 if (ret) { 118 817 if (TRACE_BOOL(INFO)) { 119 fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);818 fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id); 120 819 if (ret & GNUTLS_CERT_INVALID) 121 820 fd_log_debug(" - The certificate is not trusted (unknown CA?)\n"); … … 132 831 } 133 832 } 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)) {833 834 /* Multi-stream TLS: handshake other streams as well */ 835 if (conn->cc_sctp_para.pairs > 1) { 137 836 #ifndef DISABLE_SCTP 138 TODO("Init and resume all additional sessions from the master one."); 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)); 139 845 #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 ) ); 140 852 } 141 853 142 854 return 0; 143 855 } 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_SCTP 996 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_SCTP 1049 /* 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_SCTP 1064 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
r20 r24 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 s, NI_NUMERICHOST );102 sSA_DUMP_NODE( &ep->sa, 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 231 250 /* Configure TLS default parameters */ 232 251 if (! fd_g_config->cnf_sec_data.prio_string) { … … 239 258 } 240 259 if (! fd_g_config->cnf_sec_data.dh_bits) { 241 TRACE_DEBUG(FULL, "Generating DH parameters..."); 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 } 242 263 CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 243 264 fd_g_config->cnf_sec_data.dh_cache, 244 265 GNUTLS_DEFAULT_DHBITS), 245 266 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } ); 246 TRACE_DEBUG(FULL, "DH parameters generated."); 247 } 248 267 if (TRACE_BOOL(INFO)) { 268 fd_log_debug("Done!\n"); 269 } 270 } 249 271 250 272 return 0; -
freeDiameter/fD.h
r20 r29 152 152 enum { 153 153 /* Dump all info about this peer in the debug log */ 154 FDEVP_DUMP_ALL = 2000154 FDEVP_DUMP_ALL = 1500 155 155 156 156 /* request to terminate this peer : disconnect, requeue all messages */ 157 157 ,FDEVP_TERMINATE 158 158 159 /* A message was received in the peer */ 160 ,FDEVP_MSG_INCOMING 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 161 170 162 171 /* The PSM state is expired */ 163 172 ,FDEVP_PSM_TIMEOUT 173 164 174 }; 165 175 const char * fd_pev_str(int event); 166 176 #define CHECK_EVENT( _e ) \ 167 177 (((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 }; 168 185 169 186 /* Structure to store a sent request */ … … 173 190 }; 174 191 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 };208 192 209 193 /* Functions */ 210 int fd_peer_fini();194 int fd_peer_fini(); 211 195 void fd_peer_dump_list(int details); 212 196 void fd_peer_dump(struct fd_peer * peer, int details); 213 int fd_peer_alloc(struct fd_peer ** ptr); 214 int fd_peer_free(struct fd_peer ** ptr); 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 ); 215 200 /* fd_peer_add declared in freeDiameter.h */ 201 int fd_peer_validate( struct fd_peer * peer ); 216 202 217 203 /* Peer expiry */ … … 221 207 222 208 /* Peer state machine */ 223 int fd_psm_start();224 int fd_psm_begin(struct fd_peer * peer );225 int fd_psm_terminate(struct fd_peer * peer );209 int fd_psm_start(); 210 int fd_psm_begin(struct fd_peer * peer ); 211 int fd_psm_terminate(struct fd_peer * peer ); 226 212 void fd_psm_abord(struct fd_peer * peer ); 227 213 228 214 /* Server sockets */ 229 215 void fd_servers_dump(); 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 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); 244 238 245 239 -
freeDiameter/fdd.y
r20 r24 212 212 listenon: LISTENON '=' QSTRING ';' 213 213 { 214 struct fd_endpoint * ep;215 214 struct addrinfo hints, *ai; 216 215 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;223 216 224 217 memset(&hints, 0, sizeof(hints)); 225 218 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; 226 219 ret = getaddrinfo($3, NULL, &hints, &ai); 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);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 ); 222 freeaddrinfo(ai); 230 223 free($3); 231 freeaddrinfo(ai);232 fd_list_insert_before(&conf->cnf_endpoints, &ep->chain);233 224 } 234 225 ; … … 336 327 /* Now destroy any content in the structure */ 337 328 free(fddpi.pi_diamid); 329 free(fddpi.pi_sec_data.priority); 338 330 while (!FD_IS_LIST_EMPTY(&fddpi.pi_endpoints)) { 339 331 struct fd_list * li = fddpi.pi_endpoints.next; … … 415 407 fddpi.pi_port = (uint16_t)$4; 416 408 } 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 }423 409 | peerparams TCTIMER '=' INTEGER ';' 424 410 { 425 411 fddpi.pi_tctimer = $4; 426 412 } 413 | peerparams TLS_PRIO '=' QSTRING ';' 414 { 415 fddpi.pi_sec_data.priority = $4; 416 } 427 417 | peerparams TWTIMER '=' INTEGER ';' 428 418 { … … 431 421 | peerparams CONNTO '=' QSTRING ';' 432 422 { 433 struct fd_endpoint * ep;434 423 struct addrinfo hints, *ai; 435 424 int ret; 425 int disc = 0; 436 426 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;442 427 memset(&hints, 0, sizeof(hints)); 443 428 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST; … … 445 430 if (ret == EAI_NONAME) { 446 431 /* The name was maybe not numeric, try again */ 447 ep->meta.disc = 1;432 disc = EP_FL_DISC; 448 433 hints.ai_flags &= ~ AI_NUMERICHOST; 449 434 ret = getaddrinfo($4, NULL, &hints, &ai); 450 435 } 451 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep);YYERROR; }436 if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; } 452 437 453 memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);438 CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR ); 454 439 free($4); 455 440 freeaddrinfo(ai); 456 fd_list_insert_before(&fddpi.pi_endpoints, &ep->chain);457 441 } 458 442 ; -
freeDiameter/main.c
r20 r25 51 51 struct fd_config * fd_g_config = &conf; 52 52 53 /* gcrypt functions to support posix threads */ 53 54 GCRY_THREAD_OPTION_PTHREAD_IMPL; 54 55 … … 105 106 CHECK_FCT( fd_ext_load() ); 106 107 108 fd_conf_dump(); 109 110 /* Start the servers */ 111 CHECK_FCT( fd_servers_start() ); 112 107 113 /* Start the peer state machines */ 108 114 CHECK_FCT( fd_psm_start() ); … … 110 116 /* Now, just wait for events */ 111 117 TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); 112 fd_conf_dump();113 118 while (1) { 114 int code; 115 CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break );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 ); 116 121 switch (code) { 117 122 case FDEV_DUMP_DICT: … … 154 159 155 160 /* cleanups */ 161 CHECK_FCT_DO( fd_servers_stop(), /* Stop accepting new connections */ ); 156 162 TODO("Stop dispatch thread(s) properly (no cancel yet)"); 157 163 CHECK_FCT_DO( fd_peer_fini(), /* Stop all connections */ ); … … 333 339 334 340 TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); 335 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) );341 CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) ); 336 342 return NULL; 337 343 } -
freeDiameter/p_expiry.c
r16 r25 47 47 static void * gc_th_fct(void * arg) 48 48 { 49 fd_log_threadname ( "Peers/garb age" );50 TRACE_ENTRY( " ");49 fd_log_threadname ( "Peers/garb. col." ); 50 TRACE_ENTRY( "%p", arg ); 51 51 52 52 do { 53 53 struct fd_list * li, purge = FD_LIST_INITIALIZER(purge); 54 54 55 pthread_testcancel(); 56 sleep(GC_TIME); 55 sleep(GC_TIME); /* sleep is a cancellation point */ 57 56 58 57 /* Now check in the peers list if any peer can be deleted */ … … 88 87 TRACE_DEBUG(INFO, "An error occurred in peers module! GC thread is terminating..."); 89 88 ASSERT(0); 90 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );89 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 91 90 return NULL; 92 91 } … … 96 95 { 97 96 fd_log_threadname ( "Peers/expire" ); 98 TRACE_ENTRY( " ");97 TRACE_ENTRY( "%p", arg ); 99 98 100 99 CHECK_POSIX_DO( pthread_mutex_lock(&exp_mtx), goto error ); … … 124 123 125 124 CHECK_POSIX_DO2( pthread_cond_timedwait( &exp_cnd, &exp_mtx, &first->p_exp_timer ), 126 ETIMEDOUT, /* ETIMEDOUT is a normal error, continue */,125 ETIMEDOUT, /* ETIMEDOUT is a normal return value, continue */, 127 126 /* on other error, */ goto error ); 128 127 … … 133 132 /* Now, the first peer in the list is expired; signal it */ 134 133 fd_list_unlink( &first->p_expiry ); 135 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, NULL), goto error );134 CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error ); 136 135 137 136 } while (1); … … 141 140 TRACE_DEBUG(INFO, "An error occurred in peers module! Expiry thread is terminating..."); 142 141 ASSERT(0); 143 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );142 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 144 143 return NULL; 145 144 } -
freeDiameter/p_psm.c
r20 r29 55 55 #define case_str( _val )\ 56 56 case _val : return #_val 57 case_str(FDEVP_DUMP_ALL); 57 58 case_str(FDEVP_TERMINATE); 58 case_str(FDEVP_DUMP_ALL); 59 case_str(FDEVP_MSG_INCOMING); 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); 60 63 case_str(FDEVP_PSM_TIMEOUT); 61 64 … … 125 128 } 126 129 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 149 130 /* The state machine thread (controler) */ 150 131 static void * p_psm_th( void * arg ) … … 153 134 int created_started = started; 154 135 int event; 136 size_t ev_sz; 155 137 void * ev_data; 156 138 … … 181 163 psm_loop: 182 164 /* Get next event */ 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'",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'", 185 167 STATE_STR(peer->p_hdr.info.pi_state), 186 fd_pev_str(event), ev_data, 168 fd_pev_str(event), ev_data, ev_sz, 187 169 peer->p_hdr.info.pi_diamid); 188 170 … … 227 209 } 228 210 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 229 237 /* MSG_RECEIVED: fd_p_expi_update(struct fd_peer * peer ) */ 230 238 /* If timeout or OPEN : call cb if defined */ … … 241 249 psm_end: 242 250 pthread_cleanup_pop(1); /* set STATE_ZOMBIE */ 251 peer->p_psm = (pthread_t)NULL; 252 pthread_detach(pthread_self()); 243 253 return NULL; 244 254 } 245 246 247 248 255 249 256 /* Create the PSM thread of one peer structure */ … … 267 274 TRACE_ENTRY("%p", peer); 268 275 CHECK_PARAMS( CHECK_PEER(peer) ); 276 269 277 if (peer->p_hdr.info.pi_state != STATE_ZOMBIE) { 270 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, NULL) );278 CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); 271 279 } else { 272 280 TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); -
freeDiameter/peers.c
r20 r29 101 101 102 102 p->p_hdr.info.pi_lft = info->pi_lft; 103 p->p_hdr.info.pi_streams = info->pi_streams;104 103 p->p_hdr.info.pi_port = info->pi_port; 105 104 p->p_hdr.info.pi_tctimer = info->pi_tctimer; 106 105 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 } 107 110 108 111 /* Move the items from one list to the other */ … … 114 117 } 115 118 119 116 120 /* The internal data */ 117 121 if (orig_dbg) { … … 127 131 128 132 for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { 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)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) 132 136 continue; 133 137 if (cmp == 0) … … 229 233 230 234 if (p->p_cnxctx) { 231 TODO("destroy p->p_cnxctx");235 fd_cnx_destroy(p->p_cnxctx); 232 236 } 233 237 … … 293 297 list_empty = FD_IS_LIST_EMPTY(&fd_g_peers); 294 298 CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ ); 299 CHECK_SYS( clock_gettime(CLOCK_REALTIME, &now) ); 295 300 } 296 301 … … 370 375 } 371 376 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
r20 r29 35 35 36 36 #include "fD.h" 37 38 int fd_sctp_create_bind_server( int * socket, uint16_t port ) 37 #include "cnxctx.h" 38 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) 39 56 { 40 TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str"); 41 42 return ENOTSUP; 57 socklen_t sz; 58 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; 43 436 } 44 437 45 int fd_sctp_get_str_info( int socket, int *in, int *out ) 438 439 /* Post-binding socket options */ 440 static int fd_setsockopt_postbind(int sk, int bound_to_default) 46 441 { 47 TODO("Retrieve streams info from the socket"); 48 49 return ENOTSUP; 442 TRACE_ENTRY( "%d %d", sk, bound_to_default); 443 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; 50 482 } 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 else 524 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_ADDRESSES 559 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 else 565 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_ADDRESSES 690 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 else 696 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
r20 r29 36 36 #include "fD.h" 37 37 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 */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 daemon thread. */ 42 43 /* Servers information */ 44 44 struct server { 45 45 struct fd_list chain; /* link in the FD_SERVERS list */ 46 46 47 int socket; /* server socket, or <= 0 */ 48 47 struct cnxctx * conn; /* server connection context (listening socket) */ 49 48 int proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 50 49 int secur; /* TLS is started immediatly after connection ? */ 51 50 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 */ 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 */ 59 56 }; 60 57 61 /* Client (connected remote endpoint, not received CER yet) information*/58 /* Client information (connecting peer for which we don't have the CER yet) */ 62 59 struct client { 63 60 struct fd_list chain; /* link in the server's list of clients */ 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) */ 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 */ 71 64 }; 72 65 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; 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))); 91 } 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; 87 112 88 113 /* 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 r c = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0);94 if (r c)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);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; 99 124 } 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"); 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 */ 129 181 pthread_detach(pthread_self()); 130 shutdown(cf->sock, SHUT_RDWR);131 free(cf);132 182 free(c); 183 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 */ 191 static void * serv_th(void * arg) 192 { 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; 198 199 /* Accept incoming connections */ 200 CHECK_FCT_DO( fd_cnx_serv_listen(s->conn), goto error ); 201 202 do { 203 struct client * c = NULL; 204 struct cnxctx * conn = NULL; 205 206 /* Wait for a new client */ 207 CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error ); 208 209 TRACE_DEBUG(FULL, "New connection accepted"); 210 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 ); 224 225 } while (1); 226 133 227 error: 134 TRACE_DEBUG(INFO, "Thread is terminating"); 135 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), ); 136 return NULL; 137 } 138 139 /* The thread for the server */ 140 static void * serv_th(void * arg) 141 { 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 152 153 /* Accept incoming connections */ 154 CHECK_SYS_DO( listen(sv->socket, 5), goto error ); 155 156 do { 157 struct cli_fast * ncf; 158 pthread_t thr; 159 160 /* Re-init socket size */ 161 cf.sslen = sizeof(sSS); 162 163 /* Wait for a new client */ 164 CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error ); 165 166 TRACE_DEBUG(FULL, "New connection accepted"); 167 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 ); 174 175 } while (1); 176 177 error: 178 if (sv) 179 sv->serv_status = 2; 228 if (s) 229 s->status = 2; 180 230 /* Send error signal to the daemon */ 181 231 TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating..."); 182 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );232 CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), ); 183 233 184 234 return NULL; … … 187 237 188 238 /* Create a new server structure */ 189 static struct server * new_serv( int proto, int secur, int socket ) 190 { 191 char buf[32]; 192 char * sn = NULL; 239 static struct server * new_serv( int proto, int secur ) 240 { 193 241 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 );199 242 200 243 /* New server structure */ … … 203 246 memset(new, 0, sizeof(struct server)); 204 247 fd_list_init(&new->chain, new); 205 new->socket = socket;206 248 new->proto = proto; 207 249 new->secur = secur; … … 209 251 fd_list_init(&new->clients, new); 210 252 211 new->serv_name = sn;212 213 253 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 }236 254 } 237 255 … … 239 257 int fd_servers_start() 240 258 { 241 int socket; 242 struct server * sv; 259 struct server * s; 260 261 int empty_conf_ep = FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints); 243 262 244 263 /* SCTP */ … … 249 268 250 269 /* Create the server on default port */ 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 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 ) ); 256 285 257 286 #endif /* DISABLE_SCTP */ … … 261 290 if (!fd_g_config->cnf_flags.no_tcp) { 262 291 263 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 } 264 343 } 265 344 … … 268 347 269 348 /* Terminate all the servers */ 270 void fd_servers_stop() 271 { 272 273 } 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 } -
freeDiameter/tests/CMakeLists.txt
r10 r29 18 18 testsess 19 19 testdisp 20 testcnx 20 21 ) 21 22 -
freeDiameter/tests/tests.h
r10 r29 46 46 #include <pthread.h> 47 47 #include <errno.h> 48 #include <gcrypt.h> 48 49 49 50 /* Test timeout duration, unless -n is passed on the command line */ 50 51 #ifndef TEST_TIMEOUT 51 #define TEST_TIMEOUT 5 /* 5seconds */52 #define TEST_TIMEOUT 30 /* in seconds */ 52 53 #endif /* TEST_TIMEOUT */ 53 54 … … 78 79 struct fd_config * fd_g_config = &conf; 79 80 81 /* gcrypt functions to support posix threads */ 82 GCRY_THREAD_OPTION_PTHREAD_IMPL; 83 80 84 /* Define the standard check routines */ 81 85 #define CHECK( _val, _assert ){ \ … … 99 103 100 104 /* Minimum inits */ 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); \ 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); \ 108 115 } 109 116 -
include/freeDiameter/CMakeLists.txt
r17 r24 10 10 11 11 # Disable SCTP support completly ? 12 OPTION(DISABLE_SCTP "Disable SCTP support?") 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) 13 17 14 18 # Find TODO items in the code easily ? -
include/freeDiameter/freeDiameter-host.h.in
r13 r24 45 45 46 46 #cmakedefine DISABLE_SCTP 47 #cmakedefine DEBUG_SCTP 48 #cmakedefine SCTP_USE_MAPPED_ADDRESSES 47 49 #cmakedefine ERRORS_ON_TODO 48 50 #cmakedefine DEBUG -
include/freeDiameter/freeDiameter.h
r20 r25 118 118 struct fd_endpoint { 119 119 struct fd_list chain; /* link in cnf_endpoints list */ 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 */ 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 ? */ 130 136 }; 131 137 … … 146 152 struct fd_event { 147 153 int code; /* codespace depends on the queue */ 154 size_t size; 148 155 void *data; 149 156 }; 150 157 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 */ 158 /* Daemon's codespace: 1000->1999 */ 173 159 enum { 174 FDEV_TERMINATE 160 FDEV_TERMINATE = 1000 /* request to terminate */ 175 161 ,FDEV_DUMP_DICT /* Dump the content of the dictionary */ 176 162 ,FDEV_DUMP_EXT /* Dump state of extensions */ … … 180 166 ,FDEV_DUMP_PEERS /* Dump the list of peers */ 181 167 }; 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 } 182 227 const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */ 183 228 … … 256 301 /* Additional parameters */ 257 302 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 */259 303 uint16_t pi_port; /* port to connect to. 0: default. */ 260 304 int pi_tctimer; /* use this value for TcTimer instead of global, if != 0 */ … … 271 315 struct fd_list pi_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ 272 316 struct { 317 char *priority; /* In case the default priority is not appropriate */ 273 318 /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo */ 274 319 const gnutls_datum_t *cert_list; /* The (valid) credentials that the peer has presented */ … … 460 505 461 506 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 462 517 #endif /* _FREEDIAMETER_H */ -
include/freeDiameter/libfreeDiameter.h
r20 r29 120 120 * 121 121 * PARAMETERS: 122 * ts : The timestamp to log, or NULL for "now" 122 123 * buf : An array where the time must be stored 123 124 * len : size of the buffer 124 125 * 125 126 * DESCRIPTION: 126 * Writes the currenttimestamp (in human readable format) in a buffer.127 * Writes the timestamp (in human readable format) in a buffer. 127 128 * 128 129 * RETURN VALUE: 129 130 * pointer to buf. 130 131 */ 131 char * fd_log_time ( char * buf, size_t len );132 char * fd_log_time ( struct timespec * ts, char * buf, size_t len ); 132 133 133 134 … … 173 174 fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ 174 175 "\t%s|%*s" format "\n", \ 175 __thn, fd_log_time( __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \176 __thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \ 176 177 (level < FULL)?"@":" ",level, "", ## args); \ 177 178 } \ … … 180 181 /* Helper for function entry -- for very detailed trace of the execution */ 181 182 #define TRACE_ENTRY(_format,_args... ) \ 182 TRACE_DEBUG(FCTS, " ->%s (" #_args ") = (" _format ") >", __PRETTY_FUNCTION__, ##_args );183 TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args ); 183 184 184 185 /* Helper for debugging by adding traces -- for debuging a specific location of the code */ … … 328 329 flag); \ 329 330 if (__rc) \ 330 fd_log_debug( (char *)gai_strerror(__rc)); \331 fd_log_debug("%s", (char *)gai_strerror(__rc)); \ 331 332 else \ 332 fd_log_debug( &__addrbuf[0]);\333 fd_log_debug("%s", &__addrbuf[0]); \ 333 334 } else { \ 334 335 fd_log_debug("(NULL / ANY)"); \ 335 336 } \ 336 337 } 337 /* if needed, add sSA_DUMP_SERVICE */ 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 338 373 339 374 /* A l4 protocol name (TCP / SCTP) */ … … 390 425 ( ((ts1)->tv_sec < (ts2)->tv_sec ) \ 391 426 || (((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 392 447 393 448 … … 415 470 416 471 if (th_ret != NULL) { 417 TRACE_DEBUG( FULL, "The thread returned the following value: %p (ignored)", th_ret);472 TRACE_DEBUG(ANNOYING, "The thread returned the following value: %p (ignored)", th_ret); 418 473 } 419 474 … … 439 494 free(buffer); 440 495 } 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 441 504 442 505 /*============================================================*/ … … 465 528 void fd_list_insert_after ( struct fd_list * ref, struct fd_list * item ); 466 529 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); 467 533 468 534 /* Insert an item in an ordered list -- ordering function provided. If duplicate object found, EEXIST and it is returned in ref_duplicate */ … … 2342 2408 2343 2409 /* 2410 * FUNCTION: fd_fifo_move 2411 * 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 /* 2344 2427 * FUNCTION: fd_fifo_length 2345 2428 * -
libfreeDiameter/fifo.c
r14 r25 136 136 } 137 137 138 /* Delete a queue. It must be unused. */138 /* Delete a queue. It must be empty. */ 139 139 int fd_fifo_del ( struct fifo ** queue ) 140 140 { 141 141 struct fifo * q; 142 int loops = 0; 142 143 143 144 TRACE_ENTRY( "%p", queue ); … … 149 150 CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); 150 151 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);152 if ((q->count != 0) || (q->data != NULL)) { 153 TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %p)", q->count, q->data); 153 154 CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); 154 155 return EINVAL; 155 156 } 156 157 158 /* Ok, now invalidate the queue */ 159 q->eyec = 0xdead; 160 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 157 169 /* sanity check */ 158 170 ASSERT(FD_IS_LIST_EMPTY(&q->list)); 159 171 160 /* Ok, now invalidate the queue */161 q->eyec = 0xdead;162 163 172 /* And destroy it */ 164 173 CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); … … 170 179 free(q); 171 180 *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 ) ); 172 234 173 235 return 0; … … 379 441 awaken: 380 442 /* 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 381 450 if (queue->count > 0) { 382 451 /* There are items in the queue, so pick the first one */ -
libfreeDiameter/lists.c
r14 r25 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 72 90 } 73 91 -
libfreeDiameter/log.c
r2 r22 87 87 } 88 88 89 /* Write currenttime into a buffer */90 char * fd_log_time ( char * buf, size_t len )89 /* Write time into a buffer */ 90 char * fd_log_time ( struct timespec * ts, char * buf, size_t len ) 91 91 { 92 92 int ret; … … 96 96 97 97 /* Get current time */ 98 ret = clock_gettime(CLOCK_REALTIME, &tp); 99 if (ret != 0) { 100 snprintf(buf, len, "%s", strerror(ret)); 101 return buf; 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; 102 105 } 103 106 104 offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &t p.tv_sec , &tm ));105 offset += snprintf(buf + offset, len - offset, ".%6.6ld", t p.tv_nsec / 1000);107 offset += strftime(buf + offset, len - offset, "%D,%T", localtime_r( &ts->tv_sec , &tm )); 108 offset += snprintf(buf + offset, len - offset, ".%6.6ld", ts->tv_nsec / 1000); 106 109 107 110 return buf;
Note: See TracChangeset
for help on using the changeset viewer.