From 95170bf3a69597b49238bb7ff396d41f6dc94f30 Mon Sep 17 00:00:00 2001 From: Jordan Augé Date: Wed, 30 Oct 2019 17:56:08 +0100 Subject: [HICN-369] Implement reconciliation state machine in face manager incl. reattempts in case of errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia4ecf621fbd513d9e29313d2aaa487aa65811183 Signed-off-by: Jordan Augé --- ctrl/facemgr/src/api.c | 815 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 551 insertions(+), 264 deletions(-) (limited to 'ctrl/facemgr/src/api.c') diff --git a/ctrl/facemgr/src/api.c b/ctrl/facemgr/src/api.c index a1507bd70..19f211dbf 100644 --- a/ctrl/facemgr/src/api.c +++ b/ctrl/facemgr/src/api.c @@ -39,8 +39,8 @@ #endif /* __ANDROID__ */ #include +#include #include "common.h" -#include "facelet.h" #include "interface.h" #include "util/map.h" #include "util/set.h" @@ -49,6 +49,7 @@ #define DEFAULT_PORT 9695 +#define DEFAULT_REATTEMPT_DELAY_MS 250 #define MAX_FDS 10 typedef struct { @@ -149,6 +150,7 @@ struct facemgr_s { #ifdef WITH_EXAMPLE_UPDOWN interface_t * updown; #endif + int timer_fd; /* Timer used for reattempts */ }; int @@ -174,6 +176,8 @@ facemgr_initialize(facemgr_t * facemgr) if (!facemgr->cfg) goto ERR_CFG; + facemgr->timer_fd = 0; + return 0; ERR_CFG: @@ -194,6 +198,16 @@ facemgr_finalize(facemgr_t * facemgr) int ret = 0; int rc; + if (facemgr->timer_fd) { + rc = facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_UNREGISTER_TIMER, &facemgr->timer_fd); + if (rc < 0) { + ERROR("[facemgr_finalize] Error unregistering timer"); + ret = -1; + } + facemgr->timer_fd = 0; + } + rc = interface_map_finalize(&facemgr->interface_map); if (rc < 0) { ERROR("[facemgr_finalize] Could not finalize interface_map"); @@ -226,6 +240,8 @@ facemgr_finalize(facemgr_t * facemgr) ret = -1; #endif /* __linux__ */ + interface_unregister_all(); + return ret; } @@ -265,12 +281,49 @@ facemgr_create_with_config(facemgr_cfg_t * cfg) return facemgr; } +/* + * \brief Heuristics to determine face type based on name, until a better + * solution is found + */ +netdevice_type_t +facemgr_get_netdevice_type(const facemgr_t * facemgr, const char * interface_name) +{ + if (strncmp(interface_name, "lo", 2) == 0) { + return NETDEVICE_TYPE_LOOPBACK; + } + if ((strncmp(interface_name, "eth", 3) == 0) || + (strncmp(interface_name, "en", 2) == 0)) { + /* eth* en* enx* */ + return NETDEVICE_TYPE_WIRED; + } + if (strncmp(interface_name, "wl", 2) == 0) { + /* wlan* wlp* wlx* */ + return NETDEVICE_TYPE_WIFI; + } + if (strncmp(interface_name, "rmnet_ipa", 9) == 0) { + /* Qualcomm IPA driver */ + return NETDEVICE_TYPE_UNDEFINED; + } + if ((strncmp(interface_name, "rmnet", 5) == 0) || + (strncmp(interface_name, "rev_rmnet", 9) == 0) || + (strncmp(interface_name, "ccmni", 5) == 0)) { + /* + * rmnet* (Qualcomm) ccmni* (MediaTek) + */ + return NETDEVICE_TYPE_CELLULAR; + } + /* usb0 might be cellular (eg Zenfone2) */ + /* what about tethering */ + /* tun* dummy* ... */ + /* bnet* pan* hci* for bluetooth */ + return NETDEVICE_TYPE_UNDEFINED; +} + int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data); int facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * type, void * cfg, interface_t ** pinterface) { - int fd; char rand_name[RAND_NAME_LEN+1]; interface_t * interface; @@ -291,10 +344,6 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty } interface_set_callback(interface, facemgr, facemgr_callback); - fd = interface_initialize(interface, cfg); - if (fd < 0) - goto ERR_INIT; - interface_map_data_t * interface_map_data = malloc(sizeof(interface_map_data_t)); if (!interface_map_data) goto ERR_MAP_DATA; @@ -308,6 +357,15 @@ facemgr_create_interface(facemgr_t * facemgr, const char * name, const char * ty if (interface_map_add(&facemgr->interface_map, interface->name, interface_map_data) < 0) goto ERR_MAP_ADD; + /* + * This should be called _after_ the interface_map is initialized otherwise + * it will be impossible to register fds from *_initialize + */ + if (interface_initialize(interface, cfg) < 0) { + ERROR("[facemgr_create_interface] Error initializing interface"); + goto ERR_INIT; + } + DEBUG("Interface %s created successfully.", name); if (pinterface) *pinterface = interface; @@ -342,7 +400,13 @@ facemgr_delete_interface(facemgr_t * facemgr, interface_t * interface) for (unsigned i = 0; i < interface_map_data->num_fds; i++) { int fd = interface_map_data->fds[i]; - facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd); + fd_callback_data_t fd_callback_data = { + .fd = fd, + .owner = facemgr, + .callback = NULL, + .data = NULL, + }; + facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_FD, &fd_callback_data); if (rc < 0) WARN("[facemgr_delete_interface] Error unregistering fd %d for interface", fd); } @@ -494,7 +558,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) } netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; -#ifdef __ANDROID__ +//#ifdef __ANDROID__ /* * In addition to netdevice, netdevice_type should be present to correctly * apply rules @@ -504,7 +568,7 @@ facemgr_facelet_satisfy_rules(facemgr_t * facemgr, facelet_t * facelet) ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet"); return -2; } -#endif /* __ANDROID__ */ +//#endif /* __ANDROID__ */ /* Ignore */ bool ignore; @@ -578,11 +642,13 @@ facemgr_complement_facelet_au(facemgr_t * facemgr, facelet_t * facelet) } DEBUG("Querying android utility..."); - facelet_set_au_done(facelet); /* /!\ Synchronous code here /!\ */ - if (facemgr_query_android_utility(facemgr, netdevice) < 0) + if (facemgr_query_android_utility(facemgr, netdevice) < 0) { return -1; + } + + facelet_set_au_done(facelet); return 0; } #endif /* __ANDROID__ */ @@ -607,7 +673,7 @@ facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet) } netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; -#ifdef __ANDROID__ +//#ifdef __ANDROID__ /* * In addition to netdevice, netdevice_type should be present to correctly * apply rules @@ -617,7 +683,7 @@ facemgr_complement_facelet_bj(facemgr_t * facemgr, facelet_t * facelet) ERROR("[facemgr_complement_facelet_bj] Error retrieving netdevice_type from facelet"); return -2; } -#endif /* __ANDROID__ */ +//#endif /* __ANDROID__ */ bool discovery; if (facemgr_cfg_get_discovery(facemgr->cfg, &netdevice, netdevice_type, @@ -679,7 +745,7 @@ facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet) } netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; -#ifdef __ANDROID__ +//#ifdef __ANDROID__ /* * In addition to netdevice, netdevice_type should be present to correctly * apply rules @@ -689,7 +755,7 @@ facemgr_complement_facelet_manual(facemgr_t * facemgr, facelet_t * facelet) ERROR("[facemgr_complement_facelet_manual] Error retrieving netdevice_type from facelet"); return -2; } -#endif /* __ANDROID__ */ +//#endif /* __ANDROID__ */ int family = AF_UNSPEC; if (facelet_has_family(facelet)) { @@ -798,11 +864,22 @@ facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet) if (!facelet_has_key(facelet)) return -2; +#if 0 #ifdef __ANDROID__ rc = facemgr_complement_facelet_au(facemgr, facelet); if (rc != -2) return rc; #endif /* __ANDROID__ */ +#endif + if (!facelet_has_netdevice_type(facelet)) { + netdevice_t netdevice = NETDEVICE_EMPTY; + rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_complement_facelet] Error retrieving netdevice from facelet"); + return -1; + } + facelet_set_netdevice_type(facelet, facemgr_get_netdevice_type(facemgr, netdevice.name)); + } /* We continue only if the current call was not applicable. In the current * setting we have no interface that can be requested in parallel, and no @@ -825,105 +902,279 @@ facemgr_complement_facelet(facemgr_t * facemgr, facelet_t * facelet) return 0; } -/** - * \brief Process facelet CREATE event - * \param [in] facemgr - Pointer to the face manager instance - * \param [in] facelet - Pointer to the facelet event to process - * \return 0 if everything went correctly, or -1 in case of error. - */ -int -facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) +int facemgr_assign_face_type(facemgr_t * facemgr, facelet_t * facelet) { - /* - * We create an interface locally, which does not means it should not exist - * remotely. Once such codepath is enabled, the two facelets will have been - * merged and we need to handle an eventual update on our side. - * - * In the same way, we need to check for the equivalence of face types etc. - */ - int rc; + /* As key, netdevice and family should always be present */ + netdevice_t netdevice = NETDEVICE_EMPTY; + int rc = facelet_get_netdevice(facelet, &netdevice); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet"); + return -1; + } + netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; +//#ifdef __ANDROID__ /* - * If the facelet does not satisfy filters, we do not lose any information - * but do not take any action to complement the face + * In addition to netdevice, netdevice_type should be present to correctly + * apply rules */ - rc = facemgr_facelet_satisfy_rules(facemgr, facelet); - if (rc == -3) { - facelet_set_status(facelet, FACELET_STATUS_IGNORED); - /* Does not satisfy rules */ - return 0; + rc = facelet_get_netdevice_type(facelet, &netdevice_type); + if (rc < 0) { + ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet"); + return -2; } +//#endif /* __ANDROID__ */ - // FIXME: we should complement a part of the facelet, so that we don't - // necessarily keep this information if we get more locally. Or at least we - // should remember that. - if (rc == -2) { - /* - * We don't have equivalent for linux right now, heuristic is only used - * at the end... might change. - */ -#ifdef __ANDROID__ - /* Priority is given to information that complements a face */ - if (facemgr_complement_facelet_au(facemgr, facelet) < 0) { - ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by rule application"); - return -1; - } - return 0; -#endif /* __ANDROID__ */ + facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED; + if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0) + return rc; + facelet_set_face_type(facelet, face_type); + return 0; +} + +/* + * This function performs one step of the state machine associated to the + * facelet, from initial creation, to synchronization with the forwarder. + * + * We assume the facelet is already present in the cache + */ +int +facemgr_process_facelet(facemgr_t * facemgr, facelet_t * facelet) +{ + int rc; + + switch(facelet_get_status(facelet)) { + case FACELET_STATUS_UNCERTAIN: + /* + * All new faces are marked UNCERTAIN. We need to check whether we + * have sufficient information to check rules, if not proceed, + * otherwise possibly mark the face as IGNORED. Otherwise, we verify + * the completeness of the information we have, and continue towards + * being able to mark the face as CREATE. + */ + rc = facemgr_facelet_satisfy_rules(facemgr, facelet); + switch(rc) { + case -3: + /* Does not satisfy rules */ + facelet_set_status(facelet, FACELET_STATUS_IGNORED); + return 0; + + case -2: + /* Not enough information: AU in fact */ + if (facemgr_complement_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet] Error while attempting to complement face for fields required by face creation"); + goto ERR; + } + return 0; + + case 0: + /* Ok pass rules */ + break; + + default: + /* -1 - Error */ + goto ERR; + } + + if (facemgr_assign_face_type(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet] Could not assign face type"); + goto ERR; + } + facelet_set_status(facelet, FACELET_STATUS_INCOMPLETE); + /* Continue in case facelet satisfies rules */ + + case FACELET_STATUS_INCOMPLETE: + if (!facelet_validate_face(facelet)) { + /* We need additional information */ + if (facemgr_complement_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet] Error while attempting to complement face for fields required by face creation"); + goto ERR; + } + } + if (!facelet_validate_face(facelet)) + return 0; + + facelet_set_status(facelet, FACELET_STATUS_CREATE); + /* Continue in case we need to proceed to creation */ + + case FACELET_STATUS_CREATE: + facelet_set_event(facelet, FACELET_EVENT_CREATE); + if (interface_on_event(facemgr->hl, facelet) < 0) { + ERROR("[facemgr_process_facelet] Failed to create face"); + goto ERR; + } + + /* This works assuming the call to hicn-light is blocking */ + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + break; + + + case FACELET_STATUS_UPDATE: + facelet_set_event(facelet, FACELET_EVENT_UPDATE); + if (interface_on_event(facemgr->hl, facelet) < 0) { + ERROR("[facemgr_process_facelet] Failed to update face"); + goto ERR; + } + + /* This works assuming the call to hicn-light is blocking */ + facelet_set_status(facelet, FACELET_STATUS_CLEAN); + break; + + case FACELET_STATUS_DELETE: + facelet_set_event(facelet, FACELET_EVENT_DELETE); + if (interface_on_event(facemgr->hl, facelet) < 0) { + ERROR("[facemgr_process_facelet] Failed to delete face"); + goto ERR; + } + + /* This works assuming the call to hicn-light is blocking */ + DEBUG("[facemgr_process_facelet] Cleaning cached data"); + facelet_unset_local_addr(facelet); + facelet_unset_local_port(facelet); + facelet_unset_remote_addr(facelet); + facelet_unset_remote_port(facelet); + facelet_unset_bj_done(facelet); + //facelet_unset_au_done(facelet); + + facelet_set_status(facelet, FACELET_STATUS_DELETED); + break; + + case FACELET_STATUS_CLEAN: + case FACELET_STATUS_IGNORED: + case FACELET_STATUS_DELETED: + /* Nothing to do */ + break; + + case FACELET_STATUS_UNDEFINED: + case FACELET_STATUS_N: + ERROR("[facemgr_process_facelet] Unexpected facelet status"); + goto ERR; } - if (rc < 0) - return -1; -// netdevice_t netdevice = NETDEVICE_EMPTY; -// if (facelet_get_netdevice(facelet, &netdevice) < 0) { -// ERROR("[facemgr_process_create] Error retrieving netdevice from facelet"); -// return -1; -// } -// -// netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; -//#ifdef __ANDROID__ -// /* -// * In addition to netdevice, netdevice_type should be present to correctly -// * apply rules -// */ -// if (facelet_get_netdevice_type(facelet, &netdevice_type) < 0) { -// ERROR("[facemgr_process_create] Error retrieving netdevice_type from facelet"); -// return -2; -// } -//#endif /* __ANDROID__ */ + facelet_set_status_error(facelet, false); + return 0; +ERR: + facelet_set_status_error(facelet, true); + return -1; +} - char facelet_s[MAXSZ_FACELET]; - facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); - //DEBUG("---[ FACELET CREATE : %s ] ---", facelet_s); +int +facemgr_reattempt_timeout(facemgr_t * facemgr, int fd, void * data) +{ + bool has_error = false; - /* Do we have enough information about the facelet ? */ - if (!facelet_validate_face(facelet)) { - if (facemgr_complement_facelet(facemgr, facelet) < 0) { - ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation"); - return -1; + assert(data == NULL); + + /* Free all facelets from cache */ + facelet_t ** facelet_array; + int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array); + if (n < 0) { + ERROR("[facemgr_reattempt_timeout] Could not retrieve facelets in cache"); + } else { + for (unsigned i = 0; i < n; i++) { + facelet_t * facelet = facelet_array[i]; + + if (!facelet_get_status_error(facelet)) + continue; + + char buf[MAXSZ_FACELET]; + facelet_snprintf(buf, MAXSZ_FACELET, facelet); + DEBUG("Reattempt to process failed facelet %s", buf); + if (facemgr_process_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_reattempt_timeout] Error processing facelet"); + has_error = true; + continue; + } + facelet_set_status_error(facelet, false); } - // we should not stop after complement_manual but create a face if - // possible... so we add a second validation + free(facelet_array); } - if (!facelet_validate_face(facelet)) + if (has_error) return 0; - /* - * Is the forwarder connected, and has the facelet cache already sync'ed the - * remote faces ? - */ - // TODO + DEBUG("Cancelling timer"); + if (facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_UNREGISTER_TIMER, &facemgr->timer_fd) < 0) { + ERROR("[facemgr_reattempt_timeout] Error unregistering reattempt timer"); + return -1; + } + facemgr->timer_fd = 0; + return 0; +} - /* - * Actually create the face on the forwarder - * - * FIXME Currently hicn-light is hardcoded - */ - if (interface_on_event(facemgr->hl, facelet) < 0) +int +facemgr_start_reattempts(facemgr_t * facemgr) +{ + if (facemgr->timer_fd > 0) + return 0; + + timer_callback_data_t timer_callback = { + .delay_ms = DEFAULT_REATTEMPT_DELAY_MS, + .owner = facemgr, + .callback = (fd_callback_t)facemgr_reattempt_timeout, + .data = NULL, + }; + facemgr->timer_fd = facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_REGISTER_TIMER, &timer_callback); + return (facemgr->timer_fd > 0); +} + +/** + * \brief Process facelet CREATE event + * \param [in] facemgr - Pointer to the face manager instance + * \param [in] facelet - Pointer to the facelet event to process + * \return 0 if everything went correctly, or -1 in case of error. + * -2 means we ignored the face purposedly + */ +int +facemgr_process_facelet_create(facemgr_t * facemgr, facelet_t * facelet) +{ + switch(facelet_get_status(facelet)) { + case FACELET_STATUS_UNCERTAIN: + case FACELET_STATUS_INCOMPLETE: + case FACELET_STATUS_CREATE: + /* No change */ + break; + case FACELET_STATUS_UPDATE: + case FACELET_STATUS_DELETE: + /* + * Unlikely. The face had been created and is planned to + * be deleted. Schedule for creation (we should have all + * needed information), but make sure to handle errors + * correctly if the face is still present. + * TODO What if some fields have been updated ? + */ + facelet_set_status(facelet, FACELET_STATUS_CREATE); + break; + case FACELET_STATUS_CLEAN: + case FACELET_STATUS_IGNORED: + /* + * We should have nothing to do unless some fields have + * been updated. + */ + break; + + case FACELET_STATUS_DELETED: + /* + * Unless rules have changed, we only need to recover + * missing information, and proceed to face creation. + * Rule changes should be handled separately. + */ + facelet_set_status(facelet, FACELET_STATUS_INCOMPLETE); + break; + case FACELET_STATUS_UNDEFINED: + case FACELET_STATUS_N: + ERROR("[facemgr_process_facelet_create] Unexpected facelet status"); + return -1; + } + + if (facemgr_process_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet_create] Error processing facelet"); return -1; - facelet_set_status(facelet, FACELET_STATUS_CLEAN); + } + return 0; } @@ -935,15 +1186,15 @@ facemgr_process_create(facemgr_t * facemgr, facelet_t * facelet) * -2 means we ignored the face purposedly */ int -facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet) +facemgr_process_facelet_get(facemgr_t * facemgr, facelet_t * facelet) { - facelet_set_status(facelet, FACELET_STATUS_CLEAN); if (facelet_has_netdevice(facelet)) { netdevice_t netdevice; if (facelet_get_netdevice(facelet, &netdevice) < 0) return -1; if (!IS_VALID_NETDEVICE(netdevice)) return -2; + facelet_set_status(facelet, FACELET_STATUS_CLEAN); return facelet_cache_add(&facemgr->facelet_cache, facelet); } return -2; @@ -954,146 +1205,38 @@ facemgr_process_get(facemgr_t * facemgr, facelet_t * facelet) * \param [in] facemgr - Pointer to the face manager instance * \param [in] facelet - Pointer to the facelet event to process * \return 0 if everything went correctly, or -1 in case of error. + * -2 means we ignored the face purposedly */ int -facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) +facemgr_process_facelet_update(facemgr_t * facemgr, facelet_t * facelet) { - /* This is the most complex operation since we have the same problems as in - * CREATE + the need to manage changes... - * - * This might eventually trigger a face deletion... - */ - - /* - * Update in local does not mean the face should not be created remotely as - * it might be the first time we have enough information to create it - */ - - char facelet_s[MAXSZ_FACELET]; - facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet); - //DEBUG("---[ FACELET UPDATE : %s ] ---", facelet_s); - - /* Sets face type */ - if (!facelet_has_face_type(facelet)) { - - /* As key, netdevice and family should always be present */ - netdevice_t netdevice = NETDEVICE_EMPTY; - int rc = facelet_get_netdevice(facelet, &netdevice); - if (rc < 0) { - ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice from facelet"); - return -1; - } - - netdevice_type_t netdevice_type = NETDEVICE_TYPE_UNDEFINED; -#ifdef __ANDROID__ - /* - * In addition to netdevice, netdevice_type should be present to correctly - * apply rules - */ - rc = facelet_get_netdevice_type(facelet, &netdevice_type); - if (rc < 0) { - ERROR("[facemgr_facelet_satisfy_rules] Error retrieving netdevice_type from facelet"); - return -2; - } -#endif /* __ANDROID__ */ - - facemgr_face_type_t face_type = FACEMGR_FACE_TYPE_UNDEFINED; - if (facemgr_cfg_get_face_type(facemgr->cfg, &netdevice, netdevice_type, &face_type) < 0) - return rc; - facelet_set_face_type(facelet, face_type); - } - - /* Process GET/UDPATE... */ - int rc; switch(facelet_get_status(facelet)) { - case FACELET_STATUS_UNDEFINED: - ERROR("[facemgr_process_update] Unexpected facelet status"); - return -1; - - case FACELET_STATUS_DELETED: - case FACELET_STATUS_NEW: - /* - * If the remote action should be a CREATE, then we need to check - * whether we have enough information about the face... - */ - if (!facelet_validate_face(facelet)) { - if (facemgr_complement_facelet(facemgr, facelet) < 0) { - ERROR("[facemgr_process_update] Error while attempting to complement face for fields required by face creation"); - return -1; - } - } - - rc = facemgr_facelet_satisfy_rules(facemgr, facelet); - if (rc == -3) { - facelet_set_status(facelet, FACELET_STATUS_IGNORED); - /* Does not satisfy rules */ - return 0; - } - - if (!facelet_validate_face(facelet)) - return 0; - - facelet_set_event(facelet, FACELET_EVENT_CREATE); - interface_on_event(facemgr->hl, facelet); - - /* This works assuming the call to hicn-light is blocking */ - facelet_set_status(facelet, FACELET_STATUS_CLEAN); + case FACELET_STATUS_UNCERTAIN: + case FACELET_STATUS_INCOMPLETE: + case FACELET_STATUS_CREATE: + case FACELET_STATUS_UPDATE: + /* No change */ break; - case FACELET_STATUS_CLEAN: - /* Nothing to do */ - break; - - case FACELET_STATUS_DIRTY: - /* - * For now we assume only local changes, and proceed to try and - * update the hICN forwarder. - * - * In case of update, the face exists which means we should already - * have enough information - */ - if (!facelet_validate_face(facelet)) { - if (facemgr_complement_facelet(facemgr, facelet) < 0) { - ERROR("[facemgr_process_create] Error while attempting to complement face for fields required by face creation"); - return -1; - } - } - - rc = facemgr_facelet_satisfy_rules(facemgr, facelet); - if (rc == -3) { - facelet_set_status(facelet, FACELET_STATUS_IGNORED); - /* Does not satisfy rules */ - return 0; - } - - if (!facelet_validate_face(facelet)) - return 0; - - facelet_set_event(facelet, FACELET_EVENT_UPDATE); - if (interface_on_event(facemgr->hl, facelet) < 0) - return -1; - - /* This works assuming the call to hicn-light is blocking and we - * have proceeded to all udpates */ - facelet_set_status(facelet, FACELET_STATUS_CLEAN); + facelet_set_status(facelet, FACELET_STATUS_UPDATE); break; - - case FACELET_STATUS_CONFLICT: - ERROR("[facemgr_process_update] Conflict resolution (not) yet implemented"); - return -1; - - case FACELET_STATUS_ERROR: - ERROR("[facemgr_process_update] Case ERROR (not) yet implemented"); - break; - + case FACELET_STATUS_DELETE: + case FACELET_STATUS_DELETED: case FACELET_STATUS_IGNORED: - ERROR("[facemgr_process_update] Case IGNORED (not) yet implemented"); + /* Reconsider face creation in light of new information */ + facelet_set_status(facelet, FACELET_STATUS_UNCERTAIN); break; - + case FACELET_STATUS_UNDEFINED: case FACELET_STATUS_N: - ERROR("[facemgr_process_update] Facelet in error"); + ERROR("[facemgr_process_facelet_update] Unexpected facelet status"); return -1; } + + if (facemgr_process_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet_update] Error processing facelet"); + return -1; + } + return 0; } @@ -1102,34 +1245,47 @@ facemgr_process_update(facemgr_t * facemgr, facelet_t * facelet) * \param [in] facemgr - Pointer to the face manager instance * \param [in] facelet - Pointer to the facelet event to process * \return 0 if everything went correctly, or -1 in case of error. + * -2 means we ignored the face purposedly */ int -facemgr_process_delete(facemgr_t * facemgr, facelet_t * facelet) +facemgr_process_facelet_delete(facemgr_t * facemgr, facelet_t * facelet) { + switch(facelet_get_status(facelet)) { + case FACELET_STATUS_UNCERTAIN: + case FACELET_STATUS_INCOMPLETE: + case FACELET_STATUS_CREATE: + facelet_unset_local_addr(facelet); + facelet_unset_local_port(facelet); + facelet_unset_remote_addr(facelet); + facelet_unset_remote_port(facelet); + facelet_unset_bj_done(facelet); + //facelet_unset_au_done(facelet); + facelet_set_status(facelet, FACELET_STATUS_DELETED); + break; + case FACELET_STATUS_UPDATE: + case FACELET_STATUS_CLEAN: + facelet_set_status(facelet, FACELET_STATUS_DELETE); + break; + case FACELET_STATUS_DELETE: + case FACELET_STATUS_IGNORED: + case FACELET_STATUS_DELETED: + /* Nothing to do */ + DEBUG("%s\n", facelet_status_str[facelet_get_status(facelet)]); + break; + case FACELET_STATUS_UNDEFINED: + case FACELET_STATUS_N: + ERROR("[facemgr_process_facelet_delete] Unexpected facelet status"); + return -1; + } - DEBUG("[facemgr_process_delete] Deleting facelet on hicn-light"); - if (interface_on_event(facemgr->hl, facelet) < 0) + if (facemgr_process_facelet(facemgr, facelet) < 0) { + ERROR("[facemgr_process_facelet_delete] Error processing facelet"); return -1; - - /* - * It might be tempting to cache old information, but for now we reset the - * facelet state that might change (such as IP addresses etc). - * netdevice, netdevice_type and admin_state should not be affected. - */ - DEBUG("[facemgr_process_delete] Cleaning cached data"); - facelet_unset_local_addr(facelet); - facelet_unset_local_port(facelet); - facelet_unset_remote_addr(facelet); - facelet_unset_remote_port(facelet); - - facelet_set_status(facelet, FACELET_STATUS_DELETED); - - facelet_unset_bj_done(facelet); + } return 0; } - /** * \brief Process incoming events from interfaces * @@ -1147,37 +1303,41 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) char facelet_s[MAXSZ_FACELET]; facelet_snprintf(facelet_s, MAXSZ_FACELET, facelet_in); - //DEBUG("----------------------------------"); DEBUG("EVENT %s", facelet_s); facelet_t ** cached_facelets = NULL; int n = facelet_cache_lookup(&facemgr->facelet_cache, facelet_in, &cached_facelets); if (n < 0) { ERROR("[facemgr_on_event] Error during cache lookup"); - goto ERR; + free(facelet_in); + return -1; } if (n == 0) { /* This is a new facelet... we expect a CREATE event. */ switch(facelet_get_event(facelet_in)) { case FACELET_EVENT_CREATE: + facelet_set_status(facelet_in, FACELET_STATUS_UNCERTAIN); if (facelet_cache_add(&facemgr->facelet_cache, facelet_in) < 0) { ERROR("[facemgr_on_event] Error adding facelet to cache"); + free(facelet_in); + free(cached_facelets); return -1; } - //DEBUG("Facelet added to cache"); remove_facelet = false; - if (facemgr_process_create(facemgr, facelet_in) < 0) { - ERROR("[facemgr_on_event] Error processing CREATE event"); + if (facemgr_process_facelet_create(facemgr, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error processing facelet CREATE event"); + ret = -1; goto ERR; } + break; case FACELET_EVENT_GET: /* Insert new facelet in cached */ - rc = facemgr_process_get(facemgr, facelet_in); + rc = facemgr_process_facelet_get(facemgr, facelet_in); if (rc == 0) remove_facelet = false; if (rc == -1) { @@ -1227,10 +1387,12 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) ERROR("[facemgr_on_event] Error merging facelets"); continue; } - if (facemgr_process_create(facemgr, facelet) < 0) { - ERROR("[facemgr_on_event] Error processing CREATE event"); + + if (facemgr_process_facelet_create(facemgr, facelet_in) < 0) { + ERROR("[facemgr_on_event] Error processing facelet CREATE event"); ret = -1; } + continue; case FACELET_EVENT_GET: /* should be an INFORM message */ @@ -1245,8 +1407,8 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) ERROR("[facemgr_on_event] Error merging facelets"); continue; } - if (facemgr_process_update(facemgr, facelet) < 0) { - ERROR("[facemgr_on_event] Error processing UPDATE event"); + if (facemgr_process_facelet_update(facemgr, facelet) < 0) { + ERROR("[facemgr_on_event] Error processing facelet UPDATE event"); ret = -1; } continue; @@ -1256,8 +1418,8 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) ERROR("[facemgr_on_event] Error merging facelets"); continue; } - if (facemgr_process_delete(facemgr, facelet) < 0) { - ERROR("[facemgr_on_event] Error processing DELETE event"); + if (facemgr_process_facelet_delete(facemgr, facelet) < 0) { + ERROR("[facemgr_on_event] Error processing facelet DELETE event"); ret = -1; } continue; @@ -1268,7 +1430,6 @@ facemgr_on_event(facemgr_t * facemgr, facelet_t * facelet_in) } } - free(cached_facelets); goto DUMP_CACHE; ERR: @@ -1283,9 +1444,14 @@ DUMP_CACHE: DEBUG("----------------------------------"); #endif + free(cached_facelets); + if (remove_facelet) facelet_free(facelet_in); + if (ret == -1) + facemgr_start_reattempts(facemgr); + return ret; } @@ -1294,18 +1460,62 @@ int facemgr_callback(facemgr_t * facemgr, interface_cb_type_t type, void * data) switch(type) { case INTERFACE_CB_TYPE_RAISE_EVENT: return facemgr_on_event(facemgr, data); + case INTERFACE_CB_TYPE_REGISTER_FD: + { + /* Remember fd for further release */ + fd_callback_data_t * fd_callback_data = data; + interface_t * interface = (interface_t*)(fd_callback_data->owner); + + interface_map_data_t * interface_map_data = NULL; + if (interface_map_get(&facemgr->interface_map, interface->name, &interface_map_data) < 0) { + ERROR("[facemgr_callback] Error getting interface map data"); + return -1; + } + if (!interface_map_data) { + ERROR("[facemgr_callback] No entry in interface map data"); + return -1; + } + interface_map_data->fds[interface_map_data->num_fds++] = fd_callback_data->fd; + return facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_REGISTER_FD, data); + } + + case INTERFACE_CB_TYPE_UNREGISTER_FD: + { + fd_callback_data_t * fd_callback_data = data; + interface_t * interface = (interface_t*)(fd_callback_data->owner); + + interface_map_data_t * interface_map_data = NULL; + if (interface_map_get(&facemgr->interface_map, interface->name, &interface_map_data) < 0) { + ERROR("[facemgr_callback] Error getting interface map data"); + return -1; + } + if (!interface_map_data) { + ERROR("[facemgr_callback] No entry in interface map data"); + return -1; + } + + for (unsigned i = 0; i < interface_map_data->num_fds; i++) { + if (interface_map_data->fds[i] == fd_callback_data->fd) { + interface_map_data->fds[i] = interface_map_data->fds[--interface_map_data->num_fds]; + break; + } + } + + return facemgr->callback(facemgr->callback_owner, + FACEMGR_CB_TYPE_UNREGISTER_FD, data); + } + case INTERFACE_CB_TYPE_REGISTER_TIMER: return facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_REGISTER_TIMER, data); + case INTERFACE_CB_TYPE_UNREGISTER_TIMER: return facemgr->callback(facemgr->callback_owner, FACEMGR_CB_TYPE_UNREGISTER_TIMER, data); - case INTERFACE_CB_TYPE_UNREGISTER_FD: - return facemgr->callback(facemgr->callback_owner, - FACEMGR_CB_TYPE_UNREGISTER_FD, data); + } return -1; } @@ -1497,8 +1707,85 @@ facemgr_set_callback(facemgr_t * facemgr, void * callback_owner, facemgr_cb_t ca facemgr->callback_owner = callback_owner; } -void facemgr_list_faces(facemgr_t * facemgr, facemgr_list_faces_cb_t cb, void * user_data) +void facemgr_list_facelets(const facemgr_t * facemgr, facemgr_list_facelets_cb_t cb, void * user_data) { - //face_cache_iter(&facemgr->face_cache, cb, user_data); - facelet_cache_dump(&facemgr->facelet_cache); + facelet_t ** facelet_array; + if (!cb) + return; + int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array); + if (n < 0) { + ERROR("[facemgr_list_facelets] Could not retrieve facelets in cache"); + return; + } + for (unsigned i = 0; i < n; i++) { + facelet_t * facelet = facelet_array[i]; + cb(facemgr, facelet, user_data); + } + free(facelet_array); +} + +int +facemgr_list_facelets_json(const facemgr_t * facemgr, char ** buffer) +{ + char * cur; + char * s; + int rc; + + facelet_t ** facelet_array; + int n = facelet_cache_get_array(&facemgr->facelet_cache, &facelet_array); + if (n < 0) { + ERROR("[facemgr_list_facelets_json] Could not retrieve facelets in cache"); + return -1; + } + /* This should be enough for JSON overhead, refine later */ + size_t size = 2 * n * MAXSZ_FACELET; + *buffer = malloc(size); + if (!buffer) { + ERROR("[facemgr_list_facelets_json] Could not allocate JSON s"); + free(facelet_array); + return -1; + } + s = *buffer; + cur = s; + + rc = snprintf(cur, s + size - cur, "{\"facelets\": [\n"); + if (rc < 0) + goto ERR; + cur += rc; + if (size != 0 && cur >= s + size) + goto END; + + for (unsigned i = 0; i < n; i++) { + facelet_t * facelet = facelet_array[i]; + + rc = facelet_snprintf_json(cur, s + size - cur, facelet, /* indent */ 1); + if (rc < 0) + goto ERR; + cur += rc; + if (size != 0 && cur >= s + size) + goto END; + + rc = snprintf(cur, s + size - cur, (i == n-1) ? "\n" : ",\n"); + if (rc < 0) + goto ERR; + cur += rc; + if (size != 0 && cur >= s + size) + goto END; + } + free(facelet_array); + + rc = snprintf(cur, s + size - cur, "]}\n"); + if (rc < 0) + goto ERR; + cur += rc; + if (size != 0 && cur >= s + size) + goto END; + +END: + free(facelet_array); + return cur - s; + +ERR: + free(facelet_array); + return rc; } -- cgit 1.2.3-korg