view libfdcore/hooks.c @ 1481:c9e9f8a71946

Update to 3GPP TS 32.299 V15.7.0 (2019-06) Add AVPs: - 3GPP-OC-Rating-Group, Unsigned32, code 1321 - 3GPP-OC-Request-Type, Enumerated, code 1322 - 3GPP-OC-Specific-Reduction, Grouped, code 1320 - 3GPP-PS-Data-Off-Status-32.299, Enumerated, code 4406 - API-Content, UTF8String, code 1309 - API-Direction, Enumerated, code 1310 - API-Identifier, OctetString, code 1311 - API-Invocation-Timestamp, Time, code 1312 - API-Network-Service-Node, Enumerated, code 1315 - API-Result-Code, Unsigned32, code 1313 - API-Size, Unsigned64, code 1314 - APN-Rate-Control, Grouped, code 3933 - APN-Rate-Control-Downlink, Grouped, code 3934 - APN-Rate-Control-Uplink, Grouped, code 3935 - Access-Network-Info-Change, Grouped, code 4401 - Additional-Exception-Reports, Enumerated, code 3936 - Announcement-Identifier, Unsigned32, code 3905 - Announcement-Information, Grouped, code 3904 - Announcement-Order, Unsigned32, code 3906 - Announcing-PLMN-ID, UTF8String, code 4408 - Announcing-UE-HPLMN-Identifier, UTF8String, code 3426 - Announcing-UE-VPLMN-Identifier, UTF8String, code 3427 - Application-Specific-Data, OctetString, code 3458 - Authorised-QoS, UTF8String, code 849 - BSSID, UTF8String, code 2716 - Basic-Service-Code, Grouped, code 3411 - Bearer-Capability, OctetString, code 3412 - CN-Operator-Selection-Entity, Enumerated, code 3421 - CP-CIoT-EPS-Optimisation-Indicator, Enumerated, code 3930 - CPDT-Information, Grouped, code 3927 - Called-Identity, UTF8String, code 3916 - Called-Identity-Change, Grouped, code 3917 - Cellular-Network-Information, OctetString, code 3924 - Charging-Per-IP-CAN-Session-Indicator, Enumerated, code 4400 - Civic-Address-Information, UTF8String, code 1305 - Coverage-Info, Grouped, code 3459 - Coverage-Status, Enumerated, code 3428 - Discoveree-UE-HPLMN-Identifier, UTF8String, code 4402 - Discoveree-UE-VPLMN-Identifier, UTF8String, code 4403 - Discoverer-UE-HPLMN-Identifier, UTF8String, code 4404 - Discoverer-UE-VPLMN-Identifier, UTF8String, code 4405 - EPDG-Address, Address, code 3425 - Enhanced-Diagnostics, Grouped, code 3901 - Exposure-Function-API-Information, Grouped, code 1316 - FE-Identifier-List, UTF8String, code 4413 - Forwarding-Pending, Enumerated, code 3415 - IMS-Visited-Network-Identifier, UTF8String, code 2713 - ISUP-Cause, Grouped, code 3416 - ISUP-Cause-Diagnostics, OctetString, code 3422 - ISUP-Cause-Location, Unsigned32, code 3423 - ISUP-Cause-Value, Unsigned32, code 3424 - ISUP-Location-Number, OctetString, code 3414 - Instance-Id, UTF8String, code 3402 - Inter-UE-Transfer, Enumerated, code 3902 - Language, UTF8String, code 3914 - Layer-2-Group-ID, OctetString, code 3429 - Location-Info, Grouped, code 3460 - MBMS-Charged-Party, Enumerated, code 2323 - MSC-Address, OctetString, code 3417 - MTC-IWF-Address, Address, code 3406 - Monitored-PLMN-Identifier, UTF8String, code 3430 - Monitoring-Event-Configuration-Activity, Integer32, code 3919 - Monitoring-Event-Functionality, Integer32, code 3922 - Monitoring-Event-Information, Grouped, code 3921 - Monitoring-Event-Report-Data, Grouped, code 3920 - Monitoring-Event-Report-Number, Unsigned32, code 3923 - Monitoring-UE-HPLMN-Identifier, UTF8String, code 3431 - Monitoring-UE-Identifier, UTF8String, code 3432 - Monitoring-UE-VPLMN-Identifier, UTF8String, code 3433 - NIDD-Submission, Grouped, code 3928 - Network-Call-Reference-Number, OctetString, code 3418 - PC3-Control-Protocol-Cause, Integer32, code 3434 - PC3-EPC-Control-Protocol-Cause, Integer32, code 3435 - PC5-Radio-Technology, Enumerated, code 1300 - Play-Alternative, Enumerated, code 3913 - Privacy-Indicator, Enumerated, code 3915 - ProSe-3rd-Party-Application-ID, UTF8String, code 3440 - ProSe-Direct-Communication-Reception-Data-Container, Grouped, code 3461 - ProSe-Direct-Communication-Transmission-Data-Container, Grouped, code 3441 - ProSe-Direct-Discovery-Model, Enumerated, code 3442 - ProSe-Event-Type, Enumerated, code 3443 - ProSe-Function-IP-Address, Address, code 3444 - ProSe-Function-PLMN-Identifier, UTF8String, code 3457 - ProSe-Functionality, Enumerated, code 3445 - ProSe-Group-IP-Multicast-Address, Address, code 3446 - ProSe-Information, Grouped, code 3447 - ProSe-Range-Class, Enumerated, code 3448 - ProSe-Reason-For-Cancellation, Enumerated, code 3449 - ProSe-Request-Timestamp, Time, code 3450 - ProSe-Role-Of-UE, Enumerated, code 3451 - ProSe-Source-IP-Address, Address, code 3452 - ProSe-Target-Layer-2-ID, OctetString, code 4410 - ProSe-UE-ID, OctetString, code 3453 - ProSe-UE-to-Network-Relay-UE-ID, OctetString, code 4409 - Proximity-Alert-Indication, Enumerated, code 3454 - Proximity-Alert-Timestamp, Time, code 3455 - Proximity-Cancellation-Timestamp, Time, code 3456 - Quota-Indicator, Enumerated, code 3912 - RAN-End-Time, Time, code 1301 - RAN-Secondary-RAT-Usage-Report, Grouped, code 1302 - RAN-Start-Time, Time, code 1303 - Radio-Frequency, OctetString, code 3462 - Radio-Parameter-Set-Info, Grouped, code 3463 - Radio-Parameter-Set-Values, OctetString, code 3464 - Radio-Resources-Indicator, Integer32, code 3465 - Rate-Control-Max-Message-Size, Unsigned32, code 3937 - Rate-Control-Max-Rate, Unsigned32, code 3938 - Rate-Control-Time-Unit, Unsigned32, code 3939 - Reason-Header, UTF8String, code 3401 - Related-Change-Condition-Information, Grouped, code 3925 - Related-IMS-Charging-Identifier, UTF8String, code 2711 - Related-IMS-Charging-Identifier-Node, Address, code 2712 - Related-Trigger, Grouped, code 3926 - Relay-IP-address, Address, code 4411 - Requested-PLMN-Identifier, UTF8String, code 3436 - Requestor-PLMN-Identifier, UTF8String, code 3437 - Role-Of-ProSe-Function, Enumerated, code 3438 - Route-Header-Received, UTF8String, code 3403 - Route-Header-Transmitted, UTF8String, code 3404 - SCEF-Address, Address, code 1317 - SCS-AS-Address, Grouped, code 3940 - SCS-Address, Address, code 3941 - SCS-Realm, DiameterIdentity, code 3942 - SGi-PtP-Tunnelling-Method, Enumerated, code 3931 - SM-Device-Trigger-Indicator, Enumerated, code 3407 - SM-Device-Trigger-Information, Grouped, code 3405 - SM-Sequence-Number, Unsigned32, code 3408 - SMS-Result, Unsigned32, code 3409 - Secondary-RAT-Type, OctetString, code 1304 - Serving-Node-Identity, DiameterIdentity, code 3929 - Start-of-Charging, Time, code 3419 - TAD-Identifier, Enumerated, code 2717 - TLTRI, Unsigned32, code 1318 - TWAG-Address, Address, code 3903 - TWAN-User-Location-Info, Grouped, code 2714 - Target-IP-Address, Address, code 4412 - Teleservice, OctetString, code 3413 - Time-First-Reception, Time, code 3466 - Time-First-Transmission, Time, code 3467 - Time-Indicator, Unsigned32, code 3911 - Transmitter-Info, Grouped, code 3468 - UNI-PDU-CP-Only-Flag, Enumerated, code 3932 - UWAN-User-Location-Info, Grouped, code 3918 - Unused-Quota-Timer, Unsigned32, code 4407 - Usage-Information-Report-Sequence-Number, Integer32, code 3439 - VCS-Information, Grouped, code 3410 - VLR-Number, OctetString, code 3420 - Variable-Part, Grouped, code 3907 - Variable-Part-Order, Unsigned32, code 3908 - Variable-Part-Type, Unsigned32, code 3909 - Variable-Part-Value, UTF8String, code 3910 - WLAN-Operator-Id, Grouped, code 1306 - WLAN-Operator-Name, UTF8String, code 1307 - WLAN-PLMN-Id, UTF8String, code 1308 3GPP TS 32.299 V11.8.0 (2013-07) renamed LCS-Requestor-Id (1239) to LCS-Requestor-ID (1239). 3GPP TS 32.299 V11.8.0 (2013-07) renamed LCS-Requestor-Id-String (1240) to LCS-Requestor-ID-String (1240). 3GPP TS 32.299 V13.1.0 (2015-06) renamed PoC-User-Role-info-Units (1254) to PoC-User-Role-Info-Units (1254). 3GPP TS 32.299 V11.10.0 (2013-12) renamed Status (2702) to Status-Code (2702), and then 3GPP TS 32.299 V11.14.0 (2014-12) renamed Status-Code (2702) to Status-AS-Code (2702).
author Luke Mewburn <luke@mewburn.net>
date Thu, 26 Mar 2020 15:26:18 +1100
parents 3cbe458fbfa9
children 566bb46cc73f
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
*													 *
* Copyright (c) 2015, 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 "fdcore-internal.h"

