static void pool_region_create(struct kore_pool *pool, u_int32_t elms) { u_int32_t i; u_int8_t *p; struct kore_pool_region *reg; struct kore_pool_entry *entry; kore_debug("pool_region_create(%p, %d)", pool, elms); reg = kore_malloc(sizeof(struct kore_pool_region)); LIST_INSERT_HEAD(&(pool->regions), reg, list); reg->start = kore_malloc(elms * pool->slen); p = (u_int8_t *)reg->start; for (i = 0; i < elms; i++) { entry = (struct kore_pool_entry *)p; entry->region = reg; entry->state = POOL_ELEMENT_FREE; LIST_INSERT_HEAD(&(pool->freelist), entry, list); p = p + pool->slen; } pool->elms += elms; }
struct kore_buf * kore_buf_create(u_int32_t initial) { struct kore_buf *buf; buf = kore_malloc(sizeof(*buf)); buf->data = kore_malloc(initial); buf->length = initial; buf->offset = 0; return (buf); }
void kore_buf_replace_string(struct kore_buf *b, char *src, void *dst, size_t len) { char *key, *end, *tmp, *p; size_t blen, off, off2, nlen, klen; off = 0; klen = strlen(src); for (;;) { blen = b->offset; nlen = blen + len; p = (char *)b->data; key = kore_mem_find(p + off, b->offset - off, src, klen); if (key == NULL) break; end = key + klen; off = key - p; off2 = ((char *)(b->data + b->offset) - end); tmp = kore_malloc(nlen); memcpy(tmp, p, off); if (dst != NULL) memcpy((tmp + off), dst, len); memcpy((tmp + off + len), end, off2); kore_free(b->data); b->data = (u_int8_t *)tmp; b->offset = off + len + off2; b->length = nlen; off = off + len; } }
/* The initial state, we setup our context and fire off the pgsql query. */ int request_perform_query(struct http_request *req) { struct rstate *state; /* Setup our state context. */ state = kore_malloc(sizeof(*state)); /* Attach the state to our request. */ req->hdlr_extra = state; /* We want to move to read result after this. */ req->fsm_state = REQ_STATE_DB_WAIT; /* Fire off the query. */ if (!kore_pgsql_async(&state->sql, req, "SELECT * FROM coders")) { /* If the state was still INIT, we'll try again later. */ if (state->sql.state == KORE_PGSQL_STATE_INIT) { req->fsm_state = REQ_STATE_QUERY; return (HTTP_STATE_RETRY); } /* * Let the state machine continue immediately since we * have an error anyway. */ return (HTTP_STATE_CONTINUE); } /* Resume state machine later when the query results start coming in. */ return (HTTP_STATE_RETRY); }
attrlist_t attrinit(void) { attrlist_t al; al=kore_malloc(sizeof *al); al->len=0; al->data=NULL; return al; }
void net_send_queue(struct connection *c, void *data, u_int32_t len, struct spdy_stream *s, int before) { u_int8_t *d; struct netbuf *nb; u_int32_t avail; kore_debug("net_send_queue(%p, %p, %d, %p, %d)", c, data, len, s, before); d = data; if (before == NETBUF_LAST_CHAIN) { nb = TAILQ_LAST(&(c->send_queue), netbuf_head); if (nb != NULL && !(nb->flags & NETBUF_IS_STREAM) && nb->stream == s && nb->b_len < nb->m_len) { avail = nb->m_len - nb->b_len; if (len < avail) { memcpy(nb->buf + nb->b_len, d, len); nb->b_len += len; return; } else if (len > avail) { memcpy(nb->buf + nb->b_len, d, avail); nb->b_len += avail; len -= avail; d += avail; if (len == 0) return; } } } nb = kore_pool_get(&nb_pool); nb->flags = 0; nb->cb = NULL; nb->owner = c; nb->s_off = 0; nb->stream = s; nb->b_len = len; nb->type = NETBUF_SEND; if (nb->b_len < NETBUF_SEND_PAYLOAD_MAX) nb->m_len = NETBUF_SEND_PAYLOAD_MAX; else nb->m_len = nb->b_len; nb->buf = kore_malloc(nb->m_len); if (len > 0) memcpy(nb->buf, d, nb->b_len); if (before == NETBUF_BEFORE_CHAIN) { TAILQ_INSERT_BEFORE(c->snb, nb, list); } else { TAILQ_INSERT_TAIL(&(c->send_queue), nb, list); } }
static struct entry *create_entry(unsigned type, const char *data, unsigned len) { struct entry *ret; ret=kore_malloc(sizeof *ret); ret->type=type; ret->len=len; ret->data=data; ret->next=0; return ret; }
void * kore_calloc(size_t memb, size_t len) { if (memb == 0 || len == 0) fatal("kore_calloc(): zero size"); if (SIZE_MAX / memb < len) fatal("kore_calloc: memb * len > SIZE_MAX"); return (kore_malloc(memb * len)); }
struct kore_buf * kore_buf_alloc(size_t initial) { struct kore_buf *buf; buf = kore_malloc(sizeof(*buf)); kore_buf_init(buf, initial); buf->flags = KORE_BUF_OWNER_API; return (buf); }
void * kore_realloc(void *ptr, size_t len) { struct meminfo *mem; void *nptr; if (ptr == NULL) { nptr = kore_malloc(len); } else { mem = KORE_MEMINFO(ptr); if (mem->magic != KORE_MEM_MAGIC) fatal("kore_realloc(): magic boundary not found"); nptr = kore_malloc(len); memcpy(nptr, ptr, KORE_MEMSIZE(ptr)); kore_mem_free(ptr); } return (nptr); }
void kore_buf_init(struct kore_buf *buf, size_t initial) { if (initial > 0) buf->data = kore_malloc(initial); else buf->data = NULL; buf->length = initial; buf->offset = 0; buf->flags = 0; }
char * kore_strdup(const char *str) { size_t len; char *nstr; len = strlen(str) + 1; nstr = kore_malloc(len); kore_strlcpy(nstr, str, len); return (nstr); }
/* set an attribute */ static void attrsetn_internal(attrlist_t al, const char *name, int safe_fl, const _char *value, size_t len) { attr_t *at; at=setup_access(al, name); /* a null value would delete the attribute */ if(value==NULL) { if(at) attrdel(al, at); /* delete if there is no value */ return; } /* discard the old attribute values */ kore_mem_free(at->value); at->value=NULL; /* set the attribute */ if(safe_fl) { at->len=html_escape_len(value, len); at->value=kore_malloc(at->len+1); html_escape(at->value, at->len, value); } else { at->len=len; at->value=kore_malloc(len+1); memcpy(at->value, value, at->len+1); } }
static void task_thread_spawn(struct kore_task_thread **out) { struct kore_task_thread *tt; tt = kore_malloc(sizeof(*tt)); tt->idx = threads++; TAILQ_INIT(&(tt->tasks)); pthread_cond_init(&(tt->cond), NULL); pthread_mutex_init(&(tt->lock), NULL); if (pthread_create(&(tt->tid), NULL, task_thread, tt) != 0) fatal("pthread_create: %s", errno_s); *out = tt; }
int kore_connection_accept(struct listener *l, struct connection **out) { socklen_t len; struct connection *c; kore_debug("kore_connection_accept(%p)", l); *out = NULL; len = sizeof(struct sockaddr_in); c = (struct connection *)kore_malloc(sizeof(*c)); if ((c->fd = accept(l->fd, (struct sockaddr *)&(c->sin), &len)) == -1) { kore_mem_free(c); kore_debug("accept(): %s", errno_s); return (KORE_RESULT_ERROR); } if (!kore_connection_nonblock(c->fd)) { close(c->fd); kore_mem_free(c); return (KORE_RESULT_ERROR); } c->owner = l; c->ssl = NULL; c->flags = 0; c->inflate_started = 0; c->deflate_started = 0; c->client_stream_id = 0; c->proto = CONN_PROTO_UNKNOWN; c->state = CONN_STATE_SSL_SHAKE; c->wsize_initial = SPDY_INIT_WSIZE; c->idle_timer.start = 0; c->idle_timer.length = KORE_IDLE_TIMER_MAX; TAILQ_INIT(&(c->send_queue)); TAILQ_INIT(&(c->recv_queue)); TAILQ_INIT(&(c->spdy_streams)); kore_worker_connection_add(c); kore_connection_start_idletimer(c); *out = c; return (KORE_RESULT_OK); }
void net_recv_queue(struct connection *c, u_int32_t len, int flags, int (*cb)(struct netbuf *)) { kore_debug("net_recv_queue(): %p %d %d", c, len, flags); if (c->rnb != NULL) fatal("net_recv_queue(): called incorrectly for %p", c); c->rnb = kore_pool_get(&nb_pool); c->rnb->cb = cb; c->rnb->owner = c; c->rnb->s_off = 0; c->rnb->b_len = len; c->rnb->m_len = len; c->rnb->extra = NULL; c->rnb->flags = flags; c->rnb->type = NETBUF_RECV; c->rnb->buf = kore_malloc(c->rnb->b_len); }
void net_recv_reset(struct connection *c, u_int32_t len, int (*cb)(struct netbuf *)) { kore_debug("net_recv_reset(): %p %d", c, len); if (c->rnb->type != NETBUF_RECV) fatal("net_recv_reset(): wrong netbuf type"); c->rnb->cb = cb; c->rnb->s_off = 0; c->rnb->b_len = len; if (c->rnb->b_len <= c->rnb->m_len && c->rnb->m_len < (NETBUF_SEND_PAYLOAD_MAX / 2)) return; kore_mem_free(c->rnb->buf); c->rnb->m_len = len; c->rnb->buf = kore_malloc(c->rnb->m_len); }
void * kore_calloc(size_t memb, size_t len) { return (kore_malloc(memb * len)); }
int main(int argc, char *argv[]) { int ch, flags; flags = 0; #if !defined(KORE_SINGLE_BINARY) while ((ch = getopt(argc, argv, "c:dfhnrv")) != -1) { #else while ((ch = getopt(argc, argv, "dfhnrv")) != -1) { #endif flags++; switch (ch) { #if !defined(KORE_SINGLE_BINARY) case 'c': config_file = optarg; break; #endif #if defined(KORE_DEBUG) case 'd': kore_debug = 1; break; #endif case 'f': foreground = 1; break; case 'h': usage(); break; case 'n': skip_chroot = 1; break; case 'r': skip_runas = 1; break; case 'v': version(); break; default: usage(); } } argc -= optind; argv += optind; kore_mem_init(); #if !defined(KORE_SINGLE_BINARY) if (argc > 0) { if (flags) fatal("You cannot specify kore flags and a command"); return (kore_cli_main(argc, argv)); } #endif kore_pid = getpid(); nlisteners = 0; LIST_INIT(&listeners); kore_log_init(); #if !defined(KORE_NO_HTTP) kore_auth_init(); kore_validator_init(); #endif kore_domain_init(); kore_module_init(); kore_server_sslstart(); #if !defined(KORE_SINGLE_BINARY) if (config_file == NULL) usage(); #else kore_module_load(NULL, NULL); #endif kore_parse_config(); kore_platform_init(); #if !defined(KORE_NO_HTTP) kore_accesslog_init(); if (http_body_disk_offload > 0) { if (mkdir(http_body_disk_path, 0700) == -1 && errno != EEXIST) { printf("can't create http_body_disk_path '%s': %s\n", http_body_disk_path, errno_s); return (KORE_RESULT_ERROR); } } #endif sig_recv = 0; signal(SIGHUP, kore_signal); signal(SIGQUIT, kore_signal); signal(SIGTERM, kore_signal); if (foreground) signal(SIGINT, kore_signal); else signal(SIGINT, SIG_IGN); kore_server_start(); kore_log(LOG_NOTICE, "server shutting down"); kore_worker_shutdown(); if (!foreground) unlink(kore_pidfile); kore_listener_cleanup(); kore_log(LOG_NOTICE, "goodbye"); return (0); } #if !defined(KORE_NO_TLS) int kore_tls_sni_cb(SSL *ssl, int *ad, void *arg) { struct kore_domain *dom; const char *sname; sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); kore_debug("kore_tls_sni_cb(): received host %s", sname); if (sname != NULL && (dom = kore_domain_lookup(sname)) != NULL) { kore_debug("kore_ssl_sni_cb(): Using %s CTX", sname); SSL_set_SSL_CTX(ssl, dom->ssl_ctx); if (dom->cafile != NULL) { SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); } else { SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); } return (SSL_TLSEXT_ERR_OK); } return (SSL_TLSEXT_ERR_NOACK); } void kore_tls_info_callback(const SSL *ssl, int flags, int ret) { struct connection *c; if (flags & SSL_CB_HANDSHAKE_START) { if ((c = SSL_get_app_data(ssl)) == NULL) fatal("no SSL_get_app_data"); c->tls_reneg++; } } #endif int kore_server_bind(const char *ip, const char *port, const char *ccb) { struct listener *l; int on, r; struct addrinfo hints, *results; kore_debug("kore_server_bind(%s, %s)", ip, port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = 0; r = getaddrinfo(ip, port, &hints, &results); if (r != 0) fatal("getaddrinfo(%s): %s", ip, gai_strerror(r)); l = kore_malloc(sizeof(struct listener)); l->type = KORE_TYPE_LISTENER; l->addrtype = results->ai_family; if (l->addrtype != AF_INET && l->addrtype != AF_INET6) fatal("getaddrinfo(): unknown address family %d", l->addrtype); if ((l->fd = socket(results->ai_family, SOCK_STREAM, 0)) == -1) { kore_free(l); freeaddrinfo(results); kore_debug("socket(): %s", errno_s); printf("failed to create socket: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (!kore_connection_nonblock(l->fd, 1)) { kore_free(l); freeaddrinfo(results); printf("failed to make socket non blocking: %s\n", errno_s); return (KORE_RESULT_ERROR); } on = 1; if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)) == -1) { close(l->fd); kore_free(l); freeaddrinfo(results); kore_debug("setsockopt(): %s", errno_s); printf("failed to set SO_REUSEADDR: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (bind(l->fd, results->ai_addr, results->ai_addrlen) == -1) { close(l->fd); kore_free(l); freeaddrinfo(results); kore_debug("bind(): %s", errno_s); printf("failed to bind to %s port %s: %s\n", ip, port, errno_s); return (KORE_RESULT_ERROR); } freeaddrinfo(results); if (listen(l->fd, kore_socket_backlog) == -1) { close(l->fd); kore_free(l); kore_debug("listen(): %s", errno_s); printf("failed to listen on socket: %s\n", errno_s); return (KORE_RESULT_ERROR); } if (ccb != NULL) { *(void **)&(l->connect) = kore_module_getsym(ccb); if (l->connect == NULL) { printf("no such callback: '%s'\n", ccb); close(l->fd); kore_free(l); return (KORE_RESULT_ERROR); } } else { l->connect = NULL; } nlisteners++; LIST_INSERT_HEAD(&listeners, l, list); if (foreground) { #if !defined(KORE_NO_TLS) kore_log(LOG_NOTICE, "running on https://%s:%s", ip, port); #else kore_log(LOG_NOTICE, "running on http://%s:%s", ip, port); #endif } return (KORE_RESULT_OK); } void kore_listener_cleanup(void) { struct listener *l; while (!LIST_EMPTY(&listeners)) { l = LIST_FIRST(&listeners); LIST_REMOVE(l, list); close(l->fd); kore_free(l); } } void kore_signal(int sig) { sig_recv = sig; } static void kore_server_sslstart(void) { #if !defined(KORE_NO_TLS) kore_debug("kore_server_sslstart()"); SSL_library_init(); SSL_load_error_strings(); #endif }
int page_handler(struct http_request *req) { u_int32_t len; struct rstate *state; char *user, result[64]; /* * Lets check if a task has been created yet, this is important * as we only want to fire this off once and we will be called * again once it has been created. * * In this example, we'll store our state with our task in hdlr_extra. */ if (req->hdlr_extra == NULL) { /* Grab the user argument */ http_populate_arguments(req); if (!http_argument_get_string("user", &user, &len)) { http_response(req, 500, "ERROR\n", 6); return (KORE_RESULT_OK); } /* * Allocate rstate and bind it to the hdlr_extra field. * Kore automatically frees this when freeing the result. */ state = kore_malloc(sizeof(*state)); req->hdlr_extra = state; /* * Create a new task that will execute the run_curl() * function and bind it to our request. * * Binding a task to a request means Kore will reschedule * the page handler for that request to refire after the * task has completed or when it writes on the task channel. */ kore_task_create(&state->task, run_curl); kore_task_bind_request(&state->task, req); /* * Start the task and write the user we received in our * GET request to its channel. */ kore_task_run(&state->task); kore_task_channel_write(&state->task, user, len); /* * Tell Kore to retry us later. */ return (KORE_RESULT_RETRY); } else { state = req->hdlr_extra; } /* * Our page handler is scheduled to be called when either the * task finishes or has written data onto the channel. * * In order to distinguish between the two we can inspect the * state of the task. */ if (kore_task_state(&state->task) != KORE_TASK_STATE_FINISHED) { http_request_sleep(req); return (KORE_RESULT_RETRY); } /* * Task is finished, check the result. */ if (kore_task_result(&state->task) != KORE_RESULT_OK) { kore_task_destroy(&state->task); http_response(req, 500, NULL, 0); return (KORE_RESULT_OK); } /* * Lets read what our task has written to the channel. * * kore_task_channel_read() will return the amount of bytes * that it received for that read. If the returned bytes is * larger then the buffer you passed this is a sign of truncation * and should be treated carefully. */ len = kore_task_channel_read(&state->task, result, sizeof(result)); if (len > sizeof(result)) { http_response(req, 500, NULL, 0); } else { http_response(req, 200, result, len); } /* We good, destroy the task. */ kore_task_destroy(&state->task); return (KORE_RESULT_OK); }