nchan_msg_t *nchan_msg_derive_palloc(nchan_msg_t *parent, ngx_pool_t *pool) { nchan_msg_t *msg = msg_derive_init(parent, ngx_palloc(pool, sizeof(nchan_msg_t)), NCHAN_MSG_POOL); if(!msg || nchan_copy_new_msg_id(&msg->id, &parent->id) != NGX_OK) { return NULL; } return msg; }
void nchan_subscriber_init(subscriber_t *sub, const subscriber_t *tmpl, ngx_http_request_t *r, nchan_msg_id_t *msgid) { nchan_request_ctx_t *ctx = NULL; *sub = *tmpl; sub->request = r; if(r) { ctx = ngx_http_get_module_ctx(r, ngx_nchan_module); sub->cf = ngx_http_get_module_loc_conf(r, ngx_nchan_module); } sub->reserved = 0; sub->enqueued = 0; sub->status = ALIVE; if(msgid) { nchan_copy_new_msg_id(&sub->last_msgid, msgid); } else { sub->last_msgid.time = 0; sub->last_msgid.tag.fixed[0] = 0; sub->last_msgid.tagcount = 1; } if(ctx) { ctx->prev_msg_id = sub->last_msgid; ctx->sub = sub; ctx->subscriber_type = sub->name; } #if FAKESHARD sub->owner = memstore_slot(); #endif }
nchan_msg_t *nchan_msg_derive_alloc(nchan_msg_t *parent) { nchan_msg_t *msg = msg_derive_init(parent, ngx_alloc(sizeof(nchan_msg_t), ngx_cycle->log), NCHAN_MSG_HEAP); if(!msg || nchan_copy_new_msg_id(&msg->id, &parent->id) != NGX_OK) { ngx_free(msg); return NULL; } return msg; }
static ngx_inline void init_spool(channel_spooler_t *spl, subscriber_pool_t *spool, nchan_msg_id_t *id) { nchan_copy_new_msg_id(&spool->id, id); spool->msg = NULL; spool->msg_status = MSG_INVALID; spool->first = NULL; spool->pool = NULL; spool->sub_count = 0; spool->non_internal_sub_count = 0; spool->generation = 0; spool->responded_count = 0; spool->spooler = spl; }
subscriber_t *getmsg_proxy_subscriber_create(nchan_msg_id_t *msgid, callback_pt cb, void *pd) { sub_data_t *d; subscriber_t *sub; sub = internal_subscriber_create_init(&sub_name, NULL /*no config*/, sizeof(*d), (void **)&d, (callback_pt )sub_enqueue, (callback_pt )sub_dequeue, (callback_pt )sub_respond_message, (callback_pt )sub_respond_status, NULL, NULL); DBG("created new getmsg_proxy sub %p", sub); nchan_copy_new_msg_id(&sub->last_msgid, msgid); sub->destroy_after_dequeue = 1; sub->dequeue_after_response = 1; d->sub = sub; d->cb = cb; d->pd = pd; return sub; }
static ngx_int_t spool_fetch_msg(subscriber_pool_t *spool) { fetchmsg_data_t *data; channel_spooler_t *spl = spool->spooler; if(*spl->channel_status != READY) { DBG("%p wanted to fetch msg %V, but channel %V not ready", spool, msgid_to_str(&spool->id), spl->chid); spool->msg_status = MSG_CHANNEL_NOTREADY; return NGX_DECLINED; } DBG("%p fetch msg %V for channel %V", spool, msgid_to_str(&spool->id), spl->chid); data = ngx_alloc(sizeof(*data), ngx_cycle->log); //correctness over efficiency (at first). //TODO: optimize this alloc away assert(data); data->next = spl->fetchmsg_cb_data_list; if(data->next) { data->next->prev = data; } spl->fetchmsg_cb_data_list = data; data->prev = NULL; nchan_copy_new_msg_id(&data->msgid, &spool->id); data->spooler = spool->spooler; assert(spool->msg == NULL); assert(spool->msg_status == MSG_INVALID); spool->msg_status = MSG_PENDING; if(spl->handlers->get_message_start) { spl->handlers->get_message_start(spl, spl->handlers_privdata); } switch(spl->fetching_strategy) { case FETCH: case FETCH_IGNORE_MSG_NOTFOUND: spool->spooler->store->get_message(spool->spooler->chid, &spool->id, spool->spooler->cf, (callback_pt )spool_fetch_msg_callback, data); break; case NO_FETCH: //do nothing break; } return NGX_OK; }
subscriber_t *longpoll_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { DBG("create for req %p", r); full_subscriber_t *fsub; nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, nchan_module); //TODO: allocate from pool (but not the request's pool) if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) { ERR("Unable to allocate"); assert(0); return NULL; } ngx_memcpy(&fsub->sub, &new_longpoll_sub, sizeof(new_longpoll_sub)); fsub->sub.request = r; fsub->data.cln = NULL; fsub->data.finalize_request = 1; fsub->data.holding = 0; fsub->data.act_as_intervalpoll = 0; fsub->sub.cf = ngx_http_get_module_loc_conf(r, nchan_module); ngx_memzero(&fsub->data.timeout_ev, sizeof(fsub->data.timeout_ev)); fsub->data.timeout_handler = empty_handler; fsub->data.timeout_handler_data = NULL; fsub->data.dequeue_handler = empty_handler; fsub->data.dequeue_handler_data = NULL; fsub->data.already_responded = 0; fsub->data.awaiting_destruction = 0; fsub->sub.reserved = 0; fsub->sub.enqueued = 0; if(fsub->sub.cf->longpoll_multimsg) { fsub->sub.dequeue_after_response = 0; } fsub->data.multimsg_first = NULL; fsub->data.multimsg_last = NULL; #if NCHAN_SUBSCRIBER_LEAK_DEBUG subscriber_debug_add(&fsub->sub); //set debug label fsub->sub.lbl = ngx_calloc(r->uri.len+1, ngx_cycle->log); ngx_memcpy(fsub->sub.lbl, r->uri.data, r->uri.len); #endif if(msg_id) { nchan_copy_new_msg_id(&fsub->sub.last_msgid, msg_id); } else { fsub->sub.last_msgid.time = 0; fsub->sub.last_msgid.tag.fixed[0] = 0; fsub->sub.last_msgid.tagcount = 1; } ctx->prev_msg_id = fsub->sub.last_msgid; fsub->data.owner = memstore_slot(); //http request sudden close cleanup if((fsub->data.cln = ngx_http_cleanup_add(r, 0)) == NULL) { ERR("Unable to add request cleanup for longpoll subscriber"); assert(0); return NULL; } fsub->data.cln->data = fsub; fsub->data.cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler; DBG("%p created for request %p", &fsub->sub, r); if(ctx) { ctx->sub = &fsub->sub; ctx->subscriber_type = fsub->sub.name; } return &fsub->sub; }
subscriber_t *websocket_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { ngx_buf_t *b; nchan_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, nchan_module); nchan_request_ctx_t *ctx = ngx_http_get_module_ctx(r, nchan_module); DBG("create for req %p", r); full_subscriber_t *fsub; if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) { ERR("Unable to allocate"); return NULL; } ngx_memcpy(&fsub->sub, &new_websocket_sub, sizeof(new_websocket_sub)); fsub->sub.request = r; fsub->cln = NULL; fsub->finalize_request = 0; fsub->holding = 0; fsub->shook_hands = 0; fsub->sub.cf = ngx_http_get_module_loc_conf(r, nchan_module); fsub->sub.enqueued = 0; ngx_memzero(&fsub->ping_ev, sizeof(fsub->ping_ev)); if(msg_id) { nchan_copy_new_msg_id(&fsub->sub.last_msgid, msg_id); } else { fsub->sub.last_msgid.time = 0; fsub->sub.last_msgid.tag.fixed[0] = 0; fsub->sub.last_msgid.tagcount = 1; } ngx_memzero(&fsub->timeout_ev, sizeof(fsub->timeout_ev)); fsub->timeout_handler = empty_handler; fsub->timeout_handler_data = NULL; fsub->dequeue_handler = empty_handler; fsub->dequeue_handler_data = NULL; fsub->awaiting_destruction = 0; //initialize reusable chains and bufs ngx_memzero(&fsub->hdr_buf, sizeof(fsub->hdr_buf)); ngx_memzero(&fsub->msg_buf, sizeof(fsub->msg_buf)); //space for frame header fsub->hdr_buf.start = ngx_pcalloc(r->pool, WEBSOCKET_FRAME_HEADER_MAX_LENGTH); fsub->hdr_chain.buf = &fsub->hdr_buf; fsub->hdr_chain.next = &fsub->msg_chain; fsub->msg_chain.buf = &fsub->msg_buf; fsub->msg_chain.next = NULL; //what should the buffers look like? b = &fsub->msg_buf; b->last_buf = 1; b->last_in_chain = 1; b->flush = 1; b->memory = 1; b->temporary = 0; if(cf->pub.websocket) { fsub->publish_channel_id = nchan_get_channel_id(r, PUB, 0); } fsub->upstream_stuff = NULL; websocket_init_frame(&fsub->frame); fsub->owner = memstore_slot(); //http request sudden close cleanup if((fsub->cln = ngx_http_cleanup_add(r, 0)) == NULL) { ERR("Unable to add request cleanup for websocket subscriber"); return NULL; } fsub->cln->data = fsub; fsub->cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler; DBG("%p created for request %p", &fsub->sub, r); assert(ctx != NULL); ctx->sub = &fsub->sub; //gonna need this for recv ctx->subscriber_type = fsub->sub.name; #if NCHAN_SUBSCRIBER_LEAK_DEBUG subscriber_debug_add(&fsub->sub); #endif return &fsub->sub; }