/*=============================================================================
**
** Copyright (C) 2013 sunnada, Inc. All Rights Reserved.
**
** lsm_server.c -- LSM server.
**
** Author: xieww@sunnada.net
*/
#include "syd_thread/syd_thread.h"
#include "lsm_server.h"
#include "lsm_debug.h"
#include "lsm.h"
/* Call back function to read LSM message body. */
int lsm_server_read_msg(struct message_handler *ms, struct message_entry *me,
pal_sock_handle_t sock) {
int ret;
int type;
int nbytes;
struct lsm_server *ls;
struct lsm_server_entry *lse;
struct lsm_msg_header header;
/* Get LSM server entry from message entry. */
lse = me->info;
ls = lse->ls;
/* Reset parser pointer and size. */
lse->recv.pnt = lse->recv.buf;
lse->recv.size = 0;
/* Read LSM message header. */
nbytes = readn(sock, lse->recv.buf, LSM_MSG_HEADER_SIZE);
/* Let message handler to handle disconnect event. */
if (nbytes <= 0) {
return -1;
}
/* Check header length. If length is smaller than LSM message
* header size close the connection. */
if (nbytes != LSM_MSG_HEADER_SIZE) {
DEBUG_LSM_ERROR ("LSM: msg length[%d] is smaller thar lsm message.\n", nbytes);
return -1;
}
/* Record read size. */
lse->recv.size = nbytes;
/* Parse LSM message header. */
ret = lsm_decode_header(&lse->recv.pnt, &lse->recv.size, &header);
if (ret < 0) {
printf ("LSM: failed to parse lsm message header.\n");
return -1;
}
/*消息长度大于缓冲区大小, 直接返回 */
if (header.length > LSM_MESSAGE_MAX_LEN) {
assert(0);
return -1;
}
/* Dump LSM header. */
if (IS_LSM_DEBUG_RECV) {
lsm_header_dump(&header);
}
/* Reset parser pointer and size. */
lse->recv.pnt = lse->recv.buf;
lse->recv.size = 0;
/* Read LSM message body. */
nbytes = readn(sock, lse->recv.pnt, header.length - LSM_MSG_HEADER_SIZE);
/* Let message handler to handle disconnect event. */
if (nbytes <= 0) {
printf ("LSM: client is disconnect to lsm when to read body msg.\n");
return -1;
}
/* Record read size. */
lse->recv.size = nbytes;
type = header.type;
/* Increment counter. */
lse->recv_msg_count++;
/* Put last read type. */
lse->last_read_type = type;
/* Invoke call back function. */
if (type < LSM_MSG_MAX && ls->parser[type] && ls->callback[type]) {
ret = (*ls->parser[type]) (&lse->recv.pnt, &lse->recv.size, &header, lse,
ls->callback[type]);
if (ret < 0) {
DEBUG_LSM_ERROR ("LSM: error to parse callback function.\n");
return ret;
}
}
return nbytes;
}
/* Set protocol version. */
void lsm_server_set_version(struct lsm_server *ls, u_int16_t version) {
ls->service.version = version;
}
/* Set protocol ID. */
void lsm_server_set_protocol(struct lsm_server *ls, u_int32_t protocol_id) {
ls->service.protocol_id = protocol_id;
}
/* Set service type flag. */
int lsm_server_set_service(struct lsm_server *ls, int service)
{
if (service >= LSM_SERVICE_MAX)
return LSM_ERR_INVALID_SERVICE;
SET_FLAG(ls->service.bits, (1 << service));
return 0;
}
/* Unset service type flag. */
int lsm_server_unset_service(struct lsm_server *ls, int service)
{
if (service >= LSM_SERVICE_MAX)
return LSM_ERR_INVALID_SERVICE;
UNSET_FLAG(ls->service.bits, (1 << service));
return 0;
}
void lsm_server_clear_lse(struct lsm_server_entry *lse)
{
struct lsm_master *lm;
struct lsm_server *ls;
struct lsm_server_client *lsc;
struct route_node *rn;
struct interface *ifp;
u_int32_t i;
if (lse == NULL) {
return;
}
ls = lse->ls;
/* Figure out LSM client which lse belongs to. */
lsc = lse->lsc;
if (lsc == NULL) {
DEBUG_LSM_EVENT ("LSM: LSM client disconnect");
lsm_server_entry_free(lse);
return;
}
/* Logging. */
DEBUG_LSM_EVENT ("LSM: LSM client ID %d disconnect", lse->service.client_id);
/* Remove lse from linked list. */
if (lse->prev)
lse->prev->next = lse->next;
else
lsc->head = lse->next;
if (lse->next)
lse->next->prev = lse->prev;
else
lsc->tail = lse->prev;
/* If LSM server client becomes empty free it. */
if (lsc->head == NULL && lsc->tail == NULL) {
vector_unset(ls->client, --lsc->client_id);
free (lsc);
}
/* Free LSM server entry. */
lsm_server_entry_free(lse);
}
void lsm_server_clear()
{
struct lsm_server_entry *lse;
struct lsm_server_client *lsc;
struct lsm_server_entry *next;
u_int32_t i;
/*遍历所有的lse,断开连接 */
for (i = 0; i < vector_max(lg->server->client); i++) {
if ((lsc = vector_slot(lg->server->client, i)) != NULL) {
for (lse = lsc->head; lse; lse = next) {
next = lse->next;
message_entry_free(lse->me);
lse->me = NULL;
}
}
}
/*遍历所有的lse,清空所有lse相关的信息 */
for (i = 0; i < vector_max(lg->server->client); i++) {
if ((lsc = vector_slot(lg->server->client, i)) != NULL) {
for (lse = lsc->head; lse; lse = next) {
next = lse->next;
lsm_server_clear_lse(lse);
}
}
}
}
/* Check service type flag. */
int lsm_service_check(struct lsm_server_entry *lse, int service)
{
if (service >= LSM_SERVICE_MAX)
return 0;
return CHECK_FLAG(lse->service.bits, (1 << service));
}
/* Receive service request. */
int lsm_server_recv_service(struct lsm_msg_header *header, void *arg, void *message)
{
struct lsm_server_client *lsc = NULL;
struct lsm_server_entry *lse = arg;
struct lsm_server_entry *lse_tmp;
struct lsm_server_entry *lse_next;
struct lsm_server *ls = lse->ls;
struct lsm_msg_service *service = message;
u_int32_t index;
int ret;
int i;
/* Dump received messsage. */
lse->service = *service;
if (IS_LSM_DEBUG_RECV) {
lsm_service_dump(&lse->service);
}
/* 接收到一个协议的连接时, 检查是否存在该协议的旧连接,
* 存在则删除旧连接, 避免LSM与同一APP建立多个连接
*/
for (i = 0; i < vector_max(ls->client); i++) {
if ((lsc = vector_slot(ls->client, i)))
for (lse_tmp = lsc->head; lse_tmp; lse_tmp = lse_next) {
lse_next = lse_tmp->next;
if (lse_tmp->service.protocol_id == lse->service.protocol_id) {
DEBUG_LSM_EVENT ("LSM: Clear %s's old LSE", modname_strl(lse->service.protocol_id));
message_entry_free(lse_tmp->me);
lse_tmp->me = NULL;
lsm_server_clear_lse(lse_tmp);
}
}
}
lsc = NULL;
/* When received client id is zero, we assgin new client id for it. */
if (lse->service.client_id) {
index = service->client_id;
index--;
if (index < vector_max(ls->client))
lsc = vector_slot(ls->client, index);
}
if (!lsc) {
/* Get new client id. This is little bit tricky in vector index
* starts from zero, but client_id should be non zero. So we
* add one to vector index for client id. */
lsc = (struct lsm_server_client *) calloc (1, sizeof(struct lsm_server_client));
if (lsc == NULL) {
return -1;
}
index = vector_set(ls->client, lsc);
lsc->client_id = ++index;
lse->service.client_id = lsc->client_id;
}
/* Add LSM client entry to LSM client list. */
lse->prev = lsc->tail;
if (lsc->head == NULL)
lsc->head = lse;
else
lsc->tail->next = lse;
lsc->tail = lse;
/* Remember which NSM seve