Changeset 22:0b3b46da2c12 in freeDiameter for freeDiameter/cnxctx.c
- Timestamp:
- Oct 19, 2009, 6:43:09 PM (15 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
freeDiameter/cnxctx.c
r21 r22 36 36 #include "fD.h" 37 37 38 /* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations . 39 * They are used to hide the details of the processing to the higher layers of the daemon. 40 * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported. 41 */ 42 43 /* Note: this file could be moved to libfreeDiameter instead, but since it uses gnuTLS we prefer to keep it in the daemon */ 44 45 /* Lifetime of a cnxctx object: 46 * 1) Creation 47 * a) a server socket: 48 * - create the object with fd_cnx_serv_tcp or fd_cnx_serv_sctp 49 * - start listening incoming connections: fd_cnx_serv_listen 50 * - accept new clients with fd_cnx_serv_accept. 51 * b) a client socket: 52 * - connect to a remote server with fd_cnx_cli_connect 53 * 54 * 2) Initialization 55 * - if TLS is started first, call fd_cnx_handshake 56 * - otherwise to receive clear messages, call fd_cnx_start_clear. fd_cnx_handshake can be called later. 57 * 58 * 3) Usage 59 * - fd_cnx_receive, fd_cnx_send : exchange messages on this connection (send is synchronous, receive is not). 60 * - 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. 61 * - fd_cnx_getid : retrieve a descriptive string for the connection (for debug) 62 * - fd_cnx_getremoteid : identification of the remote peer (IP address or fqdn) 63 * - fd_cnx_getcred : get the remote peer TLS credentials, after handshake 64 * - fd_cnx_getendpoints : get the endpoints (IP) of the connection 65 * 66 * 4) End 67 * - fd_cnx_destroy 68 */ 69 38 70 /* The connection context structure */ 39 71 struct cnxctx { 72 char cc_id[60]; /* The name of this connection */ 73 char cc_remid[60]; /* Id of remote peer */ 74 40 75 int cc_socket; /* The socket object of the connection -- <=0 if no socket is created */ 41 76 42 77 int cc_proto; /* IPPROTO_TCP or IPPROTO_SCTP */ 43 78 int cc_tls; /* Is TLS already started ? */ 44 79 45 80 struct fifo * cc_events; /* Events occuring on the connection */ 46 81 pthread_t cc_mgr; /* manager thread for the connection */ 47 82 struct fifo * cc_incoming; /* FIFO queue of messages received on the connection */ 48 49 uint16_t cc_port; /* Remote port of the connection, when we are client */ 50 struct fd_list cc_ep_remote; /* The remote address(es) of the connection */ 51 struct fd_list cc_ep_local; /* The local address(es) of the connection */ 52 83 struct fifo * cc_alt; /* alternate fifo to send FDEVP_CNX_MSG_RECV events to. */ 84 53 85 /* If cc_proto == SCTP */ 54 86 struct { … … 58 90 int next; /* # of stream the next message will be sent to */ 59 91 } cc_sctp_para; 60 92 61 93 /* If cc_tls == true */ 62 94 struct { … … 64 96 gnutls_session_t session; /* Session object (stream #0 in case of SCTP) */ 65 97 } cc_tls_para; 66 98 67 99 /* If both conditions */ 68 100 struct { … … 73 105 74 106 75 /* Initialize a context structure from a socket*/76 st ruct cnxctx * fd_cnx_init(int sock, int proto)107 /* Initialize a context structure */ 108 static struct cnxctx * fd_cnx_init(int full) 77 109 { 78 110 struct cnxctx * conn = NULL; 79 80 TRACE_ENTRY("%d %d", sock, proto); 81 CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL); 82 111 112 TRACE_ENTRY("%d", full); 113 83 114 CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL ); 84 115 memset(conn, 0, sizeof(struct cnxctx)); 85 86 conn->cc_socket = sock; 87 conn->cc_proto = proto; 88 89 fd_list_init(&conn->cc_ep_remote, conn); 90 fd_list_init(&conn->cc_ep_local, conn); 91 92 if (proto == IPPROTO_SCTP) { 116 117 if (full) { 118 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_events ), return NULL ); 119 CHECK_FCT_DO( fd_fifo_new ( &conn->cc_incoming ), return NULL ); 120 } 121 122 return conn; 123 } 124 125 /* Create and bind a server socket to the given endpoint and port */ 126 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep) 127 { 128 struct cnxctx * cnx = NULL; 129 sSS dummy; 130 sSA * sa = (sSA *) &dummy; 131 132 TRACE_ENTRY("%hu %d %p", port, family, ep); 133 134 CHECK_PARAMS_DO( port, return NULL ); 135 CHECK_PARAMS_DO( ep || family, return NULL ); 136 CHECK_PARAMS_DO( (! family) || (family == AF_INET) || (family == AF_INET6), return NULL ); 137 CHECK_PARAMS_DO( (! ep) || (!family) || (ep->ss.ss_family == family), return NULL ); 138 139 /* The connection object */ 140 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); 141 142 /* Prepare the socket address information */ 143 if (ep) { 144 memcpy(sa, &ep->ss, sizeof(sSS)); 145 } else { 146 memset(&dummy, 0, sizeof(dummy)); 147 sa->sa_family = family; 148 } 149 if (sa->sa_family == AF_INET) { 150 ((sSA4 *)sa)->sin_port = htons(port); 151 } else { 152 ((sSA6 *)sa)->sin6_port = htons(port); 153 } 154 155 /* Create the socket */ 156 CHECK_FCT_DO( fd_tcp_create_bind_server( &cnx->cc_socket, sa, sizeof(sSS) ), goto error ); 157 158 /* Generate the name for the connection object */ 159 { 160 char addrbuf[INET6_ADDRSTRLEN]; 161 int rc; 162 rc = getnameinfo(sa, sizeof(sSS), addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); 163 if (rc) 164 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 165 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv TCP [%s]:%hu (%d)", addrbuf, port, cnx->cc_socket); 166 } 167 168 cnx->cc_proto = IPPROTO_TCP; 169 170 return cnx; 171 172 error: 173 fd_cnx_destroy(cnx); 174 return NULL; 175 } 93 176 #ifndef DISABLE_SCTP 94 CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ), 95 { free(conn); return NULL; } ); 96 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; 97 #else /* DISABLE_SCTP */ 98 ASSERT(0); 177 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list) 178 { 179 struct cnxctx * cnx = NULL; 180 sSS dummy; 181 sSA * sa = (sSA *) &dummy; 182 183 TRACE_ENTRY("%hu %p", port, ep_list); 184 185 CHECK_PARAMS_DO( port, return NULL ); 186 187 /* The connection object */ 188 CHECK_MALLOC_DO( cnx = fd_cnx_init(0), return NULL ); 189 190 /* Create the socket */ 191 CHECK_FCT_DO( fd_sctp_create_bind_server( &cnx->cc_socket, ep_list, port ), goto error ); 192 193 /* Generate the name for the connection object */ 194 snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Srv SCTP :%hu (%d)", port, cnx->cc_socket); 195 196 cnx->cc_proto = IPPROTO_SCTP; 197 198 return cnx; 199 200 error: 201 fd_cnx_destroy(cnx); 202 return NULL; 203 } 99 204 #endif /* DISABLE_SCTP */ 100 } 101 102 return conn; 205 206 /* Allow clients to connect on the server socket */ 207 int fd_cnx_serv_listen(struct cnxctx * conn) 208 { 209 CHECK_PARAMS( conn ); 210 211 switch (conn->cc_proto) { 212 case IPPROTO_TCP: 213 CHECK_FCT(fd_tcp_listen(conn->cc_socket)); 214 break; 215 216 case IPPROTO_SCTP: 217 CHECK_FCT(fd_sctp_listen(conn->cc_socket)); 218 break; 219 220 default: 221 CHECK_PARAMS(0); 222 } 223 224 return 0; 225 } 226 227 /* Accept a client (blocking until a new client connects) -- cancelable */ 228 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv) 229 { 230 struct cnxctx * cli = NULL; 231 sSS ss; 232 socklen_t ss_len = sizeof(ss); 233 int cli_sock = 0; 234 struct fd_endpoint * ep; 235 236 TRACE_ENTRY("%p", serv); 237 CHECK_PARAMS_DO(serv, return NULL); 238 239 CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL ); 240 241 if (TRACE_BOOL(INFO)) { 242 fd_log_debug("%s - new client [", fd_cnx_getid(serv)); 243 sSA_DUMP_NODE( &ss, AI_NUMERICHOST ); 244 fd_log_debug("] connected.\n"); 245 } 246 247 CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); return NULL; } ); 248 cli->cc_socket = cli_sock; 249 cli->cc_proto = serv->cc_proto; 250 251 /* Generate the name for the connection object */ 252 { 253 char addrbuf[INET6_ADDRSTRLEN]; 254 char portbuf[10]; 255 int rc; 256 257 /* Numeric values for debug */ 258 rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV); 259 if (rc) 260 snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc)); 261 262 snprintf(cli->cc_id, sizeof(cli->cc_id), "Client %s [%s]:%s (%d) / serv (%d)", 263 IPPROTO_NAME(cli->cc_proto), 264 addrbuf, portbuf, 265 cli->cc_socket, serv->cc_socket); 266 267 /* Textual value for log messages */ 268 rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, NI_NUMERICHOST); 269 if (rc) 270 snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc)); 271 } 272 273 /* SCTP-specific handlings */ 274 #ifndef DISABLE_SCTP 275 if (cli->cc_proto == IPPROTO_SCTP) { 276 /* Retrieve the number of streams */ 277 CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out ), goto error ); 278 if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in) 279 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out; 280 else 281 cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in; 282 } 283 #endif /* DISABLE_SCTP */ 284 285 return cli; 286 error: 287 fd_cnx_destroy(cli); 288 return NULL; 289 } 290 291 /* Client side: connect to a remote server */ 292 struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa, socklen_t addrlen) 293 { 294 295 TODO("..."); 296 return NULL; 297 } 298 299 /* Return a string describing the connection, for debug */ 300 char * fd_cnx_getid(struct cnxctx * conn) 301 { 302 CHECK_PARAMS_DO( conn, return "" ); 303 return conn->cc_id; 103 304 } 104 305 … … 106 307 int fd_cnx_start_clear(struct cnxctx * conn) 107 308 { 108 309 109 310 TODO("..."); 110 311 return ENOTSUP; … … 112 313 113 314 /* TLS handshake a connection; no need to have called start_clear before. Reception is active if handhsake is successful */ 114 int fd_cnx_handshake(struct cnxctx * conn, int mode )315 int fd_cnx_handshake(struct cnxctx * conn, int mode, char * priority) 115 316 { 116 317 TRACE_ENTRY( "%p %d", conn, mode); 117 318 CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) ); 118 319 119 320 /* Save the mode */ 120 321 conn->cc_tls_para.mode = mode; 121 322 122 323 /* Create the master session context */ 123 324 CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM ); 124 325 125 326 /* Set the algorithm suite */ 327 TODO("Use overwrite priority if non NULL"); 126 328 CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL ); 127 329 128 330 /* Set the credentials of this side of the connection */ 129 331 CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL ); 130 332 131 333 /* Request the remote credentials as well */ 132 334 if (mode == GNUTLS_SERVER) { … … 146 348 #endif /* DISABLE_SCTP */ 147 349 } 148 350 149 351 /* Handshake master session */ 150 352 { … … 153 355 { 154 356 if (TRACE_BOOL(INFO)) { 155 fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));357 fd_log_debug("TLS Handshake failed on socket %d (%s) : %s\n", conn->cc_socket, conn->cc_id, gnutls_strerror(ret)); 156 358 } 157 359 return EINVAL; 158 360 } ); 159 361 160 362 /* Now verify the remote credentials are valid -- only simple test here */ 161 363 CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL ); 162 364 if (ret) { 163 365 if (TRACE_BOOL(INFO)) { 164 fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);366 fd_log_debug("TLS: Remote certificate invalid on socket %d (%s) :\n", conn->cc_socket, conn->cc_id); 165 367 if (ret & GNUTLS_CERT_INVALID) 166 368 fd_log_debug(" - The certificate is not trusted (unknown CA?)\n"); … … 177 379 } 178 380 } 179 381 180 382 /* Other sessions in case of multi-stream SCTP are resumed from the master */ 181 383 if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) { … … 184 386 #endif /* DISABLE_SCTP */ 185 387 } 186 388 389 TODO("Start the connection state machine thread"); 390 187 391 return 0; 188 392 } … … 191 395 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size) 192 396 { 193 397 194 398 TODO("..."); 195 399 return ENOTSUP; 196 400 } 197 401 198 /* Get the list of endpoints (IP addresses) of the remote peer on this object */ 199 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * senti) 200 { 201 402 /* Get the list of endpoints (IP addresses) of the local and remote peers on this conenction */ 403 int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote) 404 { 405 TRACE_ENTRY("%p %p %p", conn, local, remote); 406 CHECK_PARAMS(conn); 407 408 if (local) { 409 /* Retrieve the local endpoint(s) of the connection */ 410 TODO("TCP : getsockname"); 411 TODO("SCTP: sctp_getladdrs / _sctp_getboundaddrs (waaad)"); 412 } 413 414 if (remote) { 415 /* Retrieve the peer endpoint(s) of the connection */ 416 TODO("TCP : getpeername"); 417 TODO("SCTP: sctp_getpaddrs"); 418 419 } 420 421 return ENOTSUP; 422 } 423 424 425 /* Get a string describing the remote peer address (ip address or fqdn) */ 426 char * fd_cnx_getremoteid(struct cnxctx * conn) 427 { 428 CHECK_PARAMS_DO( conn, return "" ); 429 return conn->cc_remid; 430 } 431 432 433 /* Receive next message. if timeout is not NULL, wait only until timeout */ 434 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 435 { 436 202 437 TODO("..."); 203 438 return ENOTSUP; 204 439 } 205 440 206 207 /* Get a string describing the remote peer address (ip address or fqdn) */ 208 char * fd_cnx_getremoteid(struct cnxctx * conn) 209 { 210 211 TODO("..."); 212 return NULL; 213 } 214 215 216 /* Receive next message. if timeout is not NULL, wait only until timeout */ 217 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len) 218 { 219 441 /* Set / reset alternate FIFO list to send FDEVP_CNX_MSG_RECV to when message is received */ 442 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo) 443 { 444 TRACE_ENTRY( "%p %p", conn, alt_fifo ); 445 CHECK_PARAMS( conn ); 446 447 /* Let's cross fingers that there is no race condition here... */ 448 conn->cc_alt = alt_fifo; 449 450 return 0; 451 } 452 453 /* Send a message */ 454 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len) 455 { 456 220 457 TODO("..."); 221 458 return ENOTSUP; … … 223 460 224 461 225 /* Send a message */226 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len)227 {228 229 TODO("...");230 return ENOTSUP;231 }232 233 234 462 /* Destroy a conn structure, and shutdown the socket */ 235 463 void fd_cnx_destroy(struct cnxctx * conn) 236 464 { 237 238 TODO("..."); 465 TRACE_ENTRY("%p", conn); 466 467 CHECK_PARAMS_DO(conn, return); 468 469 TODO("End TLS session(s) if started"); 470 471 TODO("Stop manager thread if running"); 472 473 /* Shut the connection down */ 474 if (conn->cc_socket > 0) { 475 shutdown(conn->cc_socket, SHUT_RDWR); 476 } 477 478 TODO("Empty FIFO queues"); 479 480 /* Destroy FIFO lists */ 481 if (conn->cc_events) 482 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_events ), /* continue */ ); 483 if (conn->cc_incoming) 484 CHECK_FCT_DO( fd_fifo_del ( &conn->cc_incoming ), /* continue */ ); 485 486 /* Free the object */ 487 free(conn); 488 489 /* Done! */ 239 490 return; 240 491 }
Note: See TracChangeset
for help on using the changeset viewer.