/* Structures for the fd_hook_data_hdl management */
static struct fd_hook_data_hdl {
	size_t	pmd_size;
	void  (*pmd_init_cb)(struct fd_hook_permsgdata *);
	void  (*pmd_fini_cb)(struct fd_hook_permsgdata *);
} HDH_array[FD_HOOK_HANDLE_LIMIT];
static int max_index = 0;
static pthread_mutex_t HDH_lock = PTHREAD_MUTEX_INITIALIZER;

/* The structure linked from the msg structure list */
struct pmd_list_item {
	struct fd_list	chain;		/* this list is ordered by hdl */
	struct fd_hook_data_hdl * hdl; 
	struct fd_hook_permsgdata { } pmd; /* this data belongs to the extension; we only know the size of it */
};

#define sizeof_pmd(hdl)	(((size_t)&((struct pmd_list_item *)0)->pmd) + hdl->pmd_size)

/* Now a hook registered by an extension */
struct fd_hook_hdl {
	struct fd_list chain[HOOK_LAST+1];
	void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata);
	void  *regdata;
	struct fd_hook_data_hdl *data_hdl;
};

/* Array of those hooks */
struct {
	struct fd_list sentinel;
	pthread_rwlock_t rwlock;
} HS_array[HOOK_LAST+1];

