unsigned int cmd_send(callbackp *callbacki) { json *jlist = NULL; set_json("msg", callbacki->param[3], &jlist); post_to_pipe(jlist, RAW_DATA, callbacki->param[2], getsubuser(callbacki->call_user, callbacki->host), NULL, callbacki->g_ape); return (FOR_NOTHING); }
unsigned int cmd_session(callbackp *callbacki) { if (strcmp(callbacki->param[2], "set") == 0 && (callbacki->nParam == 4 || callbacki->nParam == 5)) { if (callbacki->nParam == 5) { subuser *tmpSub = getsubuser(callbacki->call_user, callbacki->host); if (tmpSub != NULL) { tmpSub->need_update = 0; } } if (set_session(callbacki->call_user, callbacki->param[3], callbacki->param[4], (callbacki->nParam == 4 ? 0 : 1), callbacki->g_ape) == NULL) { send_error(callbacki->call_user, "SESSION_ERROR", "203", callbacki->g_ape); } } else if (strcmp(callbacki->param[2], "get") == 0 && callbacki->nParam >= 3) { int i; json *jlist = NULL, *jobj = NULL; RAW *newraw; set_json("sessions", NULL, &jlist); for (i = 3; i <= callbacki->nParam; i++) { if (strlen(callbacki->param[i]) > 32) { continue; } session *sTmp = get_session(callbacki->call_user, callbacki->param[i]); set_json(callbacki->param[i], (sTmp != NULL ? sTmp->val : NULL), &jobj); } json_attach(jlist, jobj, JSON_OBJECT); newraw = forge_raw("SESSIONS", jlist); newraw->priority = 1; /* Only sending to current subuser */ post_raw_sub(newraw, getsubuser(callbacki->call_user, callbacki->host), callbacki->g_ape); } else { send_error(callbacki->call_user, "SESSION_ERROR_PARAMS", "108", callbacki->g_ape); } return (FOR_NOTHING); }
subuser *addsubuser(int fd, const char *channel, USERS *user, acetables *g_ape) { subuser *sub; if (getsubuser(user, channel) != NULL || strlen(channel) > MAX_HOST_LENGTH) { return NULL; } sub = xmalloc(sizeof(*sub)); sub->fd = fd; sub->state = ADIED; sub->user = user; memcpy(sub->channel, channel, strlen(channel)+1); sub->next = user->subuser; sub->rawhead = NULL; sub->rawfoot = NULL; sub->nraw = 0; sub->wait_for_free = 0; sub->headers_sent = 0; sub->burn_after_writing = 0; sub->idle = time(NULL); sub->need_update = 0; (user->nsub)++; user->subuser = sub; /* if the previous subuser have some messages in queue, copy them to the new subuser */ if (sub->next != NULL && sub->next->nraw) { RAW *rTmp; for (rTmp = sub->next->rawhead; rTmp != NULL; rTmp = rTmp->next) { if (rTmp->priority == 1) { continue; } post_raw_sub(copy_raw(rTmp), sub, g_ape); } } return sub; }
/* This is usefull to ask all subuser to update their sessions */ unsigned int cmd_pong(callbackp *callbacki) { if (strcmp(callbacki->param[2], callbacki->call_user->lastping) == 0) { RAW *newraw; callbacki->call_user->lastping[0] = '\0'; json *jlist = NULL; set_json("value", callbacki->param[2], &jlist); newraw = forge_raw("UPDATE", jlist); post_raw_sub(newraw, getsubuser(callbacki->call_user, callbacki->host), callbacki->g_ape); } return (FOR_NOTHING); }
unsigned int cmd_connect(callbackp *callbacki) { USERS *nuser; RAW *newraw; json_item *jstr = NULL; nuser = adduser(NULL, NULL, NULL, callbacki->call_user, callbacki->g_ape); callbacki->call_user = nuser; subuser_restor(getsubuser(callbacki->call_user, callbacki->host), callbacki->g_ape); jstr = json_new_object(); json_set_property_strN(jstr, "sessid", 6, nuser->sessid, 32); newraw = forge_raw(RAW_LOGIN, jstr); newraw->priority = RAW_PRI_HI; post_raw(newraw, nuser, callbacki->g_ape); return (RETURN_NOTHING); }
unsigned int cmd_connect(callbackp *callbacki) { USERS *nuser; RAW *newraw; struct json *jstr = NULL; nuser = adduser(callbacki->fdclient, callbacki->host, callbacki->g_ape); callbacki->call_user = nuser; if (nuser == NULL) { SENDH(callbacki->fdclient, ERR_CONNECT, callbacki->g_ape); return (FOR_NOTHING); } if (strcmp(callbacki->param[1], "2") == 0) { nuser->transport = TRANSPORT_IFRAME; nuser->flags |= FLG_PCONNECT; } else { nuser->transport = TRANSPORT_LONGPOLLING; } subuser_restor(getsubuser(callbacki->call_user, callbacki->host), callbacki->g_ape); set_json("sessid", nuser->sessid, &jstr); newraw = forge_raw(RAW_LOGIN, jstr); newraw->priority = 1; post_raw(newraw, nuser, callbacki->g_ape); return (FOR_LOGIN | FOR_UPDATE_IP); }
subuser *addsubuser(ape_socket *client, const char *channel, USERS *user, acetables *g_ape) { subuser *sub = NULL; FIRE_EVENT(addsubuser, sub, g_ape); if (getsubuser(user, channel) != NULL || strlen(channel) > MAX_HOST_LENGTH) { return NULL; } sub = xmalloc(sizeof(*sub)); sub->client = client; sub->state = ADIED; sub->user = user; memcpy(sub->channel, channel, strlen(channel)+1); sub->next = user->subuser; sub->nraw = 0; sub->wait_for_free = 0; sub->properties = NULL; sub->headers.sent = 0; sub->headers.content = NULL; sub->burn_after_writing = 0; sub->idle = time(NULL); sub->need_update = 0; sub->current_chl = 0; sub->raw_pools.nraw = 0; /* Pre-allocate a pool of raw to reduce the number of malloc calls */ /* Low priority raws */ sub->raw_pools.low.nraw = 0; sub->raw_pools.low.size = 32; sub->raw_pools.low.rawhead = init_raw_pool(sub->raw_pools.low.size); sub->raw_pools.low.rawfoot = sub->raw_pools.low.rawhead; /* High priority raws */ sub->raw_pools.high.nraw = 0; sub->raw_pools.high.size = 8; sub->raw_pools.high.rawhead = init_raw_pool(sub->raw_pools.high.size); sub->raw_pools.high.rawfoot = sub->raw_pools.high.rawhead; (user->nsub)++; user->subuser = sub; /* if the previous subuser have some messages in queue, copy them to the new subuser */ if (sub->next != NULL && sub->next->raw_pools.low.nraw) { struct _raw_pool *rTmp; for (rTmp = sub->next->raw_pools.low.rawhead; rTmp->raw != NULL; rTmp = rTmp->next) { post_raw_sub(rTmp->raw, sub, g_ape); } } HOOK_EVENT(addsubuser, sub, g_ape); return sub; }
unsigned int checkcmd(clientget *cget, subuser **iuser, acetables *g_ape) { char *param[64+1], *cmd; callback *cmdback; size_t nTok; unsigned int flag; USERS *guser = NULL; subuser *sub = NULL; nTok = explode('&', cget->get, param, 64); if (nTok < 1) { cmd = NULL; } else { cmd = param[0]; } /* TODO: Making a simple chainlist can be more efficient since we do not have many cmds */ cmdback = (callback *)hashtbl_seek(g_ape->hCallback, cmd); if (cmdback != NULL) { if ((nTok-1) == cmdback->nParam || (cmdback->nParam < 0 && (nTok-1) >= (cmdback->nParam*-1) && (cmdback->nParam*-1) <= 16)) { int tmpfd = 0; callbackp cp; switch(cmdback->need) { case NEED_SESSID: guser = seek_user_id(param[1], g_ape); break; case NEED_NOTHING: guser = NULL; break; } if (cmdback->need != NEED_NOTHING) { if (guser == NULL) { SENDH(cget->fdclient, ERR_BAD_SESSID, g_ape); return (CONNECT_SHUTDOWN); } else { sub = getsubuser(guser, cget->host); if (sub != NULL && sub->fd != cget->fdclient && sub->state == ALIVE) { if (guser->transport == TRANSPORT_IFRAME) { /* iframe is already open on "sub" */ tmpfd = sub->fd; /* Forward data directly to iframe */ CLOSE(cget->fdclient, g_ape); shutdown(cget->fdclient, 2); /* Immediatly close controller */ } else { /* Only one connection is allowed per user/host */ CLOSE(sub->fd, g_ape); shutdown(sub->fd, 2); sub->state = ADIED; sub->fd = cget->fdclient; } } else if (sub == NULL) { sub = addsubuser(cget->fdclient, cget->host, guser); if (sub != NULL) { subuser_restor(sub, g_ape); } } else if (sub != NULL) { sub->fd = cget->fdclient; } guser->idle = (long int)time(NULL); // update user idle sub->idle = guser->idle; // Update subuser idle } } cp.param = param; cp.fdclient = (tmpfd ? tmpfd : cget->fdclient); cp.call_user = guser, cp.g_ape = g_ape; cp.nParam = nTok-1; cp.host = cget->host; flag = cmdback->func(&cp); if (flag & FOR_NULL) { guser = NULL; } else if (flag & FOR_LOGIN) { guser = cp.call_user; } if (guser != NULL) { if (sub == NULL && (sub = getsubuser(guser, cget->host)) == NULL) { if ((sub = addsubuser(cget->fdclient, cget->host, guser)) == NULL) { return (CONNECT_SHUTDOWN); } subuser_restor(sub, g_ape); if (guser->transport == TRANSPORT_IFRAME) { sendbin(sub->fd, HEADER, strlen(HEADER), g_ape); } } *iuser = (tmpfd ? NULL : sub); if (flag & FOR_UPDATE_IP) { strncpy(guser->ip, cget->ip_get, 16); } /* If tmpfd is set, we do not have reasons to change this state */ if (!tmpfd) { sub->state = ALIVE; } return (CONNECT_KEEPALIVE); } return (CONNECT_SHUTDOWN); } else { SENDH(cget->fdclient, ERR_BAD_PARAM, g_ape); } } else { // unregistered CMD SENDH(cget->fdclient, ERR_BAD_CMD, g_ape); } return (CONNECT_SHUTDOWN); }
int process_cmd(json_item *ijson, struct _cmd_process *pc, subuser **iuser, acetables *g_ape) { callback *cmdback, tmpback = {handle_bad_cmd, NEED_NOTHING}; json_item *rjson = json_lookup(ijson->jchild.child, "cmd"), *jchl; subuser *sub = pc->sub; unsigned int flag; unsigned short int attach = 1; if (rjson != NULL && rjson->jval.vu.str.value != NULL) { callbackp cp; cp.client = NULL; cp.cmd = rjson->jval.vu.str.value; cp.data = NULL; cp.hlines = NULL; json_item *jsid; if ((cmdback = (callback *)hashtbl_seek(g_ape->hCallback, rjson->jval.vu.str.value)) == NULL) { cmdback = &tmpback; } if ((pc->guser == NULL && (jsid = json_lookup(ijson->jchild.child, "sessid")) != NULL && jsid->jval.vu.str.value != NULL)) { pc->guser = seek_user_id(jsid->jval.vu.str.value, g_ape); } if (cmdback->need != NEED_NOTHING || pc->guser != NULL) { // We process the connection like a "NEED_SESSID" if the user provide its key if (pc->guser == NULL) { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "code", "004"); json_set_property_strZ(jlist, "value", "BAD_SESSID"); newraw = forge_raw(RAW_ERR, jlist); send_raw_inline(pc->client, pc->transport, newraw, g_ape); return (CONNECT_SHUTDOWN); } else if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); if (sub != NULL && sub->client->fd != pc->client->fd && sub->state == ALIVE) { /* The user open a new connection while he already has one openned */ struct _transport_open_same_host_p retval = transport_open_same_host(sub, pc->client, pc->guser->transport); if (retval.client_close != NULL) { // Send CLOSE if no response has been sent yet if (!sub->headers.sent) { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "value", "null"); newraw = forge_raw("CLOSE", jlist); send_raw_inline((retval.client_close->fd == pc->client->fd ? pc->client : sub->client), pc->transport, newraw, g_ape); } // It's not safe to leave the subuser pointer in co->attach anymore // since subuser could subsequently be deleted, leaving a pointer into free heap. // So, let this socket finish up on its own and pretend its already finished. sub->state = ADIED; sub->headers.sent = 0; http_headers_free(sub->headers.content); sub->headers.content = NULL; sub->burn_after_writing = 0; g_ape->co[retval.client_close->fd]->attach = NULL; safe_shutdown(retval.client_close->fd, g_ape); } sub->client = cp.client = retval.client_listener; sub->state = retval.substate; attach = retval.attach; } else if (sub == NULL) { sub = addsubuser(pc->client, pc->host, pc->guser, g_ape); if (sub != NULL) { subuser_restor(sub, g_ape); } } else if (sub != NULL) { sub->client = pc->client; } pc->guser->idle = (long int)time(NULL); // update user idle sub->idle = pc->guser->idle; // Update subuser idle } } if (pc->guser != NULL && sub != NULL && (jchl = json_lookup(ijson->jchild.child, "chl")) != NULL /*&& jchl->jval.vu.integer_value > sub->current_chl*/) { sub->current_chl = jchl->jval.vu.integer_value; } #if 0 else if (pc->guser != NULL && sub != NULL) { /* if a bad challenge is detected, we are stoping walking on cmds */ send_error(pc->guser, "BAD_CHL", "250", g_ape); sub->state = ALIVE; return (CONNECT_KEEPALIVE); } #endif cp.param = json_lookup(ijson->jchild.child, "params"); cp.client = (cp.client != NULL ? cp.client : pc->client); cp.call_user = pc->guser; cp.call_subuser = sub; cp.g_ape = g_ape; cp.host = pc->host; cp.ip = pc->ip; cp.chl = (sub != NULL ? sub->current_chl : 0); cp.transport = pc->transport; cp.hlines = pc->hlines; /* Little hack to access user object on connect hook callback (preallocate an user) */ if (strncasecmp(cp.cmd, "CONNECT", 7) == 0 && cp.cmd[7] == '\0') { pc->guser = cp.call_user = adduser(cp.client, cp.host, cp.ip, NULL, g_ape); pc->guser->transport = pc->transport; sub = cp.call_subuser = cp.call_user->subuser; } if ((flag = call_cmd_hook(cp.cmd, &cp, g_ape)) == RETURN_CONTINUE) { flag = cmdback->func(&cp); } if (flag & RETURN_NULL) { pc->guser = NULL; } else if (flag & RETURN_BAD_PARAMS) { RAW *newraw; json_item *jlist = json_new_object(); if (cp.chl) { json_set_property_intN(jlist, "chl", 3, cp.chl); } json_set_property_strZ(jlist, "code", "001"); json_set_property_strZ(jlist, "value", "BAD_PARAMS"); newraw = forge_raw(RAW_ERR, jlist); if (cp.call_user != NULL) { //cp.call_user->istmp = 0; if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } post_raw_sub(newraw, sub, g_ape); } else { send_raw_inline(pc->client, pc->transport, newraw, g_ape); } //guser = NULL; } else if (flag & RETURN_BAD_CMD) { RAW *newraw; json_item *jlist = json_new_object(); if (cp.chl) { json_set_property_intN(jlist, "chl", 3, cp.chl); } json_set_property_strZ(jlist, "code", "003"); json_set_property_strZ(jlist, "value", "BAD_CMD"); newraw = forge_raw(RAW_ERR, jlist); if (cp.call_user != NULL) { if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } post_raw_sub(newraw, sub, g_ape); } else { send_raw_inline(pc->client, pc->transport, newraw, g_ape); } } if (pc->guser != NULL) { if (sub == NULL) { sub = getsubuser(pc->guser, pc->host); } if (iuser != NULL) { *iuser = (attach ? sub : NULL); } /* If tmpfd is set, we do not have any reasons to change its state */ sub->state = ALIVE; if (flag & RETURN_HANG || flag & RETURN_BAD_PARAMS) { return (CONNECT_KEEPALIVE); } } else if (flag & RETURN_HANG) { /* Doesn't need sessid */ return (CONNECT_KEEPALIVE); } else { return (CONNECT_SHUTDOWN); } } else { RAW *newraw; json_item *jlist = json_new_object(); json_set_property_strZ(jlist, "code", "003"); json_set_property_strZ(jlist, "value", "NO_CMD"); newraw = forge_raw(RAW_ERR, jlist); send_raw_inline(pc->client, pc->transport, newraw, g_ape); //printf("Cant find %s\n", rjson->jval.vu.str.value); return (CONNECT_SHUTDOWN); } return -1; }