Mercurial > hg > nginx
comparison src/stream/ngx_stream_upstream.c @ 6115:61d7ae76647d
Stream: port from NGINX+.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Mon, 20 Apr 2015 13:05:11 +0300 |
parents | |
children | 68c106e6fa0a |
comparison
equal
deleted
inserted
replaced
6114:4a640716f4e2 | 6115:61d7ae76647d |
---|---|
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 } |