/* Initialize the array of sentinels for the hooks */
int fd_hooks_init(void)
{
	int i;
	for (i=0; i <= HOOK_LAST; i++) {
		fd_list_init(&HS_array[i].sentinel, NULL);
		CHECK_POSIX( pthread_rwlock_init(&HS_array[i].rwlock, NULL) );
	}
	return 0;
}

/* Get a slot in the array */
int fd_hook_data_register(
	size_t permsgdata_size,
	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
        struct fd_hook_data_hdl **new_handle)
{
	int ret = ENOSPC, idx;
	TRACE_ENTRY("%zd %p %p %p", permsgdata_size, permsgdata_init_cb, permsgdata_fini_cb, new_handle);
	
	CHECK_PARAMS( permsgdata_size && new_handle );
	
	CHECK_POSIX( pthread_mutex_lock(&HDH_lock) );
	if (max_index < FD_HOOK_HANDLE_LIMIT) {
		idx = max_index++;
		ret = 0;
	}
	CHECK_POSIX( pthread_mutex_unlock(&HDH_lock) );
	
	if (ret == 0) {
		HDH_array[idx].pmd_size = permsgdata_size;
		HDH_array[idx].pmd_init_cb = permsgdata_init_cb;
		HDH_array[idx].pmd_fini_cb = permsgdata_fini_cb;
		*new_handle = &HDH_array[idx];
	}
	
