static void accesslog_flush(struct kore_domain *dom, u_int64_t now, int force) { ssize_t written; if (force && dom->logbuf == NULL) return; if (force || dom->logbuf->offset >= DOMAIN_LOGBUF_LEN) { written = write(dom->accesslog, dom->logbuf->data, dom->logbuf->offset); if (written == -1) { if (errno == EINTR) return; if (dom->logwarn == 0 || errno != dom->logerr) { kore_log(LOG_NOTICE, "error writing log for %s (%s)", dom->domain, errno_s); dom->logwarn = now; dom->logerr = errno; } kore_buf_reset(dom->logbuf); return; } if ((size_t)written != dom->logbuf->offset) { kore_log(LOG_ERR, "partial accesslog write for %s", dom->domain); } kore_buf_reset(dom->logbuf); } }
void my_callback(void) { if (worker != NULL) kore_log(LOG_NOTICE, "running on worker %d", worker->id); else kore_log(LOG_NOTICE, "running from parent"); }
void kore_accesslog(struct http_request *req) { struct kore_log_packet logpacket; logpacket.addrtype = req->owner->addrtype; if (logpacket.addrtype == AF_INET) { memcpy(logpacket.addr, &(req->owner->addr.ipv4.sin_addr), sizeof(req->owner->addr.ipv4.sin_addr)); } else { memcpy(logpacket.addr, &(req->owner->addr.ipv6.sin6_addr), sizeof(req->owner->addr.ipv6.sin6_addr)); } logpacket.status = req->status; logpacket.method = req->method; logpacket.worker_id = worker->id; logpacket.worker_cpu = worker->cpu; logpacket.time_req = req->total; if (kore_strlcpy(logpacket.host, req->host, sizeof(logpacket.host)) >= sizeof(logpacket.host)) kore_log(LOG_NOTICE, "kore_accesslog: host truncated"); if (kore_strlcpy(logpacket.path, req->path, sizeof(logpacket.path)) >= sizeof(logpacket.path)) kore_log(LOG_NOTICE, "kore_accesslog: path truncated"); if (req->agent != NULL) { if (kore_strlcpy(logpacket.agent, req->agent, sizeof(logpacket.agent)) >= sizeof(logpacket.agent)) kore_log(LOG_NOTICE, "kore_accesslog: agent truncated"); } else { (void)kore_strlcpy(logpacket.agent, "unknown", sizeof(logpacket.agent)); } #if !defined(KORE_NO_TLS) memset(logpacket.cn, '\0', sizeof(logpacket.cn)); if (req->owner->cert != NULL) { if (X509_GET_CN(req->owner->cert, logpacket.cn, sizeof(logpacket.cn)) == -1) { kore_log(LOG_WARNING, "client cert without a CN?"); } } #endif kore_msg_send(KORE_MSG_PARENT, KORE_MSG_ACCESSLOG, &logpacket, sizeof(logpacket)); }
void kore_accesslog(struct http_request *req) { ssize_t len; struct kore_log_packet logpacket; logpacket.addrtype = req->owner->addrtype; if (logpacket.addrtype == AF_INET) { memcpy(logpacket.addr, &(req->owner->addr.ipv4.sin_addr), sizeof(req->owner->addr.ipv4.sin_addr)); } else { memcpy(logpacket.addr, &(req->owner->addr.ipv6.sin6_addr), sizeof(req->owner->addr.ipv6.sin6_addr)); } logpacket.status = req->status; logpacket.method = req->method; logpacket.worker_id = worker->id; logpacket.worker_cpu = worker->cpu; logpacket.time_req = req->total; kore_strlcpy(logpacket.host, req->host, sizeof(logpacket.host)); kore_strlcpy(logpacket.path, req->path, sizeof(logpacket.path)); if (req->agent != NULL) { kore_strlcpy(logpacket.agent, req->agent, sizeof(logpacket.agent)); } else { kore_strlcpy(logpacket.agent, "unknown", sizeof(logpacket.agent)); } memset(logpacket.cn, '\0', sizeof(logpacket.cn)); #if !defined(KORE_BENCHMARK) if (req->owner->cert != NULL) { if (X509_GET_CN(req->owner->cert, logpacket.cn, sizeof(logpacket.cn)) == -1) { kore_log(LOG_WARNING, "client cert without a CN?"); } } #endif len = send(accesslog_fd[1], &logpacket, sizeof(logpacket), 0); if (len == -1) { kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s); } else if (len != sizeof(logpacket)) { kore_log(LOG_WARNING, "short accesslog packet sent"); } }
void example_load(int state) { switch (state) { case KORE_MODULE_LOAD: kore_log(LOG_NOTICE, "module loading"); break; case KORE_MODULE_UNLOAD: kore_log(LOG_NOTICE, "module unloading"); break; default: kore_log(LOG_NOTICE, "state %d unknown!", state); break; } }
/* al - NULL to use a "dumping" mode */ void template_apply(template_t *t, attrlist_t al, kore_buf_t *out) { struct entry *e; char buf[64]; /* TODO: max macro length */ attr_t *tmp; /* TODO: we could cache the attrget lookup */ // fflush(stdout); /* we'll be using posix i/o instead of iso c */ for(e=t->entry_list;e;e=e->next) { // kore_log(LOG_DEBUG,"::%u:%u:%.*s", // e->type, e->len, e->len, e->data); /* ignore macro type if the macro is too large */ if(al && e->type && (e->len<(sizeof buf-1))) { memcpy(buf, e->data, e->len); buf[e->len]=0; tmp = attrget(al, buf); if(tmp) kore_buf_append(out, tmp->value, tmp->len); } else if(!al && e->type) { /* debug mode because al==NULL */ kore_log(LOG_DEBUG,"%s (%u)", e->data, e->len); } else { /* raw data */ if(e->data) kore_buf_append(out,e->data,e->len); } } }
// TODO: split this in two functions: one to retrieve attr and one to // strcat contents into it. void attrcatn(attrlist_t al, const char *name, const _char *value, size_t len) { attr_t *at; size_t oldlen; _char *newvalue; 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; } /* append the string */ oldlen = at->len; // kore_log(LOG_DEBUG,"attr realloc from %u to %u for value: %s", // oldlen, oldlen+len+1, value); newvalue = kore_realloc(at->value, oldlen+len+1); if(!newvalue) { kore_log(LOG_ERR,"attrcatn realloc to size %u", oldlen+len+1); return; } at->len = oldlen+len+1; strncat(newvalue,value,len); at->value=newvalue; }
int serve_index(struct http_request *req) { kore_log(1, "Request dude!"); http_response(req, 200, asset_index_html, asset_len_index_html); return (KORE_RESULT_OK); }
/* * After firing off the query, we returned HTTP_STATE_RETRY (see above). * When request_db_wait() finally is called by Kore we will have results * from pgsql so we'll process them. */ int request_db_wait(struct http_request *req) { struct rstate *state = req->hdlr_extra; kore_log(LOG_NOTICE, "request_db_wait: %d", state->sql.state); /* * When we get here, our asynchronous pgsql query has * given us something, check the state to figure out what. */ switch (state->sql.state) { case KORE_PGSQL_STATE_WAIT: return (HTTP_STATUS_RETRY); case KORE_PGSQL_STATE_COMPLETE: req->fsm_state = REQ_STATE_DONE; break; case KORE_PGSQL_STATE_ERROR: req->fsm_state = REQ_STATE_ERROR; kore_pgsql_logerror(&state->sql); break; case KORE_PGSQL_STATE_RESULT: req->fsm_state = REQ_STATE_DB_READ; break; default: /* This MUST be present in order to advance the pgsql state */ kore_pgsql_continue(req, &state->sql); break; } return (HTTP_STATE_CONTINUE); }
/* Page handler entry point (see config) */ int page(struct http_request *req) { /* Drop into our state machine. */ kore_log(LOG_NOTICE, "page start"); return (http_state_run(mystates, sizeof(mystates), req)); }
void * kore_pool_get(struct kore_pool *pool) { u_int8_t *ptr; struct kore_pool_entry *entry; if (LIST_EMPTY(&(pool->freelist))) { kore_log(LOG_NOTICE, "pool %s is exhausted (%d/%d)", pool->name, pool->inuse, pool->elms); pool_region_create(pool, pool->elms); } entry = LIST_FIRST(&(pool->freelist)); if (entry->state != POOL_ELEMENT_FREE) fatal("%s: element %p was not free", pool->name, entry); LIST_REMOVE(entry, list); entry->state = POOL_ELEMENT_BUSY; ptr = (u_int8_t *)entry + sizeof(struct kore_pool_entry); pool->inuse++; return (ptr); }
int serve_lock_test(struct http_request *req) { kore_log(LOG_NOTICE, "lock-test called on worker %d", worker->id); kore_worker_acceptlock_release(); http_response(req, 200, "OK", 2); return (KORE_RESULT_OK); }
int v_session_validate(struct http_request *req, char *data) { kore_log(LOG_NOTICE, "v_session_validate: %s", data); if (!strcmp(data, "test123")) return (KORE_RESULT_OK); return (KORE_RESULT_ERROR); }
int v_example_func(struct http_request *req, char *data) { kore_log(LOG_NOTICE, "v_example_func called"); if (!strcmp(data, "test")) return (KORE_RESULT_OK); return (KORE_RESULT_ERROR); }
int thing_show(struct http_request *req) { int rc; template_t tmpl; attrlist_t attributes; char *zErrMsg = 0; char *macaddr; http_populate_get(req); // we shouldn't free the result in macaddr if (http_argument_get_string(req, "macaddr", &macaddr)) kore_log(LOG_DEBUG, "thing_show macaddr %s",macaddr); else kore_log(LOG_ERR,"thing_show get argument error"); // prepare query snprintf(line,ml,"SELECT * FROM found WHERE macaddr = '%s'",macaddr); // allocate output buffer buf = kore_buf_create(mb); // load template template_load (asset_thing_show_html, asset_len_thing_show_html, &tmpl); attributes = attrinit(); attrcat(attributes, "title", "Dowse information panel"); // SQL query sqlquery(line, thing_show_cb, attributes); template_apply(&tmpl,attributes,buf); http_response(req, 200, buf->data, buf->offset); template_free(&tmpl); attrfree(attributes); kore_buf_free(buf); return (KORE_RESULT_OK); }
int example_load(int state) { switch (state) { case KORE_MODULE_LOAD: kore_log(LOG_NOTICE, "module loading"); /* Set server version */ http_server_version("Server/0.1"); break; case KORE_MODULE_UNLOAD: kore_log(LOG_NOTICE, "module unloading"); break; default: kore_log(LOG_NOTICE, "state %d unknown!", state); break; } return (KORE_RESULT_OK); }
void kore_platform_event_schedule(int fd, int type, int flags, void *data) { if (nchanges >= KQUEUE_EVENTS) { kore_log(LOG_WARNING, "cannot schedule %d (%d) on %d", type, flags, fd); } else { EV_SET(&changelist[nchanges], fd, type, flags, 0, 0, data); nchanges++; } }
int blog_posts(struct http_request *req) { if (req->method != HTTP_METHOD_GET) { http_response_header(req, "allow", "GET"); http_response(req, 405, NULL, 0); return (KORE_RESULT_OK); } http_response_header(req, "content-type", "application/json"); http_response(req, 200, asset_home_json, asset_len_home_json); kore_log(LOG_NOTICE, "GET BLOG POSTS"); return (KORE_RESULT_OK); }
/* * This function is called for backends while they are connecting. * In here we check for write events and attempt to connect() to the * backend. * * Once a connection is established we set the backend handle function * pointer to the backend_handle_default() callback and setup the reads * for both the backend and the client connection we received. */ int backend_handle_connect(struct connection *c) { int ret; struct connection *src; /* We will get a write notification when we can progress. */ if (!(c->flags & CONN_WRITE_POSSIBLE)) return (KORE_RESULT_OK); kore_connection_stop_idletimer(c); /* Attempt connecting. */ ret = connect(c->fd, (struct sockaddr *)&c->addr.ipv4, sizeof(c->addr.ipv4)); /* If we failed check why, we are non blocking. */ if (ret == -1) { /* If we got a real error, disconnect. */ if (errno != EALREADY && errno != EINPROGRESS && errno != EISCONN) { kore_log(LOG_ERR, "connect(): %s", errno_s); return (KORE_RESULT_ERROR); } /* Clean the write flag, we'll be called later. */ if (errno != EISCONN) { c->flags &= ~CONN_WRITE_POSSIBLE; kore_connection_start_idletimer(c); return (KORE_RESULT_OK); } } /* The connection to the backend succeeded. */ c->handle = backend_handle_default; /* Setup read calls for both backend and its client. */ net_recv_queue(c, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS, pipe_data); net_recv_queue(c->hdlr_extra, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS, pipe_data); /* Allow for all events now. */ kore_connection_start_idletimer(c); kore_platform_event_all(c->fd, c); /* Allow events from source now. */ src = c->hdlr_extra; kore_platform_event_all(src->fd, src); /* Now lets start. */ return (c->handle(c)); }
void kore_accesslog(struct http_request *req) { ssize_t len; struct kore_log_packet logpacket; logpacket.addrtype = req->owner->addrtype; if (logpacket.addrtype == AF_INET) { memcpy(logpacket.addr, &(req->owner->addr.ipv4.sin_addr), sizeof(req->owner->addr.ipv4.sin_addr)); } else { memcpy(logpacket.addr, &(req->owner->addr.ipv6.sin6_addr), sizeof(req->owner->addr.ipv6.sin6_addr)); } logpacket.status = req->status; logpacket.method = req->method; logpacket.worker_id = worker->id; logpacket.worker_cpu = worker->cpu; logpacket.time_req = req->end - req->start; kore_strlcpy(logpacket.host, req->host, sizeof(logpacket.host)); kore_strlcpy(logpacket.path, req->path, sizeof(logpacket.path)); if (req->agent != NULL) { kore_strlcpy(logpacket.agent, req->agent, sizeof(logpacket.agent)); } else { kore_strlcpy(logpacket.agent, "unknown", sizeof(logpacket.agent)); } len = send(accesslog_fd[1], &logpacket, sizeof(logpacket), 0); if (len == -1) { kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s); } else if (len != sizeof(logpacket)) { kore_log(LOG_WARNING, "short accesslog packet sent"); } }
void kore_accesslog(struct http_request *req) { ssize_t len; struct kore_log_packet logpacket; logpacket.status = req->status; logpacket.method = req->method; logpacket.worker_id = worker->id; logpacket.worker_cpu = worker->cpu; logpacket.src = req->owner->sin.sin_addr; logpacket.time_req = req->end - req->start; kore_strlcpy(logpacket.host, req->host, sizeof(logpacket.host)); kore_strlcpy(logpacket.path, req->path, sizeof(logpacket.path)); kore_strlcpy(logpacket.agent, req->agent, sizeof(logpacket.agent)); len = send(accesslog_fd[1], &logpacket, sizeof(logpacket), 0); if (len == -1) { kore_log(LOG_WARNING, "kore_accesslog(): send(): %s", errno_s); } else if (len != sizeof(logpacket)) { kore_log(LOG_WARNING, "short accesslog packet sent"); } }
// same as sqlite3_exec int sqlquery(char *query, int (*callback)(void*,int,char**,char**), attrlist_t attrl) { int rc; char *zErrMsg = 0; // open db connection if(!db) { rc = sqlite3_open("/run/things.db", &db); if( rc ) { kore_log(LOG_ERR, "%s: %s\n", sqlite3_errmsg(db), "/run/things.db"); // retry rc = sqlite3_open(THINGS_DB, &db); if( rc ) { kore_log(LOG_ERR, "%s: %s\n", sqlite3_errmsg(db), THINGS_DB); return(KORE_RESULT_ERROR); } } } sqlite3_exec(db, query, callback, attrl, &zErrMsg); if( rc != SQLITE_OK ){ kore_log(LOG_ERR, "SQL error: %s\n", zErrMsg); sqlite3_free(zErrMsg); } }
/* * This function is called everytime we get up to 128 bytes of data. * The connection can be found under nb->owner. * The data received can be found under nb->buf. * The length of the received data can be found under s_off. */ int connection_recv_data(struct netbuf *nb) { struct connection *c = (struct connection *)nb->owner; kore_log(LOG_NOTICE, "%p: received %u bytes", c, nb->s_off); /* We will just dump these back to the client. */ net_send_queue(c, nb->buf, nb->s_off); net_send_flush(c); /* Now reset the receive command for the next one. */ net_recv_reset(c, 128, connection_recv_data); return (KORE_RESULT_OK); }
int serve_file_upload(struct http_request *req) { u_int8_t *d; struct kore_buf *b; struct http_file *f; size_t len; char *name, buf[BUFSIZ]; b = kore_buf_alloc(asset_len_upload_html); kore_buf_append(b, asset_upload_html, asset_len_upload_html); if (req->method == HTTP_METHOD_POST) { if (req->http_body_fd != -1) kore_log(LOG_NOTICE, "file is on disk"); http_populate_multipart_form(req); if (http_argument_get_string(req, "firstname", &name)) { kore_buf_replace_string(b, "$firstname$", name, strlen(name)); } else { kore_buf_replace_string(b, "$firstname$", NULL, 0); } if ((f = http_file_lookup(req, "file")) != NULL) { (void)snprintf(buf, sizeof(buf), "%s is %ld bytes", f->filename, f->length); kore_buf_replace_string(b, "$upload$", buf, strlen(buf)); } else { kore_buf_replace_string(b, "$upload$", NULL, 0); } } else { kore_buf_replace_string(b, "$upload$", NULL, 0); kore_buf_replace_string(b, "$firstname$", NULL, 0); } d = kore_buf_release(b, &len); http_response_header(req, "content-type", "text/html"); http_response(req, 200, d, len); kore_free(d); return (KORE_RESULT_OK); }
void connection_setup(struct connection *c) { kore_log(LOG_NOTICE, "%p: new connection", c); /* * Setup a read command that will read up to 128 bytes and will * always call the callback connection_recv_data even if not all * 128 bytes were read. */ net_recv_queue(c, 128, NETBUF_CALL_CB_ALWAYS, connection_recv_data); /* We are responsible for setting the connection state. */ c->state = CONN_STATE_ESTABLISHED; /* Override the handle function, called when new events occur. */ c->handle = connection_handle; }
int things_list(struct http_request *req) { int rc; char *zErrMsg = 0; char *query = "SELECT * FROM found ORDER BY last DESC"; template_t tmpl; attrlist_t attributes; struct timespec when; buf = kore_buf_create(mb); if(!thing) thing = hashmap_new(); // load template from assets template_load (asset_things_list_html, asset_len_things_list_html, &tmpl); // initialise attribute list attributes = attrinit(); if( ! parse_datetime(&when, "now", NULL) ) kore_log(LOG_ERR,"parse-datetime error"); else { struct tm *tt; tt = localtime (&when.tv_sec); mktime(tt); strftime(line, ml, "Dowse :: %d %m %Y - %H:%M:%S", tt); attrcat(attributes, "title", line); } sqlquery(query, things_list_cb, attributes); template_apply(&tmpl, attributes, buf); http_response(req, 200, buf->data, buf->offset); template_free(&tmpl); attrfree(attributes); kore_buf_free(buf); return (KORE_RESULT_OK); }
int serve_static(struct http_request *req) { char filename[7 + strlen(req->path)]; sprintf(filename, "assets%s", req->path); kore_log(1, filename); char *file_buffer = read_file(filename); long file_length = file_size(filename); if (file_buffer && file_length != -1) { http_response(req, 200, file_buffer, file_length); } else { http_response(req, 404, asset_404_html, asset_len_404_html); } return (KORE_RESULT_OK); }
/* * Called when there's an actual result to be gotten. After we handle the * entire result, we'll drop back into REQ_STATE_DB_WAIT (above) in order * to continue until the pgsql API returns KORE_PGSQL_STATE_COMPLETE. */ int request_db_read(struct http_request *req) { char *name; int i, rows; struct rstate *state = req->hdlr_extra; /* We have sql data to read! */ rows = kore_pgsql_ntuples(&state->sql); for (i = 0; i < rows; i++) { name = kore_pgsql_getvalue(&state->sql, i, 0); kore_log(LOG_NOTICE, "name: '%s'", name); } /* Continue processing our query results. */ kore_pgsql_continue(req, &state->sql); /* Back to our DB waiting state. */ req->fsm_state = REQ_STATE_DB_WAIT; return (HTTP_STATE_CONTINUE); }
int serve_validator(struct http_request *req) { if (kore_validator_run(NULL, "v_example", "test")) kore_log(LOG_NOTICE, "v_example ok (expected)"); else kore_log(LOG_NOTICE, "v_example failed"); if (kore_validator_run(NULL, "v_regex", "/test/123")) kore_log(LOG_NOTICE, "regex #1 ok"); else kore_log(LOG_NOTICE, "regex #1 failed (expected)"); if (kore_validator_run(NULL, "v_regex", "/test/joris")) kore_log(LOG_NOTICE, "regex #2 ok (expected)"); else kore_log(LOG_NOTICE, "regex #2 failed"); http_response(req, 200, "OK", 2); return (KORE_RESULT_OK); }
int kore_accesslog_wait(void) { ssize_t len; time_t now; struct kore_domain *dom; struct pollfd pfd[1]; int nfds, l; struct kore_log_packet logpacket; char addr[INET6_ADDRSTRLEN]; char *method, *buf, *tbuf, *cn; pfd[0].fd = accesslog_fd[0]; pfd[0].events = POLLIN; pfd[0].revents = 0; nfds = poll(pfd, 1, 1000); if (nfds == -1 || (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) { if (nfds == -1 && errno == EINTR) return (KORE_RESULT_OK); kore_log(LOG_WARNING, "poll(): %s", errno_s); return (KORE_RESULT_ERROR); } if (nfds == 0) return (KORE_RESULT_OK); len = recv(accesslog_fd[0], &logpacket, sizeof(logpacket), 0); if (len == -1) { kore_log(LOG_WARNING, "recv(): %s", errno_s); return (KORE_RESULT_ERROR); } if (len != sizeof(logpacket)) return (KORE_RESULT_ERROR); if ((dom = kore_domain_lookup(logpacket.host)) == NULL) { kore_log(LOG_WARNING, "got accesslog packet for unknown domain: %s", logpacket.host); return (KORE_RESULT_OK); } switch (logpacket.method) { case HTTP_METHOD_GET: method = "GET"; break; case HTTP_METHOD_POST: method = "POST"; break; default: method = "UNKNOWN"; break; } if (logpacket.cn[0] != '\0') cn = logpacket.cn; else cn = "none"; if (inet_ntop(logpacket.addrtype, &(logpacket.addr), addr, sizeof(addr)) == NULL) kore_strlcpy(addr, "unknown", sizeof(addr)); time(&now); tbuf = kore_time_to_date(now); l = asprintf(&buf, "[%s] %s %d %s %s (w#%d) (%dms) (%s) (%s)\n", tbuf, addr, logpacket.status, method, logpacket.path, logpacket.worker_id, logpacket.time_req, cn, logpacket.agent); if (l == -1) { kore_log(LOG_WARNING, "kore_accesslog_wait(): asprintf() == -1"); return (KORE_RESULT_ERROR); } len = write(dom->accesslog, buf, l); if (len == -1) { free(buf); kore_log(LOG_WARNING, "kore_accesslog_wait(): write(): %s", errno_s); return (KORE_RESULT_ERROR); } if (len != l) kore_log(LOG_NOTICE, "accesslog: %s", buf); free(buf); return (KORE_RESULT_OK); }