diff options
Diffstat (limited to 'src/amps/transaction.c')
-rw-r--r-- | src/amps/transaction.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/amps/transaction.c b/src/amps/transaction.c new file mode 100644 index 0000000..d9083eb --- /dev/null +++ b/src/amps/transaction.c @@ -0,0 +1,192 @@ +/* C-Netz transaction handling + * + * (C) 2016 by Andreas Eversberg <jolly@eversberg.eu> + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include "../common/debug.h" +#include "../common/timer.h" +#include "amps.h" +//#include "database.h" + +static const char *trans_state_name(int state) +{ + switch (state) { + case 0: + return "IDLE"; + case TRANS_REGISTER_ACK: + return "REGISTER ACK"; + case TRANS_REGISTER_ACK_SEND: + return "REGISTER ACK SEND"; + case TRANS_CALL_MO_ASSIGN: + return "CALL ASSIGN MOBILE ORIGINATING"; + case TRANS_CALL_MO_ASSIGN_SEND: + return "CALL ASSIGN MOBILE ORIGINATING SEND"; + case TRANS_CALL_MT_ASSIGN: + return "CALL ASSIGN MOBILE TERMINATING"; + case TRANS_CALL_MT_ASSIGN_SEND: + return "CALL ASSIGN MOBILE TERMINATING SEND"; + case TRANS_CALL_MT_ALERT: + return "CALL ALERT MOBILE TERMINATING"; + case TRANS_CALL_REJECT: + return "CALL REJECT"; + case TRANS_CALL_REJECT_SEND: + return "CALL REJECT SEND"; + case TRANS_CALL: + return "CALL"; + case TRANS_CALL_RELEASE: + return "CALL RELEASE"; + case TRANS_CALL_RELEASE_SEND: + return "CALL RELEASE SEND"; + case TRANS_PAGE: + return "PAGE"; + case TRANS_PAGE_SEND: + return "PAGE SEND"; + case TRANS_PAGE_REPLY: + return "PAGE REPLY"; + default: + return "<invald transaction state>"; + } +} + +/* create transaction */ +transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uint32_t min1, uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order, uint16_t chan) +{ + transaction_t *trans; + + /* search transaction for this subsriber */ + trans = search_transaction_number(amps, min1, min2); + if (trans) { + const char *number = amps_min2number(trans->min1, trans->min2); + PDEBUG(DTRANS, DEBUG_NOTICE, "Found alredy pending transaction for subscriber '%s', deleting!\n", number); + destroy_transaction(trans); + } + + trans = calloc(1, sizeof(*trans)); + if (!trans) { + PDEBUG(DTRANS, DEBUG_ERROR, "No memory!\n"); + return NULL; + } + + timer_init(&trans->timer, transaction_timeout, trans); + + trans_new_state(trans, state); + trans->min1 = min1; + trans->min2 = min2; + trans->msg_type = msg_type; + trans->ordq = ordq; + trans->order = order; + trans->chan = chan; + + const char *number = amps_min2number(trans->min1, trans->min2); + PDEBUG(DTRANS, DEBUG_INFO, "Created transaction '%s' for subscriber '%s'\n", number, trans_state_name(state)); + + link_transaction(trans, amps); + + /* update database: now busy */ +// update_db(amps, min1, min2, 1, 0); + + return trans; +} + +/* destroy transaction */ +void destroy_transaction(transaction_t *trans) +{ + /* update database: now idle */ +// update_db(trans->amps, trans->min1, trans->min2, 0, trans->ma_failed); + + unlink_transaction(trans); + + const char *number = amps_min2number(trans->min1, trans->min2); + PDEBUG(DTRANS, DEBUG_INFO, "Destroying transaction for subscriber '%s'\n", number); + + timer_exit(&trans->timer); + + trans_new_state(trans, 0); + + free(trans); +} + +/* link transaction to list */ +void link_transaction(transaction_t *trans, amps_t *amps) +{ + transaction_t **transp; + + /* attach to end of list, so first transaction is served first */ + trans->amps = amps; + transp = &s->trans_list; + while (*transp) + transp = &((*transp)->next); + *transp = trans; +} + +/* unlink transaction from list */ +void unlink_transaction(transaction_t *trans) +{ + transaction_t **transp; + + /* unlink */ + transp = &trans->amps->trans_list; + while (*transp && *transp != trans) + transp = &((*transp)->next); + if (!(*transp)) { + PDEBUG(DTRANS, DEBUG_ERROR, "Transaction not in list, please fix!!\n"); + abort(); + } + *transp = trans->next; + trans->amps = NULL; +} + +transaction_t *search_transaction_number(amps_t *amps, uint32_t min1, uint16_t min2) +{ + transaction_t *trans = amps->trans_list; + + while (trans) { + if (trans->min1 == min1 + && trans->min2 == min2) { + const char *number = amps_min2number(trans->min1, trans->min2); + PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", number); + return trans; + } + trans = trans->next; + } + + return NULL; +} + +void trans_new_state(transaction_t *trans, int state) +{ + PDEBUG(DTRANS, DEBUG_INFO, "Transaction state %s -> %s\n", trans_state_name(trans->state), trans_state_name(state)); + trans->state = state; +} + +void amps_flush_other_transactions(amps_t *amps, transaction_t *trans) +{ + /* flush after this very trans */ + while (trans->next) { + PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n"); + destroy_transaction(trans); + } + /* flush before this very trans */ + while (amps->trans_list != trans) { + PDEBUG(DTRANS, DEBUG_NOTICE, "Kicking other pending transaction\n"); + destroy_transaction(amps->trans_list); + } +} + |