	return ret;
}

/* Register a new hook callback */
int fd_hook_register (  uint32_t type_mask, 
			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata), 
			void  *regdata, 
			struct fd_hook_data_hdl *data_hdl,
			struct fd_hook_hdl ** handler )
{
	struct fd_hook_hdl * newhdl = NULL;
	int i;
	
	TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler);
	
	CHECK_PARAMS( fd_hook_cb && handler );
	
	CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) );
	memset(newhdl, 0, sizeof(struct fd_hook_hdl));
	
	newhdl->fd_hook_cb = fd_hook_cb;
	newhdl->regdata = regdata;
	newhdl->data_hdl = data_hdl;
	
	for (i=0; i <= HOOK_LAST; i++) {
		fd_list_init(&newhdl->chain[i], newhdl);
		if (type_mask & (1<<i)) {
			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
			fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]);
			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
		}
	}
	
	*handler = newhdl;
	return 0;
}

/* free this hook callback */
int fd_hook_unregister( struct fd_hook_hdl * handler )
{
	int i;
	TRACE_ENTRY("%p", handler);
	CHECK_PARAMS( handler );
	
	for (i=0; i <= HOOK_LAST; i++) {
		if ( ! FD_IS_LIST_EMPTY(&handler->chain[i])) {
			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
			fd_list_unlink(&handler->chain[i]);
			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
		}
	}
	
	free(handler);
	
	return 0;
}

/* callback for the libfdproto to free the data associated with a message */
static void pmdl_free(struct fd_msg_pmdl *pmdl)
{
	/* destroy all the items in the list */
	while (!FD_IS_LIST_EMPTY(&pmdl->sentinel)) {
		struct pmd_list_item * li = (struct pmd_list_item *)(pmdl->sentinel.next);
		if (li->hdl->pmd_fini_cb) {
			(*li->hdl->pmd_fini_cb)(&li->pmd);
		}
		fd_list_unlink(&li->chain);
		free(li);
	}
	CHECK_POSIX_DO( pthread_mutex_destroy(&pmdl->lock), );
	pmdl->sentinel.o = NULL;
}

/* Save the list of pmd into the message structure, as well as the callback to free this list */
void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl)
{
	struct fd_msg_pmdl * in_msg;
	
	CHECK_PARAMS_DO( msg && pmdl, return );
	in_msg = fd_msg_pmdl_get(msg);
	ASSERT(in_msg && (in_msg->sentinel.o == NULL)); /* error / already initialized ??? */
	in_msg->sentinel.o = pmdl_free;
	/* Now move all items from the pmdl pointer into the initialized list */
	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
	fd_list_move_end(&in_msg->sentinel, &pmdl->sentinel);
	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
	pmdl_free(pmdl);
	/* We're done */
}

