Navigation


source: freeDiameter/include/freeDiameter/libfdcore.h @ 706:4ffbc9f1e922

Last change on this file since 706:4ffbc9f1e922 was 706:4ffbc9f1e922, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Large UNTESTED commit with the following changes:

  • Improved DiameterIdentity? handling (esp. interationalization issues), and improve efficiency of some string operations in peers, sessions, and dictionary modules (closes #7)
  • Cleanup in the session module to free only unreferenced sessions (#16)
  • Removed fd_cpu_flush_cache(), replaced by more robust alternatives.
  • Improved peer state machine algorithm to counter SCTP multistream race condition.
File size: 37.7 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, 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#ifndef _LIBFDCORE_H
37#define _LIBFDCORE_H
38
39
40#include <freeDiameter/libfdproto.h>
41#include <gnutls/gnutls.h>
42#include <gnutls/x509.h>
43
44/* GNUTLS version */
45#ifndef GNUTLS_VERSION
46#define GNUTLS_VERSION LIBGNUTLS_VERSION
47#endif /* GNUTLS_VERSION */
48
49/* GNUTLS calls debug level */
50#ifndef GNUTLS_DBG_LEVEL
51#define GNUTLS_DBG_LEVEL ANNOYING
52#endif /* GNUTLS_DBG_LEVEL */
53
54/* Check the return value of a GNUTLS function, log and propagate */
55#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {                                             \
56        int __ret__;                                                                            \
57        TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );                              \
58        __ret__ = (__call__);                                                                   \
59        if (__ret__ < 0) {                                                                      \
60                TRACE_DEBUG(INFO, "Error in '" #__call__ "':\t%s", gnutls_strerror(__ret__));   \
61                __fallback__;                                                                   \
62        }                                                                                       \
63}
64
65/* For GNUTLS routines that do not return a value */
66#define GNUTLS_TRACE( __call__) {                                       \
67        TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );      \
68        (__call__);                                                     \
69}
70
71
72/*============================================================*/
73/*                      INITIALIZATION                        */
74/*============================================================*/
75
76
77/* Initialize the libfdcore internals. This also initializes libfdproto */
78int fd_core_initialize(void);
79
80/* Return a string describing the version of the library */
81const char *fd_core_version(void);
82
83/* Parse the freeDiameter.conf configuration file, load the extensions */
84int fd_core_parseconf(char * conffile);
85
86/* Start the server & client threads */
87int fd_core_start(void);
88
89/* Block until the framework has completed its initialization -- useful for extensions */
90int fd_core_waitstartcomplete(void);
91
92/* Initialize shutdown of the framework */
93int fd_core_shutdown(void);
94
95/* Wait for the shutdown to be complete -- this should always be called after fd_core_shutdown */
96int fd_core_wait_shutdown_complete(void);
97
98
99/*============================================================*/
100/*                          CONFIG                            */
101/*============================================================*/
102
103/* Structure to hold the configuration of the freeDiameter daemon */
104#define EYEC_CONFIG     0xC011F16
105struct fd_config {
106        int              cnf_eyec;      /* Eye catcher: EYEC_CONFIG */
107       
108        char            *cnf_file;      /* Configuration file to parse, default is DEFAULT_CONF_FILE */
109       
110        DiamId_t         cnf_diamid;    /* Diameter Identity of the local peer (FQDN -- ASCII) */
111        size_t           cnf_diamid_len;/* cached length of the previous string */
112        DiamId_t         cnf_diamrlm;   /* Diameter realm of the local peer, default to realm part of cnf_diamid */
113        size_t           cnf_diamrlm_len;/* length of the previous string */
114       
115        unsigned int     cnf_timer_tc;  /* The value in seconds of the default Tc timer */
116        unsigned int     cnf_timer_tw;  /* The value in seconds of the default Tw timer */
117       
118        uint16_t         cnf_port;      /* the local port for legacy Diameter (default: 3868) in host byte order */
119        uint16_t         cnf_port_tls;  /* the local port for Diameter/TLS (default: 3869) in host byte order */
120        uint16_t         cnf_sctp_str;  /* default max number of streams for SCTP associations (def: 30) */
121        struct fd_list   cnf_endpoints; /* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */
122        struct fd_list   cnf_apps;      /* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */
123        uint16_t         cnf_dispthr;   /* Number of dispatch threads to create */
124        struct {
125                unsigned no_fwd : 1;    /* the peer does not relay messages (0xffffff app id) */
126                unsigned no_ip4 : 1;    /* disable IP */
127                unsigned no_ip6 : 1;    /* disable IPv6 */
128                unsigned no_tcp : 1;    /* disable use of TCP */
129                unsigned no_sctp: 1;    /* disable the use of SCTP */
130                unsigned pr_tcp : 1;    /* prefer TCP over SCTP */
131                unsigned tls_alg: 1;    /* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */
132        }                cnf_flags;
133       
134        struct {
135                /* Credentials parameters (backup) */
136                char *                           cert_file;
137                char *                           key_file;
138               
139                char *                           ca_file;
140                int                              ca_file_nr;
141                char *                           crl_file;
142               
143                char *                           prio_string;
144                unsigned int                     dh_bits;
145                char *                           dh_file;
146               
147                /* GNUTLS parameters */
148                gnutls_priority_t                prio_cache;
149                gnutls_dh_params_t               dh_cache;
150               
151                /* GNUTLS server credential(s) */
152                gnutls_certificate_credentials_t credentials;
153               
154        }                cnf_sec_data;
155       
156        uint32_t         cnf_orstateid; /* The value to use in Origin-State-Id, default to random value */
157        struct dictionary *cnf_dict;    /* pointer to the global dictionary */
158        struct fifo       *cnf_main_ev; /* events for the daemon's main (struct fd_event items) */
159};
160extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */
161
162
163
164/*============================================================*/
165/*                         PEERS                              */
166/*============================================================*/
167
168/* States of a peer */
169enum peer_state {
170        /* Stable states */
171        STATE_NEW = 0,          /* The peer has been just been created, PSM thread not started yet */
172        STATE_OPEN,             /* Connexion established */
173       
174        /* Peer state machine */
175        STATE_CLOSED,           /* No connection established, will re-attempt after TcTimer. */
176        STATE_CLOSING,          /* the connection is being shutdown (DPR/DPA in progress) */
177        STATE_WAITCNXACK,       /* Attempting to establish transport-level connection */
178        STATE_WAITCNXACK_ELEC,  /* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
179        STATE_WAITCEA,          /* Connection established, CER sent, waiting for CEA */
180        /* STATE_WAITRETURNS_ELEC, */   /* This state is not stable and therefore deprecated:
181                                   We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
182                                   If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
183                                   If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
184        STATE_OPEN_HANDSHAKE,   /* TLS Handshake and validation are in progress in open state -- we use it only for debug purpose, it is never displayed */
185       
186        /* Failover state machine */
187        STATE_SUSPECT,          /* A DWR was sent and not answered within TwTime. Failover in progress. */
188        STATE_REOPEN,           /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
189       
190        /* Ordering issues with multistream & state machine. -- see top of p_psm.c for explanation */
191        STATE_OPEN_NEW,         /* after CEA is sent, until a new message is received. Force ordering in this state */
192        STATE_CLOSING_GRACE,    /* after DPA is sent or received, give a short delay for messages in the pipe to be received. */
193       
194        /* Error state */
195        STATE_ZOMBIE            /* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
196#define STATE_MAX STATE_ZOMBIE
197};
198/* The following macro is called in freeDiameter/p_psm.c */
199#define DECLARE_STATE_STR()             \
200const char *peer_state_str[] = {        \
201          "STATE_NEW"                   \
202        , "STATE_OPEN"                  \
203        , "STATE_CLOSED"                \
204        , "STATE_CLOSING"               \
205        , "STATE_WAITCNXACK"            \
206        , "STATE_WAITCNXACK_ELEC"       \
207        , "STATE_WAITCEA"               \
208        , "STATE_OPEN_HANDSHAKE"        \
209        , "STATE_SUSPECT"               \
210        , "STATE_REOPEN"                \
211        , "STATE_OPEN_NEW"              \
212        , "STATE_CLOSING_GRACE"         \
213        , "STATE_ZOMBIE"                \
214        };
215extern const char *peer_state_str[];
216#define STATE_STR(state) \
217        (((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
218
219/* Constants for the peer_info structure bellow */
220#define PI_P3_DEFAULT   0       /* Use any available protocol */
221#define PI_P3_IP        1       /* Use only IP to connect to this peer */
222#define PI_P3_IPv6      2       /* resp, IPv6 */
223
224#define PI_P4_DEFAULT   0       /* Attempt any available protocol */
225#define PI_P4_TCP       1       /* Only use TCP */
226#define PI_P4_SCTP      2       /* Only use SCTP */
227
228#define PI_ALGPREF_SCTP 0       /* SCTP is  attempted first (default) */
229#define PI_ALGPREF_TCP  1       /* TCP is attempted first */
230
231#define PI_SEC_DEFAULT  0       /* New TLS security (handshake after connection, protecting also CER/CEA) */
232#define PI_SEC_NONE     1       /* Transparent security with this peer (IPsec) */
233#define PI_SEC_TLS_OLD  2       /* Old TLS security (use Inband-Security-Id AVP during CER/CEA) */
234                                /* Set sec = 3 to authorize use of (Inband-Security-Id == NONE) with this peer, sec = 2 only authorizing TLS */
235
236#define PI_EXP_NONE     0       /* the peer entry does not expire */
237#define PI_EXP_INACTIVE 1       /* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
238
239#define PI_PRST_NONE    0       /* the peer entry is deleted after disconnection / error */
240#define PI_PRST_ALWAYS  1       /* the peer entry is persistant (will be kept as ZOMBIE in case of error) */
241                       
242/* Information about a remote peer */
243struct peer_info {
244       
245        DiamId_t        pi_diamid;      /* (supposedly) UTF-8, \0 terminated. The Diameter Identity of the remote peer. */
246        size_t          pi_diamidlen;   /* cached length of pi_diamid */
247       
248        struct {
249                struct {
250                        unsigned        pro3 :2;        /* PI_P3_* */
251                        unsigned        pro4 :2;        /* PI_P4_* */
252                        unsigned        alg :1;         /* PI_ALGPREF_* */
253                        unsigned        sec :2;         /* PI_SEC_* */
254                        unsigned        exp :1;         /* PI_EXP_* */
255                        unsigned        persist :1;     /* PI_PRST_* */
256                       
257                }               pic_flags;      /* Flags influencing the connection to the remote peer */
258               
259                DiamId_t        pic_realm;      /* If configured, the daemon will check the received realm in CER/CEA matches this. */
260                uint16_t        pic_port;       /* port to connect to. 0: default. */
261               
262                uint32_t        pic_lft;        /* lifetime of this peer when inactive (see pic_flags.exp definition) */
263                int             pic_tctimer;    /* use this value for TcTimer instead of global, if != 0 */
264                int             pic_twtimer;    /* use this value for TwTimer instead of global, if != 0 */
265               
266                char *          pic_priority;   /* Priority string for GnuTLS if we don't use the default */
267               
268        } config;       /* Configured data (static for this peer entry) */
269       
270        struct {
271               
272                /* enum peer_state      pir_state; */ 
273                /* Since 1.1.0, read the state with fd_peer_getstate(peer). */
274               
275                DiamId_t        pir_realm;      /* The received realm in CER/CEA. */
276                size_t          pir_realmlen;   /* length of the realm */
277               
278                uint32_t        pir_vendorid;   /* Content of the Vendor-Id AVP, or 0 by default */
279                uint32_t        pir_orstate;    /* Origin-State-Id value */
280                os0_t           pir_prodname;   /* copy of Product-Name AVP (\0 terminated) */
281                uint32_t        pir_firmrev;    /* Content of the Firmware-Revision AVP */
282                int             pir_relay;      /* The remote peer advertized the relay application */
283                struct fd_list  pir_apps;       /* applications advertised by the remote peer, except relay (pi_flags.relay) */
284                int             pir_isi;        /* Inband-Security-Id advertised (PI_SEC_* bits) */
285               
286                uint32_t        pir_lastDC;     /* The last Disconnect-Cause value received */
287               
288                int             pir_proto;      /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
289                const gnutls_datum_t    *pir_cert_list;         /* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
290                                                                /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo
291                                                                   see there for example of using this data */
292                unsigned int    pir_cert_list_size;             /* Number of certificates in the list */
293               
294        } runtime;      /* Data populated after connection, may change between 2 connections -- not used by fd_peer_add */
295       
296        struct fd_list  pi_endpoints;   /* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
297};
298
299
300struct peer_hdr {
301        struct fd_list   chain; /* Link into the list of all the peers, ordered by their Diameter Id (fd_os_cmp) */
302        struct peer_info info;  /* The public data */
303       
304        /* This header is followed by more data in the private peer structure definition */
305};
306
307/* the global list of peers.
308  Since we are not expecting so many connections, we don't use a hash, but it might be changed.
309  The list items are peer_hdr structures (actually, fd_peer, but the cast is OK) */
310extern struct fd_list fd_g_peers;
311extern pthread_rwlock_t fd_g_peers_rw; /* protect the list */
312
313/*
314 * FUNCTION:    fd_peer_add
315 *
316 * PARAMETERS:
317 *  info        : Information to create the peer.
318 *  orig_dbg    : A string indicating the origin of the peer information, for debug (ex: conf, redirect, ...)
319 *  cb          : optional, a callback to call (once) when the peer connection is established or failed
320 *  cb_data     : opaque data to pass to the callback.
321 *
322 * DESCRIPTION:
323 *  Add a peer to the list of peers to which the daemon must maintain a connexion.
324 *
325 *  The content of info parameter is copied, except for the list of endpoints if
326 * not empty, which is simply moved into the created object. It means that the list
327 * items must have been malloc'd, so that they can be freed.
328 *
329 *  If cb is not null, the callback is called when the connection is in OPEN state or
330 * when an error has occurred. The callback should use the pi_state information to
331 * determine which one it is. If the first parameter of the called callback is NULL, it
332 * means that the peer is being destroyed before attempt success / failure.
333 * cb is called to allow freeing cb_data in  * this case.
334 *
335 *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
336 *
337 * RETURN VALUE:
338 *  0           : The peer is added.
339 *  EINVAL      : A parameter is invalid.
340 *  EEXIST      : A peer with the same Diameter-Id is already in the list.
341 *  (other standard errors may be returned, too, with their standard meaning. Example:
342 *    ENOMEM    : Memory allocation for the new object element failed.)
343 */
344int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data );
345
346/*
347 * FUNCTION:    fd_peer_getbyid
348 *
349 * PARAMETERS:
350 *  diamid      : an UTF8 string describing the diameter Id of the peer to seek
351 *  diamidlen   : length of the diamid
352 *  igncase     : perform an almost-case-insensitive search? (slower)
353 *  peer        : The peer is stored here if it exists.
354 *
355 * DESCRIPTION:
356 *   Search a peer by its Diameter-Id.
357 *
358 * RETURN VALUE:
359 *  0   : *peer has been updated (to NULL if the peer is not found).
360 * !0   : An error occurred.
361 */
362int fd_peer_getbyid( DiamId_t diamid, size_t diamidlen, int igncase, struct peer_hdr ** peer );
363
364/*
365 * FUNCTION:    fd_peer_get_state
366 *
367 * PARAMETERS:
368 *  peer        : The peer which state to read
369 *
370 * DESCRIPTION:
371 *   Returns the current state of the peer.
372 *
373 * RETURN VALUE:
374 *  -1  : peer is invalid
375 * >=0  : the state of the peer at the time of reading.
376 */
377int fd_peer_get_state(struct peer_hdr *peer);
378
379/*
380 * FUNCTION:    fd_peer_validate_register
381 *
382 * PARAMETERS:
383 *  peer_validate       : Callback as defined bellow.
384 *
385 * DESCRIPTION:
386 *  Add a callback to authorize / reject incoming peer connections.
387 * All registered callbacks are called until a callback sets auth = -1 or auth = 1.
388 * If no callback returns a clear decision, the default behavior is applied (reject unknown connections)
389 * The callbacks are called in FILO order of their registration.
390 *
391 * RETURN VALUE:
392 *  0   : The callback is added.
393 * !0   : An error occurred.
394 */
395int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
396/*
397 * CALLBACK:    peer_validate
398 *
399 * PARAMETERS:
400 *   info     : Structure containing information about the peer attempting the connection.
401 *   auth     : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
402 *   cb2      : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
403 *
404 * DESCRIPTION:
405 *   This callback is called when a new connection is being established from an unknown peer,
406 * after the CER is received. An extension must register such callback with peer_validate_register.
407 *
408 *   The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
409 * It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
410 * The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
411 *
412 *   If the old TLS mechanism is used,
413 * the extension may also need to check the credentials provided during the TLS
414 * exchange (remote certificate). For this purpose, it may set the address of a new callback
415 * to be called once the handshake is completed. This new callback receives the information
416 * structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
417 * or an error code otherwise. If the error code is received, the connection is closed and the
418 * peer is destroyed.
419 * Note that freeDiameter already achieves some usual checks. The callback may be used to enforce
420 * additional restrictions.
421 *
422 * RETURN VALUE:
423 *  0           : The authorization decision has been written in the location pointed by auth.
424 *  !0          : An error occurred.
425 */
426
427
428
429/*============================================================*/
430/*                         MESSAGES                           */
431/*============================================================*/
432
433/*
434 * FUNCTION:    fd_msg_send, fd_msg_send_timeout 
435 *
436 * PARAMETERS:
437 *  pmsg        : Location of the message to be sent on the network (set to NULL on function return to avoid double deletion).
438 *  anscb       : A callback to be called when answer is received, if msg is a request (optional for fd_msg_send)
439 *  anscb_data  : opaque data to be passed back to the anscb when it is called.
440 *  timeout     : (only for fd_msg_send_timeout) sets the absolute time until when to wait for an answer. Past this time,
441 *                the anscb is called with the request as parameter and the answer will be discarded when received.
442 *
443 * DESCRIPTION:
444 *   Sends a message on the network. (actually simply queues it in a global queue, to be picked by a daemon's thread)
445 * For requests, the end-to-end id must be set (see fd_msg_get_eteid / MSGFL_ALLOC_ETEID).
446 * For answers, the message must be created with function fd_msg_new_answ.
447 *
448 * The routing module will handle sending to the correct peer, usually based on the Destination-Realm / Destination-Host AVP.
449 *
450 * If the msg is a request, there are two ways of receiving the answer:
451 *  - either having registered a callback in the dispatch module (see fd_disp_register)
452 *  - or provide a callback as parameter here. If such callback is provided, it is called before the dispatch callbacks.
453 *    The prototype for this callback function is:
454 *     void anscb(void * data, struct msg ** answer)
455 *      where:
456 *              data   : opaque data that was registered along with the callback.
457 *              answer : location of the pointer to the answer.
458 *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
459 *             otherwise, the callback must take care of freeing the message (fd_msg_free).
460 *      note2: the opaque data is not freed by the daemon in any case, extensions should ensure clean handling in fd_ext_fini.
461 *
462 * If no callback is registered to handle an answer, the message is discarded and an error is logged.
463 *
464 *  fd_msg_send_timeout is similar to fd_msg_send, except that it takes an additional argument "timeout" and can be called
465 * only with requests as parameters, and an anscb callback.
466 * If the matching answer or error is received before the timeout date passes, everything occurs as with fd_msg_send. Otherwise,
467 * the request is removed from the queue (meaning the matching answer will be discarded upon reception) and passed to the answcb
468 * function. This function can easily distinguish between timeout case and answer case by checking if the message received is
469 * a request. Upon return, if the *msg parameter is not NULL, it is freed (not passed to other callbacks).
470 *
471 * RETURN VALUE:
472 *  0           : The message has been queued for sending (sending may fail asynchronously).
473 *  EINVAL      : A parameter is invalid (ex: anscb provided but message is not a request).
474 *  ...
475 */
476int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data );
477int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, const struct timespec *timeout );
478
479/*
480 * FUNCTION:    fd_msg_rescode_set
481 *
482 * PARAMETERS:
483 *  msg         : A msg object -- it must be an answer.
484 *  rescode     : The name of the returned error code (ex: "DIAMETER_INVALID_AVP")
485 *  errormsg    : (optional) human-readable error message to put in Error-Message AVP
486 *  optavp      : (optional) If provided, the content will be put inside a Failed-AVP
487 *  type_id     : 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
488 *
489 * DESCRIPTION:
490 *   This function adds a Result-Code AVP to a message, and optionally
491 *  - sets the 'E' error flag in the header,
492 *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
493 *
494 * RETURN VALUE:
495 *  0           : Operation complete.
496 *  !0          : an error occurred.
497 */
498int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id );
499
500/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */
501int fd_msg_add_origin ( struct msg * msg, int osi ); 
502
503/* Generate a new Session-Id and add it at the beginning of the message (opt is added at the end of the sid if provided) */
504int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen );
505
506
507/* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */
508int fd_msg_parse_or_error( struct msg ** msg );
509
510
511
512
513/*============================================================*/
514/*                         DISPATCH                           */
515/*============================================================*/
516
517/*
518 * FUNCTION:    fd_disp_app_support
519 *
520 * PARAMETERS:
521 *  app         : The dictionary object corresponding to the Application.
522 *  vendor      : (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id
523 *  auth        : Support auth app part.
524 *  acct        : Support acct app part.
525 *
526 * DESCRIPTION:
527 *   Registers an application to be advertized in CER/CEA exchanges.
528 *  Messages with an application-id matching a registered value are passed to the dispatch module,
529 * while other messages are simply relayed or an error is returned (if local node does not relay)
530 *
531 * RETURN VALUE:
532 *  0           : The application support is registered.
533 *  EINVAL      : A parameter is invalid.
534 */
535int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct );
536
537/* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */
538
539
540/*============================================================*/
541/*                         ROUTING                            */
542/*============================================================*/
543
544/* This file contains the definitions of types and functions involved in the routing decisions in freeDiameter,
545 * and that can be called by extensions.
546 *
547 * Three different type of messages must be distinguished:
548 *  - Messages received, and the peer is final recipient (IN messages)
549 *  - Messages received, and the peer is not final recipient (FWD messages)
550 *  - Message is locally generated (OUT messages)
551 *
552 * There are three global message queues (in queues.c) and also peers-specific queues (in struct fd_peer).
553 *
554 * (*) IN messages processing details:
555 *   - the message is received from the remote peer, a FDEVP_CNX_MSG_RECV event is generated for the peer.
556 *   - the PSM thread parses the buffer, does some verifications, handles non routable messages (fd_msg_is_routable)
557 *   - routable messages are queued in the fd_g_incoming global queue.
558 *   - a thread (routing-in) picks the message and takes the decision if it is handled locally or forwarded,
559 *       based on local capabilities (registered by extensions with fd_disp_app_support).
560 *   - If the message is handled locally, it is queued in fd_g_local.
561 *   - Another thread (dispatch.c) will handle this message and pass it to registered callbacks (see fd_disp_register in libfreeDiameter.h).
562 *
563 * (*) FWD messages details:
564 *   - The process is the same as for IN messages, until the routing-in threads makes its decision that the message is not handled locally.
565 *   - If the local peer does not relay message, an error DIAMETER_APPLICATION_UNSUPPORTED is returned.
566 *   - All callbacks registered with fd_rt_fwd_register are called for the message (see bellow).
567 *     - these callbacks will typically do proxying work. Note that adding the route-record is handled by the daemon.
568 *   - Once all callbacks have been called, the message is queued in the global fd_g_outgoing queue.
569 *   - The remaining processing is the same as for OUT messages, as described bellow.
570 *
571 * (*) OUT messages details:
572 *   - The message are picked from fd_g_outgoing (they are queued there as result of forwarding process or call to fd_msg_send.)
573 *   - The (routing-out) thread builds a list of possible destinations for the message, as follow:
574 *      - create a list of all known peers in the "OPEN" state.
575 *      - remove from that list all peers that are in a Route-Record AVP of the message, to avoid routing loops.
576 *      - remove also all peers that have previously replied an error message for this message.
577 *   - If the list is empty, create an error UNABLE_TO_DELIVER (note: should we trig dynamic discovery here???) and reply.
578 *   - Otherwise, call all callbacks registered by function fd_rt_out_register, with the list of peers and the message.
579 *   - Order the resulting list of peers by score (see bellow), and sent the message to the peer with highest (positive) score.
580 *    - in case the peer is no longer in the "OPEN" state, send the message to the second peer in the list.
581 *      - if no peer is in OPEN state anymore, restart the process of creating the list.
582 *   - Once a peer has been selected, the message is queued into that peer's outgoing queue.
583 *
584 * The following functions allow an extension to register or remove a callback as described above.
585 */
586
587/********** Forwarding callbacks: for Proxy operations ***********/
588
589/* Handle to registered callback */
590struct fd_rt_fwd_hdl;
591
592/* Message direction for the callback */
593enum fd_rt_fwd_dir {
594        RT_FWD_REQ = 1, /* The callback will be called on forwarded requests only */
595        RT_FWD_ALL = 2, /* The callback will be called on all forwarded messages (requests and answers )*/
596        RT_FWD_ANS = 3  /* The callback will be called on answers and errors only */
597};     
598
599/*
600 * FUNCTION:    fd_rt_fwd_register
601 *
602 * PARAMETERS:
603 *  rt_fwd_cb     : The callback function to register (see prototype bellow).
604 *  cbdata        : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
605 *  dir           : One of the RT_FWD_* directions defined above.
606 *  handler       : On success, a handler to the registered callback is stored here.
607 *                 This handler will be used to unregister the cb.
608 *
609 * DESCRIPTION:
610 *   Register a new callback for forwarded messages. See explanations above.
611 * Note that there is no guaranteed order for the callbacks calls.
612 *
613 * RETURN VALUE:
614 *  0           : The callback is registered.
615 *  EINVAL      : A parameter is invalid.
616 *  ENOMEM      : Not enough memory to complete the operation
617 */
618int fd_rt_fwd_register ( int (*rt_fwd_cb)(void * cbdata, struct msg ** msg), void * cbdata, enum fd_rt_fwd_dir dir, struct fd_rt_fwd_hdl ** handler );
619/*
620 * CALLBACK:    rt_fwd_cb
621 *
622 * PARAMETERS:
623 *  data        : pointer to some data that was passed when the callback was registered (optional).
624 *  msg         : The message that is being forwarded.
625 *
626 * DESCRIPTION:
627 *   This callback is called when a message is forwarded to another peer. It may for example add a Proxy-Info AVP.
628 *  The callback may also choose to handle the message in a more complex form. In that case, it must set *msg = NULL
629 *  and handle it differently. In such case, the forwarding thread will stop processing this message.
630 *
631 * RETURN VALUE:
632 *  0           : Operation complete.
633 *  !0          : An error occurred -- will result in daemon's termination.
634 */
635
636/*
637 * FUNCTION:    fd_rt_fwd_unregister
638 *
639 * PARAMETERS:
640 *  handler     : The handler of the callback that must be unregistered.
641 *  cbdata      : Will receive the data registered with the callback, that can be freed if needed.
642 *
643 * DESCRIPTION:
644 *   Removes a callback from the list of registered callbacks.
645 *
646 * RETURN VALUE:
647 *  0           : The callback is unregistered.
648 *  EINVAL      : A parameter is invalid.
649 */
650int fd_rt_fwd_unregister ( struct fd_rt_fwd_hdl * handler, void ** cbdata );
651
652
653/********** Out callbacks: for next hop routing decision operations ***********/
654
655/* Handle to registered callback */
656struct fd_rt_out_hdl;
657
658enum fd_rt_out_score {
659        FD_SCORE_NO_DELIVERY     = -70, /* We should not send this message to this candidate */
660        FD_SCORE_INI             =  -2, /* All candidates are initialized with this value */
661        FD_SCORE_LOAD_BALANCE    =   1, /* Use this to differentiate between several peers with the same score */
662        FD_SCORE_DEFAULT         =   5, /* The peer is a default route for all messages */
663        FD_SCORE_DEFAULT_REALM   =  10, /* The peer is a default route for this realm */
664        FD_SCORE_REALM           =  15, /* The peer belongs to Destination-Realm of the message */
665        FD_SCORE_REDIR_HOST      =  25, /* If there is a redirect rule with ALL_HOST for these message and peer */
666        FD_SCORE_REDIR_APP       =  30, /* If there is a redirect rule with ALL_APPLICATION for these message and peer */
667        FD_SCORE_REDIR_REALM     =  35, /* If there is a redirect rule with ALL_REALM for these message and peer */
668        FD_SCORE_REDIR_REALM_APP =  40, /* If there is a redirect rule with REALM_AND_APPLICATION for these message and peer */
669        FD_SCORE_REDIR_USER      =  45, /* If there is a redirect rule with ALL_USER for these message and peer */
670        FD_SCORE_REDIR_SESSION   =  50, /* If there is a redirect rule with ALL_SESSION for these message and peer */
671        FD_SCORE_FINALDEST       = 100  /* If the peer is the final recipient of the message (i.e. matching Destination-Host), it receives a big score. */
672};
673
674/*
675 * FUNCTION:    fd_rt_out_register
676 *
677 * PARAMETERS:
678 *  rt_out_cb     : The callback function to register (see prototype bellow).
679 *  cbdata        : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
680 *  priority      : Order for calling this callback. The callbacks are called in reverse priority order (higher priority = called sooner).
681 *  handler       : On success, a handler to the registered callback is stored here.
682 *                 This handler will be used to unregister the cb.
683 *
684 * DESCRIPTION:
685 *   Register a new callback to handle OUT routing decisions. See explanations above.
686 *
687 * RETURN VALUE:
688 *  0           : The callback is registered.
689 *  EINVAL      : A parameter is invalid.
690 *  ENOMEM      : Not enough memory to complete the operation
691 */
692int fd_rt_out_register ( int (*rt_out_cb)(void * cbdata, struct msg * msg, struct fd_list * candidates), void * cbdata, int priority, struct fd_rt_out_hdl ** handler );
693/*
694 * CALLBACK:    rt_out_cb
695 *
696 * PARAMETERS:
697 *  cbdata      : pointer to some data that was registered with the callback.
698 *  msg         : The message that must be sent.
699 *  list        : The list of peers to which the message may be sent to, as returned by fd_rtd_candidate_extract
700 *
701 * DESCRIPTION:
702 *   This callback must attribute a score (preferably from FD_SCORE_*) to each candidate peer in the list.
703 *  Once all registered callbacks have been called, the message is sent to the candidate with the highest score.
704 *  Note that each callback must *add* its locally-attributed score to the candidate current "score" parameter, not replace it!
705 *  Note also that this callback must be re-entrant since it may be called by several threads at the same time
706 *  (for different messages)
707 *
708 * RETURN VALUE:
709 *  0           : Operation complete.
710 *  !0          : An error occurred.
711 */
712
713/*
714 * FUNCTION:    fd_rt_out_unregister
715 *
716 * PARAMETERS:
717 *  handler     : The handler of the callback that must be unregistered.
718 *  cbdata      : Will receive the data registered with the callback, that can be freed if needed.
719 *
720 * DESCRIPTION:
721 *   Removes a callback from the list of registered callbacks.
722 *
723 * RETURN VALUE:
724 *  0           : The callback is unregistered.
725 *  EINVAL      : A parameter is invalid.
726 */
727int fd_rt_out_unregister ( struct fd_rt_out_hdl * handler, void ** cbdata );
728
729
730/*============================================================*/
731/*                         EVENTS                             */
732/*============================================================*/
733
734struct fd_event {
735        int      code; /* codespace depends on the queue */
736        size_t   size;
737        void    *data;
738};
739
740/* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
741enum {
742         FDEV_TERMINATE = 1000  /* request to terminate */
743        ,FDEV_DUMP_DICT         /* Dump the content of the dictionary */
744        ,FDEV_DUMP_EXT          /* Dump state of extensions */
745        ,FDEV_DUMP_SERV         /* Dump the server socket status */
746        ,FDEV_DUMP_QUEUES       /* Dump the message queues */
747        ,FDEV_DUMP_CONFIG       /* Dump the configuration */
748        ,FDEV_DUMP_PEERS        /* Dump the list of peers */
749        ,FDEV_TRIGGER           /* Trigger available for extensions. size is sizeof(int), data is int * */
750};
751
752int fd_event_send(struct fifo *queue, int code, size_t datasz, void * data);
753int fd_event_get(struct fifo *queue, int * code, size_t * datasz, void ** data);
754int fd_event_timedget(struct fifo *queue, struct timespec * timeout, int timeoutcode, int * code, size_t * datasz, void ** data);
755void fd_event_destroy(struct fifo **queue, void (*free_cb)(void * data));
756const char * fd_ev_str(int event);
757
758/* for extensions */
759int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
760void fd_event_trig_dump();
761
762
763/*============================================================*/
764/*                         ENDPOINTS                          */
765/*============================================================*/
766
767struct fd_endpoint {
768        struct fd_list  chain;  /* link in cnf_endpoints list */
769       
770        union {
771                sSS             ss;     /* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
772                sSA4            sin;
773                sSA6            sin6;
774                sSA             sa;
775        }
776#ifdef SWIG /* nested anonymous unions are not supported yet */
777                        s
778#endif /* SWIG */
779        ;
780       
781#define EP_FL_CONF      (1 << 0)        /* This endpoint is statically configured in a configuration file */
782#define EP_FL_DISC      (1 << 1)        /* This endpoint was resolved from the Diameter Identity or other DNS query */
783#define EP_FL_ADV       (1 << 2)        /* This endpoint was advertized in Diameter CER/CEA exchange */
784#define EP_FL_LL        (1 << 3)        /* Lower layer mechanism provided this endpoint */
785#define EP_FL_PRIMARY   (1 << 4)        /* This endpoint is primary in a multihomed SCTP association */
786#define EP_ACCEPTALL    (1 << 15)       /* This flag allows bypassing the address filter in fd_ep_add_merge. */
787        uint32_t        flags;          /* Additional information about the endpoint */
788               
789        /* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
790};
791
792int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
793int fd_ep_filter( struct fd_list * list, uint32_t flags );
794int fd_ep_filter_family( struct fd_list * list, int af );
795int fd_ep_filter_list( struct fd_list * list, struct fd_list * exclude_list );
796int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
797void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep, char * suffix );
798void fd_ep_dump( int indent, struct fd_list * eps );
799
800
801/*============================================================*/
802/*                         APPLICATIONS IDs                   */
803/*============================================================*/
804
805struct fd_app {
806        struct fd_list   chain; /* link in cnf_apps list. List ordered by appid. */
807        struct {
808                unsigned auth   : 1;
809                unsigned acct   : 1;
810        }                flags;
811        vendor_id_t      vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */
812        application_id_t appid; /* The identifier of the application */
813};
814       
815int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
816int fd_app_check(struct fd_list * list, application_id_t aid, struct fd_app **detail);
817int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
818int fd_app_empty(struct fd_list * list);
819
820#endif /* _LIBFDCORE_H */
Note: See TracBrowser for help on using the repository browser.