#include #include #include "log_internal.h" #include "session_internal.h" #include "session_transition.h" #define SESSION_TRANSITION_LOG_INFO(format, ...) STELLAR_LOG_INFO(__thread_local_logger, "session transition", format, ##__VA_ARGS__) #define MAX_TRANSITION_PER_STATE 8 struct session_transition { int inputs_mask; enum session_state next_state; } fsm[MAX_STATE][MAX_TRANSITION_PER_STATE]; /* * session transition * * SESSION_STATE_INIT -> SESSION_STATE_INIT ( NONE ) * SESSION_STATE_INIT -> SESSION_STATE_OPENING ( TCP_SYN | TCP_SYN_ACK | UDP_DATA ) * * SESSION_STATE_OPENING -> SESSION_STATE_OPENING ( NONE ) * SESSION_STATE_OPENING -> SESSION_STATE_ACTIVE ( TCP_DATA | UDP_DATA ) * SESSION_STATE_OPENING -> SESSION_STATE_CLOSING ( TCP_FIN | TCP_RST | TIMEOUT ) * SESSION_STATE_OPENING -> SESSION_STATE_DISCARD ( USER_CLOSE ) * SESSION_STATE_OPENING -> SESSION_STATE_CLOSED ( LRU_EVICT | PORT_REUSE_EVICT ) * * SESSION_STATE_ACTIVE -> SESSION_STATE_ACTIVE ( NONE ) * SESSION_STATE_ACTIVE -> SESSION_STATE_CLOSING ( TCP_FIN | TCP_RST | TIMEOUT ) * SESSION_STATE_ACTIVE -> SESSION_STATE_DISCARD ( USER_CLOSE ) * SESSION_STATE_ACTIVE -> SESSION_STATE_CLOSED ( LRU_EVICT | PORT_REUSE_EVICT) * * SESSION_STATE_CLOSING -> SESSION_STATE_CLOSING ( NONE ) * SESSION_STATE_CLOSING -> SESSION_STATE_DISCARD ( USER_CLOSE ) * SESSION_STATE_CLOSING -> SESSION_STATE_CLOSED ( LRU_EVICT | PORT_REUSE_EVICT | TIMEOUT ) * * SESSION_STATE_DISCARD -> SESSION_STATE_DISCARD ( NONE ) * SESSION_STATE_DISCARD -> SESSION_STATE_CLOSED ( LRU_EVICT | PORT_REUSE_EVICT | TIMEOUT ) */ static void session_inputs_to_str(int inputs, char *buff, int len) { int nused = 0; if (inputs & TCP_SYN) { nused += snprintf(buff + nused, len - nused, "TCP_SYN"); } if (inputs & TCP_SYN_ACK) { nused += snprintf(buff + nused, len - nused, "TCP_SYN_ACK"); } if (inputs & TCP_FIN) { nused += snprintf(buff + nused, len - nused, "TCP_FIN"); } if (inputs & TCP_RST) { nused += snprintf(buff + nused, len - nused, "TCP_RST"); } if (inputs & TCP_DATA) { nused += snprintf(buff + nused, len - nused, "TCP_DATA"); } if (inputs & UDP_DATA) { nused += snprintf(buff + nused, len - nused, "UDP_DATA"); } if (inputs & TIMEOUT) { nused += snprintf(buff + nused, len - nused, "TIMEOUT"); } if (inputs & LRU_EVICT) { nused += snprintf(buff + nused, len - nused, "LRU_EVICT"); } if (inputs & PORT_REUSE_EVICT) { nused += snprintf(buff + nused, len - nused, "PORT_REUSE_EVICT"); } if (inputs & USER_CLOSE) { nused += snprintf(buff + nused, len - nused, "USER_CLOSE"); } } void session_transition_init() { fsm[SESSION_STATE_INIT][0].inputs_mask = TCP_SYN | TCP_SYN_ACK | UDP_DATA; fsm[SESSION_STATE_INIT][0].next_state = SESSION_STATE_OPENING; fsm[SESSION_STATE_INIT][1].inputs_mask = NONE; fsm[SESSION_STATE_INIT][1].next_state = SESSION_STATE_INIT; fsm[SESSION_STATE_OPENING][0].inputs_mask = TCP_DATA | UDP_DATA; fsm[SESSION_STATE_OPENING][0].next_state = SESSION_STATE_ACTIVE; fsm[SESSION_STATE_OPENING][1].inputs_mask = TCP_FIN | TCP_RST | TIMEOUT; fsm[SESSION_STATE_OPENING][1].next_state = SESSION_STATE_CLOSING; fsm[SESSION_STATE_OPENING][2].inputs_mask = USER_CLOSE; fsm[SESSION_STATE_OPENING][2].next_state = SESSION_STATE_DISCARD; fsm[SESSION_STATE_OPENING][3].inputs_mask = LRU_EVICT | PORT_REUSE_EVICT; fsm[SESSION_STATE_OPENING][3].next_state = SESSION_STATE_CLOSED; fsm[SESSION_STATE_OPENING][4].inputs_mask = NONE; fsm[SESSION_STATE_OPENING][4].next_state = SESSION_STATE_OPENING; fsm[SESSION_STATE_ACTIVE][0].inputs_mask = TCP_FIN | TCP_RST | TIMEOUT; fsm[SESSION_STATE_ACTIVE][0].next_state = SESSION_STATE_CLOSING; fsm[SESSION_STATE_ACTIVE][1].inputs_mask = USER_CLOSE; fsm[SESSION_STATE_ACTIVE][1].next_state = SESSION_STATE_DISCARD; fsm[SESSION_STATE_ACTIVE][2].inputs_mask = LRU_EVICT | PORT_REUSE_EVICT; fsm[SESSION_STATE_ACTIVE][2].next_state = SESSION_STATE_CLOSED; fsm[SESSION_STATE_ACTIVE][3].inputs_mask = NONE; fsm[SESSION_STATE_ACTIVE][3].next_state = SESSION_STATE_ACTIVE; fsm[SESSION_STATE_CLOSING][0].inputs_mask = USER_CLOSE; fsm[SESSION_STATE_CLOSING][0].next_state = SESSION_STATE_DISCARD; fsm[SESSION_STATE_CLOSING][1].inputs_mask = LRU_EVICT | PORT_REUSE_EVICT | TIMEOUT; fsm[SESSION_STATE_CLOSING][1].next_state = SESSION_STATE_CLOSED; fsm[SESSION_STATE_CLOSING][2].inputs_mask = NONE; fsm[SESSION_STATE_CLOSING][2].next_state = SESSION_STATE_CLOSING; fsm[SESSION_STATE_DISCARD][0].inputs_mask = LRU_EVICT | PORT_REUSE_EVICT | TIMEOUT; fsm[SESSION_STATE_DISCARD][0].next_state = SESSION_STATE_CLOSED; fsm[SESSION_STATE_DISCARD][1].inputs_mask = NONE; fsm[SESSION_STATE_DISCARD][1].next_state = SESSION_STATE_DISCARD; } enum session_state session_transition_run(enum session_state curr_state, int inputs) { struct session_transition *list = fsm[curr_state]; for (int i = 0; i < MAX_TRANSITION_PER_STATE; i++) { int mask = list[i].inputs_mask; if (mask & inputs) { return list[i].next_state; } if (mask == NONE) { return list[i].next_state; } } assert(0); return curr_state; } void session_transition_log(struct session *sess, enum session_state curr_state, enum session_state next_state, int inputs) { if (curr_state == next_state) { return; } char reason[128] = {0}; session_inputs_to_str(inputs, reason, sizeof(reason)); SESSION_TRANSITION_LOG_INFO("%s session %lu %s (%s) %s -> %s", session_type_to_str(session_get_type(sess)), session_get_id(sess), session_get_readable_addr(sess), reason, session_state_to_str(curr_state), session_state_to_str(next_state)); }