/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */
static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_data_hdl * h)
{
	struct fd_hook_permsgdata * ret = NULL;
	struct fd_list * li;
	
	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
	
	if (pmdl->sentinel.o == NULL) {
		pmdl->sentinel.o = pmdl_free;
	}
	
	/* Search in the list for an item with the same handle. The list is ordered by this handle */
	for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
		struct pmd_list_item * pli = (struct pmd_list_item *) li;
		if (pli->hdl == h)
			ret = &pli->pmd;
		if (pli->hdl >= h)
			break;
	}
	if (!ret) {
		/* we need to create a new one and insert before li */
		struct pmd_list_item * pli;
		CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h)), );
		if (pli) {
			memset(pli, 0, sizeof_pmd(h));
			fd_list_init(&pli->chain, pli);
			pli->hdl = h;
			ret = &pli->pmd;
			if (h->pmd_init_cb) {
				(*h->pmd_init_cb)(ret);
			}
			fd_list_insert_before(li, &pli->chain);
		}
	}
	
	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
	return ret;
}

struct fd_hook_permsgdata * fd_hook_get_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * msg)
{
    return get_or_create_pmd(fd_msg_pmdl_get(msg), data_hdl);
}

struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer)
{
	struct msg * qry;
	struct fd_msg_pmdl *pmdl;
	struct fd_hook_permsgdata * ret = NULL;
	struct fd_list * li;
	
	CHECK_FCT_DO( fd_msg_answ_getq(answer, &qry), return NULL );
	if (!qry)
		return NULL;
	
	pmdl = fd_msg_pmdl_get(qry);
	if (!pmdl)
		return NULL;
	
	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
	/* Search in the list for an item with the same handle. The list is ordered by this handle */
	for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
		struct pmd_list_item * pli = (struct pmd_list_item *) li;
		if (pli->hdl == data_hdl)
			ret = &pli->pmd;
		if (pli->hdl >= data_hdl)
			break;
	}
	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
	return ret;
}

/* Create a mask */
uint32_t fd_hook_mask_helper(int dummy, ...)
{
	va_list ap;
	uint32_t ret = 0;
	int next;
	
	va_start(ap, dummy);
	while ((next = va_arg(ap, int)) >= 0) {
		if (next > HOOK_LAST)
			break; /* invalid parameter */
		ret |= (1<<next);
	}
	va_end(ap);

	return ret;
}

static pthread_mutex_t hook_default_mtx = PTHREAD_MUTEX_INITIALIZER;
static char * hook_default_buf = NULL;
static size_t hook_default_len = 0;

/* The function that does the work of calling the extension's callbacks and also managing the permessagedata structures */
void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl)
{
	struct fd_list * li;
	ASSERT(type <= HOOK_LAST);
	int call_default = 0;
	
	/* lock the list of hooks for this type */
	CHECK_POSIX_DO( pthread_rwlock_rdlock(&HS_array[type].rwlock), );
	
	pthread_cleanup_push( fd_cleanup_rwlock, &HS_array[type].rwlock );
	
	if (FD_IS_LIST_EMPTY(&HS_array[type].sentinel)) {
		call_default = 1;
	} else {
		/* for each registered hook */
		for (li = HS_array[type].sentinel.next; li != &HS_array[type].sentinel; li = li->next) {
			struct fd_hook_hdl * h = (struct fd_hook_hdl *)li->o;
			struct fd_hook_permsgdata * pmd = NULL;

			/* do we need to handle pmd ? */
			if (h->data_hdl && pmdl) {
				pmd = get_or_create_pmd(pmdl, h->data_hdl);
			}

			/* Now, call this callback */
			(*h->fd_hook_cb)(type, msg, &peer->p_hdr, other, pmd, h->regdata);
		}
	}
	
	pthread_cleanup_pop(0);
	
	/* done */
	CHECK_POSIX_DO( pthread_rwlock_unlock(&HS_array[type].rwlock), );
	
	if (call_default) {
		CHECK_POSIX_DO( pthread_mutex_lock(&hook_default_mtx), );
		
		pthread_cleanup_push( fd_cleanup_mutex, &hook_default_mtx );
	
		/* There was no registered handler, default behavior for this hook */
		switch (type) {
			case HOOK_DATA_RECEIVED: {
#ifdef DEBUG
				struct fd_cnx_rcvdata *rcv_data = other;
#endif
				LOG_A("RCV: %zd bytes", rcv_data->length);
				break;
			}
			
			case HOOK_MESSAGE_RECEIVED: {
				CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_D("RCV from '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_LOCAL: {
				CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_A("Handled to framework for sending: %s", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_SENDING: {
				LOG_A("SENDING message to '%s'", peer ? peer->p_hdr.info.pi_diamid : "<unknown>");
				break;
			}
			
			case HOOK_MESSAGE_SENT: {
				CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_D("SENT to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_FAILOVER: {
				CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_D("Failing over message sent to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_PARSING_ERROR: {
				if (msg) {
					DiamId_t id = NULL;
					if (fd_msg_source_get( msg, &id, NULL ))
						id = (DiamId_t)"<error getting source>";
					
					if (!id)
						id = (DiamId_t)"<local>";
					
					CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
					
					LOG_E("Parsing error: '%s' for the following message received from '%s':", (char *)other, (char *)id);
					LOG_SPLIT(FD_LOG_ERROR, "   ", hook_default_buf, NULL);
				} else {
					struct fd_cnx_rcvdata *rcv_data = other;
					CHECK_MALLOC_DO(fd_dump_extend_hexdump(&hook_default_buf, &hook_default_len, NULL, rcv_data->buffer, rcv_data->length, 0, 0), break);
					LOG_E("Parsing error: cannot parse %zdB buffer from '%s': %s",  rcv_data->length, peer ? peer->p_hdr.info.pi_diamid : "<unknown>", hook_default_buf);
				}
				break;
			}
			
			case HOOK_MESSAGE_PARSING_ERROR2: {
				CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);

				LOG_E("Returning following message after parsing error:");
				LOG_SPLIT(FD_LOG_ERROR, "   ", hook_default_buf, NULL);
				break;
			}
			
			case HOOK_MESSAGE_ROUTING_ERROR: {
				CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_E("Routing error: '%s' for the following message:", (char *)other);
				LOG_SPLIT(FD_LOG_ERROR, "   ", hook_default_buf, NULL);
				break;
			}
			
			case HOOK_MESSAGE_ROUTING_FORWARD: {
				CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_D("FORWARDING: %s", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_ROUTING_LOCAL: {
				CHECK_MALLOC_DO(fd_msg_dump_summary(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_D("DISPATCHING: %s", hook_default_buf);
				break;
			}
			
			case HOOK_MESSAGE_DROPPED: {
				CHECK_MALLOC_DO(fd_msg_dump_treeview(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				LOG_E("Message discarded ('%s'):", (char *)other);
				LOG_SPLIT(FD_LOG_ERROR, "   ", hook_default_buf, NULL);
				break;
			}
			
			case HOOK_PEER_CONNECT_FAILED: {
				if (msg) {
					CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
					LOG_N("Connection to '%s' failed: '%s'; CER/CEA dump:", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other);
					LOG_SPLIT(FD_LOG_NOTICE, "   ", hook_default_buf, NULL);
				} else {
					LOG_D("Connection to '%s' failed: %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other);
				}
				break;
			}
			
			case HOOK_PEER_CONNECT_SUCCESS: {
				DiamId_t id = NULL;
				if ((!fd_msg_source_get( msg, &id, NULL )) && (id == NULL)) { /* The CEA is locally issued */
					fd_msg_answ_getq(msg, &msg); /* We dump the CER in that case */
				}
				CHECK_MALLOC_DO(fd_msg_dump_full(&hook_default_buf, &hook_default_len, NULL, msg, NULL, 0, 1), break);
				char protobuf[40];
				if (peer) {
					CHECK_FCT_DO(fd_peer_cnx_proto_info(&peer->p_hdr, protobuf, sizeof(protobuf)), break );
				} else {
					protobuf[0] = '-';
					protobuf[1] = '\0';
				}
				LOG_N("Connected to '%s' (%s), remote capabilities: ", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", protobuf);
				LOG_SPLIT(FD_LOG_NOTICE, "   ", hook_default_buf, NULL);
				break;
			}
			
		}
		
		pthread_cleanup_pop(0);
		
		CHECK_POSIX_DO( pthread_mutex_unlock(&hook_default_mtx), );
	}
}
"Welcome to our mercurial repository"