static int rtr_handle_cache_response_pdu(struct rtr_socket *rtr_socket, char *pdu) { RTR_DBG1("Cache Response PDU received"); struct pdu_cache_response *cr_pdu = (struct pdu_cache_response *) pdu; //set connection session_id if (rtr_socket->request_session_id) { if (rtr_socket->last_update != 0) { //if this isnt the first sync, but we already received records, delete old records in the pfx_table pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); spki_table_src_remove(rtr_socket->spki_table, rtr_socket); rtr_socket->last_update = 0; } rtr_socket->session_id = cr_pdu->session_id; } else { if (rtr_socket->session_id != cr_pdu->session_id) { const char txt[] = "Wrong session_id in Cache Response PDU"; //TODO: Appendrtr_socket->session_id to string rtr_send_error_pdu(rtr_socket, NULL, 0, CORRUPT_DATA, txt, sizeof(txt)); rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); return RTR_ERROR; } } return RTR_SUCCESS; }
void rtr_purge_outdated_records(struct rtr_socket *rtr_socket) { if(rtr_socket->last_update == 0) return; time_t cur_time; int rtval = lrtr_get_monotonic_time(&cur_time); if(rtval == -1 || (rtr_socket->last_update + rtr_socket->expire_interval) < cur_time) { if(rtval == -1) RTR_DBG1("get_monotic_time(..) failed"); pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); RTR_DBG1("Removed outdated records from pfx_table"); spki_table_src_remove(rtr_socket->spki_table, rtr_socket); RTR_DBG1("Removed outdated router keys from spki_table"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_socket->last_update = 0; } }
void rtr_stop(struct rtr_socket *rtr_socket) { RTR_DBG1("rtr_stop()"); rtr_change_socket_state(rtr_socket, RTR_SHUTDOWN); if(rtr_socket->thread_id != 0) { RTR_DBG1("pthread_cancel()"); pthread_cancel(rtr_socket->thread_id); RTR_DBG1("pthread_join()"); pthread_join(rtr_socket->thread_id, NULL); tr_close(rtr_socket->tr_socket); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_socket->last_update = 0; pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); spki_table_src_remove(rtr_socket->spki_table, rtr_socket); rtr_socket->thread_id = 0; } RTR_DBG1("Socket shut down"); }
int rtr_sync_receive_and_store_pdus(struct rtr_socket *rtr_socket){ char pdu[RTR_MAX_PDU_LEN]; enum pdu_type type; int retval = RTR_SUCCESS; struct pdu_ipv6 *ipv6_pdus = NULL; unsigned int ipv6_pdus_nindex = 0; //next free index in ipv6_pdus unsigned int ipv6_pdus_size = 0; struct pdu_ipv4 *ipv4_pdus = NULL; unsigned int ipv4_pdus_size = 0; //next free index in ipv4_pdus unsigned int ipv4_pdus_nindex = 0; struct pdu_router_key *router_key_pdus = NULL; unsigned int router_key_pdus_size = 0; unsigned int router_key_pdus_nindex = 0; //receive LRTR_IPV4/IPV6 PDUs till EOD do { retval = rtr_receive_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, RTR_RECV_TIMEOUT); if (retval == TR_WOULDBLOCK) { rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT); retval = RTR_ERROR; goto cleanup; } else if (retval < 0) { retval = RTR_ERROR; goto cleanup; } type = rtr_get_pdu_type(pdu); if (type == IPV4_PREFIX) { if (rtr_store_prefix_pdu(rtr_socket, pdu, sizeof(*ipv4_pdus), (void **) &ipv4_pdus, &ipv4_pdus_nindex, &ipv4_pdus_size) == RTR_ERROR){ rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } else if (type == IPV6_PREFIX) { if (rtr_store_prefix_pdu(rtr_socket, pdu, sizeof(*ipv6_pdus), (void **) &ipv6_pdus, &ipv6_pdus_nindex, &ipv6_pdus_size) == RTR_ERROR){ rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } else if (type == ROUTER_KEY) { if (rtr_store_router_key_pdu(rtr_socket, pdu, sizeof(*router_key_pdus), &router_key_pdus, &router_key_pdus_nindex, &router_key_pdus_size) == RTR_ERROR){ rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } else if (type == EOD) { RTR_DBG1("EOD PDU received."); struct pdu_end_of_data_v0 *eod_pdu = (struct pdu_end_of_data_v0 *) pdu; if (eod_pdu->session_id != rtr_socket->session_id) { char txt[67]; snprintf(txt, sizeof(txt),"Expected session_id: %u, received session_id. %u in EOD PDU",rtr_socket->session_id, eod_pdu->session_id); rtr_send_error_pdu(rtr_socket, pdu, RTR_MAX_PDU_LEN, CORRUPT_DATA, txt, strlen(txt) + 1); rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } if (eod_pdu->ver == RTR_PROTOCOL_VERSION_1) { rtr_socket->expire_interval = ((struct pdu_end_of_data_v1 *) pdu)->expire_interval; rtr_socket->refresh_interval = ((struct pdu_end_of_data_v1 *) pdu)->refresh_interval; rtr_socket->retry_interval = ((struct pdu_end_of_data_v1 *) pdu)->retry_interval; RTR_DBG("New interval values: expire_interval:%u, refresh_interval:%u, retry_interval:%u", rtr_socket->expire_interval, rtr_socket->refresh_interval, rtr_socket->retry_interval); } int retval = PFX_SUCCESS; //add all IPv4 prefix pdu to the pfx_table for (unsigned int i = 0; i < ipv4_pdus_nindex; i++) { if (rtr_update_pfx_table(rtr_socket, &(ipv4_pdus[i])) == PFX_ERROR) { //undo all record updates, except the last which produced the error RTR_DBG("Error during data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number); for (unsigned int j = 0; j < i && retval == PFX_SUCCESS; j++) retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j])); if (retval == RTR_ERROR) { RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all records"); pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); rtr_socket->request_session_id = true; } rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } //add all IPv6 prefix pdu to the pfx_table for (unsigned int i = 0; i < ipv6_pdus_nindex; i++) { if (rtr_update_pfx_table(rtr_socket, &(ipv6_pdus[i])) == PFX_ERROR) { //undo all record updates if error occured RTR_DBG("Error during data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number); for (unsigned int j = 0; j < ipv4_pdus_nindex && retval == PFX_SUCCESS; j++) retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j])); for (unsigned int j = 0; j < i && retval == PFX_SUCCESS; j++) retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv6_pdus[j])); if (retval == PFX_ERROR) { RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all records"); pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); rtr_socket->request_session_id = true; } rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } //add all router key pdu to the spki_table for (unsigned int i = 0; i < router_key_pdus_nindex; i++) { if (rtr_update_spki_table(rtr_socket, &(router_key_pdus[i])) == SPKI_ERROR) { RTR_DBG("Error during router key data synchronisation, recovering Serial Nr. %u state",rtr_socket->serial_number); for (unsigned int j = 0; j < ipv4_pdus_nindex && retval == PFX_SUCCESS; j++) retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv4_pdus[j])); for (unsigned int j = 0; j < ipv6_pdus_nindex && retval == PFX_SUCCESS; j++) retval = rtr_undo_update_pfx_table(rtr_socket, &(ipv6_pdus[j])); // cppcheck-suppress duplicateExpression for (unsigned int j = 0; j < i && (retval == PFX_SUCCESS || retval == SPKI_SUCCESS); j++) retval = rtr_undo_update_spki_table(rtr_socket, &(router_key_pdus[j])); // cppcheck-suppress duplicateExpression if (retval == RTR_ERROR || retval == SPKI_ERROR) { RTR_DBG1("Couldn't undo all update operations from failed data synchronisation: Purging all key entries"); spki_table_src_remove(rtr_socket->spki_table, rtr_socket); rtr_socket->request_session_id = true; } rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); retval = RTR_ERROR; goto cleanup; } } rtr_socket->serial_number = eod_pdu->sn; RTR_DBG("Sync successfull, received %u Prefix PDUs, %u Router Key PDUs, session_id: %u, SN: %u", (ipv4_pdus_nindex + ipv6_pdus_nindex), router_key_pdus_nindex,rtr_socket->session_id,rtr_socket->serial_number); goto cleanup; } else if (type == ERROR) { rtr_handle_error_pdu(rtr_socket, pdu); retval = RTR_ERROR; goto cleanup; } else if (type == SERIAL_NOTIFY) { RTR_DBG1("Ignoring Serial Notify"); } else { RTR_DBG("Received unexpected PDU (Type: %u)", ((struct pdu_header *) pdu)->type); const char txt[] = "Unexpected PDU received during data synchronisation"; rtr_send_error_pdu(rtr_socket, pdu, sizeof(struct pdu_header), CORRUPT_DATA, txt, sizeof(txt)); retval = RTR_ERROR; goto cleanup; } } while (type != EOD); cleanup: free(router_key_pdus); free(ipv6_pdus); free(ipv4_pdus); return retval; }
void rtr_fsm_start(struct rtr_socket *rtr_socket) { rtr_socket->state = RTR_CONNECTING; install_sig_handler(); while(1) { if(rtr_socket->state == RTR_CONNECTING) { RTR_DBG1("State: RTR_CONNECTING"); rtr_socket->has_received_pdus = false; //old pfx_record could exists in the pfx_table, check if they are too old and must be removed //old key_entry could exists in the spki_table, check if they are too old and must be removed rtr_purge_outdated_records(rtr_socket); if(tr_open(rtr_socket->tr_socket) == TR_ERROR) { rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT); } else if(rtr_socket->request_session_id) { //change to state RESET, if socket dont has a session_id rtr_change_socket_state(rtr_socket, RTR_RESET); } else { //if we already have a session_id, send a serial query and start to sync if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); else rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); } } else if(rtr_socket->state == RTR_RESET) { RTR_DBG1("State: RTR_RESET"); if (rtr_send_reset_query(rtr_socket) == RTR_SUCCESS) { RTR_DBG1("rtr_start: reset pdu sent"); rtr_change_socket_state(rtr_socket, RTR_SYNC); //start to sync after connection is established } } else if(rtr_socket->state == RTR_SYNC) { RTR_DBG1("State: RTR_SYNC"); if(rtr_sync(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_ESTABLISHED); //wait for next sync after first successful sync } else if(rtr_socket->state == RTR_ESTABLISHED) { RTR_DBG1("State: RTR_ESTABLISHED"); if(rtr_wait_for_sync(rtr_socket) == RTR_SUCCESS) { //blocks till expire_interval is expired or PDU was received //send serial query if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); } } else if(rtr_socket->state == RTR_FAST_RECONNECT) { RTR_DBG1("State: RTR_FAST_RECONNECT"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); } else if(rtr_socket->state == RTR_ERROR_NO_DATA_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_DATA_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); sleep(rtr_socket->retry_interval); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_NO_INCR_UPDATE_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_INCR_UPDATE_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_TRANSPORT) { RTR_DBG1("State: RTR_ERROR_TRANSPORT"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); RTR_DBG("Waiting %u", rtr_socket->retry_interval); sleep(rtr_socket->retry_interval); } else if(rtr_socket->state == RTR_ERROR_FATAL) { RTR_DBG1("State: RTR_ERROR_FATAL"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); RTR_DBG("Waiting %u", rtr_socket->retry_interval); sleep(rtr_socket->retry_interval); } else if(rtr_socket->state == RTR_SHUTDOWN) { RTR_DBG1("State: RTR_SHUTDOWN"); tr_close(rtr_socket->tr_socket); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_socket->last_update = 0; pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); spki_table_src_remove(rtr_socket->spki_table, rtr_socket); pthread_exit(NULL); } } }