1 /*
2  * Copyright (C) 2010-2014 Weibin Yao (yaoweibin@gmail.com)
3  * Copyright (C) 2010-2014 Alibaba Group Holding Limited
4  */
5 
6 
7 #include <nginx.h>
8 #include "ngx_http_upstream_check_module.h"
9 
10 
11 typedef struct ngx_http_upstream_check_peer_s ngx_http_upstream_check_peer_t;
12 typedef struct ngx_http_upstream_check_srv_conf_s
13     ngx_http_upstream_check_srv_conf_t;
14 
15 
16 #pragma pack(push, 1)
17 
18 typedef struct {
19     u_char                                   major;
20     u_char                                   minor;
21 } ngx_ssl_protocol_version_t;
22 
23 
24 typedef struct {
25     u_char                                   msg_type;
26     ngx_ssl_protocol_version_t               version;
27     uint16_t                                 length;
28 
29     u_char                                   handshake_type;
30     u_char                                   handshake_length[3];
31     ngx_ssl_protocol_version_t               hello_version;
32 
33     time_t                                   time;
34     u_char                                   random[28];
35 
36     u_char                                   others[0];
37 } ngx_ssl_server_hello_t;
38 
39 
40 typedef struct {
41     u_char                                   packet_length[3];
42     u_char                                   packet_number;
43 
44     u_char                                   protocol_version;
45     u_char                                   others[0];
46 } ngx_mysql_handshake_init_t;
47 
48 
49 typedef struct {
50     uint16_t                                 preamble;
51     uint16_t                                 length;
52     u_char                                   type;
53 } ngx_ajp_raw_packet_t;
54 
55 #pragma pack()
56 
57 
58 typedef struct {
59     ngx_buf_t                                send;
60     ngx_buf_t                                recv;
61 
62     ngx_uint_t                               state;
63     ngx_http_status_t                        status;
64 
65     size_t                                   padding;
66     size_t                                   length;
67 } ngx_http_upstream_check_ctx_t;
68 
69 
70 typedef struct {
71     ngx_shmtx_t                              mutex;
72 #if (nginx_version >= 1002000)
73     ngx_shmtx_sh_t                           lock;
74 #else
75     ngx_atomic_t                             lock;
76 #endif
77 
78     ngx_pid_t                                owner;
79 
80     ngx_msec_t                               access_time;
81 
82     ngx_uint_t                               fall_count;
83     ngx_uint_t                               rise_count;
84 
85     ngx_uint_t                               busyness;
86     ngx_uint_t                               access_count;
87 
88     struct sockaddr                         *sockaddr;
89     socklen_t                                socklen;
90 
91     ngx_atomic_t                             down;
92 
93     u_char                                   padding[64];
94 } ngx_http_upstream_check_peer_shm_t;
95 
96 
97 typedef struct {
98     ngx_uint_t                               generation;
99     ngx_uint_t                               checksum;
100     ngx_uint_t                               number;
101 
102     /* ngx_http_upstream_check_status_peer_t */
103     ngx_http_upstream_check_peer_shm_t       peers[1];
104 } ngx_http_upstream_check_peers_shm_t;
105 
106 
107 #define NGX_HTTP_CHECK_CONNECT_DONE          0x0001
108 #define NGX_HTTP_CHECK_SEND_DONE             0x0002
109 #define NGX_HTTP_CHECK_RECV_DONE             0x0004
110 #define NGX_HTTP_CHECK_ALL_DONE              0x0008
111 
112 
113 typedef ngx_int_t (*ngx_http_upstream_check_packet_init_pt)
114     (ngx_http_upstream_check_peer_t *peer);
115 typedef ngx_int_t (*ngx_http_upstream_check_packet_parse_pt)
116     (ngx_http_upstream_check_peer_t *peer);
117 typedef void (*ngx_http_upstream_check_packet_clean_pt)
118     (ngx_http_upstream_check_peer_t *peer);
119 
120 struct ngx_http_upstream_check_peer_s {
121     ngx_flag_t                               state;
122     ngx_pool_t                              *pool;
123     ngx_uint_t                               index;
124     ngx_uint_t                               max_busy;
125     ngx_str_t                               *upstream_name;
126     ngx_addr_t                              *check_peer_addr;
127     ngx_addr_t                              *peer_addr;
128     ngx_event_t                              check_ev;
129     ngx_event_t                              check_timeout_ev;
130     ngx_peer_connection_t                    pc;
131 
132     void                                    *check_data;
133     ngx_event_handler_pt                     send_handler;
134     ngx_event_handler_pt                     recv_handler;
135 
136     ngx_http_upstream_check_packet_init_pt   init;
137     ngx_http_upstream_check_packet_parse_pt  parse;
138     ngx_http_upstream_check_packet_clean_pt  reinit;
139 
140     ngx_http_upstream_check_peer_shm_t      *shm;
141     ngx_http_upstream_check_srv_conf_t      *conf;
142 };
143 
144 
145 typedef struct {
146     ngx_str_t                                check_shm_name;
147     ngx_uint_t                               checksum;
148     ngx_array_t                              peers;
149 
150     ngx_http_upstream_check_peers_shm_t     *peers_shm;
151 } ngx_http_upstream_check_peers_t;
152 
153 
154 #define NGX_HTTP_CHECK_TCP                   0x0001
155 #define NGX_HTTP_CHECK_HTTP                  0x0002
156 #define NGX_HTTP_CHECK_SSL_HELLO             0x0004
157 #define NGX_HTTP_CHECK_MYSQL                 0x0008
158 #define NGX_HTTP_CHECK_AJP                   0x0010
159 
160 #define NGX_CHECK_HTTP_2XX                   0x0002
161 #define NGX_CHECK_HTTP_3XX                   0x0004
162 #define NGX_CHECK_HTTP_4XX                   0x0008
163 #define NGX_CHECK_HTTP_5XX                   0x0010
164 #define NGX_CHECK_HTTP_ERR                   0x8000
165 
166 typedef struct {
167     ngx_uint_t                               type;
168 
169     ngx_str_t                                name;
170 
171     ngx_str_t                                default_send;
172 
173     /* HTTP */
174     ngx_uint_t                               default_status_alive;
175 
176     ngx_event_handler_pt                     send_handler;
177     ngx_event_handler_pt                     recv_handler;
178 
179     ngx_http_upstream_check_packet_init_pt   init;
180     ngx_http_upstream_check_packet_parse_pt  parse;
181     ngx_http_upstream_check_packet_clean_pt  reinit;
182 
183     unsigned need_pool;
184     unsigned need_keepalive;
185 } ngx_check_conf_t;
186 
187 
188 typedef void (*ngx_http_upstream_check_status_format_pt) (ngx_buf_t *b,
189     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag);
190 
191 typedef struct {
192     ngx_str_t                                format;
193     ngx_str_t                                content_type;
194 
195     ngx_http_upstream_check_status_format_pt output;
196 } ngx_check_status_conf_t;
197 
198 
199 #define NGX_CHECK_STATUS_DOWN                0x0001
200 #define NGX_CHECK_STATUS_UP                  0x0002
201 
202 typedef struct {
203     ngx_check_status_conf_t                 *format;
204     ngx_flag_t                               flag;
205 } ngx_http_upstream_check_status_ctx_t;
206 
207 
208 typedef ngx_int_t (*ngx_http_upstream_check_status_command_pt)
209     (ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value);
210 
211 typedef struct {
212     ngx_str_t                                 name;
213     ngx_http_upstream_check_status_command_pt handler;
214 } ngx_check_status_command_t;
215 
216 
217 typedef struct {
218     ngx_uint_t                               check_shm_size;
219     ngx_http_upstream_check_peers_t         *peers;
220 } ngx_http_upstream_check_main_conf_t;
221 
222 
223 struct ngx_http_upstream_check_srv_conf_s {
224     ngx_uint_t                               port;
225     ngx_uint_t                               fall_count;
226     ngx_uint_t                               rise_count;
227     ngx_msec_t                               check_interval;
228     ngx_msec_t                               check_timeout;
229     ngx_uint_t                               check_keepalive_requests;
230 
231     ngx_check_conf_t                        *check_type_conf;
232     ngx_str_t                                send;
233 
234     union {
235         ngx_uint_t                           return_code;
236         ngx_uint_t                           status_alive;
237     } code;
238 
239     ngx_array_t                             *fastcgi_params;
240 
241     ngx_uint_t                               default_down;
242 };
243 
244 
245 typedef struct {
246     ngx_check_status_conf_t                 *format;
247 } ngx_http_upstream_check_loc_conf_t;
248 
249 
250 typedef struct {
251     u_char  version;
252     u_char  type;
253     u_char  request_id_hi;
254     u_char  request_id_lo;
255     u_char  content_length_hi;
256     u_char  content_length_lo;
257     u_char  padding_length;
258     u_char  reserved;
259 } ngx_http_fastcgi_header_t;
260 
261 
262 typedef struct {
263     u_char  role_hi;
264     u_char  role_lo;
265     u_char  flags;
266     u_char  reserved[5];
267 } ngx_http_fastcgi_begin_request_t;
268 
269 
270 typedef struct {
271     u_char  version;
272     u_char  type;
273     u_char  request_id_hi;
274     u_char  request_id_lo;
275 } ngx_http_fastcgi_header_small_t;
276 
277 
278 typedef struct {
279     ngx_http_fastcgi_header_t         h0;
280     ngx_http_fastcgi_begin_request_t  br;
281     ngx_http_fastcgi_header_small_t   h1;
282 } ngx_http_fastcgi_request_start_t;
283 
284 
285 #define NGX_HTTP_FASTCGI_RESPONDER      1
286 
287 #define NGX_HTTP_FASTCGI_KEEP_CONN      1
288 
289 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST  1
290 #define NGX_HTTP_FASTCGI_ABORT_REQUEST  2
291 #define NGX_HTTP_FASTCGI_END_REQUEST    3
292 #define NGX_HTTP_FASTCGI_PARAMS         4
293 #define NGX_HTTP_FASTCGI_STDIN          5
294 #define NGX_HTTP_FASTCGI_STDOUT         6
295 #define NGX_HTTP_FASTCGI_STDERR         7
296 #define NGX_HTTP_FASTCGI_DATA           8
297 
298 
299 typedef enum {
300     ngx_http_fastcgi_st_version = 0,
301     ngx_http_fastcgi_st_type,
302     ngx_http_fastcgi_st_request_id_hi,
303     ngx_http_fastcgi_st_request_id_lo,
304     ngx_http_fastcgi_st_content_length_hi,
305     ngx_http_fastcgi_st_content_length_lo,
306     ngx_http_fastcgi_st_padding_length,
307     ngx_http_fastcgi_st_reserved,
308     ngx_http_fastcgi_st_data,
309     ngx_http_fastcgi_st_padding
310 } ngx_http_fastcgi_state_e;
311 
312 
313 static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
314     { 1,                                               /* version */
315       NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
316       0,                                               /* request_id_hi */
317       1,                                               /* request_id_lo */
318       0,                                               /* content_length_hi */
319       sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
320       0,                                               /* padding_length */
321       0 },                                             /* reserved */
322 
323     { 0,                                               /* role_hi */
324       NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
325       0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
326       { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
327 
328     { 1,                                               /* version */
329       NGX_HTTP_FASTCGI_PARAMS,                         /* type */
330       0,                                               /* request_id_hi */
331       1 },                                             /* request_id_lo */
332 
333 };
334 
335 
336 static ngx_int_t ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle);
337 
338 static ngx_int_t ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c);
339 
340 static void ngx_http_upstream_check_begin_handler(ngx_event_t *event);
341 static void ngx_http_upstream_check_connect_handler(ngx_event_t *event);
342 
343 static void ngx_http_upstream_check_peek_handler(ngx_event_t *event);
344 
345 static void ngx_http_upstream_check_send_handler(ngx_event_t *event);
346 static void ngx_http_upstream_check_recv_handler(ngx_event_t *event);
347 
348 static void ngx_http_upstream_check_discard_handler(ngx_event_t *event);
349 static void ngx_http_upstream_check_dummy_handler(ngx_event_t *event);
350 
351 static ngx_int_t ngx_http_upstream_check_http_init(
352     ngx_http_upstream_check_peer_t *peer);
353 static ngx_int_t ngx_http_upstream_check_http_parse(
354     ngx_http_upstream_check_peer_t *peer);
355 static ngx_int_t ngx_http_upstream_check_parse_status_line(
356     ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b,
357     ngx_http_status_t *status);
358 static void ngx_http_upstream_check_http_reinit(
359     ngx_http_upstream_check_peer_t *peer);
360 
361 static ngx_buf_t *ngx_http_upstream_check_create_fastcgi_request(
362     ngx_pool_t *pool, ngx_str_t *params, ngx_uint_t num);
363 
364 static ngx_int_t ngx_http_upstream_check_fastcgi_parse(
365     ngx_http_upstream_check_peer_t *peer);
366 static ngx_int_t ngx_http_upstream_check_fastcgi_process_record(
367     ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b,
368     ngx_http_status_t *status);
369 static ngx_int_t ngx_http_upstream_check_parse_fastcgi_status(
370     ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b,
371     ngx_http_status_t *status);
372 
373 static ngx_int_t ngx_http_upstream_check_ssl_hello_init(
374     ngx_http_upstream_check_peer_t *peer);
375 static ngx_int_t ngx_http_upstream_check_ssl_hello_parse(
376     ngx_http_upstream_check_peer_t *peer);
377 static void ngx_http_upstream_check_ssl_hello_reinit(
378     ngx_http_upstream_check_peer_t *peer);
379 
380 static ngx_int_t ngx_http_upstream_check_mysql_init(
381     ngx_http_upstream_check_peer_t *peer);
382 static ngx_int_t ngx_http_upstream_check_mysql_parse(
383     ngx_http_upstream_check_peer_t *peer);
384 static void ngx_http_upstream_check_mysql_reinit(
385     ngx_http_upstream_check_peer_t *peer);
386 
387 static ngx_int_t ngx_http_upstream_check_ajp_init(
388     ngx_http_upstream_check_peer_t *peer);
389 static ngx_int_t ngx_http_upstream_check_ajp_parse(
390     ngx_http_upstream_check_peer_t *peer);
391 static void ngx_http_upstream_check_ajp_reinit(
392     ngx_http_upstream_check_peer_t *peer);
393 
394 static void ngx_http_upstream_check_status_update(
395     ngx_http_upstream_check_peer_t *peer,
396     ngx_int_t result);
397 
398 static void ngx_http_upstream_check_clean_event(
399     ngx_http_upstream_check_peer_t *peer);
400 
401 static void ngx_http_upstream_check_timeout_handler(ngx_event_t *event);
402 static void ngx_http_upstream_check_finish_handler(ngx_event_t *event);
403 
404 static ngx_int_t ngx_http_upstream_check_need_exit();
405 static void ngx_http_upstream_check_clear_all_events();
406 
407 static ngx_int_t ngx_http_upstream_check_status_handler(
408     ngx_http_request_t *r);
409 
410 static void ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r,
411     ngx_http_upstream_check_status_ctx_t *ctx);
412 
413 static ngx_int_t ngx_http_upstream_check_status_command_format(
414     ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value);
415 static ngx_int_t ngx_http_upstream_check_status_command_status(
416     ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value);
417 
418 static void ngx_http_upstream_check_status_html_format(ngx_buf_t *b,
419     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag);
420 static void ngx_http_upstream_check_status_csv_format(ngx_buf_t *b,
421     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag);
422 static void ngx_http_upstream_check_status_json_format(ngx_buf_t *b,
423     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag);
424 
425 static ngx_int_t ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool,
426     ngx_addr_t *dst, ngx_addr_t *src, ngx_uint_t port);
427 
428 static ngx_check_conf_t *ngx_http_get_check_type_conf(ngx_str_t *str);
429 
430 static char *ngx_http_upstream_check(ngx_conf_t *cf,
431     ngx_command_t *cmd, void *conf);
432 static char *ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf,
433     ngx_command_t *cmd, void *conf);
434 static char *ngx_http_upstream_check_http_send(ngx_conf_t *cf,
435     ngx_command_t *cmd, void *conf);
436 static char *ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf,
437     ngx_command_t *cmd, void *conf);
438 
439 static char *ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf,
440     ngx_command_t *cmd, void *conf);
441 
442 static char *ngx_http_upstream_check_shm_size(ngx_conf_t *cf,
443     ngx_command_t *cmd, void *conf);
444 
445 static ngx_check_status_conf_t *ngx_http_get_check_status_format_conf(
446     ngx_str_t *str);
447 static char *ngx_http_upstream_check_status(ngx_conf_t *cf,
448     ngx_command_t *cmd, void *conf);
449 
450 static void *ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf);
451 static char *ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf,
452     void *conf);
453 
454 static void *ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf);
455 static char *ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf);
456 
457 static void *ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf);
458 static char * ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf,
459     void *parent, void *child);
460 
461 #define SHM_NAME_LEN 256
462 
463 static char *ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf);
464 
465 static ngx_int_t ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name,
466     ngx_pool_t *pool, ngx_uint_t generation);
467 static ngx_shm_zone_t *ngx_shared_memory_find(ngx_cycle_t *cycle,
468     ngx_str_t *name, void *tag);
469 static ngx_http_upstream_check_peer_shm_t *
470 ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *peers_shm,
471     ngx_addr_t *addr);
472 
473 static ngx_int_t ngx_http_upstream_check_init_shm_peer(
474     ngx_http_upstream_check_peer_shm_t *peer_shm,
475     ngx_http_upstream_check_peer_shm_t *opeer_shm,
476     ngx_uint_t init_down, ngx_pool_t *pool, ngx_str_t *peer_name);
477 
478 static ngx_int_t ngx_http_upstream_check_init_shm_zone(
479     ngx_shm_zone_t *shm_zone, void *data);
480 
481 
482 static ngx_int_t ngx_http_upstream_check_init_process(ngx_cycle_t *cycle);
483 
484 
485 static ngx_conf_bitmask_t  ngx_check_http_expect_alive_masks[] = {
486     { ngx_string("http_2xx"), NGX_CHECK_HTTP_2XX },
487     { ngx_string("http_3xx"), NGX_CHECK_HTTP_3XX },
488     { ngx_string("http_4xx"), NGX_CHECK_HTTP_4XX },
489     { ngx_string("http_5xx"), NGX_CHECK_HTTP_5XX },
490     { ngx_null_string, 0 }
491 };
492 
493 
494 static ngx_command_t  ngx_http_upstream_check_commands[] = {
495 
496     { ngx_string("check"),
497       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
498       ngx_http_upstream_check,
499       0,
500       0,
501       NULL },
502 
503     { ngx_string("check_keepalive_requests"),
504       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
505       ngx_http_upstream_check_keepalive_requests,
506       0,
507       0,
508       NULL },
509 
510     { ngx_string("check_http_send"),
511       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
512       ngx_http_upstream_check_http_send,
513       0,
514       0,
515       NULL },
516 
517     { ngx_string("check_http_expect_alive"),
518       NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
519       ngx_http_upstream_check_http_expect_alive,
520       0,
521       0,
522       NULL },
523 
524     { ngx_string("check_fastcgi_param"),
525       NGX_HTTP_UPS_CONF|NGX_CONF_TAKE2,
526       ngx_http_upstream_check_fastcgi_params,
527       0,
528       0,
529       NULL },
530 
531     { ngx_string("check_shm_size"),
532       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
533       ngx_http_upstream_check_shm_size,
534       0,
535       0,
536       NULL },
537 
538     { ngx_string("check_status"),
539       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1|NGX_CONF_NOARGS,
540       ngx_http_upstream_check_status,
541       0,
542       0,
543       NULL },
544 
545       ngx_null_command
546 };
547 
548 
549 static ngx_http_module_t  ngx_http_upstream_check_module_ctx = {
550     NULL,                                    /* preconfiguration */
551     NULL,                                    /* postconfiguration */
552 
553     ngx_http_upstream_check_create_main_conf,/* create main configuration */
554     ngx_http_upstream_check_init_main_conf,  /* init main configuration */
555 
556     ngx_http_upstream_check_create_srv_conf, /* create server configuration */
557     NULL,                                    /* merge server configuration */
558 
559     ngx_http_upstream_check_create_loc_conf, /* create location configuration */
560     ngx_http_upstream_check_merge_loc_conf   /* merge location configuration */
561 };
562 
563 
564 ngx_module_t  ngx_http_upstream_check_module = {
565     NGX_MODULE_V1,
566     &ngx_http_upstream_check_module_ctx,   /* module context */
567     ngx_http_upstream_check_commands,      /* module directives */
568     NGX_HTTP_MODULE,                       /* module type */
569     NULL,                                  /* init master */
570     NULL,                                  /* init module */
571     ngx_http_upstream_check_init_process,  /* init process */
572     NULL,                                  /* init thread */
573     NULL,                                  /* exit thread */
574     NULL,                                  /* exit process */
575     NULL,                                  /* exit master */
576     NGX_MODULE_V1_PADDING
577 };
578 
579 
580 static ngx_str_t fastcgi_default_request;
581 static ngx_str_t fastcgi_default_params[] = {
582     ngx_string("REQUEST_METHOD"), ngx_string("GET"),
583     ngx_string("REQUEST_URI"), ngx_string("/"),
584     ngx_string("SCRIPT_FILENAME"), ngx_string("index.php"),
585 };
586 
587 
588 #define NGX_SSL_RANDOM "NGX_HTTP_CHECK_SSL_HELLO\n\n\n\n"
589 
590 /*
591  * This is the SSLv3 CLIENT HELLO packet used in conjunction with the
592  * check type of ssl_hello to ensure that the remote server speaks SSL.
593  *
594  * Check RFC 2246 (TLSv1.0) sections A.3 and A.4 for details.
595  */
596 static char sslv3_client_hello_pkt[] = {
597     "\x16"                /* ContentType         : 0x16 = Hanshake           */
598     "\x03\x01"            /* ProtocolVersion     : 0x0301 = TLSv1.0          */
599     "\x00\x6f"            /* ContentLength       : 0x6f bytes after this one */
600     "\x01"                /* HanshakeType        : 0x01 = CLIENT HELLO       */
601     "\x00\x00\x6b"        /* HandshakeLength     : 0x6b bytes after this one */
602     "\x03\x03"            /* Hello Version       : 0x0303 = TLSv1.2          */
603     "\x00\x00\x00\x00"    /* Unix GMT Time (s)   : filled with <now> (@0x0B) */
604     NGX_SSL_RANDOM        /* Random              : must be exactly 28 bytes  */
605     "\x00"                /* Session ID length   : empty (no session ID)     */
606     "\x00\x1a"            /* Cipher Suite Length : \x1a bytes after this one */
607     "\xc0\x2b" "\xc0\x2f" "\xcc\xa9" "\xcc\xa8"  /* 13 modern ciphers        */
608     "\xc0\x0a" "\xc0\x09" "\xc0\x13" "\xc0\x14"
609     "\x00\x33" "\x00\x39" "\x00\x2f" "\x00\x35"
610     "\x00\x0a"
611     "\x01"                /* Compression Length  : 0x01 = 1 byte for types   */
612     "\x00"                /* Compression Type    : 0x00 = NULL compression   */
613     "\x00\x28"            /* Extensions length */
614     "\x00\x0a"            /* EC extension */
615     "\x00\x08"            /* extension length */
616     "\x00\x06"            /* curves length */
617     "\x00\x17" "\x00\x18" "\x00\x19" /* Three curves */
618     "\x00\x0d"            /* Signature extension */
619     "\x00\x18"            /* extension length */
620     "\x00\x16"            /* hash list length */
621     "\x04\x01" "\x05\x01" "\x06\x01" "\x02\x01"  /* 11 hash algorithms */
622     "\x04\x03" "\x05\x03" "\x06\x03" "\x02\x03"
623     "\x05\x02" "\x04\x02" "\x02\x02"
624 };
625 
626 
627 #define NGX_SSL_HANDSHAKE    0x16
628 #define NGX_SSL_SERVER_HELLO 0x02
629 
630 
631 #define NGX_AJP_CPING        0x0a
632 #define NGX_AJP_CPONG        0x09
633 
634 
635 static char ngx_ajp_cping_packet[] = {
636     0x12, 0x34, 0x00, 0x01, NGX_AJP_CPING, 0x00
637 };
638 
639 static char ngx_ajp_cpong_packet[] = {
640     0x41, 0x42, 0x00, 0x01, NGX_AJP_CPONG
641 };
642 
643 
644 static ngx_check_conf_t  ngx_check_types[] = {
645 
646     { NGX_HTTP_CHECK_TCP,
647       ngx_string("tcp"),
648       ngx_null_string,
649       0,
650       ngx_http_upstream_check_peek_handler,
651       ngx_http_upstream_check_peek_handler,
652       NULL,
653       NULL,
654       NULL,
655       0,
656       1 },
657 
658     { NGX_HTTP_CHECK_HTTP,
659       ngx_string("http"),
660       ngx_string("GET / HTTP/1.0\r\n\r\n"),
661       NGX_CONF_BITMASK_SET | NGX_CHECK_HTTP_2XX | NGX_CHECK_HTTP_3XX,
662       ngx_http_upstream_check_send_handler,
663       ngx_http_upstream_check_recv_handler,
664       ngx_http_upstream_check_http_init,
665       ngx_http_upstream_check_http_parse,
666       ngx_http_upstream_check_http_reinit,
667       1,
668       1 },
669 
670     { NGX_HTTP_CHECK_HTTP,
671       ngx_string("fastcgi"),
672       ngx_null_string,
673       0,
674       ngx_http_upstream_check_send_handler,
675       ngx_http_upstream_check_recv_handler,
676       ngx_http_upstream_check_http_init,
677       ngx_http_upstream_check_fastcgi_parse,
678       ngx_http_upstream_check_http_reinit,
679       1,
680       0 },
681 
682     { NGX_HTTP_CHECK_SSL_HELLO,
683       ngx_string("ssl_hello"),
684       ngx_string(sslv3_client_hello_pkt),
685       0,
686       ngx_http_upstream_check_send_handler,
687       ngx_http_upstream_check_recv_handler,
688       ngx_http_upstream_check_ssl_hello_init,
689       ngx_http_upstream_check_ssl_hello_parse,
690       ngx_http_upstream_check_ssl_hello_reinit,
691       1,
692       0 },
693 
694     { NGX_HTTP_CHECK_MYSQL,
695       ngx_string("mysql"),
696       ngx_null_string,
697       0,
698       ngx_http_upstream_check_send_handler,
699       ngx_http_upstream_check_recv_handler,
700       ngx_http_upstream_check_mysql_init,
701       ngx_http_upstream_check_mysql_parse,
702       ngx_http_upstream_check_mysql_reinit,
703       1,
704       0 },
705 
706     { NGX_HTTP_CHECK_AJP,
707       ngx_string("ajp"),
708       ngx_string(ngx_ajp_cping_packet),
709       0,
710       ngx_http_upstream_check_send_handler,
711       ngx_http_upstream_check_recv_handler,
712       ngx_http_upstream_check_ajp_init,
713       ngx_http_upstream_check_ajp_parse,
714       ngx_http_upstream_check_ajp_reinit,
715       1,
716       0 },
717 
718     { 0,
719       ngx_null_string,
720       ngx_null_string,
721       0,
722       NULL,
723       NULL,
724       NULL,
725       NULL,
726       NULL,
727       0,
728       0 }
729 };
730 
731 
732 static ngx_check_status_conf_t  ngx_check_status_formats[] = {
733 
734     { ngx_string("html"),
735       ngx_string("text/html"),
736       ngx_http_upstream_check_status_html_format },
737 
738     { ngx_string("csv"),
739       ngx_string("text/plain"),
740       ngx_http_upstream_check_status_csv_format },
741 
742     { ngx_string("json"),
743       ngx_string("application/json"), /* RFC 4627 */
744       ngx_http_upstream_check_status_json_format },
745 
746     { ngx_null_string, ngx_null_string, NULL }
747 };
748 
749 
750 static ngx_check_status_command_t ngx_check_status_commands[] =  {
751 
752     { ngx_string("format"),
753       ngx_http_upstream_check_status_command_format },
754 
755     { ngx_string("status"),
756       ngx_http_upstream_check_status_command_status },
757 
758     { ngx_null_string, NULL }
759 };
760 
761 
762 static ngx_uint_t ngx_http_upstream_check_shm_generation = 0;
763 static ngx_http_upstream_check_peers_t *check_peers_ctx = NULL;
764 
765 
766 ngx_uint_t
ngx_http_upstream_check_add_peer(ngx_conf_t * cf,ngx_http_upstream_srv_conf_t * us,ngx_addr_t * peer_addr)767 ngx_http_upstream_check_add_peer(ngx_conf_t *cf,
768     ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer_addr)
769 {
770     ngx_http_upstream_check_peer_t       *peer;
771     ngx_http_upstream_check_peers_t      *peers;
772     ngx_http_upstream_check_srv_conf_t   *ucscf;
773     ngx_http_upstream_check_main_conf_t  *ucmcf;
774 
775     if (us->srv_conf == NULL) {
776         return NGX_ERROR;
777     }
778 
779     ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module);
780 
781     if(ucscf->check_interval == 0) {
782         return NGX_ERROR;
783     }
784 
785     ucmcf = ngx_http_conf_get_module_main_conf(cf,
786                                                ngx_http_upstream_check_module);
787     peers = ucmcf->peers;
788 
789     peer = ngx_array_push(&peers->peers);
790     if (peer == NULL) {
791         return NGX_ERROR;
792     }
793 
794     ngx_memzero(peer, sizeof(ngx_http_upstream_check_peer_t));
795 
796     peer->index = peers->peers.nelts - 1;
797     peer->conf = ucscf;
798     peer->upstream_name = &us->host;
799     peer->peer_addr = peer_addr;
800 
801     if (ucscf->port) {
802         peer->check_peer_addr = ngx_pcalloc(cf->pool, sizeof(ngx_addr_t));
803         if (peer->check_peer_addr == NULL) {
804             return NGX_ERROR;
805         }
806 
807         if (ngx_http_upstream_check_addr_change_port(cf->pool,
808                 peer->check_peer_addr, peer_addr, ucscf->port)
809             != NGX_OK) {
810 
811             return NGX_ERROR;
812         }
813 
814     } else {
815         peer->check_peer_addr = peer->peer_addr;
816     }
817 
818     peers->checksum +=
819         ngx_murmur_hash2(peer_addr->name.data, peer_addr->name.len);
820 
821     return peer->index;
822 }
823 
824 
825 static ngx_int_t
ngx_http_upstream_check_addr_change_port(ngx_pool_t * pool,ngx_addr_t * dst,ngx_addr_t * src,ngx_uint_t port)826 ngx_http_upstream_check_addr_change_port(ngx_pool_t *pool, ngx_addr_t *dst,
827     ngx_addr_t *src, ngx_uint_t port)
828 {
829     size_t                len;
830     u_char               *p;
831     struct sockaddr_in   *sin;
832 #if (NGX_HAVE_INET6)
833     struct sockaddr_in6  *sin6;
834 #endif
835 
836     dst->socklen = src->socklen;
837     dst->sockaddr = ngx_palloc(pool, dst->socklen);
838     if (dst->sockaddr == NULL) {
839         return NGX_ERROR;
840     }
841 
842     ngx_memcpy(dst->sockaddr, src->sockaddr, dst->socklen);
843 
844     switch (dst->sockaddr->sa_family) {
845 
846     case AF_INET:
847 
848         len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
849         sin = (struct sockaddr_in *) dst->sockaddr;
850         sin->sin_port = htons(port);
851 
852         break;
853 
854 #if (NGX_HAVE_INET6)
855     case AF_INET6:
856 
857         len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1;
858         sin6 = (struct sockaddr_in6 *) dst->sockaddr;
859         sin6->sin6_port = htons(port);
860 
861         break;
862 #endif
863 
864     default:
865         return NGX_ERROR;
866     }
867 
868     p = ngx_pnalloc(pool, len);
869     if (p == NULL) {
870         return NGX_ERROR;
871     }
872 
873 #if (nginx_version >= 1005012)
874     len = ngx_sock_ntop(dst->sockaddr, dst->socklen, p, len, 1);
875 #else
876     len = ngx_sock_ntop(dst->sockaddr, p, len, 1);
877 #endif
878 
879     dst->name.len = len;
880     dst->name.data = p;
881 
882     return NGX_OK;
883 }
884 
885 
886 ngx_uint_t
ngx_http_upstream_check_peer_down(ngx_uint_t index)887 ngx_http_upstream_check_peer_down(ngx_uint_t index)
888 {
889     ngx_http_upstream_check_peer_t  *peer;
890 
891     if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) {
892         return 0;
893     }
894 
895     peer = check_peers_ctx->peers.elts;
896 
897     return (peer[index].shm->down);
898 }
899 
900 
901 /* TODO: this interface can count each peer's busyness */
902 void
ngx_http_upstream_check_get_peer(ngx_uint_t index)903 ngx_http_upstream_check_get_peer(ngx_uint_t index)
904 {
905     ngx_http_upstream_check_peer_t  *peer;
906 
907     if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) {
908         return;
909     }
910 
911     peer = check_peers_ctx->peers.elts;
912 
913     ngx_shmtx_lock(&peer[index].shm->mutex);
914 
915     peer[index].shm->busyness++;
916     peer[index].shm->access_count++;
917 
918     ngx_shmtx_unlock(&peer[index].shm->mutex);
919 }
920 
921 
922 void
ngx_http_upstream_check_free_peer(ngx_uint_t index)923 ngx_http_upstream_check_free_peer(ngx_uint_t index)
924 {
925     ngx_http_upstream_check_peer_t  *peer;
926 
927     if (check_peers_ctx == NULL || index >= check_peers_ctx->peers.nelts) {
928         return;
929     }
930 
931     peer = check_peers_ctx->peers.elts;
932 
933     ngx_shmtx_lock(&peer[index].shm->mutex);
934 
935     if (peer[index].shm->busyness > 0) {
936         peer[index].shm->busyness--;
937     }
938 
939     ngx_shmtx_unlock(&peer[index].shm->mutex);
940 }
941 
942 
943 static ngx_int_t
ngx_http_upstream_check_add_timers(ngx_cycle_t * cycle)944 ngx_http_upstream_check_add_timers(ngx_cycle_t *cycle)
945 {
946     ngx_uint_t                           i;
947     ngx_msec_t                           t, delay;
948     ngx_check_conf_t                    *cf;
949     ngx_http_upstream_check_peer_t      *peer;
950     ngx_http_upstream_check_peers_t     *peers;
951     ngx_http_upstream_check_srv_conf_t  *ucscf;
952     ngx_http_upstream_check_peer_shm_t  *peer_shm;
953     ngx_http_upstream_check_peers_shm_t *peers_shm;
954 
955     peers = check_peers_ctx;
956     if (peers == NULL) {
957         return NGX_OK;
958     }
959 
960     peers_shm = peers->peers_shm;
961     if (peers_shm == NULL) {
962         return NGX_OK;
963     }
964 
965     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cycle->log, 0,
966                    "http check upstream init_process, shm_name: %V, "
967                    "peer number: %ud",
968                    &peers->check_shm_name,
969                    peers->peers.nelts);
970 
971     srandom(ngx_pid);
972 
973     peer = peers->peers.elts;
974     peer_shm = peers_shm->peers;
975 
976     for (i = 0; i < peers->peers.nelts; i++) {
977         peer[i].shm = &peer_shm[i];
978 
979         peer[i].check_ev.handler = ngx_http_upstream_check_begin_handler;
980         peer[i].check_ev.log = cycle->log;
981         peer[i].check_ev.data = &peer[i];
982         peer[i].check_ev.timer_set = 0;
983 
984         peer[i].check_timeout_ev.handler =
985             ngx_http_upstream_check_timeout_handler;
986         peer[i].check_timeout_ev.log = cycle->log;
987         peer[i].check_timeout_ev.data = &peer[i];
988         peer[i].check_timeout_ev.timer_set = 0;
989 
990         ucscf = peer[i].conf;
991         cf = ucscf->check_type_conf;
992 
993         if (cf->need_pool) {
994             peer[i].pool = ngx_create_pool(ngx_pagesize, cycle->log);
995             if (peer[i].pool == NULL) {
996                 return NGX_ERROR;
997             }
998         }
999 
1000         peer[i].send_handler = cf->send_handler;
1001         peer[i].recv_handler = cf->recv_handler;
1002 
1003         peer[i].init = cf->init;
1004         peer[i].parse = cf->parse;
1005         peer[i].reinit = cf->reinit;
1006 
1007         /*
1008          * We add a random start time here, since we don't want to trigger
1009          * the check events too close to each other at the beginning.
1010          */
1011         delay = ucscf->check_interval > 1000 ? ucscf->check_interval : 1000;
1012         t = ngx_random() % delay;
1013 
1014         ngx_add_timer(&peer[i].check_ev, t);
1015     }
1016 
1017     return NGX_OK;
1018 }
1019 
1020 
1021 static void
ngx_http_upstream_check_begin_handler(ngx_event_t * event)1022 ngx_http_upstream_check_begin_handler(ngx_event_t *event)
1023 {
1024     ngx_msec_t                           interval;
1025     ngx_http_upstream_check_peer_t      *peer;
1026     ngx_http_upstream_check_peers_t     *peers;
1027     ngx_http_upstream_check_srv_conf_t  *ucscf;
1028     ngx_http_upstream_check_peers_shm_t *peers_shm;
1029 
1030     if (ngx_http_upstream_check_need_exit()) {
1031         return;
1032     }
1033 
1034     peers = check_peers_ctx;
1035     if (peers == NULL) {
1036         return;
1037     }
1038 
1039     peers_shm = peers->peers_shm;
1040     if (peers_shm == NULL) {
1041         return;
1042     }
1043 
1044     peer = event->data;
1045     ucscf = peer->conf;
1046 
1047     ngx_add_timer(event, ucscf->check_interval / 2);
1048 
1049     /* This process is processing this peer now. */
1050     if ((peer->shm->owner == ngx_pid  ||
1051         (peer->pc.connection != NULL) ||
1052         peer->check_timeout_ev.timer_set)) {
1053         return;
1054     }
1055 
1056     interval = ngx_current_msec - peer->shm->access_time;
1057     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, event->log, 0,
1058                    "http check begin handler index: %ui, owner: %P, "
1059                    "ngx_pid: %P, interval: %M, check_interval: %M",
1060                    peer->index, peer->shm->owner,
1061                    ngx_pid, interval,
1062                    ucscf->check_interval);
1063 
1064     ngx_shmtx_lock(&peer->shm->mutex);
1065 
1066     if (peers_shm->generation != ngx_http_upstream_check_shm_generation) {
1067         ngx_shmtx_unlock(&peer->shm->mutex);
1068         return;
1069     }
1070 
1071     if ((interval >= ucscf->check_interval)
1072          && (peer->shm->owner == NGX_INVALID_PID))
1073     {
1074         peer->shm->owner = ngx_pid;
1075 
1076     } else if (interval >= (ucscf->check_interval << 4)) {
1077 
1078         /*
1079          * If the check peer has been untouched for 2^4 times of
1080          * the check interval, activate the current timer.
1081          * Sometimes, the checking process may disappear
1082          * in some circumstances, and the clean event will never
1083          * be triggered.
1084          */
1085         peer->shm->owner = ngx_pid;
1086         peer->shm->access_time = ngx_current_msec;
1087     }
1088 
1089     ngx_shmtx_unlock(&peer->shm->mutex);
1090 
1091     if (peer->shm->owner == ngx_pid) {
1092         ngx_http_upstream_check_connect_handler(event);
1093     }
1094 }
1095 
1096 
1097 static void
ngx_http_upstream_check_connect_handler(ngx_event_t * event)1098 ngx_http_upstream_check_connect_handler(ngx_event_t *event)
1099 {
1100     ngx_int_t                            rc;
1101     ngx_connection_t                    *c;
1102     ngx_http_upstream_check_peer_t      *peer;
1103     ngx_http_upstream_check_srv_conf_t  *ucscf;
1104 
1105     if (ngx_http_upstream_check_need_exit()) {
1106         return;
1107     }
1108 
1109     peer = event->data;
1110     ucscf = peer->conf;
1111 
1112     if (peer->pc.connection != NULL) {
1113         c = peer->pc.connection;
1114         if ((rc = ngx_http_upstream_check_peek_one_byte(c)) == NGX_OK) {
1115             goto upstream_check_connect_done;
1116         } else {
1117             ngx_close_connection(c);
1118             peer->pc.connection = NULL;
1119         }
1120     }
1121     ngx_memzero(&peer->pc, sizeof(ngx_peer_connection_t));
1122 
1123     peer->pc.sockaddr = peer->check_peer_addr->sockaddr;
1124     peer->pc.socklen = peer->check_peer_addr->socklen;
1125     peer->pc.name = &peer->check_peer_addr->name;
1126 
1127     peer->pc.get = ngx_event_get_peer;
1128     peer->pc.log = event->log;
1129     peer->pc.log_error = NGX_ERROR_ERR;
1130 
1131     peer->pc.cached = 0;
1132     peer->pc.connection = NULL;
1133 
1134     rc = ngx_event_connect_peer(&peer->pc);
1135 
1136     if (rc == NGX_ERROR || rc == NGX_DECLINED) {
1137         ngx_http_upstream_check_status_update(peer, 0);
1138         ngx_http_upstream_check_clean_event(peer);
1139         return;
1140     }
1141 
1142     /* NGX_OK or NGX_AGAIN */
1143     c = peer->pc.connection;
1144     c->data = peer;
1145     c->log = peer->pc.log;
1146     c->sendfile = 0;
1147     c->read->log = c->log;
1148     c->write->log = c->log;
1149     c->pool = peer->pool;
1150 
1151 upstream_check_connect_done:
1152     peer->state = NGX_HTTP_CHECK_CONNECT_DONE;
1153 
1154     c->write->handler = peer->send_handler;
1155     c->read->handler = peer->recv_handler;
1156 
1157     ngx_add_timer(&peer->check_timeout_ev, ucscf->check_timeout);
1158 
1159     /* The kqueue's loop interface needs it. */
1160     if (rc == NGX_OK) {
1161         c->write->handler(c->write);
1162     }
1163 }
1164 
1165 static ngx_int_t
ngx_http_upstream_check_peek_one_byte(ngx_connection_t * c)1166 ngx_http_upstream_check_peek_one_byte(ngx_connection_t *c)
1167 {
1168     char                            buf[1];
1169     ngx_int_t                       n;
1170     ngx_err_t                       err;
1171 
1172     n = recv(c->fd, buf, 1, MSG_PEEK);
1173     err = ngx_socket_errno;
1174 
1175     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err,
1176                    "http check upstream recv(): %i, fd: %d",
1177                    n, c->fd);
1178 
1179     if (n == 1 || (n == -1 && err == NGX_EAGAIN)) {
1180         return NGX_OK;
1181     } else {
1182         return NGX_ERROR;
1183     }
1184 }
1185 
1186 static void
ngx_http_upstream_check_peek_handler(ngx_event_t * event)1187 ngx_http_upstream_check_peek_handler(ngx_event_t *event)
1188 {
1189     ngx_connection_t               *c;
1190     ngx_http_upstream_check_peer_t *peer;
1191 
1192     if (ngx_http_upstream_check_need_exit()) {
1193         return;
1194     }
1195 
1196     c = event->data;
1197     peer = c->data;
1198 
1199     if (ngx_http_upstream_check_peek_one_byte(c) == NGX_OK) {
1200         ngx_http_upstream_check_status_update(peer, 1);
1201 
1202     } else {
1203         c->error = 1;
1204         ngx_http_upstream_check_status_update(peer, 0);
1205     }
1206 
1207     ngx_http_upstream_check_clean_event(peer);
1208 
1209     ngx_http_upstream_check_finish_handler(event);
1210 }
1211 
1212 
1213 static void
ngx_http_upstream_check_discard_handler(ngx_event_t * event)1214 ngx_http_upstream_check_discard_handler(ngx_event_t *event)
1215 {
1216     u_char                          buf[4096];
1217     ssize_t                         size;
1218     ngx_connection_t               *c;
1219     ngx_http_upstream_check_peer_t *peer;
1220 
1221     c = event->data;
1222 
1223     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1224                    "upstream check discard handler");
1225 
1226     if (ngx_http_upstream_check_need_exit()) {
1227         return;
1228     }
1229 
1230     peer = c->data;
1231 
1232     while (1) {
1233         size = c->recv(c, buf, 4096);
1234 
1235         if (size > 0) {
1236             continue;
1237 
1238         } else if (size == NGX_AGAIN) {
1239             break;
1240 
1241         } else {
1242             if (size == 0) {
1243                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1244                                "peer closed its half side of the connection");
1245             }
1246 
1247             goto check_discard_fail;
1248         }
1249     }
1250 
1251     if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1252         goto check_discard_fail;
1253     }
1254 
1255     return;
1256 
1257  check_discard_fail:
1258     c->error = 1;
1259     ngx_http_upstream_check_clean_event(peer);
1260 }
1261 
1262 
1263 static void
ngx_http_upstream_check_dummy_handler(ngx_event_t * event)1264 ngx_http_upstream_check_dummy_handler(ngx_event_t *event)
1265 {
1266     return;
1267 }
1268 
1269 
1270 static void
ngx_http_upstream_check_send_handler(ngx_event_t * event)1271 ngx_http_upstream_check_send_handler(ngx_event_t *event)
1272 {
1273     ssize_t                         size;
1274     ngx_connection_t               *c;
1275     ngx_http_upstream_check_ctx_t  *ctx;
1276     ngx_http_upstream_check_peer_t *peer;
1277 
1278     if (ngx_http_upstream_check_need_exit()) {
1279         return;
1280     }
1281 
1282     c = event->data;
1283     peer = c->data;
1284 
1285     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send.");
1286 
1287     if (c->pool == NULL) {
1288         ngx_log_error(NGX_LOG_ERR, event->log, 0,
1289                       "check pool NULL with peer: %V ",
1290                       &peer->check_peer_addr->name);
1291 
1292         goto check_send_fail;
1293     }
1294 
1295     if (peer->state != NGX_HTTP_CHECK_CONNECT_DONE) {
1296         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
1297 
1298             ngx_log_error(NGX_LOG_ERR, event->log, 0,
1299                           "check handle write event error with peer: %V ",
1300                           &peer->check_peer_addr->name);
1301 
1302             goto check_send_fail;
1303         }
1304 
1305         return;
1306     }
1307 
1308     if (peer->check_data == NULL) {
1309 
1310         peer->check_data = ngx_pcalloc(peer->pool,
1311                                        sizeof(ngx_http_upstream_check_ctx_t));
1312         if (peer->check_data == NULL) {
1313             goto check_send_fail;
1314         }
1315 
1316         if (peer->init == NULL || peer->init(peer) != NGX_OK) {
1317 
1318             ngx_log_error(NGX_LOG_ERR, event->log, 0,
1319                           "check init error with peer: %V ",
1320                           &peer->check_peer_addr->name);
1321 
1322             goto check_send_fail;
1323         }
1324     }
1325 
1326     ctx = peer->check_data;
1327 
1328     while (ctx->send.pos < ctx->send.last) {
1329 
1330         size = c->send(c, ctx->send.pos, ctx->send.last - ctx->send.pos);
1331 
1332 #if (NGX_DEBUG)
1333         {
1334         ngx_err_t  err;
1335 
1336         err = (size >=0) ? 0 : ngx_socket_errno;
1337         ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, err,
1338                        "http check send size: %z, total: %z",
1339                        size, ctx->send.last - ctx->send.pos);
1340         }
1341 #endif
1342 
1343         if (size > 0) {
1344             ctx->send.pos += size;
1345         } else if (size == 0 || size == NGX_AGAIN) {
1346             return;
1347         } else {
1348             c->error = 1;
1349             goto check_send_fail;
1350         }
1351     }
1352 
1353     if (ctx->send.pos == ctx->send.last) {
1354         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http check send done.");
1355         peer->state = NGX_HTTP_CHECK_SEND_DONE;
1356         c->requests++;
1357     }
1358 
1359     return;
1360 
1361 check_send_fail:
1362     ngx_http_upstream_check_status_update(peer, 0);
1363     ngx_http_upstream_check_clean_event(peer);
1364 }
1365 
1366 
1367 static void
ngx_http_upstream_check_recv_handler(ngx_event_t * event)1368 ngx_http_upstream_check_recv_handler(ngx_event_t *event)
1369 {
1370     u_char                         *new_buf;
1371     ssize_t                         size, n;
1372     ngx_int_t                       rc;
1373     ngx_connection_t               *c;
1374     ngx_http_upstream_check_ctx_t  *ctx;
1375     ngx_http_upstream_check_peer_t *peer;
1376 
1377     if (ngx_http_upstream_check_need_exit()) {
1378         return;
1379     }
1380 
1381     c = event->data;
1382     peer = c->data;
1383 
1384     if (peer->state != NGX_HTTP_CHECK_SEND_DONE) {
1385 
1386         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
1387             goto check_recv_fail;
1388         }
1389 
1390         return;
1391     }
1392 
1393     ctx = peer->check_data;
1394 
1395     if (ctx->recv.start == NULL) {
1396         /* 1/2 of the page_size, is it enough? */
1397         ctx->recv.start = ngx_palloc(c->pool, ngx_pagesize / 2);
1398         if (ctx->recv.start == NULL) {
1399             goto check_recv_fail;
1400         }
1401 
1402         ctx->recv.last = ctx->recv.pos = ctx->recv.start;
1403         ctx->recv.end = ctx->recv.start + ngx_pagesize / 2;
1404     }
1405 
1406     while (1) {
1407         n = ctx->recv.end - ctx->recv.last;
1408 
1409         /* buffer not big enough? enlarge it by twice */
1410         if (n == 0) {
1411             size = ctx->recv.end - ctx->recv.start;
1412             new_buf = ngx_palloc(c->pool, size * 2);
1413             if (new_buf == NULL) {
1414                 goto check_recv_fail;
1415             }
1416 
1417             ngx_memcpy(new_buf, ctx->recv.start, size);
1418 
1419             ctx->recv.pos = ctx->recv.start = new_buf;
1420             ctx->recv.last = new_buf + size;
1421             ctx->recv.end = new_buf + size * 2;
1422 
1423             n = ctx->recv.end - ctx->recv.last;
1424         }
1425 
1426         size = c->recv(c, ctx->recv.last, n);
1427 
1428 #if (NGX_DEBUG)
1429         {
1430         ngx_err_t  err;
1431 
1432         err = (size >= 0) ? 0 : ngx_socket_errno;
1433         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, err,
1434                        "http check recv size: %z, peer: %V ",
1435                        size, &peer->check_peer_addr->name);
1436         }
1437 #endif
1438 
1439         if (size > 0) {
1440             ctx->recv.last += size;
1441             continue;
1442         } else if (size == 0 || size == NGX_AGAIN) {
1443             break;
1444         } else {
1445             c->error = 1;
1446             goto check_recv_fail;
1447         }
1448     }
1449 
1450     rc = peer->parse(peer);
1451 
1452     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
1453                    "http check parse rc: %i, peer: %V ",
1454                    rc, &peer->check_peer_addr->name);
1455 
1456     switch (rc) {
1457 
1458     case NGX_AGAIN:
1459         /* The peer has closed its half side of the connection. */
1460         if (size == 0) {
1461             ngx_http_upstream_check_status_update(peer, 0);
1462             c->error = 1;
1463             break;
1464         }
1465 
1466         return;
1467 
1468     case NGX_ERROR:
1469         ngx_log_error(NGX_LOG_ERR, event->log, 0,
1470                       "check protocol %V error with peer: %V ",
1471                       &peer->conf->check_type_conf->name,
1472                       &peer->check_peer_addr->name);
1473 
1474         ngx_http_upstream_check_status_update(peer, 0);
1475         break;
1476 
1477     case NGX_OK:
1478         /* fall through */
1479 
1480     default:
1481         ngx_http_upstream_check_status_update(peer, 1);
1482         break;
1483     }
1484 
1485     peer->state = NGX_HTTP_CHECK_RECV_DONE;
1486     ngx_http_upstream_check_clean_event(peer);
1487     return;
1488 
1489 check_recv_fail:
1490     ngx_http_upstream_check_status_update(peer, 0);
1491     ngx_http_upstream_check_clean_event(peer);
1492 }
1493 
1494 
1495 static ngx_int_t
ngx_http_upstream_check_http_init(ngx_http_upstream_check_peer_t * peer)1496 ngx_http_upstream_check_http_init(ngx_http_upstream_check_peer_t *peer)
1497 {
1498     ngx_http_upstream_check_ctx_t       *ctx;
1499     ngx_http_upstream_check_srv_conf_t  *ucscf;
1500 
1501     ctx = peer->check_data;
1502     ucscf = peer->conf;
1503 
1504     ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data;
1505     ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len;
1506 
1507     ctx->recv.start = ctx->recv.pos = NULL;
1508     ctx->recv.end = ctx->recv.last = NULL;
1509 
1510     ctx->state = 0;
1511 
1512     ngx_memzero(&ctx->status, sizeof(ngx_http_status_t));
1513 
1514     return NGX_OK;
1515 }
1516 
1517 
1518 static ngx_int_t
ngx_http_upstream_check_http_parse(ngx_http_upstream_check_peer_t * peer)1519 ngx_http_upstream_check_http_parse(ngx_http_upstream_check_peer_t *peer)
1520 {
1521     ngx_int_t                            rc;
1522     ngx_uint_t                           code, code_n;
1523     ngx_http_upstream_check_ctx_t       *ctx;
1524     ngx_http_upstream_check_srv_conf_t  *ucscf;
1525 
1526     ucscf = peer->conf;
1527     ctx = peer->check_data;
1528 
1529     if ((ctx->recv.last - ctx->recv.pos) > 0) {
1530 
1531         rc = ngx_http_upstream_check_parse_status_line(ctx,
1532                                                        &ctx->recv,
1533                                                        &ctx->status);
1534         if (rc == NGX_AGAIN) {
1535             return rc;
1536         }
1537 
1538         if (rc == NGX_ERROR) {
1539             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1540                           "http parse status line error with peer: %V ",
1541                           &peer->check_peer_addr->name);
1542             return rc;
1543         }
1544 
1545         code = ctx->status.code;
1546 
1547         if (code >= 200 && code < 300) {
1548             code_n = NGX_CHECK_HTTP_2XX;
1549         } else if (code >= 300 && code < 400) {
1550             code_n = NGX_CHECK_HTTP_3XX;
1551         } else if (code >= 400 && code < 500) {
1552             peer->pc.connection->error = 1;
1553             code_n = NGX_CHECK_HTTP_4XX;
1554         } else if (code >= 500 && code < 600) {
1555             peer->pc.connection->error = 1;
1556             code_n = NGX_CHECK_HTTP_5XX;
1557         } else {
1558             peer->pc.connection->error = 1;
1559             code_n = NGX_CHECK_HTTP_ERR;
1560         }
1561 
1562         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1563                        "http_parse: code_n: %ui, conf: %ui",
1564                        code_n, ucscf->code.status_alive);
1565 
1566         if (code_n & ucscf->code.status_alive) {
1567             return NGX_OK;
1568         } else {
1569             return NGX_ERROR;
1570         }
1571     } else {
1572         return NGX_AGAIN;
1573     }
1574 
1575     return NGX_OK;
1576 }
1577 
1578 
1579 static ngx_int_t
ngx_http_upstream_check_fastcgi_process_record(ngx_http_upstream_check_ctx_t * ctx,ngx_buf_t * b,ngx_http_status_t * status)1580 ngx_http_upstream_check_fastcgi_process_record(
1581     ngx_http_upstream_check_ctx_t *ctx, ngx_buf_t *b, ngx_http_status_t *status)
1582 {
1583     u_char                     ch, *p;
1584     ngx_http_fastcgi_state_e   state;
1585 
1586     state = ctx->state;
1587 
1588     for (p = b->pos; p < b->last; p++) {
1589 
1590         ch = *p;
1591 
1592         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1593                        "http fastcgi record byte: %02Xd", ch);
1594 
1595         switch (state) {
1596 
1597         case ngx_http_fastcgi_st_version:
1598             if (ch != 1) {
1599                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1600                               "upstream sent unsupported FastCGI "
1601                               "protocol version: %d", ch);
1602                 return NGX_ERROR;
1603             }
1604             state = ngx_http_fastcgi_st_type;
1605             break;
1606 
1607         case ngx_http_fastcgi_st_type:
1608             switch (ch) {
1609             case NGX_HTTP_FASTCGI_STDOUT:
1610             case NGX_HTTP_FASTCGI_STDERR:
1611             case NGX_HTTP_FASTCGI_END_REQUEST:
1612                 status->code = (ngx_uint_t) ch;
1613                 break;
1614             default:
1615                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1616                               "upstream sent invalid FastCGI "
1617                               "record type: %d", ch);
1618                 return NGX_ERROR;
1619 
1620             }
1621             state = ngx_http_fastcgi_st_request_id_hi;
1622             break;
1623 
1624         /* we support the single request per connection */
1625 
1626         case ngx_http_fastcgi_st_request_id_hi:
1627             if (ch != 0) {
1628                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1629                               "upstream sent unexpected FastCGI "
1630                               "request id high byte: %d", ch);
1631                 return NGX_ERROR;
1632             }
1633             state = ngx_http_fastcgi_st_request_id_lo;
1634             break;
1635 
1636         case ngx_http_fastcgi_st_request_id_lo:
1637             if (ch != 1) {
1638                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1639                               "upstream sent unexpected FastCGI "
1640                               "request id low byte: %d", ch);
1641                 return NGX_ERROR;
1642             }
1643             state = ngx_http_fastcgi_st_content_length_hi;
1644             break;
1645 
1646         case ngx_http_fastcgi_st_content_length_hi:
1647             ctx->length = ch << 8;
1648             state = ngx_http_fastcgi_st_content_length_lo;
1649             break;
1650 
1651         case ngx_http_fastcgi_st_content_length_lo:
1652             ctx->length |= (size_t) ch;
1653             state = ngx_http_fastcgi_st_padding_length;
1654             break;
1655 
1656         case ngx_http_fastcgi_st_padding_length:
1657             ctx->padding = (size_t) ch;
1658             state = ngx_http_fastcgi_st_reserved;
1659             break;
1660 
1661         case ngx_http_fastcgi_st_reserved:
1662             state = ngx_http_fastcgi_st_data;
1663 
1664             b->pos = p + 1;
1665             ctx->state = state;
1666 
1667             return NGX_OK;
1668 
1669         /* suppress warning */
1670         case ngx_http_fastcgi_st_data:
1671         case ngx_http_fastcgi_st_padding:
1672             break;
1673         }
1674     }
1675 
1676     ctx->state = state;
1677 
1678     return NGX_AGAIN;
1679 }
1680 
1681 
1682 static ngx_int_t
ngx_http_upstream_check_fastcgi_parse(ngx_http_upstream_check_peer_t * peer)1683 ngx_http_upstream_check_fastcgi_parse(ngx_http_upstream_check_peer_t *peer)
1684 {
1685     ngx_int_t                            rc;
1686     ngx_flag_t                           done;
1687     ngx_uint_t                           type, code, code_n;
1688     ngx_http_upstream_check_ctx_t       *ctx;
1689     ngx_http_upstream_check_srv_conf_t  *ucscf;
1690 
1691     ucscf = peer->conf;
1692     ctx = peer->check_data;
1693 
1694     if ((ctx->recv.last - ctx->recv.pos) <= 0) {
1695         return NGX_AGAIN;
1696     }
1697 
1698     done = 0;
1699 
1700     for ( ;; ) {
1701 
1702         if (ctx->state < ngx_http_fastcgi_st_data) {
1703             rc = ngx_http_upstream_check_fastcgi_process_record(ctx,
1704                     &ctx->recv, &ctx->status);
1705 
1706             type = ctx->status.code;
1707 
1708             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1709                            "fastcgi_parse rc: [%i], type: [%ui]", rc, type);
1710 
1711             if (rc == NGX_AGAIN) {
1712                 return rc;
1713             }
1714 
1715             if (rc == NGX_ERROR) {
1716                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1717                    "check fastcgi parse status line error with peer: %V",
1718                    &peer->check_peer_addr->name);
1719 
1720                 return rc;
1721             }
1722 
1723             if (type != NGX_HTTP_FASTCGI_STDOUT
1724                 && type != NGX_HTTP_FASTCGI_STDERR)
1725             {
1726                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1727                    "check fastcgi sent unexpected FastCGI record: %d", type);
1728 
1729                 return NGX_ERROR;
1730             }
1731 
1732             if (type == NGX_HTTP_FASTCGI_STDOUT && ctx->length == 0) {
1733                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1734                    "check fastcgi prematurely closed FastCGI stdout");
1735 
1736                 return NGX_ERROR;
1737             }
1738         }
1739 
1740         if (ctx->state == ngx_http_fastcgi_st_padding) {
1741 
1742             if (ctx->recv.pos + ctx->padding < ctx->recv.last) {
1743                 ctx->status.code = ngx_http_fastcgi_st_version;
1744                 ctx->recv.pos += ctx->padding;
1745 
1746                 continue;
1747             }
1748 
1749             if (ctx->recv.pos + ctx->padding == ctx->recv.last) {
1750                 ctx->status.code = ngx_http_fastcgi_st_version;
1751                 ctx->recv.pos = ctx->recv.last;
1752 
1753                 return NGX_AGAIN;
1754             }
1755 
1756             ctx->padding -= ctx->recv.last - ctx->recv.pos;
1757             ctx->recv.pos = ctx->recv.last;
1758 
1759             return NGX_AGAIN;
1760         }
1761 
1762         if (ctx->status.code == NGX_HTTP_FASTCGI_STDERR) {
1763 
1764             ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0,
1765                           "fastcgi check error");
1766 
1767             return NGX_ERROR;
1768         }
1769 
1770         /* ctx->status.code == NGX_HTTP_FASTCGI_STDOUT */
1771 
1772         if (ctx->recv.pos + ctx->length < ctx->recv.last) {
1773             ctx->recv.last = ctx->recv.pos + ctx->length;
1774         } else {
1775             return NGX_ERROR;
1776         }
1777 
1778         ctx->status.code = 0;
1779 
1780         for ( ;; ) {
1781             rc = ngx_http_upstream_check_parse_fastcgi_status(ctx,
1782                                                               &ctx->recv,
1783                                                               &ctx->status);
1784             ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
1785                           "fastcgi http parse status line rc: %i ", rc);
1786 
1787             if (rc == NGX_ERROR) {
1788                 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
1789                    "fastcgi http parse status line error with peer: %V ",
1790                     &peer->check_peer_addr->name);
1791                 return NGX_ERROR;
1792             }
1793 
1794             if (rc == NGX_AGAIN) {
1795                 break;
1796             }
1797 
1798             if (rc == NGX_DONE) {
1799                 done = 1;
1800                 ngx_log_error(NGX_LOG_DEBUG, ngx_cycle->log, 0,
1801                               "fastcgi http parse status: %i",
1802                               ctx->status.code);
1803                 break;
1804             }
1805 
1806             /* rc = NGX_OK */
1807         }
1808 
1809         if (ucscf->code.status_alive == 0 || done == 0) {
1810             return NGX_OK;
1811         }
1812 
1813         code = ctx->status.code;
1814 
1815         if (code >= 200 && code < 300) {
1816             code_n = NGX_CHECK_HTTP_2XX;
1817         } else if (code >= 300 && code < 400) {
1818             code_n = NGX_CHECK_HTTP_3XX;
1819         } else if (code >= 400 && code < 500) {
1820             code_n = NGX_CHECK_HTTP_4XX;
1821         } else if (code >= 500 && code < 600) {
1822             code_n = NGX_CHECK_HTTP_5XX;
1823         } else {
1824             code_n = NGX_CHECK_HTTP_ERR;
1825         }
1826 
1827         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1828                        "fastcgi http_parse: code_n: %ui, conf: %ui",
1829                        code_n, ucscf->code.status_alive);
1830 
1831         if (code_n & ucscf->code.status_alive) {
1832             return NGX_OK;
1833         } else {
1834             return NGX_ERROR;
1835         }
1836 
1837     }
1838 
1839     return NGX_OK;
1840 }
1841 
1842 
1843 static ngx_int_t
ngx_http_upstream_check_parse_fastcgi_status(ngx_http_upstream_check_ctx_t * ctx,ngx_buf_t * b,ngx_http_status_t * status)1844 ngx_http_upstream_check_parse_fastcgi_status(ngx_http_upstream_check_ctx_t *ctx,
1845     ngx_buf_t *b, ngx_http_status_t *status)
1846 {
1847     u_char      c, ch, *p, *name_s, *name_e;
1848     ngx_flag_t  find;
1849 
1850     enum {
1851         sw_start = 0,
1852         sw_name,
1853         sw_space_before_value,
1854         sw_value,
1855         sw_space_after_value,
1856         sw_ignore_line,
1857         sw_almost_done,
1858         sw_header_almost_done
1859     } state;
1860 
1861     /* the last '\0' is not needed because string is zero terminated */
1862 
1863     static u_char  lowcase[] =
1864         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1865         "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
1866         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
1867         "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
1868         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1869         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1870         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1871         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
1872 
1873     status->count = 0;
1874     status->code = 0;
1875     find = 0;
1876     name_s = name_e = NULL;
1877     state = sw_start;
1878 
1879     for (p = b->pos; p < b->last; p++) {
1880         ch = *p;
1881 
1882         switch (state) {
1883 
1884         /* first char */
1885         case sw_start:
1886 
1887             switch (ch) {
1888             case CR:
1889                 state = sw_header_almost_done;
1890                 break;
1891             case LF:
1892                 goto header_done;
1893             default:
1894                 state = sw_name;
1895 
1896                 c = lowcase[ch];
1897 
1898                 if (c) {
1899                     name_s = p;
1900                     break;
1901                 }
1902 
1903                 if (ch == '\0') {
1904                     return NGX_ERROR;
1905                 }
1906 
1907 
1908                 break;
1909             }
1910 
1911             break;
1912 
1913         /* header name */
1914         case sw_name:
1915             c = lowcase[ch];
1916 
1917             if (c) {
1918                 break;
1919             }
1920 
1921             if (ch == ':') {
1922                 name_e = p;
1923 #if (NGX_DEBUG)
1924                 ngx_str_t name;
1925                 name.data = name_s;
1926                 name.len = name_e - name_s;
1927                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1928                                "fastcgi header: %V", &name);
1929 #endif
1930                 state = sw_space_before_value;
1931 
1932                 if (ngx_strncasecmp(name_s, (u_char *) "status",
1933                                     name_e - name_s)
1934                     == 0)
1935                 {
1936 
1937                     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
1938                                    "find status header");
1939 
1940                     find = 1;
1941                 }
1942 
1943                 break;
1944             }
1945 
1946             if (ch == CR) {
1947                 state = sw_almost_done;
1948                 break;
1949             }
1950 
1951             if (ch == LF) {
1952                 goto done;
1953             }
1954 
1955             /* IIS may send the duplicate "HTTP/1.1 ..." lines */
1956             if (ch == '\0') {
1957                 return NGX_ERROR;
1958             }
1959 
1960             break;
1961 
1962         /* space* before header value */
1963         case sw_space_before_value:
1964             switch (ch) {
1965             case ' ':
1966                 break;
1967             case CR:
1968                 state = sw_almost_done;
1969                 break;
1970             case LF:
1971                 goto done;
1972             case '\0':
1973                 return NGX_ERROR;
1974             default:
1975                 state = sw_value;
1976                 if (find) {
1977                     if (ch < '1' || ch > '9') {
1978                         return NGX_ERROR;
1979                     }
1980 
1981                     status->code = status->code * 10 + ch - '0';
1982                     if (status->count++ != 0) {
1983                         return NGX_ERROR;
1984                     }
1985                 }
1986 
1987                 break;
1988             }
1989 
1990             break;
1991 
1992         /* header value */
1993         case sw_value:
1994 
1995             if (find) {
1996                 if (ch < '0' || ch > '9') {
1997                     return NGX_ERROR;
1998                 }
1999 
2000                 status->code = status->code * 10 + ch - '0';
2001 
2002                 if (++status->count == 3) {
2003                     return NGX_DONE;
2004                 }
2005             }
2006 
2007             switch (ch) {
2008             case ' ':
2009                 state = sw_space_after_value;
2010                 break;
2011             case CR:
2012                 state = sw_almost_done;
2013                 break;
2014             case LF:
2015                 goto done;
2016             case '\0':
2017                 return NGX_ERROR;
2018             }
2019 
2020             break;
2021 
2022         /* space* before end of header line */
2023         case sw_space_after_value:
2024             switch (ch) {
2025             case ' ':
2026                 break;
2027             case CR:
2028                 state = sw_almost_done;
2029                 break;
2030             case LF:
2031                 state = sw_start;
2032                 break;
2033             case '\0':
2034                 return NGX_ERROR;
2035             default:
2036                 state = sw_value;
2037                 break;
2038             }
2039             break;
2040 
2041         /* ignore header line */
2042         case sw_ignore_line:
2043             switch (ch) {
2044             case LF:
2045                 state = sw_start;
2046                 break;
2047             default:
2048                 break;
2049             }
2050             break;
2051 
2052         /* end of header line */
2053         case sw_almost_done:
2054             switch (ch) {
2055             case LF:
2056                 goto done;
2057             case CR:
2058                 break;
2059             default:
2060                 return NGX_ERROR;
2061             }
2062             break;
2063 
2064         /* end of header */
2065         case sw_header_almost_done:
2066             switch (ch) {
2067             case LF:
2068                 goto header_done;
2069             default:
2070                 return NGX_ERROR;
2071             }
2072         }
2073     }
2074 
2075     b->pos = p;
2076     ctx->state = state;
2077 
2078     return NGX_AGAIN;
2079 
2080 done:
2081 
2082     b->pos = p + 1;
2083     ctx->state = sw_start;
2084 
2085     return NGX_OK;
2086 
2087 header_done:
2088 
2089     b->pos = p + 1;
2090     ctx->state = sw_start;
2091 
2092     return NGX_OK;
2093 }
2094 
2095 
2096 static ngx_int_t
ngx_http_upstream_check_parse_status_line(ngx_http_upstream_check_ctx_t * ctx,ngx_buf_t * b,ngx_http_status_t * status)2097 ngx_http_upstream_check_parse_status_line(ngx_http_upstream_check_ctx_t *ctx,
2098     ngx_buf_t *b, ngx_http_status_t *status)
2099 {
2100     u_char ch, *p;
2101     enum {
2102         sw_start = 0,
2103         sw_H,
2104         sw_HT,
2105         sw_HTT,
2106         sw_HTTP,
2107         sw_first_major_digit,
2108         sw_major_digit,
2109         sw_first_minor_digit,
2110         sw_minor_digit,
2111         sw_status,
2112         sw_space_after_status,
2113         sw_status_text,
2114         sw_almost_done
2115     } state;
2116 
2117     state = ctx->state;
2118 
2119     for (p = b->pos; p < b->last; p++) {
2120         ch = *p;
2121 
2122         switch (state) {
2123 
2124         /* "HTTP/" */
2125         case sw_start:
2126             if (ch != 'H') {
2127                 return NGX_ERROR;
2128             }
2129 
2130             state = sw_H;
2131             break;
2132 
2133         case sw_H:
2134             if (ch != 'T') {
2135                 return NGX_ERROR;
2136             }
2137 
2138             state = sw_HT;
2139             break;
2140 
2141         case sw_HT:
2142             if (ch != 'T') {
2143                 return NGX_ERROR;
2144             }
2145 
2146             state = sw_HTT;
2147             break;
2148 
2149         case sw_HTT:
2150             if (ch != 'P') {
2151                 return NGX_ERROR;
2152             }
2153 
2154             state = sw_HTTP;
2155             break;
2156 
2157         case sw_HTTP:
2158             if (ch != '/') {
2159                 return NGX_ERROR;
2160             }
2161 
2162             state = sw_first_major_digit;
2163             break;
2164 
2165         /* the first digit of major HTTP version */
2166         case sw_first_major_digit:
2167             if (ch < '1' || ch > '9') {
2168                 return NGX_ERROR;
2169             }
2170 
2171             state = sw_major_digit;
2172             break;
2173 
2174         /* the major HTTP version or dot */
2175         case sw_major_digit:
2176             if (ch == '.') {
2177                 state = sw_first_minor_digit;
2178                 break;
2179             }
2180 
2181             if (ch < '0' || ch > '9') {
2182                 return NGX_ERROR;
2183             }
2184 
2185             break;
2186 
2187         /* the first digit of minor HTTP version */
2188         case sw_first_minor_digit:
2189             if (ch < '0' || ch > '9') {
2190                 return NGX_ERROR;
2191             }
2192 
2193             state = sw_minor_digit;
2194             break;
2195 
2196         /* the minor HTTP version or the end of the request line */
2197         case sw_minor_digit:
2198             if (ch == ' ') {
2199                 state = sw_status;
2200                 break;
2201             }
2202 
2203             if (ch < '0' || ch > '9') {
2204                 return NGX_ERROR;
2205             }
2206 
2207             break;
2208 
2209         /* HTTP status code */
2210         case sw_status:
2211             if (ch == ' ') {
2212                 break;
2213             }
2214 
2215             if (ch < '0' || ch > '9') {
2216                 return NGX_ERROR;
2217             }
2218 
2219             status->code = status->code * 10 + ch - '0';
2220 
2221             if (++status->count == 3) {
2222                 state = sw_space_after_status;
2223                 status->start = p - 2;
2224             }
2225 
2226             break;
2227 
2228         /* space or end of line */
2229         case sw_space_after_status:
2230             switch (ch) {
2231             case ' ':
2232                 state = sw_status_text;
2233                 break;
2234             case '.':                    /* IIS may send 403.1, 403.2, etc */
2235                 state = sw_status_text;
2236                 break;
2237             case CR:
2238                 state = sw_almost_done;
2239                 break;
2240             case LF:
2241                 goto done;
2242             default:
2243                 return NGX_ERROR;
2244             }
2245             break;
2246 
2247         /* any text until end of line */
2248         case sw_status_text:
2249             switch (ch) {
2250             case CR:
2251                 state = sw_almost_done;
2252 
2253                 break;
2254             case LF:
2255                 goto done;
2256             }
2257             break;
2258 
2259         /* end of status line */
2260         case sw_almost_done:
2261             status->end = p - 1;
2262             if (ch == LF) {
2263                 goto done;
2264             } else {
2265                 return NGX_ERROR;
2266             }
2267         }
2268     }
2269 
2270     b->pos = p;
2271     ctx->state = state;
2272 
2273     return NGX_AGAIN;
2274 
2275 done:
2276 
2277     b->pos = p + 1;
2278 
2279     if (status->end == NULL) {
2280         status->end = p;
2281     }
2282 
2283     ctx->state = sw_start;
2284 
2285     return NGX_OK;
2286 }
2287 
2288 
2289 static void
ngx_http_upstream_check_http_reinit(ngx_http_upstream_check_peer_t * peer)2290 ngx_http_upstream_check_http_reinit(ngx_http_upstream_check_peer_t *peer)
2291 {
2292     ngx_http_upstream_check_ctx_t  *ctx;
2293 
2294     ctx = peer->check_data;
2295 
2296     ctx->send.pos = ctx->send.start;
2297     ctx->send.last = ctx->send.end;
2298 
2299     ctx->recv.pos = ctx->recv.last = ctx->recv.start;
2300 
2301     ctx->state = 0;
2302 
2303     ngx_memzero(&ctx->status, sizeof(ngx_http_status_t));
2304 }
2305 
2306 
2307 static ngx_int_t
ngx_http_upstream_check_ssl_hello_init(ngx_http_upstream_check_peer_t * peer)2308 ngx_http_upstream_check_ssl_hello_init(ngx_http_upstream_check_peer_t *peer)
2309 {
2310     ngx_http_upstream_check_ctx_t       *ctx;
2311     ngx_http_upstream_check_srv_conf_t  *ucscf;
2312 
2313     ctx = peer->check_data;
2314     ucscf = peer->conf;
2315 
2316     ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data;
2317     ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len;
2318 
2319     ctx->recv.start = ctx->recv.pos = NULL;
2320     ctx->recv.end = ctx->recv.last = NULL;
2321 
2322     return NGX_OK;
2323 }
2324 
2325 
2326 /* a rough check of server ssl_hello responses */
2327 static ngx_int_t
ngx_http_upstream_check_ssl_hello_parse(ngx_http_upstream_check_peer_t * peer)2328 ngx_http_upstream_check_ssl_hello_parse(ngx_http_upstream_check_peer_t *peer)
2329 {
2330     size_t                         size;
2331     ngx_ssl_server_hello_t        *resp;
2332     ngx_http_upstream_check_ctx_t *ctx;
2333 
2334     ctx = peer->check_data;
2335 
2336     size = ctx->recv.last - ctx->recv.pos;
2337     if (size < sizeof(ngx_ssl_server_hello_t)) {
2338         return NGX_AGAIN;
2339     }
2340 
2341     resp = (ngx_ssl_server_hello_t *) ctx->recv.pos;
2342 
2343     ngx_log_debug7(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
2344                    "http check ssl_parse, type: %ud, version: %ud.%ud, "
2345                    "length: %ud, handshanke_type: %ud, hello_version: %ud.%ud",
2346                    resp->msg_type, resp->version.major, resp->version.minor,
2347                    ntohs(resp->length), resp->handshake_type,
2348                    resp->hello_version.major, resp->hello_version.minor);
2349 
2350     if (resp->msg_type != NGX_SSL_HANDSHAKE) {
2351         return NGX_ERROR;
2352     }
2353 
2354     if (resp->handshake_type != NGX_SSL_SERVER_HELLO) {
2355         return NGX_ERROR;
2356     }
2357 
2358     return NGX_OK;
2359 }
2360 
2361 
2362 static void
ngx_http_upstream_check_ssl_hello_reinit(ngx_http_upstream_check_peer_t * peer)2363 ngx_http_upstream_check_ssl_hello_reinit(ngx_http_upstream_check_peer_t *peer)
2364 {
2365     ngx_http_upstream_check_ctx_t *ctx;
2366 
2367     ctx = peer->check_data;
2368 
2369     ctx->send.pos = ctx->send.start;
2370     ctx->send.last = ctx->send.end;
2371 
2372     ctx->recv.pos = ctx->recv.last = ctx->recv.start;
2373 }
2374 
2375 
2376 static ngx_int_t
ngx_http_upstream_check_mysql_init(ngx_http_upstream_check_peer_t * peer)2377 ngx_http_upstream_check_mysql_init(ngx_http_upstream_check_peer_t *peer)
2378 {
2379     ngx_http_upstream_check_ctx_t       *ctx;
2380     ngx_http_upstream_check_srv_conf_t  *ucscf;
2381 
2382     ctx = peer->check_data;
2383     ucscf = peer->conf;
2384 
2385     ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data;
2386     ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len;
2387 
2388     ctx->recv.start = ctx->recv.pos = NULL;
2389     ctx->recv.end = ctx->recv.last = NULL;
2390 
2391     return NGX_OK;
2392 }
2393 
2394 
2395 /* a rough check of mysql greeting responses */
2396 static ngx_int_t
ngx_http_upstream_check_mysql_parse(ngx_http_upstream_check_peer_t * peer)2397 ngx_http_upstream_check_mysql_parse(ngx_http_upstream_check_peer_t *peer)
2398 {
2399     size_t                         size;
2400     ngx_mysql_handshake_init_t    *handshake;
2401     ngx_http_upstream_check_ctx_t *ctx;
2402 
2403     ctx = peer->check_data;
2404 
2405     size = ctx->recv.last - ctx->recv.pos;
2406     if (size < sizeof(ngx_mysql_handshake_init_t)) {
2407         return NGX_AGAIN;
2408     }
2409 
2410     handshake = (ngx_mysql_handshake_init_t *) ctx->recv.pos;
2411 
2412     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
2413                    "mysql_parse: packet_number=%ud, protocol=%ud, server=%s",
2414                    handshake->packet_number, handshake->protocol_version,
2415                    handshake->others);
2416 
2417     /* The mysql greeting packet's serial number always begins with 0. */
2418     if (handshake->packet_number != 0x00) {
2419         return NGX_ERROR;
2420     }
2421 
2422     return NGX_OK;
2423 }
2424 
2425 
2426 static void
ngx_http_upstream_check_mysql_reinit(ngx_http_upstream_check_peer_t * peer)2427 ngx_http_upstream_check_mysql_reinit(ngx_http_upstream_check_peer_t *peer)
2428 {
2429     ngx_http_upstream_check_ctx_t *ctx;
2430 
2431     ctx = peer->check_data;
2432 
2433     ctx->send.pos = ctx->send.start;
2434     ctx->send.last = ctx->send.end;
2435 
2436     ctx->recv.pos = ctx->recv.last = ctx->recv.start;
2437 }
2438 
2439 
2440 static ngx_int_t
ngx_http_upstream_check_ajp_init(ngx_http_upstream_check_peer_t * peer)2441 ngx_http_upstream_check_ajp_init(ngx_http_upstream_check_peer_t *peer)
2442 {
2443     ngx_http_upstream_check_ctx_t       *ctx;
2444     ngx_http_upstream_check_srv_conf_t  *ucscf;
2445 
2446     ctx = peer->check_data;
2447     ucscf = peer->conf;
2448 
2449     ctx->send.start = ctx->send.pos = (u_char *)ucscf->send.data;
2450     ctx->send.end = ctx->send.last = ctx->send.start + ucscf->send.len;
2451 
2452     ctx->recv.start = ctx->recv.pos = NULL;
2453     ctx->recv.end = ctx->recv.last = NULL;
2454 
2455     return NGX_OK;
2456 }
2457 
2458 
2459 static ngx_int_t
ngx_http_upstream_check_ajp_parse(ngx_http_upstream_check_peer_t * peer)2460 ngx_http_upstream_check_ajp_parse(ngx_http_upstream_check_peer_t *peer)
2461 {
2462     size_t                         size;
2463     u_char                        *p;
2464     ngx_http_upstream_check_ctx_t *ctx;
2465 
2466     ctx = peer->check_data;
2467 
2468     size = ctx->recv.last - ctx->recv.pos;
2469     if (size < sizeof(ngx_ajp_cpong_packet)) {
2470         return NGX_AGAIN;
2471     }
2472 
2473     p = ctx->recv.pos;
2474 
2475 #if (NGX_DEBUG)
2476     {
2477     ngx_ajp_raw_packet_t  *ajp;
2478 
2479     ajp = (ngx_ajp_raw_packet_t *) p;
2480     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
2481                    "ajp_parse: preamble=0x%uxd, length=0x%uxd, type=0x%uxd",
2482                    ntohs(ajp->preamble), ntohs(ajp->length), ajp->type);
2483     }
2484 #endif
2485 
2486     if (ngx_memcmp(ngx_ajp_cpong_packet, p, sizeof(ngx_ajp_cpong_packet)) == 0)
2487     {
2488         return NGX_OK;
2489     } else {
2490         return NGX_ERROR;
2491     }
2492 }
2493 
2494 
2495 static void
ngx_http_upstream_check_ajp_reinit(ngx_http_upstream_check_peer_t * peer)2496 ngx_http_upstream_check_ajp_reinit(ngx_http_upstream_check_peer_t *peer)
2497 {
2498     ngx_http_upstream_check_ctx_t  *ctx;
2499 
2500     ctx = peer->check_data;
2501 
2502     ctx->send.pos = ctx->send.start;
2503     ctx->send.last = ctx->send.end;
2504 
2505     ctx->recv.pos = ctx->recv.last = ctx->recv.start;
2506 }
2507 
2508 
2509 static void
ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t * peer,ngx_int_t result)2510 ngx_http_upstream_check_status_update(ngx_http_upstream_check_peer_t *peer,
2511     ngx_int_t result)
2512 {
2513     ngx_http_upstream_check_srv_conf_t  *ucscf;
2514 
2515     ucscf = peer->conf;
2516 
2517     if (result) {
2518         peer->shm->rise_count++;
2519         peer->shm->fall_count = 0;
2520         if (peer->shm->down && peer->shm->rise_count >= ucscf->rise_count) {
2521             peer->shm->down = 0;
2522             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
2523                           "enable check peer: %V ",
2524                           &peer->check_peer_addr->name);
2525         }
2526     } else {
2527         peer->shm->rise_count = 0;
2528         peer->shm->fall_count++;
2529         if (!peer->shm->down && peer->shm->fall_count >= ucscf->fall_count) {
2530             peer->shm->down = 1;
2531             ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
2532                           "disable check peer: %V ",
2533                           &peer->check_peer_addr->name);
2534         }
2535     }
2536 
2537     peer->shm->access_time = ngx_current_msec;
2538 }
2539 
2540 
2541 static void
ngx_http_upstream_check_clean_event(ngx_http_upstream_check_peer_t * peer)2542 ngx_http_upstream_check_clean_event(ngx_http_upstream_check_peer_t *peer)
2543 {
2544     ngx_connection_t                    *c;
2545     ngx_http_upstream_check_srv_conf_t  *ucscf;
2546     ngx_check_conf_t                    *cf;
2547 
2548     c = peer->pc.connection;
2549     ucscf = peer->conf;
2550     cf = ucscf->check_type_conf;
2551 
2552     if (c) {
2553         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
2554                        "http check clean event: index:%i, fd: %d",
2555                        peer->index, c->fd);
2556         if (c->error == 0 &&
2557             cf->need_keepalive &&
2558             (c->requests < ucscf->check_keepalive_requests))
2559         {
2560             c->write->handler = ngx_http_upstream_check_dummy_handler;
2561             c->read->handler = ngx_http_upstream_check_discard_handler;
2562         } else {
2563             ngx_close_connection(c);
2564             peer->pc.connection = NULL;
2565         }
2566     }
2567 
2568     if (peer->check_timeout_ev.timer_set) {
2569         ngx_del_timer(&peer->check_timeout_ev);
2570     }
2571 
2572     peer->state = NGX_HTTP_CHECK_ALL_DONE;
2573 
2574     if (peer->check_data != NULL && peer->reinit) {
2575         peer->reinit(peer);
2576     }
2577 
2578     peer->shm->owner = NGX_INVALID_PID;
2579 }
2580 
2581 
2582 static void
ngx_http_upstream_check_timeout_handler(ngx_event_t * event)2583 ngx_http_upstream_check_timeout_handler(ngx_event_t *event)
2584 {
2585     ngx_http_upstream_check_peer_t  *peer;
2586 
2587     if (ngx_http_upstream_check_need_exit()) {
2588         return;
2589     }
2590 
2591     peer = event->data;
2592     peer->pc.connection->error = 1;
2593 
2594     ngx_log_error(NGX_LOG_ERR, event->log, 0,
2595                   "check time out with peer: %V ",
2596                   &peer->check_peer_addr->name);
2597 
2598     ngx_http_upstream_check_status_update(peer, 0);
2599     ngx_http_upstream_check_clean_event(peer);
2600 }
2601 
2602 
2603 static void
ngx_http_upstream_check_finish_handler(ngx_event_t * event)2604 ngx_http_upstream_check_finish_handler(ngx_event_t *event)
2605 {
2606     if (ngx_http_upstream_check_need_exit()) {
2607         return;
2608     }
2609 }
2610 
2611 
2612 static ngx_int_t
ngx_http_upstream_check_need_exit()2613 ngx_http_upstream_check_need_exit()
2614 {
2615     if (ngx_terminate || ngx_exiting || ngx_quit) {
2616         ngx_http_upstream_check_clear_all_events();
2617         return 1;
2618     }
2619 
2620     return 0;
2621 }
2622 
2623 
2624 static void
ngx_http_upstream_check_clear_all_events()2625 ngx_http_upstream_check_clear_all_events()
2626 {
2627     ngx_uint_t                       i;
2628     ngx_connection_t                *c;
2629     ngx_http_upstream_check_peer_t  *peer;
2630     ngx_http_upstream_check_peers_t *peers;
2631 
2632     static ngx_flag_t                has_cleared = 0;
2633 
2634     if (has_cleared || check_peers_ctx == NULL) {
2635         return;
2636     }
2637 
2638     ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
2639                   "clear all the events on %P ", ngx_pid);
2640 
2641     has_cleared = 1;
2642 
2643     peers = check_peers_ctx;
2644 
2645     peer = peers->peers.elts;
2646     for (i = 0; i < peers->peers.nelts; i++) {
2647 
2648         if (peer[i].check_ev.timer_set) {
2649             ngx_del_timer(&peer[i].check_ev);
2650         }
2651 
2652         if (peer[i].check_timeout_ev.timer_set) {
2653             ngx_del_timer(&peer[i].check_timeout_ev);
2654         }
2655 
2656         c = peer[i].pc.connection;
2657         if (c) {
2658             ngx_close_connection(c);
2659             peer[i].pc.connection = NULL;
2660         }
2661 
2662         if (peer[i].pool != NULL) {
2663             ngx_destroy_pool(peer[i].pool);
2664             peer[i].pool = NULL;
2665         }
2666     }
2667 }
2668 
2669 
2670 static ngx_int_t
ngx_http_upstream_check_status_handler(ngx_http_request_t * r)2671 ngx_http_upstream_check_status_handler(ngx_http_request_t *r)
2672 {
2673     size_t                                 buffer_size;
2674     ngx_int_t                              rc;
2675     ngx_buf_t                             *b;
2676     ngx_chain_t                            out;
2677     ngx_http_upstream_check_peers_t       *peers;
2678     ngx_http_upstream_check_loc_conf_t    *uclcf;
2679     ngx_http_upstream_check_status_ctx_t  *ctx;
2680 
2681     if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
2682         return NGX_HTTP_NOT_ALLOWED;
2683     }
2684 
2685     rc = ngx_http_discard_request_body(r);
2686 
2687     if (rc != NGX_OK) {
2688         return rc;
2689     }
2690 
2691     uclcf = ngx_http_get_module_loc_conf(r, ngx_http_upstream_check_module);
2692 
2693     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_check_status_ctx_t));
2694     if (ctx == NULL) {
2695         return NGX_HTTP_INTERNAL_SERVER_ERROR;
2696     }
2697 
2698     ngx_http_upstream_check_status_parse_args(r, ctx);
2699 
2700     if (ctx->format == NULL) {
2701         ctx->format = uclcf->format;
2702     }
2703 
2704     r->headers_out.content_type = ctx->format->content_type;
2705 
2706     if (r->method == NGX_HTTP_HEAD) {
2707         r->headers_out.status = NGX_HTTP_OK;
2708 
2709         rc = ngx_http_send_header(r);
2710 
2711         if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
2712             return rc;
2713         }
2714     }
2715 
2716     peers = check_peers_ctx;
2717     if (peers == NULL) {
2718         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2719                       "http upstream check module can not find any check "
2720                       "server, make sure you've added the check servers");
2721 
2722         return NGX_HTTP_INTERNAL_SERVER_ERROR;
2723     }
2724 
2725     /* 1/4 pagesize for each record */
2726     buffer_size = peers->peers.nelts * ngx_pagesize / 4;
2727     buffer_size = ngx_align(buffer_size, ngx_pagesize) + ngx_pagesize;
2728 
2729     b = ngx_create_temp_buf(r->pool, buffer_size);
2730     if (b == NULL) {
2731         return NGX_HTTP_INTERNAL_SERVER_ERROR;
2732     }
2733 
2734     out.buf = b;
2735     out.next = NULL;
2736 
2737     ctx->format->output(b, peers, ctx->flag);
2738 
2739     r->headers_out.status = NGX_HTTP_OK;
2740     r->headers_out.content_length_n = b->last - b->pos;
2741 
2742     if (r->headers_out.content_length_n == 0) {
2743         r->header_only = 1;
2744     }
2745 
2746     b->last_buf = 1;
2747 
2748     rc = ngx_http_send_header(r);
2749 
2750     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
2751         return rc;
2752     }
2753 
2754     return ngx_http_output_filter(r, &out);
2755 }
2756 
2757 
2758 static void
ngx_http_upstream_check_status_parse_args(ngx_http_request_t * r,ngx_http_upstream_check_status_ctx_t * ctx)2759 ngx_http_upstream_check_status_parse_args(ngx_http_request_t *r,
2760     ngx_http_upstream_check_status_ctx_t *ctx)
2761 {
2762     ngx_str_t                    value;
2763     ngx_uint_t                   i;
2764     ngx_check_status_command_t  *command;
2765 
2766     if (r->args.len == 0) {
2767         return;
2768     }
2769 
2770     for (i = 0; /* void */ ; i++) {
2771 
2772         command = &ngx_check_status_commands[i];
2773 
2774         if (command->name.len == 0) {
2775             break;
2776         }
2777 
2778         if (ngx_http_arg(r, command->name.data, command->name.len, &value)
2779             == NGX_OK) {
2780 
2781            if (command->handler(ctx, &value) != NGX_OK) {
2782                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2783                              "http upstream check, bad argument: \"%V\"",
2784                              &value);
2785            }
2786         }
2787     }
2788 
2789     ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0,
2790             "http upstream check, flag: \"%ui\"", ctx->flag);
2791 }
2792 
2793 
2794 static ngx_int_t
ngx_http_upstream_check_status_command_format(ngx_http_upstream_check_status_ctx_t * ctx,ngx_str_t * value)2795 ngx_http_upstream_check_status_command_format(
2796     ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value)
2797 {
2798     ctx->format = ngx_http_get_check_status_format_conf(value);
2799     if (ctx->format == NULL) {
2800         return NGX_ERROR;
2801     }
2802 
2803     return NGX_OK;
2804 }
2805 
2806 
2807 static ngx_int_t
ngx_http_upstream_check_status_command_status(ngx_http_upstream_check_status_ctx_t * ctx,ngx_str_t * value)2808 ngx_http_upstream_check_status_command_status(
2809     ngx_http_upstream_check_status_ctx_t *ctx, ngx_str_t *value)
2810 {
2811     if (value->len == (sizeof("down") - 1)
2812         && ngx_strncasecmp(value->data, (u_char *) "down", value->len) == 0) {
2813 
2814         ctx->flag |= NGX_CHECK_STATUS_DOWN;
2815 
2816     } else if (value->len == (sizeof("up") - 1)
2817                && ngx_strncasecmp(value->data, (u_char *) "up", value->len)
2818                == 0) {
2819 
2820         ctx->flag |= NGX_CHECK_STATUS_UP;
2821 
2822     } else {
2823         return NGX_ERROR;
2824     }
2825 
2826     return NGX_OK;
2827 }
2828 
2829 
2830 static void
ngx_http_upstream_check_status_html_format(ngx_buf_t * b,ngx_http_upstream_check_peers_t * peers,ngx_uint_t flag)2831 ngx_http_upstream_check_status_html_format(ngx_buf_t *b,
2832     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag)
2833 {
2834     ngx_uint_t                      i, count;
2835     ngx_http_upstream_check_peer_t *peer;
2836 
2837     peer = peers->peers.elts;
2838 
2839     count = 0;
2840 
2841     for (i = 0; i < peers->peers.nelts; i++) {
2842 
2843         if (flag & NGX_CHECK_STATUS_DOWN) {
2844 
2845             if (!peer[i].shm->down) {
2846                 continue;
2847             }
2848 
2849         } else if (flag & NGX_CHECK_STATUS_UP) {
2850 
2851             if (peer[i].shm->down) {
2852                 continue;
2853             }
2854         }
2855 
2856         count++;
2857     }
2858 
2859     b->last = ngx_snprintf(b->last, b->end - b->last,
2860             "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\n"
2861             "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
2862             "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
2863             "<head>\n"
2864             "  <title>Nginx http upstream check status</title>\n"
2865             "</head>\n"
2866             "<body>\n"
2867             "<h1>Nginx http upstream check status</h1>\n"
2868             "<h2>Check upstream server number: %ui, generation: %ui</h2>\n"
2869             "<table style=\"background-color:white\" cellspacing=\"0\" "
2870             "       cellpadding=\"3\" border=\"1\">\n"
2871             "  <tr bgcolor=\"#C0C0C0\">\n"
2872             "    <th>Index</th>\n"
2873             "    <th>Upstream</th>\n"
2874             "    <th>Name</th>\n"
2875             "    <th>Status</th>\n"
2876             "    <th>Rise counts</th>\n"
2877             "    <th>Fall counts</th>\n"
2878             "    <th>Check type</th>\n"
2879             "    <th>Check port</th>\n"
2880             "  </tr>\n",
2881             count, ngx_http_upstream_check_shm_generation);
2882 
2883     for (i = 0; i < peers->peers.nelts; i++) {
2884 
2885         if (flag & NGX_CHECK_STATUS_DOWN) {
2886 
2887             if (!peer[i].shm->down) {
2888                 continue;
2889             }
2890 
2891         } else if (flag & NGX_CHECK_STATUS_UP) {
2892 
2893             if (peer[i].shm->down) {
2894                 continue;
2895             }
2896         }
2897 
2898         b->last = ngx_snprintf(b->last, b->end - b->last,
2899                 "  <tr%s>\n"
2900                 "    <td>%ui</td>\n"
2901                 "    <td>%V</td>\n"
2902                 "    <td>%V</td>\n"
2903                 "    <td>%s</td>\n"
2904                 "    <td>%ui</td>\n"
2905                 "    <td>%ui</td>\n"
2906                 "    <td>%V</td>\n"
2907                 "    <td>%ui</td>\n"
2908                 "  </tr>\n",
2909                 peer[i].shm->down ? " bgcolor=\"#FF0000\"" : "",
2910                 i,
2911                 peer[i].upstream_name,
2912                 &peer[i].peer_addr->name,
2913                 peer[i].shm->down ? "down" : "up",
2914                 peer[i].shm->rise_count,
2915                 peer[i].shm->fall_count,
2916                 &peer[i].conf->check_type_conf->name,
2917                 peer[i].conf->port);
2918     }
2919 
2920     b->last = ngx_snprintf(b->last, b->end - b->last,
2921             "</table>\n"
2922             "</body>\n"
2923             "</html>\n");
2924 }
2925 
2926 
2927 static void
ngx_http_upstream_check_status_csv_format(ngx_buf_t * b,ngx_http_upstream_check_peers_t * peers,ngx_uint_t flag)2928 ngx_http_upstream_check_status_csv_format(ngx_buf_t *b,
2929     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag)
2930 {
2931     ngx_uint_t                       i;
2932     ngx_http_upstream_check_peer_t  *peer;
2933 
2934     peer = peers->peers.elts;
2935     for (i = 0; i < peers->peers.nelts; i++) {
2936 
2937         if (flag & NGX_CHECK_STATUS_DOWN) {
2938 
2939             if (!peer[i].shm->down) {
2940                 continue;
2941             }
2942 
2943         } else if (flag & NGX_CHECK_STATUS_UP) {
2944 
2945             if (peer[i].shm->down) {
2946                 continue;
2947             }
2948         }
2949 
2950         b->last = ngx_snprintf(b->last, b->end - b->last,
2951                 "%ui,%V,%V,%s,%ui,%ui,%V,%ui\n",
2952                 i,
2953                 peer[i].upstream_name,
2954                 &peer[i].peer_addr->name,
2955                 peer[i].shm->down ? "down" : "up",
2956                 peer[i].shm->rise_count,
2957                 peer[i].shm->fall_count,
2958                 &peer[i].conf->check_type_conf->name,
2959                 peer[i].conf->port);
2960     }
2961 }
2962 
2963 
2964 static void
ngx_http_upstream_check_status_json_format(ngx_buf_t * b,ngx_http_upstream_check_peers_t * peers,ngx_uint_t flag)2965 ngx_http_upstream_check_status_json_format(ngx_buf_t *b,
2966     ngx_http_upstream_check_peers_t *peers, ngx_uint_t flag)
2967 {
2968     ngx_uint_t                       count, i, last;
2969     ngx_http_upstream_check_peer_t  *peer;
2970 
2971     peer = peers->peers.elts;
2972 
2973     count = 0;
2974 
2975     for (i = 0; i < peers->peers.nelts; i++) {
2976 
2977         if (flag & NGX_CHECK_STATUS_DOWN) {
2978 
2979             if (!peer[i].shm->down) {
2980                 continue;
2981             }
2982 
2983         } else if (flag & NGX_CHECK_STATUS_UP) {
2984 
2985             if (peer[i].shm->down) {
2986                 continue;
2987             }
2988         }
2989 
2990         count++;
2991     }
2992 
2993     b->last = ngx_snprintf(b->last, b->end - b->last,
2994             "{\"servers\": {\n"
2995             "  \"total\": %ui,\n"
2996             "  \"generation\": %ui,\n"
2997             "  \"server\": [\n",
2998             count,
2999             ngx_http_upstream_check_shm_generation);
3000 
3001     last = peers->peers.nelts - 1;
3002     for (i = 0; i < peers->peers.nelts; i++) {
3003 
3004         if (flag & NGX_CHECK_STATUS_DOWN) {
3005 
3006             if (!peer[i].shm->down) {
3007                 continue;
3008             }
3009 
3010         } else if (flag & NGX_CHECK_STATUS_UP) {
3011 
3012             if (peer[i].shm->down) {
3013                 continue;
3014             }
3015         }
3016 
3017         b->last = ngx_snprintf(b->last, b->end - b->last,
3018                 "    {\"index\": %ui, "
3019                 "\"upstream\": \"%V\", "
3020                 "\"name\": \"%V\", "
3021                 "\"status\": \"%s\", "
3022                 "\"rise\": %ui, "
3023                 "\"fall\": %ui, "
3024                 "\"type\": \"%V\", "
3025                 "\"port\": %ui}"
3026                 "%s\n",
3027                 i,
3028                 peer[i].upstream_name,
3029                 &peer[i].peer_addr->name,
3030                 peer[i].shm->down ? "down" : "up",
3031                 peer[i].shm->rise_count,
3032                 peer[i].shm->fall_count,
3033                 &peer[i].conf->check_type_conf->name,
3034                 peer[i].conf->port,
3035                 (i == last) ? "" : ",");
3036     }
3037 
3038     b->last = ngx_snprintf(b->last, b->end - b->last,
3039             "  ]\n");
3040 
3041     b->last = ngx_snprintf(b->last, b->end - b->last,
3042             "}}\n");
3043 }
3044 
3045 
3046 static ngx_check_conf_t *
ngx_http_get_check_type_conf(ngx_str_t * str)3047 ngx_http_get_check_type_conf(ngx_str_t *str)
3048 {
3049     ngx_uint_t  i;
3050 
3051     for (i = 0; /* void */ ; i++) {
3052 
3053         if (ngx_check_types[i].type == 0) {
3054             break;
3055         }
3056 
3057         if (str->len != ngx_check_types[i].name.len) {
3058             continue;
3059         }
3060 
3061         if (ngx_strncmp(str->data, ngx_check_types[i].name.data,
3062                         str->len) == 0)
3063         {
3064             return &ngx_check_types[i];
3065         }
3066     }
3067 
3068     return NULL;
3069 }
3070 
3071 
3072 static char *
ngx_http_upstream_check(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3073 ngx_http_upstream_check(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3074 {
3075     ngx_str_t                           *value, s;
3076     ngx_uint_t                           i, port, rise, fall, default_down;
3077     ngx_msec_t                           interval, timeout;
3078     ngx_http_upstream_check_srv_conf_t  *ucscf;
3079 
3080     /* default values */
3081     port = 0;
3082     rise = 2;
3083     fall = 5;
3084     interval = 30000;
3085     timeout = 1000;
3086     default_down = 1;
3087 
3088     value = cf->args->elts;
3089 
3090     ucscf = ngx_http_conf_get_module_srv_conf(cf,
3091                                               ngx_http_upstream_check_module);
3092     if (ucscf == NULL) {
3093         return NGX_CONF_ERROR;
3094     }
3095 
3096     for (i = 1; i < cf->args->nelts; i++) {
3097 
3098         if (ngx_strncmp(value[i].data, "type=", 5) == 0) {
3099             s.len = value[i].len - 5;
3100             s.data = value[i].data + 5;
3101 
3102             ucscf->check_type_conf = ngx_http_get_check_type_conf(&s);
3103 
3104             if (ucscf->check_type_conf == NULL) {
3105                 goto invalid_check_parameter;
3106             }
3107 
3108             continue;
3109         }
3110 
3111         if (ngx_strncmp(value[i].data, "port=", 5) == 0) {
3112             s.len = value[i].len - 5;
3113             s.data = value[i].data + 5;
3114 
3115             port = ngx_atoi(s.data, s.len);
3116             if (port == (ngx_uint_t) NGX_ERROR || port == 0) {
3117                 goto invalid_check_parameter;
3118             }
3119 
3120             continue;
3121         }
3122 
3123         if (ngx_strncmp(value[i].data, "interval=", 9) == 0) {
3124             s.len = value[i].len - 9;
3125             s.data = value[i].data + 9;
3126 
3127             interval = ngx_atoi(s.data, s.len);
3128             if (interval == (ngx_msec_t) NGX_ERROR || interval == 0) {
3129                 goto invalid_check_parameter;
3130             }
3131 
3132             continue;
3133         }
3134 
3135         if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) {
3136             s.len = value[i].len - 8;
3137             s.data = value[i].data + 8;
3138 
3139             timeout = ngx_atoi(s.data, s.len);
3140             if (timeout == (ngx_msec_t) NGX_ERROR || timeout == 0) {
3141                 goto invalid_check_parameter;
3142             }
3143 
3144             continue;
3145         }
3146 
3147         if (ngx_strncmp(value[i].data, "rise=", 5) == 0) {
3148             s.len = value[i].len - 5;
3149             s.data = value[i].data + 5;
3150 
3151             rise = ngx_atoi(s.data, s.len);
3152             if (rise == (ngx_uint_t) NGX_ERROR || rise == 0) {
3153                 goto invalid_check_parameter;
3154             }
3155 
3156             continue;
3157         }
3158 
3159         if (ngx_strncmp(value[i].data, "fall=", 5) == 0) {
3160             s.len = value[i].len - 5;
3161             s.data = value[i].data + 5;
3162 
3163             fall = ngx_atoi(s.data, s.len);
3164             if (fall == (ngx_uint_t) NGX_ERROR || fall == 0) {
3165                 goto invalid_check_parameter;
3166             }
3167 
3168             continue;
3169         }
3170 
3171         if (ngx_strncmp(value[i].data, "default_down=", 13) == 0) {
3172             s.len = value[i].len - 13;
3173             s.data = value[i].data + 13;
3174 
3175             if (ngx_strcasecmp(s.data, (u_char *) "true") == 0) {
3176                 default_down = 1;
3177             } else if (ngx_strcasecmp(s.data, (u_char *) "false") == 0) {
3178                 default_down = 0;
3179             } else {
3180                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3181                                    "invalid value \"%s\", "
3182                                    "it must be \"true\" or \"false\"",
3183                                    value[i].data);
3184                 return NGX_CONF_ERROR;
3185             }
3186 
3187             continue;
3188         }
3189 
3190         goto invalid_check_parameter;
3191     }
3192 
3193     ucscf->port = port;
3194     ucscf->check_interval = interval;
3195     ucscf->check_timeout = timeout;
3196     ucscf->fall_count = fall;
3197     ucscf->rise_count = rise;
3198     ucscf->default_down = default_down;
3199 
3200     if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) {
3201         ngx_str_set(&s, "tcp");
3202         ucscf->check_type_conf = ngx_http_get_check_type_conf(&s);
3203     }
3204 
3205     return NGX_CONF_OK;
3206 
3207 invalid_check_parameter:
3208 
3209     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3210                        "invalid parameter \"%V\"", &value[i]);
3211 
3212     return NGX_CONF_ERROR;
3213 }
3214 
3215 
3216 static char *
ngx_http_upstream_check_keepalive_requests(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3217 ngx_http_upstream_check_keepalive_requests(ngx_conf_t *cf, ngx_command_t *cmd,
3218     void *conf)
3219 {
3220     ngx_str_t                           *value;
3221     ngx_http_upstream_check_srv_conf_t  *ucscf;
3222     ngx_uint_t                           requests;
3223 
3224     value = cf->args->elts;
3225 
3226     ucscf = ngx_http_conf_get_module_srv_conf(cf,
3227                                               ngx_http_upstream_check_module);
3228 
3229     requests = ngx_atoi(value[1].data, value[1].len);
3230     if (requests == (ngx_uint_t) NGX_ERROR || requests == 0) {
3231         return "invalid value";
3232     }
3233 
3234     ucscf->check_keepalive_requests = requests;
3235 
3236     return NGX_CONF_OK;
3237 }
3238 
3239 
3240 static char *
ngx_http_upstream_check_http_send(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3241 ngx_http_upstream_check_http_send(ngx_conf_t *cf, ngx_command_t *cmd,
3242     void *conf)
3243 {
3244     ngx_str_t                           *value;
3245     ngx_http_upstream_check_srv_conf_t  *ucscf;
3246 
3247     value = cf->args->elts;
3248 
3249     ucscf = ngx_http_conf_get_module_srv_conf(cf,
3250                                               ngx_http_upstream_check_module);
3251 
3252     ucscf->send = value[1];
3253 
3254     return NGX_CONF_OK;
3255 }
3256 
3257 
3258 static char *
ngx_http_upstream_check_fastcgi_params(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3259 ngx_http_upstream_check_fastcgi_params(ngx_conf_t *cf, ngx_command_t *cmd,
3260     void *conf)
3261 {
3262     ngx_str_t                           *value, *k, *v;
3263     ngx_http_upstream_check_srv_conf_t  *ucscf;
3264 
3265     value = cf->args->elts;
3266 
3267     ucscf = ngx_http_conf_get_module_srv_conf(cf,
3268                                               ngx_http_upstream_check_module);
3269 
3270     k = ngx_array_push(ucscf->fastcgi_params);
3271     if (k == NULL) {
3272         return NGX_CONF_ERROR;
3273     }
3274 
3275     v = ngx_array_push(ucscf->fastcgi_params);
3276     if (v == NULL) {
3277         return NGX_CONF_ERROR;
3278     }
3279 
3280     *k = value[1];
3281     *v = value[2];
3282 
3283     return NGX_CONF_OK;
3284 }
3285 
3286 
3287 static char *
ngx_http_upstream_check_http_expect_alive(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3288 ngx_http_upstream_check_http_expect_alive(ngx_conf_t *cf, ngx_command_t *cmd,
3289     void *conf)
3290 {
3291     ngx_str_t                           *value;
3292     ngx_uint_t                           bit, i, m;
3293     ngx_conf_bitmask_t                  *mask;
3294     ngx_http_upstream_check_srv_conf_t  *ucscf;
3295 
3296     value = cf->args->elts;
3297     mask = ngx_check_http_expect_alive_masks;
3298 
3299     ucscf = ngx_http_conf_get_module_srv_conf(cf,
3300                                               ngx_http_upstream_check_module);
3301     bit = ucscf->code.status_alive;
3302 
3303     for (i = 1; i < cf->args->nelts; i++) {
3304         for (m = 0; mask[m].name.len != 0; m++) {
3305 
3306             if (mask[m].name.len != value[i].len
3307                 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
3308             {
3309                 continue;
3310             }
3311 
3312             if (bit & mask[m].mask) {
3313                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3314                                    "duplicate value \"%s\"", value[i].data);
3315 
3316             } else {
3317                 bit |= mask[m].mask;
3318             }
3319 
3320             break;
3321         }
3322 
3323         if (mask[m].name.len == 0) {
3324             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3325                                "invalid value \"%s\"", value[i].data);
3326 
3327             return NGX_CONF_ERROR;
3328         }
3329     }
3330 
3331     ucscf->code.status_alive = bit;
3332 
3333     return NGX_CONF_OK;
3334 }
3335 
3336 
3337 static char *
ngx_http_upstream_check_shm_size(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3338 ngx_http_upstream_check_shm_size(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3339 {
3340     ngx_str_t                            *value;
3341     ngx_http_upstream_check_main_conf_t  *ucmcf;
3342 
3343     ucmcf = ngx_http_conf_get_module_main_conf(cf,
3344                                                ngx_http_upstream_check_module);
3345     if (ucmcf->check_shm_size) {
3346         return "is duplicate";
3347     }
3348 
3349     value = cf->args->elts;
3350 
3351     ucmcf->check_shm_size = ngx_parse_size(&value[1]);
3352     if (ucmcf->check_shm_size == (size_t) NGX_ERROR) {
3353         return "invalid value";
3354     }
3355 
3356     return NGX_CONF_OK;
3357 }
3358 
3359 
3360 static ngx_check_status_conf_t *
ngx_http_get_check_status_format_conf(ngx_str_t * str)3361 ngx_http_get_check_status_format_conf(ngx_str_t *str)
3362 {
3363     ngx_uint_t  i;
3364 
3365     for (i = 0; /* void */ ; i++) {
3366 
3367         if (ngx_check_status_formats[i].format.len == 0) {
3368             break;
3369         }
3370 
3371         if (str->len != ngx_check_status_formats[i].format.len) {
3372             continue;
3373         }
3374 
3375         if (ngx_strncmp(str->data, ngx_check_status_formats[i].format.data,
3376                         str->len) == 0)
3377         {
3378             return &ngx_check_status_formats[i];
3379         }
3380     }
3381 
3382     return NULL;
3383 }
3384 
3385 
3386 static char *
ngx_http_upstream_check_status(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3387 ngx_http_upstream_check_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3388 {
3389     ngx_str_t                           *value;
3390     ngx_http_core_loc_conf_t            *clcf;
3391     ngx_http_upstream_check_loc_conf_t  *uclcf;
3392 
3393     value = cf->args->elts;
3394 
3395     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3396 
3397     clcf->handler = ngx_http_upstream_check_status_handler;
3398 
3399     if (cf->args->nelts == 2) {
3400         uclcf = ngx_http_conf_get_module_loc_conf(cf,
3401                                               ngx_http_upstream_check_module);
3402 
3403         uclcf->format = ngx_http_get_check_status_format_conf(&value[1]);
3404         if (uclcf->format == NULL) {
3405             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3406                                "invalid check format \"%V\"", &value[1]);
3407 
3408             return NGX_CONF_ERROR;
3409         }
3410     }
3411 
3412     return NGX_CONF_OK;
3413 }
3414 
3415 
3416 static void *
ngx_http_upstream_check_create_main_conf(ngx_conf_t * cf)3417 ngx_http_upstream_check_create_main_conf(ngx_conf_t *cf)
3418 {
3419     ngx_http_upstream_check_main_conf_t  *ucmcf;
3420 
3421     ucmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_main_conf_t));
3422     if (ucmcf == NULL) {
3423         return NULL;
3424     }
3425 
3426     ucmcf->peers = ngx_pcalloc(cf->pool,
3427                                sizeof(ngx_http_upstream_check_peers_t));
3428     if (ucmcf->peers == NULL) {
3429         return NULL;
3430     }
3431 
3432     ucmcf->peers->checksum = 0;
3433 
3434     if (ngx_array_init(&ucmcf->peers->peers, cf->pool, 16,
3435                        sizeof(ngx_http_upstream_check_peer_t)) != NGX_OK)
3436     {
3437         return NULL;
3438     }
3439 
3440     return ucmcf;
3441 }
3442 
3443 
3444 static ngx_buf_t *
ngx_http_upstream_check_create_fastcgi_request(ngx_pool_t * pool,ngx_str_t * params,ngx_uint_t num)3445 ngx_http_upstream_check_create_fastcgi_request(ngx_pool_t *pool,
3446     ngx_str_t *params, ngx_uint_t num)
3447 {
3448     size_t                      size, len, padding;
3449     ngx_buf_t                  *b;
3450     ngx_str_t                  *k, *v;
3451     ngx_uint_t                  i, j;
3452     ngx_http_fastcgi_header_t  *h;
3453 
3454     len = 0;
3455     for (i = 0, j = 0; i < num; i++, j = i * 2) {
3456         k = &params[j];
3457         v = &params[j + 1];
3458 
3459         len += 1 + k->len + ((v->len > 127) ? 4 : 1) + v->len;
3460     }
3461 
3462     padding = 8 - len % 8;
3463     padding = (padding == 8) ? 0 : padding;
3464 
3465     size = sizeof(ngx_http_fastcgi_header_t)
3466         + sizeof(ngx_http_fastcgi_begin_request_t)
3467 
3468         + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
3469         + len + padding
3470         + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
3471 
3472         + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */
3473 
3474 
3475     b = ngx_create_temp_buf(pool, size);
3476     if (b == NULL) {
3477         return NULL;
3478     }
3479 
3480     ngx_http_fastcgi_request_start.br.flags = 0;
3481 
3482     ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
3483                sizeof(ngx_http_fastcgi_request_start_t));
3484 
3485     h = (ngx_http_fastcgi_header_t *)
3486         (b->pos + sizeof(ngx_http_fastcgi_header_t)
3487          + sizeof(ngx_http_fastcgi_begin_request_t));
3488 
3489     h->content_length_hi = (u_char) ((len >> 8) & 0xff);
3490     h->content_length_lo = (u_char) (len & 0xff);
3491     h->padding_length = (u_char) padding;
3492     h->reserved = 0;
3493 
3494     b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
3495         + sizeof(ngx_http_fastcgi_begin_request_t)
3496         + sizeof(ngx_http_fastcgi_header_t);
3497 
3498     for (i = 0, j = 0; i < num; i++, j = i * 2) {
3499         k = &params[j];
3500         v = &params[j + 1];
3501 
3502         if (k->len > 127) {
3503             *b->last++ = (u_char) (((k->len >> 24) & 0x7f) | 0x80);
3504             *b->last++ = (u_char) ((k->len >> 16) & 0xff);
3505             *b->last++ = (u_char) ((k->len >> 8) & 0xff);
3506             *b->last++ = (u_char) (k->len & 0xff);
3507 
3508         } else {
3509             *b->last++ = (u_char) k->len;
3510         }
3511 
3512         if (v->len > 127) {
3513             *b->last++ = (u_char) (((v->len >> 24) & 0x7f) | 0x80);
3514             *b->last++ = (u_char) ((v->len >> 16) & 0xff);
3515             *b->last++ = (u_char) ((v->len >> 8) & 0xff);
3516             *b->last++ = (u_char) (v->len & 0xff);
3517 
3518         } else {
3519             *b->last++ = (u_char) v->len;
3520         }
3521 
3522         b->last = ngx_copy(b->last, k->data, k->len);
3523         b->last = ngx_copy(b->last, v->data, v->len);
3524     }
3525 
3526     if (padding) {
3527         ngx_memzero(b->last, padding);
3528         b->last += padding;
3529     }
3530 
3531     h = (ngx_http_fastcgi_header_t *) b->last;
3532     b->last += sizeof(ngx_http_fastcgi_header_t);
3533 
3534     h->version = 1;
3535     h->type = NGX_HTTP_FASTCGI_PARAMS;
3536     h->request_id_hi = 0;
3537     h->request_id_lo = 1;
3538     h->content_length_hi = 0;
3539     h->content_length_lo = 0;
3540     h->padding_length = 0;
3541     h->reserved = 0;
3542 
3543     h = (ngx_http_fastcgi_header_t *) b->last;
3544     b->last += sizeof(ngx_http_fastcgi_header_t);
3545 
3546     return b;
3547 }
3548 
3549 
3550 static char *
ngx_http_upstream_check_init_main_conf(ngx_conf_t * cf,void * conf)3551 ngx_http_upstream_check_init_main_conf(ngx_conf_t *cf, void *conf)
3552 {
3553     ngx_buf_t                      *b;
3554     ngx_uint_t                      i;
3555     ngx_http_upstream_srv_conf_t  **uscfp;
3556     ngx_http_upstream_main_conf_t  *umcf;
3557 
3558     umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
3559 
3560     b = ngx_http_upstream_check_create_fastcgi_request(cf->pool,
3561             fastcgi_default_params,
3562             sizeof(fastcgi_default_params) / sizeof(ngx_str_t) / 2);
3563 
3564     if (b == NULL) {
3565         return NGX_CONF_ERROR;
3566     }
3567 
3568     fastcgi_default_request.data = b->pos;
3569     fastcgi_default_request.len = b->last - b->pos;
3570 
3571     uscfp = umcf->upstreams.elts;
3572 
3573     for (i = 0; i < umcf->upstreams.nelts; i++) {
3574 
3575         if (ngx_http_upstream_check_init_srv_conf(cf, uscfp[i]) != NGX_OK) {
3576             return NGX_CONF_ERROR;
3577         }
3578     }
3579 
3580     return ngx_http_upstream_check_init_shm(cf, conf);
3581 }
3582 
3583 
3584 static void *
ngx_http_upstream_check_create_srv_conf(ngx_conf_t * cf)3585 ngx_http_upstream_check_create_srv_conf(ngx_conf_t *cf)
3586 {
3587     ngx_http_upstream_check_srv_conf_t  *ucscf;
3588 
3589     ucscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_srv_conf_t));
3590     if (ucscf == NULL) {
3591         return NULL;
3592     }
3593 
3594     ucscf->fastcgi_params = ngx_array_create(cf->pool, 2 * 4, sizeof(ngx_str_t));
3595     if (ucscf->fastcgi_params == NULL) {
3596         return NULL;
3597     }
3598 
3599     ucscf->port = NGX_CONF_UNSET_UINT;
3600     ucscf->fall_count = NGX_CONF_UNSET_UINT;
3601     ucscf->rise_count = NGX_CONF_UNSET_UINT;
3602     ucscf->check_timeout = NGX_CONF_UNSET_MSEC;
3603     ucscf->check_keepalive_requests = NGX_CONF_UNSET_UINT;
3604     ucscf->check_type_conf = NGX_CONF_UNSET_PTR;
3605 
3606     return ucscf;
3607 }
3608 
3609 
3610 static void *
ngx_http_upstream_check_create_loc_conf(ngx_conf_t * cf)3611 ngx_http_upstream_check_create_loc_conf(ngx_conf_t *cf)
3612 {
3613     ngx_http_upstream_check_loc_conf_t  *uclcf;
3614 
3615     uclcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_check_loc_conf_t));
3616     if (uclcf == NULL) {
3617         return NULL;
3618     }
3619 
3620     uclcf->format = NGX_CONF_UNSET_PTR;
3621 
3622     return uclcf;
3623 }
3624 
3625 
3626 static char *
ngx_http_upstream_check_init_srv_conf(ngx_conf_t * cf,void * conf)3627 ngx_http_upstream_check_init_srv_conf(ngx_conf_t *cf, void *conf)
3628 {
3629     ngx_str_t                           s;
3630     ngx_buf_t                          *b;
3631     ngx_check_conf_t                   *check;
3632     ngx_http_upstream_srv_conf_t       *us = conf;
3633     ngx_http_upstream_check_srv_conf_t *ucscf;
3634 
3635     if (us->srv_conf == NULL) {
3636         return NGX_CONF_OK;
3637     }
3638 
3639     ucscf = ngx_http_conf_upstream_srv_conf(us, ngx_http_upstream_check_module);
3640 
3641     if (ucscf->port == NGX_CONF_UNSET_UINT) {
3642         ucscf->port = 0;
3643     }
3644 
3645     if (ucscf->fall_count == NGX_CONF_UNSET_UINT) {
3646         ucscf->fall_count = 2;
3647     }
3648 
3649     if (ucscf->rise_count == NGX_CONF_UNSET_UINT) {
3650         ucscf->rise_count = 5;
3651     }
3652 
3653     if (ucscf->check_interval == NGX_CONF_UNSET_MSEC) {
3654         ucscf->check_interval = 0;
3655     }
3656 
3657     if (ucscf->check_timeout == NGX_CONF_UNSET_MSEC) {
3658         ucscf->check_timeout = 1000;
3659     }
3660 
3661     if (ucscf->check_keepalive_requests == NGX_CONF_UNSET_UINT) {
3662         ucscf->check_keepalive_requests = 1;
3663     }
3664 
3665     if (ucscf->check_type_conf == NGX_CONF_UNSET_PTR) {
3666         ucscf->check_type_conf = NULL;
3667     }
3668 
3669     check = ucscf->check_type_conf;
3670 
3671     if (check) {
3672         if (ucscf->send.len == 0) {
3673             ngx_str_set(&s, "fastcgi");
3674 
3675             if (check == ngx_http_get_check_type_conf(&s)) {
3676 
3677                 if (ucscf->fastcgi_params->nelts == 0) {
3678                     ucscf->send.data = fastcgi_default_request.data;
3679                     ucscf->send.len = fastcgi_default_request.len;
3680 
3681                 } else {
3682                     b = ngx_http_upstream_check_create_fastcgi_request(
3683                             cf->pool, ucscf->fastcgi_params->elts,
3684                             ucscf->fastcgi_params->nelts / 2);
3685                     if (b == NULL) {
3686                         return NGX_CONF_ERROR;
3687                     }
3688 
3689                     ucscf->send.data = b->pos;
3690                     ucscf->send.len = b->last - b->pos;
3691                 }
3692             } else {
3693                 ucscf->send.data = check->default_send.data;
3694                 ucscf->send.len = check->default_send.len;
3695             }
3696         }
3697 
3698 
3699         if (ucscf->code.status_alive == 0) {
3700             ucscf->code.status_alive = check->default_status_alive;
3701         }
3702     }
3703 
3704     return NGX_CONF_OK;
3705 }
3706 
3707 
3708 static char *
ngx_http_upstream_check_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)3709 ngx_http_upstream_check_merge_loc_conf(ngx_conf_t *cf, void *parent,
3710     void *child)
3711 {
3712     ngx_str_t                            format = ngx_string("html");
3713     ngx_http_upstream_check_loc_conf_t  *prev = parent;
3714     ngx_http_upstream_check_loc_conf_t  *conf = child;
3715 
3716     ngx_conf_merge_ptr_value(conf->format, prev->format,
3717                              ngx_http_get_check_status_format_conf(&format));
3718 
3719     return NGX_CONF_OK;
3720 }
3721 
3722 
3723 static char *
ngx_http_upstream_check_init_shm(ngx_conf_t * cf,void * conf)3724 ngx_http_upstream_check_init_shm(ngx_conf_t *cf, void *conf)
3725 {
3726     ngx_str_t                            *shm_name;
3727     ngx_uint_t                            shm_size;
3728     ngx_shm_zone_t                       *shm_zone;
3729     ngx_http_upstream_check_main_conf_t  *ucmcf = conf;
3730 
3731     if (ucmcf->peers->peers.nelts > 0) {
3732 
3733         ngx_http_upstream_check_shm_generation++;
3734 
3735         shm_name = &ucmcf->peers->check_shm_name;
3736 
3737         ngx_http_upstream_check_get_shm_name(shm_name, cf->pool,
3738                                     ngx_http_upstream_check_shm_generation);
3739 
3740         /* The default check shared memory size is 1M */
3741         shm_size = 1 * 1024 * 1024;
3742 
3743         shm_size = shm_size < ucmcf->check_shm_size ?
3744                               ucmcf->check_shm_size : shm_size;
3745 
3746         shm_zone = ngx_shared_memory_add(cf, shm_name, shm_size,
3747                                          &ngx_http_upstream_check_module);
3748 
3749         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
3750                        "http upstream check, upsteam:%V, shm_zone size:%ui",
3751                        shm_name, shm_size);
3752 
3753         shm_zone->data = cf->pool;
3754         check_peers_ctx = ucmcf->peers;
3755 
3756         shm_zone->init = ngx_http_upstream_check_init_shm_zone;
3757     }
3758     else {
3759          check_peers_ctx = NULL;
3760     }
3761 
3762     return NGX_CONF_OK;
3763 }
3764 
3765 
3766 static ngx_int_t
ngx_http_upstream_check_get_shm_name(ngx_str_t * shm_name,ngx_pool_t * pool,ngx_uint_t generation)3767 ngx_http_upstream_check_get_shm_name(ngx_str_t *shm_name, ngx_pool_t *pool,
3768     ngx_uint_t generation)
3769 {
3770     u_char  *last;
3771 
3772     shm_name->data = ngx_palloc(pool, SHM_NAME_LEN);
3773     if (shm_name->data == NULL) {
3774         return NGX_ERROR;
3775     }
3776 
3777     last = ngx_snprintf(shm_name->data, SHM_NAME_LEN, "%s#%ui",
3778                         "ngx_http_upstream_check", generation);
3779 
3780     shm_name->len = last - shm_name->data;
3781 
3782     return NGX_OK;
3783 }
3784 
3785 
3786 static ngx_int_t
ngx_http_upstream_check_init_shm_zone(ngx_shm_zone_t * shm_zone,void * data)3787 ngx_http_upstream_check_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data)
3788 {
3789     size_t                               size;
3790     ngx_str_t                            oshm_name;
3791     ngx_int_t                            rc;
3792     ngx_uint_t                           i, same, number;
3793     ngx_pool_t                          *pool;
3794     ngx_shm_zone_t                      *oshm_zone;
3795     ngx_slab_pool_t                     *shpool;
3796     ngx_http_upstream_check_peer_t      *peer;
3797     ngx_http_upstream_check_peers_t     *peers;
3798     ngx_http_upstream_check_srv_conf_t  *ucscf;
3799     ngx_http_upstream_check_peer_shm_t  *peer_shm, *opeer_shm;
3800     ngx_http_upstream_check_peers_shm_t *peers_shm, *opeers_shm;
3801 
3802     opeers_shm = NULL;
3803     peers_shm = NULL;
3804     ngx_str_null(&oshm_name);
3805 
3806     same = 0;
3807     peers = check_peers_ctx;
3808     if (peers == NULL) {
3809         return NGX_OK;
3810     }
3811 
3812     number = peers->peers.nelts;
3813     if (number == 0) {
3814         return NGX_OK;
3815     }
3816 
3817     pool = shm_zone->data;
3818     if (pool == NULL) {
3819         pool = ngx_cycle->pool;
3820     }
3821 
3822     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
3823 
3824     if (data) {
3825         opeers_shm = data;
3826 
3827         if ((opeers_shm->number == number)
3828             && (opeers_shm->checksum == peers->checksum)) {
3829 
3830             peers_shm = data;
3831             same = 1;
3832         }
3833     }
3834 
3835     if (!same) {
3836 
3837         if (ngx_http_upstream_check_shm_generation > 1) {
3838 
3839             ngx_http_upstream_check_get_shm_name(&oshm_name,
3840                     pool, ngx_http_upstream_check_shm_generation - 1);
3841 
3842             /* The global variable ngx_cycle still points to the old one */
3843             oshm_zone = ngx_shared_memory_find((ngx_cycle_t *) ngx_cycle,
3844                                                &oshm_name,
3845                                                &ngx_http_upstream_check_module);
3846 
3847             if (oshm_zone) {
3848                 opeers_shm = oshm_zone->data;
3849 
3850                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
3851                                "http upstream check, find oshm_zone:%p, "
3852                                "opeers_shm: %p",
3853                                oshm_zone, opeers_shm);
3854             }
3855         }
3856 
3857         size = sizeof(*peers_shm) +
3858                (number - 1) * sizeof(ngx_http_upstream_check_peer_shm_t);
3859 
3860         peers_shm = ngx_slab_alloc(shpool, size);
3861 
3862         if (peers_shm == NULL) {
3863             goto failure;
3864         }
3865 
3866         ngx_memzero(peers_shm, size);
3867     }
3868 
3869     peers_shm->generation = ngx_http_upstream_check_shm_generation;
3870     peers_shm->checksum = peers->checksum;
3871     peers_shm->number = number;
3872 
3873     peer = peers->peers.elts;
3874 
3875     for (i = 0; i < number; i++) {
3876 
3877         peer_shm = &peers_shm->peers[i];
3878 
3879         /*
3880          * This function may be triggered before the old stale
3881          * work process exits. The owner may stick to the old
3882          * pid.
3883          */
3884         peer_shm->owner = NGX_INVALID_PID;
3885 
3886         if (same) {
3887             continue;
3888         }
3889 
3890         peer_shm->socklen = peer[i].peer_addr->socklen;
3891         peer_shm->sockaddr = ngx_slab_alloc(shpool, peer_shm->socklen);
3892         if (peer_shm->sockaddr == NULL) {
3893             goto failure;
3894         }
3895 
3896         ngx_memcpy(peer_shm->sockaddr, peer[i].peer_addr->sockaddr,
3897                    peer_shm->socklen);
3898 
3899         if (opeers_shm) {
3900 
3901             opeer_shm = ngx_http_upstream_check_find_shm_peer(opeers_shm,
3902                                                               peer[i].peer_addr);
3903             if (opeer_shm) {
3904                 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, shm_zone->shm.log, 0,
3905                                "http upstream check, inherit opeer: %V ",
3906                                &peer[i].peer_addr->name);
3907 
3908                 rc = ngx_http_upstream_check_init_shm_peer(peer_shm, opeer_shm,
3909                          0, pool, &peer[i].peer_addr->name);
3910                 if (rc != NGX_OK) {
3911                     return NGX_ERROR;
3912                 }
3913 
3914                 continue;
3915             }
3916         }
3917 
3918         ucscf = peer[i].conf;
3919         rc = ngx_http_upstream_check_init_shm_peer(peer_shm, NULL,
3920                                                    ucscf->default_down, pool,
3921                                                    &peer[i].peer_addr->name);
3922         if (rc != NGX_OK) {
3923             return NGX_ERROR;
3924         }
3925     }
3926 
3927     peers->peers_shm = peers_shm;
3928     shm_zone->data = peers_shm;
3929 
3930     return NGX_OK;
3931 
3932 failure:
3933     ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
3934                   "http upstream check_shm_size is too small, "
3935                   "you should specify a larger size.");
3936     return NGX_ERROR;
3937 }
3938 
3939 
3940 static ngx_shm_zone_t *
ngx_shared_memory_find(ngx_cycle_t * cycle,ngx_str_t * name,void * tag)3941 ngx_shared_memory_find(ngx_cycle_t *cycle, ngx_str_t *name, void *tag)
3942 {
3943     ngx_uint_t        i;
3944     ngx_shm_zone_t   *shm_zone;
3945     ngx_list_part_t  *part;
3946 
3947     part = (ngx_list_part_t *) &(cycle->shared_memory.part);
3948     shm_zone = part->elts;
3949 
3950     for (i = 0; /* void */ ; i++) {
3951 
3952         if (i >= part->nelts) {
3953             if (part->next == NULL) {
3954                 break;
3955             }
3956             part = part->next;
3957             shm_zone = part->elts;
3958             i = 0;
3959         }
3960 
3961         if (name->len != shm_zone[i].shm.name.len) {
3962             continue;
3963         }
3964 
3965         if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len) != 0)
3966         {
3967             continue;
3968         }
3969 
3970         if (tag != shm_zone[i].tag) {
3971             continue;
3972         }
3973 
3974         return &shm_zone[i];
3975     }
3976 
3977     return NULL;
3978 }
3979 
3980 
3981 static ngx_http_upstream_check_peer_shm_t *
ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t * p,ngx_addr_t * addr)3982 ngx_http_upstream_check_find_shm_peer(ngx_http_upstream_check_peers_shm_t *p,
3983     ngx_addr_t *addr)
3984 {
3985     ngx_uint_t                          i;
3986     ngx_http_upstream_check_peer_shm_t *peer_shm;
3987 
3988     for (i = 0; i < p->number; i++) {
3989 
3990         peer_shm = &p->peers[i];
3991 
3992         if (addr->socklen != peer_shm->socklen) {
3993             continue;
3994         }
3995 
3996         if (ngx_memcmp(addr->sockaddr, peer_shm->sockaddr, addr->socklen) == 0) {
3997             return peer_shm;
3998         }
3999     }
4000 
4001     return NULL;
4002 }
4003 
4004 
4005 static ngx_int_t
ngx_http_upstream_check_init_shm_peer(ngx_http_upstream_check_peer_shm_t * psh,ngx_http_upstream_check_peer_shm_t * opsh,ngx_uint_t init_down,ngx_pool_t * pool,ngx_str_t * name)4006 ngx_http_upstream_check_init_shm_peer(ngx_http_upstream_check_peer_shm_t *psh,
4007     ngx_http_upstream_check_peer_shm_t *opsh, ngx_uint_t init_down,
4008     ngx_pool_t *pool, ngx_str_t *name)
4009 {
4010     u_char  *file;
4011 
4012     if (opsh) {
4013         psh->access_time  = opsh->access_time;
4014         psh->access_count = opsh->access_count;
4015 
4016         psh->fall_count   = opsh->fall_count;
4017         psh->rise_count   = opsh->rise_count;
4018         psh->busyness     = opsh->busyness;
4019 
4020         psh->down         = opsh->down;
4021 
4022     } else {
4023         psh->access_time  = 0;
4024         psh->access_count = 0;
4025 
4026         psh->fall_count   = 0;
4027         psh->rise_count   = 0;
4028         psh->busyness     = 0;
4029 
4030         psh->down         = init_down;
4031     }
4032 
4033 #if (NGX_HAVE_ATOMIC_OPS)
4034 
4035     file = NULL;
4036 
4037 #else
4038 
4039     file = ngx_pnalloc(pool, ngx_cycle->lock_file.len + name->len);
4040     if (file == NULL) {
4041         return NGX_ERROR;
4042     }
4043 
4044     (void) ngx_sprintf(file, "%V%V%Z", &ngx_cycle->lock_file, name);
4045 
4046 #endif
4047 
4048 #if (nginx_version >= 1002000)
4049     if (ngx_shmtx_create(&psh->mutex, &psh->lock, file) != NGX_OK) {
4050 #else
4051     if (ngx_shmtx_create(&psh->mutex, (void *) &psh->lock, file) != NGX_OK) {
4052 #endif
4053         return NGX_ERROR;
4054     }
4055 
4056     return NGX_OK;
4057 }
4058 
4059 
4060 static ngx_int_t
4061 ngx_http_upstream_check_init_process(ngx_cycle_t *cycle)
4062 {
4063     ngx_http_upstream_check_main_conf_t *ucmcf;
4064 
4065     ucmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_upstream_check_module);
4066     if (ucmcf == NULL) {
4067         return NGX_OK;
4068     }
4069 
4070     return ngx_http_upstream_check_add_timers(cycle);
4071 }
4072