1 /********************************************************************************************************* 2 * Software License Agreement (BSD License) * 3 * Author: Sebastien Decugis <sdecugis@freediameter.net> * 4 * * 5 * Copyright (c) 2020, WIDE Project and NICT * 6 * All rights reserved. * 7 * * 8 * Redistribution and use of this software in source and binary forms, with or without modification, are * 9 * permitted provided that the following conditions are met: * 10 * * 11 * * Redistributions of source code must retain the above * 12 * copyright notice, this list of conditions and the * 13 * following disclaimer. * 14 * * 15 * * Redistributions in binary form must reproduce the above * 16 * copyright notice, this list of conditions and the * 17 * following disclaimer in the documentation and/or other * 18 * materials provided with the distribution. * 19 * * 20 * * Neither the name of the WIDE Project or NICT nor the * 21 * names of its contributors may be used to endorse or * 22 * promote products derived from this software without * 23 * specific prior written permission of WIDE Project and * 24 * NICT. * 25 * * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * 27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * 29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * 30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * 32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 34 *********************************************************************************************************/ 35 36 /* This file contains the definitions for internal use in the freeDiameter core library */ 37 38 #ifndef _FDCORE_INTERNAL_H 39 #define _FDCORE_INTERNAL_H 40 41 #include <freeDiameter/freeDiameter-host.h> 42 #include <freeDiameter/libfdcore.h> 43 44 #ifdef DISABLE_SCTP 45 #undef IPPROTO_SCTP 46 #define IPPROTO_SCTP (2 = 4) /* some compilation error to spot the references */ 47 #endif /* DISABLE_SCTP */ 48 49 #ifndef HAVE_AI_ADDRCONFIG 50 #define AI_ADDRCONFIG 0 /* ignore this flag at the moment */ 51 #endif /* HAVE_AI_ADDRCONFIG */ 52 53 /* Timeout for establishing a connection */ 54 #ifndef CNX_TIMEOUT 55 #define CNX_TIMEOUT 10 /* in seconds */ 56 #endif /* CNX_TIMEOUT */ 57 58 /* Timeout for receiving a CER after incoming connection is established */ 59 #ifndef INCNX_TIMEOUT 60 #define INCNX_TIMEOUT 20 /* in seconds */ 61 #endif /* INCNX_TIMEOUT */ 62 63 /* Timeout for receiving a CEA after CER is sent */ 64 #ifndef CEA_TIMEOUT 65 #define CEA_TIMEOUT 10 /* in seconds */ 66 #endif /* CEA_TIMEOUT */ 67 68 /* The timeout value to wait for answer to a DPR */ 69 #ifndef DPR_TIMEOUT 70 #define DPR_TIMEOUT 15 /* in seconds */ 71 #endif /* DPR_TIMEOUT */ 72 73 /* Delay where the connection is maintained opened to allow exchanging remaining pending answers after DPR/DPA */ 74 #ifndef GRACE_TIMEOUT 75 #define GRACE_TIMEOUT 1 /* in seconds */ 76 #endif /* GRACE_TIMEOUT */ 77 78 /* The Vendor-Id to advertise in CER/CEA */ 79 #ifndef MY_VENDOR_ID 80 #define MY_VENDOR_ID 0 /* Reserved value to tell it must be ignored */ 81 #endif /* MY_VENDOR_ID */ 82 83 84 85 /* Configuration */ 86 int fd_conf_init(); 87 int fd_conf_deinit(); 88 int fd_conf_parse(); 89 int fddparse(struct fd_config * conf); /* yacc generated */ 90 int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out); 91 92 93 /* Extensions */ 94 int fd_ext_add( char * filename, char * conffile ); 95 int fd_ext_load(); 96 int fd_ext_term(void); 97 98 /* Messages */ 99 int fd_msg_init(void); 100 extern struct dict_object * fd_dict_avp_OSI; /* Origin-State-Id */ 101 extern struct dict_object * fd_dict_cmd_CER; /* Capabilities-Exchange-Request */ 102 extern struct dict_object * fd_dict_cmd_DWR; /* Device-Watchdog-Request */ 103 extern struct dict_object * fd_dict_avp_DC; /* Disconnect-Cause */ 104 extern struct dict_object * fd_dict_cmd_DPR; /* Disconnect-Peer-Request */ 105 106 /* Global message queues */ 107 extern struct fifo * fd_g_incoming; /* all messages received from other peers, except local messages (CER, ...) */ 108 extern struct fifo * fd_g_outgoing; /* messages to be sent to other peers on the network following routing procedure */ 109 extern struct fifo * fd_g_local; /* messages to be handled to local extensions */ 110 /* Message queues */ 111 int fd_queues_init(void); 112 int fd_queues_init_after_conf(void); 113 int fd_queues_fini(struct fifo ** queue); 114 115 /* Trigged events */ 116 int fd_event_trig_call_cb(int trigger_val); 117 int fd_event_trig_fini(void); 118 119 /* Create all the dictionary objects defined in the Diameter base RFC. */ 120 int fd_dict_base_protocol(struct dictionary * dict); 121 122 /* Routing */ 123 int fd_rtdisp_init(void); 124 int fd_rtdisp_cleanstop(void); 125 int fd_rtdisp_fini(void); 126 int fd_rtdisp_cleanup(void); 127 128 /* Sentinel for the sent requests list */ 129 struct sr_list { 130 struct fd_list srs; /* requests ordered by hop-by-hop id */ 131 struct fd_list exp; /* requests that have a timeout set, ordered by timeout */ 132 long cnt; /* number of requests in the srs list */ 133 long cnt_lost; /* number of requests that have not been answered in time. 134 It is decremented when an unexpected answer is received, so this may not be accurate. */ 135 pthread_mutex_t mtx; /* mutex to protect these lists */ 136 pthread_cond_t cnd; /* cond var used by the thread that handles timeouts */ 137 pthread_t thr; /* the thread that handles timeouts (expirecb called in separate forked threads) */ 138 }; 139 140 /* Peers */ 141 struct fd_peer { /* The "real" definition of the peer structure */ 142 143 /* The public data */ 144 struct peer_hdr p_hdr; 145 146 /* Eye catcher, EYEC_PEER */ 147 int p_eyec; 148 #define EYEC_PEER 0x373C9336 149 150 /* Origin of this peer object, for debug */ 151 char *p_dbgorig; 152 153 /* State of the peer, and its lock */ 154 enum peer_state p_state; 155 pthread_mutex_t p_state_mtx; 156 157 /* Chaining in peers sublists */ 158 struct fd_list p_actives; /* list of peers in the STATE_OPEN state -- used by routing */ 159 struct fd_list p_expiry; /* list of expiring peers, ordered by their timeout value */ 160 struct timespec p_exp_timer; /* Timestamp where the peer will expire; updated each time activity is seen on the peer (except DW) */ 161 162 /* Some flags influencing the peer state machine */ 163 struct { 164 unsigned pf_responder : 1; /* The peer has been created to handle incoming connection */ 165 unsigned pf_delete : 1; /* Destroy the peer when the connection is terminated */ 166 unsigned pf_localterm : 1; /* If the latest DPR/DPA was initiated from this side */ 167 168 unsigned pf_dw_pending : 1; /* A DWR message was sent and not answered yet */ 169 170 unsigned pf_cnx_pb : 1; /* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */ 171 unsigned pf_reopen_cnt : 2; /* remaining DW to be exchanged after re-established connection */ 172 173 } p_flags; 174 175 /* The events queue, peer state machine thread, timer for states timeouts */ 176 struct fifo *p_events; /* The mutex of this FIFO list protects also the state and timer information */ 177 pthread_t p_psm; 178 struct timespec p_psm_timer; 179 180 /* Outgoing message queue, and thread managing sending the messages */ 181 struct fifo *p_tosend; 182 pthread_t p_outthr; 183 184 /* The next hop-by-hop id value for the link, only read & modified by p_outthr */ 185 uint32_t p_hbh; 186 187 /* Sent requests (for fallback), list of struct sentreq ordered by hbh */ 188 struct sr_list p_sr; 189 struct fifo *p_tofailover; 190 191 /* Pending received requests not yet answered (count only) */ 192 long p_reqin_count; /* We use p_state_mtx to protect this value */ 193 194 /* Data for transitional states before the peer is in OPEN state */ 195 struct { 196 struct cnxctx * p_receiver; /* Only used in case of election */ 197 struct msg * p_cer; /* Only used in case of election */ 198 199 pthread_t p_ini_thr; /* Initiator thread for establishing a connection */ 200 struct fd_list p_connparams; /* The list of connection attempts, see p_cnx.c */ 201 }; 202 203 /* connection context: socket and related information */ 204 struct cnxctx *p_cnxctx; 205 206 /* Callback for peer validation after the handshake */ 207 int (*p_cb2)(struct peer_info *); 208 209 /* Callback on initial connection success / failure after the peer was added */ 210 void (*p_cb)(struct peer_info *, void *); 211 void *p_cb_data; 212 213 }; 214 #define CHECK_PEER( _p ) \ 215 (((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER)) 216 217 #define fd_peer_getstate(peer) fd_peer_get_state((struct peer_hdr *)(peer)) 218 219 220 /* Events codespace for struct fd_peer->p_events */ 221 enum { 222 /* request to terminate this peer : disconnect, requeue all messages */ 223 FDEVP_TERMINATE = 1500 224 225 /* A connection object has received a message. (data contains the buffer + padding + struct fd_msg_pmdl) */ 226 ,FDEVP_CNX_MSG_RECV 227 228 /* A connection object has encountered an error (disconnected). */ 229 ,FDEVP_CNX_ERROR 230 231 /* Endpoints of a connection have been changed (multihomed SCTP). */ 232 ,FDEVP_CNX_EP_CHANGE 233 234 /* The connection is being shutdown (SCTP notification). */ 235 ,FDEVP_CNX_SHUTDOWN 236 237 /* A new connection (with a CER) has been received */ 238 ,FDEVP_CNX_INCOMING 239 240 /* A new connection has been established to the remote peer (event data is the cnxctx object) */ 241 ,FDEVP_CNX_ESTABLISHED 242 243 /* A connection attempt (initiator side) has failed */ 244 ,FDEVP_CNX_FAILED 245 246 /* The PSM state is expired */ 247 ,FDEVP_PSM_TIMEOUT 248 249 }; 250 #define CHECK_PEVENT( _e ) \ 251 (((int)(_e) >= FDEVP_TERMINATE) && ((int)(_e) <= FDEVP_PSM_TIMEOUT)) 252 /* The following macro is actually called in p_psm.c -- another solution would be to declare it static inline */ 253 #define DECLARE_PEV_STR() \ 254 const char * fd_pev_str(int event) \ 255 { \ 256 switch (event) { \ 257 case_str(FDEVP_TERMINATE); \ 258 case_str(FDEVP_CNX_MSG_RECV); \ 259 case_str(FDEVP_CNX_ERROR); \ 260 case_str(FDEVP_CNX_EP_CHANGE); \ 261 case_str(FDEVP_CNX_INCOMING); \ 262 case_str(FDEVP_CNX_ESTABLISHED); \ 263 case_str(FDEVP_CNX_FAILED); \ 264 case_str(FDEVP_PSM_TIMEOUT); \ 265 } \ 266 TRACE_DEBUG(FULL, "Unknown event : %d", event); \ 267 return "Unknown event"; \ 268 } 269 const char * fd_pev_str(int event); 270 271 /* The data structure for FDEVP_CNX_INCOMING event */ 272 struct cnx_incoming { 273 struct msg * cer; /* the CER message received on this connection */ 274 struct cnxctx * cnx; /* The connection context */ 275 int validate; /* The peer is new, it must be validated (by an extension) or error CEA to be sent */ 276 }; 277 278 /* Functions */ 279 int fd_peer_fini(); 280 int fd_peer_alloc(struct fd_peer ** ptr); 281 int fd_peer_free(struct fd_peer ** ptr); 282 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx ); 283 /* fd_peer_add declared in freeDiameter.h */ 284 int fd_peer_validate( struct fd_peer * peer ); 285 void fd_peer_failover_msg(struct fd_peer * peer); 286 287 /* Peer expiry */ 288 int fd_p_expi_init(void); 289 int fd_p_expi_fini(void); 290 int fd_p_expi_update(struct fd_peer * peer ); 291 292 /* Peer state machine */ 293 int fd_psm_start(); 294 int fd_psm_begin(struct fd_peer * peer ); 295 int fd_psm_terminate(struct fd_peer * peer, char * reason ); 296 void fd_psm_abord(struct fd_peer * peer ); 297 void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay); 298 int fd_psm_change_state(struct fd_peer * peer, int new_state); 299 void fd_psm_cleanup(struct fd_peer * peer, int terminate); 300 301 /* Peer out */ 302 int fd_out_send(struct msg ** msg, struct cnxctx * cnx, struct fd_peer * peer, int update_reqin_cnt); 303 int fd_out_start(struct fd_peer * peer); 304 int fd_out_stop(struct fd_peer * peer); 305 306 /* Initiating connections */ 307 int fd_p_cnx_init(struct fd_peer * peer); 308 void fd_p_cnx_abort(struct fd_peer * peer, int cleanup_all); 309 310 /* Peer sent requests cache */ 311 int fd_p_sr_store(struct sr_list * srlist, struct msg **req, uint32_t *hbhloc, uint32_t hbh_restore); 312 int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req); 313 int fd_p_sr_start(struct sr_list * srlist); 314 int fd_p_sr_stop(struct sr_list * srlist); 315 void fd_p_sr_failover(struct sr_list * srlist); 316 317 /* Local Link messages (CER/CEA, DWR/DWA, DPR/DPA) */ 318 int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer); 319 int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid); 320 int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator); 321 int fd_p_ce_process_receiver(struct fd_peer * peer); 322 void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept); 323 int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer); 324 int fd_p_dw_timeout(struct fd_peer * peer); 325 int fd_p_dw_reopen(struct fd_peer * peer); 326 int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer); 327 int fd_p_dp_initiate(struct fd_peer * peer, char * reason); 328 int fd_p_dp_newdelay(struct fd_peer * peer); 329 330 /* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */ 331 extern struct fd_list fd_g_activ_peers; 332 extern pthread_rwlock_t fd_g_activ_peers_rw; /* protect the list */ 333 334 335 /* Server sockets */ 336 int fd_servers_start(); 337 int fd_servers_stop(); 338 339 /* Connection contexts -- there are also definitions in cnxctx.h for the relevant files */ 340 struct cnxctx * fd_cnx_serv_tcp(uint16_t port, int family, struct fd_endpoint * ep); 341 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list); 342 int fd_cnx_serv_listen(struct cnxctx * conn); 343 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv); 344 struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen); 345 struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list, struct fd_list * src_list); 346 int fd_cnx_start_clear(struct cnxctx * conn, int loop); 347 void fd_cnx_sethostname(struct cnxctx * conn, DiamId_t hn); 348 int fd_cnx_proto_info(struct cnxctx * conn, char * buf, size_t len); 349 #define ALGO_HANDSHAKE_DEFAULT 0 /* TLS for TCP, DTLS for SCTP */ 350 #define ALGO_HANDSHAKE_3436 1 /* For TLS for SCTP also */ 351 int fd_cnx_handshake(struct cnxctx * conn, int mode, int algo, char * priority, void * alt_creds); 352 char * fd_cnx_getid(struct cnxctx * conn); 353 int fd_cnx_getproto(struct cnxctx * conn); 354 int fd_cnx_getTLS(struct cnxctx * conn); 355 int fd_cnx_is_unordered_delivery_supported(struct cnxctx * conn); 356 int fd_cnx_unordered_delivery(struct cnxctx * conn, int is_allowed); 357 int fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size); 358 int fd_cnx_get_local_eps(struct fd_list * list); 359 int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps); 360 char * fd_cnx_getremoteid(struct cnxctx * conn); 361 int fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len); 362 int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */ 363 int fd_cnx_send(struct cnxctx * conn, unsigned char * buf, size_t len); 364 void fd_cnx_destroy(struct cnxctx * conn); 365 #ifdef GNUTLS_VERSION_300 366 int fd_tls_verify_credentials_2(gnutls_session_t session); 367 #endif /* GNUTLS_VERSION_300 */ 368 369 /* Internal calls of the hook mechanism */ 370 void fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl); 371 void fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl); 372 int fd_hooks_init(void); 373 size_t fd_msg_pmdl_sizewithoverhead(size_t datalen); 374 struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen); 375 376 #endif /* _FDCORE_INTERNAL_H */ 377