/* * Copyright (C) NGINX, Inc. */ #include #include //#include #include #include #include #define nxt_expect(c, x) __builtin_expect((long) (x), (c)) #define nxt_fast_path(x) nxt_expect(1, x) #define nxt_slow_path(x) nxt_expect(0, x) #define CONTENT_TYPE "Content-Type" #define TEXT_PLAIN "text/plain" #define NEW_LINE "\n" #define REQUEST_DATA "Request data:\n" #define METHOD " Method: " #define PROTOCOL " Protocol: " #define REMOTE_ADDR " Remote addr: " #define LOCAL_ADDR " Local addr: " #define TARGET " Target: " #define PATH " Path: " #define QUERY " Query: " #define FIELDS " Fields:\n" #define FIELD_PAD " " #define FIELD_SEP ": " #define BODY " Body:\n" static int ready_handler(nxt_unit_ctx_t *ctx); static void *worker(void *main_ctx); static void greeting_app_request_handler(nxt_unit_request_info_t *req); static int thread_count; static pthread_t *threads; int main(int argc, char **argv) { int i, err; nxt_unit_ctx_t *ctx; nxt_unit_init_t init; if (argc == 3 && strcmp(argv[1], "-t") == 0) { thread_count = atoi(argv[2]); } memset(&init, 0, sizeof(nxt_unit_init_t)); init.callbacks.request_handler = greeting_app_request_handler; init.callbacks.ready_handler = ready_handler; ctx = nxt_unit_init(&init); if (ctx == NULL) { return 1; } err = nxt_unit_run(ctx); nxt_unit_debug(ctx, "main worker finished with %d code", err); if (thread_count > 1) { for (i = 0; i < thread_count - 1; i++) { err = pthread_join(threads[i], NULL); if (nxt_fast_path(err == 0)) { nxt_unit_debug(ctx, "join thread #%d", i); } else { nxt_unit_alert(ctx, "pthread_join(#%d) failed: %s (%d)", i, strerror(err), err); } } nxt_unit_free(ctx, threads); } nxt_unit_done(ctx); nxt_unit_debug(NULL, "main worker done"); return 0; } static int ready_handler(nxt_unit_ctx_t *ctx) { int i, err; nxt_unit_debug(ctx, "ready"); if (thread_count <= 1) { return NXT_UNIT_OK; } threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1)); if (threads == NULL) { return NXT_UNIT_ERROR; } for (i = 0; i < thread_count - 1; i++) { err = pthread_create(&threads[i], NULL, worker, ctx); if (err != 0) { return NXT_UNIT_ERROR; } } return NXT_UNIT_OK; } static void * worker(void *main_ctx) { int rc; nxt_unit_ctx_t *ctx; ctx = nxt_unit_ctx_alloc(main_ctx, NULL); if (ctx == NULL) { return NULL; } nxt_unit_debug(ctx, "start worker"); rc = nxt_unit_run(ctx); nxt_unit_debug(ctx, "worker finished with %d code", rc); nxt_unit_done(ctx); return (void *) (intptr_t) rc; } static void greeting_app_request_handler(nxt_unit_request_info_t *req) { int rc; char *p; ssize_t res; uint32_t i; nxt_unit_buf_t *buf, *buf2; nxt_unit_field_t *f; nxt_unit_request_t *r; rc = nxt_unit_response_init(req, 200 /* Status code. */, 2 /* Number of response headers. */, strlen(CONTENT_TYPE) + strlen(TEXT_PLAIN) + strlen("Content-Length") + strlen("42") + strlen("Hello world\n!")); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_add_field(req, CONTENT_TYPE, strlen(CONTENT_TYPE), TEXT_PLAIN, strlen(TEXT_PLAIN)); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_add_field(req, "Content-Length", strlen("Content-Length"), "42", strlen("42")); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_add_content(req, "Hello", strlen("Hello")); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_add_content(req, " world!\n", strlen(" world!\n")); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_send(req); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } r = req->request; buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end - req->request_buf->start) + strlen(REQUEST_DATA) + strlen(METHOD) + strlen(NEW_LINE) + strlen(PROTOCOL) + strlen(NEW_LINE) + strlen(REMOTE_ADDR) + strlen(NEW_LINE) + strlen(LOCAL_ADDR) + strlen(NEW_LINE) + strlen(TARGET) + strlen(NEW_LINE) + strlen(PATH) + strlen(NEW_LINE) + strlen(QUERY) + strlen(NEW_LINE) + strlen(FIELDS) + r->fields_count * ( strlen(FIELD_PAD) + strlen(FIELD_SEP)) + strlen(BODY)); if (nxt_slow_path(buf == NULL)) { rc = NXT_UNIT_ERROR; goto fail; } p = buf->free; p = mempcpy(p, REQUEST_DATA, strlen(REQUEST_DATA)); p = mempcpy(p, METHOD, strlen(METHOD)); p = mempcpy(p, nxt_unit_sptr_get(&r->method), r->method_length); *p++ = '\n'; p = mempcpy(p, PROTOCOL, strlen(PROTOCOL)); p = mempcpy(p, nxt_unit_sptr_get(&r->version), r->version_length); *p++ = '\n'; p = mempcpy(p, REMOTE_ADDR, strlen(REMOTE_ADDR)); p = mempcpy(p, nxt_unit_sptr_get(&r->remote), r->remote_length); *p++ = '\n'; p = mempcpy(p, LOCAL_ADDR, strlen(LOCAL_ADDR)); p = mempcpy(p, nxt_unit_sptr_get(&r->local_addr), r->local_addr_length); *p++ = '\n'; p = mempcpy(p, TARGET, strlen(TARGET)); p = mempcpy(p, nxt_unit_sptr_get(&r->target), r->target_length); *p++ = '\n'; p = mempcpy(p, PATH, strlen(PATH)); p = mempcpy(p, nxt_unit_sptr_get(&r->path), r->path_length); *p++ = '\n'; if (r->query.offset) { p = mempcpy(p, QUERY, strlen(QUERY)); p = mempcpy(p, nxt_unit_sptr_get(&r->query), r->query_length); *p++ = '\n'; } p = mempcpy(p, FIELDS, strlen(FIELDS)); for (i = 0; i < r->fields_count; i++) { f = r->fields + i; p = mempcpy(p, FIELD_PAD, strlen(FIELD_PAD)); p = mempcpy(p, nxt_unit_sptr_get(&f->name), f->name_length); p = mempcpy(p, FIELD_SEP, strlen(FIELD_SEP)); p = mempcpy(p, nxt_unit_sptr_get(&f->value), f->value_length); *p++ = '\n'; } if (r->content_length > 0) { p = mempcpy(p, BODY, strlen(BODY)); res = nxt_unit_request_read(req, buf->free, buf->end - buf->free); buf->free += res; } buf->free = p; rc = nxt_unit_buf_send(buf); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } buf = nxt_unit_response_buf_alloc(req, strlen("Some extra contents.\n")); if (nxt_slow_path(buf == NULL)) { rc = NXT_UNIT_ERROR; goto fail; } buf2 = nxt_unit_response_buf_alloc(req, strlen("But send this first.\n")); if (nxt_slow_path(buf2 == NULL)) { rc = NXT_UNIT_ERROR; goto fail; } buf2->free = mempcpy(buf2->free, "But send this first.\n", strlen("But send this first.\n")); buf->free = mempcpy(buf->free, "Some extra contents.\n", strlen("Some extra contents.\n")); rc = nxt_unit_buf_send(buf2); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_buf_send(buf); if (nxt_slow_path(rc != NXT_UNIT_OK)) { goto fail; } rc = nxt_unit_response_write(req, "And some more\n", strlen("And some more\n")); if (nxt_slow_path(rc != 0)) { goto fail; } fail: nxt_unit_request_done(req, rc); }