コード例 #1
0
static ngx_int_t ngx_http_push_respond_to_subscribers(ngx_http_push_channel_t *channel, ngx_http_push_subscriber_t *sentinel, ngx_http_push_msg_t *msg, ngx_int_t status_code, const ngx_str_t *status_line) {
	ngx_slab_pool_t                *shpool = ngx_http_push_shpool;
	ngx_http_push_subscriber_t     *cur, *next;
	ngx_int_t                       responded_subscribers=0;
	if(sentinel==NULL) {
		return NGX_OK;
	}
	
	cur=(ngx_http_push_subscriber_t *)ngx_queue_head(&sentinel->queue);
	if(msg!=NULL) {
		//copy everything we need first
		ngx_str_t                  *content_type=NULL;
		ngx_str_t                  *etag=NULL;
		time_t                      last_modified_time;
		ngx_chain_t                *chain;
		size_t                      content_type_len;
		ngx_http_request_t         *r;
		ngx_buf_t                  *buffer;
		u_char                     *pos;
		
		ngx_shmtx_lock(&shpool->mutex);
		
		//etag
		NGX_HTTP_PUSH_MAKE_ETAG(msg->message_tag, etag, ngx_pcalloc, ngx_http_push_pool);
		if(etag==NULL) {
			//oh, nevermind...
			ngx_shmtx_unlock(&shpool->mutex);
			return NGX_ERROR;
		}
		
		//content-type
		content_type_len = msg->content_type.len;
		if(content_type_len>0) {
			NGX_HTTP_PUSH_MAKE_CONTENT_TYPE(content_type, content_type_len, msg, ngx_http_push_pool);
			if(content_type==NULL) {
				ngx_shmtx_unlock(&shpool->mutex);
				ngx_pfree(ngx_http_push_pool, etag);
				ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "push module: unable to allocate memory for content-type header while responding to several subscriber request");
				return NGX_ERROR;
			}
		}
		
		//preallocate output chain. yes, same one for every waiting subscriber
		if((chain = ngx_http_push_create_output_chain_locked(msg->buf, ngx_http_push_pool, ngx_cycle->log, shpool))==NULL) {
			ngx_shmtx_unlock(&shpool->mutex);
			ngx_pfree(ngx_http_push_pool, etag);
			ngx_pfree(ngx_http_push_pool, content_type);
			ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "push module: unable to create output chain while responding to several subscriber request");
			return NGX_ERROR;
		}
		
		buffer = chain->buf;
		pos = buffer->pos;
		
		last_modified_time = msg->message_time;
		
		ngx_shmtx_unlock(&shpool->mutex);
		
		//now let's respond to some requests!
		while(cur!=sentinel) {
			next=(ngx_http_push_subscriber_t *)ngx_queue_next(&cur->queue);
			//in this block, nothing in shared memory should be dereferenced.
			r=cur->request;
			//cleanup oughtn't dequeue anything. or decrement the subscriber count, for that matter
			ngx_http_push_subscriber_clear_ctx(cur);
			
			r->discard_body=0; //hacky hacky!
			
			ngx_http_finalize_request(r, ngx_http_push_prepare_response_to_subscriber_request(r, chain, content_type, etag, last_modified_time)); //BAM!
			responded_subscribers++;
			
			//done with this subscriber. free the sucker.
			ngx_pfree(ngx_http_push_pool, cur);
			
			//rewind the buffer, please
			buffer->pos = pos;
			buffer->last_buf=1;
			
			cur=next;
		}
		
		//free everything relevant
		ngx_pfree(ngx_http_push_pool, etag);
		ngx_pfree(ngx_http_push_pool, content_type);
		if(buffer->file) {
			ngx_close_file(buffer->file->fd);
		}
		ngx_pfree(ngx_http_push_pool, buffer);
		ngx_pfree(ngx_http_push_pool, chain);
		
		if(responded_subscribers) {
			ngx_shmtx_lock(&shpool->mutex);
			//message deletion
			ngx_http_push_release_message_locked(channel, msg);
			ngx_shmtx_unlock(&shpool->mutex);
		}
	}
	else {
		//headers only probably
		ngx_http_request_t     *r;
		while(cur!=sentinel) {
			next=(ngx_http_push_subscriber_t *)ngx_queue_next(&cur->queue);
			r=cur->request;
			
			//cleanup oughtn't dequeue anything. or decrement the subscriber count, for that matter
			ngx_http_push_subscriber_clear_ctx(cur);
			ngx_http_finalize_request(r, ngx_http_push_respond_status_only(r, status_code, status_line));
			responded_subscribers++;
			ngx_pfree(ngx_http_push_pool, cur);
			cur=next;
		}
	}
	ngx_shmtx_lock(&shpool->mutex);
	channel->subscribers-=responded_subscribers;
	//is the message still needed?
	ngx_shmtx_unlock(&shpool->mutex);
	ngx_pfree(ngx_http_push_pool, sentinel);
	return NGX_OK;
}
コード例 #2
0
ngx_int_t ngx_http_push_respond_to_subscribers(ngx_http_push_channel_t *channel, ngx_http_push_subscriber_t *sentinel, ngx_http_push_msg_t *msg, ngx_int_t status_code, const ngx_str_t *status_line) {

  //copy everything we need first
  ngx_str_t                  *content_type=NULL;
  ngx_str_t                  *etag=NULL;
  time_t                      last_modified = 0;
  ngx_chain_t                *chain=NULL;
  ngx_http_request_t         *r;
  ngx_buf_t                  *buffer = NULL;
  ngx_chain_t                *rchain;
  ngx_buf_t                  *rbuffer;
  ngx_int_t                  *buf_use_count = NULL;
  ngx_http_push_subscriber_cleanup_t *clndata;
  ngx_http_push_subscriber_t *cur=NULL;
  ngx_int_t                   responded_subscribers=0;

  if(sentinel==NULL) {
    //ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, "respond_to_subscribers with sentinel==NULL");
    return NGX_OK;
  }
  
  if(msg!=NULL) {
    if(ngx_http_push_alloc_for_subscriber_response(ngx_http_push_pool, 1, msg, &chain, &content_type, &etag, &last_modified)==NGX_ERROR) {
      ngx_http_push_store->release_message(channel, msg);
      return NGX_ERROR;
    }
    
    buffer = chain->buf;
    buffer->recycled = 1;

    buf_use_count = ngx_pcalloc(ngx_http_push_pool, sizeof(*buf_use_count));
    *buf_use_count = ngx_http_push_store->channel_worker_subscribers(sentinel);
  }
    
  while((cur=ngx_http_push_store->next_subscriber(channel, sentinel, cur, 1))!=NULL) {
    //in this block, nothing in shared memory should be dereferenced.
    r=cur->request;

    if(msg!=NULL) {
      //chain and buffer for this request
      rchain = ngx_pcalloc(r->pool, sizeof(*rchain));
      rchain->next = NULL;
      rbuffer = ngx_pcalloc(r->pool, sizeof(*rbuffer));
      rchain->buf = rbuffer;
      ngx_memcpy(rbuffer, buffer, sizeof(*buffer));

      //request buffer cleanup
      clndata = cur->clndata;
      clndata->buf = buffer;
      clndata->buf_use_count = buf_use_count;
      clndata->rchain = rchain;
      clndata->rpool = r->pool;

      if (rbuffer->in_file && (fcntl(rbuffer->file->fd, F_GETFD) == -1)) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "push module: buffer in invalid file descriptor");
      }
      //cleanup oughtn't dequeue anything. or decrement the subscriber count, for that matter
      ngx_http_push_subscriber_clear_ctx(cur);
      ngx_http_finalize_request(r, ngx_http_push_prepare_response_to_subscriber_request(r, rchain, content_type, etag, last_modified)); //BAM!
    }
    else {
      ngx_http_push_subscriber_clear_ctx(cur);
      ngx_http_finalize_request(r, ngx_http_push_respond_status_only(r, status_code, status_line));
    }
    responded_subscribers++;
  }
  if(msg!=NULL) {
    ngx_http_push_store->release_message(channel, msg);
    ngx_pfree(ngx_http_push_pool, etag);
    ngx_pfree(ngx_http_push_pool, content_type);
    ngx_pfree(ngx_http_push_pool, chain);
  }
  
  //ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, "respond_to_subscribers with msg %p finished", msg);
  ngx_http_push_store->lock();
  channel->subscribers-=responded_subscribers;
  //is the message still needed?
  ngx_http_push_store->unlock();
  ngx_http_push_store->release_subscriber_sentinel(channel, sentinel);
  return NGX_OK;
}