示例#1
0
文件: main.c 项目: a-c-m/couchnode
int main(void) {
    lcb_pool_t pool;
    lcb_t instance;
    struct lcb_create_st options;
    lcb_error_t error;

    /* set up the options to represent your cluster (hostname etc) */
    /* ... */

    /* Create the pool */
    error = pool_create(10, &options, &pool, initiate);
    if (error != LCB_SUCCESS) {
        fprintf(stderr, "Failed to create pool: %s\n",
                lcb_strerror(NULL, error));
        exit(EXIT_FAILURE);
    }

    /*
     * Every time you want to use libcouchbase you would grab an instance
     * from the pool by:
     */
    instance = pool_pop(pool);

    /* use the instance for whatever you wanted to do */


    /*
     * When you're done using the instance you would put it back into the
     * pool (and ready for others to use) by:
     */
    pool_push(pool, instance);

    return 0;
}
示例#2
0
文件: http1.c 项目: boazsegev/iodine
protocol_s* http1_alloc(intptr_t fd, http_settings_s* settings) {
  validate_mem();
  // HTTP/1.1 should send a busy response
  // if there aren't enough available file descriptors.
  if (sock_max_capacity() - sock_uuid2fd(fd) <= HTTP_BUSY_UNLESS_HAS_FDS)
    goto is_busy;
  // get an http object from the pool
  http1_protocol_s* http = pool_pop();
  // of malloc one
  if (http == NULL)
    http = malloc(HTTP1_PROTOCOL_SIZE);
  // review allocation
  if (http == NULL)
    return NULL;

  // we shouldn't update the `http` protocol as a struct, as this will waste
  // time as the whole buffer will be zeroed out when there is no need.

  // setup parsing state
  http->buffer_pos = 0;
  // setup protocol callbacks
  http->protocol = (protocol_s){
      .service = HTTP1,
      .on_data = (void (*)(intptr_t, protocol_s*))http1_on_data,
      .on_close = (void (*)(protocol_s*))http1_free,
  };
  // setup request data
  http->request = (http_request_s){
      .metadata.max_headers = HTTP1_MAX_HEADER_COUNT,
      .metadata.fd = fd,
      .metadata.owner = http,
  };
  // update settings
  http->settings = settings;
  http->on_request = settings->on_request;
  // set the timeout
  server_set_timeout(fd, settings->timeout);
  return (protocol_s*)http;

is_busy:
  if (settings->public_folder && settings->public_folder_length) {
    size_t p_len = settings->public_folder_length;
    struct stat file_data = {};
    char fname[p_len + 8 + 1];
    memcpy(fname, settings->public_folder, p_len);
    if (settings->public_folder[p_len - 1] == '/' ||
        settings->public_folder[p_len - 1] == '\\')
      p_len--;
    memcpy(fname + p_len, "/503.html", 9);
    p_len += 9;
    if (stat(fname, &file_data))
      goto busy_no_file;
    // check that we have a file and not something else
    if (!S_ISREG(file_data.st_mode) && !S_ISLNK(file_data.st_mode))
      goto busy_no_file;
    int file = open(fname, O_RDONLY);
    if (file == -1)
      goto busy_no_file;
    sock_packet_s* packet;
    packet = sock_checkout_packet();
    memcpy(packet->buffer,
           "HTTP/1.1 503 Service Unavailable\r\n"
           "Content-Type: text/html\r\n"
           "Connection: close\r\n"
           "Content-Length: ",
           94);
    p_len = 94 + http_ul2a(packet->buffer + 94, file_data.st_size);
    memcpy(packet->buffer + p_len, "\r\n\r\n", 4);
    p_len += 4;
    if (BUFFER_PACKET_SIZE - p_len > file_data.st_size) {
      if (read(file, packet->buffer + p_len, file_data.st_size) < 0) {
        close(file);
        sock_free_packet(packet);
        goto busy_no_file;
      }
      close(file);
      packet->length = p_len + file_data.st_size;
      sock_send_packet(fd, packet);
    } else {
      packet->length = p_len;
      sock_send_packet(fd, packet);
      sock_sendfile(fd, file, 0, file_data.st_size);
    }
    return NULL;
  }
busy_no_file:
  sock_write(fd,
             "HTTP/1.1 503 Service Unavailable\r\nContent-Length: "
             "13\r\n\r\nServer Busy.",
             68);
  return NULL;
}

