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; }
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); }
/* * 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; }
/* * 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; }