1 2 /* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6 #include <nxt_auto_config.h> 7 #include <nxt_version.h> 8 #include <nxt_unit.h> 9 #include <nxt_unit_request.h> 10 #include <nxt_clang.h> 11 #include <pthread.h> 12 #include <string.h> 13 #include <stdlib.h> 14 15 16 #define CONTENT_TYPE "Content-Type" 17 #define TEXT_PLAIN "text/plain" 18 #define HELLO_WORLD "Hello world!\n" 19 20 #define NEW_LINE "\n" 21 22 #define REQUEST_DATA "Request data:\n" 23 #define METHOD " Method: " 24 #define PROTOCOL " Protocol: " 25 #define REMOTE_ADDR " Remote addr: " 26 #define LOCAL_ADDR " Local addr: " 27 #define TARGET " Target: " 28 #define PATH " Path: " 29 #define QUERY " Query: " 30 #define FIELDS " Fields:\n" 31 #define FIELD_PAD " " 32 #define FIELD_SEP ": " 33 #define BODY " Body:\n" 34 35 36 static int ready_handler(nxt_unit_ctx_t *ctx); 37 static void *worker(void *main_ctx); 38 static void greeting_app_request_handler(nxt_unit_request_info_t *req); 39 static inline char *copy(char *p, const void *src, uint32_t len); 40 41 42 static int thread_count; 43 static pthread_t *threads; 44 45 46 int 47 main(int argc, char **argv) 48 { 49 int i, err; 50 nxt_unit_ctx_t *ctx; 51 nxt_unit_init_t init; 52 53 if (argc == 3 && strcmp(argv[1], "-t") == 0) { 54 thread_count = atoi(argv[2]); 55 } 56 57 memset(&init, 0, sizeof(nxt_unit_init_t)); 58 59 init.callbacks.request_handler = greeting_app_request_handler; 60 init.callbacks.ready_handler = ready_handler; 61 62 ctx = nxt_unit_init(&init); 63 if (ctx == NULL) { 64 return 1; 65 } 66 67 err = nxt_unit_run(ctx); 68 69 nxt_unit_debug(ctx, "main worker finished with %d code", err); 70 71 if (thread_count > 1) { 72 for (i = 0; i < thread_count - 1; i++) { 73 err = pthread_join(threads[i], NULL); 74 75 nxt_unit_debug(ctx, "join thread #%d: %d", i, err); 76 } 77 78 nxt_unit_free(ctx, threads); 79 } 80 81 nxt_unit_done(ctx); 82 83 nxt_unit_debug(NULL, "main worker done"); 84 85 return 0; 86 } 87 88 89 static int 90 ready_handler(nxt_unit_ctx_t *ctx) 91 { 92 int i, err; 93 94 nxt_unit_debug(ctx, "ready"); 95 96 if (!nxt_unit_is_main_ctx(ctx) || thread_count <= 1) { 97 return NXT_UNIT_OK; 98 } 99 100 threads = nxt_unit_malloc(ctx, sizeof(pthread_t) * (thread_count - 1)); 101 if (threads == NULL) { 102 return NXT_UNIT_ERROR; 103 } 104 105 for (i = 0; i < thread_count - 1; i++) { 106 err = pthread_create(&threads[i], NULL, worker, ctx); 107 if (err != 0) { 108 return NXT_UNIT_ERROR; 109 } 110 } 111 112 return NXT_UNIT_OK; 113 } 114 115 116 static void * 117 worker(void *main_ctx) 118 { 119 int rc; 120 nxt_unit_ctx_t *ctx; 121 122 ctx = nxt_unit_ctx_alloc(main_ctx, NULL); 123 if (ctx == NULL) { 124 return NULL; 125 } 126 127 nxt_unit_debug(ctx, "start worker"); 128 129 rc = nxt_unit_run(ctx); 130 131 nxt_unit_debug(ctx, "worker finished with %d code", rc); 132 133 nxt_unit_done(ctx); 134 135 return NULL; 136 } 137 138 139 static void 140 greeting_app_request_handler(nxt_unit_request_info_t *req) 141 { 142 int rc; 143 char *p; 144 ssize_t res; 145 uint32_t i; 146 nxt_unit_buf_t *buf; 147 nxt_unit_field_t *f; 148 nxt_unit_request_t *r; 149 150 rc = nxt_unit_response_init(req, 200 /* Status code. */, 151 1 /* Number of response headers. */, 152 nxt_length(CONTENT_TYPE) 153 + nxt_length(TEXT_PLAIN) 154 + nxt_length(HELLO_WORLD)); 155 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 156 goto fail; 157 } 158 159 rc = nxt_unit_response_add_field(req, 160 CONTENT_TYPE, nxt_length(CONTENT_TYPE), 161 TEXT_PLAIN, nxt_length(TEXT_PLAIN)); 162 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 163 goto fail; 164 } 165 166 rc = nxt_unit_response_add_content(req, HELLO_WORLD, 167 nxt_length(HELLO_WORLD)); 168 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 169 goto fail; 170 } 171 172 rc = nxt_unit_response_send(req); 173 if (nxt_slow_path(rc != NXT_UNIT_OK)) { 174 goto fail; 175 } 176 177 r = req->request; 178 179 buf = nxt_unit_response_buf_alloc(req, (req->request_buf->end 180 - req->request_buf->start) 181 + nxt_length(REQUEST_DATA) 182 + nxt_length(METHOD) 183 + nxt_length(NEW_LINE) 184 + nxt_length(PROTOCOL) 185 + nxt_length(NEW_LINE) 186 + nxt_length(REMOTE_ADDR) 187 + nxt_length(NEW_LINE) 188 + nxt_length(LOCAL_ADDR) 189 + nxt_length(NEW_LINE) 190 + nxt_length(TARGET) 191 + nxt_length(NEW_LINE) 192 + nxt_length(PATH) 193 + nxt_length(NEW_LINE) 194 + nxt_length(QUERY) 195 + nxt_length(NEW_LINE) 196 + nxt_length(FIELDS) 197 + r->fields_count * ( 198 nxt_length(FIELD_PAD) 199 + nxt_length(FIELD_SEP)) 200 + nxt_length(BODY)); 201 if (nxt_slow_path(buf == NULL)) { 202 rc = NXT_UNIT_ERROR; 203 204 goto fail; 205 } 206 207 p = buf->free; 208 209 p = copy(p, REQUEST_DATA, nxt_length(REQUEST_DATA)); 210 211 p = copy(p, METHOD, nxt_length(METHOD)); 212 p = copy(p, nxt_unit_sptr_get(&r->method), r->method_length); 213 *p++ = '\n'; 214 215 p = copy(p, PROTOCOL, nxt_length(PROTOCOL)); 216 p = copy(p, nxt_unit_sptr_get(&r->version), r->version_length); 217 *p++ = '\n'; 218 219 p = copy(p, REMOTE_ADDR, nxt_length(REMOTE_ADDR)); 220 p = copy(p, nxt_unit_sptr_get(&r->remote), r->remote_length); 221 *p++ = '\n'; 222 223 p = copy(p, LOCAL_ADDR, nxt_length(LOCAL_ADDR)); 224 p = copy(p, nxt_unit_sptr_get(&r->local), r->local_length); 225 *p++ = '\n'; 226 227 p = copy(p, TARGET, nxt_length(TARGET)); 228 p = copy(p, nxt_unit_sptr_get(&r->target), r->target_length); 229 *p++ = '\n'; 230 231 p = copy(p, PATH, nxt_length(PATH)); 232 p = copy(p, nxt_unit_sptr_get(&r->path), r->path_length); 233 *p++ = '\n'; 234 235 if (r->query.offset) { 236 p = copy(p, QUERY, nxt_length(QUERY)); 237 p = copy(p, nxt_unit_sptr_get(&r->query), r->query_length); 238 *p++ = '\n'; 239 } 240 241 p = copy(p, FIELDS, nxt_length(FIELDS)); 242 243 for (i = 0; i < r->fields_count; i++) { 244 f = r->fields + i; 245 246 p = copy(p, FIELD_PAD, nxt_length(FIELD_PAD)); 247 p = copy(p, nxt_unit_sptr_get(&f->name), f->name_length); 248 p = copy(p, FIELD_SEP, nxt_length(FIELD_SEP)); 249 p = copy(p, nxt_unit_sptr_get(&f->value), f->value_length); 250 *p++ = '\n'; 251 } 252 253 if (r->content_length > 0) { 254 p = copy(p, BODY, nxt_length(BODY)); 255 256 res = nxt_unit_request_read(req, buf->free, buf->end - buf->free); 257 buf->free += res; 258 259 } 260 261 buf->free = p; 262 263 rc = nxt_unit_buf_send(buf); 264 265 fail: 266 267 nxt_unit_request_done(req, rc); 268 } 269 270 271 static inline char * 272 copy(char *p, const void *src, uint32_t len) 273 { 274 memcpy(p, src, len); 275 276 return p + len; 277 } 278