diff --git a/src/pc_pomelo.c b/src/pc_pomelo.c index 51f1fc9..2f9bf6a 100644 --- a/src/pc_pomelo.c +++ b/src/pc_pomelo.c @@ -307,18 +307,18 @@ static void pc__handle_event(pc_client_t* client, pc_event_t* ev) assert(PC_EV_IS_RESP(ev->type) || PC_EV_IS_NOTIFY_SENT(ev->type) || PC_EV_IS_NET_EVENT(ev->type)); if (PC_EV_IS_RESP(ev->type)) { - pc__trans_resp(client, ev->data.req.req_id, ev->data.req.rc, ev->data.req.resp, 0/* not pending */); + pc__trans_resp(client, ev->data.req.req_id, ev->data.req.rc, ev->data.req.resp); pc_lib_log(PC_LOG_DEBUG, "pc__handle_event - fire pending trans resp, req_id: %u, rc: %s", ev->data.req.req_id, pc_client_rc_str(ev->data.req.rc)); pc_lib_free((char* )ev->data.req.resp); ev->data.req.resp = NULL; } else if (PC_EV_IS_NOTIFY_SENT(ev->type)) { - pc__trans_sent(client, ev->data.notify.seq_num, ev->data.notify.rc, 0/* not pending */); + pc__trans_sent(client, ev->data.notify.seq_num, ev->data.notify.rc); pc_lib_log(PC_LOG_DEBUG, "pc__handle_event - fire pending trans sent, seq_num: %u, rc: %s", ev->data.notify.seq_num, pc_client_rc_str(ev->data.notify.rc)); } else { - pc__trans_fire_event(client, ev->data.ev.ev_type, ev->data.ev.arg1, ev->data.ev.arg2, 0/* not pending */); + pc__trans_fire_event(client, ev->data.ev.ev_type, ev->data.ev.arg1, ev->data.ev.arg2); pc_lib_log(PC_LOG_DEBUG, "pc__handle_event - fire pending trans event: %s, arg1: %s", pc_client_ev_str(ev->data.ev.ev_type), ev->data.ev.arg1 ? ev->data.ev.arg1 : ""); pc_lib_free((char* )ev->data.ev.arg1); diff --git a/src/pc_pomelo_i.h b/src/pc_pomelo_i.h index a4ba85a..0d23749 100644 --- a/src/pc_pomelo_i.h +++ b/src/pc_pomelo_i.h @@ -142,9 +142,9 @@ struct pc_client_s { int is_in_poll; }; -void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp, int pending); -void pc__trans_sent(pc_client_t* client, unsigned int req_num, int rc, int pending); -void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2, int pending); +void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp); +void pc__trans_sent(pc_client_t* client, unsigned int req_num, int rc); +void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2); #endif /* PC_POMELO_I_H */ diff --git a/src/pc_trans.c b/src/pc_trans.c index 6a45f0f..f97b345 100644 --- a/src/pc_trans.c +++ b/src/pc_trans.c @@ -11,48 +11,85 @@ #include "pc_lib.h" #include "pc_pomelo_i.h" -void pc_trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2) +struct state_trans_s { + char allowed[PC_ST_COUNT]; + int narg; + int to; +}; + + +#define UNCHANGE_STATE PC_ST_COUNT + +static const struct state_trans_s fsm[PC_EV_COUNT] = { + {{0, 0, 0, 1, 1, 0}, 1, UNCHANGE_STATE}, // PC_EV_USER_DEFINED_PUSH + {{0, 0, 1, 0, 0, 0}, 0, PC_ST_CONNECTED}, // PC_EV_CONNECTED 1 + {{0, 0, 1, 0, 1, 0}, 1, UNCHANGE_STATE}, // PC_EV_CONNECT_ERROR 2 + {{0, 0, 1, 0, 1, 0}, 1, PC_ST_INITED}, // PC_EV_CONNECT_FAILED 3 + {{0, 0, 0, 0, 1, 0}, 0, PC_ST_INITED}, // PC_EV_DISCONNECT 4 + {{0, 0, 0, 1, 1, 0}, 0, PC_ST_INITED}, // PC_EV_KICKED_BY_SERVER 5 + {{0, 0, 1, 1, 1, 0}, 1, PC_ST_INITED}, // PC_EV_UNEXPECTED_DISCONNECT 6 + {{0, 0, 1, 1, 1, 0}, 1, PC_ST_INITED}, // PC_EV_PROTO_ERROR 7 +}; + + +static int state_translate(pc_client_t* client, int ev_type, const char* arg1, const char* arg2) { - int pending = 0; + int from; + if (ev_type >= PC_EV_COUNT || ev_type < 0) { + pc_lib_log(PC_LOG_ERROR, "state_translate - error event type"); + return 0; + } - if (!client) { - pc_lib_log(PC_LOG_ERROR, "pc_client_fire_event - client is null"); - return ; + pc_mutex_lock(&client->state_mutex); + from = client->state; + +#define RETURN_IF(cond, ...) if (cond) { \ + pc_mutex_unlock(&client->state_mutex); \ + pc_lib_log(PC_LOG_ERROR, "state_translate - " __VA_ARGS__); \ + return 0; \ } - if (client->config.enable_polling) { - pending = 1; + RETURN_IF(from >= PC_ST_COUNT || from < 0, "error client state: %s", pc_client_state_str(from)); + RETURN_IF(!fsm[ev_type].allowed[from], "client in %s not allow fires %s", pc_client_state_str(from), pc_client_ev_str(ev_type)); + switch (fsm[ev_type].narg) { + case 2: + RETURN_IF(arg2 == NULL, "to fire %s requires arg2 != NULL", pc_client_ev_str(ev_type)); // fall through + case 1: + RETURN_IF(arg1 == NULL, "to fire %s requires arg1 != NULL", pc_client_ev_str(ev_type)); // fall through } +#undef RETURN_IF - pc__trans_fire_event(client, ev_type, arg1, arg2, pending); + if (fsm[ev_type].to != UNCHANGE_STATE) { + client->state = fsm[ev_type].to; + } + pc_mutex_unlock(&client->state_mutex); + return 1; } -void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2, int pending) -{ - QUEUE* q; - pc_ev_handler_t* handler; - pc_event_t* ev; - int i; +static void pc__trans_queue_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2); - if (ev_type >= PC_EV_COUNT || ev_type < 0) { - pc_lib_log(PC_LOG_ERROR, "pc__transport_fire_event - error event type"); - return; +void pc_trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2) +{ + if (!client) { + pc_lib_log(PC_LOG_ERROR, "pc_client_fire_event - client is null"); + return ; } - if (ev_type == PC_EV_USER_DEFINED_PUSH && (!arg1 || !arg2)) { - pc_lib_log(PC_LOG_ERROR, "pc__transport_fire_event - push msg but without a route or msg"); + if (!state_translate(client, ev_type, arg1, arg2)) return; - } - if (ev_type == PC_EV_CONNECT_ERROR || ev_type == PC_EV_UNEXPECTED_DISCONNECT - || ev_type == PC_EV_PROTO_ERROR || ev_type == PC_EV_CONNECT_FAILED) { - if (!arg1) { - pc_lib_log(PC_LOG_ERROR, "pc__transport_fire_event - event should be with a reason description"); - return ; - } - } + if (client->config.enable_polling) + pc__trans_queue_event(client, ev_type, arg1, arg2); + else + pc__trans_fire_event(client, ev_type, arg1, arg2); +} - if (pending) { +void pc__trans_queue_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2) +{ + pc_event_t* ev; + int i; + + // follow code has extra indent for better git diff in pull request. assert(client->config.enable_polling); pc_lib_log(PC_LOG_INFO, "pc__trans_fire_event - add pending event: %s", pc_client_ev_str(ev_type)); @@ -94,53 +131,15 @@ void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, co } pc_mutex_unlock(&client->event_mutex); +} - return ; - } +void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, const char* arg2) +{ + QUEUE* q; + pc_ev_handler_t* handler; pc_lib_log(PC_LOG_INFO, "pc__trans_fire_event - fire event: %s, arg1: %s, arg2: %s", pc_client_ev_str(ev_type), arg1 ? arg1 : "", arg2 ? arg2 : ""); - pc_mutex_lock(&client->state_mutex); - switch(ev_type) { - case PC_EV_CONNECTED: - assert(client->state == PC_ST_CONNECTING); - client->state = PC_ST_CONNECTED; - break; - - case PC_EV_CONNECT_ERROR: - assert(client->state == PC_ST_CONNECTING || client->state == PC_ST_DISCONNECTING); - break; - - case PC_EV_CONNECT_FAILED: - assert(client->state == PC_ST_CONNECTING || client->state == PC_ST_DISCONNECTING); - client->state = PC_ST_INITED; - break; - - case PC_EV_DISCONNECT: - assert(client->state == PC_ST_DISCONNECTING); - client->state = PC_ST_INITED; - break; - - case PC_EV_KICKED_BY_SERVER: - assert(client->state == PC_ST_CONNECTED || client->state == PC_ST_DISCONNECTING); - client->state = PC_ST_INITED; - break; - - case PC_EV_UNEXPECTED_DISCONNECT: - case PC_EV_PROTO_ERROR: - assert(client->state == PC_ST_CONNECTING || client->state == PC_ST_CONNECTED - || client->state == PC_ST_DISCONNECTING); - client->state = PC_ST_CONNECTING; - break; - case PC_EV_USER_DEFINED_PUSH: - /* do nothing here */ - break; - - default: - /* never run to here */ - pc_lib_log(PC_LOG_ERROR, "pc__trans_fire_event - unknown network event: %d", ev_type); - } - pc_mutex_unlock(&client->state_mutex); /* invoke handler */ pc_mutex_lock(&client->handler_mutex); @@ -152,30 +151,27 @@ void pc__trans_fire_event(pc_client_t* client, int ev_type, const char* arg1, co pc_mutex_unlock(&client->handler_mutex); } +static void pc__trans_queue_sent(pc_client_t* client, unsigned int seq_num, int rc); void pc_trans_sent(pc_client_t* client, unsigned int seq_num, int rc) { - int pending = 0; - if (!client) { pc_lib_log(PC_LOG_ERROR, "pc_trans_sent - client is null"); return ; } if (client->config.enable_polling) { - pending = 1; + pc__trans_queue_sent(client, seq_num, rc); + } else { + pc__trans_sent(client, seq_num, rc); } - pc__trans_sent(client, seq_num, rc, pending); } -void pc__trans_sent(pc_client_t* client, unsigned int seq_num, int rc, int pending) +void pc__trans_queue_sent(pc_client_t* client, unsigned int seq_num, int rc) { - QUEUE* q; - pc_notify_t* notify; - pc_notify_t* target; pc_event_t* ev; int i; - if (pending) { + // follow code has extra indent for better git diff in pull request. pc_mutex_lock(&client->event_mutex); pc_lib_log(PC_LOG_INFO, "pc__trans_sent - add pending sent event, seq_num: %u, rc: %s", @@ -205,9 +201,13 @@ void pc__trans_sent(pc_client_t* client, unsigned int seq_num, int rc, int pendi QUEUE_INSERT_TAIL(&client->pending_ev_queue, &ev->queue); pc_mutex_unlock(&client->event_mutex); +} - return ; - } +void pc__trans_sent(pc_client_t* client, unsigned int seq_num, int rc) +{ + QUEUE* q; + pc_notify_t* notify; + pc_notify_t* target; /* callback immediately */ pc_mutex_lock(&client->notify_mutex); @@ -251,31 +251,28 @@ void pc__trans_sent(pc_client_t* client, unsigned int seq_num, int rc, int pendi } } +static void pc__trans_queue_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp); + void pc_trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp) { - int pending = 0; - if (!client) { pc_lib_log(PC_LOG_ERROR, "pc_trans_resp - client is null"); return ; } if (client->config.enable_polling) { - pending = 1; + pc__trans_queue_resp(client, req_id, rc, resp); + } else { + pc__trans_resp(client, req_id, rc, resp); } - - pc__trans_resp(client, req_id, rc, resp, pending); } -void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp, int pending) +void pc__trans_queue_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp) { - QUEUE* q; - pc_request_t* req; pc_event_t* ev; - pc_request_t* target; int i; - if (pending) { + // follow code has extra indent for better git diff in pull request. pc_mutex_lock(&client->event_mutex); pc_lib_log(PC_LOG_INFO, "pc__trans_resp - add pending resp event, req_id: %u, rc: %s", @@ -306,8 +303,13 @@ void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char QUEUE_INSERT_TAIL(&client->pending_ev_queue, &ev->queue); pc_mutex_unlock(&client->event_mutex); - return ; - } +} + +void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char* resp) +{ + QUEUE* q; + pc_request_t* req; + pc_request_t* target; /* invoke callback immediately */ target = NULL; @@ -350,4 +352,3 @@ void pc__trans_resp(pc_client_t* client, unsigned int req_id, int rc, const char " get a response, req id: %u", req_id); } } -