/* *****************************************************************************
HTTP/1.1 protocol bare-bones implementation
*/

#define HTTP_BODY_CHUNK_SIZE 3072  // 4096

/* parse and call callback */
static void http1_on_data(intptr_t uuid, http1_protocol_s* protocol) {
  ssize_t len = 0;
  ssize_t result;
  char buff[HTTP_BODY_CHUNK_SIZE];
  char* buffer;
  http_request_s* request = &protocol->request;
  for (;;) {
    // handle requests with no file data
    if (request->body_file <= 0) {
      // request headers parsing
      if (len == 0) {
        buffer = protocol->buffer;
        // make sure headers don't overflow
        len = sock_read(uuid, buffer + protocol->buffer_pos,
                        HTTP1_MAX_HEADER_SIZE - protocol->buffer_pos);
        // update buffer read position.
        protocol->buffer_pos += len;
      }
      if (len <= 0) {
        return;
      }
      // parse headers
      result =
          http1_parse_request_headers(buffer, protocol->buffer_pos, request);
      // review result
      if (result >= 0) {  // headers comeplete
        // mark buffer position, for HTTP pipelining
        protocol->buffer_pos = result;
        // are we done?
        if (request->content_length == 0 || request->body_str) {
          goto handle_request;
        }
        if (request->content_length > protocol->settings->max_body_size) {
          goto body_to_big;
        }
        // initialize or submit body data
        result =
            http1_parse_request_body(buffer + result, len - result, request);
        if (result >= 0) {
          protocol->buffer_pos += result;
          goto handle_request;
        } else if (result == -1)  // parser error
          goto parser_error;
        goto parse_body;
      } else if (result == -1)  // parser error
        goto parser_error;
      // assume incomplete (result == -2), even if wrong, we're right.
      len = 0;
      continue;
    }
    if (request->body_file > 0) {
    parse_body:
      buffer = buff;
      // request body parsing
      len = sock_read(uuid, buffer, HTTP_BODY_CHUNK_SIZE);
      if (len <= 0)
        return;
      result = http1_parse_request_body(buffer, len, request);
      if (result >= 0) {
        // set buffer pos for piplining support
        protocol->buffer_pos = result;
        goto handle_request;
      } else if (result == -1)  // parser error
        goto parser_error;
      if (len < HTTP_BODY_CHUNK_SIZE)  // pause parser for more data
        return;
      goto parse_body;
    }
    continue;
  handle_request:
    // review required headers / data
    if (request->host == NULL)
      goto bad_request;
    http_settings_s* settings = protocol->settings;
    // call request callback
    if (protocol && settings &&
        (protocol->settings->public_folder == NULL ||
         http_response_sendfile2(NULL, request, settings->public_folder,
                                 settings->public_folder_length, request->path,
                                 request->path_len, settings->log_static))) {
      protocol->on_request(request);
    }
    // clear request state
    http_request_clear(request);
    // rotate buffer for HTTP pipelining
    if (result >= len) {
      len = 0;
    } else {
      memmove(protocol->buffer, buffer + protocol->buffer_pos, len - result);
      len -= result;
    }
    // restart buffer position
    protocol->buffer_pos = 0;
    buffer = protocol->buffer;
  }
  // no routes lead here.
  fprintf(stderr,
          "I am lost on a deserted island, no code can reach me here :-)\n");
  return;  // How did we get here?
parser_error:
  if (request->headers_count == request->metadata.max_headers)
    goto too_big;
bad_request:
  /* handle generally bad requests */
  {
    http_response_s response = http_response_init(request);
    response.status = 400;
    http_response_write_body(&response, "Bad Request", 11);
    http_response_finish(&response);
    sock_close(uuid);
    protocol->buffer_pos = 0;
    return;
  }
too_big:
  /* handle oversized headers */
  {
    http_response_s response = http_response_init(request);
    response.status = 431;
    http_response_write_body(&response, "Request Header Fields Too Large", 31);
    http_response_finish(&response);
    sock_close(uuid);
    protocol->buffer_pos = 0;
    return;
  body_to_big:
    /* handle oversized body */
    {
      http_response_s response = http_response_init(request);
      response.status = 413;
      http_response_write_body(&response, "Payload Too Large", 17);
      http_response_finish(&response);
      sock_close(uuid);
      protocol->buffer_pos = 0;
      return;
    }
  }
}

/* *****************************************************************************
HTTP/1.1 listenning API implementation
*/

#undef http1_listen

static void http1_on_init(http_settings_s* settings) {
  if (settings->timeout == 0)
    settings->timeout = 5;
  if (settings->max_body_size == 0)
    settings->max_body_size = HTTP_DEFAULT_BODY_LIMIT;
  if (settings->public_folder) {
    settings->public_folder_length = strlen(settings->public_folder);
    if (settings->public_folder[0] == '~' &&
        settings->public_folder[1] == '/' && getenv("HOME")) {
      char* home = getenv("HOME");
      size_t home_len = strlen(home);
      char* tmp = malloc(settings->public_folder_length + home_len + 1);
      memcpy(tmp, home, home_len);
      if (home[home_len - 1] == '/')
        --home_len;
      memcpy(tmp + home_len, settings->public_folder + 1,
             settings->public_folder_length);  // copy also the NULL
      settings->public_folder = tmp;
      settings->private_metaflags |= 1;
      settings->public_folder_length = strlen(settings->public_folder);
    }
  }
}
static void http1_on_finish(http_settings_s* settings) {
  if (settings->private_metaflags & 1)
    free((void*)settings->public_folder);
  if (settings->private_metaflags & 2)
    free(settings);
}

int http1_listen(const char* port,
                 const char* address,
                 http_settings_s settings) {
  if (settings.on_request == NULL) {
    fprintf(
        stderr,
        "ERROR: http1_listen requires the .on_request parameter to be set\n");
    exit(11);
  }
  http_settings_s* settings_copy = malloc(sizeof(*settings_copy));
  *settings_copy = settings;
  settings_copy->private_metaflags = 2;
  return server_listen(.port = port, .address = address,
                       .on_start = (void*)http1_on_init,
                       .on_finish = (void*)http1_on_finish,
                       .on_open = (void*)http1_alloc, .udata = settings_copy);
}
示例#3
0
/*
 * 	Call the function_name inside the module
 * 	Store all vps in hashes %RAD_CHECK %RAD_REPLY %RAD_REQUEST
 *
 */
static int rlmperl_call(void *instance, REQUEST *request, char *function_name)
{

	PERL_INST	*inst = instance;
	VALUE_PAIR	*vp;
	int		exitstatus=0, count;
	STRLEN		n_a;

	HV		*rad_reply_hv;
	HV		*rad_check_hv;
	HV		*rad_request_hv;
	HV		*rad_request_proxy_hv;
	HV		*rad_request_proxy_reply_hv;

#ifdef USE_ITHREADS
	POOL_HANDLE	*handle;

	if ((handle = pool_pop(instance)) == NULL) {
		return RLM_MODULE_FAIL;
	}

	radlog(L_DBG,"found interpetator at address 0x%lx",(unsigned long) handle->clone);
	{
	dTHXa(handle->clone);
	PERL_SET_CONTEXT(handle->clone);
	}
#else
	PERL_SET_CONTEXT(inst->perl);
	radlog(L_DBG,"Using perl at 0x%lx",(unsigned long) inst->perl);
#endif
	{
	dSP;

	ENTER;
	SAVETMPS;


	/*
	 *	Radius has told us to call this function, but none
	 *	is defined.
	 */
	if (!function_name) {
		return RLM_MODULE_FAIL;
	}

	rad_reply_hv = get_hv("RAD_REPLY",1);
	rad_check_hv = get_hv("RAD_CHECK",1);
	rad_request_hv = get_hv("RAD_REQUEST",1);
	rad_request_proxy_hv = get_hv("RAD_REQUEST_PROXY",1);
	rad_request_proxy_reply_hv = get_hv("RAD_REQUEST_PROXY_REPLY",1);


	perl_store_vps(request->reply->vps, rad_reply_hv);
	perl_store_vps(request->config_items, rad_check_hv);
	perl_store_vps(request->packet->vps, rad_request_hv);
	
	if (request->proxy != NULL) {
		perl_store_vps(request->proxy->vps, rad_request_proxy_hv);
	} else {
		hv_undef(rad_request_proxy_hv);
	}

	if (request->proxy_reply !=NULL) {
		perl_store_vps(request->proxy_reply->vps, rad_request_proxy_reply_hv);
	} else {
		hv_undef(rad_request_proxy_reply_hv);
	}	
	
	vp = NULL;


	PUSHMARK(SP);
	/*
	* This way %RAD_xx can be pushed onto stack as sub parameters.
	* XPUSHs( newRV_noinc((SV *)rad_request_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_reply_hv) );
	* XPUSHs( newRV_noinc((SV *)rad_check_hv) );
	* PUTBACK;
	*/

	count = call_pv(function_name, G_SCALAR | G_EVAL | G_NOARGS);

	SPAGAIN;

	if (SvTRUE(ERRSV)) {
		radlog(L_ERR, "rlm_perl: perl_embed:: module = %s , func = %s exit status= %s\n",
		       inst->module,
		       function_name, SvPV(ERRSV,n_a));
		POPs;
	}

	if (count == 1) {
		exitstatus = POPi;
		if (exitstatus >= 100 || exitstatus < 0) {
			exitstatus = RLM_MODULE_FAIL;
		}
	}
	

	PUTBACK;
	FREETMPS;
	LEAVE;


	if ((get_hv_content(rad_reply_hv, &vp)) > 0 ) {
		pairmove(&request->reply->vps, &vp);
		pairfree(&vp);
	}

	if ((get_hv_content(rad_check_hv, &vp)) > 0 ) {
		pairmove(&request->config_items, &vp);
		pairfree(&vp);
	}
	
	if ((get_hv_content(rad_request_proxy_reply_hv, &vp)) > 0 && request->proxy_reply != NULL) {
		pairfree(&request->proxy_reply->vps);
		pairmove(&request->proxy_reply->vps, &vp);
		pairfree(&vp);
	}
	}
#ifdef USE_ITHREADS
	pool_release(handle,instance);
	radlog(L_DBG,"Unreserve perl at address 0x%lx", (unsigned long) handle->clone);
#endif

	return exitstatus;
}
示例#4
0
/*
 * The xlat function
 */
static int perl_xlat(void *instance, REQUEST *request, char *fmt, char * out,
		     size_t freespace, RADIUS_ESCAPE_STRING func)
{

	PERL_INST	*inst= (PERL_INST *) instance;
	PerlInterpreter *perl;
	char		params[1024], *ptr, *tmp;
	int		count, ret=0;
	STRLEN		n_a;

	/*
	 * Do an xlat on the provided string (nice recursive operation).
	*/
	if (!radius_xlat(params, sizeof(params), fmt, request, func)) {
		radlog(L_ERR, "rlm_perl: xlat failed.");
		return 0;
	}
#ifndef USE_ITHREADS
	perl = inst->perl;
#endif
#ifdef USE_ITHREADS
	POOL_HANDLE	*handle;

	if ((handle = pool_pop(instance)) == NULL) {
		return 0;
	}

	perl = handle->clone;

	radlog(L_DBG,"Found a interpetator 0x%lx",(unsigned long) perl);
	{
	dTHXa(perl);
	}
#endif
	PERL_SET_CONTEXT(perl);
	{
	dSP;
	ENTER;SAVETMPS;

	ptr = strtok(params, " ");

	PUSHMARK(SP);

	while (ptr != NULL) {
		XPUSHs(sv_2mortal(newSVpv(ptr,0)));
		ptr = strtok(NULL, " ");
	}

	PUTBACK;

	count = call_pv(inst->func_xlat, G_SCALAR | G_EVAL);

	SPAGAIN;
	if (SvTRUE(ERRSV)) {
		radlog(L_ERR, "rlm_perl: perl_xlat exit %s\n",
		       SvPV(ERRSV,n_a));
		POPs ;
	} else if (count > 0) {
		tmp = POPp;
		ret = strlen(tmp);
		strncpy(out,tmp,ret);

		radlog(L_DBG,"rlm_perl: Len is %d , out is %s freespace is %d",
		       ret, out,freespace);
	}

	PUTBACK ;
	FREETMPS ;
	LEAVE ;

	}
#ifdef USE_ITHREADS
	pool_release(handle, instance);
#endif
	return ret;
}