6115
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 * Copyright (C) Nginx, Inc.
|
|
5 */
|
|
6
|
|
7
|
|
8 #include <ngx_config.h>
|
|
9 #include <ngx_core.h>
|
|
10 #include <ngx_stream.h>
|
|
11
|
|
12
|
|
13 static char *ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd,
|
|
14 void *dummy);
|
|
15 static char *ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
|
|
16 void *conf);
|
|
17 static void *ngx_stream_upstream_create_main_conf(ngx_conf_t *cf);
|
|
18 static char *ngx_stream_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
|
|
19
|
|
20
|
|
21 static ngx_command_t ngx_stream_upstream_commands[] = {
|
|
22
|
|
23 { ngx_string("upstream"),
|
|
24 NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
|
|
25 ngx_stream_upstream,
|
|
26 0,
|
|
27 0,
|
|
28 NULL },
|
|
29
|
|
30 { ngx_string("server"),
|
|
31 NGX_STREAM_UPS_CONF|NGX_CONF_1MORE,
|
|
32 ngx_stream_upstream_server,
|
|
33 NGX_STREAM_SRV_CONF_OFFSET,
|
|
34 0,
|
|
35 NULL },
|
|
36
|
|
37 ngx_null_command
|
|
38 };
|
|
39
|
|
40
|
|
41 static ngx_stream_module_t ngx_stream_upstream_module_ctx = {
|
|
42 ngx_stream_upstream_create_main_conf, /* create main configuration */
|
|
43 ngx_stream_upstream_init_main_conf, /* init main configuration */
|
|
44
|
|
45 NULL, /* create server configuration */
|
|
46 NULL, /* merge server configuration */
|
|
47 };
|
|
48
|
|
49
|
|
50 ngx_module_t ngx_stream_upstream_module = {
|
|
51 NGX_MODULE_V1,
|
|
52 &ngx_stream_upstream_module_ctx, /* module context */
|
|
53 ngx_stream_upstream_commands, /* module directives */
|
|
54 NGX_STREAM_MODULE, /* module type */
|
|
55 NULL, /* init master */
|
|
56 NULL, /* init module */
|
|
57 NULL, /* init process */
|
|
58 NULL, /* init thread */
|
|
59 NULL, /* exit thread */
|
|
60 NULL, /* exit process */
|
|
61 NULL, /* exit master */
|
|
62 NGX_MODULE_V1_PADDING
|
|
63 };
|
|
64
|
|
65
|
|
66 static char *
|
|
67 ngx_stream_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
|
|
68 {
|
|
69 char *rv;
|
|
70 void *mconf;
|
|
71 ngx_str_t *value;
|
|
72 ngx_url_t u;
|
|
73 ngx_uint_t m;
|
|
74 ngx_conf_t pcf;
|
|
75 ngx_stream_module_t *module;
|
|
76 ngx_stream_conf_ctx_t *ctx, *stream_ctx;
|
|
77 ngx_stream_upstream_srv_conf_t *uscf;
|
|
78
|
|
79 ngx_memzero(&u, sizeof(ngx_url_t));
|
|
80
|
|
81 value = cf->args->elts;
|
|
82 u.host = value[1];
|
|
83 u.no_resolve = 1;
|
|
84 u.no_port = 1;
|
|
85
|
|
86 uscf = ngx_stream_upstream_add(cf, &u, NGX_STREAM_UPSTREAM_CREATE
|
|
87 |NGX_STREAM_UPSTREAM_WEIGHT
|
|
88 |NGX_STREAM_UPSTREAM_MAX_FAILS
|
|
89 |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
|
|
90 |NGX_STREAM_UPSTREAM_DOWN
|
|
91 |NGX_STREAM_UPSTREAM_BACKUP);
|
|
92 if (uscf == NULL) {
|
|
93 return NGX_CONF_ERROR;
|
|
94 }
|
|
95
|
|
96
|
|
97 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t));
|
|
98 if (ctx == NULL) {
|
|
99 return NGX_CONF_ERROR;
|
|
100 }
|
|
101
|
|
102 stream_ctx = cf->ctx;
|
|
103 ctx->main_conf = stream_ctx->main_conf;
|
|
104
|
|
105 /* the upstream{}'s srv_conf */
|
|
106
|
|
107 ctx->srv_conf = ngx_pcalloc(cf->pool,
|
|
108 sizeof(void *) * ngx_stream_max_module);
|
|
109 if (ctx->srv_conf == NULL) {
|
|
110 return NGX_CONF_ERROR;
|
|
111 }
|
|
112
|
|
113 ctx->srv_conf[ngx_stream_upstream_module.ctx_index] = uscf;
|
|
114
|
|
115 uscf->srv_conf = ctx->srv_conf;
|
|
116
|
|
117 for (m = 0; ngx_modules[m]; m++) {
|
|
118 if (ngx_modules[m]->type != NGX_STREAM_MODULE) {
|
|
119 continue;
|
|
120 }
|
|
121
|
|
122 module = ngx_modules[m]->ctx;
|
|
123
|
|
124 if (module->create_srv_conf) {
|
|
125 mconf = module->create_srv_conf(cf);
|
|
126 if (mconf == NULL) {
|
|
127 return NGX_CONF_ERROR;
|
|
128 }
|
|
129
|
|
130 ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
|
|
131 }
|
|
132 }
|
|
133
|
|
134 uscf->servers = ngx_array_create(cf->pool, 4,
|
|
135 sizeof(ngx_stream_upstream_server_t));
|
|
136 if (uscf->servers == NULL) {
|
|
137 return NGX_CONF_ERROR;
|
|
138 }
|
|
139
|
|
140
|
|
141 /* parse inside upstream{} */
|
|
142
|
|
143 pcf = *cf;
|
|
144 cf->ctx = ctx;
|
|
145 cf->cmd_type = NGX_STREAM_UPS_CONF;
|
|
146
|
|
147 rv = ngx_conf_parse(cf, NULL);
|
|
148
|
|
149 *cf = pcf;
|
|
150
|
|
151 if (rv != NGX_CONF_OK) {
|
|
152 return rv;
|
|
153 }
|
|
154
|
|
155 if (uscf->servers->nelts == 0) {
|
|
156 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
157 "no servers are inside upstream");
|
|
158 return NGX_CONF_ERROR;
|
|
159 }
|
|
160
|
|
161 return rv;
|
|
162 }
|
|
163
|
|
164
|
|
165 static char *
|
|
166 ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|
167 {
|
|
168 ngx_stream_upstream_srv_conf_t *uscf = conf;
|
|
169
|
|
170 time_t fail_timeout;
|
|
171 ngx_str_t *value, s;
|
|
172 ngx_url_t u;
|
|
173 ngx_int_t weight, max_fails;
|
|
174 ngx_uint_t i;
|
|
175 ngx_stream_upstream_server_t *us;
|
|
176
|
|
177 us = ngx_array_push(uscf->servers);
|
|
178 if (us == NULL) {
|
|
179 return NGX_CONF_ERROR;
|
|
180 }
|
|
181
|
|
182 ngx_memzero(us, sizeof(ngx_stream_upstream_server_t));
|
|
183
|
|
184 value = cf->args->elts;
|
|
185
|
|
186 weight = 1;
|
|
187 max_fails = 1;
|
|
188 fail_timeout = 10;
|
|
189
|
|
190 for (i = 2; i < cf->args->nelts; i++) {
|
|
191
|
|
192 if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
|
|
193
|
|
194 if (!(uscf->flags & NGX_STREAM_UPSTREAM_WEIGHT)) {
|
|
195 goto not_supported;
|
|
196 }
|
|
197
|
|
198 weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
|
|
199
|
|
200 if (weight == NGX_ERROR || weight == 0) {
|
|
201 goto invalid;
|
|
202 }
|
|
203
|
|
204 continue;
|
|
205 }
|
|
206
|
|
207 if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
|
|
208
|
|
209 if (!(uscf->flags & NGX_STREAM_UPSTREAM_MAX_FAILS)) {
|
|
210 goto not_supported;
|
|
211 }
|
|
212
|
|
213 max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
|
|
214
|
|
215 if (max_fails == NGX_ERROR) {
|
|
216 goto invalid;
|
|
217 }
|
|
218
|
|
219 continue;
|
|
220 }
|
|
221
|
|
222 if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
|
|
223
|
|
224 if (!(uscf->flags & NGX_STREAM_UPSTREAM_FAIL_TIMEOUT)) {
|
|
225 goto not_supported;
|
|
226 }
|
|
227
|
|
228 s.len = value[i].len - 13;
|
|
229 s.data = &value[i].data[13];
|
|
230
|
|
231 fail_timeout = ngx_parse_time(&s, 1);
|
|
232
|
|
233 if (fail_timeout == (time_t) NGX_ERROR) {
|
|
234 goto invalid;
|
|
235 }
|
|
236
|
|
237 continue;
|
|
238 }
|
|
239
|
|
240 if (ngx_strcmp(value[i].data, "backup") == 0) {
|
|
241
|
|
242 if (!(uscf->flags & NGX_STREAM_UPSTREAM_BACKUP)) {
|
|
243 goto not_supported;
|
|
244 }
|
|
245
|
|
246 us->backup = 1;
|
|
247
|
|
248 continue;
|
|
249 }
|
|
250
|
|
251 if (ngx_strcmp(value[i].data, "down") == 0) {
|
|
252
|
|
253 if (!(uscf->flags & NGX_STREAM_UPSTREAM_DOWN)) {
|
|
254 goto not_supported;
|
|
255 }
|
|
256
|
|
257 us->down = 1;
|
|
258
|
|
259 continue;
|
|
260 }
|
|
261
|
|
262 goto invalid;
|
|
263 }
|
|
264
|
|
265 ngx_memzero(&u, sizeof(ngx_url_t));
|
|
266
|
|
267 u.url = value[1];
|
|
268
|
|
269 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
|
|
270 if (u.err) {
|
|
271 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
272 "%s in upstream \"%V\"", u.err, &u.url);
|
|
273 }
|
|
274
|
|
275 return NGX_CONF_ERROR;
|
|
276 }
|
|
277
|
|
278 if (u.no_port) {
|
|
279 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
280 "no port in upstream \"%V\"", &u.url);
|
|
281 return NGX_CONF_ERROR;
|
|
282 }
|
|
283
|
|
284 us->name = u.url;
|
|
285 us->addrs = u.addrs;
|
|
286 us->naddrs = u.naddrs;
|
|
287 us->weight = weight;
|
|
288 us->max_fails = max_fails;
|
|
289 us->fail_timeout = fail_timeout;
|
|
290
|
|
291 return NGX_CONF_OK;
|
|
292
|
|
293 invalid:
|
|
294
|
|
295 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
296 "invalid parameter \"%V\"", &value[i]);
|
|
297
|
|
298 return NGX_CONF_ERROR;
|
|
299
|
|
300 not_supported:
|
|
301
|
|
302 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
303 "balancing method does not support parameter \"%V\"",
|
|
304 &value[i]);
|
|
305
|
|
306 return NGX_CONF_ERROR;
|
|
307 }
|
|
308
|
|
309
|
|
310 ngx_stream_upstream_srv_conf_t *
|
|
311 ngx_stream_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
|
|
312 {
|
|
313 ngx_uint_t i;
|
|
314 ngx_stream_upstream_server_t *us;
|
|
315 ngx_stream_upstream_srv_conf_t *uscf, **uscfp;
|
|
316 ngx_stream_upstream_main_conf_t *umcf;
|
|
317
|
|
318 if (!(flags & NGX_STREAM_UPSTREAM_CREATE)) {
|
|
319
|
|
320 if (ngx_parse_url(cf->pool, u) != NGX_OK) {
|
|
321 if (u->err) {
|
|
322 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
323 "%s in upstream \"%V\"", u->err, &u->url);
|
|
324 }
|
|
325
|
|
326 return NULL;
|
|
327 }
|
|
328 }
|
|
329
|
|
330 umcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_upstream_module);
|
|
331
|
|
332 uscfp = umcf->upstreams.elts;
|
|
333
|
|
334 for (i = 0; i < umcf->upstreams.nelts; i++) {
|
|
335
|
|
336 if (uscfp[i]->host.len != u->host.len
|
|
337 || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
|
|
338 != 0)
|
|
339 {
|
|
340 continue;
|
|
341 }
|
|
342
|
|
343 if ((flags & NGX_STREAM_UPSTREAM_CREATE)
|
|
344 && (uscfp[i]->flags & NGX_STREAM_UPSTREAM_CREATE))
|
|
345 {
|
|
346 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
347 "duplicate upstream \"%V\"", &u->host);
|
|
348 return NULL;
|
|
349 }
|
|
350
|
|
351 if ((uscfp[i]->flags & NGX_STREAM_UPSTREAM_CREATE) && !u->no_port) {
|
|
352 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
|
353 "upstream \"%V\" may not have port %d",
|
|
354 &u->host, u->port);
|
|
355 return NULL;
|
|
356 }
|
|
357
|
|
358 if ((flags & NGX_STREAM_UPSTREAM_CREATE) && !uscfp[i]->no_port) {
|
|
359 ngx_log_error(NGX_LOG_WARN, cf->log, 0,
|
|
360 "upstream \"%V\" may not have port %d in %s:%ui",
|
|
361 &u->host, uscfp[i]->port,
|
|
362 uscfp[i]->file_name, uscfp[i]->line);
|
|
363 return NULL;
|
|
364 }
|
|
365
|
|
366 if (uscfp[i]->port != u->port) {
|
|
367 continue;
|
|
368 }
|
|
369
|
|
370 if (flags & NGX_STREAM_UPSTREAM_CREATE) {
|
|
371 uscfp[i]->flags = flags;
|
|
372 }
|
|
373
|
|
374 return uscfp[i];
|
|
375 }
|
|
376
|
|
377 uscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_srv_conf_t));
|
|
378 if (uscf == NULL) {
|
|
379 return NULL;
|
|
380 }
|
|
381
|
|
382 uscf->flags = flags;
|
|
383 uscf->host = u->host;
|
|
384 uscf->file_name = cf->conf_file->file.name.data;
|
|
385 uscf->line = cf->conf_file->line;
|
|
386 uscf->port = u->port;
|
|
387 uscf->no_port = u->no_port;
|
|
388
|
|
389 if (u->naddrs == 1) {
|
|
390 uscf->servers = ngx_array_create(cf->pool, 1,
|
|
391 sizeof(ngx_stream_upstream_server_t));
|
|
392 if (uscf->servers == NULL) {
|
|
393 return NULL;
|
|
394 }
|
|
395
|
|
396 us = ngx_array_push(uscf->servers);
|
|
397 if (us == NULL) {
|
|
398 return NULL;
|
|
399 }
|
|
400
|
|
401 ngx_memzero(us, sizeof(ngx_stream_upstream_server_t));
|
|
402
|
|
403 us->addrs = u->addrs;
|
|
404 us->naddrs = 1;
|
|
405 }
|
|
406
|
|
407 uscfp = ngx_array_push(&umcf->upstreams);
|
|
408 if (uscfp == NULL) {
|
|
409 return NULL;
|
|
410 }
|
|
411
|
|
412 *uscfp = uscf;
|
|
413
|
|
414 return uscf;
|
|
415 }
|
|
416
|
|
417
|
|
418 static void *
|
|
419 ngx_stream_upstream_create_main_conf(ngx_conf_t *cf)
|
|
420 {
|
|
421 ngx_stream_upstream_main_conf_t *umcf;
|
|
422
|
|
423 umcf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_upstream_main_conf_t));
|
|
424 if (umcf == NULL) {
|
|
425 return NULL;
|
|
426 }
|
|
427
|
|
428 if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
|
|
429 sizeof(ngx_stream_upstream_srv_conf_t *))
|
|
430 != NGX_OK)
|
|
431 {
|
|
432 return NULL;
|
|
433 }
|
|
434
|
|
435 return umcf;
|
|
436 }
|
|
437
|
|
438
|
|
439 static char *
|
|
440 ngx_stream_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
|
|
441 {
|
|
442 ngx_stream_upstream_main_conf_t *umcf = conf;
|
|
443
|
|
444 ngx_uint_t i;
|
|
445 ngx_stream_upstream_init_pt init;
|
|
446 ngx_stream_upstream_srv_conf_t **uscfp;
|
|
447
|
|
448 uscfp = umcf->upstreams.elts;
|
|
449
|
|
450 for (i = 0; i < umcf->upstreams.nelts; i++) {
|
|
451
|
|
452 init = uscfp[i]->peer.init_upstream
|
|
453 ? uscfp[i]->peer.init_upstream
|
|
454 : ngx_stream_upstream_init_round_robin;
|
|
455
|
|
456 if (init(cf, uscfp[i]) != NGX_OK) {
|
|
457 return NGX_CONF_ERROR;
|
|
458 }
|
|
459 }
|
|
460
|
|
461 return NGX_CONF_OK;
|
|
462 }
|