Commit ff977f36 authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Added a large part of connection establishment logic, to test

parent e1309f9d
......@@ -9,6 +9,7 @@ SET_SOURCE_FILES_PROPERTIES(lex.fdd.c fdd.tab.c PROPERTIES COMPILE_FLAGS "-I ${C
# List of source files
SET(FD_COMMON_SRC
fD.h
apps.c
cnxctx.h
config.c
cnxctx.c
......
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@nict.go.jp> *
* *
* Copyright (c) 2009, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification, are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* * Neither the name of the WIDE Project or NICT nor the *
* names of its contributors may be used to endorse or *
* promote products derived from this software without *
* specific prior written permission of WIDE Project and *
* NICT. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
#include "fD.h"
/* Merge information into a list of apps */
int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct)
{
struct fd_list * li;
int skip = 0;
/* List is ordered by appid. Avoid duplicates */
for (li = list; li->next != list; li = li->next) {
struct fd_app * na = (struct fd_app *)(li->next);
if (na->appid < aid)
continue;
if (na->appid > aid)
break;
/* Otherwise, we merge with existing entry -- ignore vendor id in this case */
skip = 1;
if (auth)
na->flags.auth = 1;
if (acct)
na->flags.acct = 1;
break;
}
if (!skip) {
struct fd_app * new = NULL;
CHECK_MALLOC( new = malloc(sizeof(struct fd_app)) );
memset(new, 0, sizeof(struct fd_app));
fd_list_init(&new->chain, NULL);
new->flags.auth = (auth ? 1 : 0);
new->flags.acct = (acct ? 1 : 0);
new->vndid = vid;
new->appid = aid;
fd_list_insert_after(li, &new->chain);
}
return 0;
}
/* Tag any common application between target and reference (into target) */
int fd_app_find_common(struct fd_list * target, struct fd_list * reference)
{
}
/* Return true if at least one app was tagged common, false otherwise */
int fd_app_gotcommon(struct fd_list * apps)
{
}
......@@ -996,7 +996,7 @@ int fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo)
CHECK_PARAMS( conn && alt_fifo && conn->cc_incoming );
/* The magic function does it all */
CHECK_FCT( fd_fifo_move( &conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
CHECK_FCT( fd_fifo_move( conn->cc_incoming, alt_fifo, &conn->cc_alt ) );
return 0;
}
......@@ -1113,6 +1113,9 @@ void fd_cnx_destroy(struct cnxctx * conn)
TRACE_ENTRY("%p", conn);
CHECK_PARAMS_DO(conn, return);
/* Avoid sending further events to the alt fifo */
conn->cc_alt = NULL;
/* In case of TLS, stop receiver thread, then close properly the gnutls session */
if ((conn->cc_tls) && (conn->cc_sctp_para.pairs > 1)) {
......
......@@ -210,6 +210,9 @@ int fd_dict_base_protocol(struct dictionary * dict)
/* relay application */
{
struct dict_application_data data = { 0xffffffff, "Relay" };
#if AI_RELAY != 0xffffffff
#error "AI_RELAY definition mismatch"
#endif
CHECK_dict_new( DICT_APPLICATION, &data , NULL, NULL);
}
}
......@@ -906,8 +909,8 @@ int fd_dict_base_protocol(struct dictionary * dict)
struct dict_object * type;
struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated*(Inband-Security-Id)" , NULL, NULL};
struct dict_enumval_data t_0 = { "NO_INBAND_SECURITY", { .u32 = 0 }};
struct dict_enumval_data t_1 = { "TLS", { .u32 = 1 }};
struct dict_enumval_data t_0 = { "NO_INBAND_SECURITY", { .u32 = ACV_ISI_NO_INBAND_SECURITY }};
struct dict_enumval_data t_1 = { "TLS", { .u32 = ACV_ISI_TLS }};
struct dict_avp_data data = {
299, /* Code */
#if AC_INBAND_SECURITY_ID != 299
......
......@@ -35,12 +35,11 @@
#include "fD.h"
/* Add an application into the peer's supported apps */
int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct )
{
vendor_id_t vid = 0;
application_id_t aid = 0;
struct fd_list * li;
int skip = 0;
vendor_id_t vid = 0;
TRACE_ENTRY("%p %p %d %d", app, vendor, auth, acct);
CHECK_PARAMS( app && (auth || acct) );
......@@ -53,48 +52,15 @@ int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor,
CHECK_FCT( fd_dict_getval(app, &data) );
aid = data.application_id;
}
/* Now insert in the list ordered by appid. Avoid duplicates */
for (li = &fd_g_config->cnf_apps; li->next != &fd_g_config->cnf_apps; li = li->next) {
struct fd_app * na = (struct fd_app *)(li->next);
if (na->appid < aid)
continue;
if (na->appid > aid)
break;
/* Otherwise, we merge with existing entry -- ignore vendor id in this case */
skip = 1;
if (auth)
na->flags.auth = 1;
if (acct)
na->flags.acct = 1;
break;
}
if (!skip) {
struct fd_app * new = NULL;
if (vendor) {
enum dict_object_type type = 0;
struct dict_vendor_data data;
CHECK_FCT( fd_dict_gettype(vendor, &type) );
CHECK_PARAMS( type == DICT_VENDOR );
CHECK_FCT( fd_dict_getval(vendor, &data) );
vid = data.vendor_id;
}
CHECK_MALLOC( new = malloc(sizeof(struct fd_app)) );
memset(new, 0, sizeof(struct fd_app));
fd_list_init(&new->chain, NULL);
new->flags.auth = (auth ? 1 : 0);
new->flags.acct = (acct ? 1 : 0);
new->vndid = vid;
new->appid = aid;
fd_list_insert_after(li, &new->chain);
if (vendor) {
enum dict_object_type type = 0;
struct dict_vendor_data data;
CHECK_FCT( fd_dict_gettype(vendor, &type) );
CHECK_PARAMS( type == DICT_VENDOR );
CHECK_FCT( fd_dict_getval(vendor, &data) );
vid = data.vendor_id;
}
return 0;
return fd_app_merge(&fd_g_config->cnf_apps, aid, vid, auth, acct);
}
......@@ -125,6 +125,11 @@ int fd_ep_clearflags( struct fd_list * list, uint32_t flags )
for (li = list->next; li != list; li = li->next) {
struct fd_endpoint * ep = (struct fd_endpoint *)li;
ep->flags &= ~flags;
if (ep->flags == 0) {
li = li->prev;
fd_list_unlink(&ep->chain);
free(ep);
}
}
return 0;
......
......@@ -66,6 +66,13 @@
#define DPR_TIMEOUT 15 /* in seconds */
#endif /* DPR_TIMEOUT */
/* The Vendor-Id to advertise in CER/CEA */
#ifndef MY_VENDOR_ID
#define MY_VENDOR_ID 0 /* Reserved value to tell it must be ignored */
#endif /* MY_VENDOR_ID */
/* Configuration */
int fd_conf_init();
void fd_conf_dump();
......@@ -144,9 +151,10 @@ struct fd_peer { /* The "real" definition of the peer structure */
/* Data for transitional states before the peer is in OPEN state */
struct {
struct cnxctx * p_initiator; /* Connection before CEA is received */
struct cnxctx * p_receiver; /* Only used in case of election */
pthread_t p_ini_thr;
struct msg * p_cer; /* Only used in case of election */
pthread_t p_ini_thr; /* Initiator thread for establishing a connection */
struct fd_list p_connparams; /* The list of connection attempts, see p_cnx.c */
};
......@@ -264,9 +272,11 @@ void fd_p_sr_failover(struct sr_list * srlist);
int fd_p_ce_msgrcv(struct msg ** msg, int req, struct fd_peer * peer);
int fd_p_ce_handle_newCER(struct msg ** msg, struct fd_peer * peer, struct cnxctx ** cnx, int valid);
int fd_p_ce_handle_newcnx(struct fd_peer * peer, struct cnxctx * initiator);
int fd_p_ce_winelection(struct fd_peer * peer);
int fd_p_ce_process_receiver(struct fd_peer * peer);
void fd_p_ce_clear_cnx(struct fd_peer * peer, struct cnxctx ** cnx_kept);
int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer);
int fd_p_dw_timeout(struct fd_peer * peer);
int fd_p_dw_reopen(struct fd_peer * peer);
int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer);
int fd_p_dp_initiate(struct fd_peer * peer);
......
This diff is collapsed.
......@@ -245,6 +245,9 @@ static void * connect_thr(void * arg)
fd_ep_filter(&peer->p_hdr.info.pi_endpoints, EP_FL_CONF);
return NULL;
} );
} else {
/* Prepare to receive the next message */
CHECK_FCT_DO( fd_cnx_start_clear(cnx, 0), goto fatal_error );
}
/* Upon success, generate FDEVP_CNX_ESTABLISHED */
......
......@@ -53,4 +53,13 @@ int fd_p_dw_timeout(struct fd_peer * peer)
return ENOTSUP;
}
/* Handle DW exchanges after the peer has come alive again */
int fd_p_dw_reopen(struct fd_peer * peer)
{
TODO("...");
return ENOTSUP;
}
......@@ -249,15 +249,7 @@ void fd_psm_cleanup(struct fd_peer * peer, int terminate)
fd_p_cnx_abort(peer, terminate);
if (peer->p_cnxctx) {
fd_cnx_destroy(peer->p_cnxctx);
peer->p_cnxctx = NULL;
}
if (peer->p_initiator) {
fd_cnx_destroy(peer->p_initiator);
peer->p_initiator = NULL;
}
fd_p_ce_clear_cnx(peer, NULL);
if (peer->p_receiver) {
fd_cnx_destroy(peer->p_receiver);
......@@ -593,7 +585,7 @@ psm_loop:
if (event == FDEVP_CNX_ESTABLISHED) {
struct cnxctx * cnx = ev_data;
/* Release the resources of the thread */
/* Release the resources of the connecting thread */
CHECK_POSIX_DO( pthread_join( peer->p_ini_thr, NULL), /* ignore, it is not a big deal */);
peer->p_ini_thr = (pthread_t)NULL;
......@@ -641,7 +633,7 @@ psm_loop:
fd_p_cnx_abort(peer, 0);
/* Handle receiver side */
CHECK_FCT_DO( fd_p_ce_winelection(peer), goto psm_end );
CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end );
break;
}
}
......
......@@ -335,6 +335,7 @@ struct peer_info {
uint32_t pir_firmrev; /* Content of the Firmware-Revision AVP */
int pir_relay; /* The remote peer advertized the relay application */
struct fd_list pir_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */
int pir_isi; /* Inband-Security-Id advertised (PI_SEC_* bits) */
int pir_proto; /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */
const gnutls_datum_t *pir_cert_list; /* The (valid) credentials that the peer has presented, or NULL if TLS is not used */
......@@ -422,14 +423,15 @@ int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info
* This callback is called when a new connection is being established from an unknown peer,
* after the CER is received. An extension must register such callback with peer_validate_register.
*
* If (info->pi_flags.sec == PI_SEC_TLS_OLD) the extension may instruct the daemon explicitely
* to not use TLS by clearing info->pi_flags.inband_tls -- only if inband_none is set.
* The callback can learn if the peer has sent Inband-Security-Id AVPs in runtime.pir_isi fields.
* It can also learn if a handshake has already been performed in runtime.pir_cert_list field.
* The callback must set the value of config.pic_flags.sec appropriately to allow a connection without TLS.
*
* If (info->pi_flags.sec == PI_SEC_TLS_OLD) and info->pi_flags.inband_tls is set,
* If the old TLS mechanism is used,
* the extension may also need to check the credentials provided during the TLS
* exchange (remote certificate). For this purpose, it may set the address of a new callback
* to be called once the handshake is completed. This new callback receives the information
* structure as parameter (with pi_sec_data set) and returns 0 if the credentials are correct,
* structure as parameter (with pir_cert_list set) and returns 0 if the credentials are correct,
* or an error code otherwise. If the error code is received, the connection is closed and the
* peer is destroyed.
*
......@@ -544,4 +546,12 @@ int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep, char * suffix );
void fd_ep_dump( int indent, struct fd_list * eps );
/***************************************/
/* Applications lists helpers */
/***************************************/
int fd_app_merge(struct fd_list * list, application_id_t aid, vendor_id_t vid, int auth, int acct);
int fd_app_find_common(struct fd_list * target, struct fd_list * reference);
int fd_app_gotcommon(struct fd_list * apps);
#endif /* _FREEDIAMETER_H */
......@@ -717,8 +717,10 @@ be freed automatically along with the object itself with call to dict_fini later
printf("my vendor id: %d\n", myvendordata.vendor_id );
}
*/
/* Special function: */
uint32_t * fd_dict_get_vendorid_list(struct dictionary * dict);
/*
***************************************************************************
......@@ -1328,6 +1330,9 @@ The "parent" parameter can not be NULL. It points to the object (grouped avp or
*/
/* Define some hard-coded values */
/* Application */
#define AI_RELAY 0xffffffff
/* Commands Codes */
#define CC_CAPABILITIES_EXCHANGE 257
#define CC_RE_AUTH 258
......@@ -1368,6 +1373,8 @@ The "parent" parameter can not be NULL. It points to the object (grouped avp or
#define AC_ERROR_REPORTING_HOST 294
#define AC_ORIGIN_REALM 296
#define AC_INBAND_SECURITY_ID 299
#define ACV_ISI_NO_INBAND_SECURITY 0
#define ACV_ISI_TLS 1
/* Error codes */
#define ER_DIAMETER_SUCCESS 2001
......@@ -2425,18 +2432,18 @@ int fd_fifo_del ( struct fifo ** queue );
* FUNCTION: fd_fifo_move
*
* PARAMETERS:
* old : Location of a FIFO that is to be emptied and deleted.
* old : Location of a FIFO that is to be emptied.
* new : A FIFO that will receive the old data.
* loc_update : if non NULL, a place to store the pointer to new FIFO atomically with the move.
*
* DESCRIPTION:
* Delete a queue and move its content to another one atomically.
* Empties a queue and move its content to another one atomically.
*
* RETURN VALUE:
* 0 : The queue has been destroyed successfully.
* EINVAL : A parameter is invalid.
*/
int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update );
int fd_fifo_move ( struct fifo * old, struct fifo * new, struct fifo ** loc_update );
/*
* FUNCTION: fd_fifo_length
......
......@@ -1528,7 +1528,7 @@ int fd_dict_init ( struct dictionary ** dict)
new->dict_vendors.list[0].o = NULL; /* overwrite since element is also sentinel for this list. */
/* Initialize the sentinel for applciations */
/* Initialize the sentinel for applications */
init_object( &new->dict_applications, DICT_APPLICATION );
new->dict_applications.data.application.application_name = "Diameter Common Messages";
new->dict_applications.list[0].o = NULL; /* overwrite since since element is also sentinel for this list. */
......
......@@ -182,55 +182,52 @@ int fd_fifo_del ( struct fifo ** queue )
return 0;
}
/* Move the content of old into new, and update loc_update atomically */
int fd_fifo_move ( struct fifo ** old, struct fifo * new, struct fifo ** loc_update )
/* Move the content of old into new, and update loc_update atomically. We leave the old queue empty but valid */
int fd_fifo_move ( struct fifo * old, struct fifo * new, struct fifo ** loc_update )
{
struct fifo * q;
int loops = 0;
TRACE_ENTRY("%p %p %p", old, new, loc_update);
CHECK_PARAMS( old && CHECK_FIFO( *old ) && CHECK_FIFO( new ));
CHECK_PARAMS( CHECK_FIFO( old ) && CHECK_FIFO( new ));
q = *old;
CHECK_PARAMS( ! q->data );
CHECK_PARAMS( ! old->data );
if (new->high) {
TODO("Implement support for thresholds in fd_fifo_move...");
}
/* Update loc_update */
*old = NULL;
if (loc_update)
*loc_update = new;
/* Lock the queues */
CHECK_POSIX( pthread_mutex_lock( &q->mtx ) );
CHECK_POSIX( pthread_mutex_lock( &old->mtx ) );
CHECK_POSIX( pthread_mutex_lock( &new->mtx ) );
/* Any waiting thread on the old queue returns an error */
q->eyec = 0xdead;
while (q->thrs) {
CHECK_POSIX( pthread_cond_signal(&q->cond) );
CHECK_POSIX( pthread_mutex_unlock( &q->mtx ));
old->eyec = 0xdead;
while (old->thrs) {
CHECK_POSIX( pthread_cond_signal(&old->cond) );
CHECK_POSIX( pthread_mutex_unlock( &old->mtx ));
pthread_yield();
CHECK_POSIX( pthread_mutex_lock( &q->mtx ) );
CHECK_POSIX( pthread_mutex_lock( &old->mtx ) );
ASSERT( ++loops < 10 ); /* detect infinite loops */
}
/* Move all data from old to new */
fd_list_move_end( &new->list, &q->list );
if (q->count && (!new->count)) {
fd_list_move_end( &new->list, &old->list );
if (old->count && (!new->count)) {
CHECK_POSIX( pthread_cond_signal(&new->cond) );
}
new->count += q->count;
new->count += old->count;
/* Destroy old */
CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) );
CHECK_POSIX( pthread_cond_destroy( &q->cond ) );
CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) );
free(q);
/* Reset old */
old->count = 0;
old->eyec = FIFO_EYEC;
/* Unlock new, we're done */
/* Unlock, we're done */
CHECK_POSIX( pthread_mutex_unlock( &new->mtx ) );
CHECK_POSIX( pthread_mutex_unlock( &old->mtx ) );
return 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment