1743Smax.romanov@nginx.com 2743Smax.romanov@nginx.com /* 3743Smax.romanov@nginx.com * Copyright (C) NGINX, Inc. 4743Smax.romanov@nginx.com */ 5743Smax.romanov@nginx.com 6743Smax.romanov@nginx.com #include <nxt_unit.h> 7743Smax.romanov@nginx.com #include <nxt_unit_request.h> 8743Smax.romanov@nginx.com #include <nxt_clang.h> 91669Smax.romanov@nginx.com #include <pthread.h> 101669Smax.romanov@nginx.com #include <string.h> 111669Smax.romanov@nginx.com #include <stdlib.h> 12743Smax.romanov@nginx.com 13743Smax.romanov@nginx.com 14743Smax.romanov@nginx.com #define CONTENT_TYPE "Content-Type" 15743Smax.romanov@nginx.com #define TEXT_PLAIN "text/plain" 16743Smax.romanov@nginx.com #define HELLO_WORLD "Hello world!\n" 17743Smax.romanov@nginx.com 18743Smax.romanov@nginx.com #define NEW_LINE "\n" 19743Smax.romanov@nginx.com 20743Smax.romanov@nginx.com #define REQUEST_DATA "Request data:\n" 21743Smax.romanov@nginx.com #define METHOD " Method: " 22743Smax.romanov@nginx.com #define PROTOCOL " Protocol: " 23743Smax.romanov@nginx.com #define REMOTE_ADDR " Remote addr: " 24743Smax.romanov@nginx.com #define LOCAL_ADDR " Local addr: " 25743Smax.romanov@nginx.com #define TARGET " Target: " 26743Smax.romanov@nginx.com #define PATH " Path: " 27743Smax.romanov@nginx.com #define QUERY " Query: " 28743Smax.romanov@nginx.com #define FIELDS " Fields:\n" 29743Smax.romanov@nginx.com #define FIELD_PAD " " 30743Smax.romanov@nginx.com #define FIELD_SEP ": " 31743Smax.romanov@nginx.com #define BODY " Body:\n" 32743Smax.romanov@nginx.com 33743Smax.romanov@nginx.com 341669Smax.romanov@nginx.com static int ready_handler(nxt_unit_ctx_t *ctx); 351669Smax.romanov@nginx.com static void *worker(void *main_ctx); 361669Smax.romanov@nginx.com static void greeting_app_request_handler(nxt_unit_request_info_t *req); 371669Smax.romanov@nginx.com static inline char *copy(char *p, const void *src, uint32_t len); 381669Smax.romanov@nginx.com 391669Smax.romanov@nginx.com 401669Smax.romanov@nginx.com static int thread_count; 411669Smax.romanov@nginx.com static pthread_t *threads; 421669Smax.romanov@nginx.com 431669Smax.romanov@nginx.com 441669Smax.romanov@nginx.com int 451669Smax.romanov@nginx.com main(int argc, char **argv) 46743Smax.romanov@nginx.com { 471669Smax.romanov@nginx.com int i, err; 481669Smax.romanov@nginx.com nxt_unit_ctx_t *ctx; 491669Smax.romanov@nginx.com nxt_unit_init_t init; 501669Smax.romanov@nginx.com 511669Smax.romanov@nginx.com if (argc == 3 && strcmp(argv[1], "-t") == 0) { 521669Smax.romanov@nginx.com thread_count = atoi(argv[2]); 531669Smax.romanov@nginx.com } 541669Smax.romanov@nginx.com 551669Smax.romanov@nginx.com memset(&init, 0, sizeof(nxt_unit_init_t)); 561669Smax.romanov@nginx.com 571669Smax.romanov@nginx.com init.callbacks.request_handler = greeting_app_request_handler; 581669Smax.romanov@nginx.com init.callbacks.ready_handler = ready_handler; 591669Smax.romanov@nginx.com 601669Smax.romanov@nginx.com ctx = nxt_unit_init(&init); 611669Smax.romanov@nginx.com if (ctx == NULL) { 621669Smax.romanov@nginx.com return 1; 631669Smax.romanov@nginx.com } 641669Smax.romanov@nginx.com 651669Smax.romanov@nginx.com err = nxt_unit_run(ctx); 661669Smax.romanov@nginx.com 671669Smax.romanov@nginx.com nxt_unit_debug(ctx, "main worker finished with %d code", err); 681669Smax.romanov@nginx.com 691669Smax.romanov@nginx.com if (thread_count > 1) { 701669Smax.romanov@nginx.com for (i = 0; i < thread_count - 1; i++) { 711669Smax.romanov@nginx.com err = pthread_join(threads[i], NULL); 721669Smax.romanov@nginx.com 731676Svbart@nginx.com if (nxt_fast_path(err == 0)) { 741676Svbart@nginx.com nxt_unit_debug(ctx, "join thread #%d", i); 751676Svbart@nginx.com 761676Svbart@nginx.com } else { 771676Svbart@nginx.com nxt_unit_alert(ctx, "pthread_join(#%d) failed: %s (%d)", 781676Svbart@nginx.com i, strerror(err), err); 791676Svbart@nginx.com } 801669Smax.romanov@nginx.com } 811669Smax.romanov@nginx.com 821669Smax.romanov@nginx.com nxt_unit_free(ctx, threads); 831669Smax.romanov@nginx.com } 841669Smax.romanov@nginx.com 851669Smax.romanov@nginx.com nxt_unit_done(ctx); 861669Smax.romanov@nginx.com 871669Smax.romanov@nginx.com nxt_unit_debug(NULL, "main worker done"); 881669Smax.romanov@nginx.com 891669Smax.romanov@nginx.com return 0; 901669Smax.romanov@nginx.com } 911669Smax.romanov@nginx.com 92743Smax.romanov@nginx.com 931669Smax.romanov@nginx.com static int 941669Smax.romanov@nginx.com ready_handler(nxt_unit_ctx_t *ctx) 951669Smax.romanov@nginx.com { 961669Smax.romanov@nginx.com int i, err; 971669Smax.romanov@nginx.com 981669Smax.romanov@nginx.com nxt_unit_debug(ctx, "ready"); 991669Smax.romanov@nginx.com 1001980Smax.romanov@nginx.com if (thread_count <= 1) { 1011669Smax.romanov@nginx.com return NXT_UNIT_OK; 1021669Smax.romanov@nginx.com } 1031669Smax.romanov@nginx.com 1041669Smax.romanov@nginx.com threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1)); 1051669Smax.romanov@nginx.com if (threads == NULL) { 1061669Smax.romanov@nginx.com return NXT_UNIT_ERROR; 1071669Smax.romanov@nginx.com } 1081669Smax.romanov@nginx.com 1091669Smax.romanov@nginx.com for (i = 0; i < thread_count - 1; i++) { 1101669Smax.romanov@nginx.com err = pthread_create(&threads[i], NULL, worker, ctx); 1111669Smax.romanov@nginx.com if (err != 0) { 1121669Smax.romanov@nginx.com return NXT_UNIT_ERROR; 1131669Smax.romanov@nginx.com } 1141669Smax.romanov@nginx.com } 1151669Smax.romanov@nginx.com 1161669Smax.romanov@nginx.com return NXT_UNIT_OK; 1171669Smax.romanov@nginx.com } 1181669Smax.romanov@nginx.com 1191669Smax.romanov@nginx.com 1201669Smax.romanov@nginx.com static void * 1211669Smax.romanov@nginx.com worker(void *main_ctx) 1221669Smax.romanov@nginx.com { 1231669Smax.romanov@nginx.com int rc; 1241669Smax.romanov@nginx.com nxt_unit_ctx_t *ctx; 1251669Smax.romanov@nginx.com 1261669Smax.romanov@nginx.com ctx = nxt_unit_ctx_alloc(main_ctx, NULL); 1271669Smax.romanov@nginx.com if (ctx == NULL) { 1281669Smax.romanov@nginx.com return NULL; 1291669Smax.romanov@nginx.com } 1301669Smax.romanov@nginx.com 1311669Smax.romanov@nginx.com nxt_unit_debug(ctx, "start worker"); 1321669Smax.romanov@nginx.com 1331669Smax.romanov@nginx.com rc = nxt_unit_run(ctx); 1341669Smax.romanov@nginx.com 1351669Smax.romanov@nginx.com nxt_unit_debug(ctx, "worker finished with %d code", rc); 1361669Smax.romanov@nginx.com 1371669Smax.romanov@nginx.com nxt_unit_done(ctx); 1381669Smax.romanov@nginx.com 1391676Svbart@nginx.com return (void *) (intptr_t) rc; 140743Smax.romanov@nginx.com } 141743Smax.romanov@nginx.com 142743Smax.romanov@nginx.com 143743Smax.romanov@nginx.com static void 144743Smax.romanov@nginx.com greeting_app_request_handler(nxt_unit_request_info_t *req) 145743Smax.romanov@nginx.com { 146743Smax.romanov@nginx.com int rc; 147743Smax.romanov@nginx.com char *p; 148743Smax.romanov@nginx.com ssize_t res; 149743Smax.romanov@nginx.com uint32_t i; 150743Smax.romanov@nginx.com nxt_unit_buf_t *buf; 151743Smax.romanov@nginx.com nxt_unit_field_t *f; 152743Smax.romanov@nginx.com nxt_unit_request_t *r; 153743Smax.romanov@nginx.com 154743Smax.romanov@nginx.com rc = nxt_unit_response_init(req, 200 /* Status code. */, 155743Smax.romanov@nginx.com 1 /* Number of response headers. */, 156743Smax.romanov@nginx.com nxt_length(CONTENT_TYPE) 157743Smax.romanov@nginx.com + nxt_length(TEXT_PLAIN) 158743Smax.romanov@nginx.com + nxt_length(HELLO_WORLD)); 159743Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 160743Smax.romanov@nginx.com goto fail; 161743Smax.romanov@nginx.com } 162743Smax.romanov@nginx.com 163743Smax.romanov@nginx.com rc = nxt_unit_response_add_field(req, 164743Smax.romanov@nginx.com CONTENT_TYPE, nxt_length(CONTENT_TYPE), 165743Smax.romanov@nginx.com TEXT_PLAIN, nxt_length(TEXT_PLAIN)); 166743Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 167743Smax.romanov@nginx.com goto fail; 168743Smax.romanov@nginx.com } 169743Smax.romanov@nginx.com 170743Smax.romanov@nginx.com rc = nxt_unit_response_add_content(req, HELLO_WORLD, 171743Smax.romanov@nginx.com nxt_length(HELLO_WORLD)); 172743Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 173743Smax.romanov@nginx.com goto fail; 174743Smax.romanov@nginx.com } 175743Smax.romanov@nginx.com 176743Smax.romanov@nginx.com rc = nxt_unit_response_send(req); 177743Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) { 178743Smax.romanov@nginx.com goto fail; 179743Smax.romanov@nginx.com } 180743Smax.romanov@nginx.com 181743Smax.romanov@nginx.com r = req->request; 182743Smax.romanov@nginx.com 183743Smax.romanov@nginx.com buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end 184743Smax.romanov@nginx.com - req->request_buf->start) 185743Smax.romanov@nginx.com + nxt_length(REQUEST_DATA) 186743Smax.romanov@nginx.com + nxt_length(METHOD) 187743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 188743Smax.romanov@nginx.com + nxt_length(PROTOCOL) 189743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 190743Smax.romanov@nginx.com + nxt_length(REMOTE_ADDR) 191743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 192743Smax.romanov@nginx.com + nxt_length(LOCAL_ADDR) 193743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 194743Smax.romanov@nginx.com + nxt_length(TARGET) 195743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 196743Smax.romanov@nginx.com + nxt_length(PATH) 197743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 198743Smax.romanov@nginx.com + nxt_length(QUERY) 199743Smax.romanov@nginx.com + nxt_length(NEW_LINE) 200743Smax.romanov@nginx.com + nxt_length(FIELDS) 201743Smax.romanov@nginx.com + r->fields_count * ( 202743Smax.romanov@nginx.com nxt_length(FIELD_PAD) 203743Smax.romanov@nginx.com + nxt_length(FIELD_SEP)) 204743Smax.romanov@nginx.com + nxt_length(BODY)); 205743Smax.romanov@nginx.com if (nxt_slow_path(buf == NULL)) { 206743Smax.romanov@nginx.com rc = NXT_UNIT_ERROR; 207743Smax.romanov@nginx.com 208743Smax.romanov@nginx.com goto fail; 209743Smax.romanov@nginx.com } 210743Smax.romanov@nginx.com 211743Smax.romanov@nginx.com p = buf->free; 212743Smax.romanov@nginx.com 213743Smax.romanov@nginx.com p = copy(p, REQUEST_DATA, nxt_length(REQUEST_DATA)); 214743Smax.romanov@nginx.com 215743Smax.romanov@nginx.com p = copy(p, METHOD, nxt_length(METHOD)); 216743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->method), r->method_length); 217743Smax.romanov@nginx.com *p++ = '\n'; 218743Smax.romanov@nginx.com 219743Smax.romanov@nginx.com p = copy(p, PROTOCOL, nxt_length(PROTOCOL)); 220743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->version), r->version_length); 221743Smax.romanov@nginx.com *p++ = '\n'; 222743Smax.romanov@nginx.com 223743Smax.romanov@nginx.com p = copy(p, REMOTE_ADDR, nxt_length(REMOTE_ADDR)); 224743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->remote), r->remote_length); 225743Smax.romanov@nginx.com *p++ = '\n'; 226743Smax.romanov@nginx.com 227743Smax.romanov@nginx.com p = copy(p, LOCAL_ADDR, nxt_length(LOCAL_ADDR)); 228*2208Sa.clayton@nginx.com p = copy(p, nxt_unit_sptr_get(&r->local_addr), r->local_addr_length); 229743Smax.romanov@nginx.com *p++ = '\n'; 230743Smax.romanov@nginx.com 231743Smax.romanov@nginx.com p = copy(p, TARGET, nxt_length(TARGET)); 232743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->target), r->target_length); 233743Smax.romanov@nginx.com *p++ = '\n'; 234743Smax.romanov@nginx.com 235743Smax.romanov@nginx.com p = copy(p, PATH, nxt_length(PATH)); 236743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->path), r->path_length); 237743Smax.romanov@nginx.com *p++ = '\n'; 238743Smax.romanov@nginx.com 239743Smax.romanov@nginx.com if (r->query.offset) { 240743Smax.romanov@nginx.com p = copy(p, QUERY, nxt_length(QUERY)); 241743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&r->query), r->query_length); 242743Smax.romanov@nginx.com *p++ = '\n'; 243743Smax.romanov@nginx.com } 244743Smax.romanov@nginx.com 245743Smax.romanov@nginx.com p = copy(p, FIELDS, nxt_length(FIELDS)); 246743Smax.romanov@nginx.com 247743Smax.romanov@nginx.com for (i = 0; i < r->fields_count; i++) { 248743Smax.romanov@nginx.com f = r->fields + i; 249743Smax.romanov@nginx.com 250743Smax.romanov@nginx.com p = copy(p, FIELD_PAD, nxt_length(FIELD_PAD)); 251743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&f->name), f->name_length); 252743Smax.romanov@nginx.com p = copy(p, FIELD_SEP, nxt_length(FIELD_SEP)); 253743Smax.romanov@nginx.com p = copy(p, nxt_unit_sptr_get(&f->value), f->value_length); 254743Smax.romanov@nginx.com *p++ = '\n'; 255743Smax.romanov@nginx.com } 256743Smax.romanov@nginx.com 257743Smax.romanov@nginx.com if (r->content_length > 0) { 258743Smax.romanov@nginx.com p = copy(p, BODY, nxt_length(BODY)); 259743Smax.romanov@nginx.com 260743Smax.romanov@nginx.com res = nxt_unit_request_read(req, buf->free, buf->end - buf->free); 261743Smax.romanov@nginx.com buf->free += res; 262743Smax.romanov@nginx.com 263743Smax.romanov@nginx.com } 264743Smax.romanov@nginx.com 265743Smax.romanov@nginx.com buf->free = p; 266743Smax.romanov@nginx.com 267743Smax.romanov@nginx.com rc = nxt_unit_buf_send(buf); 268743Smax.romanov@nginx.com 269743Smax.romanov@nginx.com fail: 270743Smax.romanov@nginx.com 271743Smax.romanov@nginx.com nxt_unit_request_done(req, rc); 272743Smax.romanov@nginx.com } 273743Smax.romanov@nginx.com 274743Smax.romanov@nginx.com 2751669Smax.romanov@nginx.com static inline char * 2761669Smax.romanov@nginx.com copy(char *p, const void *src, uint32_t len) 2771669Smax.romanov@nginx.com { 2781669Smax.romanov@nginx.com memcpy(p, src, len); 279743Smax.romanov@nginx.com 2801669Smax.romanov@nginx.com return p + len; 281743Smax.romanov@nginx.com } 282