-
Notifications
You must be signed in to change notification settings - Fork 1
/
atom.xml
513 lines (270 loc) · 907 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>weeweetan's blog</title>
<subtitle>GitHub个人站点</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://weeweetan.github.io/"/>
<updated>2024-11-28T13:52:32.758Z</updated>
<id>https://weeweetan.github.io/</id>
<author>
<name>weeweetan</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>BPF之巅学习笔记</title>
<link href="https://weeweetan.github.io/2024/03/09/BPF%E4%B9%8B%E5%B7%85%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<id>https://weeweetan.github.io/2024/03/09/BPF之巅学习笔记/</id>
<published>2024-03-09T13:34:31.000Z</published>
<updated>2024-11-28T13:52:32.758Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h3 id="第二章"><a href="#第二章" class="headerlink" title="第二章"></a>第二章</h3><h4 id="2-3-扩展版BPF"><a href="#2-3-扩展版BPF" class="headerlink" title="2.3 扩展版BPF"></a>2.3 扩展版BPF</h4><h4 id="2-4-调用栈回溯"><a href="#2-4-调用栈回溯" class="headerlink" title="2.4 调用栈回溯"></a>2.4 调用栈回溯</h4><h4 id="2-5-火焰图"><a href="#2-5-火焰图" class="headerlink" title="2.5 火焰图"></a>2.5 火焰图</h4><h4 id="2-6-事件源"><a href="#2-6-事件源" class="headerlink" title="2.6 事件源"></a>2.6 事件源</h4><h4 id="2-7-kprobes"><a href="#2-7-kprobes" class="headerlink" title="2.7 kprobes"></a>2.7 kprobes</h4><blockquote><p>内核探测点</p></blockquote><h4 id="2-8-uprobes"><a href="#2-8-uprobes" class="headerlink" title="2.8 uprobes"></a>2.8 uprobes</h4><blockquote><p>用户层探测点</p></blockquote><h4 id="2-9-跟踪点"><a href="#2-9-跟踪点" class="headerlink" title="2.9 跟踪点"></a>2.9 跟踪点</h4><h4 id="2-10-USDT"><a href="#2-10-USDT" class="headerlink" title="2.10 USDT"></a>2.10 USDT</h4><h4 id="2-11-动态USDT"><a href="#2-11-动态USDT" class="headerlink" title="2.11 动态USDT"></a>2.11 动态USDT</h4><h4 id="2-12-性能监控计数器"><a href="#2-12-性能监控计数器" class="headerlink" title="2.12 性能监控计数器"></a>2.12 性能监控计数器</h4><h4 id="2-13-perf-events"><a href="#2-13-perf-events" class="headerlink" title="2.13 perf_events"></a>2.13 perf_events</h4><h3 id="第三章"><a href="#第三章" class="headerlink" title="第三章"></a>第三章</h3><h4 id="3-1-概论"><a href="#3-1-概论" class="headerlink" title="3.1 概论"></a>3.1 概论</h4><h4 id="3-2-性能分析方法论"><a href="#3-2-性能分析方法论" class="headerlink" title="3.2 性能分析方法论"></a>3.2 性能分析方法论</h4><h5 id="3-2-1-业务负载画像"><a href="#3-2-1-业务负载画像" class="headerlink" title="3.2.1 业务负载画像"></a>3.2.1 业务负载画像</h5><blockquote><p>谁导致了这个负载(eg PID, process name, UID, IP address)?<br>Why is the load called (code path, stack trace, flame graph)?<br>What is the load (IOPS, throughput, type)?<br>How is the load changing over time (per-interval summaries)?</p></blockquote><h5 id="3-2-2-下钻分析"><a href="#3-2-2-下钻分析" class="headerlink" title="3.2.2 下钻分析"></a>3.2.2 下钻分析</h5><blockquote><p>Start examining the highest level.<br>Examine next-level details.</p></blockquote><h5 id="3-2-3-USE方法论"><a href="#3-2-3-USE方法论" class="headerlink" title="3.2.3 USE方法论"></a>3.2.3 USE方法论</h5><blockquote><p>Utilization 使用率<br>Saturation 负载率<br>Errors 错误</p></blockquote><h5 id="3-2-4-检查清单法"><a href="#3-2-4-检查清单法" class="headerlink" title="3.2.4 检查清单法"></a>3.2.4 检查清单法</h5><blockquote></blockquote><h4 id="3-3-Linux-60s分析"><a href="#3-3-Linux-60s分析" class="headerlink" title="3.3 Linux 60s分析"></a>3.3 Linux 60s分析</h4><h5 id="3-3-1-uptime"><a href="#3-3-1-uptime" class="headerlink" title="3.3.1 uptime"></a>3.3.1 uptime</h5><h5 id="3-3-2-dmesg-tail"><a href="#3-3-2-dmesg-tail" class="headerlink" title="3.3.2 dmesg|tail"></a>3.3.2 dmesg|tail</h5><h5 id="3-3-3-vmstat-1"><a href="#3-3-3-vmstat-1" class="headerlink" title="3.3.3 vmstat 1"></a>3.3.3 vmstat 1</h5><h5 id="3-3-4-mpstat-P-ALL-1"><a href="#3-3-4-mpstat-P-ALL-1" class="headerlink" title="3.3.4 mpstat -P ALL 1"></a>3.3.4 mpstat -P ALL 1</h5><h5 id="3-3-5-pidstat-1"><a href="#3-3-5-pidstat-1" class="headerlink" title="3.3.5 pidstat 1"></a>3.3.5 pidstat 1</h5><h5 id="3-3-6-iostat-xz-1"><a href="#3-3-6-iostat-xz-1" class="headerlink" title="3.3.6 iostat -xz 1"></a>3.3.6 iostat -xz 1</h5><h5 id="3-3-7-free-m"><a href="#3-3-7-free-m" class="headerlink" title="3.3.7 free -m"></a>3.3.7 free -m</h5><h5 id="3-3-8-sar-n-DEV-1"><a href="#3-3-8-sar-n-DEV-1" class="headerlink" title="3.3.8 sar -n DEV 1"></a>3.3.8 sar -n DEV 1</h5><h5 id="3-3-9-sar-n-TCP-ETCP-1"><a href="#3-3-9-sar-n-TCP-ETCP-1" class="headerlink" title="3.3.9 sar -n TCP,ETCP 1"></a>3.3.9 sar -n TCP,ETCP 1</h5><h5 id="3-3-10-top"><a href="#3-3-10-top" class="headerlink" title="3.3.10 top"></a>3.3.10 top</h5><h4 id="3-4-BCC工具检查清单"><a href="#3-4-BCC工具检查清单" class="headerlink" title="3.4 BCC工具检查清单"></a>3.4 BCC工具检查清单</h4><h5 id="3-4-1-execsnoop"><a href="#3-4-1-execsnoop" class="headerlink" title="3.4.1 execsnoop"></a>3.4.1 execsnoop</h5><blockquote><p>统计系统调用exec<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># execsnoop</span></span><br><span class="line">PCOMM PID RET ARGS</span><br><span class="line">supervise <span class="number">9660</span> <span class="number">0</span> ./run</span><br><span class="line">supervise <span class="number">9661</span> <span class="number">0</span> ./run</span><br><span class="line">mkdir <span class="number">9662</span> <span class="number">0</span> /bin/mkdir -p ./main</span><br><span class="line">run <span class="number">9663</span> <span class="number">0</span> ./run</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-2-opensnoop"><a href="#3-4-2-opensnoop" class="headerlink" title="3.4.2 opensnoop"></a>3.4.2 opensnoop</h5><blockquote><p>统计系统调用open<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># opensnoop</span></span><br><span class="line">PID COMM FD ERR PATH</span><br><span class="line"><span class="number">1565</span> redis-server <span class="number">5</span> <span class="number">0</span> /proc/<span class="number">1565</span>/stat</span><br><span class="line"><span class="number">1603</span> snmpd <span class="number">9</span> <span class="number">0</span> /proc/net/dev</span><br><span class="line"><span class="number">1603</span> snmpd <span class="number">11</span> <span class="number">0</span> /proc/net/if_inet6</span><br><span class="line"><span class="number">1603</span> snmpd <span class="number">-1</span> <span class="number">2</span> /sys/<span class="class"><span class="keyword">class</span>/<span class="title">net</span>/<span class="title">eth0</span>/<span class="title">device</span>/<span class="title">vendor</span></span></span><br><span class="line"><span class="class">1603 <span class="title">snmpd</span> 11 0 /<span class="title">proc</span>/<span class="title">sys</span>/<span class="title">net</span>/<span class="title">ipv4</span>/<span class="title">neigh</span>/<span class="title">eth0</span>/<span class="title">retrans_time_ms</span></span></span><br><span class="line"><span class="class">1603 <span class="title">snmpd</span> 11 0 /<span class="title">proc</span>/<span class="title">sys</span>/<span class="title">net</span>/<span class="title">ipv6</span>/<span class="title">neigh</span>/<span class="title">eth0</span>/<span class="title">retrans_time</span></span></span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-3-ext4slower"><a href="#3-4-3-ext4slower" class="headerlink" title="3.4.3 ext4slower"></a>3.4.3 ext4slower</h5><blockquote><p>统计ext4文件系统<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># ext4slower</span><br><span class="line">Tracing ext4 operations slower than <span class="number">10</span> ms</span><br><span class="line"><span class="function">TIME COMM PID T BYTES OFF_KB <span class="title">LAT</span><span class="params">(ms)</span> FILENAME</span></span><br><span class="line">06:35:01 cron 16464 R 1249 0 16.05 common-auth</span><br><span class="line"><span class="number">06</span>:<span class="number">35</span>:<span class="number">01</span> cron <span class="number">16463</span> R <span class="number">1249</span> <span class="number">0</span> <span class="number">16.04</span> common-auth</span><br><span class="line"><span class="number">06</span>:<span class="number">35</span>:<span class="number">01</span> cron <span class="number">16465</span> R <span class="number">1249</span> <span class="number">0</span> <span class="number">16.03</span> common-auth</span><br><span class="line"><span class="number">06</span>:<span class="number">35</span>:<span class="number">01</span> cron <span class="number">16465</span> R <span class="number">4096</span> <span class="number">0</span> <span class="number">10.62</span> login.defs</span><br><span class="line"><span class="number">06</span>:<span class="number">35</span>:<span class="number">01</span> cron <span class="number">16464</span> R <span class="number">4096</span> <span class="number">0</span> <span class="number">10.61</span> login.defs</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-4-biolatency"><a href="#3-4-4-biolatency" class="headerlink" title="3.4.4 biolatency"></a>3.4.4 biolatency</h5><blockquote><p>bio延迟直方图<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># biolatency -m</span></span><br><span class="line">Tracing block device I/O... Hit Ctrl-C to end.</span><br><span class="line">^C</span><br><span class="line">msecs : count distribution</span><br><span class="line"><span class="number">0</span> -> <span class="number">1</span> : <span class="number">16335</span> |****************************************|</span><br><span class="line"><span class="number">2</span> -> <span class="number">3</span> : <span class="number">2272</span> |***** |</span><br><span class="line"><span class="number">4</span> -> <span class="number">7</span> : <span class="number">3603</span> |******** |</span><br><span class="line"><span class="number">8</span> -> <span class="number">15</span> : <span class="number">4328</span> |********** |</span><br><span class="line"><span class="number">16</span> -> <span class="number">31</span> : <span class="number">3379</span> |******** |</span><br><span class="line"><span class="number">32</span> -> <span class="number">63</span> : <span class="number">5815</span> |************** |</span><br><span class="line"><span class="number">64</span> -> <span class="number">127</span> : <span class="number">0</span> | |</span><br><span class="line"><span class="number">128</span> -> <span class="number">255</span> : <span class="number">0</span> | |</span><br><span class="line"><span class="number">256</span> -> <span class="number">511</span> : <span class="number">0</span> | |</span><br><span class="line"><span class="number">512</span> -> <span class="number">1023</span> : <span class="number">1</span> | |</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-5-biosnoop"><a href="#3-4-5-biosnoop" class="headerlink" title="3.4.5 biosnoop"></a>3.4.5 biosnoop</h5><blockquote><p>bio size直方图<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># biosnoop</span></span><br><span class="line">TIME(s) <span class="function">COMM PID DISK T SECTOR BYTES <span class="title">LAT</span><span class="params">(ms)</span></span></span><br><span class="line">0.000004001 supervise 1950 xvda1 W 13092560 4096 0.74</span><br><span class="line"><span class="number">0.000178002</span> supervise <span class="number">1950</span> xvda1 W <span class="number">13092432</span> <span class="number">4096</span> <span class="number">0.61</span></span><br><span class="line"><span class="number">0.001469001</span> supervise <span class="number">1956</span> xvda1 W <span class="number">13092440</span> <span class="number">4096</span> <span class="number">1.24</span></span><br><span class="line"><span class="number">0.001588002</span> supervise <span class="number">1956</span> xvda1 W <span class="number">13115128</span> <span class="number">4096</span> <span class="number">1.09</span></span><br><span class="line"><span class="number">1.022346001</span> supervise <span class="number">1950</span> xvda1 W <span class="number">13115272</span> <span class="number">4096</span> <span class="number">0.98</span></span><br><span class="line">[...]</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-6-cachestat"><a href="#3-4-6-cachestat" class="headerlink" title="3.4.6 cachestat"></a>3.4.6 cachestat</h5><blockquote><p>统计文件系统缓存<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># cachestat</span></span><br><span class="line">HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB</span><br><span class="line"><span class="number">53401</span> <span class="number">2755</span> <span class="number">20953</span> <span class="number">95.09</span>% <span class="number">14</span> <span class="number">90223</span></span><br><span class="line"><span class="number">49599</span> <span class="number">4098</span> <span class="number">21460</span> <span class="number">92.37</span>% <span class="number">14</span> <span class="number">90230</span></span><br><span class="line"><span class="number">16601</span> <span class="number">2689</span> <span class="number">61329</span> <span class="number">86.06</span>% <span class="number">14</span> <span class="number">90381</span></span><br><span class="line"><span class="number">15197</span> <span class="number">2477</span> <span class="number">58028</span> <span class="number">85.99</span>% <span class="number">14</span> <span class="number">90522</span></span><br><span class="line">[...]</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-7-tcpconnect"><a href="#3-4-7-tcpconnect" class="headerlink" title="3.4.7 tcpconnect"></a>3.4.7 tcpconnect</h5><blockquote><p>统计系统调用connect<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># tcpconnect</span></span><br><span class="line">PID COMM IP SADDR DADDR DPORT</span><br><span class="line"><span class="number">1479</span> telnet <span class="number">4</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> <span class="number">23</span></span><br><span class="line"><span class="number">1469</span> curl <span class="number">4</span> <span class="number">10.201</span><span class="number">.219</span><span class="number">.236</span> <span class="number">54.245</span><span class="number">.105</span><span class="number">.25</span> <span class="number">80</span></span><br><span class="line"><span class="number">1469</span> curl <span class="number">4</span> <span class="number">10.201</span><span class="number">.219</span><span class="number">.236</span> <span class="number">54.67</span><span class="number">.101</span><span class="number">.145</span> <span class="number">80</span></span><br><span class="line"><span class="number">1991</span> telnet <span class="number">6</span> ::<span class="number">1</span> ::<span class="number">1</span> <span class="number">23</span></span><br><span class="line"><span class="number">2015</span> ssh <span class="number">6</span> fe80::<span class="number">2000</span>:bff:fe82:<span class="number">3</span>ac fe80::<span class="number">2000</span>:bff:fe82:<span class="number">3</span>ac <span class="number">22</span></span><br><span class="line">[...]</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-8-tcpaccept"><a href="#3-4-8-tcpaccept" class="headerlink" title="3.4.8 tcpaccept"></a>3.4.8 tcpaccept</h5><blockquote><p>统计系统调用accept<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># tcpaccept</span></span><br><span class="line">PID COMM IP RADDR LADDR LPORT</span><br><span class="line"><span class="number">907</span> sshd <span class="number">4</span> <span class="number">192.168</span><span class="number">.56</span><span class="number">.1</span> <span class="number">192.168</span><span class="number">.56</span><span class="number">.102</span> <span class="number">22</span></span><br><span class="line"><span class="number">907</span> sshd <span class="number">4</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> <span class="number">22</span></span><br><span class="line"><span class="number">5389</span> perl <span class="number">6</span> <span class="number">1234</span>:ab12:<span class="number">2040</span>:<span class="number">5020</span>:<span class="number">2299</span>:<span class="number">0</span>:<span class="number">5</span>:<span class="number">0</span> <span class="number">1234</span>:ab12:<span class="number">2040</span>:<span class="number">5020</span>:<span class="number">2299</span>:<span class="number">0</span>:<span class="number">5</span>:<span class="number">0</span> <span class="number">7001</span></span><br><span class="line">[...]</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-9-tcpretrans"><a href="#3-4-9-tcpretrans" class="headerlink" title="3.4.9 tcpretrans"></a>3.4.9 tcpretrans</h5><blockquote><p>tcp重传统计<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># tcpretrans</span></span><br><span class="line">TIME PID IP LADDR:LPORT T> RADDR:RPORT STATE</span><br><span class="line"><span class="number">01</span>:<span class="number">55</span>:<span class="number">05</span> <span class="number">0</span> <span class="number">4</span> <span class="number">10.153</span><span class="number">.223</span><span class="number">.157</span>:<span class="number">22</span> R> <span class="number">69.53</span><span class="number">.245</span><span class="number">.40</span>:<span class="number">34619</span> ESTABLISHED</span><br><span class="line"><span class="number">01</span>:<span class="number">55</span>:<span class="number">05</span> <span class="number">0</span> <span class="number">4</span> <span class="number">10.153</span><span class="number">.223</span><span class="number">.157</span>:<span class="number">22</span> R> <span class="number">69.53</span><span class="number">.245</span><span class="number">.40</span>:<span class="number">34619</span> ESTABLISHED</span><br><span class="line"><span class="number">01</span>:<span class="number">55</span>:<span class="number">17</span> <span class="number">0</span> <span class="number">4</span> <span class="number">10.153</span><span class="number">.223</span><span class="number">.157</span>:<span class="number">22</span> R> <span class="number">69.53</span><span class="number">.245</span><span class="number">.40</span>:<span class="number">22957</span> ESTABLISHED</span><br><span class="line">[...]</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-10-runqlat"><a href="#3-4-10-runqlat" class="headerlink" title="3.4.10 runqlat"></a>3.4.10 runqlat</h5><blockquote><p>cpu上运行队列统计<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># runqlat</span></span><br><span class="line">Tracing run <span class="built_in">queue</span> latency... Hit Ctrl-C to end.</span><br><span class="line">^C</span><br><span class="line">usecs : count distribution</span><br><span class="line"><span class="number">0</span> -> <span class="number">1</span> : <span class="number">233</span> |*********** |</span><br><span class="line"><span class="number">2</span> -> <span class="number">3</span> : <span class="number">742</span> |************************************ |</span><br><span class="line"><span class="number">4</span> -> <span class="number">7</span> : <span class="number">203</span> |********** |</span><br><span class="line"><span class="number">8</span> -> <span class="number">15</span> : <span class="number">173</span> |******** |</span><br><span class="line"><span class="number">16</span> -> <span class="number">31</span> : <span class="number">24</span> |* |</span><br><span class="line"><span class="number">32</span> -> <span class="number">63</span> : <span class="number">0</span> | |</span><br><span class="line"><span class="number">64</span> -> <span class="number">127</span> : <span class="number">30</span> |* |</span><br><span class="line"><span class="number">128</span> -> <span class="number">255</span> : <span class="number">6</span> | |</span><br><span class="line"><span class="number">256</span> -> <span class="number">511</span> : <span class="number">3</span> | |</span><br><span class="line"><span class="number">512</span> -> <span class="number">1023</span> : <span class="number">5</span> | |</span><br><span class="line"><span class="number">1024</span> -> <span class="number">2047</span> : <span class="number">27</span> |* |</span><br><span class="line"><span class="number">2048</span> -> <span class="number">4095</span> : <span class="number">30</span> |* |</span><br><span class="line"><span class="number">4096</span> -> <span class="number">8191</span> : <span class="number">20</span> | |</span><br><span class="line"><span class="number">8192</span> -> <span class="number">16383</span> : <span class="number">29</span> |* |</span><br><span class="line"><span class="number">16384</span> -> <span class="number">32767</span> : <span class="number">809</span> |****************************************|</span><br><span class="line"><span class="number">32768</span> -> <span class="number">65535</span> : <span class="number">64</span> |*** |</span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="3-4-11-profile"><a href="#3-4-11-profile" class="headerlink" title="3.4.11 profile"></a>3.4.11 profile</h5><blockquote><p>采集CPU<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"># profile</span></span><br><span class="line">Sampling at <span class="number">49</span> Hertz of all threads by user + kernel <span class="built_in">stack</span>... Hit Ctrl-C to end.</span><br><span class="line">^C</span><br><span class="line">[...]</span><br><span class="line">copy_user_enhanced_fast_string</span><br><span class="line">copy_user_enhanced_fast_string</span><br><span class="line">_copy_from_iter_full</span><br><span class="line">tcp_sendmsg_locked</span><br><span class="line">tcp_sendmsg</span><br><span class="line">inet_sendmsg</span><br><span class="line">sock_sendmsg</span><br><span class="line">sock_write_iter</span><br><span class="line">new_sync_write</span><br><span class="line">__vfs_write</span><br><span class="line">vfs_write</span><br><span class="line">SyS_write</span><br><span class="line">do_syscall_64</span><br><span class="line">entry_SYSCALL_64_after_hwframe</span><br><span class="line">[unknown]</span><br><span class="line">[unknown]</span><br><span class="line">- iperf (<span class="number">24092</span>)</span><br><span class="line"><span class="number">58</span></span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="第四章"><a href="#第四章" class="headerlink" title="第四章"></a>第四章</h4><h5 id="4-1-BCC的组件"><a href="#4-1-BCC的组件" class="headerlink" title="4.1 BCC的组件"></a>4.1 BCC的组件</h5><blockquote></blockquote><h5 id="4-2-BCC的特性"><a href="#4-2-BCC的特性" class="headerlink" title="4.2 BCC的特性"></a>4.2 BCC的特性</h5><blockquote></blockquote><h5 id="4-3-安装BCC"><a href="#4-3-安装BCC" class="headerlink" title="4.3 安装BCC"></a>4.3 安装BCC</h5><blockquote></blockquote><h5 id="4-4-BCC的工具"><a href="#4-4-BCC的工具" class="headerlink" title="4.4 BCC的工具"></a>4.4 BCC的工具</h5><blockquote></blockquote><h5 id="4-5-funccount"><a href="#4-5-funccount" class="headerlink" title="4.5 funccount"></a>4.5 funccount</h5><blockquote><p>统计指定函数调用次数</p></blockquote><h5 id="4-6-stackcount"><a href="#4-6-stackcount" class="headerlink" title="4.6 stackcount"></a>4.6 stackcount</h5><blockquote><p>统计栈调用次数<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="4-7-trace"><a href="#4-7-trace" class="headerlink" title="4.7 trace"></a>4.7 trace</h5><blockquote><p>用于跟踪和调试应用程序的执行过程<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h5 id="4-8-argdist"><a href="#4-8-argdist" class="headerlink" title="4.8 argdist"></a>4.8 argdist</h5><blockquote><p>函数参数分布统计</p></blockquote><h5 id="4-9-工具文档"><a href="#4-9-工具文档" class="headerlink" title="4.9 工具文档"></a>4.9 工具文档</h5><h6 id="4-9-1-Man-Page-opensnoop"><a href="#4-9-1-Man-Page-opensnoop" class="headerlink" title="4.9.1 Man Page: opensnoop"></a>4.9.1 Man Page: opensnoop</h6><blockquote></blockquote><h6 id="4-9-2-Examples-File-opensnoop"><a href="#4-9-2-Examples-File-opensnoop" class="headerlink" title="4.9.2 Examples File: opensnoop"></a>4.9.2 Examples File: opensnoop</h6><h5 id="4-10-开发BCC工具"><a href="#4-10-开发BCC工具" class="headerlink" title="4.10 开发BCC工具"></a>4.10 开发BCC工具</h5><blockquote></blockquote><h5 id="4-11-BCC的内部实现"><a href="#4-11-BCC的内部实现" class="headerlink" title="4.11 BCC的内部实现"></a>4.11 BCC的内部实现</h5><blockquote></blockquote><h5 id="4-12-BCC的调试"><a href="#4-12-BCC的调试" class="headerlink" title="4.12 BCC的调试"></a>4.12 BCC的调试</h5><h6 id="4-12-1-printf-Debugging"><a href="#4-12-1-printf-Debugging" class="headerlink" title="4.12.1 printf() Debugging"></a>4.12.1 printf() Debugging</h6><h6 id="4-12-2-BCC-Debug-output"><a href="#4-12-2-BCC-Debug-output" class="headerlink" title="4.12.2 BCC Debug output"></a>4.12.2 BCC Debug output</h6><h6 id="4-12-3-BCC-Debug-Flag"><a href="#4-12-3-BCC-Debug-Flag" class="headerlink" title="4.12.3 BCC Debug Flag"></a>4.12.3 BCC Debug Flag</h6><h6 id="4-12-4-bpflist"><a href="#4-12-4-bpflist" class="headerlink" title="4.12.4 bpflist"></a>4.12.4 bpflist</h6><h6 id="4-12-5-bpftool"><a href="#4-12-5-bpftool" class="headerlink" title="4.12.5 bpftool"></a>4.12.5 bpftool</h6><h6 id="4-12-6-dmesg"><a href="#4-12-6-dmesg" class="headerlink" title="4.12.6 dmesg"></a>4.12.6 dmesg</h6><h6 id="4-12-7-Resetting-Events"><a href="#4-12-7-Resetting-Events" class="headerlink" title="4.12.7 Resetting Events"></a>4.12.7 Resetting Events</h6><h4 id="4-13-Summary"><a href="#4-13-Summary" class="headerlink" title="4.13 Summary"></a>4.13 Summary</h4><blockquote></blockquote><h4 id="第五章"><a href="#第五章" class="headerlink" title="第五章"></a>第五章</h4><h5 id="5-1-bpftrace的组件"><a href="#5-1-bpftrace的组件" class="headerlink" title="5.1 bpftrace的组件"></a>5.1 bpftrace的组件</h5><blockquote></blockquote><h5 id="5-2-bpftrace的特性"><a href="#5-2-bpftrace的特性" class="headerlink" title="5.2 bpftrace的特性"></a>5.2 bpftrace的特性</h5><h6 id="5-2-1-bpftrace-Event-Sources"><a href="#5-2-1-bpftrace-Event-Sources" class="headerlink" title="5.2.1 bpftrace Event Sources"></a>5.2.1 bpftrace Event Sources</h6><h6 id="5-2-2-bpftrace-Actions"><a href="#5-2-2-bpftrace-Actions" class="headerlink" title="5.2.2 bpftrace Actions"></a>5.2.2 bpftrace Actions</h6><h6 id="5-2-3-bpftrace-General-Features"><a href="#5-2-3-bpftrace-General-Features" class="headerlink" title="5.2.3 bpftrace General Features"></a>5.2.3 bpftrace General Features</h6><h6 id="5-2-4-bpftrace-Compared-to-Other-Observability-Tools"><a href="#5-2-4-bpftrace-Compared-to-Other-Observability-Tools" class="headerlink" title="5.2.4 bpftrace Compared to Other Observability Tools"></a>5.2.4 bpftrace Compared to Other Observability Tools</h6><blockquote></blockquote><h5 id="5-3-bpftrace的安装"><a href="#5-3-bpftrace的安装" class="headerlink" title="5.3 bpftrace的安装"></a>5.3 bpftrace的安装</h5><h6 id="5-3-1-Kernel-Requirements"><a href="#5-3-1-Kernel-Requirements" class="headerlink" title="5.3.1 Kernel Requirements"></a>5.3.1 Kernel Requirements</h6><h6 id="5-3-2-Ubuntu"><a href="#5-3-2-Ubuntu" class="headerlink" title="5.3.2 Ubuntu"></a>5.3.2 Ubuntu</h6><h6 id="5-3-3-Fedora"><a href="#5-3-3-Fedora" class="headerlink" title="5.3.3 Fedora"></a>5.3.3 Fedora</h6><h6 id="5-3-4-Post-Build-Steps"><a href="#5-3-4-Post-Build-Steps" class="headerlink" title="5.3.4 Post-Build Steps"></a>5.3.4 Post-Build Steps</h6><h6 id="5-3-5-Other-Distributions"><a href="#5-3-5-Other-Distributions" class="headerlink" title="5.3.5 Other Distributions"></a>5.3.5 Other Distributions</h6><blockquote></blockquote><h5 id="5-4-bpftrace工具"><a href="#5-4-bpftrace工具" class="headerlink" title="5.4 bpftrace工具"></a>5.4 bpftrace工具</h5><h6 id="5-4-1-Highlighted-Tools"><a href="#5-4-1-Highlighted-Tools" class="headerlink" title="5.4.1 Highlighted Tools"></a>5.4.1 Highlighted Tools</h6><h6 id="5-4-2-Tool-Characteristics"><a href="#5-4-2-Tool-Characteristics" class="headerlink" title="5.4.2 Tool Characteristics"></a>5.4.2 Tool Characteristics</h6><h6 id="5-4-3-Tool-Execution"><a href="#5-4-3-Tool-Execution" class="headerlink" title="5.4.3 Tool Execution"></a>5.4.3 Tool Execution</h6><blockquote></blockquote><h5 id="5-5-bpftrace单行程序"><a href="#5-5-bpftrace单行程序" class="headerlink" title="5.5 bpftrace单行程序"></a>5.5 bpftrace单行程序</h5><blockquote></blockquote><h5 id="5-6-bpftrace的文档"><a href="#5-6-bpftrace的文档" class="headerlink" title="5.6 bpftrace的文档"></a>5.6 bpftrace的文档</h5><blockquote></blockquote><h5 id="5-7-bpftrace编程"><a href="#5-7-bpftrace编程" class="headerlink" title="5.7 bpftrace编程"></a>5.7 bpftrace编程</h5><h6 id="5-7-1-Usage"><a href="#5-7-1-Usage" class="headerlink" title="5.7.1 Usage"></a>5.7.1 Usage</h6><h6 id="5-7-2-Program-Structure"><a href="#5-7-2-Program-Structure" class="headerlink" title="5.7.2 Program Structure"></a>5.7.2 Program Structure</h6><h6 id="5-7-3-Comments"><a href="#5-7-3-Comments" class="headerlink" title="5.7.3 Comments"></a>5.7.3 Comments</h6><h6 id="5-7-4-Probe-Format"><a href="#5-7-4-Probe-Format" class="headerlink" title="5.7.4 Probe Format"></a>5.7.4 Probe Format</h6><h6 id="5-7-5-Probe-Wildcards"><a href="#5-7-5-Probe-Wildcards" class="headerlink" title="5.7.5 Probe Wildcards"></a>5.7.5 Probe Wildcards</h6><h6 id="5-7-6-Filters"><a href="#5-7-6-Filters" class="headerlink" title="5.7.6 Filters"></a>5.7.6 Filters</h6><h6 id="5-7-7-Actions"><a href="#5-7-7-Actions" class="headerlink" title="5.7.7 Actions"></a>5.7.7 Actions</h6><h6 id="5-7-8-Hello-World"><a href="#5-7-8-Hello-World" class="headerlink" title="5.7.8 Hello, World!"></a>5.7.8 Hello, World!</h6><h6 id="5-7-9-Functions"><a href="#5-7-9-Functions" class="headerlink" title="5.7.9 Functions"></a>5.7.9 Functions</h6><h6 id="5-7-10-Variables"><a href="#5-7-10-Variables" class="headerlink" title="5.7.10 Variables"></a>5.7.10 Variables</h6><h6 id="5-7-11-Map-Functions"><a href="#5-7-11-Map-Functions" class="headerlink" title="5.7.11 Map Functions"></a>5.7.11 Map Functions</h6><h6 id="5-7-12-Timing-vfs-read"><a href="#5-7-12-Timing-vfs-read" class="headerlink" title="5.7.12 Timing vfs_read()"></a>5.7.12 Timing vfs_read()</h6><blockquote></blockquote><h5 id="5-8-bpftrace的帮助信息"><a href="#5-8-bpftrace的帮助信息" class="headerlink" title="5.8 bpftrace的帮助信息"></a>5.8 bpftrace的帮助信息</h5><blockquote></blockquote><h5 id="5-9-bpftrace的探针类型"><a href="#5-9-bpftrace的探针类型" class="headerlink" title="5.9 bpftrace的探针类型"></a>5.9 bpftrace的探针类型</h5><h6 id="5-9-1-tracepoint"><a href="#5-9-1-tracepoint" class="headerlink" title="5.9.1 tracepoint"></a>5.9.1 tracepoint</h6><h6 id="5-9-2-usdt"><a href="#5-9-2-usdt" class="headerlink" title="5.9.2 usdt"></a>5.9.2 usdt</h6><h6 id="5-9-3-kprobe-and-kretprobe"><a href="#5-9-3-kprobe-and-kretprobe" class="headerlink" title="5.9.3 kprobe and kretprobe"></a>5.9.3 kprobe and kretprobe</h6><h6 id="5-9-4-uprobe-and-uretprobe"><a href="#5-9-4-uprobe-and-uretprobe" class="headerlink" title="5.9.4 uprobe and uretprobe"></a>5.9.4 uprobe and uretprobe</h6><h6 id="5-9-5-software-and-hardware"><a href="#5-9-5-software-and-hardware" class="headerlink" title="5.9.5 software and hardware"></a>5.9.5 software and hardware</h6><h6 id="5-9-6-profile-and-interval"><a href="#5-9-6-profile-and-interval" class="headerlink" title="5.9.6 profile and interval"></a>5.9.6 profile and interval</h6><blockquote></blockquote><h5 id="5-10-bpftrace的控制流"><a href="#5-10-bpftrace的控制流" class="headerlink" title="5.10 bpftrace的控制流"></a>5.10 bpftrace的控制流</h5><h6 id="5-10-1-Filter"><a href="#5-10-1-Filter" class="headerlink" title="5.10.1 Filter"></a>5.10.1 Filter</h6><h6 id="5-10-2-Ternary-Operators"><a href="#5-10-2-Ternary-Operators" class="headerlink" title="5.10.2 Ternary Operators"></a>5.10.2 Ternary Operators</h6><h6 id="5-10-3-If-Statements"><a href="#5-10-3-If-Statements" class="headerlink" title="5.10.3 If Statements"></a>5.10.3 If Statements</h6><h6 id="5-10-4-Unrolled-Loops"><a href="#5-10-4-Unrolled-Loops" class="headerlink" title="5.10.4 Unrolled Loops"></a>5.10.4 Unrolled Loops</h6><h6 id="5-13-3-str"><a href="#5-13-3-str" class="headerlink" title="5.13.3 str()"></a>5.13.3 str()</h6><blockquote></blockquote><h5 id="5-11-bpftrace的运算符"><a href="#5-11-bpftrace的运算符" class="headerlink" title="5.11 bpftrace的运算符"></a>5.11 bpftrace的运算符</h5><blockquote></blockquote><h5 id="5-12-bpftrace的变量"><a href="#5-12-bpftrace的变量" class="headerlink" title="5.12 bpftrace的变量"></a>5.12 bpftrace的变量</h5><h6 id="5-12-1-Built-in-Variables"><a href="#5-12-1-Built-in-Variables" class="headerlink" title="5.12.1 Built-in Variables"></a>5.12.1 Built-in Variables</h6><h6 id="5-12-2-Built-ins-pid-comm-and-uid"><a href="#5-12-2-Built-ins-pid-comm-and-uid" class="headerlink" title="5.12.2 Built-ins: pid, comm, and uid"></a>5.12.2 Built-ins: pid, comm, and uid</h6><h6 id="5-12-3-Built-ins-kstack-and-ustack"><a href="#5-12-3-Built-ins-kstack-and-ustack" class="headerlink" title="5.12.3 Built-ins: kstack and ustack"></a>5.12.3 Built-ins: kstack and ustack</h6><h6 id="5-12-4-Built-ins-Positional-Parameters"><a href="#5-12-4-Built-ins-Positional-Parameters" class="headerlink" title="5.12.4 Built-ins: Positional Parameters"></a>5.12.4 Built-ins: Positional Parameters</h6><h6 id="5-12-5-Scratch"><a href="#5-12-5-Scratch" class="headerlink" title="5.12.5 Scratch"></a>5.12.5 Scratch</h6><h6 id="5-12-6-Maps"><a href="#5-12-6-Maps" class="headerlink" title="5.12.6 Maps"></a>5.12.6 Maps</h6><blockquote></blockquote><h5 id="5-13-bpftrace的函数"><a href="#5-13-bpftrace的函数" class="headerlink" title="5.13 bpftrace的函数"></a>5.13 bpftrace的函数</h5><h6 id="5-13-1-printf"><a href="#5-13-1-printf" class="headerlink" title="5.13.1 printf()"></a>5.13.1 printf()</h6><h6 id="5-13-2-join"><a href="#5-13-2-join" class="headerlink" title="5.13.2 join()"></a>5.13.2 join()</h6><h6 id="5-13-3-str-1"><a href="#5-13-3-str-1" class="headerlink" title="5.13.3 str()"></a>5.13.3 str()</h6><h6 id="5-13-4-kstack-and-ustack"><a href="#5-13-4-kstack-and-ustack" class="headerlink" title="5.13.4 kstack() and ustack()"></a>5.13.4 kstack() and ustack()</h6><h6 id="5-13-5-ksym-and-usym"><a href="#5-13-5-ksym-and-usym" class="headerlink" title="5.13.5 ksym() and usym()"></a>5.13.5 ksym() and usym()</h6><h6 id="5-13-6-kaddr-and-uaddr"><a href="#5-13-6-kaddr-and-uaddr" class="headerlink" title="5.13.6 kaddr() and uaddr()"></a>5.13.6 kaddr() and uaddr()</h6><h6 id="5-13-7-system"><a href="#5-13-7-system" class="headerlink" title="5.13.7 system()"></a>5.13.7 system()</h6><h6 id="5-13-8-exit"><a href="#5-13-8-exit" class="headerlink" title="5.13.8 exit()"></a>5.13.8 exit()</h6><blockquote></blockquote><h5 id="5-14-bpftrace映射表的操作函数"><a href="#5-14-bpftrace映射表的操作函数" class="headerlink" title="5.14 bpftrace映射表的操作函数"></a>5.14 bpftrace映射表的操作函数</h5><h6 id="5-14-1-count"><a href="#5-14-1-count" class="headerlink" title="5.14.1 count()"></a>5.14.1 count()</h6><h6 id="5-14-2-sum-avg-min-and-max"><a href="#5-14-2-sum-avg-min-and-max" class="headerlink" title="5.14.2 sum(), avg(), min(), and max()"></a>5.14.2 sum(), avg(), min(), and max()</h6><h6 id="5-14-3-hist"><a href="#5-14-3-hist" class="headerlink" title="5.14.3 hist()"></a>5.14.3 hist()</h6><h6 id="5-14-4-lhist"><a href="#5-14-4-lhist" class="headerlink" title="5.14.4 lhist()"></a>5.14.4 lhist()</h6><h6 id="5-14-5-delete"><a href="#5-14-5-delete" class="headerlink" title="5.14.5 delete()"></a>5.14.5 delete()</h6><blockquote></blockquote><h5 id="5-15-bpftrace的下一步工作"><a href="#5-15-bpftrace的下一步工作" class="headerlink" title="5.15 bpftrace的下一步工作"></a>5.15 bpftrace的下一步工作</h5><blockquote></blockquote><h5 id="5-16-bpftrace的内部运作"><a href="#5-16-bpftrace的内部运作" class="headerlink" title="5.16 bpftrace的内部运作"></a>5.16 bpftrace的内部运作</h5><blockquote></blockquote><h5 id="5-17-bpftrace的调试"><a href="#5-17-bpftrace的调试" class="headerlink" title="5.17 bpftrace的调试"></a>5.17 bpftrace的调试</h5><blockquote></blockquote><h4 id="第六章-CPU"><a href="#第六章-CPU" class="headerlink" title="第六章 CPU"></a>第六章 CPU</h4><h5 id="6-1-背景知识"><a href="#6-1-背景知识" class="headerlink" title="6.1 背景知识"></a>6.1 背景知识</h5><blockquote></blockquote><h5 id="6-2-传统工具"><a href="#6-2-传统工具" class="headerlink" title="6.2 传统工具"></a>6.2 传统工具</h5><blockquote></blockquote><h5 id="6-3-BPF工具"><a href="#6-3-BPF工具" class="headerlink" title="6.3 BPF工具"></a>6.3 BPF工具</h5><blockquote></blockquote><h5 id="6-4-BPF单行程序"><a href="#6-4-BPF单行程序" class="headerlink" title="6.4 BPF单行程序"></a>6.4 BPF单行程序</h5><blockquote></blockquote><h4 id="第七章-内存"><a href="#第七章-内存" class="headerlink" title="第七章 内存"></a>第七章 内存</h4><h5 id="7-1-背景知识"><a href="#7-1-背景知识" class="headerlink" title="7.1 背景知识"></a>7.1 背景知识</h5><blockquote></blockquote><h5 id="7-2-传统工具"><a href="#7-2-传统工具" class="headerlink" title="7.2 传统工具"></a>7.2 传统工具</h5><blockquote></blockquote><h5 id="7-3-BPF工具"><a href="#7-3-BPF工具" class="headerlink" title="7.3 BPF工具"></a>7.3 BPF工具</h5><blockquote></blockquote><h5 id="7-4-BPF单行程序"><a href="#7-4-BPF单行程序" class="headerlink" title="7.4 BPF单行程序"></a>7.4 BPF单行程序</h5><blockquote></blockquote><h4 id="第八章-文件系统"><a href="#第八章-文件系统" class="headerlink" title="第八章 文件系统"></a>第八章 文件系统</h4><h5 id="8-1-背景知识"><a href="#8-1-背景知识" class="headerlink" title="8.1 背景知识"></a>8.1 背景知识</h5><blockquote></blockquote><h5 id="8-2-传统工具"><a href="#8-2-传统工具" class="headerlink" title="8.2 传统工具"></a>8.2 传统工具</h5><blockquote></blockquote><h5 id="8-3-BPF工具"><a href="#8-3-BPF工具" class="headerlink" title="8.3 BPF工具"></a>8.3 BPF工具</h5><blockquote></blockquote><h5 id="8-4-BPF单行程序"><a href="#8-4-BPF单行程序" class="headerlink" title="8.4 BPF单行程序"></a>8.4 BPF单行程序</h5><h4 id="第九章-磁盘io"><a href="#第九章-磁盘io" class="headerlink" title="第九章 磁盘io"></a>第九章 磁盘io</h4><blockquote></blockquote><h5 id="9-1-背景知识"><a href="#9-1-背景知识" class="headerlink" title="9.1 背景知识"></a>9.1 背景知识</h5><blockquote></blockquote><h5 id="9-2-传统工具"><a href="#9-2-传统工具" class="headerlink" title="9.2 传统工具"></a>9.2 传统工具</h5><blockquote></blockquote><h5 id="9-3-BPF工具"><a href="#9-3-BPF工具" class="headerlink" title="9.3 BPF工具"></a>9.3 BPF工具</h5><blockquote></blockquote><h5 id="9-4-BPF单行程序"><a href="#9-4-BPF单行程序" class="headerlink" title="9.4 BPF单行程序"></a>9.4 BPF单行程序</h5><blockquote></blockquote><h4 id="第十章-网络"><a href="#第十章-网络" class="headerlink" title="第十章 网络"></a>第十章 网络</h4><h5 id="10-1-背景知识"><a href="#10-1-背景知识" class="headerlink" title="10.1 背景知识"></a>10.1 背景知识</h5><blockquote></blockquote><h5 id="10-2-传统工具"><a href="#10-2-传统工具" class="headerlink" title="10.2 传统工具"></a>10.2 传统工具</h5><blockquote></blockquote><h5 id="10-3-BPF工具"><a href="#10-3-BPF工具" class="headerlink" title="10.3 BPF工具"></a>10.3 BPF工具</h5><blockquote></blockquote><h5 id="10-4-BPF单行程序"><a href="#10-4-BPF单行程序" class="headerlink" title="10.4 BPF单行程序"></a>10.4 BPF单行程序</h5><blockquote></blockquote><h4 id="第十一章-安全"><a href="#第十一章-安全" class="headerlink" title="第十一章 安全"></a>第十一章 安全</h4><h5 id="11-1-背景知识"><a href="#11-1-背景知识" class="headerlink" title="11.1 背景知识"></a>11.1 背景知识</h5><blockquote></blockquote><h5 id="11-2-BPF工具"><a href="#11-2-BPF工具" class="headerlink" title="11.2 BPF工具"></a>11.2 BPF工具</h5><blockquote></blockquote><h5 id="11-3-BPF单行程序"><a href="#11-3-BPF单行程序" class="headerlink" title="11.3 BPF单行程序"></a>11.3 BPF单行程序</h5><blockquote></blockquote><h4 id="第十二章-编程语言"><a href="#第十二章-编程语言" class="headerlink" title="第十二章 编程语言"></a>第十二章 编程语言</h4><blockquote></blockquote><h5 id="12-1-背景知识"><a href="#12-1-背景知识" class="headerlink" title="12.1 背景知识"></a>12.1 背景知识</h5><blockquote></blockquote><h5 id="12-2-C"><a href="#12-2-C" class="headerlink" title="12.2 C"></a>12.2 C</h5><blockquote></blockquote><h5 id="12-3-Java"><a href="#12-3-Java" class="headerlink" title="12.3 Java"></a>12.3 Java</h5><blockquote></blockquote><h5 id="12-4-bash-shell"><a href="#12-4-bash-shell" class="headerlink" title="12.4 bash shell"></a>12.4 bash shell</h5><blockquote></blockquote><h5 id="12-5-其他语言"><a href="#12-5-其他语言" class="headerlink" title="12.5 其他语言"></a>12.5 其他语言</h5><blockquote></blockquote><h4 id="第十三章-应用程序"><a href="#第十三章-应用程序" class="headerlink" title="第十三章 应用程序"></a>第十三章 应用程序</h4><h5 id="13-1-背景知识"><a href="#13-1-背景知识" class="headerlink" title="13.1 背景知识"></a>13.1 背景知识</h5><blockquote></blockquote><h5 id="13-2-BPF工具"><a href="#13-2-BPF工具" class="headerlink" title="13.2 BPF工具"></a>13.2 BPF工具</h5><blockquote></blockquote><h5 id="13-3-单行程序"><a href="#13-3-单行程序" class="headerlink" title="13.3 单行程序"></a>13.3 单行程序</h5><blockquote></blockquote><h5 id="13-4-BPF单行程序示例"><a href="#13-4-BPF单行程序示例" class="headerlink" title="13.4 BPF单行程序示例"></a>13.4 BPF单行程序示例</h5><blockquote></blockquote><h4 id="第十四章-内核"><a href="#第十四章-内核" class="headerlink" title="第十四章 内核"></a>第十四章 内核</h4><blockquote></blockquote><h5 id="14-1-背景知识"><a href="#14-1-背景知识" class="headerlink" title="14.1 背景知识"></a>14.1 背景知识</h5><blockquote></blockquote><h5 id="14-2-分析策略"><a href="#14-2-分析策略" class="headerlink" title="14.2 分析策略"></a>14.2 分析策略</h5><blockquote></blockquote><h5 id="14-3-传统工具"><a href="#14-3-传统工具" class="headerlink" title="14.3 传统工具"></a>14.3 传统工具</h5><blockquote></blockquote><h5 id="14-4-BPF工具"><a href="#14-4-BPF工具" class="headerlink" title="14.4 BPF工具"></a>14.4 BPF工具</h5><blockquote></blockquote><h5 id="14-5-BPF单行程序"><a href="#14-5-BPF单行程序" class="headerlink" title="14.5 BPF单行程序"></a>14.5 BPF单行程序</h5><blockquote></blockquote><h5 id="14-6-BPF单行程序示例"><a href="#14-6-BPF单行程序示例" class="headerlink" title="14.6 BPF单行程序示例"></a>14.6 BPF单行程序示例</h5><blockquote></blockquote><h4 id="第十五章-容器"><a href="#第十五章-容器" class="headerlink" title="第十五章 容器"></a>第十五章 容器</h4><blockquote></blockquote><h5 id="15-1-背景知识"><a href="#15-1-背景知识" class="headerlink" title="15.1 背景知识"></a>15.1 背景知识</h5><blockquote></blockquote><h5 id="15-2-传统工具"><a href="#15-2-传统工具" class="headerlink" title="15.2 传统工具"></a>15.2 传统工具</h5><blockquote></blockquote><h5 id="15-3-BPF工具"><a href="#15-3-BPF工具" class="headerlink" title="15.3 BPF工具"></a>15.3 BPF工具</h5><blockquote></blockquote><h5 id="15-4-BPF单行程序"><a href="#15-4-BPF单行程序" class="headerlink" title="15.4 BPF单行程序"></a>15.4 BPF单行程序</h5><blockquote></blockquote><h5 id="15-5-可选练习"><a href="#15-5-可选练习" class="headerlink" title="15.5 可选练习"></a>15.5 可选练习</h5><blockquote></blockquote><h4 id="第十六章-虚拟机管理器"><a href="#第十六章-虚拟机管理器" class="headerlink" title="第十六章 虚拟机管理器"></a>第十六章 虚拟机管理器</h4><blockquote></blockquote><h5 id="16-1-背景知识"><a href="#16-1-背景知识" class="headerlink" title="16.1 背景知识"></a>16.1 背景知识</h5><blockquote></blockquote><h5 id="16-2-传统工具"><a href="#16-2-传统工具" class="headerlink" title="16.2 传统工具"></a>16.2 传统工具</h5><blockquote></blockquote><h5 id="16-3-访客系统的BPF工具"><a href="#16-3-访客系统的BPF工具" class="headerlink" title="16.3 访客系统的BPF工具"></a>16.3 访客系统的BPF工具</h5><blockquote></blockquote><h5 id="16-4-宿主机的BPF工具"><a href="#16-4-宿主机的BPF工具" class="headerlink" title="16.4 宿主机的BPF工具"></a>16.4 宿主机的BPF工具</h5><blockquote></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h3 id="第二章"><a href="#第二章" class="headerlink" title="第二章"></a>第二章</h3><h4
</summary>
<category term="BPF" scheme="https://weeweetan.github.io/categories/BPF/"/>
<category term="BPF" scheme="https://weeweetan.github.io/tags/BPF/"/>
</entry>
<entry>
<title>Nginx的mirror模块详解</title>
<link href="https://weeweetan.github.io/2023/12/14/Nginx%E7%9A%84mirror%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2023/12/14/Nginx的mirror模块详解/</id>
<published>2023-12-14T14:28:05.000Z</published>
<updated>2024-02-28T14:33:13.923Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Syntax:mirror uri | off;</span><br><span class="line">Default:</span><br><span class="line">mirror off;</span><br><span class="line">Context:http, server, location</span><br><span class="line"></span><br><span class="line">Syntax:mirror_request_body on | off;</span><br><span class="line">Default:</span><br><span class="line">mirror_request_body on;</span><br><span class="line">Context:http, server, location</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="2-配置解析函数"><a href="#2-配置解析函数" class="headerlink" title="2.配置解析函数"></a>2.配置解析函数</h2><blockquote><p>首先看下指令mirror的配置解析函数ngx_http_mirror的实现<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_mirror(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_mirror_loc_conf_t</span> *mlcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, *s;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">//判断参数是否为off</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">1</span>].data, <span class="string">"off"</span>) == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (mlcf->mirror != NGX_CONF_UNSET_PTR) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> mlcf->mirror = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (mlcf->mirror == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 构造数组mlcf->mirror</span></span><br><span class="line"> <span class="keyword">if</span> (mlcf->mirror == NGX_CONF_UNSET_PTR) {</span><br><span class="line"> mlcf->mirror = ngx_array_create(cf->pool, <span class="number">4</span>, <span class="keyword">sizeof</span>(<span class="keyword">ngx_str_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (mlcf->mirror == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// push一个数组元素,用于保存mirror配置</span></span><br><span class="line"> s = ngx_array_push(mlcf->mirror);</span><br><span class="line"> <span class="keyword">if</span> (s == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 保存参数,也就是url</span></span><br><span class="line"> *s = value[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看看handler函数ngx_http_mirror_handler的实现<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_mirror_handler(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_int_t</span> rc;</span><br><span class="line"> <span class="keyword">ngx_http_mirror_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_http_mirror_loc_conf_t</span> *mlcf;</span><br><span class="line"> <span class="comment">// 子请求,直接返回</span></span><br><span class="line"> <span class="keyword">if</span> (r != r->main) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 获取location级别的配置</span></span><br><span class="line"> mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);</span><br><span class="line"> <span class="comment">// 没有配置mirror,直接返回</span></span><br><span class="line"> <span class="keyword">if</span> (mlcf->mirror == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>, <span class="string">"mirror handler"</span>);</span><br><span class="line"> <span class="comment">// 处理请求body</span></span><br><span class="line"> <span class="keyword">if</span> (mlcf->request_body) {</span><br><span class="line"> ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx) {</span><br><span class="line"> <span class="keyword">return</span> ctx->status;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 申请ctx内存</span></span><br><span class="line"> ctx = ngx_pcalloc(r->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_mirror_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->status = NGX_DONE;</span><br><span class="line"> <span class="comment">// 设置ctx</span></span><br><span class="line"> ngx_http_set_ctx(r, ctx, ngx_http_mirror_module);</span><br><span class="line"> <span class="comment">// 读request_body</span></span><br><span class="line"> rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler);</span><br><span class="line"> <span class="keyword">if</span> (rc >= NGX_HTTP_SPECIAL_RESPONSE) {</span><br><span class="line"> <span class="keyword">return</span> rc;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 结束请求</span></span><br><span class="line"> ngx_http_finalize_request(r, NGX_DONE);</span><br><span class="line"> <span class="keyword">return</span> NGX_DONE;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 调用handler</span></span><br><span class="line"> <span class="keyword">return</span> ngx_http_mirror_handler_internal(r);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看看ngx_http_mirror_body_handler处理逻辑<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">void</span></span><br><span class="line">ngx_http_mirror_body_handler(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_mirror_ctx_t</span> *ctx;</span><br><span class="line"> <span class="comment">// get ctx</span></span><br><span class="line"> ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module);</span><br><span class="line"> <span class="comment">//调用internal</span></span><br><span class="line"> ctx->status = ngx_http_mirror_handler_internal(r);</span><br><span class="line"></span><br><span class="line"> r->preserve_body = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 重新执行各个阶段</span></span><br><span class="line"> r->write_event_handler = ngx_http_core_run_phases;</span><br><span class="line"> ngx_http_core_run_phases(r);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看下ngx_http_mirror_init的处理逻辑<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_mirror_init(<span class="keyword">ngx_conf_t</span> *cf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_handler_pt *h;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);</span><br><span class="line"> <span class="comment">// precontent阶段,push出一个元素,用于保存handler</span></span><br><span class="line"> h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers);</span><br><span class="line"> <span class="keyword">if</span> (h == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// handler赋值</span></span><br><span class="line"> *h = ngx_http_mirror_handler;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看看ngx_http_mirror_handler_internal实现,主要是遍历所有mirror指令,创建子请求<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_mirror_handler_internal(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *name;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_http_request_t</span> *sr;</span><br><span class="line"> <span class="keyword">ngx_http_mirror_loc_conf_t</span> *mlcf;</span><br><span class="line"></span><br><span class="line"> mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module);</span><br><span class="line"></span><br><span class="line"> name = mlcf->mirror->elts;</span><br><span class="line"> <span class="comment">// 遍历location下的mirror指令</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < mlcf->mirror->nelts; i++) {</span><br><span class="line"> <span class="comment">//创建子请求</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_subrequest(r, &name[i], &r->args, &sr, <span class="literal">NULL</span>,</span><br><span class="line"> NGX_HTTP_SUBREQUEST_BACKGROUND)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> sr->header_only = <span class="number">1</span>;</span><br><span class="line"> sr->method = r->method;</span><br><span class="line"> sr->method_name = r->method_name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>以上就是mirror模块主要功能<p></p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的auth_basic模块详解</title>
<link href="https://weeweetan.github.io/2023/09/21/Nginx%E7%9A%84auth-basic%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2023/09/21/Nginx的auth-basic模块详解/</id>
<published>2023-09-21T15:14:35.000Z</published>
<updated>2024-03-08T14:38:03.899Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">Syntax:auth_basic <span class="built_in">string</span> | off;</span><br><span class="line">Default:</span><br><span class="line">auth_basic off;</span><br><span class="line">Context:http, server, location, limit_except</span><br><span class="line"></span><br><span class="line">Syntax:auth_basic_user_file file;</span><br><span class="line">Default:—</span><br><span class="line">Context:http, server, location, limit_except</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="2-配置解析函数"><a href="#2-配置解析函数" class="headerlink" title="2.配置解析函数"></a>2.配置解析函数</h2><blockquote><p>首先看下指令auth_basic的配置解析函数ngx_http_set_complex_value_slot,这是个通用的函数,这里不再赘述<br>接下来看下指令auth_basic_user_file的配置解析函数<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_auth_basic_user_file(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// 模块配置</span></span><br><span class="line"> <span class="keyword">ngx_http_auth_basic_loc_conf_t</span> *alcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_http_compile_complex_value_t</span> ccv;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 判断是否重复设置</span></span><br><span class="line"> <span class="keyword">if</span> (alcf->user_file != NGX_CONF_UNSET_PTR) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//申请内存</span></span><br><span class="line"> alcf->user_file = ngx_palloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_complex_value_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (alcf->user_file == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">// 初始化变量</span></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[<span class="number">1</span>];</span><br><span class="line"> ccv.complex_value = alcf->user_file;</span><br><span class="line"> ccv.zero = <span class="number">1</span>;</span><br><span class="line"> ccv.conf_prefix = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">// 编译变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h2 id="3-handler函数"><a href="#3-handler函数" class="headerlink" title="3.handler函数"></a>3.handler函数</h2><blockquote><p>1.接下来看下ngx_http_auth_basic_handler的实现<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_auth_basic_handler(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">off_t</span> offset;</span><br><span class="line"> <span class="keyword">ssize_t</span> n;</span><br><span class="line"> <span class="keyword">ngx_fd_t</span> fd;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> rc;</span><br><span class="line"> <span class="keyword">ngx_err_t</span> err;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> pwd, realm, user_file;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, level, login, left, passwd;</span><br><span class="line"> <span class="keyword">ngx_file_t</span> file;</span><br><span class="line"> <span class="keyword">ngx_http_auth_basic_loc_conf_t</span> *alcf;</span><br><span class="line"> u_char buf[NGX_HTTP_AUTH_BUF_SIZE];</span><br><span class="line"> <span class="keyword">enum</span> {</span><br><span class="line"> sw_login,</span><br><span class="line"> sw_passwd,</span><br><span class="line"> sw_skip</span><br><span class="line"> } state;</span><br><span class="line"></span><br><span class="line"> alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (alcf->realm == <span class="literal">NULL</span> || alcf->user_file == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 编译变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (realm.len == <span class="number">3</span> && ngx_strncmp(realm.data, <span class="string">"off"</span>, <span class="number">3</span>) == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 从authorization header中解析出user以及password</span></span><br><span class="line"> rc = ngx_http_auth_basic_user(r);</span><br><span class="line"> <span class="comment">// 没有解析出user password, 添加必要header,返回401</span></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_DECLINED) {</span><br><span class="line"></span><br><span class="line"> ngx_log_error(NGX_LOG_INFO, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"no user/password was provided for basic authentication"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ngx_http_auth_basic_set_realm(r, &realm);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 编译变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_complex_value(r, alcf->user_file, &user_file) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 打开文件</span></span><br><span class="line"> fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, <span class="number">0</span>);</span><br><span class="line"> <span class="comment">// 打开失败</span></span><br><span class="line"> <span class="keyword">if</span> (fd == NGX_INVALID_FILE) {</span><br><span class="line"> err = ngx_errno;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (err == NGX_ENOENT) {</span><br><span class="line"> level = NGX_LOG_ERR;</span><br><span class="line"> rc = NGX_HTTP_FORBIDDEN;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> level = NGX_LOG_CRIT;</span><br><span class="line"> rc = NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_error(level, r->connection-><span class="built_in">log</span>, err,</span><br><span class="line"> ngx_open_file_n <span class="string">" \"%s\" failed"</span>, user_file.data);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rc;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&file, <span class="keyword">sizeof</span>(<span class="keyword">ngx_file_t</span>));</span><br><span class="line"></span><br><span class="line"> file.fd = fd;</span><br><span class="line"> file.name = user_file;</span><br><span class="line"> file.<span class="built_in">log</span> = r->connection-><span class="built_in">log</span>;</span><br><span class="line"></span><br><span class="line"> state = sw_login;</span><br><span class="line"> passwd = <span class="number">0</span>;</span><br><span class="line"> login = <span class="number">0</span>;</span><br><span class="line"> left = <span class="number">0</span>;</span><br><span class="line"> offset = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> ( ;; ) {</span><br><span class="line"> i = left;</span><br><span class="line"> <span class="comment">// 读文件</span></span><br><span class="line"> n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,</span><br><span class="line"> offset);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n == NGX_ERROR) {</span><br><span class="line"> rc = NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> <span class="keyword">goto</span> cleanup;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 文件读完</span></span><br><span class="line"> <span class="keyword">if</span> (n == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 状态机处理</span></span><br><span class="line"> <span class="keyword">for</span> (i = left; i < left + n; i++) {</span><br><span class="line"> <span class="keyword">switch</span> (state) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> sw_login:</span><br><span class="line"> <span class="keyword">if</span> (login == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// 跳过注释</span></span><br><span class="line"> <span class="keyword">if</span> (buf[i] == <span class="string">'#'</span> || buf[i] == CR) {</span><br><span class="line"> state = sw_skip;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 跳过换行符</span></span><br><span class="line"> <span class="keyword">if</span> (buf[i] == LF) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 长度不匹配,直接跳过</span></span><br><span class="line"> <span class="keyword">if</span> (buf[i] != r->headers_in.user.data[login]) {</span><br><span class="line"> state = sw_skip;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//username匹配完成</span></span><br><span class="line"> <span class="keyword">if</span> (login == r->headers_in.user.len) {</span><br><span class="line"> state = sw_passwd;</span><br><span class="line"> passwd = i + <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> login++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="comment">//开始解析密码</span></span><br><span class="line"> <span class="keyword">case</span> sw_passwd:</span><br><span class="line"> <span class="keyword">if</span> (buf[i] == LF || buf[i] == CR || buf[i] == <span class="string">':'</span>) {</span><br><span class="line"> buf[i] = <span class="string">'\0'</span>;</span><br><span class="line"></span><br><span class="line"> pwd.len = i - passwd;</span><br><span class="line"> pwd.data = &buf[passwd];</span><br><span class="line"> <span class="comment">//处理密码</span></span><br><span class="line"> rc = ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);</span><br><span class="line"> <span class="keyword">goto</span> cleanup;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> sw_skip:</span><br><span class="line"> <span class="keyword">if</span> (buf[i] == LF) {</span><br><span class="line"> state = sw_login;</span><br><span class="line"> login = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//密码没有解析完,继续解析</span></span><br><span class="line"> <span class="keyword">if</span> (state == sw_passwd) {</span><br><span class="line"> left = left + n - passwd;</span><br><span class="line"> ngx_memmove(buf, &buf[passwd], left);</span><br><span class="line"> passwd = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> left = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 偏移n</span></span><br><span class="line"> offset += n;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 解析到密码段</span></span><br><span class="line"> <span class="keyword">if</span> (state == sw_passwd) {</span><br><span class="line"> pwd.len = i - passwd;</span><br><span class="line"> pwd.data = ngx_pnalloc(r->pool, pwd.len + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (pwd.data == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//拷贝密码</span></span><br><span class="line"> ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + <span class="number">1</span>);</span><br><span class="line"> <span class="comment">//对密码进行处理</span></span><br><span class="line"> rc = ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);</span><br><span class="line"> <span class="keyword">goto</span> cleanup;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_error(NGX_LOG_ERR, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"user \"%V\" was not found in \"%s\""</span>,</span><br><span class="line"> &r->headers_in.user, user_file.data);</span><br><span class="line"> <span class="comment">// 调用函数,设置auth header</span></span><br><span class="line"> rc = ngx_http_auth_basic_set_realm(r, &realm);</span><br><span class="line"></span><br><span class="line">cleanup:</span><br><span class="line"> <span class="comment">// 关闭文件</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_close_file(file.fd) == NGX_FILE_ERROR) {</span><br><span class="line"> ngx_log_error(NGX_LOG_ALERT, r->connection-><span class="built_in">log</span>, ngx_errno,</span><br><span class="line"> ngx_close_file_n <span class="string">" \"%s\" failed"</span>, user_file.data);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_explicit_memzero(buf, NGX_HTTP_AUTH_BUF_SIZE);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rc;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>接下来看下ngx_http_auth_basic_crypt_handler函数实现<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">static ngx_int_t</span><br><span class="line">ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, ngx_str_t *passwd,</span><br><span class="line"> ngx_str_t *realm)</span><br><span class="line">{</span><br><span class="line"> ngx_int_t rc;</span><br><span class="line"> u_char *encrypted;</span><br><span class="line"> // 使用header中的passwd作为key进行编码</span><br><span class="line"> rc = ngx_crypt(r->pool, r->headers_in.passwd.data, passwd->data,</span><br><span class="line"> &encrypted);</span><br><span class="line"></span><br><span class="line"> ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</span><br><span class="line"> "rc: %i user: \"%V\" salt: \"%s\"",</span><br><span class="line"> rc, &r->headers_in.user, passwd->data);</span><br><span class="line"></span><br><span class="line"> if (rc != NGX_OK) {</span><br><span class="line"> return NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"> // 比较编码后的字符串</span><br><span class="line"> if (ngx_strcmp(encrypted, passwd->data) == 0) {</span><br><span class="line"> return NGX_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</span><br><span class="line"> "encrypted: \"%s\"", encrypted);</span><br><span class="line"></span><br><span class="line"> ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,</span><br><span class="line"> "user \"%V\": password mismatch",</span><br><span class="line"> &r->headers_in.user);</span><br><span class="line"></span><br><span class="line"> return ngx_http_auth_basic_set_realm(r, realm);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看看ngx_http_auth_basic_set_realm的函数实现<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">static ngx_int_t</span><br><span class="line">ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)</span><br><span class="line">{</span><br><span class="line"> size_t len;</span><br><span class="line"> u_char *basic, *p;</span><br><span class="line"> // 从headers list中获取一个元素</span><br><span class="line"> r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers);</span><br><span class="line"> if (r->headers_out.www_authenticate == NULL) {</span><br><span class="line"> return NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"> //初始化header len</span><br><span class="line"> len = sizeof("Basic realm=\"\"") - 1 + realm->len;</span><br><span class="line"> // 申请内存</span><br><span class="line"> basic = ngx_pnalloc(r->pool, len);</span><br><span class="line"> if (basic == NULL) {</span><br><span class="line"> r->headers_out.www_authenticate->hash = 0;</span><br><span class="line"> r->headers_out.www_authenticate = NULL;</span><br><span class="line"> return NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"> //复制header</span><br><span class="line"> p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1);</span><br><span class="line"> p = ngx_cpymem(p, realm->data, realm->len);</span><br><span class="line"> *p = '"';</span><br><span class="line"> // 设置header</span><br><span class="line"> r->headers_out.www_authenticate->hash = 1;</span><br><span class="line"> ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate");</span><br><span class="line"> r->headers_out.www_authenticate->value.data = basic;</span><br><span class="line"> r->headers_out.www_authenticate->value.len = len;</span><br><span class="line"> //返回401</span><br><span class="line"> return NGX_HTTP_UNAUTHORIZED;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>以上就是这个auth-basic模块的实现<p></p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的geoip模块详解</title>
<link href="https://weeweetan.github.io/2023/06/29/Nginx%E7%9A%84geoip%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2023/06/29/Nginx的geoip模块详解/</id>
<published>2023-06-29T15:06:24.000Z</published>
<updated>2023-09-20T14:50:43.033Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">Syntax:geoip_country file;</span><br><span class="line">Default:—</span><br><span class="line">Context:http</span><br><span class="line"></span><br><span class="line">Syntax:geoip_city file;</span><br><span class="line">Default:—</span><br><span class="line">Context:http</span><br><span class="line"></span><br><span class="line">Syntax:geoip_org file;</span><br><span class="line">Default:—</span><br><span class="line">Context:http</span><br><span class="line">This directive appeared in version <span class="number">1.0</span><span class="number">.3</span>.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">Syntax:geoip_proxy address | CIDR;</span><br><span class="line">Default:—</span><br><span class="line">Context:http</span><br><span class="line">This directive appeared in versions <span class="number">1.3</span><span class="number">.0</span> <span class="keyword">and</span> <span class="number">1.2</span><span class="number">.1</span>.</span><br><span class="line"></span><br><span class="line">Syntax:geoip_proxy_recursive on | off;</span><br><span class="line">Default:</span><br><span class="line">geoip_proxy_recursive off;</span><br><span class="line">Context:http</span><br><span class="line">This directive appeared in versions <span class="number">1.3</span><span class="number">.0</span> <span class="keyword">and</span> <span class="number">1.2</span><span class="number">.1</span>.</span><br></pre></td></tr></table></figure><h2 id="2-配置解析函数"><a href="#2-配置解析函数" class="headerlink" title="2.配置解析函数"></a>2.配置解析函数</h2><blockquote><p>首先看下配置解析函数ngx_http_geoip_country<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geoip_country(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_geoip_conf_t</span> *gcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="comment">//重复配置校验</span></span><br><span class="line"> <span class="keyword">if</span> (gcf->country) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 获取指令后面的参数</span></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">// 打开数据文件</span></span><br><span class="line"> gcf->country = GeoIP_open((<span class="keyword">char</span> *) value[<span class="number">1</span>].data, GEOIP_MEMORY_CACHE);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (gcf->country == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"GeoIP_open(\"%V\") failed"</span>, &value[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 判断参数个数,设置编码格式</span></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">3</span>) {</span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">2</span>].data, <span class="string">"utf8"</span>) == <span class="number">0</span>) {</span><br><span class="line"> GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"%V\""</span>, &value[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> (gcf->country->databaseType) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> GEOIP_COUNTRY_EDITION:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_GEOIP_V6)</span></span><br><span class="line"> <span class="keyword">case</span> GEOIP_COUNTRY_EDITION_V6:</span><br><span class="line"></span><br><span class="line"> gcf->country_v6 = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid GeoIP database \"%V\" type:%d"</span>,</span><br><span class="line"> &value[<span class="number">1</span>], gcf->country->databaseType);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>接下来看下配置解析函数ngx_http_geoip_org<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geoip_org(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_geoip_conf_t</span> *gcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="comment">// 重复配置检查</span></span><br><span class="line"> <span class="keyword">if</span> (gcf->org) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">// 打开数据文件</span></span><br><span class="line"> gcf->org = GeoIP_open((<span class="keyword">char</span> *) value[<span class="number">1</span>].data, GEOIP_MEMORY_CACHE);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (gcf->org == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"GeoIP_open(\"%V\") failed"</span>, &value[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置文件编码格式</span></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">3</span>) {</span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">2</span>].data, <span class="string">"utf8"</span>) == <span class="number">0</span>) {</span><br><span class="line"> GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"%V\""</span>, &value[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//选择数据类型</span></span><br><span class="line"> <span class="keyword">switch</span> (gcf->org->databaseType) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> GEOIP_ISP_EDITION:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_ORG_EDITION:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_DOMAIN_EDITION:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_ASNUM_EDITION:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_GEOIP_V6)</span></span><br><span class="line"> <span class="keyword">case</span> GEOIP_ISP_EDITION_V6:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_ORG_EDITION_V6:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_DOMAIN_EDITION_V6:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_ASNUM_EDITION_V6:</span><br><span class="line"></span><br><span class="line"> gcf->org_v6 = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid GeoIP database \"%V\" type:%d"</span>,</span><br><span class="line"> &value[<span class="number">1</span>], gcf->org->databaseType);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看下配置解析函数ngx_http_geoip_city<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geoip_city(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_geoip_conf_t</span> *gcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="comment">// 重复设置判断</span></span><br><span class="line"> <span class="keyword">if</span> (gcf->city) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">// 打开数据文件</span></span><br><span class="line"> gcf->city = GeoIP_open((<span class="keyword">char</span> *) value[<span class="number">1</span>].data, GEOIP_MEMORY_CACHE);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (gcf->city == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"GeoIP_open(\"%V\") failed"</span>, &value[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//处理编码格式</span></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">3</span>) {</span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">2</span>].data, <span class="string">"utf8"</span>) == <span class="number">0</span>) {</span><br><span class="line"> GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"%V\""</span>, &value[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 针对数据类型做处理</span></span><br><span class="line"> <span class="keyword">switch</span> (gcf->city->databaseType) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> GEOIP_CITY_EDITION_REV0:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_CITY_EDITION_REV1:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_GEOIP_V6)</span></span><br><span class="line"> <span class="keyword">case</span> GEOIP_CITY_EDITION_REV0_V6:</span><br><span class="line"> <span class="keyword">case</span> GEOIP_CITY_EDITION_REV1_V6:</span><br><span class="line"></span><br><span class="line"> gcf->city_v6 = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid GeoIP City database \"%V\" type:%d"</span>,</span><br><span class="line"> &value[<span class="number">1</span>], gcf->city->databaseType);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看下配置解析函数ngx_http_geoip_proxy<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geoip_proxy(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_geoip_srv_conf_t</span> *gscf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_cidr_t</span> cidr, *c;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> <span class="comment">// 解析cidr地址</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_geoip_cidr_value(cf, &value[<span class="number">1</span>], &cidr) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 初始化proxy数组</span></span><br><span class="line"> <span class="keyword">if</span> (gscf->proxies == NGX_CONF_UNSET_PTR) {</span><br><span class="line"> gscf->proxies = ngx_array_create(cf->pool, <span class="number">4</span>, <span class="keyword">sizeof</span>(<span class="keyword">ngx_cidr_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (gscf->proxies == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// push 一个元素用于保存cidr</span></span><br><span class="line"> c = ngx_array_push(gscf->proxies);</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 保存cidr地址</span></span><br><span class="line"> *c = cidr;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>指令geoip_proxy_recursive使用原生函数ngx_conf_set_flag_slot,这里就不再赘述<p></p></blockquote><h2 id="3-hander函数"><a href="#3-hander函数" class="headerlink" title="3.hander函数"></a>3.hander函数</h2><blockquote><p>此模块没有handler函数</p></blockquote><h2 id="4-变量处理函数"><a href="#4-变量处理函数" class="headerlink" title="4.变量处理函数"></a>4.变量处理函数</h2><blockquote><p>此模块功能都是为变量实现,所以主要函数都是为变量实现<br>首先来看下变量geoip_country_code的处理函数ngx_http_geoip_country_variable<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_geoip_country_variable(<span class="keyword">ngx_http_request_t</span> *r,</span><br><span class="line"> <span class="keyword">ngx_http_variable_value_t</span> *v, <span class="keyword">uintptr_t</span> data)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// 根据data类型获取对应函数指针,ngx_http_geoip_country_functions在代码有定义</span></span><br><span class="line"> ngx_http_geoip_variable_handler_pt handler =</span><br><span class="line"> ngx_http_geoip_country_functions[data];</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_GEOIP_V6)</span></span><br><span class="line"> ngx_http_geoip_variable_handler_v6_pt handler_v6 =</span><br><span class="line"> ngx_http_geoip_country_v6_functions[data];</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> <span class="keyword">char</span> *val;</span><br><span class="line"> <span class="keyword">ngx_http_geoip_conf_t</span> *gcf;</span><br><span class="line"> <span class="comment">// 获取main级别conf</span></span><br><span class="line"> gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);</span><br><span class="line"> <span class="comment">// 没有配置country数据</span></span><br><span class="line"> <span class="keyword">if</span> (gcf->country == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">goto</span> not_found;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//在handler内部调用ngx_http_geoip_addr</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_GEOIP_V6)</span></span><br><span class="line"> val = gcf->country_v6</span><br><span class="line"> ? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf))</span><br><span class="line"> : handler(gcf->country, ngx_http_geoip_addr(r, gcf));</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (val == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">goto</span> not_found;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//为变量赋值</span></span><br><span class="line"> v->len = ngx_strlen(val);</span><br><span class="line"> v->valid = <span class="number">1</span>;</span><br><span class="line"> v->no_cacheable = <span class="number">0</span>;</span><br><span class="line"> v->not_found = <span class="number">0</span>;</span><br><span class="line"> v->data = (u_char *) val;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line"></span><br><span class="line">not_found:</span><br><span class="line"></span><br><span class="line"> v->not_found = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看看ngx_http_geoip_addr函数实现<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> u_long</span><br><span class="line">ngx_http_geoip_addr(<span class="keyword">ngx_http_request_t</span> *r, <span class="keyword">ngx_http_geoip_conf_t</span> *gcf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_addr_t</span> addr;</span><br><span class="line"> <span class="keyword">ngx_array_t</span> *xfwd;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> *<span class="title">sin</span>;</span></span><br><span class="line"></span><br><span class="line"> addr.sockaddr = r->connection->sockaddr;</span><br><span class="line"> addr.socklen = r->connection->socklen;</span><br><span class="line"> <span class="comment">/* addr.name = r->connection->addr_text; */</span></span><br><span class="line"></span><br><span class="line"> xfwd = &r->headers_in.x_forwarded_for;</span><br><span class="line"> <span class="comment">//获取server级别配置</span></span><br><span class="line"> <span class="keyword">ngx_http_geoip_srv_conf_t</span> *gscf = ngx_http_get_module_srv_conf(r, ngx_http_geoip_module);</span><br><span class="line"> <span class="comment">//从xff头中获取ip</span></span><br><span class="line"> <span class="keyword">if</span> (xfwd->nelts > <span class="number">0</span> && gscf->proxies != <span class="literal">NULL</span>) {</span><br><span class="line"> (<span class="keyword">void</span>) ngx_http_get_forwarded_addr(r, &addr, xfwd, <span class="literal">NULL</span>,</span><br><span class="line"> gscf->proxies, gscf->proxy_recursive);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> <span class="comment">//判断是否为IPV6</span></span><br><span class="line"> <span class="keyword">if</span> (addr.sockaddr->sa_family == AF_INET6) {</span><br><span class="line"> u_char *p;</span><br><span class="line"> <span class="keyword">in_addr_t</span> inaddr;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span> *<span class="title">inaddr6</span>;</span></span><br><span class="line"></span><br><span class="line"> inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (IN6_IS_ADDR_V4MAPPED(inaddr6)) {</span><br><span class="line"> p = inaddr6->s6_addr;</span><br><span class="line"></span><br><span class="line"> inaddr = p[<span class="number">12</span>] << <span class="number">24</span>;</span><br><span class="line"> inaddr += p[<span class="number">13</span>] << <span class="number">16</span>;</span><br><span class="line"> inaddr += p[<span class="number">14</span>] << <span class="number">8</span>;</span><br><span class="line"> inaddr += p[<span class="number">15</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> inaddr;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="comment">//非ipv4协议</span></span><br><span class="line"> <span class="keyword">if</span> (addr.sockaddr->sa_family != AF_INET) {</span><br><span class="line"> <span class="keyword">return</span> INADDR_NONE;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//返回主机字节序</span></span><br><span class="line"> <span class="built_in">sin</span> = (struct sockaddr_in *) addr.sockaddr;</span><br><span class="line"> <span class="keyword">return</span> ntohl(<span class="built_in">sin</span>->sin_addr.s_addr);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>接下来看下ngx_http_geoip_city_variable函数实现<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_geoip_city_variable(<span class="keyword">ngx_http_request_t</span> *r,</span><br><span class="line"> <span class="keyword">ngx_http_variable_value_t</span> *v, <span class="keyword">uintptr_t</span> data)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *val;</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> GeoIPRecord *gr;</span><br><span class="line"> <span class="comment">//获取city record</span></span><br><span class="line"> gr = ngx_http_geoip_get_city_record(r);</span><br><span class="line"> <span class="keyword">if</span> (gr == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">goto</span> not_found;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取val的值</span></span><br><span class="line"> val = *(<span class="keyword">char</span> **) ((<span class="keyword">char</span> *) gr + data);</span><br><span class="line"> <span class="keyword">if</span> (val == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">goto</span> no_value;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//获取变量长度</span></span><br><span class="line"> len = ngx_strlen(val);</span><br><span class="line"> v->data = ngx_pnalloc(r->pool, len);</span><br><span class="line"> <span class="keyword">if</span> (v->data == <span class="literal">NULL</span>) {</span><br><span class="line"> GeoIPRecord_delete(gr);</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//复制变量值</span></span><br><span class="line"> ngx_memcpy(v->data, val, len);</span><br><span class="line"></span><br><span class="line"> v->len = len;</span><br><span class="line"> v->valid = <span class="number">1</span>;</span><br><span class="line"> v->no_cacheable = <span class="number">0</span>;</span><br><span class="line"> v->not_found = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">//回收geoip资源</span></span><br><span class="line"> GeoIPRecord_delete(gr);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line"></span><br><span class="line">no_value:</span><br><span class="line"></span><br><span class="line"> GeoIPRecord_delete(gr);</span><br><span class="line"></span><br><span class="line">not_found:</span><br><span class="line"></span><br><span class="line"> v->not_found = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>以上就是geoip模块的所有内容<p></p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的try_files模块</title>
<link href="https://weeweetan.github.io/2023/02/26/Nginx%E7%9A%84try-files%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2023/02/26/Nginx的try-files模块/</id>
<published>2023-02-26T15:59:53.000Z</published>
<updated>2023-05-28T19:59:50.438Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Syntax:try_files file ... uri;</span><br><span class="line">try_files file ... =code;</span><br><span class="line">Default:—</span><br><span class="line">Context:server, location</span><br></pre></td></tr></table></figure><h2 id="2-配置解析函数"><a href="#2-配置解析函数" class="headerlink" title="2.配置解析函数"></a>2.配置解析函数</h2><blockquote><p>首先看下配置解析函数ngx_http_try_files<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_try_files(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_try_files_loc_conf_t</span> *tlcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> code;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n;</span><br><span class="line"> <span class="keyword">ngx_http_try_file_t</span> *tf;</span><br><span class="line"> <span class="keyword">ngx_http_script_compile_t</span> sc;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//判断是否重复设置</span></span><br><span class="line"> <span class="keyword">if</span> (tlcf->try_files) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 申请必要内存,根据参数申请内存</span></span><br><span class="line"> tf = ngx_pcalloc(cf->pool, cf->args->nelts * <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_try_file_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (tf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> tlcf->try_files = tf;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析参数</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < cf->args->nelts - <span class="number">1</span>; i++) {</span><br><span class="line"></span><br><span class="line"> tf[i].name = value[i + <span class="number">1</span>];</span><br><span class="line"> <span class="comment">// 判断当前参数是否可以作为文件查找的目录,如果是,则将test_dir置位</span></span><br><span class="line"> <span class="keyword">if</span> (tf[i].name.len > <span class="number">0</span></span><br><span class="line"> && tf[i].name.data[tf[i].name.len - <span class="number">1</span>] == <span class="string">'/'</span></span><br><span class="line"> && i + <span class="number">2</span> < cf->args->nelts)</span><br><span class="line"> {</span><br><span class="line"> tf[i].test_dir = <span class="number">1</span>;</span><br><span class="line"> tf[i].name.len--;</span><br><span class="line"> tf[i].name.data[tf[i].name.len] = <span class="string">'\0'</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 计算参数中的变量的个数</span></span><br><span class="line"> n = ngx_http_script_variables_count(&tf[i].name);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理变量</span></span><br><span class="line"> <span class="keyword">if</span> (n) {</span><br><span class="line"> ngx_memzero(&sc, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_compile_t</span>));</span><br><span class="line"></span><br><span class="line"> sc.cf = cf;</span><br><span class="line"> sc.source = &tf[i].name;</span><br><span class="line"> sc.lengths = &tf[i].lengths;</span><br><span class="line"> sc.values = &tf[i].values;</span><br><span class="line"> sc.variables = n;</span><br><span class="line"> sc.complete_lengths = <span class="number">1</span>;</span><br><span class="line"> sc.complete_values = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_script_compile(&sc) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">/* add trailing '\0' to length */</span></span><br><span class="line"> tf[i].name.len++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//如果最后一个参数第一个字符是=,则解析最后一个参数的code</span></span><br><span class="line"> <span class="keyword">if</span> (tf[i - <span class="number">1</span>].name.data[<span class="number">0</span>] == <span class="string">'='</span>) {</span><br><span class="line"></span><br><span class="line"> code = ngx_atoi(tf[i - <span class="number">1</span>].name.data + <span class="number">1</span>, tf[i - <span class="number">1</span>].name.len - <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (code == NGX_ERROR || code > <span class="number">999</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid code \"%*s\""</span>,</span><br><span class="line"> tf[i - <span class="number">1</span>].name.len - <span class="number">1</span>, tf[i - <span class="number">1</span>].name.data);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> tf[i].code = code;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>filter模块需要在配置解析完成之后,在适当的阶段介入,在ngx_http_try_files_module_ctx中设置<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_http_module_t</span> ngx_http_try_files_module_ctx = {</span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* preconfiguration */</span></span><br><span class="line"> ngx_http_try_files_init, <span class="comment">/* postconfiguration */</span></span><br><span class="line"></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* create main configuration */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* init main configuration */</span></span><br><span class="line"></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* create server configuration */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* merge server configuration */</span></span><br><span class="line"></span><br><span class="line"> ngx_http_try_files_create_loc_conf, <span class="comment">/* create location configuration */</span></span><br><span class="line"> <span class="literal">NULL</span> <span class="comment">/* merge location configuration */</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><br>看下ngx_http_try_files_init函数实现,可以看到try_files模块的filter在precontent阶段介入<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_try_files_init(<span class="keyword">ngx_conf_t</span> *cf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_handler_pt *h;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从precontent阶段的handler中取一个</span></span><br><span class="line"> h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers);</span><br><span class="line"> <span class="keyword">if</span> (h == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *h = ngx_http_try_files_handler;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>接下来看下ngx_http_try_files_handler模块具体实现<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_try_files_handler(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> len, root, alias, reserve, allocated;</span><br><span class="line"> u_char *p, *name;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> path, args;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> test_dir;</span><br><span class="line"> <span class="keyword">ngx_http_try_file_t</span> *tf;</span><br><span class="line"> <span class="keyword">ngx_open_file_info_t</span> of;</span><br><span class="line"> ngx_http_script_code_pt code;</span><br><span class="line"> <span class="keyword">ngx_http_script_engine_t</span> e;</span><br><span class="line"> <span class="keyword">ngx_http_core_loc_conf_t</span> *clcf;</span><br><span class="line"> ngx_http_script_len_code_pt lcode;</span><br><span class="line"> <span class="keyword">ngx_http_try_files_loc_conf_t</span> *tlcf;</span><br><span class="line"></span><br><span class="line"> tlcf = ngx_http_get_module_loc_conf(r, ngx_http_try_files_module);</span><br><span class="line"> <span class="comment">//如果没有配置try_file直接返回</span></span><br><span class="line"> <span class="keyword">if</span> (tlcf->try_files == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"try files handler"</span>);</span><br><span class="line"></span><br><span class="line"> allocated = <span class="number">0</span>;</span><br><span class="line"> root = <span class="number">0</span>;</span><br><span class="line"> name = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="comment">/* suppress MSVC warning */</span></span><br><span class="line"> path.data = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> tf = tlcf->try_files;</span><br><span class="line"></span><br><span class="line"> clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);</span><br><span class="line"> <span class="comment">// 获取location下配置的alias</span></span><br><span class="line"> alias = clcf->alias;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> ( ;; ) {</span><br><span class="line"> <span class="comment">// 解析try_files后面的变量</span></span><br><span class="line"> <span class="keyword">if</span> (tf->lengths) {</span><br><span class="line"> ngx_memzero(&e, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_engine_t</span>));</span><br><span class="line"></span><br><span class="line"> e.ip = tf->lengths->elts;</span><br><span class="line"> e.request = r;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 1 is for terminating '\0' as in static names */</span></span><br><span class="line"> len = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (*(<span class="keyword">uintptr_t</span> *) e.ip) {</span><br><span class="line"> lcode = *(ngx_http_script_len_code_pt *) e.ip;</span><br><span class="line"> len += lcode(&e);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> len = tf->name.len;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 如果没有alias,则判断try_files第一个参数长度与uri的长度</span></span><br><span class="line"> <span class="keyword">if</span> (!alias) {</span><br><span class="line"> reserve = len > r->uri.len ? len - r->uri.len : <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (alias == NGX_MAX_SIZE_T_VALUE) {</span><br><span class="line"> reserve = len;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (reserve > allocated || !allocated) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* 16 bytes are preallocation */</span></span><br><span class="line"> allocated = reserve + <span class="number">16</span>;</span><br><span class="line"> <span class="comment">// 根据uri映射磁盘文件</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_map_uri_to_path(r, &path, &root, allocated) == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name = path.data + root;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (tf->values == <span class="literal">NULL</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* tf->name.len includes the terminating '\0' */</span></span><br><span class="line"></span><br><span class="line"> ngx_memcpy(name, tf->name.data, tf->name.len);</span><br><span class="line"></span><br><span class="line"> path.len = (name + tf->name.len - <span class="number">1</span>) - path.data;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> e.ip = tf->values->elts;</span><br><span class="line"> e.pos = name;</span><br><span class="line"> e.flushed = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//处理变量</span></span><br><span class="line"> <span class="keyword">while</span> (*(<span class="keyword">uintptr_t</span> *) e.ip) {</span><br><span class="line"> code = *(ngx_http_script_code_pt *) e.ip;</span><br><span class="line"> code((<span class="keyword">ngx_http_script_engine_t</span> *) &e);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> path.len = e.pos - path.data;</span><br><span class="line"></span><br><span class="line"> *e.pos = <span class="string">'\0'</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (alias && alias != NGX_MAX_SIZE_T_VALUE</span><br><span class="line"> && ngx_strncmp(name, r->uri.data, alias) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> ngx_memmove(name, name + alias, len - alias);</span><br><span class="line"> path.len -= alias;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> test_dir = tf->test_dir;</span><br><span class="line"> <span class="comment">// 指针后移</span></span><br><span class="line"> tf++;</span><br><span class="line"></span><br><span class="line"> ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"trying to use %s: \"%s\" \"%s\""</span>,</span><br><span class="line"> test_dir ? <span class="string">"dir"</span> : <span class="string">"file"</span>, name, path.data);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (tf->lengths == <span class="literal">NULL</span> && tf->name.len == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// 如果最后一个参数code有设置,则直接返回该code</span></span><br><span class="line"> <span class="keyword">if</span> (tf->code) {</span><br><span class="line"> <span class="keyword">return</span> tf->code;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> path.len -= root;</span><br><span class="line"> path.data += root;</span><br><span class="line"> <span class="comment">// 如果是@开头的path,则跳转到对应location</span></span><br><span class="line"> <span class="keyword">if</span> (path.data[<span class="number">0</span>] == <span class="string">'@'</span>) {</span><br><span class="line"> (<span class="keyword">void</span>) ngx_http_named_location(r, &path);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ngx_http_split_args(r, &path, &args);</span><br><span class="line"> <span class="comment">//内部重定向</span></span><br><span class="line"> (<span class="keyword">void</span>) ngx_http_internal_redirect(r, &path, &args);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 结束请求</span></span><br><span class="line"> ngx_http_finalize_request(r, NGX_DONE);</span><br><span class="line"> <span class="keyword">return</span> NGX_DONE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&of, <span class="keyword">sizeof</span>(<span class="keyword">ngx_open_file_info_t</span>));</span><br><span class="line"> <span class="comment">// 设置cache_file参数</span></span><br><span class="line"> of.read_ahead = clcf->read_ahead;</span><br><span class="line"> of.directio = clcf->directio;</span><br><span class="line"> of.valid = clcf->open_file_cache_valid;</span><br><span class="line"> of.min_uses = clcf->open_file_cache_min_uses;</span><br><span class="line"> of.test_only = <span class="number">1</span>;</span><br><span class="line"> of.errors = clcf->open_file_cache_errors;</span><br><span class="line"> of.events = clcf->open_file_cache_events;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理软链接</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 打开文件</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (of.err == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (of.err != NGX_ENOENT</span><br><span class="line"> && of.err != NGX_ENOTDIR</span><br><span class="line"> && of.err != NGX_ENAMETOOLONG)</span><br><span class="line"> {</span><br><span class="line"> ngx_log_error(NGX_LOG_CRIT, r->connection-><span class="built_in">log</span>, of.err,</span><br><span class="line"> <span class="string">"%s \"%s\" failed"</span>, of.failed, path.data);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 当前目录不可用于查找文件</span></span><br><span class="line"> <span class="keyword">if</span> (of.is_dir != test_dir) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> path.len -= root;</span><br><span class="line"> path.data += root;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!alias) {</span><br><span class="line"> r->uri = path;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (alias == NGX_MAX_SIZE_T_VALUE) {</span><br><span class="line"> <span class="keyword">if</span> (!test_dir) {</span><br><span class="line"> r->uri = path;</span><br><span class="line"> r->add_uri_to_alias = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> name = r->uri.data;</span><br><span class="line"></span><br><span class="line"> r->uri.len = alias + path.len;</span><br><span class="line"> r->uri.data = ngx_pnalloc(r->pool, r->uri.len);</span><br><span class="line"> <span class="keyword">if</span> (r->uri.data == <span class="literal">NULL</span>) {</span><br><span class="line"> r->uri.len = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> p = ngx_copy(r->uri.data, name, alias);</span><br><span class="line"> <span class="comment">// 保存path</span></span><br><span class="line"> ngx_memcpy(p, path.data, path.len);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 设置文件后缀</span></span><br><span class="line"> ngx_http_set_exten(r);</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"try file uri: \"%V\""</span>, &r->uri);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* not reached */</span></span><br></pre></td></tr></table></figure><p></p></blockquote><h2 id="3-总结"><a href="#3-总结" class="headerlink" title="3.总结"></a>3.总结</h2><blockquote><p>以上就是try_files模块的详解,从指令到handler都进行了一些说明。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的header_filter模块</title>
<link href="https://weeweetan.github.io/2022/12/16/Nginx%E7%9A%84header-filter%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2022/12/16/Nginx的header-filter模块/</id>
<published>2022-12-16T15:41:15.000Z</published>
<updated>2023-02-26T15:55:03.390Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><blockquote><p>header_filter模块主要有以下几个指令<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Syntax:add_header name value [always];</span><br><span class="line">Default:—</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Context:http, server, location, if in location</span><br><span class="line">Syntax:add_trailer name value [always];</span><br><span class="line">Default:—</span><br><span class="line">Context:http, server, location, if in location</span><br><span class="line">This directive appeared in version 1.13.2.</span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Syntax:expires [modified] time;</span><br><span class="line">expires epoch | max | off;</span><br><span class="line">Default:</span><br><span class="line">expires off;</span><br><span class="line">Context:http, server, location, <span class="keyword">if</span> in location</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>配置示例<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">expires <span class="number">24</span>h;</span><br><span class="line">expires modified +<span class="number">24</span>h;</span><br><span class="line">expires @<span class="number">24</span>h;</span><br><span class="line">expires <span class="number">0</span>;</span><br><span class="line">expires <span class="number">-1</span>;</span><br><span class="line">expires epoch;</span><br><span class="line">expires $expires;</span><br><span class="line">add_header Cache-Control <span class="keyword">private</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h2 id="2-源码解析"><a href="#2-源码解析" class="headerlink" title="2. 源码解析"></a>2. 源码解析</h2><h3 id="2-1-配置解析函数"><a href="#2-1-配置解析函数" class="headerlink" title="2.1 配置解析函数"></a>2.1 配置解析函数</h3><blockquote><ol><li>首先来看下add_header指令解析函数<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br></pre></td><td class="code"><pre><span class="line">static char *</span><br><span class="line">ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_headers_conf_t *hcf = conf;</span><br><span class="line"></span><br><span class="line"> ngx_str_t *value;</span><br><span class="line"> ngx_uint_t i;</span><br><span class="line"> ngx_array_t **headers;</span><br><span class="line"> ngx_http_header_val_t *hv;</span><br><span class="line"> ngx_http_set_header_t *set;</span><br><span class="line"> ngx_http_compile_complex_value_t ccv;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> // 取到数组指针</span><br><span class="line"> headers = (ngx_array_t **) ((char *) hcf + cmd->offset);</span><br><span class="line"></span><br><span class="line"> if (*headers == NULL) {</span><br><span class="line"> *headers = ngx_array_create(cf->pool, 1,</span><br><span class="line"> sizeof(ngx_http_header_val_t));</span><br><span class="line"> if (*headers == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //从数组中push一个元素</span><br><span class="line"> hv = ngx_array_push(*headers);</span><br><span class="line"> if (hv == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 取配置header的key</span><br><span class="line"> hv->key = value[1];</span><br><span class="line"> hv->handler = NULL;</span><br><span class="line"> hv->offset = 0;</span><br><span class="line"> hv->always = 0;</span><br><span class="line"></span><br><span class="line"> if (headers == &hcf->headers) {</span><br><span class="line"> hv->handler = ngx_http_add_header;</span><br><span class="line"></span><br><span class="line"> set = ngx_http_set_headers;</span><br><span class="line"> for (i = 0; set[i].name.len; i++) {</span><br><span class="line"> if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> hv->offset = set[i].offset;</span><br><span class="line"> hv->handler = set[i].handler;</span><br><span class="line"></span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (value[2].len == 0) {</span><br><span class="line"> ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t));</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[2];</span><br><span class="line"> ccv.complex_value = &hv->value;</span><br><span class="line"></span><br><span class="line"> if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (cf->args->nelts == 3) {</span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[3].data, "always") != 0) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid parameter \"%V\"", &value[3]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> hv->always = 1;</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="2"><li>接下来看下expires指令解析函数<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">static char *</span><br><span class="line">ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_headers_conf_t *hcf = conf;</span><br><span class="line"></span><br><span class="line"> char *err;</span><br><span class="line"> ngx_str_t *value;</span><br><span class="line"> ngx_int_t rc;</span><br><span class="line"> ngx_uint_t n;</span><br><span class="line"> ngx_http_complex_value_t cv;</span><br><span class="line"> ngx_http_compile_complex_value_t ccv;</span><br><span class="line"></span><br><span class="line"> // 判断是否已经设置过该指令</span><br><span class="line"> if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {</span><br><span class="line"> return "is duplicate";</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> //判断指令后的参数</span><br><span class="line"> if (cf->args->nelts == 2) {</span><br><span class="line"></span><br><span class="line"> hcf->expires = NGX_HTTP_EXPIRES_ACCESS;</span><br><span class="line"></span><br><span class="line"> n = 1;</span><br><span class="line"></span><br><span class="line"> } else { /* cf->args->nelts == 3 */</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[1].data, "modified") != 0) {</span><br><span class="line"> return "invalid value";</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> hcf->expires = NGX_HTTP_EXPIRES_MODIFIED;</span><br><span class="line"></span><br><span class="line"> n = 2;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 准备变量</span><br><span class="line"> ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[n];</span><br><span class="line"> ccv.complex_value = &cv;</span><br><span class="line"></span><br><span class="line"> //编译变量</span><br><span class="line"> if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (cv.lengths != NULL) {</span><br><span class="line"></span><br><span class="line"> hcf->expires_value = ngx_palloc(cf->pool,</span><br><span class="line"> sizeof(ngx_http_complex_value_t));</span><br><span class="line"> if (hcf->expires_value == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *hcf->expires_value = cv;</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rc = ngx_http_parse_expires(&value[n], &hcf->expires, &hcf->expires_time,</span><br><span class="line"> &err);</span><br><span class="line"> if (rc != NGX_OK) {</span><br><span class="line"> return err;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol></blockquote><h3 id="2-2-filter函数"><a href="#2-2-filter函数" class="headerlink" title="2.2 filter函数"></a>2.2 filter函数</h3><h4 id="2-2-1-headers-filter函数"><a href="#2-2-1-headers-filter函数" class="headerlink" title="2.2.1 headers_filter函数"></a>2.2.1 headers_filter函数</h4><blockquote><p>首先看下ngx_http_headers_filter函数实现<br></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line">static ngx_int_t</span><br><span class="line">ngx_http_headers_filter(ngx_http_request_t *r)</span><br><span class="line">{</span><br><span class="line"> ngx_str_t value;</span><br><span class="line"> ngx_uint_t i, safe_status;</span><br><span class="line"> ngx_http_header_val_t *h;</span><br><span class="line"> ngx_http_headers_conf_t *conf;</span><br><span class="line"></span><br><span class="line"> // 子请求不做处理,直接返回</span><br><span class="line"> if (r != r->main) {</span><br><span class="line"> return ngx_http_next_header_filter(r);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 获取location级别配置</span><br><span class="line"> conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);</span><br><span class="line"></span><br><span class="line"> if (conf->expires == NGX_HTTP_EXPIRES_OFF</span><br><span class="line"> && conf->headers == NULL</span><br><span class="line"> && conf->trailers == NULL)</span><br><span class="line"> {</span><br><span class="line"> return ngx_http_next_header_filter(r);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> switch (r->headers_out.status) {</span><br><span class="line"></span><br><span class="line"> case NGX_HTTP_OK:</span><br><span class="line"> case NGX_HTTP_CREATED:</span><br><span class="line"> case NGX_HTTP_NO_CONTENT:</span><br><span class="line"> case NGX_HTTP_PARTIAL_CONTENT:</span><br><span class="line"> case NGX_HTTP_MOVED_PERMANENTLY:</span><br><span class="line"> case NGX_HTTP_MOVED_TEMPORARILY:</span><br><span class="line"> case NGX_HTTP_SEE_OTHER:</span><br><span class="line"> case NGX_HTTP_NOT_MODIFIED:</span><br><span class="line"> case NGX_HTTP_TEMPORARY_REDIRECT:</span><br><span class="line"> case NGX_HTTP_PERMANENT_REDIRECT:</span><br><span class="line"> safe_status = 1;</span><br><span class="line"> break;</span><br><span class="line"></span><br><span class="line"> default:</span><br><span class="line"> safe_status = 0;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (conf->expires != NGX_HTTP_EXPIRES_OFF && safe_status) {</span><br><span class="line"> if (ngx_http_set_expires(r, conf) != NGX_OK) {</span><br><span class="line"> return NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (conf->headers) {</span><br><span class="line"> h = conf->headers->elts;</span><br><span class="line"> for (i = 0; i < conf->headers->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> if (!safe_status && !h[i].always) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {</span><br><span class="line"> return NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (h[i].handler(r, &h[i], &value) != NGX_OK) {</span><br><span class="line"> return NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (conf->trailers) {</span><br><span class="line"> h = conf->trailers->elts;</span><br><span class="line"> for (i = 0; i < conf->trailers->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> if (!safe_status && !h[i].always) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> r->expect_trailers = 1;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return ngx_http_next_header_filter(r);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="2-2-2-ngx-http-trailers-filter函数"><a href="#2-2-2-ngx-http-trailers-filter函数" class="headerlink" title="2.2.2 ngx_http_trailers_filter函数"></a>2.2.2 ngx_http_trailers_filter函数</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_trailers_filter(<span class="keyword">ngx_http_request_t</span> *r, <span class="keyword">ngx_chain_t</span> *in)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_str_t</span> value;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, safe_status;</span><br><span class="line"> <span class="keyword">ngx_chain_t</span> *cl;</span><br><span class="line"> <span class="keyword">ngx_table_elt_t</span> *t;</span><br><span class="line"> <span class="keyword">ngx_http_header_val_t</span> *h;</span><br><span class="line"> <span class="keyword">ngx_http_headers_conf_t</span> *conf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取location级别配置</span></span><br><span class="line"> conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果满足如下条件,则跳过本filter</span></span><br><span class="line"> <span class="keyword">if</span> (in == <span class="literal">NULL</span></span><br><span class="line"> || conf->trailers == <span class="literal">NULL</span></span><br><span class="line"> || !r->expect_trailers</span><br><span class="line"> || r->header_only)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_next_body_filter(r, in);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 找到最后一个buf</span></span><br><span class="line"> <span class="keyword">for</span> (cl = in; cl; cl = cl->next) {</span><br><span class="line"> <span class="keyword">if</span> (cl->buf->last_buf) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果cl为null,则跳过本filter</span></span><br><span class="line"> <span class="keyword">if</span> (cl == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_next_body_filter(r, in);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 根据响应码做选择</span></span><br><span class="line"> <span class="keyword">switch</span> (r->headers_out.status) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_OK:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_CREATED:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_NO_CONTENT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_PARTIAL_CONTENT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_MOVED_PERMANENTLY:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_MOVED_TEMPORARILY:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_SEE_OTHER:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_NOT_MODIFIED:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_TEMPORARY_REDIRECT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_PERMANENT_REDIRECT:</span><br><span class="line"> safe_status = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> safe_status = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 遍历配置的所有trailer</span></span><br><span class="line"> h = conf->trailers->elts;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < conf->trailers->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!safe_status && !h[i].always) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value.len) {</span><br><span class="line"> t = ngx_list_push(&r->headers_out.trailers);</span><br><span class="line"> <span class="keyword">if</span> (t == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> t->key = h[i].key;</span><br><span class="line"> t->value = value;</span><br><span class="line"> t->hash = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ngx_http_next_body_filter(r, in);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>docker下安装使用systemptap</title>
<link href="https://weeweetan.github.io/2022/03/12/docker%E4%B8%8B%E5%AE%89%E8%A3%85%E4%BD%BF%E7%94%A8systemptap/"/>
<id>https://weeweetan.github.io/2022/03/12/docker下安装使用systemptap/</id>
<published>2022-03-12T09:50:26.000Z</published>
<updated>2022-03-14T15:07:44.066Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><!-- rebuild by neat -->
</summary>
<category term="systemtap" scheme="https://weeweetan.github.io/tags/systemtap/"/>
</entry>
<entry>
<title>systemtap调试技巧</title>
<link href="https://weeweetan.github.io/2021/12/28/systemtap%E8%B0%83%E8%AF%95%E6%8A%80%E5%B7%A7/"/>
<id>https://weeweetan.github.io/2021/12/28/systemtap调试技巧/</id>
<published>2021-12-28T14:16:25.000Z</published>
<updated>2024-02-27T13:56:59.888Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、安装"><a href="#1、安装" class="headerlink" title="1、安装"></a>1、安装</h2><h3 id="Centos"><a href="#Centos" class="headerlink" title="Centos"></a>Centos</h3><h4 id="1-1-必要库"><a href="#1-1-必要库" class="headerlink" title="1.1 必要库"></a>1.1 必要库</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum -y install elfutils、gcc、kernel-devel、kernel-debuginfo、yum-utils</span><br></pre></td></tr></table></figure><h4 id="1-2-yum安装"><a href="#1-2-yum安装" class="headerlink" title="1.2 yum安装"></a>1.2 yum安装</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum -y systemtap</span><br></pre></td></tr></table></figure><h3 id="Ubuntu"><a href="#Ubuntu" class="headerlink" title="Ubuntu"></a>Ubuntu</h3><h4 id="1-1-必要库-1"><a href="#1-1-必要库-1" class="headerlink" title="1.1 必要库"></a>1.1 必要库</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">$ apt-get install build-essential</span><br><span class="line">$ apt-get install gettext</span><br><span class="line">$ apt-get install elfutils</span><br><span class="line">$ apt-get install libdw-dev</span><br></pre></td></tr></table></figure><h4 id="1-2-源码安装"><a href="#1-2-源码安装" class="headerlink" title="1.2 源码安装"></a>1.2 源码安装</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ git clone git:<span class="comment">//sourceware.org/git/systemtap.git</span></span><br><span class="line">$ cd systemtap</span><br><span class="line">$ git checkout release<span class="number">-4.9</span></span><br><span class="line">$ ./configure</span><br><span class="line">$ make -j (getconf _NPROCESSORS_ONLN)</span><br></pre></td></tr></table></figure><blockquote><p>目前需要使用release4.9分支,安装完成后,在/usr/local/systemtap</p></blockquote><h2 id="2、入门"><a href="#2、入门" class="headerlink" title="2、入门"></a>2、入门</h2><h3 id="2-1、简介"><a href="#2-1、简介" class="headerlink" title="2.1、简介"></a>2.1、简介</h3><blockquote><p>SystemTap是一个Linux非常有用的调试(跟踪/探测)工具,常用于Linux内核或者应用程序的信息采集,需要编译时,指定-g选项,比如:获取一个函数里面运行时的变量、调用堆栈,甚至可以直接修改变量的值,对诊断性能或功能问题非常有帮助。SystemTap提供非常简单的命令行接口和很简洁的脚本语言,以及非常丰富的tapset和例子。</p></blockquote><h3 id="2-2、何时使用"><a href="#2-2、何时使用" class="headerlink" title="2.2、何时使用"></a>2.2、何时使用</h3><blockquote><p>定位(内核)函数位置<br>查看函数被调用时的调用堆栈、局部变量、参数<br>查看函数指针变量实际指的是哪个函数<br>查看代码的执行轨迹(哪些行被执行了)<br>查看内核或者进程的执行流程<br>调试内存泄露或者内存重复释放<br>统计函数调用次数<br>……</p></blockquote><h3 id="2-3、stap命令"><a href="#2-3、stap命令" class="headerlink" title="2.3、stap命令"></a>2.3、stap命令</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">stap [OPTIONS] FILENAME [ARGUMENTS]</span><br><span class="line">stap [OPTIONS] - [ARGUMENTS]</span><br><span class="line">stap [OPTIONS] –e SCRIPT [ARGUMENTS]</span><br><span class="line"></span><br><span class="line">比较常用和有用的参数:</span><br><span class="line">-e SCRIPT Run given script.</span><br><span class="line">-l PROBE List matching probes.</span><br><span class="line">-L PROBE List matching probes <span class="keyword">and</span> local variables.</span><br><span class="line">-g guru mode </span><br><span class="line">-D NM=VAL emit macro definition into generated C code</span><br><span class="line">-o FILE send script output to file, instead of <span class="built_in">stdout</span>.</span><br><span class="line">-x PID sets target() to PID</span><br><span class="line">-T time <span class="built_in">set</span> execute time</span><br><span class="line">-G var=val <span class="built_in">set</span> variable</span><br><span class="line">-d object add trace object</span><br></pre></td></tr></table></figure><h2 id="2-4、staprun命令"><a href="#2-4、staprun命令" class="headerlink" title="2.4、staprun命令"></a>2.4、staprun命令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">staprun [OPTIONS] MODULE [MODULE-OPTIONS]</span><br></pre></td></tr></table></figure><blockquote><p>stap命令与staprun命令的区别在于:<br>stap命令的操作对象是stp文件或script命令等,而staprun命令的操作对象是编译生成的内核模块。</p></blockquote><h2 id="3、脚本语言"><a href="#3、脚本语言" class="headerlink" title="3、脚本语言"></a>3、脚本语言</h2><h3 id="3-1、probe"><a href="#3-1、probe" class="headerlink" title="3.1、probe"></a>3.1、probe</h3><blockquote><p>“probe” <=> “探测”, 是SystemTap进行具体地收集数据的关键字。“probe point” 是probe动作的时机,也称探测点。也就是probe程序监视的某事件点,一旦侦测的事件触发了,则probe将从此处插入内核或者用户进程中。“probe handle” 是当probe插入内核或者用户进程后所做的具体动作。<br>probe用法:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">probe probe-point { statement }</span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>在Hello World例子中begin和end就是probe-point, statement就是该探测点的处理逻辑,在Hello World例子中statement只有一行print,statement可以是复杂的代码块。<br>探测点语法:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">kernel.function(PATTERN)</span><br><span class="line">kernel.function(PATTERN).call</span><br><span class="line">kernel.function(PATTERN).<span class="keyword">return</span></span><br><span class="line">kernel.function(PATTERN).<span class="keyword">return</span>.maxactive(VALUE)</span><br><span class="line">kernel.function(PATTERN).<span class="keyword">inline</span></span><br><span class="line">kernel.function(PATTERN).label(LPATTERN)</span><br><span class="line"><span class="keyword">module</span>(MPATTERN).function(PATTERN)</span><br><span class="line"><span class="keyword">module</span>(MPATTERN).function(PATTERN).call</span><br><span class="line"><span class="keyword">module</span>(MPATTERN).function(PATTERN).<span class="keyword">return</span>.maxactive(VALUE)</span><br><span class="line"><span class="keyword">module</span>(MPATTERN).function(PATTERN).<span class="keyword">inline</span></span><br><span class="line">kernel.statement(PATTERN)</span><br><span class="line">kernel.statement(ADDRESS).absolute</span><br><span class="line"><span class="keyword">module</span>(MPATTERN).statement(PATTERN)</span><br><span class="line">process(PROCESSPATH).function(PATTERN)</span><br><span class="line">process(PROCESSPATH).function(PATTERN).call</span><br><span class="line">process(PROCESSPATH).function(PATTERN).<span class="keyword">return</span></span><br><span class="line">process(PROCESSPATH).function(PATTERN).<span class="keyword">inline</span></span><br><span class="line">process(PROCESSPATH).statement(PATTERN)</span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>PATTERN语法为:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">func[@file]</span><br><span class="line">func@file:linenumber</span><br></pre></td></tr></table></figure><br>例如:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">kernel.function(<span class="string">"*init*"</span>)</span><br><span class="line"><span class="keyword">module</span>(<span class="string">"ext3"</span>).function(<span class="string">"*"</span>)</span><br><span class="line">kernel.statement(<span class="string">"*@kernel/time.c:296"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).function(<span class="string">"ngx_http_process_request"</span>)</span><br></pre></td></tr></table></figure><br>在return探测点可以用$return获取该函数的返回值。<br>inline函数无法安装.return探测点,也无法用$return获取其返回值。<p></p></blockquote><h3 id="3-2-基本语法"><a href="#3-2-基本语法" class="headerlink" title="3.2 基本语法"></a>3.2 基本语法</h3><blockquote><p>SystemTap脚本语法比较简单,与C语言类似,只是每一行结尾”;”是可选的。主要语句如下:<br>if/else、while、for/foreach、break/continue、return、next、delete、try/catch<br>其中:<br>next:主要在probe探测点逻辑处理中使用,调用此语句时,立刻从调用函数中退出。不同于exit()的是,next只是退出当前的调用函数,而此SystemTap并没有终了,但exit()则会终止SystemTap。</p></blockquote><h3 id="3-3-变量"><a href="#3-3-变量" class="headerlink" title="3.3 变量"></a>3.3 变量</h3><blockquote><p>不需要明确声明变量类型,脚本语言会根据函数参数等自动判断变量是什么类型的。<br>局部变量:在声明的probe和block(”{ }“范围内的部分)内有效。<br>全局变量:用”global“声明的变量,在此SystemTap的整个动作过程中都有效。全局变量的声明位置没有具体要求。需要注意的是,全局变量默认有锁保护,使用过多会有性能损失,如果用全局变量保存指针,可能出现指针所指的内容被进程修改,在探测点中拿不到真正的数据。<br>获取进程中的变量(全局变量、局部变量、参数)直接在变量名前面加$即可。</p></blockquote><h3 id="3-4-注释"><a href="#3-4-注释" class="headerlink" title="3.4 注释"></a>3.4 注释</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># ...... : Shell语言风格 </span><br><span class="line"><span class="comment">//...... : C++语言风格 </span></span><br><span class="line"> <span class="comment">/*......*/</span> : C语言风格</span><br></pre></td></tr></table></figure><h3 id="3-5-运算符"><a href="#3-5-运算符" class="headerlink" title="3.5 运算符"></a>3.5 运算符</h3><blockquote><p>比较运算符、算数运算符基本上与C语言一样,需要特别指出的是:<br>(1)、.操作符:连接两个字符串,类似于php;<br>(2)、=~和!~:正则匹配和正则不匹配;</p></blockquote><h3 id="3-6-函数"><a href="#3-6-函数" class="headerlink" title="3.6 函数"></a>3.6 函数</h3><blockquote><p>函数的例子<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">function indent:<span class="built_in">string</span> (delta:<span class="keyword">long</span>){</span><br><span class="line"> <span class="keyword">return</span> _generic_indent(<span class="number">-1</span>, <span class="string">""</span>, delta)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">function _generic_indent (idx, desc, delta)</span><br><span class="line">{</span><br><span class="line"> ts = __indent_timestamp ()</span><br><span class="line"> <span class="keyword">if</span> (! _indent_counters[idx]) _indent_timestamps[idx] = ts</span><br><span class="line"> depth = _generic_indent_depth(idx, delta)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">sprintf</span>(<span class="string">"%6d (%d:%d) %s:%-*s"</span>, (ts - _indent_timestamps[idx]), depth, delta, desc, depth, <span class="string">""</span>)</span><br><span class="line">} </span><br><span class="line"></span><br><span class="line">function <span class="built_in">strlen</span>:<span class="keyword">long</span>(s:<span class="built_in">string</span>) %{</span><br><span class="line"> STAP_RETURN(<span class="built_in">strlen</span>(STAP_ARG_s));</span><br><span class="line">%} </span><br></pre></td></tr></table></figure><br>官方有很多很有用的函数,详情请参考:<a href="https://sourceware.org/systemtap/tapsets/" target="_blank" rel="noopener">https://sourceware.org/systemtap/tapsets/</a><br>以及在本机安装了SystemTap之后在目录/usr/local/share/systemtap/tapset/下也可以看具体函数的实现以及一些奇特的用法。<p></p></blockquote><h3 id="3-7、技巧"><a href="#3-7、技巧" class="headerlink" title="3.7、技巧"></a>3.7、技巧</h3><h4 id="3-7-1、定位函数位置"><a href="#3-7-1、定位函数位置" class="headerlink" title="3.7.1、定位函数位置"></a>3.7.1、定位函数位置</h4><blockquote><p>在一个大型项目中找出函数在哪里定义有时很有用,特别是一些比较难找出在哪里定义的函数,比如内核或者glibc中的某个函数想要看其实现时,首先得找出其在哪个文件的哪一行定义,用SystemTap一行命令就可以搞定。<br>比如要看printf在glibc中哪里定义的:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~# stap -l 'kernel.function("sys_recv")'</span><br><span class="line">kernel.function(<span class="string">"sys_recv@/build/buildd/linux-lts-trusty-3.13.0/net/socket.c:1868"</span>)</span><br></pre></td></tr></table></figure><br>可以看出recv是在socket.c第1868行定义的。<br>甚至可以*号来模糊查找:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~# stap -l 'kernel.function("*recv")' </span><br><span class="line">kernel.function(<span class="string">"__audit_mq_sendrecv@/build/buildd/linux-lts-trusty-3.13.0/kernel/auditsc.c:2062"</span>)</span><br><span class="line">kernel.function(<span class="string">"audit_mq_sendrecv@/build/buildd/linux-lts-trusty-3.13.0/include/linux/audit.h:263"</span>)</span><br><span class="line">kernel.function(<span class="string">"compat_sys_recv@/build/buildd/linux-lts-trusty-3.13.0/net/compat.c:762"</span>)</span><br><span class="line">kernel.function(<span class="string">"i2c_master_recv@/build/buildd/linux-lts-trusty-3.13.0/drivers/i2c/i2c-core.c:1827"</span>)</span><br><span class="line">kernel.function(<span class="string">"ip_cmsg_recv@/build/buildd/linux-lts-trusty-3.13.0/net/ipv4/ip_sockglue.c:147"</span>)</span><br><span class="line">kernel.function(<span class="string">"kgdb_tty_recv@/build/buildd/linux-lts-trusty-3.13.0/drivers/tty/serial/kgdb_nmi.c:109"</span>)</span><br><span class="line">kernel.function(<span class="string">"ppp_do_recv@/build/buildd/linux-lts-trusty-3.13.0/drivers/net/ppp/ppp_generic.c:1617"</span>)</span><br><span class="line">kernel.function(<span class="string">"scm_recv@/build/buildd/linux-lts-trusty-3.13.0/include/net/scm.h:109"</span>)</span><br><span class="line">kernel.function(<span class="string">"sys_recv@/build/buildd/linux-lts-trusty-3.13.0/net/socket.c:1868"</span>)</span><br><span class="line">kernel.function(<span class="string">"tcp_event_data_recv@/build/buildd/linux-lts-trusty-3.13.0/net/ipv4/tcp_input.c:615"</span>)</span><br><span class="line">kernel.function(<span class="string">"tcp_splice_data_recv@/build/buildd/linux-lts-trusty-3.13.0/net/ipv4/tcp.c:637"</span>)</span><br><span class="line">kernel.function(<span class="string">"tpm_tis_recv@/build/buildd/linux-lts-trusty-3.13.0/drivers/char/tpm/tpm_tis.c:231"</span>)</span><br><span class="line">kernel.function(<span class="string">"try_fill_recv@/build/buildd/linux-lts-trusty-3.13.0/drivers/net/virtio_net.c:615"</span>)</span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>同理,也可以用来定位用户进程的函数位置:<br>比如tengine的文件ngx_shmem.c里面为了兼容各个操作系统而实现了三个版本的ngx_shm_alloc,用#if (NGX_HAVE_MAP_ANON)、#elif (NGX_HAVE_MAP_DEVZERO)、#elif (NGX_HAVE_SYSVSHM)、#endif来做条件编译,那怎么知道编译出来的是哪个版本呢,用SystemTap的话就很简单了,否则要去grep一下这几宏有没有定义才知道了。<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@cache4 tengine]# stap -l 'process("/home/admin/tengine/bin/nginx").function("ngx_shm_alloc")'</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).function(<span class="string">"ngx_shm_alloc@src/os/unix/ngx_shmem.c:15"</span>)</span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="3-7-2-查看可用探测点以及该探测点上可用的变量"><a href="#3-7-2-查看可用探测点以及该探测点上可用的变量" class="headerlink" title="3.7.2 查看可用探测点以及该探测点上可用的变量"></a>3.7.2 查看可用探测点以及该探测点上可用的变量</h4><blockquote><p>在一些探测点上能获取的变量比较有限,这是因为这些变量可能已经被编译器优化掉了,优化掉的变量就获取不到了。一般先用-L参数来看看有哪些变量可以直接使用:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@cache4 tengine]# stap -L 'process("/home/admin/tengine/bin/nginx").function("ngx_shm_alloc")' </span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).function(<span class="string">"ngx_shm_alloc@src/os/unix/ngx_shmem.c:15"</span>) $shm:<span class="keyword">ngx_shm_t</span>*</span><br></pre></td></tr></table></figure><br>可见在该探测点上可以直接使用$shm这个变量,其类型是ngx_shm_t*。<br>statement探测点也类似:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">[root@cache4 tengine]# stap -L 'process("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:*")' </span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_pcalloc@src/core/ngx_palloc.c:395"</span>) $pool:<span class="keyword">ngx_pool_t</span>* $size:<span class="keyword">size_t</span></span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_pcalloc@src/core/ngx_palloc.c:398"</span>) $pool:<span class="keyword">ngx_pool_t</span>* $size:<span class="keyword">size_t</span></span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_pcalloc@src/core/ngx_palloc.c:399"</span>) $size:<span class="keyword">size_t</span></span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_pcalloc@src/core/ngx_palloc.c:404"</span>) $size:<span class="keyword">size_t</span> $p:<span class="keyword">void</span>*</span><br></pre></td></tr></table></figure><br>可以直接使用这些探测点<p></p></blockquote><h4 id="3-7-3-输出调用堆栈"><a href="#3-7-3-输出调用堆栈" class="headerlink" title="3.7.3 输出调用堆栈"></a>3.7.3 输出调用堆栈</h4><blockquote><p>用户态探测点堆栈:print_ubacktrace()、sprint_ubacktrace()<br>内核态探测点堆栈:print_backtrace()、sprint_backtrace()<br>不带s和带s的区别是前者直接输出,后者是返回堆栈字符串。<br>这几个函数非常有用,在排查问题时可以根据一些特定条件来过滤函数被执行时是怎么调用进来的,比如排查tengine返回5xx时的调用堆栈是怎样的:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat debug_tengine_5xx.stp </span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_finalize_request").call {</span><br><span class="line"> <span class="keyword">if</span> ($rc >= <span class="number">500</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"rc: %d\n"</span>, $rc)</span><br><span class="line"> print_ubacktrace()</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#stap debug_tengine_5xx.stp </span></span><br><span class="line">rc: <span class="number">502</span></span><br><span class="line"> <span class="number">0x49af2e</span> : ngx_http_finalize_request+<span class="number">0xe</span>/<span class="number">0x480</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x543305</span> : ngx_http_video_flv_send_rest+<span class="number">0xf5</span>/<span class="number">0x380</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x543187</span> : ngx_http_video_finalize_request+<span class="number">0x57</span>/<span class="number">0xe0</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x49828f</span> : ngx_http_terminate_request+<span class="number">0x4f</span>/<span class="number">0xc0</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x49b760</span> : ngx_http_test_reading+<span class="number">0x50</span>/<span class="number">0x130</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x49779f</span> : ngx_http_request_handler+<span class="number">0x1f</span>/<span class="number">0x40</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x47ea8f</span> : ngx_epoll_process_events+<span class="number">0x2df</span>/<span class="number">0x330</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x4753f9</span> : ngx_process_events_and_timers+<span class="number">0x69</span>/<span class="number">0x1c0</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x47d4d8</span> : ngx_worker_process_cycle+<span class="number">0x138</span>/<span class="number">0x260</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x47a38a</span> : ngx_spawn_process+<span class="number">0x1ca</span>/<span class="number">0x5e0</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x47c73c</span> : ngx_start_worker_processes+<span class="number">0x7c</span>/<span class="number">0x100</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x47db5f</span> : ngx_master_process_cycle+<span class="number">0x3af</span>/<span class="number">0x9b0</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x45a740</span> : main+<span class="number">0xa90</span>/<span class="number">0xb50</span> [/home/admin/tengine/bin/nginx]</span><br><span class="line"> <span class="number">0x3623e1ecdd</span> [/lib64/libc<span class="number">-2.12</span>.so+<span class="number">0x1ecdd</span>/<span class="number">0x38d000</span>]</span><br></pre></td></tr></table></figure><br>比如看看内核是怎么收包的:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">root@jusse ~<span class="meta"># cat netif_receive_skb.stp </span></span><br><span class="line">probe kernel.function(<span class="string">"netif_receive_skb"</span>) </span><br><span class="line">{ </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"--------------------------------------------------------\n"</span>); </span><br><span class="line"> print_backtrace(); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"--------------------------------------------------------\n"</span>); </span><br><span class="line">} </span><br><span class="line">root@jusse ~<span class="meta"># stap netif_receive_skb.stp</span></span><br><span class="line">--------------------------------------------------------</span><br><span class="line"> <span class="number">0xffffffff8164dc00</span> : netif_receive_skb+<span class="number">0x0</span>/<span class="number">0x90</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff8164e280</span> : napi_gro_receive+<span class="number">0xb0</span>/<span class="number">0x130</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff81554537</span> : handle_incoming_queue+<span class="number">0xe7</span>/<span class="number">0x100</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff815555d9</span> : xennet_poll+<span class="number">0x279</span>/<span class="number">0x430</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff8164ee09</span> : net_rx_action+<span class="number">0x139</span>/<span class="number">0x250</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff810702cd</span> : __do_softirq+<span class="number">0xdd</span>/<span class="number">0x300</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff8107088e</span> : irq_exit+<span class="number">0x11e</span>/<span class="number">0x140</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff8144e785</span> : xen_evtchn_do_upcall+<span class="number">0x35</span>/<span class="number">0x50</span> [kernel]</span><br><span class="line"> <span class="number">0xffffffff8176c9ed</span> : xen_hvm_callback_vector+<span class="number">0x6d</span>/<span class="number">0x80</span> [kernel]</span><br><span class="line">--------------------------------------------------------</span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="3-7-4-获取函数参数"><a href="#3-7-4-获取函数参数" class="headerlink" title="3.7.4 获取函数参数"></a>3.7.4 获取函数参数</h4><blockquote><p>一些被编译器优化掉的函数参数用-L去看的时候没有找到,这样的话在探测点里面也不能直接用$方式获取该参数变量,这时可以使用SystemTap提供的_arg函数接口,是根据类型指定的,比如pointer_arg是获取指针类型参数,int_arg是获取整型参数,类似的还有long_arg、longlong_arg、uint_arg、ulong_arg、ulonglong_arg、s32_arg、s64_arg、u32_arg、u64_arg:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~# stap -L 'kernel.function("sys_open")' </span><br><span class="line">kernel.function(<span class="string">"SyS_open@/build/buildd/linux-lts-trusty-3.13.0/fs/open.c:1011"</span>) $ret:<span class="keyword">long</span> <span class="keyword">int</span></span><br><span class="line">root@j9 ~<span class="meta"># cat sys_open.stp </span></span><br><span class="line">probe kernel.function(<span class="string">"sys_open"</span>).call</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"filename: %p(%s), flags: %d, mode: %x\n"</span>, pointer_arg(<span class="number">1</span>), kernel_string(pointer_arg(<span class="number">1</span>)), int_arg(<span class="number">2</span>), int_arg(<span class="number">3</span>));</span><br><span class="line">}</span><br><span class="line">root@j9 ~<span class="meta"># stap sys_open.stp </span></span><br><span class="line">filename: <span class="number">0xc2081d2120</span>(/proc/stat), flags: <span class="number">524288</span>, mode: <span class="number">0</span></span><br><span class="line">filename: <span class="number">0x7facec00e838</span>(/root/opt/libexec/systemtap/stapio), flags: <span class="number">0</span>, mode: <span class="number">1b</span>6</span><br><span class="line">filename: <span class="number">0x2219488</span>(/var/<span class="built_in">log</span>/auth.<span class="built_in">log</span>), flags: <span class="number">0</span>, mode: <span class="number">1b</span>6</span><br><span class="line">filename: <span class="number">0x7facec00e838</span>(/root/opt/libexec/systemtap/stapio), flags: <span class="number">0</span>, mode: <span class="number">1b</span>6</span><br><span class="line">filename: <span class="number">0x7fad10172c29</span>(/etc/passwd), flags: <span class="number">524288</span>, mode: <span class="number">1b</span>6</span><br></pre></td></tr></table></figure><br>这两个函数的参数完全兼容,只是第二个参数命名不一样而已,可以像下面这么用:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat debug_tengine_5xx.stp </span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_finalize_request").call, process("/home/admin/tengine/bin/nginx").function("ngx_http_special_response_handler").call {</span><br><span class="line"> rc = int_arg(<span class="number">2</span>)</span><br><span class="line"> <span class="keyword">if</span> (rc >= <span class="number">500</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"rc: %d\n"</span>, rc)</span><br><span class="line"> print_ubacktrace()</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="3-7-5-获取全局变量"><a href="#3-7-5-获取全局变量" class="headerlink" title="3.7.5 获取全局变量"></a>3.7.5 获取全局变量</h4><blockquote><p>有时候用$可以直接获取到全局变量,但有时候又获取不到,那可以试试@var:<br>比如获取nginx的全局变量ngx_cycyle:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~<span class="meta"># cat get_ngx_cycle.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_process_events_and_timers").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"ngx_cycle->connections: %d\n"</span>, $ngx_cycle->connections)</span><br><span class="line"> <span class="built_in">exit</span>()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># stap get_ngx_cycle.stp</span></span><br><span class="line">semantic error: while processing probe process("/home/admin/tengine/bin/nginx").function("ngx_process_events_and_timers@src/event/ngx_event.c:225").call from: process("/home/admin/tengine/bin/nginx").function("ngx_process_events_and_timers").call</span><br><span class="line"></span><br><span class="line">semantic error: unable to find local 'ngx_cycle', [man error::dwarf] dieoffset 0x73ca8 in /home/admin/tengine/bin/nginx, near pc 0x434152 in ngx_process_events_and_timers src/event/ngx_event.c (alternatives: $cycle, $delta, $timer, $flags)): identifier '$ngx_cycle' at get_ngx_cycle.stp:3:44</span><br><span class="line"> source: <span class="built_in">printf</span>(<span class="string">"ngx_cycle->connections: %d\n"</span>, $ngx_cycle->connections)</span><br><span class="line"> ^</span><br><span class="line"></span><br><span class="line">Pass <span class="number">2</span>: analysis failed. [man error::pass2]</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># cat get_ngx_cycle.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_process_events_and_timers").call {</span><br><span class="line"> ngx_cycle = @var(<span class="string">"ngx_cycle@src/core/ngx_cycle.c"</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"ngx_cycle->connections: %d\n"</span>, ngx_cycle->connections)</span><br><span class="line"> <span class="built_in">exit</span>()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~# stap get_ngx_cycle.stp</span><br><span class="line">ngx_cycle->connections: <span class="number">19507312</span></span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="3-7-6-获取数据结构成员用法"><a href="#3-7-6-获取数据结构成员用法" class="headerlink" title="3.7.6 获取数据结构成员用法"></a>3.7.6 获取数据结构成员用法</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_http_uri.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri.len, $r->uri.data)</span><br><span class="line">}</span><br><span class="line"><span class="meta">#stap get_http_uri.stp</span></span><br><span class="line">WARNING: never-assigned local variable 'len' (similar: data): identifier 'len' at get_http_uri.stp:2:57</span><br><span class="line"> source: <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri.len, $r->uri.data)</span><br><span class="line"> ^</span><br><span class="line">WARNING: never-assigned local variable 'data' (similar: len): identifier 'data' at :2:70</span><br><span class="line"> source: <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri.len, $r->uri.data)</span><br><span class="line"> ^</span><br><span class="line">semantic error: invalid <span class="keyword">operator</span>: <span class="keyword">operator</span> <span class="string">'.'</span> at :<span class="number">2</span>:<span class="number">56</span></span><br><span class="line"> source: <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri.len, $r->uri.data)</span><br><span class="line"> ^</span><br><span class="line"></span><br><span class="line">semantic error: type mismatch: expected <span class="keyword">long</span> but found <span class="built_in">string</span>: <span class="keyword">operator</span> <span class="string">'.'</span> at :<span class="number">2</span>:<span class="number">56</span></span><br><span class="line"> source: <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri.len, $r->uri.data)</span><br><span class="line"> ^</span><br><span class="line"></span><br><span class="line">Pass <span class="number">2</span>: analysis failed. [man error::pass2]</span><br><span class="line"></span><br><span class="line"><span class="meta">#cat get_http_uri.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"r->uri.len: %d, r->uri.data: %p\n"</span>, $r->uri->len, $r->uri->data)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#stap get_http_uri.stp</span></span><br><span class="line">r->uri.len: <span class="number">1</span>, r->uri.data: <span class="number">0x1276f94</span></span><br><span class="line">r->uri.len: <span class="number">1</span>, r->uri.data: <span class="number">0x11d5fc4</span></span><br><span class="line">r->uri.len: <span class="number">1</span>, r->uri.data: <span class="number">0x124fd24</span></span><br><span class="line">^C</span><br></pre></td></tr></table></figure><h4 id="3-7-7-输出整个数据结构"><a href="#3-7-7-输出整个数据结构" class="headerlink" title="3.7.7 输出整个数据结构"></a>3.7.7 输出整个数据结构</h4><blockquote><p>SystemTap有两个语法可以输出整个数据结构:在变量的后面加一个或者两个$即可,例子如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_r_pool.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"$r->pool$: %s\n$r->pool$$: %s\n"</span>, $r->pool$, $r->pool$$)</span><br><span class="line">}</span><br><span class="line"><span class="meta">#stap get_r_pool.stp</span></span><br><span class="line">$r->pool$: {.d={...}, .max=<span class="number">4016</span>, .current=<span class="number">0x161acd0</span>, .chain=<span class="number">0x0</span>, .large=<span class="number">0x0</span>, .cleanup=<span class="number">0x0</span>, .<span class="built_in">log</span>=<span class="number">0x161c690</span>}</span><br><span class="line">$r->pool$$: {.d={.last=<span class="string">"a"</span>, .end=<span class="string">""</span>, .next=<span class="number">0x1617650</span>, .failed=<span class="number">0</span>}, .max=<span class="number">4016</span>, .current=<span class="number">0x161acd0</span>, .chain=<span class="number">0x0</span>, .large=<span class="number">0x0</span>, .cleanup=<span class="number">0x0</span>, .<span class="built_in">log</span>=<span class="number">0x161c690</span>}</span><br></pre></td></tr></table></figure><br>其中r->pool的结构如下:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line"> u_char *last;</span><br><span class="line"> u_char *end;</span><br><span class="line"> <span class="keyword">ngx_pool_t</span> *next;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> failed;</span><br><span class="line">} <span class="keyword">ngx_pool_data_t</span>;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ngx_pool_s</span> {</span></span><br><span class="line"> <span class="keyword">ngx_pool_data_t</span> d;</span><br><span class="line"> <span class="keyword">size_t</span> max;</span><br><span class="line"> <span class="keyword">ngx_pool_t</span> *current;</span><br><span class="line"> <span class="keyword">ngx_chain_t</span> *chain;</span><br><span class="line"> <span class="keyword">ngx_pool_large_t</span> *large;</span><br><span class="line"> <span class="keyword">ngx_pool_cleanup_t</span> *cleanup;</span><br><span class="line"> <span class="keyword">ngx_log_t</span> *<span class="built_in">log</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_DEBUG_POOL)</span></span><br><span class="line"> <span class="keyword">size_t</span> size;</span><br><span class="line"> <span class="keyword">ngx_pool_stat_t</span> *stat;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><br>ngx_pool_s包含了结构ngx_pool_data_t。变量后面加和$的区别是后者展开了里面的结构而前者不展开,此用法只输出基本数据类型的值。<p></p></blockquote><h4 id="3-7-8-输出字符串指针"><a href="#3-7-8-输出字符串指针" class="headerlink" title="3.7.8 输出字符串指针"></a>3.7.8 输出字符串指针</h4><blockquote><p>用户态使用:user_string、user_string_n<br>内核态使用:kernel_string、kernel_string_n、user_string_quoted<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_http_uri.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"r->uri: %s\nr->uri(n): %s\n"</span>, user_string($r->uri->data), user_string_n($r->uri->data, $r->uri->len))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#stap get_http_uri.stp</span></span><br><span class="line">r->uri: /?id=<span class="number">1</span> HTTP/<span class="number">1.1</span></span><br><span class="line">User-Agent</span><br><span class="line">r->uri(n): /</span><br></pre></td></tr></table></figure><br>user_string_quoted是获取用户态传给内核的字符串,代码中一般有__user宏标记:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat sys_open.stp</span></span><br><span class="line">probe kernel.function(<span class="string">"sys_open"</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"filename: %s\n"</span>, user_string_quoted(pointer_arg(<span class="number">1</span>)));</span><br><span class="line">}</span><br><span class="line"><span class="meta">#stap sys_open.stp </span></span><br><span class="line">filename: <span class="string">"/var/log/auth.log"</span></span><br><span class="line">filename: <span class="string">"/proc/stat"</span></span><br><span class="line">filename: <span class="string">"/proc/uptime"</span></span><br></pre></td></tr></table></figure><p></p></blockquote><h4 id="3-7-9-指针类型转换"><a href="#3-7-9-指针类型转换" class="headerlink" title="3.7.9 指针类型转换"></a>3.7.9 指针类型转换</h4><blockquote><p>SystemTap提供@cast来实现指针类型转换,比如可以将void *转成自己需要的类型<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_c_fd.stp </span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request_line").call {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"c->fd: %d\n"</span>, @cast($rev->data, <span class="string">"ngx_connection_t"</span>)->fd)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#stap get_c_fd.stp </span></span><br><span class="line">c->fd: <span class="number">3</span></span><br><span class="line">c->fd: <span class="number">28</span></span><br><span class="line">c->fd: <span class="number">30</span></span><br><span class="line">c->fd: <span class="number">32</span></span><br><span class="line">c->fd: <span class="number">34</span></span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-10-定义某个类型的变量"><a href="#3-7-10-定义某个类型的变量" class="headerlink" title="3.7.10 定义某个类型的变量"></a>3.7.10 定义某个类型的变量</h3><blockquote><p>同样是用@cast,定义一个变量用来保存其转换后的地址即可,用法如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_c.stp </span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request_line").call {</span><br><span class="line"> c = &@cast($rev->data, <span class="string">"ngx_connection_t"</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"c->fd: %d, c->requests: %d\n"</span>, c->fd, c->requests)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#stap get_c.stp </span><br><span class="line">c->fd: <span class="number">3</span>, c->requests: <span class="number">1</span></span><br><span class="line">c->fd: <span class="number">28</span>, c->requests: <span class="number">1</span></span><br><span class="line">c->fd: <span class="number">30</span>, c->requests: <span class="number">1</span></span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-11-多级指针用法"><a href="#3-7-11-多级指针用法" class="headerlink" title="3.7.11 多级指针用法"></a>3.7.11 多级指针用法</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~<span class="meta"># cat cc_multi_pointer.c</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">test</span> {</span></span><br><span class="line"> <span class="keyword">int</span> count;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{ </span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">test</span> <span class="title">t</span> = {</span>.count = <span class="number">5566</span>};</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">test</span> *<span class="title">pt</span> = &<span class="title">t</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">test</span> **<span class="title">ppt</span> = &<span class="title">pt</span>;</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"t.count: %d, pt->count: %d, ppt->count: %d\n"</span>, t.count, pt->count, (*ppt)->count);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># gcc -Wall -g -o cc_multi_pointer ./cc_multi_pointer.c</span></span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># cat cc_multi_pointer.stp</span></span><br><span class="line">probe process("./cc_multi_pointer").statement("main@./cc_multi_pointer.c:13")</span><br><span class="line">{ </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"$t->count: %d, $pt->count: %d, $ppt->count: %d"</span>, $t->count, $pt->count, $ppt[<span class="number">0</span>]->count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~# ./cc_multi_pointer</span><br><span class="line">t.count: <span class="number">5566</span>, pt->count: <span class="number">5566</span>, ppt->count: <span class="number">5566</span></span><br><span class="line"></span><br><span class="line">root@j9 ~# stap ./cc_multi_pointer.stp -c './cc_multi_pointer'</span><br><span class="line">t.count: <span class="number">5566</span>, pt->count: <span class="number">5566</span>, ppt->count: <span class="number">5566</span></span><br><span class="line">$t->count: <span class="number">5566</span>, $pt->count: <span class="number">5566</span>, $ppt->count: <span class="number">5566</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>简言之:通过[0]去解引用即可</p></blockquote><h3 id="3-7-12-遍历C语言数组"><a href="#3-7-12-遍历C语言数组" class="headerlink" title="3.7.12 遍历C语言数组"></a>3.7.12 遍历C语言数组</h3><blockquote><p>下面是在nginx处理请求关闭时遍历请求头的例子:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat debug_http_header.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_finalize_request").call {</span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> headers_in_part = &$r->headers_in->headers->part</span><br><span class="line"> headers = &@cast(headers_in_part->elts, <span class="string">"ngx_table_elt_t"</span>)[<span class="number">0</span>]</span><br><span class="line"> <span class="keyword">while</span> (headers) {</span><br><span class="line"> <span class="keyword">if</span> (i >= headers_in_part->nelts) {</span><br><span class="line"> <span class="keyword">if</span> (!headers_in_part->next) {</span><br><span class="line"> <span class="keyword">break</span></span><br><span class="line"> }</span><br><span class="line"> headers_in_part = headers_in_part->next;</span><br><span class="line"> headers = &@cast(headers_in_part->elts, <span class="string">"ngx_table_elt_t"</span>)[<span class="number">0</span>]</span><br><span class="line"> i = <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> h = &@cast(headers, <span class="string">"ngx_table_elt_t"</span>)[i]</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s: %s\n"</span>, user_string_n(h->key->data, h->key->len), user_string_n(h->value->data, h->value->len))</span><br><span class="line"> i += <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#stap debug_http_header.stp</span><br><span class="line">User-Agent: curl/<span class="number">7.29</span><span class="number">.0</span></span><br><span class="line">Host: <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span>:<span class="number">20090</span></span><br><span class="line">Accept: *<span class="comment">/*</span></span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-13-查看函数指针所指的函数名"><a href="#3-7-13-查看函数指针所指的函数名" class="headerlink" title="3.7.13 查看函数指针所指的函数名"></a>3.7.13 查看函数指针所指的函数名</h3><p>获取一个地址所对应的符号:<br>用户态:usymname<br>内核态:symname<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat get_c_handler.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request_line").call {</span><br><span class="line"> c = &@cast($rev->data, <span class="string">"ngx_connection_t"</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"c->read->handlers: %s, c->write->handler: %s\n"</span>, usymname(c->read->handler), usymname(c->write->handler))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">#stap get_c_handler.stp</span><br><span class="line">c->read->handlers: ngx_http_process_request_line, c->write->handler: ngx_http_empty_handler</span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p></p><h3 id="3-7-14-修改进程中的变量"><a href="#3-7-14-修改进程中的变量" class="headerlink" title="3.7.14 修改进程中的变量"></a>3.7.14 修改进程中的变量</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~<span class="meta"># cat stap_set_var.c -n </span></span><br><span class="line"> <span class="number">1</span> <span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><stdio.h></span></span></span><br><span class="line"> <span class="number">2</span></span><br><span class="line"> <span class="number">3</span> <span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">policy</span> {</span></span><br><span class="line"> <span class="number">4</span> <span class="keyword">int</span> id;</span><br><span class="line"> <span class="number">5</span> } <span class="keyword">policy_t</span>;</span><br><span class="line"> <span class="number">6</span></span><br><span class="line"> <span class="number">7</span> <span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"> 8 </span>{</span><br><span class="line"> <span class="number">9</span> <span class="keyword">policy_t</span> policy;</span><br><span class="line"> <span class="number">10</span> <span class="keyword">policy_t</span> *p = &policy;</span><br><span class="line"> <span class="number">11</span> <span class="keyword">policy_t</span> **pp;</span><br><span class="line"> <span class="number">12</span></span><br><span class="line"> <span class="number">13</span> p->id = <span class="number">111</span>;</span><br><span class="line"> <span class="number">14</span></span><br><span class="line"> <span class="number">15</span> <span class="built_in">printf</span>(<span class="string">"before stap set, p->id: %d\n"</span>, p->id);</span><br><span class="line"> <span class="number">16</span></span><br><span class="line"> <span class="number">17</span> pp = &p;</span><br><span class="line"> <span class="number">18</span></span><br><span class="line"> <span class="number">19</span> <span class="built_in">printf</span>(<span class="string">"after stap set, p->id: %d, (*pp)->id: %d\n"</span>, p->id, (*pp)->id);</span><br><span class="line"> <span class="number">20</span></span><br><span class="line"> <span class="number">21</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> <span class="number">22</span> }</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># gcc -Wall -g -o ./stap_set_var ./stap_set_var.c</span></span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># cat stap_set_var.stp</span></span><br><span class="line">probe process("./stap_set_var").statement("main@./stap_set_var.c:17")</span><br><span class="line">{</span><br><span class="line"> $p->id = <span class="number">222</span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"$p$: %s\n"</span>, $p$)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># stap -g stap_set_var.stp -c ./stap_set_var</span></span><br><span class="line">before stap <span class="built_in">set</span>, p->id: <span class="number">111</span></span><br><span class="line">after stap <span class="built_in">set</span>, p->id: <span class="number">222</span>, (*pp)->id: <span class="number">222</span></span><br><span class="line">$p$: {.id=<span class="number">222</span>}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>可以看出在第17行用SystemTap修改后的值在第19行就生效了。<br>需要注意的是stap要加-g参数在guru模式下才能修改变量的值。</p></blockquote><h3 id="3-7-15-跟踪进程执行流程"><a href="#3-7-15-跟踪进程执行流程" class="headerlink" title="3.7.15 跟踪进程执行流程"></a>3.7.15 跟踪进程执行流程</h3><blockquote><p>thread_indent(n): 补充空格<br>ppfunc(): 当前探测点所在的函数<br>在call探测点调用thread_indent(4)补充4个空格,在return探测点调用thread_indent(-4)回退4个空格,效果如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#cat trace_nginx.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("*@src/http/ngx_http_*").call</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s -> %s\n"</span>, thread_indent(<span class="number">4</span>), ppfunc());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").function("*@src/http/ngx_http_*").return</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s <- %s\n"</span>, thread_indent(<span class="number">-4</span>), ppfunc());</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-16-查看代码执行路径"><a href="#3-7-16-查看代码执行路径" class="headerlink" title="3.7.16 查看代码执行路径"></a>3.7.16 查看代码执行路径</h3><blockquote><p>pp(): 输出当前被激活的探测点<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line"><span class="meta">#cat ngx_http_process_request.stp</span></span><br><span class="line">probe process("/home/admin/tengine/bin/nginx").statement("ngx_http_process_request@src/http/ngx_http_request.c:*") {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, pp())</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#stap ngx_http_process_request.stp </span></span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2762"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2768"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2771"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2773"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2774"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2783"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2835"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2840"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2841"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2842"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2843"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2846"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2847"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2848"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2850"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2852"</span>)</span><br><span class="line">process(<span class="string">"/home/admin/tengine/bin/nginx"</span>).statement(<span class="string">"ngx_http_process_request@src/http/ngx_http_request.c:2853"</span>)</span><br><span class="line">^C</span><br></pre></td></tr></table></figure><br>可以看出该函数哪些行被执行了<p></p></blockquote><h3 id="3-7-17-巧用正则匹配过滤"><a href="#3-7-17-巧用正则匹配过滤" class="headerlink" title="3.7.17 巧用正则匹配过滤"></a>3.7.17 巧用正则匹配过滤</h3><blockquote><p>在排查问题时,可以利用一些正则匹配来获取自己想要的信息,比如下面是只收集*.j9.com的堆栈:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line">#</span><br><span class="line">cat debug_tengine_5xx.stp </span><br><span class="line">probe process("/home/admin/tengine/bin/t-coresystem-tengine-cdn").function("ngx_http_finalize_request").call {</span><br><span class="line"> rc = $rc</span><br><span class="line"> <span class="keyword">if</span> (rc < <span class="number">0</span>) {</span><br><span class="line"> host = <span class="string">"(null)"</span></span><br><span class="line"> <span class="keyword">if</span> ($r->headers_in->server->len != <span class="number">0</span>) {</span><br><span class="line"> host = user_string_n($r->headers_in->server->data, $r->headers_in->server->len)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> cscf = &@cast($r->srv_conf, <span class="string">"ngx_http_core_srv_conf_t"</span>)[@var(<span class="string">"ngx_http_core_module@src/http/ngx_http_core_module.c"</span>)->ctx_index]</span><br><span class="line"> <span class="keyword">if</span> (cscf->server_name->len != <span class="number">0</span>) {</span><br><span class="line"> host = user_string_n(cscf->server_name->data, cscf->server_name->len)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (host =~ <span class="string">".*\.j9\.com"</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"rc: %d, host: %s\n"</span>, rc, host)</span><br><span class="line"> print_ubacktrace()</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">ss#stap debug_tengine_5xx.stp</span><br><span class="line">WARNING: Missing unwind data for module, rerun with 'stap -d /lib64/libc-2.12.so'</span><br><span class="line">rc: <span class="number">-4</span>, host: www.j9.com</span><br><span class="line"> <span class="number">0x49af2e</span> : ngx_http_finalize_request+<span class="number">0xe</span>/<span class="number">0x480</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x492eab</span> : ngx_http_core_content_phase+<span class="number">0x2b</span>/<span class="number">0x130</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x48e74d</span> : ngx_http_core_run_phases+<span class="number">0x3d</span>/<span class="number">0x50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x514c3c</span> : ngx_http_lua_socket_tcp_read+<span class="number">0x44c</span>/<span class="number">0x590</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x513150</span> : ngx_http_lua_socket_tcp_handler+<span class="number">0x30</span>/<span class="number">0x50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x475b96</span> : ngx_event_process_posted+<span class="number">0x36</span>/<span class="number">0x40</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47d4d8</span> : ngx_worker_process_cycle+<span class="number">0x138</span>/<span class="number">0x260</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47a38a</span> : ngx_spawn_process+<span class="number">0x1ca</span>/<span class="number">0x5e0</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47c73c</span> : ngx_start_worker_processes+<span class="number">0x7c</span>/<span class="number">0x100</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47db5f</span> : ngx_master_process_cycle+<span class="number">0x3af</span>/<span class="number">0x9b0</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x45a740</span> : main+<span class="number">0xa90</span>/<span class="number">0xb50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x3623e1ecdd</span> [/lib64/libc<span class="number">-2.12</span>.so+<span class="number">0x1ecdd</span>/<span class="number">0x38d000</span>]</span><br><span class="line">rc: <span class="number">-4</span>, host: cdn.j9.com</span><br><span class="line"> <span class="number">0x49af2e</span> : ngx_http_finalize_request+<span class="number">0xe</span>/<span class="number">0x480</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x492eab</span> : ngx_http_core_content_phase+<span class="number">0x2b</span>/<span class="number">0x130</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x48e74d</span> : ngx_http_core_run_phases+<span class="number">0x3d</span>/<span class="number">0x50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x514c3c</span> : ngx_http_lua_socket_tcp_read+<span class="number">0x44c</span>/<span class="number">0x590</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x513150</span> : ngx_http_lua_socket_tcp_handler+<span class="number">0x30</span>/<span class="number">0x50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x475b96</span> : ngx_event_process_posted+<span class="number">0x36</span>/<span class="number">0x40</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47d4d8</span> : ngx_worker_process_cycle+<span class="number">0x138</span>/<span class="number">0x260</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47a38a</span> : ngx_spawn_process+<span class="number">0x1ca</span>/<span class="number">0x5e0</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47c73c</span> : ngx_start_worker_processes+<span class="number">0x7c</span>/<span class="number">0x100</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x47db5f</span> : ngx_master_process_cycle+<span class="number">0x3af</span>/<span class="number">0x9b0</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x45a740</span> : main+<span class="number">0xa90</span>/<span class="number">0xb50</span> [/home/admin/tengine/bin/t-coresystem-tengine-cdn]</span><br><span class="line"> <span class="number">0x3623e1ecdd</span> [/lib64/libc<span class="number">-2.12</span>.so+<span class="number">0x1ecdd</span>/<span class="number">0x38d000</span>]</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-18-关联数组用法"><a href="#3-7-18-关联数组用法" class="headerlink" title="3.7.18 关联数组用法"></a>3.7.18 关联数组用法</h3><blockquote><p>SystemTap的关联数组必须是全局变量,需要用global进行声明,其索引可以支持多达9项索引域,各域间以逗号隔开。支持 =, ++ 与 +=操作,其默认的初始值为0。<br>例如:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~<span class="meta"># cat stap_array.stp </span></span><br><span class="line">global reads</span><br><span class="line">probe vfs.read {</span><br><span class="line"> reads[execname(), pid()] ++</span><br><span class="line">}</span><br><span class="line">probe timer.s(<span class="number">3</span>) {</span><br><span class="line"> foreach ([execname, pid] in reads) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s(%d) : %d \n"</span>, execname, pid, reads[execname, pid])</span><br><span class="line"> }</span><br><span class="line"> print(<span class="string">"============================\n"</span>)</span><br><span class="line"> <span class="keyword">delete</span> reads</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># stap stap_array.stp </span></span><br><span class="line">stapio(<span class="number">18716</span>) : <span class="number">16</span> </span><br><span class="line">rsyslogd(<span class="number">770</span>) : <span class="number">1</span> </span><br><span class="line">docker(<span class="number">743</span>) : <span class="number">3</span> </span><br><span class="line">IFSWatch(<span class="number">5594</span>) : <span class="number">30</span> </span><br><span class="line">QThread(<span class="number">5594</span>) : <span class="number">6</span> </span><br><span class="line">AliYunDunUpdate(<span class="number">1057</span>) : <span class="number">4</span> </span><br><span class="line">sshd(<span class="number">15118</span>) : <span class="number">1</span> </span><br><span class="line">sshd(<span class="number">15191</span>) : <span class="number">1</span> </span><br><span class="line">============================</span><br><span class="line">stapio(<span class="number">18716</span>) : <span class="number">16</span> </span><br><span class="line">sshd(<span class="number">15191</span>) : <span class="number">3</span> </span><br><span class="line">docker(<span class="number">743</span>) : <span class="number">3</span> </span><br><span class="line">IFSWatch(<span class="number">5594</span>) : <span class="number">30</span> </span><br><span class="line">sshd(<span class="number">15118</span>) : <span class="number">2</span> </span><br><span class="line">QThread(<span class="number">5594</span>) : <span class="number">12</span> </span><br><span class="line">AliYunDunUpdate(<span class="number">1057</span>) : <span class="number">8</span> </span><br><span class="line">============================</span><br><span class="line">^C</span><br><span class="line">root@j9 ~/systemtap#</span><br></pre></td></tr></table></figure><br>也可以用+、-进行排序:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">root@j9 ~<span class="meta"># cat stap_array.stp</span></span><br><span class="line">global reads</span><br><span class="line">probe vfs.read {</span><br><span class="line"> reads[execname(), pid()] ++</span><br><span class="line">}</span><br><span class="line">probe timer.s(<span class="number">3</span>) {</span><br><span class="line"> foreach ([execname, pid+] in reads) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s(%d) : %d \n"</span>, execname, pid, reads[execname, pid])</span><br><span class="line"> }</span><br><span class="line"> print(<span class="string">"============================\n"</span>)</span><br><span class="line"> <span class="keyword">delete</span> reads</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@j9 ~<span class="meta"># stap stap_array.stp </span></span><br><span class="line">docker(<span class="number">743</span>) : <span class="number">3</span> </span><br><span class="line">rsyslogd(<span class="number">770</span>) : <span class="number">1</span> </span><br><span class="line">AliYunDunUpdate(<span class="number">1057</span>) : <span class="number">12</span> </span><br><span class="line">IFSWatch(<span class="number">5594</span>) : <span class="number">30</span> </span><br><span class="line">QThread(<span class="number">5594</span>) : <span class="number">12</span> </span><br><span class="line">sshd(<span class="number">15118</span>) : <span class="number">2</span> </span><br><span class="line">sshd(<span class="number">15191</span>) : <span class="number">2</span> </span><br><span class="line">stapio(<span class="number">19021</span>) : <span class="number">16</span> </span><br><span class="line">============================</span><br><span class="line">docker(<span class="number">743</span>) : <span class="number">3</span> </span><br><span class="line">AliYunDunUpdate(<span class="number">1057</span>) : <span class="number">12</span> </span><br><span class="line">IFSWatch(<span class="number">5594</span>) : <span class="number">30</span> </span><br><span class="line">QThread(<span class="number">5594</span>) : <span class="number">6</span> </span><br><span class="line">sshd(<span class="number">15118</span>) : <span class="number">1</span> </span><br><span class="line">sshd(<span class="number">15191</span>) : <span class="number">19</span> </span><br><span class="line">stapio(<span class="number">19021</span>) : <span class="number">16</span> </span><br><span class="line">============================</span><br><span class="line">^C</span><br><span class="line">root@j9 ~#</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-19-调试内存泄漏以及内存重复释放"><a href="#3-7-19-调试内存泄漏以及内存重复释放" class="headerlink" title="3.7.19 调试内存泄漏以及内存重复释放"></a>3.7.19 调试内存泄漏以及内存重复释放</h3><blockquote><p>在return探测点,使用函数入参需要@entry<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">probe begin {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"=============begin============\n"</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//记录内存分配和释放的计数关联数组</span></span><br><span class="line">global g_mem_ref_tbl</span><br><span class="line"><span class="comment">//记录内存分配和释放的调用堆栈关联数组,以内存地址作为key</span></span><br><span class="line">global g_mem_bt_tbl</span><br><span class="line"></span><br><span class="line">probe process("/lib/x86_64-linux-gnu/libc.so.6").function("__libc_malloc").return, process("/lib/x86_64-linux-gnu/libc.so.6").function("__libc_calloc").return {</span><br><span class="line"> <span class="keyword">if</span> (target() == pid()) {</span><br><span class="line"> <span class="keyword">if</span> (g_mem_ref_tbl[$<span class="keyword">return</span>] == <span class="number">0</span>) {</span><br><span class="line"> g_mem_ref_tbl[$<span class="keyword">return</span>]++</span><br><span class="line"> g_mem_bt_tbl[$<span class="keyword">return</span>] = sprint_ubacktrace()</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//$mem是__libc_free的参数</span></span><br><span class="line">probe process(<span class="string">"/lib/x86_64-linux-gnu/libc.so.6"</span>).function(<span class="string">"__libc_free"</span>).call {</span><br><span class="line"> <span class="keyword">if</span> (target() == pid()) {</span><br><span class="line"> g_mem_ref_tbl[$mem]--</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (g_mem_ref_tbl[$mem] == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> ($mem != <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//记录上次释放的调用堆栈</span></span><br><span class="line"> g_mem_bt_tbl[$mem] = sprint_ubacktrace()</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (g_mem_ref_tbl[$mem] < <span class="number">0</span> && $mem != <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//如果调用free已经失衡,那就出现了重复释放内存的问题,这里输出当前调用堆栈,以及这个地址上次释放的调用堆栈</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"MMMMMMMMMMMMMMMMMMMMMMMMMMMM\n"</span>)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"g_mem_ref_tbl[%p]: %d\n"</span>, $mem, g_mem_ref_tbl[$mem])</span><br><span class="line"> print_ubacktrace()</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"last free backtrace:\n%s\n"</span>, g_mem_bt_tbl[$mem])</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"WWWWWWWWWWWWWWWWWWWWWWWWWWWW\n"</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">probe end {</span><br><span class="line"> <span class="comment">//最后输出产生泄漏的内存是在哪里分配的</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"=============end============\n"</span>)</span><br><span class="line"> foreach(mem in g_mem_ref_tbl) {</span><br><span class="line"> <span class="keyword">if</span> (g_mem_ref_tbl[mem] > <span class="number">0</span>) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, g_mem_bt_tbl[mem])</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"--------------------------------\n"</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-20-嵌入C代码"><a href="#3-7-20-嵌入C代码" class="headerlink" title="3.7.20 嵌入C代码"></a>3.7.20 嵌入C代码</h3><blockquote><p>在进程fork出子进程时打印出进程id和进程名:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">root@jusse ~/systemtap<span class="meta"># cat copy_process.stp</span></span><br><span class="line">function getprocname:<span class="built_in">string</span>(task:<span class="keyword">long</span>)</span><br><span class="line">%{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">task_struct</span> *<span class="title">task</span> = (<span class="title">struct</span> <span class="title">task_struct</span> *)<span class="title">STAP_ARG_task</span>;</span></span><br><span class="line"> <span class="built_in">snprintf</span>(STAP_RETVALUE, MAXSTRINGLEN, <span class="string">"pid: %d, comm: %s"</span>, task->pid, task->comm);</span><br><span class="line">%}</span><br><span class="line"></span><br><span class="line">function getprocid:<span class="keyword">long</span>(task:<span class="keyword">long</span>)</span><br><span class="line">%{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">task_struct</span> *<span class="title">task</span> = (<span class="title">struct</span> <span class="title">task_struct</span> *)<span class="title">STAP_ARG_task</span>;</span></span><br><span class="line"> STAP_RETURN(task->pid);</span><br><span class="line">%}</span><br><span class="line"></span><br><span class="line">probe kernel.function(<span class="string">"copy_process"</span>).<span class="keyword">return</span></span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"copy_process return: %p, pid: %d, getprocname: %s, getprocid: %d\n"</span>, $<span class="keyword">return</span>, $<span class="keyword">return</span>->pid, getprocname($<span class="keyword">return</span>), getprocid($<span class="keyword">return</span>));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">root@jusse ~/systemtap<span class="meta"># stap -g copy_process.stp</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880039f61800</span>, pid: <span class="number">12212</span>, getprocname: pid: <span class="number">12212</span>, comm: bash, getprocid: <span class="number">12212</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880039f61800</span>, pid: <span class="number">12212</span>, getprocname: pid: <span class="number">12212</span>, comm: bash, getprocid: <span class="number">12212</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880039f63000</span>, pid: <span class="number">12213</span>, getprocname: pid: <span class="number">12213</span>, comm: cc_epoll, getprocid: <span class="number">12213</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880039f63000</span>, pid: <span class="number">12213</span>, getprocname: pid: <span class="number">12213</span>, comm: cc_epoll, getprocid: <span class="number">12213</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff8800081a9800</span>, pid: <span class="number">12214</span>, getprocname: pid: <span class="number">12214</span>, comm: cc_epoll, getprocid: <span class="number">12214</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff8800081a9800</span>, pid: <span class="number">12214</span>, getprocname: pid: <span class="number">12214</span>, comm: cc_epoll, getprocid: <span class="number">12214</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff8800004d8000</span>, pid: <span class="number">12215</span>, getprocname: pid: <span class="number">12215</span>, comm: cc_epoll, getprocid: <span class="number">12215</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff8800004d8000</span>, pid: <span class="number">12215</span>, getprocname: pid: <span class="number">12215</span>, comm: cc_epoll, getprocid: <span class="number">12215</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880000564800</span>, pid: <span class="number">12216</span>, getprocname: pid: <span class="number">12216</span>, comm: cc_epoll, getprocid: <span class="number">12216</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880000564800</span>, pid: <span class="number">12216</span>, getprocname: pid: <span class="number">12216</span>, comm: cc_epoll, getprocid: <span class="number">12216</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880000566000</span>, pid: <span class="number">12217</span>, getprocname: pid: <span class="number">12217</span>, comm: cc_epoll, getprocid: <span class="number">12217</span></span><br><span class="line">copy_process <span class="keyword">return</span>: <span class="number">0xffff880000566000</span>, pid: <span class="number">12217</span>, getprocname: pid: <span class="number">12217</span>, comm: cc_epoll, getprocid: <span class="number">12217</span></span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>有三个需要注意的地方:<br>1)、SystemTap脚本里面嵌入C语言代码要在每个大括号前加%前缀,是%{…… %} 而不是%{ …… }%;<br>2)、获取脚本函数参数要用STAP_ARG_前缀;<br>3)、一般long等返回值用STAP_RETURN,而string类型返回值要用snprintf、strncat等方式把字符串复制到STAP_RETVALUE里面。</p></blockquote><h3 id="3-7-21-调试内核模块"><a href="#3-7-21-调试内核模块" class="headerlink" title="3.7.21 调试内核模块"></a>3.7.21 调试内核模块</h3><blockquote><p>这小节就不细讲了,这篇博客 (<a href="http://blog.chinaunix.net/uid-14528823-id-4726046.html" target="_blank" rel="noopener">http://blog.chinaunix.net/uid-14528823-id-4726046.html</a>) 写得很详细,这里只copy两个关键点过来记录一下:<br>要调试自己的内核模块,需要注意的有两个关键点:<br>1)、使用SystemTap调试内核模块,探测点的编写格式示例为:<br>module(“ext3”).function(“ext3_*”)<br>2)、需要将自己的模块cp到/lib/modules/uname -r/extra目录中,否则找不到符号,如果/lib/modules/uname -r/目录下没有extra这个目录,自己mkdir一下就可以。</p></blockquote><h3 id="3-7-22-一些错误提示及解决办法"><a href="#3-7-22-一些错误提示及解决办法" class="headerlink" title="3.7.22 一些错误提示及解决办法"></a>3.7.22 一些错误提示及解决办法</h3><blockquote><p>错误提示1:<br></p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ERROR: MAXACTION exceeded near keyword at debug_connection.stp:<span class="number">86</span>:<span class="number">9</span></span><br><span class="line">ERROR: MAXACTION exceeded near operator '->' at debug_connection.stp:84:30</span><br></pre></td></tr></table></figure><br>解决办法:<br>加上stap参数:-DMAXACTION=102400,如果还报这种类型的错误,只需把102400调成更大的值即可。<br>错误提示2:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WARNING: Number of errors: <span class="number">0</span>, skipped probes: <span class="number">82</span></span><br></pre></td></tr></table></figure><br>解决办法:<br>加上-DMAXSKIPPED=102400和-DSTP_NO_OVERLOAD参数<br>还有一些可以去掉限制的宏:<p></p></blockquote><p>MAXSTRINGLEN:这个宏会影响sprintf的buffer大小,默认为512字节。<br>MAXTRYLOCK:对全局变量进行try lock操作的次数,超过则次数还拿不到锁则放弃和跳过该探测点,默认值为1000.全局变量多的时候可以把这个宏开大一点。</p><h3 id="3-7-23-传递参数"><a href="#3-7-23-传递参数" class="headerlink" title="3.7.23 传递参数"></a>3.7.23 传递参数</h3><h3 id="3-7-24-常用函数"><a href="#3-7-24-常用函数" class="headerlink" title="3.7.24 常用函数"></a>3.7.24 常用函数</h3><blockquote><p>本节来介绍systemtap中常用的一些函数<br>tid():当前线程ID。<br>uid():当前用户ID。<br>cpu():当前CPU编号。<br>ctime():当前UNIX epoch秒数。<br>pp():当前探测点的描述字符串<br>exit(): 执行一次后退出。<br>execname():当前运行的进程名称。<br>probefunc():探测点函数名称。<br>target():在stap使用-c command或者-x process命令时,target()能拿到进程的pid。<br>name():返回系统调用的名称字符串,仅能在syscall类型的探针处理函数中使用。<br>thread_indent(delta):它可以输出当前probe所处的可执行程序名称、线程id、函数执行的相对时间和执行的次数(通过空格的数量)信息,它的返回值就是一个字符串。参数delta是在每次调用时增加或移除的空白数量。<br>@defined和@choose_defined<br>由于版本变化,有一些变量可能在新版本中不存在了,此时可以使用@define来检查变量是否存在:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">probe vm.pagefault = kernel.function(<span class="string">"__handle_mm_fault@mm/memory.c"</span>) ?,</span><br><span class="line"> kernel.function(<span class="string">"handle_mm_fault@mm/memory.c"</span>) ?</span><br><span class="line">{</span><br><span class="line"> write_access = (@defined($flags) ? $flags & FAULT_FLAG_WRITE : $write_access)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>@entry<br>在.return探针中,有一个特殊的操作符@entry,用于存储该探针的入口处的表达式的值,可以使用这个操作符,完成比如计算探针函数执行时间计算等工作,比如:<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">global sloth = <span class="number">50</span></span><br><span class="line"> </span><br><span class="line">probe vfs.open.<span class="keyword">return</span> {</span><br><span class="line"> time = gettimeofday_us()-@entry(gettimeofday_us())</span><br><span class="line"> <span class="keyword">if</span> (time >= sloth)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s[%d] %d %s\n"</span>, execname(), tid(), time, pathname)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><br>这个脚本在vfs.open.return探针处理函数中,通过@entry操作符,计算完成vfs.open操作的时间差,如果超过设置的阈值50就打印相关信息。<br>-G命令行参数,可以设置全局变量VAR的值为VAL,相应地就可以作为开关来控制脚本的行为,比如:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">// sudo stap G-params.stp -G flag=1</span><br><span class="line">// flag has set</span><br><span class="line">global flag=0</span><br><span class="line"></span><br><span class="line">probe begin {</span><br><span class="line"> if (flag == 0) {</span><br><span class="line"> printf("flag not set\n")</span><br><span class="line"> } else {</span><br><span class="line"> printf("flag has set\n")</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="3-7-25-异步事件"><a href="#3-7-25-异步事件" class="headerlink" title="3.7.25 异步事件"></a>3.7.25 异步事件</h3><blockquote><p>常见的异步事件是begin、end、never、timers。<br>timers用于定义定时器探测点,常见的格式timer.s(1)来定义每秒触发的探测点。<br>never定义的探测点不会被调用到,很多时候加这个探测点只是为了检查一些语法错误。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、安装"><a href="#1、安装" class="headerlink" title="1、安装"></a>1、安装</h2>
</summary>
<category term="systemtap" scheme="https://weeweetan.github.io/tags/systemtap/"/>
</entry>
<entry>
<title>Nginx的http模块代码分析</title>
<link href="https://weeweetan.github.io/2021/10/02/Nginx%E7%9A%84http%E6%A8%A1%E5%9D%97%E4%BB%A3%E7%A0%81%E5%88%86%E6%9E%90/"/>
<id>https://weeweetan.github.io/2021/10/02/Nginx的http模块代码分析/</id>
<published>2021-10-02T11:29:02.000Z</published>
<updated>2024-03-04T14:45:02.258Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、代码框架"><a href="#1、代码框架" class="headerlink" title="1、代码框架"></a>1、代码框架</h2><blockquote><p>http模块主要代码放在ngx_http.c这个文件中,接下来我们就来分析下相关代码<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">char</span> *<span class="title">ngx_http_block</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_phases</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_headers_in_hash</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_phase_handlers</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_add_addresses</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf, <span class="keyword">ngx_http_conf_port_t</span> *port,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_listen_opt_t</span> *lsopt)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_add_address</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf, <span class="keyword">ngx_http_conf_port_t</span> *port,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_listen_opt_t</span> *lsopt)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_add_server</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf, <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">char</span> *<span class="title">ngx_http_merge_servers</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf, <span class="keyword">ngx_http_module_t</span> *<span class="keyword">module</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_uint_t</span> ctx_index)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">char</span> *<span class="title">ngx_http_merge_locations</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_queue_t</span> *locations, <span class="keyword">void</span> **loc_conf, <span class="keyword">ngx_http_module_t</span> *<span class="keyword">module</span>,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_uint_t</span> ctx_index)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_locations</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf, <span class="keyword">ngx_http_core_loc_conf_t</span> *pclcf)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_static_location_trees</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_loc_conf_t</span> *pclcf)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_cmp_locations</span><span class="params">(<span class="keyword">const</span> <span class="keyword">ngx_queue_t</span> *one,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">ngx_queue_t</span> *two)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_join_exact_locations</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_queue_t</span> *locations)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">ngx_http_create_locations_list</span><span class="params">(<span class="keyword">ngx_queue_t</span> *locations,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_queue_t</span> *q)</span></span>;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_http_location_tree_node_t</span> *</span><br><span class="line"> ngx_http_create_locations_tree(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_queue_t</span> *locations,</span><br><span class="line"> <span class="keyword">size_t</span> prefix);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_optimize_servers</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf, <span class="keyword">ngx_array_t</span> *ports)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_server_names</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf, <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_cmp_conf_addrs</span><span class="params">(<span class="keyword">const</span> <span class="keyword">void</span> *one, <span class="keyword">const</span> <span class="keyword">void</span> *two)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> ngx_libc_cdecl <span class="title">ngx_http_cmp_dns_wildcards</span><span class="params">(<span class="keyword">const</span> <span class="keyword">void</span> *one,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">const</span> <span class="keyword">void</span> *two)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_init_listening</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_conf_port_t</span> *port)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_listening_t *<span class="title">ngx_http_add_listening</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_add_addrs</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_port_t</span> *hport,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span></span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> ngx_int_t <span class="title">ngx_http_add_addrs6</span><span class="params">(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_port_t</span> *hport,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span></span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br></pre></td></tr></table></figure><br>在ngx_http.c文件最前面这部分代码全部是函数声明,接下来看下http模块配置,指令设置、函数指针以及模块结构初始化<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ngx_uint_t</span> ngx_http_max_module;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">ngx_http_output_header_filter_pt ngx_http_top_header_filter;</span><br><span class="line">ngx_http_output_body_filter_pt ngx_http_top_body_filter;</span><br><span class="line">ngx_http_request_body_filter_pt ngx_http_top_request_body_filter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">ngx_str_t</span> ngx_http_html_default_types[] = {</span><br><span class="line"> ngx_string(<span class="string">"text/html"</span>),</span><br><span class="line"> ngx_null_string</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// http指令定义</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_command_t</span> ngx_http_commands[] = {</span><br><span class="line"></span><br><span class="line"> { ngx_string(<span class="string">"http"</span>),</span><br><span class="line"> NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,</span><br><span class="line"> ngx_http_block,</span><br><span class="line"> <span class="number">0</span>,</span><br><span class="line"> <span class="number">0</span>,</span><br><span class="line"> <span class="literal">NULL</span> },</span><br><span class="line"></span><br><span class="line"> ngx_null_command</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">//核心模块上下文</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_core_module_t</span> ngx_http_module_ctx = {</span><br><span class="line"> ngx_string(<span class="string">"http"</span>),</span><br><span class="line"> <span class="literal">NULL</span>,</span><br><span class="line"> <span class="literal">NULL</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">//http模块定义</span></span><br><span class="line"><span class="keyword">ngx_module_t</span> ngx_http_module = {</span><br><span class="line"> NGX_MODULE_V1,</span><br><span class="line"> &ngx_http_module_ctx, <span class="comment">/* module context */</span></span><br><span class="line"> ngx_http_commands, <span class="comment">/* module directives */</span></span><br><span class="line"> NGX_CORE_MODULE, <span class="comment">/* module type */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* init master */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* init module */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* init process */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* init thread */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* exit thread */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* exit process */</span></span><br><span class="line"> <span class="literal">NULL</span>, <span class="comment">/* exit master */</span></span><br><span class="line"> NGX_MODULE_V1_PADDING</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>接下来看下http块解析函数,ngx_http_block函数实现<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_block(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *rv;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> mi, m, s;</span><br><span class="line"> <span class="keyword">ngx_conf_t</span> pcf;</span><br><span class="line"> <span class="keyword">ngx_http_module_t</span> *<span class="keyword">module</span>;</span><br><span class="line"> <span class="keyword">ngx_http_conf_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_http_core_loc_conf_t</span> *clcf;</span><br><span class="line"> <span class="keyword">ngx_http_core_srv_conf_t</span> **cscfp;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 判断是否重复配置</span></span><br><span class="line"> <span class="keyword">if</span> (*(<span class="keyword">ngx_http_conf_ctx_t</span> **) conf) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* the main http context */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 申请保存上下文的内存</span></span><br><span class="line"> ctx = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_conf_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *(<span class="keyword">ngx_http_conf_ctx_t</span> **) conf = ctx;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* count the number of the http modules and set up their indices */</span></span><br><span class="line"></span><br><span class="line"> ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* the http main_conf context, it is the same in the all http contexts */</span></span><br><span class="line"></span><br><span class="line"> ctx->main_conf = ngx_pcalloc(cf->pool,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) * ngx_http_max_module);</span><br><span class="line"> <span class="keyword">if</span> (ctx->main_conf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * the http null srv_conf context, it is used to merge</span></span><br><span class="line"><span class="comment"> * the server{}s' srv_conf's</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> ctx->srv_conf = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) * ngx_http_max_module);</span><br><span class="line"> <span class="keyword">if</span> (ctx->srv_conf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * the http null loc_conf context, it is used to merge</span></span><br><span class="line"><span class="comment"> * the server{}s' loc_conf's</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> ctx->loc_conf = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) * ngx_http_max_module);</span><br><span class="line"> <span class="keyword">if</span> (ctx->loc_conf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * create the main_conf's, the null srv_conf's, and the null loc_conf's</span></span><br><span class="line"><span class="comment"> * of the all http modules</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">0</span>; cf->cycle->modules[m]; m++) {</span><br><span class="line"> <span class="comment">// 跳过非http模块</span></span><br><span class="line"> <span class="keyword">if</span> (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">module</span> = cf->cycle->modules[m]->ctx;</span><br><span class="line"> mi = cf->cycle->modules[m]->ctx_index;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个模块创建main级别conf的函数指针</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->create_main_conf) {</span><br><span class="line"> ctx->main_conf[mi] = <span class="keyword">module</span>->create_main_conf(cf);</span><br><span class="line"> <span class="keyword">if</span> (ctx->main_conf[mi] == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个模块创建server级别conf的函数指针</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->create_srv_conf) {</span><br><span class="line"> ctx->srv_conf[mi] = <span class="keyword">module</span>->create_srv_conf(cf);</span><br><span class="line"> <span class="keyword">if</span> (ctx->srv_conf[mi] == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个模块创建location级别conf的函数指针</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->create_loc_conf) {</span><br><span class="line"> ctx->loc_conf[mi] = <span class="keyword">module</span>->create_loc_conf(cf);</span><br><span class="line"> <span class="keyword">if</span> (ctx->loc_conf[mi] == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 保存cf,在解析完配置后会还原</span></span><br><span class="line"> pcf = *cf;</span><br><span class="line"> <span class="comment">// 保存http级别conf</span></span><br><span class="line"> cf->ctx = ctx;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">0</span>; cf->cycle->modules[m]; m++) {</span><br><span class="line"> <span class="comment">// 跳过非http模块</span></span><br><span class="line"> <span class="keyword">if</span> (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">module</span> = cf->cycle->modules[m]->ctx;</span><br><span class="line"> <span class="comment">//调用每个模块preconfiguration函数指针,在解析配置前需要做的</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->preconfiguration) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->preconfiguration(cf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* parse inside the http{} block */</span></span><br><span class="line"></span><br><span class="line"> cf->module_type = NGX_HTTP_MODULE;</span><br><span class="line"> cf->cmd_type = NGX_HTTP_MAIN_CONF;</span><br><span class="line"> <span class="comment">// 开始解析http块里面的配置</span></span><br><span class="line"> rv = ngx_conf_parse(cf, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rv != NGX_CONF_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * init http{} main_conf's, merge the server{}s' srv_conf's</span></span><br><span class="line"><span class="comment"> * and its location{}s' loc_conf's</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 取http main级别的conf</span></span><br><span class="line"> cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"> cscfp = cmcf->servers.elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个http模块初始化main级别配置的函数</span></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">0</span>; cf->cycle->modules[m]; m++) {</span><br><span class="line"> <span class="comment">// 跳过非http模块</span></span><br><span class="line"> <span class="keyword">if</span> (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">module</span> = cf->cycle->modules[m]->ctx;</span><br><span class="line"> mi = cf->cycle->modules[m]->ctx_index;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* init http{} main_conf's */</span></span><br><span class="line"> <span class="comment">// 调用每个模块init_main_conf函数指针</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->init_main_conf) {</span><br><span class="line"> rv = <span class="keyword">module</span>->init_main_conf(cf, ctx->main_conf[mi]);</span><br><span class="line"> <span class="keyword">if</span> (rv != NGX_CONF_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 合并server级别及location级别配置</span></span><br><span class="line"> rv = ngx_http_merge_servers(cf, cmcf, <span class="keyword">module</span>, mi);</span><br><span class="line"> <span class="keyword">if</span> (rv != NGX_CONF_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* create location trees */</span></span><br><span class="line"> <span class="comment">// 构造http请求location匹配树</span></span><br><span class="line"> <span class="keyword">for</span> (s = <span class="number">0</span>; s < cmcf->servers.nelts; s++) {</span><br><span class="line"></span><br><span class="line"> clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 构造静态location匹配树</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化各个阶段的array</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_phases(cf, cmcf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化http请求头headers</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理每个http模块postconfiguration</span></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">0</span>; cf->cycle->modules[m]; m++) {</span><br><span class="line"> <span class="keyword">if</span> (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">module</span> = cf->cycle->modules[m]->ctx;</span><br><span class="line"> <span class="comment">//调用每个模块postconfiguration函数指针,用于处理配置解析完成后的操作</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->postconfiguration) {</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->postconfiguration(cf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化http变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_variables_init_vars(cf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * http{}'s cf->ctx was needed while the configuration merging</span></span><br><span class="line"><span class="comment"> * and in postconfiguration process</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="comment">// 恢复cf</span></span><br><span class="line"> *cf = pcf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化http各个阶段handler</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* optimize the lists of ports, addresses and server names */</span></span><br><span class="line"> <span class="comment">// 处理相同端口以及server_name</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"></span><br><span class="line">failed:</span><br><span class="line"> <span class="comment">// 恢复cf</span></span><br><span class="line"> *cf = pcf;</span><br><span class="line"> <span class="comment">// 返回结果</span></span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>接下来分析ngx_http_optimize_servers函数,此函数用于处理IP+Port相同,不同server_name的情况<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_optimize_servers(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf,</span><br><span class="line"> <span class="keyword">ngx_array_t</span> *ports)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> p, a;</span><br><span class="line"> <span class="keyword">ngx_http_conf_port_t</span> *port;</span><br><span class="line"> <span class="keyword">ngx_http_conf_addr_t</span> *addr;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果没有配置端口,则返回</span></span><br><span class="line"> <span class="keyword">if</span> (ports == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 遍历已经配置的port列表,</span></span><br><span class="line"> port = ports->elts;</span><br><span class="line"> <span class="keyword">for</span> (p = <span class="number">0</span>; p < ports->nelts; p++) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将同一个port下挂的addr进行排序</span></span><br><span class="line"> ngx_sort(port[p].addrs.elts, (<span class="keyword">size_t</span>) port[p].addrs.nelts,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_conf_addr_t</span>), ngx_http_cmp_conf_addrs);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * check whether all name-based servers have the same</span></span><br><span class="line"><span class="comment"> * configuration as a default server for given address:port</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果一个addr下有多个server块,则处理server_name</span></span><br><span class="line"> addr = port[p].addrs.elts;</span><br><span class="line"> <span class="keyword">for</span> (a = <span class="number">0</span>; a < port[p].addrs.nelts; a++) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (addr[a].servers.nelts > <span class="number">1</span></span><br><span class="line">#<span class="keyword">if</span> (NGX_PCRE)</span><br><span class="line"> || addr[a].default_server->captures</span><br><span class="line">#endif</span><br><span class="line"> )</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理listen,从cycle->listening分配元素</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><ol start="3"><li>接下来分析ngx_http_server_names函数,这个函数的功能是server_name进行hash处理<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_server_names(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf,</span><br><span class="line"> <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_int_t</span> rc;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> n, s;</span><br><span class="line"> <span class="keyword">ngx_hash_init_t</span> hash;</span><br><span class="line"> <span class="keyword">ngx_hash_keys_arrays_t</span> ha;</span><br><span class="line"> <span class="keyword">ngx_http_server_name_t</span> *name;</span><br><span class="line"> <span class="keyword">ngx_http_core_srv_conf_t</span> **cscfp;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"> <span class="keyword">ngx_uint_t</span> regex, i;</span><br><span class="line"></span><br><span class="line"> regex = <span class="number">0</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化hash key数组</span></span><br><span class="line"> ngx_memzero(&ha, <span class="keyword">sizeof</span>(<span class="keyword">ngx_hash_keys_arrays_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建初始化hash table所需的内存池</span></span><br><span class="line"> ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf-><span class="built_in">log</span>);</span><br><span class="line"> <span class="keyword">if</span> (ha.temp_pool == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ha.pool = cf->pool;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化hash key</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cscfp = addr->servers.elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 遍历此地址下的所有server块</span></span><br><span class="line"> <span class="keyword">for</span> (s = <span class="number">0</span>; s < addr->servers.nelts; s++) {</span><br><span class="line"></span><br><span class="line"> name = cscfp[s]->server_names.elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < cscfp[s]->server_names.nelts; n++) {</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"> <span class="keyword">if</span> (name[n].regex) {</span><br><span class="line"> regex++;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将server_name添加到key中</span></span><br><span class="line"> rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,</span><br><span class="line"> NGX_HASH_WILDCARD_KEY);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_DECLINED) {</span><br><span class="line"> ngx_log_error(NGX_LOG_EMERG, cf-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid server name or wildcard \"%V\" on %V"</span>,</span><br><span class="line"> &name[n].name, &addr->opt.addr_text);</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// server_name出现冲突</span></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_BUSY) {</span><br><span class="line"> ngx_log_error(NGX_LOG_WARN, cf-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"conflicting server name \"%V\" on %V, ignored"</span>,</span><br><span class="line"> &name[n].name, &addr->opt.addr_text);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 对hash表赋初值</span></span><br><span class="line"> hash.key = ngx_hash_key_lc;</span><br><span class="line"> hash.max_size = cmcf->server_names_hash_max_size;</span><br><span class="line"> hash.bucket_size = cmcf->server_names_hash_bucket_size;</span><br><span class="line"> hash.name = <span class="string">"server_names_hash"</span>;</span><br><span class="line"> hash.pool = cf->pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ha.keys.nelts) {</span><br><span class="line"> hash.hash = &addr->hash;</span><br><span class="line"> hash.temp_pool = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 前缀匹配</span></span><br><span class="line"> <span class="keyword">if</span> (ha.dns_wc_head.nelts) {</span><br><span class="line"></span><br><span class="line"> ngx_qsort(ha.dns_wc_head.elts, (<span class="keyword">size_t</span>) ha.dns_wc_head.nelts,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_hash_key_t</span>), ngx_http_cmp_dns_wildcards);</span><br><span class="line"></span><br><span class="line"> hash.hash = <span class="literal">NULL</span>;</span><br><span class="line"> hash.temp_pool = ha.temp_pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,</span><br><span class="line"> ha.dns_wc_head.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addr->wc_head = (<span class="keyword">ngx_hash_wildcard_t</span> *) hash.hash;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 后缀匹配</span></span><br><span class="line"> <span class="keyword">if</span> (ha.dns_wc_tail.nelts) {</span><br><span class="line"></span><br><span class="line"> ngx_qsort(ha.dns_wc_tail.elts, (<span class="keyword">size_t</span>) ha.dns_wc_tail.nelts,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_hash_key_t</span>), ngx_http_cmp_dns_wildcards);</span><br><span class="line"></span><br><span class="line"> hash.hash = <span class="literal">NULL</span>;</span><br><span class="line"> hash.temp_pool = ha.temp_pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,</span><br><span class="line"> ha.dns_wc_tail.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addr->wc_tail = (<span class="keyword">ngx_hash_wildcard_t</span> *) hash.hash;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_destroy_pool(ha.temp_pool);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理正则</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (regex == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addr->nregex = regex;</span><br><span class="line"> addr->regex = ngx_palloc(cf->pool, regex * <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_server_name_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (addr->regex == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (s = <span class="number">0</span>; s < addr->servers.nelts; s++) {</span><br><span class="line"></span><br><span class="line"> name = cscfp[s]->server_names.elts;</span><br><span class="line"> <span class="comment">// 遍历server_name,对regex进行处理</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < cscfp[s]->server_names.nelts; n++) {</span><br><span class="line"> <span class="keyword">if</span> (name[n].regex) {</span><br><span class="line"> addr->regex[i++] = name[n];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line"></span><br><span class="line">failed:</span><br><span class="line"> <span class="comment">// 释放temp_pool</span></span><br><span class="line"> ngx_destroy_pool(ha.temp_pool);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="4"><li>接下来分析ngx_http_init_listening函数<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_init_listening(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_conf_port_t</span> *port)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, last, bind_wildcard;</span><br><span class="line"> <span class="keyword">ngx_listening_t</span> *ls;</span><br><span class="line"> <span class="keyword">ngx_http_port_t</span> *hport;</span><br><span class="line"> <span class="keyword">ngx_http_conf_addr_t</span> *addr;</span><br><span class="line"></span><br><span class="line"> addr = port->addrs.elts;</span><br><span class="line"> last = port->addrs.nelts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> * If there is a binding to an "*:port" then we need to bind() to</span></span><br><span class="line"><span class="comment"> * the "*:port" only and ignore other implicit bindings. The bindings</span></span><br><span class="line"><span class="comment"> * have been already sorted: explicit bindings are on the start, then</span></span><br><span class="line"><span class="comment"> * implicit bindings go, and wildcard binding is in the end.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (addr[last - <span class="number">1</span>].opt.wildcard) {</span><br><span class="line"> addr[last - <span class="number">1</span>].opt.bind = <span class="number">1</span>;</span><br><span class="line"> bind_wildcard = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> bind_wildcard = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> i = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (i < last) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (bind_wildcard && !addr[i].opt.bind) {</span><br><span class="line"> i++;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从ngx_cycle->listening中push一个ls,跟socket相关的都保存在这里面</span></span><br><span class="line"> ls = ngx_http_add_listening(cf, &addr[i]);</span><br><span class="line"> <span class="keyword">if</span> (ls == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 分配保存地址的内存,在ngx_init_connection中使用</span></span><br><span class="line"> hport = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_port_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (hport == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ls->servers = hport;</span><br><span class="line"></span><br><span class="line"> hport->naddrs = i + <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> (ls->sockaddr->sa_family) {</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> <span class="keyword">case</span> AF_INET6:</span><br><span class="line"> <span class="keyword">if</span> (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">default</span>: <span class="comment">/* AF_INET */</span></span><br><span class="line"> <span class="comment">// 将addr中的内容复制到hport中</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addr++;</span><br><span class="line"> last--;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="5"><li>接下来看看ngx_http_add_addrs函数的实现,ngx_http_add_addrs6类似<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_add_addrs(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_port_t</span> *hport,</span><br><span class="line"> <span class="keyword">ngx_http_conf_addr_t</span> *addr)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_http_in_addr_t</span> *addrs;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> *<span class="title">sin</span>;</span></span><br><span class="line"> <span class="keyword">ngx_http_virtual_names_t</span> *vn;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 申请必要内存,naddrs就是外面计算的这个端口下的ip个数</span></span><br><span class="line"> hport->addrs = ngx_pcalloc(cf->pool,</span><br><span class="line"> hport->naddrs * <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_in_addr_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (hport->addrs == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addrs = hport->addrs;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < hport->naddrs; i++) {</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sin</span> = (struct sockaddr_in *) addr[i].opt.sockaddr;</span><br><span class="line"> addrs[i].addr = <span class="built_in">sin</span>->sin_addr.s_addr;</span><br><span class="line"> addrs[i].conf.default_server = addr[i].default_server;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HTTP_SSL)</span></span><br><span class="line"> addrs[i].conf.ssl = addr[i].opt.ssl;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HTTP_V2)</span></span><br><span class="line"> addrs[i].conf.http2 = addr[i].opt.http2;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果匹配server_name所需的hash桶为空,则不进行下一步操作</span></span><br><span class="line"> <span class="keyword">if</span> (addr[i].hash.buckets == <span class="literal">NULL</span></span><br><span class="line"> && (addr[i].wc_head == <span class="literal">NULL</span></span><br><span class="line"> || addr[i].wc_head->hash.buckets == <span class="literal">NULL</span>)</span><br><span class="line"> && (addr[i].wc_tail == <span class="literal">NULL</span></span><br><span class="line"> || addr[i].wc_tail->hash.buckets == <span class="literal">NULL</span>)</span><br><span class="line">#<span class="keyword">if</span> (NGX_PCRE)</span><br><span class="line"> && addr[i].nregex == <span class="number">0</span></span><br><span class="line">#endif</span><br><span class="line"> )</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 申请保存server_name匹配所需内存</span></span><br><span class="line"> vn = ngx_palloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_virtual_names_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (vn == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> addrs[i].conf.virtual_names = vn;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 保存server_name匹配所需的hash值</span></span><br><span class="line"> vn->names.hash = addr[i].hash;</span><br><span class="line"> vn->names.wc_head = addr[i].wc_head;</span><br><span class="line"> vn->names.wc_tail = addr[i].wc_tail;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"> vn->nregex = addr[i].nregex;</span><br><span class="line"> vn->regex = addr[i].regex;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li>接下来看看函数的实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、代码框架"><a href="#1、代码框架" class="headerlink" title="1、代码框架"></a>1、代
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的http_core模块</title>
<link href="https://weeweetan.github.io/2021/05/09/Nginx%E7%9A%84http-core%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2021/05/09/Nginx的http-core模块/</id>
<published>2021-05-09T13:06:24.000Z</published>
<updated>2023-06-28T14:45:12.710Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相关配置</h2><blockquote><p>核心模块配置如下<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">server {</span><br><span class="line"> listen <span class="number">80</span>;</span><br><span class="line"> location / {</span><br><span class="line"> root html;</span><br><span class="line"> index index.html;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>以上是http模块最核心的配置,一条listen指令,一条location指令,能够监听80端口,提供简单的web服务。<p></p></blockquote><h2 id="2、相关代码"><a href="#2、相关代码" class="headerlink" title="2、相关代码"></a>2、相关代码</h2><blockquote><ol><li>首先看下解析server指令的代码<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_core_server(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *dummy)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *rv;</span><br><span class="line"> <span class="keyword">void</span> *mconf;</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> u_char *p;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_conf_t</span> pcf;</span><br><span class="line"> <span class="keyword">ngx_http_module_t</span> *<span class="keyword">module</span>;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">sockaddr_in</span> *<span class="title">sin</span>;</span></span><br><span class="line"> <span class="keyword">ngx_http_conf_ctx_t</span> *ctx, *http_ctx;</span><br><span class="line"> <span class="keyword">ngx_http_listen_opt_t</span> lsopt;</span><br><span class="line"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf, **cscfp;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 首先分配上下文内存</span></span><br><span class="line"> ctx = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_conf_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 保存http模块main级别的conf</span></span><br><span class="line"> http_ctx = cf->ctx;</span><br><span class="line"> ctx->main_conf = http_ctx->main_conf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* the server{}'s srv_conf */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 预分配保存server级别的内存</span></span><br><span class="line"> ctx->srv_conf = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) * ngx_http_max_module);</span><br><span class="line"> <span class="keyword">if</span> (ctx->srv_conf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* the server{}'s loc_conf */</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 预分配location级别的内存</span></span><br><span class="line"> ctx->loc_conf = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">void</span> *) * ngx_http_max_module);</span><br><span class="line"> <span class="keyword">if</span> (ctx->loc_conf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; cf->cycle->modules[i]; i++) {</span><br><span class="line"> <span class="keyword">if</span> (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">module</span> = cf->cycle->modules[i]->ctx;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个模块create_srv_conf函数指针,创建server级别conf</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->create_srv_conf) {</span><br><span class="line"> mconf = <span class="keyword">module</span>->create_srv_conf(cf);</span><br><span class="line"> <span class="keyword">if</span> (mconf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 使用模块索引保存创建的server级别conf</span></span><br><span class="line"> ctx->srv_conf[cf->cycle->modules[i]->ctx_index] = mconf;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用每个模块create_loc_conf函数指针,创建location级别conf</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">module</span>->create_loc_conf) {</span><br><span class="line"> mconf = <span class="keyword">module</span>->create_loc_conf(cf);</span><br><span class="line"> <span class="keyword">if</span> (mconf == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 使用模块索引保存创建的location级别conf</span></span><br><span class="line"> ctx->loc_conf[cf->cycle->modules[i]->ctx_index] = mconf;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* the server configuration context */</span></span><br><span class="line"></span><br><span class="line"> cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"> cscf->ctx = ctx;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取http的主配置</span></span><br><span class="line"> cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建servers数组</span></span><br><span class="line"> cscfp = ngx_array_push(&cmcf->servers);</span><br><span class="line"> <span class="keyword">if</span> (cscfp == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//保存cscfp</span></span><br><span class="line"> *cscfp = cscf;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/* parse inside server{} */</span></span><br><span class="line"></span><br><span class="line"> pcf = *cf;</span><br><span class="line"> cf->ctx = ctx;</span><br><span class="line"> cf->cmd_type = NGX_HTTP_SRV_CONF;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 开始解析server块配置</span></span><br><span class="line"> rv = ngx_conf_parse(cf, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 还原cf</span></span><br><span class="line"> *cf = pcf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理没有监听端口的情况, 默认80</span></span><br><span class="line"> <span class="keyword">if</span> (rv == NGX_CONF_OK && !cscf->listen) {</span><br><span class="line"> ngx_memzero(&lsopt, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_listen_opt_t</span>));</span><br><span class="line"></span><br><span class="line"> p = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(struct sockaddr_in));</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lsopt.sockaddr = (struct sockaddr *) p;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sin</span> = (struct sockaddr_in *) p;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">sin</span>->sin_family = AF_INET;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_WIN32)</span></span><br><span class="line"> <span class="built_in">sin</span>->sin_port = htons(<span class="number">80</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> <span class="built_in">sin</span>->sin_port = htons((getuid() == <span class="number">0</span>) ? <span class="number">80</span> : <span class="number">8000</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="built_in">sin</span>->sin_addr.s_addr = INADDR_ANY;</span><br><span class="line"></span><br><span class="line"> lsopt.socklen = <span class="keyword">sizeof</span>(struct sockaddr_in);</span><br><span class="line"></span><br><span class="line"> lsopt.backlog = NGX_LISTEN_BACKLOG;</span><br><span class="line"> lsopt.rcvbuf = <span class="number">-1</span>;</span><br><span class="line"> lsopt.sndbuf = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_SETFIB)</span></span><br><span class="line"> lsopt.setfib = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_TCP_FASTOPEN)</span></span><br><span class="line"> lsopt.fastopen = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> lsopt.wildcard = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> len = NGX_INET_ADDRSTRLEN + <span class="keyword">sizeof</span>(<span class="string">":65535"</span>) - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> p = ngx_pnalloc(cf->pool, len);</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lsopt.addr_text.data = p;</span><br><span class="line"> lsopt.addr_text.len = ngx_sock_ntop(lsopt.sockaddr, lsopt.socklen, p,</span><br><span class="line"> len, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 添加端口到listening列表</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="2"><li>接下来看看解析listen指令的函数, ngx_http_core_listen的实现<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_core_listen(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_core_srv_conf_t</span> *cscf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, size;</span><br><span class="line"> <span class="keyword">ngx_url_t</span> u;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> n;</span><br><span class="line"> <span class="keyword">ngx_http_listen_opt_t</span> lsopt;</span><br><span class="line"></span><br><span class="line"> cscf->listen = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// URL结构体内存空间置零</span></span><br><span class="line"> ngx_memzero(&u, <span class="keyword">sizeof</span>(<span class="keyword">ngx_url_t</span>));</span><br><span class="line"></span><br><span class="line"> u.url = value[<span class="number">1</span>];</span><br><span class="line"> u.listen = <span class="number">1</span>;</span><br><span class="line"> u.default_port = <span class="number">80</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析listen指令后的ip+port</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_parse_url(cf->pool, &u) != NGX_OK) {</span><br><span class="line"> <span class="keyword">if</span> (u.err) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"%s in \"%V\" of the \"listen\" directive"</span>,</span><br><span class="line"> u.err, &u.url);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&lsopt, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_listen_opt_t</span>));</span><br><span class="line"></span><br><span class="line"> lsopt.backlog = NGX_LISTEN_BACKLOG;</span><br><span class="line"> lsopt.rcvbuf = <span class="number">-1</span>;</span><br><span class="line"> lsopt.sndbuf = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_SETFIB)</span></span><br><span class="line"> lsopt.setfib = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_TCP_FASTOPEN)</span></span><br><span class="line"> lsopt.fastopen = <span class="number">-1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> lsopt.ipv6only = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="comment">// 开始解析listen指令后的参数,第一个参数是listen,第二个参数是IP端口,所以n从2开始</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">2</span>; n < cf->args->nelts; n++) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析default server参数,并设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"default_server"</span>) == <span class="number">0</span></span><br><span class="line"> || ngx_strcmp(value[n].data, <span class="string">"default"</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> lsopt.default_server = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析bind参数,并设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"bind"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_SETFIB)</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"setfib="</span>, <span class="number">7</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.setfib = ngx_atoi(value[n].data + <span class="number">7</span>, value[n].len - <span class="number">7</span>);</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.setfib == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid setfib \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_TCP_FASTOPEN)</span></span><br><span class="line"> <span class="comment">// 解析fastopen参数,设置标志位和值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"fastopen="</span>, <span class="number">9</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.fastopen = ngx_atoi(value[n].data + <span class="number">9</span>, value[n].len - <span class="number">9</span>);</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.fastopen == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid fastopen \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析backlog参数,设置标志位和值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"backlog="</span>, <span class="number">8</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.backlog = ngx_atoi(value[n].data + <span class="number">8</span>, value[n].len - <span class="number">8</span>);</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.backlog == NGX_ERROR || lsopt.backlog == <span class="number">0</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid backlog \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// recv buf参数,设置标志位和值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"rcvbuf="</span>, <span class="number">7</span>) == <span class="number">0</span>) {</span><br><span class="line"> size.len = value[n].len - <span class="number">7</span>;</span><br><span class="line"> size.data = value[n].data + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"> lsopt.rcvbuf = ngx_parse_size(&size);</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.rcvbuf == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid rcvbuf \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// send buf参数,设置标志位和值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"sndbuf="</span>, <span class="number">7</span>) == <span class="number">0</span>) {</span><br><span class="line"> size.len = value[n].len - <span class="number">7</span>;</span><br><span class="line"> size.data = value[n].data + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line"> lsopt.sndbuf = ngx_parse_size(&size);</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.sndbuf == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid sndbuf \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析accept_filter参数,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"accept_filter="</span>, <span class="number">14</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)</span></span><br><span class="line"> lsopt.accept_filter = (<span class="keyword">char</span> *) &value[n].data[<span class="number">14</span>];</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"accept filters \"%V\" are not supported "</span></span><br><span class="line"> <span class="string">"on this platform, ignored"</span>,</span><br><span class="line"> &value[n]);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// deferred 参数</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"deferred"</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)</span></span><br><span class="line"> lsopt.deferred_accept = <span class="number">1</span>;</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the deferred accept is not supported "</span></span><br><span class="line"> <span class="string">"on this platform, ignored"</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析ipv6参数,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"ipv6only=o"</span>, <span class="number">10</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6 && defined IPV6_V6ONLY)</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(&value[n].data[<span class="number">10</span>], <span class="string">"n"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.ipv6only = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (ngx_strcmp(&value[n].data[<span class="number">10</span>], <span class="string">"ff"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.ipv6only = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid ipv6only flags \"%s\""</span>,</span><br><span class="line"> &value[n].data[<span class="number">9</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"ipv6only is not supported "</span></span><br><span class="line"> <span class="string">"on this platform"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// reuseport 参数,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"reuseport"</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_REUSEPORT)</span></span><br><span class="line"> lsopt.reuseport = <span class="number">1</span>;</span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"reuseport is not supported "</span></span><br><span class="line"> <span class="string">"on this platform, ignored"</span>);</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析ssl参数,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"ssl"</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HTTP_SSL)</span></span><br><span class="line"> lsopt.ssl = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the \"ssl\" parameter requires "</span></span><br><span class="line"> <span class="string">"ngx_http_ssl_module"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析http2参数,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"http2"</span>) == <span class="number">0</span>) {</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HTTP_V2)</span></span><br><span class="line"> lsopt.http2 = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the \"http2\" parameter requires "</span></span><br><span class="line"> <span class="string">"ngx_http_v2_module"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析spdy参数</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"spdy"</span>) == <span class="number">0</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"spdy\": "</span></span><br><span class="line"> <span class="string">"ngx_http_spdy_module was superseded "</span></span><br><span class="line"> <span class="string">"by ngx_http_v2_module"</span>);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析so_keepalive,设置标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[n].data, <span class="string">"so_keepalive="</span>, <span class="number">13</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(&value[n].data[<span class="number">13</span>], <span class="string">"on"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.so_keepalive = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (ngx_strcmp(&value[n].data[<span class="number">13</span>], <span class="string">"off"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.so_keepalive = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"></span><br><span class="line">#<span class="keyword">if</span> (NGX_HAVE_KEEPALIVE_TUNABLE)</span><br><span class="line"> u_char *p, *end;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> s;</span><br><span class="line"></span><br><span class="line"> end = value[n].data + value[n].len;</span><br><span class="line"> s.data = value[n].data + <span class="number">13</span>;</span><br><span class="line"></span><br><span class="line"> p = ngx_strlchr(s.data, end, <span class="string">':'</span>);</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>) {</span><br><span class="line"> p = end;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (p > s.data) {</span><br><span class="line"> s.len = p - s.data;</span><br><span class="line"></span><br><span class="line"> lsopt.tcp_keepidle = ngx_parse_time(&s, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (lsopt.tcp_keepidle == (<span class="keyword">time_t</span>) NGX_ERROR) {</span><br><span class="line"> <span class="keyword">goto</span> invalid_so_keepalive;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> s.data = (p < end) ? (p + <span class="number">1</span>) : end;</span><br><span class="line"></span><br><span class="line"> p = ngx_strlchr(s.data, end, <span class="string">':'</span>);</span><br><span class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>) {</span><br><span class="line"> p = end;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (p > s.data) {</span><br><span class="line"> s.len = p - s.data;</span><br><span class="line"></span><br><span class="line"> lsopt.tcp_keepintvl = ngx_parse_time(&s, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (lsopt.tcp_keepintvl == (<span class="keyword">time_t</span>) NGX_ERROR) {</span><br><span class="line"> <span class="keyword">goto</span> invalid_so_keepalive;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> s.data = (p < end) ? (p + <span class="number">1</span>) : end;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (s.data < end) {</span><br><span class="line"> s.len = end - s.data;</span><br><span class="line"></span><br><span class="line"> lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);</span><br><span class="line"> <span class="keyword">if</span> (lsopt.tcp_keepcnt == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">goto</span> invalid_so_keepalive;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (lsopt.tcp_keepidle == <span class="number">0</span> && lsopt.tcp_keepintvl == <span class="number">0</span></span><br><span class="line"> && lsopt.tcp_keepcnt == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">goto</span> invalid_so_keepalive;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lsopt.so_keepalive = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the \"so_keepalive\" parameter accepts "</span></span><br><span class="line"> <span class="string">"only \"on\" or \"off\" on this platform"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lsopt.<span class="built_in">set</span> = <span class="number">1</span>;</span><br><span class="line"> lsopt.bind = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_KEEPALIVE_TUNABLE)</span></span><br><span class="line"> invalid_so_keepalive:</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid so_keepalive value: \"%s\""</span>,</span><br><span class="line"> &value[n].data[<span class="number">13</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析pp协议参数,开启pp协议标志位</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[n].data, <span class="string">"proxy_protocol"</span>) == <span class="number">0</span>) {</span><br><span class="line"> lsopt.proxy_protocol = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"%V\""</span>, &value[n]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理监听端口</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < u.naddrs; n++) {</span><br><span class="line"> lsopt.sockaddr = u.addrs[n].sockaddr;</span><br><span class="line"> lsopt.socklen = u.addrs[n].socklen;</span><br><span class="line"> lsopt.addr_text = u.addrs[n].name;</span><br><span class="line"> <span class="comment">// 获取通配符关键字</span></span><br><span class="line"> lsopt.wildcard = ngx_inet_wildcard(lsopt.sockaddr);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将端口放入全局端口列表中</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="3"><li>接下来看看解析location指令的函数, ngx_http_core_location的实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br></pre></td><td class="code"><pre><span class="line">static char *</span><br><span class="line">ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)</span><br><span class="line">{</span><br><span class="line"> char *rv;</span><br><span class="line"> u_char *mod;</span><br><span class="line"> size_t len;</span><br><span class="line"> ngx_str_t *value, *name;</span><br><span class="line"> ngx_uint_t i;</span><br><span class="line"> ngx_conf_t save;</span><br><span class="line"> ngx_http_module_t *module;</span><br><span class="line"> ngx_http_conf_ctx_t *ctx, *pctx;</span><br><span class="line"> ngx_http_core_loc_conf_t *clcf, *pclcf;</span><br><span class="line"></span><br><span class="line"> // 首先申请保存配置的内存</span><br><span class="line"> ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));</span><br><span class="line"> if (ctx == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 设置main级别和server级别配置</span><br><span class="line"> pctx = cf->ctx;</span><br><span class="line"> ctx->main_conf = pctx->main_conf;</span><br><span class="line"> ctx->srv_conf = pctx->srv_conf;</span><br><span class="line"></span><br><span class="line"> ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);</span><br><span class="line"> if (ctx->loc_conf == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 遍历http模块,调用创建location级别配置函数</span><br><span class="line"> for (i = 0; cf->cycle->modules[i]; i++) {</span><br><span class="line"> // 跳过非http模块</span><br><span class="line"> if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> module = cf->cycle->modules[i]->ctx;</span><br><span class="line"></span><br><span class="line"> if (module->create_loc_conf) {</span><br><span class="line"> ctx->loc_conf[cf->cycle->modules[i]->ctx_index] =</span><br><span class="line"> module->create_loc_conf(cf);</span><br><span class="line"> if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 取出core模块的location级别配置</span><br><span class="line"> clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"> clcf->loc_conf = ctx->loc_conf;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> // 处理location指令后的参数,比如/ ~ = 以及其他正则表达式</span><br><span class="line"> if (cf->args->nelts == 3) {</span><br><span class="line"></span><br><span class="line"> len = value[1].len;</span><br><span class="line"> mod = value[1].data;</span><br><span class="line"> name = &value[2];</span><br><span class="line"></span><br><span class="line"> if (len == 1 && mod[0] == '=') {</span><br><span class="line"></span><br><span class="line"> clcf->name = *name;</span><br><span class="line"> clcf->exact_match = 1;</span><br><span class="line"></span><br><span class="line"> } else if (len == 2 && mod[0] == '^' && mod[1] == '~') {</span><br><span class="line"></span><br><span class="line"> clcf->name = *name;</span><br><span class="line"> clcf->noregex = 1;</span><br><span class="line"></span><br><span class="line"> } else if (len == 1 && mod[0] == '~') {</span><br><span class="line"></span><br><span class="line"> if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else if (len == 2 && mod[0] == '~' && mod[1] == '*') {</span><br><span class="line"></span><br><span class="line"> if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid location modifier \"%V\"", &value[1]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"></span><br><span class="line"> name = &value[1];</span><br><span class="line"></span><br><span class="line"> if (name->data[0] == '=') {</span><br><span class="line"></span><br><span class="line"> clcf->name.len = name->len - 1;</span><br><span class="line"> clcf->name.data = name->data + 1;</span><br><span class="line"> clcf->exact_match = 1;</span><br><span class="line"></span><br><span class="line"> } else if (name->data[0] == '^' && name->data[1] == '~') {</span><br><span class="line"></span><br><span class="line"> clcf->name.len = name->len - 2;</span><br><span class="line"> clcf->name.data = name->data + 2;</span><br><span class="line"> clcf->noregex = 1;</span><br><span class="line"></span><br><span class="line"> } else if (name->data[0] == '~') {</span><br><span class="line"></span><br><span class="line"> name->len--;</span><br><span class="line"> name->data++;</span><br><span class="line"></span><br><span class="line"> if (name->data[0] == '*') {</span><br><span class="line"></span><br><span class="line"> name->len--;</span><br><span class="line"> name->data++;</span><br><span class="line"></span><br><span class="line"> // 处理正则表达式</span><br><span class="line"> if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"></span><br><span class="line"> // 保存clcf的name</span><br><span class="line"> clcf->name = *name;</span><br><span class="line"></span><br><span class="line"> if (name->data[0] == '@') {</span><br><span class="line"> clcf->named = 1;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 设置location级别的配置</span><br><span class="line"> pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];</span><br><span class="line"></span><br><span class="line"> // 判断是否微location类型配置</span><br><span class="line"> if (cf->cmd_type == NGX_HTTP_LOC_CONF) {</span><br><span class="line"></span><br><span class="line"> /* nested location */</span><br><span class="line"></span><br><span class="line">#if 0</span><br><span class="line"> clcf->prev_location = pclcf;</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> if (pclcf->exact_match) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "location \"%V\" cannot be inside "</span><br><span class="line"> "the exact location \"%V\"",</span><br><span class="line"> &clcf->name, &pclcf->name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (pclcf->named) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "location \"%V\" cannot be inside "</span><br><span class="line"> "the named location \"%V\"",</span><br><span class="line"> &clcf->name, &pclcf->name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (clcf->named) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "named location \"%V\" can be "</span><br><span class="line"> "on the server level only",</span><br><span class="line"> &clcf->name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> len = pclcf->name.len;</span><br><span class="line"></span><br><span class="line">#if (NGX_PCRE)</span><br><span class="line"> if (clcf->regex == NULL</span><br><span class="line"> && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)</span><br><span class="line">#else</span><br><span class="line"> if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)</span><br><span class="line">#endif</span><br><span class="line"> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "location \"%V\" is outside location \"%V\"",</span><br><span class="line"> &clcf->name, &pclcf->name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 添加location</span><br><span class="line"> if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 保持cf结构体</span><br><span class="line"> save = *cf;</span><br><span class="line"> cf->ctx = ctx;</span><br><span class="line"> cf->cmd_type = NGX_HTTP_LOC_CONF;</span><br><span class="line"></span><br><span class="line"> // 解析location里面的指令</span><br><span class="line"> rv = ngx_conf_parse(cf, NULL);</span><br><span class="line"></span><br><span class="line"> // 恢复原来的配置</span><br><span class="line"> *cf = save;</span><br><span class="line"></span><br><span class="line"> return rv;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="3"><li>接下来看看root指令解析函数,ngx_http_core_root的实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static char *</span><br><span class="line">ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_core_loc_conf_t *clcf = conf;</span><br><span class="line"></span><br><span class="line"> ngx_str_t *value;</span><br><span class="line"> ngx_int_t alias;</span><br><span class="line"> ngx_uint_t n;</span><br><span class="line"> ngx_http_script_compile_t sc;</span><br><span class="line"></span><br><span class="line"> alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;</span><br><span class="line"></span><br><span class="line"> if (clcf->root.data) {</span><br><span class="line"></span><br><span class="line"> if ((clcf->alias != 0) == alias) {</span><br><span class="line"> return "is duplicate";</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "\"%V\" directive is duplicate, "</span><br><span class="line"> "\"%s\" directive was specified earlier",</span><br><span class="line"> &cmd->name, clcf->alias ? "alias" : "root");</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (clcf->named && alias) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "the \"alias\" directive cannot be used "</span><br><span class="line"> "inside the named location");</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> // 处理第一个参数</span><br><span class="line"> if (ngx_strstr(value[1].data, "$document_root")</span><br><span class="line"> || ngx_strstr(value[1].data, "${document_root}"))</span><br><span class="line"> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "the $document_root variable cannot be used "</span><br><span class="line"> "in the \"%V\" directive",</span><br><span class="line"> &cmd->name);</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strstr(value[1].data, "$realpath_root")</span><br><span class="line"> || ngx_strstr(value[1].data, "${realpath_root}"))</span><br><span class="line"> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "the $realpath_root variable cannot be used "</span><br><span class="line"> "in the \"%V\" directive",</span><br><span class="line"> &cmd->name);</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> clcf->alias = alias ? clcf->name.len : 0;</span><br><span class="line"> clcf->root = value[1];</span><br><span class="line"></span><br><span class="line"> if (!alias && clcf->root.len > 0</span><br><span class="line"> && clcf->root.data[clcf->root.len - 1] == '/')</span><br><span class="line"> {</span><br><span class="line"> clcf->root.len--;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (clcf->root.data[0] != '$') {</span><br><span class="line"> if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 统计变量数量</span><br><span class="line"> n = ngx_http_script_variables_count(&clcf->root);</span><br><span class="line"></span><br><span class="line"> // 结构体置空</span><br><span class="line"> ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));</span><br><span class="line"> sc.variables = n;</span><br><span class="line"></span><br><span class="line">#if (NGX_PCRE)</span><br><span class="line"> if (alias && clcf->regex) {</span><br><span class="line"> clcf->alias = NGX_MAX_SIZE_T_VALUE;</span><br><span class="line"> n = 1;</span><br><span class="line"> }</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> //处理变量</span><br><span class="line"> if (n) {</span><br><span class="line"> sc.cf = cf;</span><br><span class="line"> sc.source = &clcf->root;</span><br><span class="line"> sc.lengths = &clcf->root_lengths;</span><br><span class="line"> sc.values = &clcf->root_values;</span><br><span class="line"> sc.complete_lengths = 1;</span><br><span class="line"> sc.complete_values = 1;</span><br><span class="line"></span><br><span class="line"> if (ngx_http_script_compile(&sc) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="4"><li>接下来看看type指令解析函数, ngx_http_core_type的实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line">static char *</span><br><span class="line">ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_core_loc_conf_t *clcf = conf;</span><br><span class="line"></span><br><span class="line"> ngx_str_t *value, *content_type, *old;</span><br><span class="line"> ngx_uint_t i, n, hash;</span><br><span class="line"> ngx_hash_key_t *type;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> // 解析第一个参数,判断是否为include</span><br><span class="line"> if (ngx_strcmp(value[0].data, "include") == 0) {</span><br><span class="line"> if (cf->args->nelts != 2) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid number of arguments"</span><br><span class="line"> " in \"include\" directive");</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return ngx_conf_include(cf, dummy, conf);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //申请保存content_type的内存</span><br><span class="line"> content_type = ngx_palloc(cf->pool, sizeof(ngx_str_t));</span><br><span class="line"> if (content_type == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 取content_type的值</span><br><span class="line"> *content_type = value[0];</span><br><span class="line"></span><br><span class="line"> for (i = 1; i < cf->args->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);</span><br><span class="line"></span><br><span class="line"> type = clcf->types->elts;</span><br><span class="line"> for (n = 0; n < clcf->types->nelts; n++) {</span><br><span class="line"> if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {</span><br><span class="line"> old = type[n].value;</span><br><span class="line"> type[n].value = content_type;</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, 0,</span><br><span class="line"> "duplicate extension \"%V\", "</span><br><span class="line"> "content type: \"%V\", "</span><br><span class="line"> "previous content type: \"%V\"",</span><br><span class="line"> &value[i], content_type, old);</span><br><span class="line"> goto next;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 从types中取出一个元素</span><br><span class="line"> type = ngx_array_push(clcf->types);</span><br><span class="line"> if (type == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //保存</span><br><span class="line"> type->key = value[i];</span><br><span class="line"> type->key_hash = hash;</span><br><span class="line"> type->value = content_type;</span><br><span class="line"></span><br><span class="line"> next:</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="5"><li>接下来看看server_name指令的解析函数, ngx_http_core_server_name的实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line">static char *</span><br><span class="line">ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</span><br><span class="line">{</span><br><span class="line"> ngx_http_core_srv_conf_t *cscf = conf;</span><br><span class="line"></span><br><span class="line"> u_char ch;</span><br><span class="line"> ngx_str_t *value;</span><br><span class="line"> ngx_uint_t i;</span><br><span class="line"> ngx_http_server_name_t *sn;</span><br><span class="line"></span><br><span class="line"> // 取参数</span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> // 遍历参数个数</span><br><span class="line"> for (i = 1; i < cf->args->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> ch = value[i].data[0];</span><br><span class="line"></span><br><span class="line"> // 判断是否为通配符</span><br><span class="line"> if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))</span><br><span class="line"> || (ch == '.' && value[i].len < 2))</span><br><span class="line"> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "server name \"%V\" is invalid", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 判断server_name中是否含有/</span><br><span class="line"> if (ngx_strchr(value[i].data, '/')) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, 0,</span><br><span class="line"> "server name \"%V\" has suspicious symbols",</span><br><span class="line"> &value[i]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 取一个server_name的元素</span><br><span class="line"> sn = ngx_array_push(&cscf->server_names);</span><br><span class="line"> if (sn == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">#if (NGX_PCRE)</span><br><span class="line"> sn->regex = NULL;</span><br><span class="line">#endif</span><br><span class="line"> // 保存server块配置结构体</span><br><span class="line"> sn->server = cscf;</span><br><span class="line"></span><br><span class="line"> // 判断server_name参数是否为主机名称,如果是,则使用cycle->hostname,否则server_name的值就是value的值</span><br><span class="line"> if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {</span><br><span class="line"> sn->name = cf->cycle->hostname;</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> sn->name = value[i];</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 处理server_name转小写</span><br><span class="line"> if (value[i].data[0] != '~') {</span><br><span class="line"> ngx_strlow(sn->name.data, sn->name.data, sn->name.len);</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">#if (NGX_PCRE)</span><br><span class="line"> // 处理正则表达式</span><br><span class="line"> {</span><br><span class="line"> u_char *p;</span><br><span class="line"> ngx_regex_compile_t rc;</span><br><span class="line"> u_char errstr[NGX_MAX_CONF_ERRSTR];</span><br><span class="line"></span><br><span class="line"> if (value[i].len == 1) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "empty regex in server name \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 跳过第一个符号</span><br><span class="line"> value[i].len--;</span><br><span class="line"> value[i].data++;</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&rc, sizeof(ngx_regex_compile_t));</span><br><span class="line"></span><br><span class="line"> rc.pattern = value[i];</span><br><span class="line"> rc.err.len = NGX_MAX_CONF_ERRSTR;</span><br><span class="line"> rc.err.data = errstr;</span><br><span class="line"></span><br><span class="line"> for (p = value[i].data; p < value[i].data + value[i].len; p++) {</span><br><span class="line"> if (*p >= 'A' && *p <= 'Z') {</span><br><span class="line"> rc.options = NGX_REGEX_CASELESS;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 编译正则表达式</span><br><span class="line"> sn->regex = ngx_http_regex_compile(cf, &rc);</span><br><span class="line"> if (sn->regex == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> sn->name = value[i];</span><br><span class="line"> cscf->captures = (rc.captures > 0);</span><br><span class="line"> }</span><br><span class="line">#else</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "using regex \"%V\" "</span><br><span class="line"> "requires PCRE library", &value[i]);</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">#endif</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="6"><li>接下来看看error_page指令的解析函数, ngx_http_core_error_page的实现<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line">ngx_http_core_error_page(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_core_loc_conf_t</span> *clcf = conf;</span><br><span class="line"></span><br><span class="line"> u_char *p;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> overwrite;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, uri, args;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n;</span><br><span class="line"> <span class="keyword">ngx_http_err_page_t</span> *err;</span><br><span class="line"> <span class="keyword">ngx_http_complex_value_t</span> cv;</span><br><span class="line"> <span class="keyword">ngx_http_compile_complex_value_t</span> ccv;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (clcf->error_pages == <span class="literal">NULL</span>) {</span><br><span class="line"> clcf->error_pages = ngx_array_create(cf->pool, <span class="number">4</span>,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_err_page_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (clcf->error_pages == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> i = cf->args->nelts - <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析重定向的code</span></span><br><span class="line"> <span class="keyword">if</span> (value[i].data[<span class="number">0</span>] == <span class="string">'='</span>) {</span><br><span class="line"> <span class="keyword">if</span> (i == <span class="number">1</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid value \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value[i].len > <span class="number">1</span>) {</span><br><span class="line"> overwrite = ngx_atoi(&value[i].data[<span class="number">1</span>], value[i].len - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (overwrite == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid value \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> overwrite = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> n = <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> overwrite = <span class="number">-1</span>;</span><br><span class="line"> n = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> uri = value[cf->args->nelts - <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &uri;</span><br><span class="line"> ccv.complex_value = &cv;</span><br><span class="line"> <span class="comment">// 解析uri变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_str_null(&args);</span><br><span class="line"> <span class="comment">// 解析uri及参数</span></span><br><span class="line"> <span class="keyword">if</span> (cv.lengths == <span class="literal">NULL</span> && uri.len && uri.data[<span class="number">0</span>] == <span class="string">'/'</span>) {</span><br><span class="line"> <span class="comment">//搜索查询参数起点</span></span><br><span class="line"> p = (u_char *) ngx_strchr(uri.data, <span class="string">'?'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (p) {</span><br><span class="line"> cv.value.len = p - uri.data;</span><br><span class="line"> cv.value.data = uri.data;</span><br><span class="line"> p++;</span><br><span class="line"> args.len = (uri.data + uri.len) - p;</span><br><span class="line"> args.data = p;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 开始从第一个参数解析需要重定向的code</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">1</span>; i < cf->args->nelts - n; i++) {</span><br><span class="line"> err = ngx_array_push(clcf->error_pages);</span><br><span class="line"> <span class="keyword">if</span> (err == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 解析数字code</span></span><br><span class="line"> err->status = ngx_atoi(value[i].data, value[i].len);</span><br><span class="line"> <span class="comment">// 如果解析出错或者是499,则直接返回错误</span></span><br><span class="line"> <span class="keyword">if</span> (err->status == NGX_ERROR || err->status == <span class="number">499</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid value \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// status范围300-599之间</span></span><br><span class="line"> <span class="keyword">if</span> (err->status < <span class="number">300</span> || err->status > <span class="number">599</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"value \"%V\" must be between 300 and 599"</span>,</span><br><span class="line"> &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> err->overwrite = overwrite;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (overwrite == <span class="number">-1</span>) {</span><br><span class="line"> <span class="keyword">switch</span> (err->status) {</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_TO_HTTPS:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_CERT_ERROR:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_NO_CERT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_REQUEST_HEADER_TOO_LARGE:</span><br><span class="line"> err->overwrite = NGX_HTTP_BAD_REQUEST;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> err->value = cv;</span><br><span class="line"> err->args = args;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>error_page主要用于内部重定向,在special response的时候处理相关逻辑<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_special_response_handler(<span class="keyword">ngx_http_request_t</span> *r, <span class="keyword">ngx_int_t</span> error)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, err;</span><br><span class="line"> <span class="keyword">ngx_http_err_page_t</span> *err_page;</span><br><span class="line"> <span class="keyword">ngx_http_core_loc_conf_t</span> *clcf;</span><br><span class="line"></span><br><span class="line"> ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"http special response: %i, \"%V?%V\""</span>,</span><br><span class="line"> error, &r->uri, &r->args);</span><br><span class="line"></span><br><span class="line"> r->err_status = error;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (r->keepalive) {</span><br><span class="line"> <span class="keyword">switch</span> (error) {</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_BAD_REQUEST:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_REQUEST_URI_TOO_LARGE:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_TO_HTTPS:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_CERT_ERROR:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_NO_CERT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_INTERNAL_SERVER_ERROR:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_NOT_IMPLEMENTED:</span><br><span class="line"> r->keepalive = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (r->lingering_close) {</span><br><span class="line"> <span class="keyword">switch</span> (error) {</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_BAD_REQUEST:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_TO_HTTPS:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_CERT_ERROR:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_NO_CERT:</span><br><span class="line"> r->lingering_close = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// content-length置为0</span></span><br><span class="line"> r->headers_out.content_type.len = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);</span><br><span class="line"> <span class="comment">// 这里对error_page以及uri_changes判断</span></span><br><span class="line"> <span class="keyword">if</span> (!r->error_page && clcf->error_pages && r->uri_changes != <span class="number">0</span>) {</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> (clcf->recursive_error_pages == <span class="number">0</span>) {</span><br><span class="line"> r->error_page = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> err_page = clcf->error_pages->elts;</span><br><span class="line"> <span class="comment">// 找到对应code</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < clcf->error_pages->nelts; i++) {</span><br><span class="line"> <span class="keyword">if</span> (err_page[i].status == error) {</span><br><span class="line"> <span class="comment">// 直接调用error_page逻辑</span></span><br><span class="line"> <span class="keyword">return</span> ngx_http_send_error_page(r, &err_page[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> r->expect_tested = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_discard_request_body(r) != NGX_OK) {</span><br><span class="line"> r->keepalive = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (clcf->msie_refresh</span><br><span class="line"> && r->headers_in.msie</span><br><span class="line"> && (error == NGX_HTTP_MOVED_PERMANENTLY</span><br><span class="line"> || error == NGX_HTTP_MOVED_TEMPORARILY))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_send_refresh(r);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (error == NGX_HTTP_CREATED) {</span><br><span class="line"> <span class="comment">/* 201 */</span></span><br><span class="line"> err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (error == NGX_HTTP_NO_CONTENT) {</span><br><span class="line"> <span class="comment">/* 204 */</span></span><br><span class="line"> err = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (error >= NGX_HTTP_MOVED_PERMANENTLY</span><br><span class="line"> && error < NGX_HTTP_LAST_3XX)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* 3XX */</span></span><br><span class="line"> err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (error >= NGX_HTTP_BAD_REQUEST</span><br><span class="line"> && error < NGX_HTTP_LAST_4XX)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* 4XX */</span></span><br><span class="line"> err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (error >= NGX_HTTP_NGINX_CODES</span><br><span class="line"> && error < NGX_HTTP_LAST_5XX)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">/* 49X, 5XX */</span></span><br><span class="line"> err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;</span><br><span class="line"> <span class="keyword">switch</span> (error) {</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_TO_HTTPS:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_CERT_ERROR:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTPS_NO_CERT:</span><br><span class="line"> <span class="keyword">case</span> NGX_HTTP_REQUEST_HEADER_TOO_LARGE:</span><br><span class="line"> r->err_status = NGX_HTTP_BAD_REQUEST;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">/* unknown code, zero body */</span></span><br><span class="line"> err = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ngx_http_send_special_response(r, clcf, err);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><p>接下来看下ngx_http_send_error_page的函数实现<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_send_error_page(<span class="keyword">ngx_http_request_t</span> *r, <span class="keyword">ngx_http_err_page_t</span> *err_page)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_int_t</span> overwrite;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> uri, args;</span><br><span class="line"> <span class="keyword">ngx_table_elt_t</span> *location;</span><br><span class="line"> <span class="keyword">ngx_http_core_loc_conf_t</span> *clcf;</span><br><span class="line"></span><br><span class="line"> overwrite = err_page->overwrite;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (overwrite && overwrite != NGX_HTTP_OK) {</span><br><span class="line"> r->expect_tested = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果配置了code,则将error_code置为配置的code</span></span><br><span class="line"> <span class="keyword">if</span> (overwrite >= <span class="number">0</span>) {</span><br><span class="line"> r->err_status = overwrite;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 处理url中的变量</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果url是/开始</span></span><br><span class="line"> <span class="keyword">if</span> (uri.len && uri.data[<span class="number">0</span>] == <span class="string">'/'</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (err_page->value.lengths) {</span><br><span class="line"> ngx_http_split_args(r, &uri, &args);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> args = err_page->args;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (r->method != NGX_HTTP_HEAD) {</span><br><span class="line"> r->method = NGX_HTTP_GET;</span><br><span class="line"> r->method_name = ngx_http_core_get_method;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ngx_http_internal_redirect(r, &uri, &args);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 跳转到name的location</span></span><br><span class="line"> <span class="keyword">if</span> (uri.len && uri.data[<span class="number">0</span>] == <span class="string">'@'</span>) {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_named_location(r, &uri);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> r->expect_tested = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_discard_request_body(r) != NGX_OK) {</span><br><span class="line"> r->keepalive = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从headers中取一个元素,用作重定向</span></span><br><span class="line"> location = ngx_list_push(&r->headers_out.headers);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (location == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (overwrite != NGX_HTTP_MOVED_PERMANENTLY</span><br><span class="line"> && overwrite != NGX_HTTP_MOVED_TEMPORARILY</span><br><span class="line"> && overwrite != NGX_HTTP_SEE_OTHER</span><br><span class="line"> && overwrite != NGX_HTTP_TEMPORARY_REDIRECT</span><br><span class="line"> && overwrite != NGX_HTTP_PERMANENT_REDIRECT)</span><br><span class="line"> {</span><br><span class="line"> r->err_status = NGX_HTTP_MOVED_TEMPORARILY;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> location->hash = <span class="number">1</span>;</span><br><span class="line"> ngx_str_set(&location->key, <span class="string">"Location"</span>);</span><br><span class="line"> location->value = uri;</span><br><span class="line"></span><br><span class="line"> ngx_http_clear_location(r);</span><br><span class="line"></span><br><span class="line"> r->headers_out.location = location;</span><br><span class="line"></span><br><span class="line"> clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (clcf->msie_refresh && r->headers_in.msie) {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_send_refresh(r);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> ngx_http_send_special_response(r, clcf, r->err_status</span><br><span class="line"> - NGX_HTTP_MOVED_PERMANENTLY</span><br><span class="line"> + NGX_HTTP_OFF_3XX);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p></p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>vxlan学习笔记</title>
<link href="https://weeweetan.github.io/2021/04/10/vxlan%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<id>https://weeweetan.github.io/2021/04/10/vxlan学习笔记/</id>
<published>2021-04-10T14:05:41.000Z</published>
<updated>2021-04-29T14:02:30.501Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-报文格式"><a href="#1-报文格式" class="headerlink" title="1. 报文格式"></a>1. 报文格式</h2><blockquote><p>具体参照RFC7348<br>0 1 2 3<br>0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1</p></blockquote><p>Outer Ethernet Header:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Outer Destination MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Outer Destination MAC Address | Outer Source MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Outer Source MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>|OptnlEthtype = C-Tag 802.1Q | Outer.VLAN Tag Information |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Ethertype = 0x0800 |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>Outer IPv4 Header:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>|Version| IHL |Type of Service| Total Length |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Identification |Flags| Fragment Offset |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Time to Live |Protocl=17(UDP)| Header Checksum |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Outer Source IPv4 Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Outer Destination IPv4 Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p><p>Outer UDP Header:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Source Port | Dest Port = VXLAN Port |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| UDP Length | UDP Checksum |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p><p>VXLAN Header:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>|R|R|R|R|I|R|R|R| Reserved |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| VXLAN Network Identifier (VNI) | Reserved |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p><p>Inner Ethernet Header:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Inner Destination MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Inner Destination MAC Address | Inner Source MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Inner Source MAC Address |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>|OptnlEthtype = C-Tag 802.1Q | Inner.VLAN Tag Information |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p><p>Payload:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| Ethertype of Original Payload | |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |<br>| Original Ethernet Payload |<br>| |<br>|(Note that the original Ethernet Frame’s FCS is not included) |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>Frame Check Sequence:<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+<br>| New FCS (Frame Check Sequence) for Outer Ethernet Frame |<br>+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</p><h2 id="2-字段说明"><a href="#2-字段说明" class="headerlink" title="2. 字段说明"></a>2. 字段说明</h2><blockquote><p>Outer MAC Header:封装外层以太头,14字节,如果有VLAN TAG则为18字节。其中,源MAC地址(Outer Source MAC Address)为源VM所属VTEP的MAC地址,目的MAC地址(Outer Destination MAC Address)为到达目的VTEP的路径上下一跳设备的MAC地址。类型字段为0x0800,指示内层封装的是IP报文。<br>Outer IP Header:封装外层IP头,20字节。其中,源IP地址(Outer Source IP Address)为源VM所属VTEP的IP地址,目的IP地址(Outer Destination IP Address)为目的VM所属VTEP的IP地址。协议字段为0x11,指示内层封装的是UDP报文。<br>UDP Header:UDP报文头,8字节。其中,UDP目的端口号(UDP Destination Port)固定为4789,指示内层封装报文为VXLAN报文。UDP源端口号(UDP Source Port)为随机任意值,可以用于VTEP之间多路径负载分担的计算。<br>VXLAN Header:VXLAN协议新定义的VXLAN头,8字节。<br>Flags:8 bit,RRRRIRRR。”I”位为1时,表示VXLAN头中的VXLAN ID有效;为0,表示VXLAN ID无效。”R”位保留未用,设置为0。<br>VXLAN ID(VNI):24 bit,用于标识一个单独的VXLAN网络。<br>Reserved:分别为24 bit和8 bit。保留位。<br>Original L2 Frame:原始以太网报文。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-报文格式"><a href="#1-报文格式" class="headerlink" title="1. 报文格式"></a>1.
</summary>
<category term="vxlan" scheme="https://weeweetan.github.io/tags/vxlan/"/>
</entry>
<entry>
<title>FFmpeg学习笔记</title>
<link href="https://weeweetan.github.io/2020/11/14/FFmpeg%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<id>https://weeweetan.github.io/2020/11/14/FFmpeg学习笔记/</id>
<published>2020-11-14T09:37:03.000Z</published>
<updated>2021-04-09T14:27:28.830Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1、组件"><a href="#1、组件" class="headerlink" title="1、组件"></a>1、组件</h2><h3 id="1-1、avcodec:编解码(最重要的库)"><a href="#1-1、avcodec:编解码(最重要的库)" class="headerlink" title="1.1、avcodec:编解码(最重要的库)"></a>1.1、avcodec:编解码(最重要的库)</h3><h3 id="1-2、avdevice:各种设备的输入输出"><a href="#1-2、avdevice:各种设备的输入输出" class="headerlink" title="1.2、avdevice:各种设备的输入输出"></a>1.2、avdevice:各种设备的输入输出</h3><h3 id="1-3、avfilter:滤镜特效处理"><a href="#1-3、avfilter:滤镜特效处理" class="headerlink" title="1.3、avfilter:滤镜特效处理"></a>1.3、avfilter:滤镜特效处理</h3><h3 id="1-4、avformat:封装格式处理"><a href="#1-4、avformat:封装格式处理" class="headerlink" title="1.4、avformat:封装格式处理"></a>1.4、avformat:封装格式处理</h3><h3 id="1-5、avutil:工具库(大部分库都需要这个库的支持)"><a href="#1-5、avutil:工具库(大部分库都需要这个库的支持)" class="headerlink" title="1.5、avutil:工具库(大部分库都需要这个库的支持)"></a>1.5、avutil:工具库(大部分库都需要这个库的支持)</h3><h3 id="1-6、postproc:后加工"><a href="#1-6、postproc:后加工" class="headerlink" title="1.6、postproc:后加工"></a>1.6、postproc:后加工</h3><h3 id="1-7、swresample:音频采样数据格式转换"><a href="#1-7、swresample:音频采样数据格式转换" class="headerlink" title="1.7、swresample:音频采样数据格式转换"></a>1.7、swresample:音频采样数据格式转换</h3><h3 id="1-8、swscale:视频像素数据格式转换"><a href="#1-8、swscale:视频像素数据格式转换" class="headerlink" title="1.8、swscale:视频像素数据格式转换"></a>1.8、swscale:视频像素数据格式转换</h3><h2 id="2、命令行工具"><a href="#2、命令行工具" class="headerlink" title="2、命令行工具"></a>2、命令行工具</h2><h3 id="2-1、ffmpeg"><a href="#2-1、ffmpeg" class="headerlink" title="2.1、ffmpeg"></a>2.1、ffmpeg</h3><blockquote><p>fmpeg是用于转码的应用程序,常用命令可用ffmpeg -h显示</p></blockquote><h3 id="2-2、ffplay"><a href="#2-2、ffplay" class="headerlink" title="2.2、ffplay"></a>2.2、ffplay</h3><blockquote><p>ffplay用 SDL和FFmpeg库开发的一个简单的媒体播放器,支持格式众多,可支持udp、rtp、hls、rtsp等</p></blockquote><h3 id="2-3、ffprobe"><a href="#2-3、ffprobe" class="headerlink" title="2.3、ffprobe"></a>2.3、ffprobe</h3><blockquote><p>查看多媒体文件信息的模块,此模块可以用来查看多媒体文件格式以及编码。</p></blockquote><h3 id="2-4、ffserver"><a href="#2-4、ffserver" class="headerlink" title="2.4、ffserver"></a>2.4、ffserver</h3><blockquote><p>基于HTTP、RTSP用于实时广播的多媒体服务器.也支持时间平移</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1、组件"><a href="#1、组件" class="headerlink" title="1、组件"></a>1、组件</h2>
</summary>
<category term="FFmpeg" scheme="https://weeweetan.github.io/categories/FFmpeg/"/>
<category term="FFmpeg" scheme="https://weeweetan.github.io/tags/FFmpeg/"/>
</entry>
<entry>
<title>Nginx的共享内存详解</title>
<link href="https://weeweetan.github.io/2020/05/25/Nginx%E7%9A%84%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2020/05/25/Nginx的共享内存详解/</id>
<published>2020-05-25T12:05:11.000Z</published>
<updated>2020-08-11T11:41:49.819Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-简述"><a href="#1-简述" class="headerlink" title="1. 简述"></a>1. 简述</h2><h3 id="1-1-应用介绍"><a href="#1-1-应用介绍" class="headerlink" title="1.1 应用介绍"></a>1.1 应用介绍</h3><blockquote><p>nginx使用共享内存的模块有ngx_http_file_cache_module、ngx_http_limit_conn_module、ngx_http_limit_req_module等模块。无一例外,这几个模块都是使用nginx实现的红黑树,基于共享内存来保存他们所需要的数据。</p></blockquote><h2 id="2-源码详解"><a href="#2-源码详解" class="headerlink" title="2 源码详解"></a>2 源码详解</h2><h3 id="2-1-首先来看看相关结构体定义"><a href="#2-1-首先来看看相关结构体定义" class="headerlink" title="2.1 首先来看看相关结构体定义"></a>2.1 首先来看看相关结构体定义</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">ngx_slab_page_s</span> <span class="title">ngx_slab_page_t</span>;</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ngx_slab_page_s</span> {</span></span><br><span class="line"> <span class="keyword">uintptr_t</span> slab;</span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *next; <span class="comment">//下一个page页</span></span><br><span class="line"> <span class="keyword">uintptr_t</span> prev; <span class="comment">//上一个page页</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// slab状态结构体</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line"> <span class="keyword">ngx_uint_t</span> total;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> used;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_uint_t</span> reqs;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> fails;</span><br><span class="line">} <span class="keyword">ngx_slab_stat_t</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> {</span></span><br><span class="line"> <span class="keyword">ngx_shmtx_sh_t</span> lock; <span class="comment">//mutex锁</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">size_t</span> min_size; <span class="comment">//设定的最小内存块长度;</span></span><br><span class="line"> <span class="keyword">size_t</span> min_shift; <span class="comment">//ngx_init_zone_pool中默认为3</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *pages; <span class="comment">//每一页对应一个ngx_slab_page_t页描述结构体,所有的ngx_slab_page_t存放在连续的内存中构成数组,而pages就是数组首地址</span></span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *last; <span class="comment">//最后页面地址</span></span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> <span class="built_in">free</span>; <span class="comment">//所有的空闲页组成一个链表挂在free成员上</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_slab_stat_t</span> *stats; </span><br><span class="line"> <span class="keyword">ngx_uint_t</span> pfree; <span class="comment">// 剩余页数</span></span><br><span class="line"></span><br><span class="line"> u_char *start; <span class="comment">//第一页的首地址</span></span><br><span class="line"> u_char *end; <span class="comment">//指向这段共享内存的尾部</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_shmtx_t</span> mutex; <span class="comment">//Nginx封装的互斥锁</span></span><br><span class="line"></span><br><span class="line"> u_char *log_ctx; <span class="comment">// slab操作失败时会记录日志,为区别是哪个slab共享内存出错,可以在slab中分配一段内存存放描述的字符串,然后再用</span></span><br><span class="line">log_ctx指向这个字符串</span><br><span class="line"> u_char zero; <span class="comment">// 表示空字符串防止出错</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">unsigned</span> log_nomem:<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">void</span> *data; <span class="comment">//slab的模块自由使用,slab管理内存时不会用到它</span></span><br><span class="line"> <span class="keyword">void</span> *addr; <span class="comment">//指向所属的ngx_shm_zone_t里的ngx_shm_t成员的addr成员,一般用于指示一段共享内存块的起始位置</span></span><br><span class="line">} <span class="keyword">ngx_slab_pool_t</span>;</span><br></pre></td></tr></table></figure><h3 id="2-2-相关函数及其介绍"><a href="#2-2-相关函数及其介绍" class="headerlink" title="2.2 相关函数及其介绍"></a>2.2 相关函数及其介绍</h3><blockquote><p>主要涉及到共享内存的初始化,加锁申请,不加锁申请,加锁释放,不加锁释放等函数。首先来看下初始化的两个函数ngx_slab_sizes_init、ngx_slab_init,ngx_slab_sizes_init函数使用操作系统内存页初始化slab_max_size。</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">void</span></span><br><span class="line">ngx_slab_sizes_init(<span class="keyword">void</span>)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> n;</span><br><span class="line"></span><br><span class="line"> ngx_slab_max_size = ngx_pagesize / <span class="number">2</span>;</span><br><span class="line"> ngx_slab_exact_size = ngx_pagesize / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>));</span><br><span class="line"> <span class="keyword">for</span> (n = ngx_slab_exact_size; n >>= <span class="number">1</span>; ngx_slab_exact_shift++) {</span><br><span class="line"> <span class="comment">/* void */</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span></span><br><span class="line">ngx_slab_init(<span class="keyword">ngx_slab_pool_t</span> *pool)</span><br><span class="line">{</span><br><span class="line"> u_char *p;</span><br><span class="line"> <span class="keyword">size_t</span> size;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> m;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n, pages;</span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *slots, *page;</span><br><span class="line"> <span class="comment">//最小分配的空间是8byte </span></span><br><span class="line"> pool->min_size = (<span class="keyword">size_t</span>) <span class="number">1</span> << pool->min_shift;</span><br><span class="line"></span><br><span class="line"> slots = ngx_slab_slots(pool);</span><br><span class="line"></span><br><span class="line"> p = (u_char *) slots;</span><br><span class="line"> size = pool->end - p;</span><br><span class="line"></span><br><span class="line"> ngx_slab_junk(p, size);</span><br><span class="line"></span><br><span class="line"> n = ngx_pagesize_shift - pool->min_shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="comment">/* only "next" is used in list head */</span></span><br><span class="line"> slots[i].slab = <span class="number">0</span>;</span><br><span class="line"> slots[i].next = &slots[i];</span><br><span class="line"> slots[i].prev = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//跳过上面那些slab page</span></span><br><span class="line"> p += n * <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_page_t</span>);</span><br><span class="line"></span><br><span class="line"> pool->stats = (<span class="keyword">ngx_slab_stat_t</span> *) p;</span><br><span class="line"> ngx_memzero(pool->stats, n * <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_stat_t</span>));</span><br><span class="line"></span><br><span class="line"> p += n * <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_stat_t</span>);</span><br><span class="line"></span><br><span class="line"> size -= n * (<span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_page_t</span>) + <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_stat_t</span>));</span><br><span class="line"></span><br><span class="line"> pages = (<span class="keyword">ngx_uint_t</span>) (size / (ngx_pagesize + <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_page_t</span>)));</span><br><span class="line"></span><br><span class="line"> pool->pages = (<span class="keyword">ngx_slab_page_t</span> *) p;</span><br><span class="line"> ngx_memzero(pool->pages, pages * <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_page_t</span>));</span><br><span class="line"></span><br><span class="line"> page = pool->pages;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* only "next" is used in list head */</span></span><br><span class="line"> <span class="comment">//初始化free,free.next是下次分配页时候的入口 </span></span><br><span class="line"> pool-><span class="built_in">free</span>.slab = <span class="number">0</span>;</span><br><span class="line"> pool-><span class="built_in">free</span>.next = page;</span><br><span class="line"> pool-><span class="built_in">free</span>.prev = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">//更新第一个slab page的状态,这儿slab成员记录了整个缓存区的页数目 </span></span><br><span class="line"> page->slab = pages;</span><br><span class="line"> page->next = &pool-><span class="built_in">free</span>;</span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &pool-><span class="built_in">free</span>;</span><br><span class="line"> <span class="comment">//实际缓存区(页)的开头,对齐 </span></span><br><span class="line"> <span class="comment">//因为对齐的原因,使得m_page数组和数据区域之间可能有些内存无法使用</span></span><br><span class="line"> pool->start = ngx_align_ptr(p + pages * <span class="keyword">sizeof</span>(<span class="keyword">ngx_slab_page_t</span>),</span><br><span class="line"> ngx_pagesize);</span><br><span class="line"></span><br><span class="line"> m = pages - (pool->end - pool->start) / ngx_pagesize;</span><br><span class="line"> <span class="keyword">if</span> (m > <span class="number">0</span>) {</span><br><span class="line"> pages -= m;</span><br><span class="line"> page->slab = pages;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//跳过pages * sizeof(ngx_slab_page_t)</span></span><br><span class="line"> pool->last = pool->pages + pages;</span><br><span class="line"> pool->pfree = pages;</span><br><span class="line"></span><br><span class="line"> pool->log_nomem = <span class="number">1</span>;</span><br><span class="line"> pool->log_ctx = &pool->zero;</span><br><span class="line"> pool->zero = <span class="string">'\0'</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>接下来看看申请内存的相关函数ngx_slab_alloc、ngx_slab_alloc_locked、ngx_slab_calloc、ngx_slab_calloc_locked<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">void</span> *</span><br><span class="line">ngx_slab_alloc(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">size_t</span> size)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">void</span> *p;</span><br><span class="line"> <span class="comment">//由于是共享内存,所以在进程间需要用锁来保持同步</span></span><br><span class="line"> ngx_shmtx_lock(&pool->mutex);</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_alloc_locked(pool, size);</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&pool->mutex);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> p;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> *</span><br><span class="line">ngx_slab_alloc_locked(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">size_t</span> size)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> s;</span><br><span class="line"> <span class="keyword">uintptr_t</span> p, m, mask, *bitmap;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n, slot, shift, <span class="built_in">map</span>;</span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *page, *prev, *slots;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (size > ngx_slab_max_size) {</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"slab alloc: %uz"</span>, size);</span><br><span class="line"></span><br><span class="line"> page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)</span><br><span class="line"> + ((size % ngx_pagesize) ? <span class="number">1</span> : <span class="number">0</span>));</span><br><span class="line"> <span class="keyword">if</span> (page) {</span><br><span class="line"> p = ngx_slab_page_addr(pool, page);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> p = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (size > pool->min_size) {</span><br><span class="line"> shift = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">for</span> (s = size - <span class="number">1</span>; s >>= <span class="number">1</span>; shift++) { <span class="comment">/* void */</span> }</span><br><span class="line"> slot = shift - pool->min_shift;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> shift = pool->min_shift;</span><br><span class="line"> slot = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].reqs++;</span><br><span class="line"></span><br><span class="line"> ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"slab alloc: %uz slot: %ui"</span>, size, slot);</span><br><span class="line"></span><br><span class="line"> slots = ngx_slab_slots(pool);</span><br><span class="line"> page = slots[slot].next;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->next != page) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (shift < ngx_slab_exact_shift) {</span><br><span class="line"></span><br><span class="line"> bitmap = (<span class="keyword">uintptr_t</span> *) ngx_slab_page_addr(pool, page);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span> = (ngx_pagesize >> shift) / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < <span class="built_in">map</span>; n++) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (bitmap[n] != NGX_SLAB_BUSY) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">1</span>, i = <span class="number">0</span>; m; m <<= <span class="number">1</span>, i++) {</span><br><span class="line"> <span class="keyword">if</span> (bitmap[n] & m) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> bitmap[n] |= m;</span><br><span class="line"></span><br><span class="line"> i = (n * <span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>) + i) << shift;</span><br><span class="line"></span><br><span class="line"> p = (<span class="keyword">uintptr_t</span>) bitmap + i;</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (bitmap[n] == NGX_SLAB_BUSY) {</span><br><span class="line"> <span class="keyword">for</span> (n = n + <span class="number">1</span>; n < <span class="built_in">map</span>; n++) {</span><br><span class="line"> <span class="keyword">if</span> (bitmap[n] != NGX_SLAB_BUSY) {</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> prev = ngx_slab_page_prev(page);</span><br><span class="line"> prev->next = page->next;</span><br><span class="line"> page->next->prev = page->prev;</span><br><span class="line"></span><br><span class="line"> page->next = <span class="literal">NULL</span>;</span><br><span class="line"> page->prev = NGX_SLAB_SMALL;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (shift == ngx_slab_exact_shift) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (m = <span class="number">1</span>, i = <span class="number">0</span>; m; m <<= <span class="number">1</span>, i++) {</span><br><span class="line"> <span class="keyword">if</span> (page->slab & m) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> page->slab |= m;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->slab == NGX_SLAB_BUSY) {</span><br><span class="line"> prev = ngx_slab_page_prev(page);</span><br><span class="line"> prev->next = page->next;</span><br><span class="line"> page->next->prev = page->prev;</span><br><span class="line"></span><br><span class="line"> page->next = <span class="literal">NULL</span>;</span><br><span class="line"> page->prev = NGX_SLAB_EXACT;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_page_addr(pool, page) + (i << shift);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> { <span class="comment">/* shift > ngx_slab_exact_shift */</span></span><br><span class="line"></span><br><span class="line"> mask = ((<span class="keyword">uintptr_t</span>) <span class="number">1</span> << (ngx_pagesize >> shift)) - <span class="number">1</span>;</span><br><span class="line"> mask <<= NGX_SLAB_MAP_SHIFT;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (m = (<span class="keyword">uintptr_t</span>) <span class="number">1</span> << NGX_SLAB_MAP_SHIFT, i = <span class="number">0</span>;</span><br><span class="line"> m & mask;</span><br><span class="line"> m <<= <span class="number">1</span>, i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (page->slab & m) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> page->slab |= m;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((page->slab & NGX_SLAB_MAP_MASK) == mask) {</span><br><span class="line"> prev = ngx_slab_page_prev(page);</span><br><span class="line"> prev->next = page->next;</span><br><span class="line"> page->next->prev = page->prev;</span><br><span class="line"></span><br><span class="line"> page->next = <span class="literal">NULL</span>;</span><br><span class="line"> page->prev = NGX_SLAB_BIG;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_page_addr(pool, page) + (i << shift);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT, <span class="string">"ngx_slab_alloc(): page is busy"</span>);</span><br><span class="line"> ngx_debug_point();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//分出一页加入到m_slot数组对应元素中 </span></span><br><span class="line"> page = ngx_slab_alloc_pages(pool, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page) {</span><br><span class="line"> <span class="keyword">if</span> (shift < ngx_slab_exact_shift) {</span><br><span class="line"> bitmap = (<span class="keyword">uintptr_t</span> *) ngx_slab_page_addr(pool, page);</span><br><span class="line"></span><br><span class="line"> n = (ngx_pagesize >> shift) / ((<span class="number">1</span> << shift) * <span class="number">8</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n == <span class="number">0</span>) {</span><br><span class="line"> n = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* "n" elements for bitmap, plus one requested */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < (n + <span class="number">1</span>) / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>)); i++) {</span><br><span class="line"> bitmap[i] = NGX_SLAB_BUSY;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> m = ((<span class="keyword">uintptr_t</span>) <span class="number">1</span> << ((n + <span class="number">1</span>) % (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>)))) - <span class="number">1</span>;</span><br><span class="line"> bitmap[i] = m;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span> = (ngx_pagesize >> shift) / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = i + <span class="number">1</span>; i < <span class="built_in">map</span>; i++) {</span><br><span class="line"> bitmap[i] = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> page->slab = shift;</span><br><span class="line"> page->next = &slots[slot];</span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_SMALL;</span><br><span class="line"></span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total += (ngx_pagesize >> shift) - n;</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_page_addr(pool, page) + (n << shift);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (shift == ngx_slab_exact_shift) {</span><br><span class="line"></span><br><span class="line"> page->slab = <span class="number">1</span>;</span><br><span class="line"> page->next = &slots[slot];</span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_EXACT;</span><br><span class="line"></span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total += <span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>);</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_page_addr(pool, page);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> { <span class="comment">/* shift > ngx_slab_exact_shift */</span></span><br><span class="line"></span><br><span class="line"> page->slab = ((<span class="keyword">uintptr_t</span>) <span class="number">1</span> << NGX_SLAB_MAP_SHIFT) | shift;</span><br><span class="line"> page->next = &slots[slot];</span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_BIG;</span><br><span class="line"></span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total += ngx_pagesize >> shift;</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_page_addr(pool, page);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> p = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].fails++;</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"slab alloc: %p"</span>, (<span class="keyword">void</span> *) p);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (<span class="keyword">void</span> *) p;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 由于是共享内存,所以在进程间需要用锁来保持同步 */</span></span><br><span class="line"><span class="keyword">void</span> *</span><br><span class="line">ngx_slab_calloc(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">size_t</span> size)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">void</span> *p;</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_lock(&pool->mutex);</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_calloc_locked(pool, size);</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&pool->mutex);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> p;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> *</span><br><span class="line">ngx_slab_calloc_locked(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">size_t</span> size)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">void</span> *p;</span><br><span class="line"></span><br><span class="line"> p = ngx_slab_alloc_locked(pool, size);</span><br><span class="line"> <span class="keyword">if</span> (p) {</span><br><span class="line"> ngx_memzero(p, size);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> p;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_slab_page_t</span> *</span><br><span class="line">ngx_slab_alloc_pages(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">ngx_uint_t</span> pages)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *page, *p;</span><br><span class="line"> <span class="comment">//初始化的时候pool->free.next默认指向第一个pool->pages</span></span><br><span class="line"> <span class="comment">//从pool->free.next开始,每次取(slab page) page = page->next</span></span><br><span class="line"> <span class="keyword">for</span> (page = pool-><span class="built_in">free</span>.next; page != &pool-><span class="built_in">free</span>; page = page->next) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->slab >= pages) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->slab > pages) {</span><br><span class="line"> page[page->slab - <span class="number">1</span>].prev = (<span class="keyword">uintptr_t</span>) &page[pages];</span><br><span class="line"></span><br><span class="line"> page[pages].slab = page->slab - pages;</span><br><span class="line"> page[pages].next = page->next;</span><br><span class="line"> page[pages].prev = page->prev;</span><br><span class="line"></span><br><span class="line"> p = (<span class="keyword">ngx_slab_page_t</span> *) page->prev;</span><br><span class="line"> p->next = &page[pages];</span><br><span class="line"> page->next->prev = (<span class="keyword">uintptr_t</span>) &page[pages];</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {<span class="comment">//page页不够用了,则free的next和prev都指向自己</span></span><br><span class="line"> p = (<span class="keyword">ngx_slab_page_t</span> *) page->prev;</span><br><span class="line"> p->next = page->next;</span><br><span class="line"> page->next->prev = page->prev;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//NGX_SLAB_PAGE_START标记page是分配的pages个页的第一个页,并在第一个页page中记录出其后连续的pages个页是一起分配的</span></span><br><span class="line"> page->slab = pages | NGX_SLAB_PAGE_START;</span><br><span class="line"> page->next = <span class="literal">NULL</span>;</span><br><span class="line"> page->prev = NGX_SLAB_PAGE;</span><br><span class="line"></span><br><span class="line"> pool->pfree -= pages;</span><br><span class="line"> <span class="comment">//pages为1。则直接返回该page</span></span><br><span class="line"> <span class="keyword">if</span> (--pages == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> page;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (p = page + <span class="number">1</span>; pages; pages--) {</span><br><span class="line"> <span class="comment">//如果分配的页数pages>1,更新后面page slab的slab成员为NGX_SLAB_PAGE_BUSY</span></span><br><span class="line"> p->slab = NGX_SLAB_PAGE_BUSY;</span><br><span class="line"> p->next = <span class="literal">NULL</span>;</span><br><span class="line"> p->prev = NGX_SLAB_PAGE;</span><br><span class="line"> p++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> page;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (pool->log_nomem) {</span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_CRIT,</span><br><span class="line"> <span class="string">"ngx_slab_alloc() failed: no memory"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>最后来看看释放内存相关函数ngx_slab_free、ngx_slab_free_locked<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">void</span></span><br><span class="line">ngx_slab_free(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">void</span> *p)</span><br><span class="line">{</span><br><span class="line"> ngx_shmtx_lock(&pool->mutex);</span><br><span class="line"></span><br><span class="line"> ngx_slab_free_locked(pool, p);</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&pool->mutex);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span></span><br><span class="line">ngx_slab_free_locked(<span class="keyword">ngx_slab_pool_t</span> *pool, <span class="keyword">void</span> *p)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> size;</span><br><span class="line"> <span class="keyword">uintptr_t</span> slab, m, *bitmap;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n, type, slot, shift, <span class="built_in">map</span>;</span><br><span class="line"> <span class="keyword">ngx_slab_page_t</span> *slots, *page;</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle-><span class="built_in">log</span>, <span class="number">0</span>, <span class="string">"slab free: %p"</span>, p);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((u_char *) p < pool->start || (u_char *) p > pool->end) {</span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT, <span class="string">"ngx_slab_free(): outside of pool"</span>);</span><br><span class="line"> <span class="keyword">goto</span> fail;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//根据p找到需要释放的m_page元素 </span></span><br><span class="line"> n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;</span><br><span class="line"> page = &pool->pages[n];</span><br><span class="line"> <span class="comment">//如果分配的时候一次性分配多个page,则第一个page的slab指定本次一次性分配了多少个页page</span></span><br><span class="line"> slab = page->slab;</span><br><span class="line"> type = ngx_slab_page_type(page);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">switch</span> (type) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> NGX_SLAB_SMALL:</span><br><span class="line"></span><br><span class="line"> shift = slab & NGX_SLAB_SHIFT_MASK;</span><br><span class="line"> size = (<span class="keyword">size_t</span>) <span class="number">1</span> << shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">uintptr_t</span>) p & (size - <span class="number">1</span>)) {</span><br><span class="line"> <span class="keyword">goto</span> wrong_chunk;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> n = ((<span class="keyword">uintptr_t</span>) p & (ngx_pagesize - <span class="number">1</span>)) >> shift;</span><br><span class="line"> m = (<span class="keyword">uintptr_t</span>) <span class="number">1</span> << (n % (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>)));</span><br><span class="line"> n /= <span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>);</span><br><span class="line"> bitmap = (<span class="keyword">uintptr_t</span> *)</span><br><span class="line"> ((<span class="keyword">uintptr_t</span>) p & ~((<span class="keyword">uintptr_t</span>) ngx_pagesize - <span class="number">1</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (bitmap[n] & m) {</span><br><span class="line"> slot = shift - pool->min_shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->next == <span class="literal">NULL</span>) {</span><br><span class="line"> slots = ngx_slab_slots(pool);</span><br><span class="line"></span><br><span class="line"> page->next = slots[slot].next;</span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_SMALL;</span><br><span class="line"> page->next->prev = (<span class="keyword">uintptr_t</span>) page | NGX_SLAB_SMALL;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> bitmap[n] &= ~m;</span><br><span class="line"></span><br><span class="line"> n = (ngx_pagesize >> shift) / ((<span class="number">1</span> << shift) * <span class="number">8</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n == <span class="number">0</span>) {</span><br><span class="line"> n = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> i = n / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>));</span><br><span class="line"> m = ((<span class="keyword">uintptr_t</span>) <span class="number">1</span> << (n % (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>)))) - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (bitmap[i] & ~m) {</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span> = (ngx_pagesize >> shift) / (<span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = i + <span class="number">1</span>; i < <span class="built_in">map</span>; i++) {</span><br><span class="line"> <span class="keyword">if</span> (bitmap[i]) {</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_slab_free_pages(pool, page, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total -= (ngx_pagesize >> shift) - n;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> chunk_already_free;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> NGX_SLAB_EXACT:</span><br><span class="line"></span><br><span class="line"> m = (<span class="keyword">uintptr_t</span>) <span class="number">1</span> <<</span><br><span class="line"> (((<span class="keyword">uintptr_t</span>) p & (ngx_pagesize - <span class="number">1</span>)) >> ngx_slab_exact_shift);</span><br><span class="line"> size = ngx_slab_exact_size;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">uintptr_t</span>) p & (size - <span class="number">1</span>)) {</span><br><span class="line"> <span class="keyword">goto</span> wrong_chunk;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//slab(位图)中对应的位为1 </span></span><br><span class="line"> <span class="keyword">if</span> (slab & m) {</span><br><span class="line"> slot = ngx_slab_exact_shift - pool->min_shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (slab == NGX_SLAB_BUSY) {</span><br><span class="line"> slots = ngx_slab_slots(pool);</span><br><span class="line"></span><br><span class="line"> page->next = slots[slot].next;</span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_EXACT;</span><br><span class="line"> page->next->prev = (<span class="keyword">uintptr_t</span>) page | NGX_SLAB_EXACT;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> page->slab &= ~m;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->slab) {</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_slab_free_pages(pool, page, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total -= <span class="number">8</span> * <span class="keyword">sizeof</span>(<span class="keyword">uintptr_t</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> chunk_already_free;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">case</span> NGX_SLAB_BIG:</span><br><span class="line"> <span class="comment">//slab的高16位是slot块的位图,低16位用于存储slot块大小的偏移</span></span><br><span class="line"> shift = slab & NGX_SLAB_SHIFT_MASK;</span><br><span class="line"> size = (<span class="keyword">size_t</span>) <span class="number">1</span> << shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">uintptr_t</span>) p & (size - <span class="number">1</span>)) {</span><br><span class="line"> <span class="keyword">goto</span> wrong_chunk;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> m = (<span class="keyword">uintptr_t</span>) <span class="number">1</span> << ((((<span class="keyword">uintptr_t</span>) p & (ngx_pagesize - <span class="number">1</span>)) >> shift)</span><br><span class="line"> + NGX_SLAB_MAP_SHIFT);</span><br><span class="line"> <span class="comment">//该slab块确实正在被使用 </span></span><br><span class="line"> <span class="keyword">if</span> (slab & m) {</span><br><span class="line"> slot = shift - pool->min_shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->next == <span class="literal">NULL</span>) {</span><br><span class="line"> slots = ngx_slab_slots(pool);</span><br><span class="line"></span><br><span class="line"> page->next = slots[slot].next;</span><br><span class="line"> slots[slot].next = page;</span><br><span class="line"></span><br><span class="line"> page->prev = (<span class="keyword">uintptr_t</span>) &slots[slot] | NGX_SLAB_BIG;</span><br><span class="line"> page->next->prev = (<span class="keyword">uintptr_t</span>) page | NGX_SLAB_BIG;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> page->slab &= ~m;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (page->slab & NGX_SLAB_MAP_MASK) {</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//如果page页中所有slab块都不在使用就将该页面链入free中</span></span><br><span class="line"> ngx_slab_free_pages(pool, page, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].total -= ngx_pagesize >> shift;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> chunk_already_free;</span><br><span class="line"> <span class="comment">//用户归还整个页面 </span></span><br><span class="line"> <span class="keyword">case</span> NGX_SLAB_PAGE:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">uintptr_t</span>) p & (ngx_pagesize - <span class="number">1</span>)) {</span><br><span class="line"> <span class="keyword">goto</span> wrong_chunk;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(slab & NGX_SLAB_PAGE_START)) {</span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT,</span><br><span class="line"> <span class="string">"ngx_slab_free(): page is already free"</span>);</span><br><span class="line"> <span class="keyword">goto</span> fail;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (slab == NGX_SLAB_PAGE_BUSY) {</span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT,</span><br><span class="line"> <span class="string">"ngx_slab_free(): pointer to wrong page"</span>);</span><br><span class="line"> <span class="keyword">goto</span> fail;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//计算归还page的个数</span></span><br><span class="line"> size = slab & ~NGX_SLAB_PAGE_START;</span><br><span class="line"> <span class="comment">//归还页面 </span></span><br><span class="line"> ngx_slab_free_pages(pool, page, size);</span><br><span class="line"></span><br><span class="line"> ngx_slab_junk(p, size << ngx_pagesize_shift);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* not reached */</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"></span><br><span class="line"> pool->stats[slot].used--;</span><br><span class="line"></span><br><span class="line"> ngx_slab_junk(p, size);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">wrong_chunk:</span><br><span class="line"></span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT,</span><br><span class="line"> <span class="string">"ngx_slab_free(): pointer to wrong chunk"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> fail;</span><br><span class="line"></span><br><span class="line">chunk_already_free:</span><br><span class="line"></span><br><span class="line"> ngx_slab_error(pool, NGX_LOG_ALERT,</span><br><span class="line"> <span class="string">"ngx_slab_free(): chunk is already free"</span>);</span><br><span class="line"></span><br><span class="line">fail:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h2 id="3-总结"><a href="#3-总结" class="headerlink" title="3 总结"></a>3 总结</h2><blockquote><p>以上就是slab相关函数实现,nginx的slab共享内存借鉴了linux内核的内存管理的实现。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-简述"><a href="#1-简述" class="headerlink" title="1. 简述"></a>1. 简述</h
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx限流模块详解</title>
<link href="https://weeweetan.github.io/2020/04/15/Nginx%E9%99%90%E6%B5%81%E6%A8%A1%E5%9D%97%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2020/04/15/Nginx限流模块详解/</id>
<published>2020-04-15T14:54:37.000Z</published>
<updated>2021-06-05T14:20:15.119Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相关指令</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Syntax: limit_conn_zone key zone=name:size;</span><br><span class="line">Default: —</span><br><span class="line">Context: http</span><br></pre></td></tr></table></figure><blockquote><p>此指令设置限流所需共享内存的名称和size,key指定限流的标志,比如$binary_remote_addr。</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">Syntax:limit_conn zone number;</span><br><span class="line">Default: —</span><br><span class="line">Context: http, server, location</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>此指令指定共享内存名以及限制多少连接,比如limit_conn_zone指令key设置为$binary_remote_addr,zone设置为limit_zone,那么来自于$binary_remote_addr的连接超过number,nginx直接给客户端响应503。</p></blockquote><h2 id="2-源码解析"><a href="#2-源码解析" class="headerlink" title="2.源码解析"></a>2.源码解析</h2><h3 id="2-1-配置解析函数"><a href="#2-1-配置解析函数" class="headerlink" title="2.1 配置解析函数"></a>2.1 配置解析函数</h3><blockquote><ol><li>首先来看下limit_conn_zone指令的解析函数ngx_http_limit_conn_zone,这个函数的功能主要是解析共享内存的name和size,然后使用这两个值作为参数调用ngx_shared_memory_add函数,将共享内存添加到nginx共享内存管理模块中,设置共享内存的data以及初始化函数。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_limit_conn_zone(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> u_char *p;</span><br><span class="line"> <span class="keyword">ssize_t</span> size;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, name, s;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_shm_zone_t</span> *shm_zone;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_http_compile_complex_value_t</span> ccv;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> ctx = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_limit_conn_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[<span class="number">1</span>];</span><br><span class="line"> ccv.complex_value = &ctx->key;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> size = <span class="number">0</span>;</span><br><span class="line"> name.len = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">2</span>; i < cf->args->nelts; i++) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[i].data, <span class="string">"zone="</span>, <span class="number">5</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> name.data = value[i].data + <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"> p = (u_char *) ngx_strchr(name.data, <span class="string">':'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (p == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid zone size \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name.len = p - name.data;</span><br><span class="line"></span><br><span class="line"> s.data = p + <span class="number">1</span>;</span><br><span class="line"> s.len = value[i].data + value[i].len - s.data;</span><br><span class="line"></span><br><span class="line"> size = ngx_parse_size(&s);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (size == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid zone size \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (size < (<span class="keyword">ssize_t</span>) (<span class="number">8</span> * ngx_pagesize)) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"zone \"%V\" is too small"</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid parameter \"%V\""</span>, &value[i]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name.len == <span class="number">0</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"\"%V\" must have \"zone\" parameter"</span>,</span><br><span class="line"> &cmd->name);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> shm_zone = ngx_shared_memory_add(cf, &name, size,</span><br><span class="line"> &ngx_http_limit_conn_module);</span><br><span class="line"> <span class="keyword">if</span> (shm_zone == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (shm_zone->data) {</span><br><span class="line"> ctx = shm_zone->data;</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"%V \"%V\" is already bound to key \"%V\""</span>,</span><br><span class="line"> &cmd->name, &name, &ctx->key.value);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> shm_zone->init = ngx_http_limit_conn_init_zone;</span><br><span class="line"> shm_zone->data = ctx;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="2"><li>接下来看下limit_conn指令解析函数ngx_http_limit_conn,这个函数主要是保存配置的共享内存名以及限制连接的个数。</li></ol></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_limit_conn(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_shm_zone_t</span> *shm_zone;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_conf_t</span> *lccf = conf;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_limit_t</span> *limit, *limits;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> n;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> shm_zone = ngx_shared_memory_add(cf, &value[<span class="number">1</span>], <span class="number">0</span>,</span><br><span class="line"> &ngx_http_limit_conn_module);</span><br><span class="line"> <span class="keyword">if</span> (shm_zone == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> limits = lccf->limits.elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (limits == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">if</span> (ngx_array_init(&lccf->limits, cf->pool, <span class="number">1</span>,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_limit_conn_limit_t</span>))</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < lccf->limits.nelts; i++) {</span><br><span class="line"> <span class="keyword">if</span> (shm_zone == limits[i].shm_zone) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 解析配置种被限制的连接数</span></span><br><span class="line"> n = ngx_atoi(value[<span class="number">2</span>].data, value[<span class="number">2</span>].len);</span><br><span class="line"> <span class="keyword">if</span> (n <= <span class="number">0</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid number of connections \"%V\""</span>, &value[<span class="number">2</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n > <span class="number">65535</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"connection limit must be less 65536"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> limit = ngx_array_push(&lccf->limits);</span><br><span class="line"> <span class="keyword">if</span> (limit == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> limit->conn = n;</span><br><span class="line"> limit->shm_zone = shm_zone;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><ol start="3"><li>接下来就来看下nginx是如何实现限流的,这个功能由ngx_http_limit_conn_handler实现,主要功能就是统计各个进程与key对应的连接数,超过则返回503,在统计各个进程数据的时候使用了共享内存。<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_limit_conn_handler(<span class="keyword">ngx_http_request_t</span> *r)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> n;</span><br><span class="line"> <span class="keyword">uint32_t</span> hash;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> key;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_slab_pool_t</span> *shpool;</span><br><span class="line"> <span class="keyword">ngx_rbtree_node_t</span> *node;</span><br><span class="line"> <span class="keyword">ngx_pool_cleanup_t</span> *cln;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_node_t</span> *lc;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_conf_t</span> *lccf;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_limit_t</span> *limits;</span><br><span class="line"> <span class="keyword">ngx_http_limit_conn_cleanup_t</span> *lccln;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (r->main->limit_conn_set) {</span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);</span><br><span class="line"> limits = lccf->limits.elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < lccf->limits.nelts; i++) {</span><br><span class="line"> ctx = limits[i].shm_zone->data;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取limit_conn_zone指令后key的值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (key.len == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (key.len > <span class="number">255</span>) {</span><br><span class="line"> ngx_log_error(NGX_LOG_ERR, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the value of the \"%V\" key "</span></span><br><span class="line"> <span class="string">"is more than 255 bytes: \"%V\""</span>,</span><br><span class="line"> &ctx->key.value, &key);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> r->main->limit_conn_set = <span class="number">1</span>;</span><br><span class="line"> <span class="comment">//对key进行crc计算,用于在红黑树中查找结点</span></span><br><span class="line"> hash = ngx_crc32_short(key.data, key.len);</span><br><span class="line"></span><br><span class="line"> shpool = (<span class="keyword">ngx_slab_pool_t</span> *) limits[i].shm_zone->shm.addr;</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_lock(&shpool->mutex);</span><br><span class="line"> <span class="comment">// 查找符合要求的结点</span></span><br><span class="line"> node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);</span><br><span class="line"> <span class="comment">// 没有找到对应的结点,将此次请求插入到红黑树中</span></span><br><span class="line"> <span class="keyword">if</span> (node == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="comment">//计算结点所需内存</span></span><br><span class="line"> n = offsetof(<span class="keyword">ngx_rbtree_node_t</span>, color)</span><br><span class="line"> + offsetof(<span class="keyword">ngx_http_limit_conn_node_t</span>, data)</span><br><span class="line"> + key.len;</span><br><span class="line"> <span class="comment">// 申请结点内存</span></span><br><span class="line"> node = ngx_slab_alloc_locked(shpool, n);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (node == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_shmtx_unlock(&shpool->mutex);</span><br><span class="line"> ngx_http_limit_conn_cleanup_all(r->pool);</span><br><span class="line"> <span class="keyword">return</span> lccf->status_code;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> lc = (<span class="keyword">ngx_http_limit_conn_node_t</span> *) &node->color;</span><br><span class="line"> <span class="comment">// 赋值key,用于下次请求到来查询</span></span><br><span class="line"> node->key = hash;</span><br><span class="line"> lc->len = (u_char) key.len;</span><br><span class="line"> lc->conn = <span class="number">1</span>;</span><br><span class="line"> ngx_memcpy(lc->data, key.data, key.len);</span><br><span class="line"></span><br><span class="line"> ngx_rbtree_insert(ctx->rbtree, node);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"></span><br><span class="line"> lc = (<span class="keyword">ngx_http_limit_conn_node_t</span> *) &node->color;</span><br><span class="line"> <span class="comment">// 判断key标记的connections是否超过配置,如果超过则返回错误码</span></span><br><span class="line"> <span class="keyword">if</span> ((<span class="keyword">ngx_uint_t</span>) lc->conn >= limits[i].conn) {</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&shpool->mutex);</span><br><span class="line"></span><br><span class="line"> ngx_log_error(lccf->log_level, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"limiting connections by zone \"%V\""</span>,</span><br><span class="line"> &limits[i].shm_zone->shm.name);</span><br><span class="line"></span><br><span class="line"> ngx_http_limit_conn_cleanup_all(r->pool);</span><br><span class="line"> <span class="keyword">return</span> lccf->status_code;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//连接数量+1</span></span><br><span class="line"> lc->conn++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"limit conn: %08Xi %d"</span>, node->key, lc->conn);</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&shpool->mutex);</span><br><span class="line"> <span class="comment">//注册内存池清理函数</span></span><br><span class="line"> cln = ngx_pool_cleanup_add(r->pool,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_limit_conn_cleanup_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (cln == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_HTTP_INTERNAL_SERVER_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 绑定内存清理函数</span></span><br><span class="line"> cln->handler = ngx_http_limit_conn_cleanup;</span><br><span class="line"> lccln = cln->data;</span><br><span class="line"></span><br><span class="line"> lccln->shm_zone = limits[i].shm_zone;</span><br><span class="line"> lccln->node = node;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_DECLINED;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="4"><li>结点插入函数,限流模块是将每个连接都存进一颗红黑树中,nginx提供一个默认的插入函数,限流模块自己实现了一个插入函数。</li></ol></blockquote><h2 id="3-总结"><a href="#3-总结" class="headerlink" title="3. 总结"></a>3. 总结</h2><blockquote><p>以上就是nginx限流模块的基本实现,其他限制请求数的模块类似。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1-相关指令"><a href="#1-相关指令" class="headerlink" title="1.相关指令"></a>1.相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>GDB调试技巧</title>
<link href="https://weeweetan.github.io/2020/02/26/GDB%E8%B0%83%E8%AF%95%E6%8A%80%E5%B7%A7/"/>
<id>https://weeweetan.github.io/2020/02/26/GDB调试技巧/</id>
<published>2020-02-26T11:24:12.000Z</published>
<updated>2023-05-18T15:38:50.610Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-预备工作"><a href="#1-预备工作" class="headerlink" title="1 预备工作"></a>1 预备工作</h2><h3 id="1-1-添加编译参数"><a href="#1-1-添加编译参数" class="headerlink" title="1.1 添加编译参数"></a>1.1 添加编译参数</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc -g</span><br></pre></td></tr></table></figure><blockquote><p>只有在编译的时候添加了-g这个参数,才能够使用gdb进行调试。可以使用-O0,避免某些变量被优化</p></blockquote><h2 id="2-调试过程"><a href="#2-调试过程" class="headerlink" title="2 调试过程"></a>2 调试过程</h2><h3 id="2-1-调试新进程"><a href="#2-1-调试新进程" class="headerlink" title="2.1 调试新进程"></a>2.1 调试新进程</h3><blockquote><p>gdb 程序名称</p></blockquote><h3 id="2-2-调试已有进程"><a href="#2-2-调试已有进程" class="headerlink" title="2.2 调试已有进程"></a>2.2 调试已有进程</h3><blockquote><p>使用命令 gdb attach pid,跟踪现有进程,也可使用gdb -p pid, 输入bt,直接查看当前进程运行到哪里</p></blockquote><h3 id="2-3-常用命令"><a href="#2-3-常用命令" class="headerlink" title="2.3 常用命令"></a>2.3 常用命令</h3><blockquote><ol><li>单步调式 s,全称step,意味着每个函数都会进入</li><li>单步调试 n, 全称next,不会进入函数</li><li>打印变量 p, 全称print,可以打印各种变量的值,打印二进制 p/t xxx</li><li>继续进程 c, 全称continue,设置好断点后,继续运行,直到发生断点</li><li>设置断点 b, 全称breakpoint,可设置函数断点也可以设置代码行号断点</li><li>打印堆栈 bt, 全称backtrace, 打印当前函数调用栈</li><li>退出当前函数栈 finish, 当使用s命令进入到某个函数后,可以使用finish指令退出当前函数</li><li>设置命令行参数 set args, 若函数需要argv,args,可以使用此命令设置</li><li>跳转到指定调用栈 f (0…N), 后面跟随栈层,伴随bt命令使用,首先使用bt参看当前函数调用栈,然后使用f命令查看对应栈的信息</li><li>显示隐藏字符串set print elements 0,字符串过长的情况下使用p打印会以…结束,无法完整显示,使用此命令可以显示完全</li><li>条件断点 b point if condition,条件满足才会触发中断</li><li>监控某个值 watch,值改变就会触发中断,也可监控某个内存地址,watch *(内存地址),适用于跟踪一些全局的结构体指针。</li><li>跳转到指定行 until 行号,对于跳出循环很有用</li><li>格式化打印printf fmt, var,类似于C语言的库函数 printf “%s”, str</li><li>打印错误号: p errno</li><li>设置变量set $a</li><li>while循环以end结束</li><li>layout src, 加载源码</li><li>info local, 打印当前帧所有局部变量</li><li>p ‘a.c’::xx,打印其他文件的全局变量</li><li>p *a@123, 打印以a开始的123字节,需要配合10使用</li><li>info args,打印函数入参</li><li>r,运行程序</li></ol></blockquote><h2 id="3-总结"><a href="#3-总结" class="headerlink" title="3 总结"></a>3 总结</h2><blockquote><p>以上就是gdb调试常用命令,大多数场景都能应用。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-预备工作"><a href="#1-预备工作" class="headerlink" title="1 预备工作"></a>1 预
</summary>
<category term="总结" scheme="https://weeweetan.github.io/categories/%E6%80%BB%E7%BB%93/"/>
<category term="GDB" scheme="https://weeweetan.github.io/tags/GDB/"/>
</entry>
<entry>
<title>Nginx缓存清理</title>
<link href="https://weeweetan.github.io/2019/10/27/Nginx%E7%BC%93%E5%AD%98%E6%B8%85%E7%90%86/"/>
<id>https://weeweetan.github.io/2019/10/27/Nginx缓存清理/</id>
<published>2019-10-27T13:56:19.000Z</published>
<updated>2020-11-13T11:47:58.998Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相关配置</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">proxy_cache_path /dev/sda1/data inactive=<span class="number">60</span>m max_size=<span class="number">10</span>G;</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>proxy_cache_path指令的inactive参数和max_size参数用来维护缓存队列大小</p></blockquote><h2 id="2、源码解析"><a href="#2、源码解析" class="headerlink" title="2、源码解析"></a>2、源码解析</h2><blockquote><ol><li>首先来看看配置解析函数<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br></pre></td><td class="code"><pre><span class="line">char *</span><br><span class="line">ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)</span><br><span class="line">{</span><br><span class="line"> char *confp = conf;</span><br><span class="line"></span><br><span class="line"> off_t max_size;</span><br><span class="line"> u_char *last, *p;</span><br><span class="line"> time_t inactive;</span><br><span class="line"> ssize_t size;</span><br><span class="line"> ngx_str_t s, name, *value;</span><br><span class="line"> ngx_int_t loader_files, manager_files;</span><br><span class="line"> ngx_msec_t loader_sleep, manager_sleep, loader_threshold,</span><br><span class="line"> manager_threshold;</span><br><span class="line"> ngx_uint_t i, n, use_temp_path;</span><br><span class="line"> ngx_array_t *caches;</span><br><span class="line"> ngx_http_file_cache_t *cache, **ce;</span><br><span class="line"></span><br><span class="line"> cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));</span><br><span class="line"> if (cache == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));</span><br><span class="line"> if (cache->path == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> use_temp_path = 1;</span><br><span class="line"></span><br><span class="line"> inactive = 600;</span><br><span class="line"></span><br><span class="line"> loader_files = 100;</span><br><span class="line"> loader_sleep = 50;</span><br><span class="line"> loader_threshold = 200;</span><br><span class="line"></span><br><span class="line"> manager_files = 100;</span><br><span class="line"> manager_sleep = 50;</span><br><span class="line"> manager_threshold = 200;</span><br><span class="line"></span><br><span class="line"> name.len = 0;</span><br><span class="line"> size = 0;</span><br><span class="line"> max_size = NGX_MAX_OFF_T_VALUE;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"> //指定路径名称</span><br><span class="line"> cache->path->name = value[1];</span><br><span class="line"></span><br><span class="line"> if (cache->path->name.data[cache->path->name.len - 1] == '/') {</span><br><span class="line"> cache->path->name.len--;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //解析proxy_cache_path指令后的参数</span><br><span class="line"> for (i = 2; i < cf->args->nelts; i++) {</span><br><span class="line"> //解析目录层级参数</span><br><span class="line"> if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {</span><br><span class="line"></span><br><span class="line"> p = value[i].data + 7;</span><br><span class="line"> last = value[i].data + value[i].len;</span><br><span class="line"></span><br><span class="line"> for (n = 0; n < NGX_MAX_PATH_LEVEL && p < last; n++) {</span><br><span class="line"></span><br><span class="line"> if (*p > '0' && *p < '3') {</span><br><span class="line"></span><br><span class="line"> cache->path->level[n] = *p++ - '0';</span><br><span class="line"> cache->path->len += cache->path->level[n] + 1;</span><br><span class="line"></span><br><span class="line"> if (p == last) {</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (*p++ == ':' && n < NGX_MAX_PATH_LEVEL - 1 && p < last) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> goto invalid_levels;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> goto invalid_levels;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (cache->path->len < 10 + NGX_MAX_PATH_LEVEL) {</span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> invalid_levels:</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid \"levels\" \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strncmp(value[i].data, "use_temp_path=", 14) == 0) {</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(&value[i].data[14], "on") == 0) {</span><br><span class="line"> use_temp_path = 1;</span><br><span class="line"></span><br><span class="line"> } else if (ngx_strcmp(&value[i].data[14], "off") == 0) {</span><br><span class="line"> use_temp_path = 0;</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid use_temp_path value \"%V\", "</span><br><span class="line"> "it must be \"on\" or \"off\"",</span><br><span class="line"> &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析共享内存名称参数</span><br><span class="line"> if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {</span><br><span class="line"></span><br><span class="line"> name.data = value[i].data + 10;</span><br><span class="line"></span><br><span class="line"> p = (u_char *) ngx_strchr(name.data, ':');</span><br><span class="line"></span><br><span class="line"> if (p == NULL) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid keys zone size \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name.len = p - name.data;</span><br><span class="line"></span><br><span class="line"> s.data = p + 1;</span><br><span class="line"> s.len = value[i].data + value[i].len - s.data;</span><br><span class="line"></span><br><span class="line"> size = ngx_parse_size(&s);</span><br><span class="line"></span><br><span class="line"> if (size == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid keys zone size \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (size < (ssize_t) (2 * ngx_pagesize)) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "keys zone \"%V\" is too small", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析缓存分片活跃时间</span><br><span class="line"> if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 9;</span><br><span class="line"> s.data = value[i].data + 9;</span><br><span class="line"></span><br><span class="line"> inactive = ngx_parse_time(&s, 1);</span><br><span class="line"> if (inactive == (time_t) NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid inactive value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析配置的目录最大能保存多少缓存分片</span><br><span class="line"> if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 9;</span><br><span class="line"> s.data = value[i].data + 9;</span><br><span class="line"></span><br><span class="line"> max_size = ngx_parse_offset(&s);</span><br><span class="line"> if (max_size < 0) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid max_size value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析缓存加载进程暂停阈值</span><br><span class="line"> if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {</span><br><span class="line"></span><br><span class="line"> loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);</span><br><span class="line"> if (loader_files == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid loader_files value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析缓存加载进程暂停时间</span><br><span class="line"> if (ngx_strncmp(value[i].data, "loader_sleep=", 13) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 13;</span><br><span class="line"> s.data = value[i].data + 13;</span><br><span class="line"></span><br><span class="line"> loader_sleep = ngx_parse_time(&s, 0);</span><br><span class="line"> if (loader_sleep == (ngx_msec_t) NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid loader_sleep value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 17;</span><br><span class="line"> s.data = value[i].data + 17;</span><br><span class="line"></span><br><span class="line"> loader_threshold = ngx_parse_time(&s, 0);</span><br><span class="line"> if (loader_threshold == (ngx_msec_t) NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid loader_threshold value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"> //解析缓存管理进程暂停阈值</span><br><span class="line"> if (ngx_strncmp(value[i].data, "manager_files=", 14) == 0) {</span><br><span class="line"></span><br><span class="line"> manager_files = ngx_atoi(value[i].data + 14, value[i].len - 14);</span><br><span class="line"> if (manager_files == NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid manager_files value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //manager进程达到阈值后的睡眠时间</span><br><span class="line"> if (ngx_strncmp(value[i].data, "manager_sleep=", 14) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 14;</span><br><span class="line"> s.data = value[i].data + 14;</span><br><span class="line"></span><br><span class="line"> manager_sleep = ngx_parse_time(&s, 0);</span><br><span class="line"> if (manager_sleep == (ngx_msec_t) NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid manager_sleep value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strncmp(value[i].data, "manager_threshold=", 18) == 0) {</span><br><span class="line"></span><br><span class="line"> s.len = value[i].len - 18;</span><br><span class="line"> s.data = value[i].data + 18;</span><br><span class="line"></span><br><span class="line"> manager_threshold = ngx_parse_time(&s, 0);</span><br><span class="line"> if (manager_threshold == (ngx_msec_t) NGX_ERROR) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid manager_threshold value \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> continue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "invalid parameter \"%V\"", &value[i]);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (name.len == 0 || size == 0) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "\"%V\" must have \"keys_zone\" parameter",</span><br><span class="line"> &cmd->name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //设置loader跟manager进程的回调函数</span><br><span class="line"> cache->path->manager = ngx_http_file_cache_manager;</span><br><span class="line"> cache->path->loader = ngx_http_file_cache_loader;</span><br><span class="line"> cache->path->data = cache;</span><br><span class="line"> cache->path->conf_file = cf->conf_file->file.name.data;</span><br><span class="line"> cache->path->line = cf->conf_file->line;</span><br><span class="line"> cache->loader_files = loader_files;</span><br><span class="line"> cache->loader_sleep = loader_sleep;</span><br><span class="line"> cache->loader_threshold = loader_threshold;</span><br><span class="line"> cache->manager_files = manager_files;</span><br><span class="line"> cache->manager_sleep = manager_sleep;</span><br><span class="line"> cache->manager_threshold = manager_threshold;</span><br><span class="line"> //将缓存路径添加到全局管理</span><br><span class="line"> if (ngx_add_path(cf, &cache->path) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> //添加共享内存名称</span><br><span class="line"> cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);</span><br><span class="line"> if (cache->shm_zone == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (cache->shm_zone->data) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "duplicate zone \"%V\"", &name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //设置共享内存初始化函数指针</span><br><span class="line"> cache->shm_zone->init = ngx_http_file_cache_init;</span><br><span class="line"> cache->shm_zone->data = cache;</span><br><span class="line"></span><br><span class="line"> cache->use_temp_path = use_temp_path;</span><br><span class="line"></span><br><span class="line"> cache->inactive = inactive;</span><br><span class="line"> cache->max_size = max_size;</span><br><span class="line"></span><br><span class="line"> caches = (ngx_array_t *) (confp + cmd->offset);</span><br><span class="line"> //保存cache结构体</span><br><span class="line"> ce = ngx_array_push(caches);</span><br><span class="line"> if (ce == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *ce = cache;</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol></blockquote><blockquote><ol start="2"><li>上述代码中我们只关注inactive,max_size参数解析、cache->path相关成员赋值以及loader和manager相关的赋值代码,如下所示:</li></ol></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">cache->path->manager = ngx_http_file_cache_manager;</span><br><span class="line">cache->path->loader = ngx_http_file_cache_loader;</span><br><span class="line">cache->path->data = cache;</span><br><span class="line">cache->path->conf_file = cf->conf_file->file.name.data;</span><br><span class="line">cache->path->line = cf->conf_file->line;</span><br><span class="line">cache->loader_files = loader_files;</span><br><span class="line">cache->loader_sleep = loader_sleep;</span><br><span class="line">cache->loader_threshold = loader_threshold;</span><br><span class="line">cache->manager_files = manager_files;</span><br><span class="line">cache->manager_sleep = manager_sleep;</span><br><span class="line">cache->manager_threshold = manager_threshold;</span><br><span class="line"></span><br><span class="line">if (ngx_add_path(cf, &cache->path) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line">//添加共享内存名称</span><br><span class="line">cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);</span><br><span class="line">if (cache->shm_zone == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">if (cache->shm_zone->data) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "duplicate zone \"%V\"", &name);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//设置共享内存初始化函数</span><br><span class="line">cache->shm_zone->init = ngx_http_file_cache_init;</span><br><span class="line">cache->shm_zone->data = cache;</span><br><span class="line"></span><br><span class="line">cache->use_temp_path = use_temp_path;</span><br><span class="line"></span><br><span class="line">cache->inactive = inactive;</span><br><span class="line">cache->max_size = max_size;</span><br><span class="line">//保存cache</span><br><span class="line">caches = (ngx_array_t *) (confp + cmd->offset);</span><br><span class="line"></span><br><span class="line">ce = ngx_array_push(caches);</span><br><span class="line">if (ce == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">*ce = cache;</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><ol start="3"><li>path结构体初始化完成之后,ngx_add_path函数将配置的路径添加到nginx全局路径管理器后,配置解析完成之后会统一管理,接下来我们来看看几个跟目录相关的回调函数。</li></ol></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">ngx_http_file_cache_manager</span><br><span class="line">//加载本地已有缓存函数</span><br><span class="line">ngx_http_file_cache_loader</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><ol start="4"><li>首先来看看ngx_http_file_cache_manager函数的具体实现</li></ol></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static ngx_msec_t</span><br><span class="line">ngx_http_file_cache_manager(void *data)</span><br><span class="line">{</span><br><span class="line"> ngx_http_file_cache_t *cache = data;</span><br><span class="line"></span><br><span class="line"> off_t size;</span><br><span class="line"> time_t wait;</span><br><span class="line"> ngx_msec_t elapsed, next;</span><br><span class="line"> ngx_uint_t count, watermark;</span><br><span class="line"></span><br><span class="line"> cache->last = ngx_current_msec;</span><br><span class="line"> cache->files = 0;</span><br><span class="line"> //查找过期缓存结点</span><br><span class="line"> next = (ngx_msec_t) ngx_http_file_cache_expire(cache) * 1000;</span><br><span class="line"></span><br><span class="line"> if (next == 0) {</span><br><span class="line"> next = cache->manager_sleep;</span><br><span class="line"> goto done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> for ( ;; ) {</span><br><span class="line"> ngx_shmtx_lock(&cache->shpool->mutex);</span><br><span class="line"></span><br><span class="line"> size = cache->sh->size;</span><br><span class="line"> count = cache->sh->count;</span><br><span class="line"> watermark = cache->sh->watermark;</span><br><span class="line"></span><br><span class="line"> ngx_shmtx_unlock(&cache->shpool->mutex);</span><br><span class="line"></span><br><span class="line"> ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,</span><br><span class="line"> "http file cache size: %O c:%ui w:%i",</span><br><span class="line"> size, count, (ngx_int_t) watermark);</span><br><span class="line"></span><br><span class="line"> if (size < cache->max_size && count < watermark) {</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> //处理缓存目录已经满了的情况</span><br><span class="line"> wait = ngx_http_file_cache_forced_expire(cache);</span><br><span class="line"></span><br><span class="line"> if (wait > 0) {</span><br><span class="line"> next = (ngx_msec_t) wait * 1000;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_quit || ngx_terminate) {</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (++cache->files >= cache->manager_files) {</span><br><span class="line"> next = cache->manager_sleep;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_time_update();</span><br><span class="line"></span><br><span class="line"> elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));</span><br><span class="line"></span><br><span class="line"> if (elapsed >= cache->manager_threshold) {</span><br><span class="line"> next = cache->manager_sleep;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"></span><br><span class="line"> elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last));</span><br><span class="line"></span><br><span class="line"> ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,</span><br><span class="line"> "http file cache manager: %ui e:%M n:%M",</span><br><span class="line"> cache->files, elapsed, next);</span><br><span class="line"></span><br><span class="line"> return next;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><ol start="5"><li>这个函数主要的功能就是遍历缓存结点数,找出过期结点,并删除,接下来看看ngx_http_file_cache_loader函数实现<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"> </span><br><span class="line">static void</span><br><span class="line">ngx_http_file_cache_loader(void *data)</span><br><span class="line">{</span><br><span class="line"> ngx_http_file_cache_t *cache = data;</span><br><span class="line"></span><br><span class="line"> ngx_tree_ctx_t tree;</span><br><span class="line"></span><br><span class="line"> if (!cache->sh->cold || cache->sh->loading) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) {</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,</span><br><span class="line"> "http file cache loader");</span><br><span class="line"> //设置遍历目录时所需的函数指针</span><br><span class="line"> tree.init_handler = NULL;</span><br><span class="line"> //遍历目录时,遇到文件处理函数</span><br><span class="line"> tree.file_handler = ngx_http_file_cache_manage_file;</span><br><span class="line"> //遍历目录时,遇到文件处理函数</span><br><span class="line"> tree.pre_tree_handler = ngx_http_file_cache_manage_directory;</span><br><span class="line"> tree.post_tree_handler = ngx_http_file_cache_noop;</span><br><span class="line"> //缓存目录中有不符合规则的缓存文件,会删除文件</span><br><span class="line"> tree.spec_handler = ngx_http_file_cache_delete_file;</span><br><span class="line"> tree.data = cache;</span><br><span class="line"> tree.alloc = 0;</span><br><span class="line"> tree.log = ngx_cycle->log;</span><br><span class="line"></span><br><span class="line"> cache->last = ngx_current_msec;</span><br><span class="line"> cache->files = 0;</span><br><span class="line"> //遍历配置路径下所有文件</span><br><span class="line"> if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {</span><br><span class="line"> cache->sh->loading = 0;</span><br><span class="line"> return;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cache->sh->cold = 0;</span><br><span class="line"> cache->sh->loading = 0;</span><br><span class="line"></span><br><span class="line"> ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,</span><br><span class="line"> "http file cache: %V %.3fM, bsize: %uz",</span><br><span class="line"> &cache->path->name,</span><br><span class="line"> ((double) cache->sh->size * cache->bsize) / (1024 * 1024),</span><br><span class="line"> cache->bsize);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">>6. 此函数功能就是绑定回调函数,然后遍历配置的目录,根据目录中不同的对象调用不同的回调函数</span><br><span class="line"> </span><br></pre></td></tr></table></figure></li></ol></blockquote><h2 id="3、总结"><a href="#3、总结" class="headerlink" title="3、总结"></a>3、总结</h2><blockquote><p>以上就是nginx缓存管理的主要代码,总的来说就是在解析配置时设置ngx_path_t结构体的回调函数,cache_manager进程定时启动扫描LRU队列,删除过期结点</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的return模块</title>
<link href="https://weeweetan.github.io/2019/10/12/Nginx%E7%9A%84return%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2019/10/12/Nginx的return模块/</id>
<published>2019-10-12T06:05:34.000Z</published>
<updated>2021-05-29T14:39:16.013Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-相关配置"><a href="#1-相关配置" class="headerlink" title="1 相关配置"></a>1 相关配置</h2><blockquote><p>return模块配置指令如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">return</span> value;</span><br></pre></td></tr></table></figure><p></p></blockquote><p>详细用法参考<a href="http://nginx.org/en/docs/stream/ngx_stream_return_module.html#return" target="_blank" rel="noopener">nginx官方文档</a></p><h2 id="2-源码解析"><a href="#2-源码解析" class="headerlink" title="2 源码解析"></a>2 源码解析</h2><h3 id="2-1-首先看看指令解析函数,这个函数的主要功能就是把return指令后面的文本以nginx变量的形式保存,绑定此阶段的处理函数。"><a href="#2-1-首先看看指令解析函数,这个函数的主要功能就是把return指令后面的文本以nginx变量的形式保存,绑定此阶段的处理函数。" class="headerlink" title="2.1 首先看看指令解析函数,这个函数的主要功能就是把return指令后面的文本以nginx变量的形式保存,绑定此阶段的处理函数。"></a>2.1 首先看看指令解析函数,这个函数的主要功能就是把return指令后面的文本以nginx变量的形式保存,绑定此阶段的处理函数。</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_stream_return(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_stream_return_srv_conf_t</span> *rscf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_stream_core_srv_conf_t</span> *cscf;</span><br><span class="line"> <span class="keyword">ngx_stream_compile_complex_value_t</span> ccv;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rscf->text.value.data) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">"is duplicate"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_stream_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[<span class="number">1</span>];</span><br><span class="line"> ccv.complex_value = &rscf->text;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module);</span><br><span class="line"></span><br><span class="line"> cscf->handler = ngx_stream_return_handler;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="2-2-在上一步设置好处理函数后,nginx运行到此阶段就会调用ngx-stream-return-handler函数,并给客户端响应"><a href="#2-2-在上一步设置好处理函数后,nginx运行到此阶段就会调用ngx-stream-return-handler函数,并给客户端响应" class="headerlink" title="2.2 在上一步设置好处理函数后,nginx运行到此阶段就会调用ngx_stream_return_handler函数,并给客户端响应"></a>2.2 在上一步设置好处理函数后,nginx运行到此阶段就会调用ngx_stream_return_handler函数,并给客户端响应</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">void</span></span><br><span class="line">ngx_stream_return_handler(<span class="keyword">ngx_stream_session_t</span> *s)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_str_t</span> text;</span><br><span class="line"> <span class="keyword">ngx_buf_t</span> *b;</span><br><span class="line"> <span class="keyword">ngx_connection_t</span> *c;</span><br><span class="line"> <span class="keyword">ngx_stream_return_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_stream_return_srv_conf_t</span> *rscf;</span><br><span class="line"></span><br><span class="line"> c = s->connection;</span><br><span class="line"></span><br><span class="line"> c-><span class="built_in">log</span>->action = <span class="string">"returning text"</span>;</span><br><span class="line"></span><br><span class="line"> rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 获取变量值</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {</span><br><span class="line"> ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"stream return text: \"%V\""</span>, &text);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (text.len == <span class="number">0</span>) {</span><br><span class="line"> ngx_stream_finalize_session(s, NGX_STREAM_OK);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 分配上下文内存</span></span><br><span class="line"> ctx = ngx_pcalloc(c->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_stream_return_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (ctx == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置模块上下文</span></span><br><span class="line"> ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);</span><br><span class="line"></span><br><span class="line"> b = ngx_calloc_buf(c->pool);</span><br><span class="line"> <span class="keyword">if</span> (b == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> b->memory = <span class="number">1</span>;</span><br><span class="line"> b->pos = text.data;</span><br><span class="line"> b->last = text.data + text.len;</span><br><span class="line"> b->last_buf = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> ctx->out = ngx_alloc_chain_link(c->pool);</span><br><span class="line"> <span class="keyword">if</span> (ctx->out == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 挂载输出buf</span></span><br><span class="line"> ctx->out->buf = b;</span><br><span class="line"> ctx->out->next = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置写回调函数</span></span><br><span class="line"> c->write->handler = ngx_stream_return_write_handler;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 调用写回调函数</span></span><br><span class="line"> ngx_stream_return_write_handler(c->write);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>ngx_stream_return_handler函数首先解析出return指令后面的字符串值,然后为当前模块的ngx_stream_return_ctx_t申请内存,主要用来挂载发送数据的chain,再为发送数据的chain以及buf申请内存,设置写事件的handler,最后发送响应到客户端。</p></blockquote><h2 id="3-总结"><a href="#3-总结" class="headerlink" title="3 总结"></a>3 总结</h2><blockquote><p>return模块属于stream模块,在stream模块中处于第4阶段,所以需要绑定handler函数,将return指令后的变量或者纯文本响应给客户端。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:02 GMT+0800 (GMT+08:00) --><h2 id="1-相关配置"><a href="#1-相关配置" class="headerlink" title="1 相关配置"></a>1 相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的geo模块</title>
<link href="https://weeweetan.github.io/2019/10/12/Nginx%E7%9A%84geo%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2019/10/12/Nginx的geo模块/</id>
<published>2019-10-12T01:26:55.000Z</published>
<updated>2019-12-20T12:45:20.028Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相关配置</h2><blockquote><p>geo模块配置指令如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">geo $remote_addr $var {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><p>详细用法参考<a href="http://nginx.org/en/docs/http/ngx_http_geo_module.html#geo" target="_blank" rel="noopener">nginx官方文档</a></p><h2 id="2、源码详解"><a href="#2、源码详解" class="headerlink" title="2、源码详解"></a>2、源码详解</h2><blockquote><p>2.1 首先来看看geo指令配置解析函数,这个函数的主要功能就是解析geo指令之后的变量,然后再调用ngx_http_geo解析{}中的内容</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geo_block(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *rv;</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, name;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_conf_t</span> save;</span><br><span class="line"> <span class="keyword">ngx_pool_t</span> *pool;</span><br><span class="line"> <span class="keyword">ngx_array_t</span> *a;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *var;</span><br><span class="line"> <span class="keyword">ngx_http_geo_ctx_t</span> *geo;</span><br><span class="line"> <span class="keyword">ngx_http_geo_conf_ctx_t</span> ctx;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">struct</span> <span class="title">in6_addr</span> <span class="title">zero</span>;</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> geo = ngx_palloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_geo_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (geo == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name = value[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name.data[<span class="number">0</span>] != <span class="string">'$'</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid variable name \"%V\""</span>, &name);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name.len--;</span><br><span class="line"> name.data++;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">3</span>) {</span><br><span class="line"></span><br><span class="line"> geo->index = ngx_http_get_variable_index(cf, &name);</span><br><span class="line"> <span class="keyword">if</span> (geo->index == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name = value[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name.data[<span class="number">0</span>] != <span class="string">'$'</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid variable name \"%V\""</span>, &name);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> name.len--;</span><br><span class="line"> name.data++;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> geo->index = <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);</span><br><span class="line"> <span class="keyword">if</span> (var == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf-><span class="built_in">log</span>);</span><br><span class="line"> <span class="keyword">if</span> (pool == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ctx, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_geo_conf_ctx_t</span>));</span><br><span class="line"></span><br><span class="line"> ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf-><span class="built_in">log</span>);</span><br><span class="line"> <span class="keyword">if</span> (ctx.temp_pool == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value);</span><br><span class="line"></span><br><span class="line"> ctx.pool = cf->pool;</span><br><span class="line"> ctx.data_size = <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_geo_header_t</span>)</span><br><span class="line"> + <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_value_t</span>)</span><br><span class="line"> + <span class="number">0x10000</span> * <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_geo_range_t</span> *);</span><br><span class="line"> ctx.allow_binary_include = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> save = *cf;</span><br><span class="line"> cf->pool = pool;</span><br><span class="line"> cf->ctx = &ctx;</span><br><span class="line"> cf->handler = ngx_http_geo;</span><br><span class="line"> cf->handler_conf = conf;</span><br><span class="line"></span><br><span class="line"> rv = ngx_conf_parse(cf, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> *cf = save;</span><br><span class="line"></span><br><span class="line"> geo->proxies = ctx.proxies;</span><br><span class="line"> geo->proxy_recursive = ctx.proxy_recursive;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.ranges) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.high.low && !ctx.binary_include) {</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < <span class="number">0x10000</span>; i++) {</span><br><span class="line"> a = (<span class="keyword">ngx_array_t</span> *) ctx.high.low[i];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (a == <span class="literal">NULL</span> || a->nelts == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> len = a->nelts * <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_geo_range_t</span>);</span><br><span class="line"></span><br><span class="line"> ctx.high.low[i] = ngx_palloc(cf->pool, len + <span class="keyword">sizeof</span>(<span class="keyword">void</span> *));</span><br><span class="line"> <span class="keyword">if</span> (ctx.high.low[i] == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memcpy(ctx.high.low[i], a->elts, len);</span><br><span class="line"> ctx.high.low[i][a->nelts].value = <span class="literal">NULL</span>;</span><br><span class="line"> ctx.data_size += len + <span class="keyword">sizeof</span>(<span class="keyword">void</span> *);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.allow_binary_include</span><br><span class="line"> && !ctx.outside_entries</span><br><span class="line"> && ctx.entries > <span class="number">100000</span></span><br><span class="line"> && ctx.includes == <span class="number">1</span>)</span><br><span class="line"> {</span><br><span class="line"> ngx_http_geo_create_binary_base(&ctx);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.high.default_value == <span class="literal">NULL</span>) {</span><br><span class="line"> ctx.high.default_value = &ngx_http_variable_null_value;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> geo->u.high = ctx.high;</span><br><span class="line"></span><br><span class="line"> var->get_handler = ngx_http_geo_range_variable;</span><br><span class="line"> var->data = (<span class="keyword">uintptr_t</span>) geo;</span><br><span class="line"></span><br><span class="line"> ngx_destroy_pool(ctx.temp_pool);</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (ctx.tree == <span class="literal">NULL</span>) {</span><br><span class="line"> ctx.tree = ngx_radix_tree_create(cf->pool, <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">if</span> (ctx.tree == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> geo->u.trees.tree = ctx.tree;</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> <span class="keyword">if</span> (ctx.tree6 == <span class="literal">NULL</span>) {</span><br><span class="line"> ctx.tree6 = ngx_radix_tree_create(cf->pool, <span class="number">-1</span>);</span><br><span class="line"> <span class="keyword">if</span> (ctx.tree6 == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> geo->u.trees.tree6 = ctx.tree6;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> var->get_handler = ngx_http_geo_cidr_variable;</span><br><span class="line"> var->data = (<span class="keyword">uintptr_t</span>) geo;</span><br><span class="line"></span><br><span class="line"> ngx_destroy_pool(ctx.temp_pool);</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_radix32tree_insert(ctx.tree, <span class="number">0</span>, <span class="number">0</span>,</span><br><span class="line"> (<span class="keyword">uintptr_t</span>) &ngx_http_variable_null_value)</span><br><span class="line"> == NGX_ERROR)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* NGX_BUSY is okay (default was set explicitly) */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_HAVE_INET6)</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr,</span><br><span class="line"> (<span class="keyword">uintptr_t</span>) &ngx_http_variable_null_value)</span><br><span class="line"> == NGX_ERROR)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>2.2 ngx_http_geo解析{}中的内容,处理ranges等指令和IP地址段或者CIDR地址</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_geo(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *dummy, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">char</span> *rv;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_cidr_t</span> cidr;</span><br><span class="line"> <span class="keyword">ngx_http_geo_conf_ctx_t</span> *ctx;</span><br><span class="line"></span><br><span class="line"> ctx = cf->ctx;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">1</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"ranges"</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx->tree</span><br><span class="line">#<span class="keyword">if</span> (NGX_HAVE_INET6)</span><br><span class="line"> || ctx->tree6</span><br><span class="line">#endif</span><br><span class="line"> )</span><br><span class="line"> {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the \"ranges\" directive must be "</span></span><br><span class="line"> <span class="string">"the first directive inside \"geo\" block"</span>);</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->ranges = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> rv = NGX_CONF_OK;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"proxy_recursive"</span>) == <span class="number">0</span>) {</span><br><span class="line"> ctx->proxy_recursive = <span class="number">1</span>;</span><br><span class="line"> rv = NGX_CONF_OK;</span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts != <span class="number">2</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid number of the geo parameters"</span>);</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"include"</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> rv = ngx_http_geo_include(cf, ctx, &value[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"proxy"</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_geo_cidr_value(cf, &value[<span class="number">1</span>], &cidr) != NGX_OK) {</span><br><span class="line"> <span class="keyword">goto</span> failed;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rv = ngx_http_geo_add_proxy(cf, ctx, &cidr);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> done;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx->ranges) {</span><br><span class="line"> rv = ngx_http_geo_range(cf, ctx, value);</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> rv = ngx_http_geo_cidr(cf, ctx, value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">done:</span><br><span class="line"></span><br><span class="line"> ngx_reset_pool(cf->pool);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line"></span><br><span class="line">failed:</span><br><span class="line"></span><br><span class="line"> ngx_reset_pool(cf->pool);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>2.3 处理range地址,调用ngx_http_geo_range函数实现,接下来看看这个函数的实现</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static char *</span><br><span class="line">ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,</span><br><span class="line"> ngx_str_t *value)</span><br><span class="line">{</span><br><span class="line"> u_char *p, *last;</span><br><span class="line"> in_addr_t start, end;</span><br><span class="line"> ngx_str_t *net;</span><br><span class="line"> ngx_uint_t del;</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[0].data, "default") == 0) {</span><br><span class="line"></span><br><span class="line"> if (ctx->high.default_value) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, 0,</span><br><span class="line"> "duplicate default geo range value: \"%V\", old value: \"%v\"",</span><br><span class="line"> &value[1], ctx->high.default_value);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->high.default_value = ngx_http_geo_value(cf, ctx, &value[1]);</span><br><span class="line"> if (ctx->high.default_value == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ctx->binary_include) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</span><br><span class="line"> "binary geo range base \"%s\" cannot be mixed with usual entries",</span><br><span class="line"> ctx->include_name.data);</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ctx->high.low == NULL) {</span><br><span class="line"> ctx->high.low = ngx_pcalloc(ctx->pool,</span><br><span class="line"> 0x10000 * sizeof(ngx_http_geo_range_t *));</span><br><span class="line"> if (ctx->high.low == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->entries++;</span><br><span class="line"> ctx->outside_entries = 1;</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[0].data, "delete") == 0) {</span><br><span class="line"> net = &value[1];</span><br><span class="line"> del = 1;</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> net = &value[0];</span><br><span class="line"> del = 0;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> last = net->data + net->len;</span><br><span class="line"></span><br><span class="line"> p = ngx_strlchr(net->data, last, '-');</span><br><span class="line"></span><br><span class="line"> if (p == NULL) {</span><br><span class="line"> goto invalid;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> start = ngx_inet_addr(net->data, p - net->data);</span><br><span class="line"></span><br><span class="line"> if (start == INADDR_NONE) {</span><br><span class="line"> goto invalid;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> start = ntohl(start);</span><br><span class="line"></span><br><span class="line"> p++;</span><br><span class="line"></span><br><span class="line"> end = ngx_inet_addr(p, last - p);</span><br><span class="line"></span><br><span class="line"> if (end == INADDR_NONE) {</span><br><span class="line"> goto invalid;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> end = ntohl(end);</span><br><span class="line"></span><br><span class="line"> if (start > end) {</span><br><span class="line"> goto invalid;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (del) {</span><br><span class="line"> if (ngx_http_geo_delete_range(cf, ctx, start, end)) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, 0,</span><br><span class="line"> "no address range \"%V\" to delete", net);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->value = ngx_http_geo_value(cf, ctx, &value[1]);</span><br><span class="line"></span><br><span class="line"> if (ctx->value == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->net = net;</span><br><span class="line"></span><br><span class="line"> return ngx_http_geo_add_range(cf, ctx, start, end);</span><br><span class="line"></span><br><span class="line">invalid:</span><br><span class="line"></span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid range \"%V\"", net);</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>2.4 处理CIDR地址,调用ngx_http_geo_cidr函数实现,接下来看看这个函数的实现</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static char *</span><br><span class="line">ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,</span><br><span class="line"> ngx_str_t *value)</span><br><span class="line">{</span><br><span class="line"> char *rv;</span><br><span class="line"> ngx_int_t rc, del;</span><br><span class="line"> ngx_str_t *net;</span><br><span class="line"> ngx_cidr_t cidr;</span><br><span class="line"></span><br><span class="line"> if (ctx->tree == NULL) {</span><br><span class="line"> ctx->tree = ngx_radix_tree_create(ctx->pool, -1);</span><br><span class="line"> if (ctx->tree == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">#if (NGX_HAVE_INET6)</span><br><span class="line"> if (ctx->tree6 == NULL) {</span><br><span class="line"> ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1);</span><br><span class="line"> if (ctx->tree6 == NULL) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[0].data, "default") == 0) {</span><br><span class="line"> cidr.family = AF_INET;</span><br><span class="line"> cidr.u.in.addr = 0;</span><br><span class="line"> cidr.u.in.mask = 0;</span><br><span class="line"></span><br><span class="line"> rv = ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]);</span><br><span class="line"></span><br><span class="line"> if (rv != NGX_CONF_OK) {</span><br><span class="line"> return rv;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">#if (NGX_HAVE_INET6)</span><br><span class="line"> cidr.family = AF_INET6;</span><br><span class="line"> ngx_memzero(&cidr.u.in6, sizeof(ngx_in6_cidr_t));</span><br><span class="line"></span><br><span class="line"> rv = ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]);</span><br><span class="line"></span><br><span class="line"> if (rv != NGX_CONF_OK) {</span><br><span class="line"> return rv;</span><br><span class="line"> }</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_strcmp(value[0].data, "delete") == 0) {</span><br><span class="line"> net = &value[1];</span><br><span class="line"> del = 1;</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> net = &value[0];</span><br><span class="line"> del = 0;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) {</span><br><span class="line"> return NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (cidr.family == AF_INET) {</span><br><span class="line"> cidr.u.in.addr = ntohl(cidr.u.in.addr);</span><br><span class="line"> cidr.u.in.mask = ntohl(cidr.u.in.mask);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (del) {</span><br><span class="line"> switch (cidr.family) {</span><br><span class="line"></span><br><span class="line">#if (NGX_HAVE_INET6)</span><br><span class="line"> case AF_INET6:</span><br><span class="line"> rc = ngx_radix128tree_delete(ctx->tree6,</span><br><span class="line"> cidr.u.in6.addr.s6_addr,</span><br><span class="line"> cidr.u.in6.mask.s6_addr);</span><br><span class="line"> break;</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> default: /* AF_INET */</span><br><span class="line"> rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,</span><br><span class="line"> cidr.u.in.mask);</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (rc != NGX_OK) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_WARN, cf, 0,</span><br><span class="line"> "no network \"%V\" to delete", net);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], net);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>2.5 获取解析好的变量值,调用ngx_http_geo_range_variable函数实现,接下来看看这个函数的实现</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">static ngx_int_t</span><br><span class="line">ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,</span><br><span class="line"> uintptr_t data)</span><br><span class="line">{</span><br><span class="line"> ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;</span><br><span class="line"></span><br><span class="line"> in_addr_t inaddr;</span><br><span class="line"> ngx_addr_t addr;</span><br><span class="line"> ngx_uint_t n;</span><br><span class="line"> struct sockaddr_in *sin;</span><br><span class="line"> ngx_http_geo_range_t *range;</span><br><span class="line">#if (NGX_HAVE_INET6)</span><br><span class="line"> u_char *p;</span><br><span class="line"> struct in6_addr *inaddr6;</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> *v = *ctx->u.high.default_value;</span><br><span class="line"></span><br><span class="line"> if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) {</span><br><span class="line"></span><br><span class="line"> switch (addr.sockaddr->sa_family) {</span><br><span class="line"></span><br><span class="line">#if (NGX_HAVE_INET6)</span><br><span class="line"> case AF_INET6:</span><br><span class="line"> inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;</span><br><span class="line"></span><br><span class="line"> if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {</span><br><span class="line"> p = inaddr6->s6_addr;</span><br><span class="line"></span><br><span class="line"> inaddr = p[12] << 24;</span><br><span class="line"> inaddr += p[13] << 16;</span><br><span class="line"> inaddr += p[14] << 8;</span><br><span class="line"> inaddr += p[15];</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> inaddr = INADDR_NONE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> break;</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line">#if (NGX_HAVE_UNIX_DOMAIN)</span><br><span class="line"> case AF_UNIX:</span><br><span class="line"> inaddr = INADDR_NONE;</span><br><span class="line"> break;</span><br><span class="line">#endif</span><br><span class="line"></span><br><span class="line"> default: /* AF_INET */</span><br><span class="line"> sin = (struct sockaddr_in *) addr.sockaddr;</span><br><span class="line"> inaddr = ntohl(sin->sin_addr.s_addr);</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } else {</span><br><span class="line"> inaddr = INADDR_NONE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (ctx->u.high.low) {</span><br><span class="line"> range = ctx->u.high.low[inaddr >> 16];</span><br><span class="line"></span><br><span class="line"> if (range) {</span><br><span class="line"> n = inaddr & 0xffff;</span><br><span class="line"> do {</span><br><span class="line"> if (n >= (ngx_uint_t) range->start</span><br><span class="line"> && n <= (ngx_uint_t) range->end)</span><br><span class="line"> {</span><br><span class="line"> *v = *range->value;</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> } while ((++range)->value);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</span><br><span class="line"> "http geo: %v", v);</span><br><span class="line"></span><br><span class="line"> return NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="3、总结"><a href="#3、总结" class="headerlink" title="3、总结"></a>3、总结</h2><blockquote><p>以上就是整个geo模块的核心,stream下的geo模块实现方式类似。s</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx的map模块</title>
<link href="https://weeweetan.github.io/2019/10/12/Nginx%E7%9A%84map%E6%A8%A1%E5%9D%97/"/>
<id>https://weeweetan.github.io/2019/10/12/Nginx的map模块/</id>
<published>2019-10-12T01:25:27.000Z</published>
<updated>2021-05-24T13:50:05.498Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相关配置</h2><blockquote><p>geo模块配置指令如下:<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="built_in">map</span> $var1 $var2 {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><p>详细用法参考<a href="http://nginx.org/en/docs/http/ngx_http_map_module.html#map" target="_blank" rel="noopener">nginx官方文档</a>,此模块的功能是将$var1通过{}中的匹配条件生成$var2的值,支持正则表达式。</p><h2 id="2、代码详解"><a href="#2、代码详解" class="headerlink" title="2、代码详解"></a>2、代码详解</h2><h3 id="2-1、首先来看看配置解析函数,负责解析map指令后的两个变量,并设置获取变量值的函数指针"><a href="#2-1、首先来看看配置解析函数,负责解析map指令后的两个变量,并设置获取变量值的函数指针" class="headerlink" title="2.1、首先来看看配置解析函数,负责解析map指令后的两个变量,并设置获取变量值的函数指针"></a>2.1、首先来看看配置解析函数,负责解析map指令后的两个变量,并设置获取变量值的函数指针</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_map_block(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_map_conf_t</span> *mcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">char</span> *rv;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, name;</span><br><span class="line"> <span class="keyword">ngx_conf_t</span> save;</span><br><span class="line"> <span class="keyword">ngx_pool_t</span> *pool;</span><br><span class="line"> <span class="keyword">ngx_hash_init_t</span> hash;</span><br><span class="line"> <span class="keyword">ngx_http_map_ctx_t</span> *<span class="built_in">map</span>;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *var;</span><br><span class="line"> <span class="keyword">ngx_http_map_conf_ctx_t</span> ctx;</span><br><span class="line"> <span class="keyword">ngx_http_compile_complex_value_t</span> ccv;</span><br><span class="line"> <span class="comment">//设置hash桶最大值</span></span><br><span class="line"> <span class="keyword">if</span> (mcf->hash_max_size == NGX_CONF_UNSET_UINT) {</span><br><span class="line"> mcf->hash_max_size = <span class="number">2048</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (mcf->hash_bucket_size == NGX_CONF_UNSET_UINT) {</span><br><span class="line"> mcf->hash_bucket_size = ngx_cacheline_size;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> mcf->hash_bucket_size = ngx_align(mcf->hash_bucket_size,</span><br><span class="line"> ngx_cacheline_size);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span> = ngx_pcalloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_map_ctx_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">map</span> == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = cf;</span><br><span class="line"> ccv.value = &value[<span class="number">1</span>];</span><br><span class="line"> ccv.complex_value = &<span class="built_in">map</span>->value;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//解析第二个变量</span></span><br><span class="line"> name = value[<span class="number">2</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name.data[<span class="number">0</span>] != <span class="string">'$'</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid variable name \"%V\""</span>, &name);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//保存$符号后面的字符串</span></span><br><span class="line"> name.len--;</span><br><span class="line"> name.data++;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 把变量名添加到全局变量中</span></span><br><span class="line"> var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);</span><br><span class="line"> <span class="keyword">if</span> (var == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//设置获取此变量值的handler</span></span><br><span class="line"> var->get_handler = ngx_http_map_variable;</span><br><span class="line"> var->data = (<span class="keyword">uintptr_t</span>) <span class="built_in">map</span>;</span><br><span class="line"></span><br><span class="line"> pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf-><span class="built_in">log</span>);</span><br><span class="line"> <span class="keyword">if</span> (pool == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx.keys.pool = cf->pool;</span><br><span class="line"> ctx.keys.temp_pool = pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_keys_array_init(&ctx.keys, NGX_HASH_LARGE) != NGX_OK) {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx.values_hash = ngx_pcalloc(pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_array_t</span>) * ctx.keys.hsize);</span><br><span class="line"> <span class="keyword">if</span> (ctx.values_hash == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 初始化正则表达式</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_array_init(&ctx.regexes, cf->pool, <span class="number">2</span>, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_map_regex_t</span>))</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> ctx.default_value = <span class="literal">NULL</span>;</span><br><span class="line"> ctx.cf = &save;</span><br><span class="line"> ctx.hostnames = <span class="number">0</span>;</span><br><span class="line"> ctx.no_cacheable = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> save = *cf;</span><br><span class="line"> cf->pool = pool;</span><br><span class="line"> cf->ctx = &ctx;</span><br><span class="line"> cf->handler = ngx_http_map;</span><br><span class="line"> cf->handler_conf = conf;</span><br><span class="line"></span><br><span class="line"> rv = ngx_conf_parse(cf, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> *cf = save;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rv != NGX_CONF_OK) {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.no_cacheable) {</span><br><span class="line"> var->flags |= NGX_HTTP_VAR_NOCACHEABLE;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span>->default_value = ctx.default_value ? ctx.default_value:</span><br><span class="line"> &ngx_http_variable_null_value;</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span>->hostnames = ctx.hostnames;</span><br><span class="line"></span><br><span class="line"> hash.key = ngx_hash_key_lc;</span><br><span class="line"> hash.max_size = mcf->hash_max_size;</span><br><span class="line"> hash.bucket_size = mcf->hash_bucket_size;</span><br><span class="line"> hash.name = <span class="string">"map_hash"</span>;</span><br><span class="line"> hash.pool = cf->pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.keys.keys.nelts) {</span><br><span class="line"> hash.hash = &<span class="built_in">map</span>-><span class="built_in">map</span>.hash.hash;</span><br><span class="line"> hash.temp_pool = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.keys.dns_wc_head.nelts) {</span><br><span class="line"></span><br><span class="line"> ngx_qsort(ctx.keys.dns_wc_head.elts,</span><br><span class="line"> (<span class="keyword">size_t</span>) ctx.keys.dns_wc_head.nelts,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_hash_key_t</span>), ngx_http_map_cmp_dns_wildcards);</span><br><span class="line"></span><br><span class="line"> hash.hash = <span class="literal">NULL</span>;</span><br><span class="line"> hash.temp_pool = pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts,</span><br><span class="line"> ctx.keys.dns_wc_head.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span>-><span class="built_in">map</span>.hash.wc_head = (<span class="keyword">ngx_hash_wildcard_t</span> *) hash.hash;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.keys.dns_wc_tail.nelts) {</span><br><span class="line"></span><br><span class="line"> ngx_qsort(ctx.keys.dns_wc_tail.elts,</span><br><span class="line"> (<span class="keyword">size_t</span>) ctx.keys.dns_wc_tail.nelts,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_hash_key_t</span>), ngx_http_map_cmp_dns_wildcards);</span><br><span class="line"></span><br><span class="line"> hash.hash = <span class="literal">NULL</span>;</span><br><span class="line"> hash.temp_pool = pool;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts,</span><br><span class="line"> ctx.keys.dns_wc_tail.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">map</span>-><span class="built_in">map</span>.hash.wc_tail = (<span class="keyword">ngx_hash_wildcard_t</span> *) hash.hash;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx.regexes.nelts) {</span><br><span class="line"> <span class="built_in">map</span>-><span class="built_in">map</span>.regex = ctx.regexes.elts;</span><br><span class="line"> <span class="built_in">map</span>-><span class="built_in">map</span>.nregex = ctx.regexes.nelts;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> ngx_destroy_pool(pool);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> rv;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-2、解析map块中的内容"><a href="#2-2、解析map块中的内容" class="headerlink" title="2.2、解析map块中的内容"></a>2.2、解析map块中的内容</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_map(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *dummy, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> u_char *data;</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> <span class="keyword">ngx_int_t</span> rv;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value, v;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, key;</span><br><span class="line"> <span class="keyword">ngx_http_map_conf_ctx_t</span> *ctx;</span><br><span class="line"> <span class="keyword">ngx_http_complex_value_t</span> cv, *cvp;</span><br><span class="line"> <span class="keyword">ngx_http_variable_value_t</span> *var, **vp;</span><br><span class="line"> <span class="keyword">ngx_http_compile_complex_value_t</span> ccv;</span><br><span class="line"></span><br><span class="line"> ctx = cf->ctx;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">1</span></span><br><span class="line"> && ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"hostnames"</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> ctx->hostnames = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts == <span class="number">1</span></span><br><span class="line"> && ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"volatile"</span>) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> ctx->no_cacheable = <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cf->args->nelts != <span class="number">2</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid number of the map parameters"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"include"</span>) == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> ngx_conf_include(cf, dummy, conf);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> key = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < value[<span class="number">1</span>].len; i++) {</span><br><span class="line"> key = ngx_hash(key, value[<span class="number">1</span>].data[i]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> key %= ctx->keys.hsize;</span><br><span class="line"></span><br><span class="line"> vp = ctx->values_hash[key].elts;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (vp) {</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < ctx->values_hash[key].nelts; i++) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (vp[i]->valid) {</span><br><span class="line"> data = vp[i]->data;</span><br><span class="line"> len = vp[i]->len;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> cvp = (<span class="keyword">ngx_http_complex_value_t</span> *) vp[i]->data;</span><br><span class="line"> data = cvp->value.data;</span><br><span class="line"> len = cvp->value.len;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value[<span class="number">1</span>].len != len) {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strncmp(value[<span class="number">1</span>].data, data, len) == <span class="number">0</span>) {</span><br><span class="line"> var = vp[i];</span><br><span class="line"> <span class="keyword">goto</span> found;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (ngx_array_init(&ctx->values_hash[key], cf->pool, <span class="number">4</span>,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_value_t</span> *))</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> var = ngx_palloc(ctx->keys.pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_value_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (var == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> v.len = value[<span class="number">1</span>].len;</span><br><span class="line"> v.data = ngx_pstrdup(ctx->keys.pool, &value[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (v.data == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&ccv, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_compile_complex_value_t</span>));</span><br><span class="line"></span><br><span class="line"> ccv.cf = ctx->cf;</span><br><span class="line"> ccv.value = &v;</span><br><span class="line"> ccv.complex_value = &cv;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_compile_complex_value(&ccv) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cv.lengths != <span class="literal">NULL</span>) {</span><br><span class="line"> cvp = ngx_palloc(ctx->keys.pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_complex_value_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (cvp == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *cvp = cv;</span><br><span class="line"></span><br><span class="line"> var->len = <span class="number">0</span>;</span><br><span class="line"> var->data = (u_char *) cvp;</span><br><span class="line"> var->valid = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> var->len = v.len;</span><br><span class="line"> var->data = v.data;</span><br><span class="line"> var->valid = <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> var->no_cacheable = <span class="number">0</span>;</span><br><span class="line"> var->not_found = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> vp = ngx_array_push(&ctx->values_hash[key]);</span><br><span class="line"> <span class="keyword">if</span> (vp == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> *vp = var;</span><br><span class="line"></span><br><span class="line">found:</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_strcmp(value[<span class="number">0</span>].data, <span class="string">"default"</span>) == <span class="number">0</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ctx->default_value) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"duplicate default map parameter"</span>);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx->default_value = var;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> (NGX_PCRE)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value[<span class="number">0</span>].len && value[<span class="number">0</span>].data[<span class="number">0</span>] == <span class="string">'~'</span>) {</span><br><span class="line"> <span class="keyword">ngx_regex_compile_t</span> rc;</span><br><span class="line"> <span class="keyword">ngx_http_map_regex_t</span> *regex;</span><br><span class="line"> u_char errstr[NGX_MAX_CONF_ERRSTR];</span><br><span class="line"></span><br><span class="line"> regex = ngx_array_push(&ctx->regexes);</span><br><span class="line"> <span class="keyword">if</span> (regex == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value[<span class="number">0</span>].len--;</span><br><span class="line"> value[<span class="number">0</span>].data++;</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&rc, <span class="keyword">sizeof</span>(<span class="keyword">ngx_regex_compile_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value[<span class="number">0</span>].data[<span class="number">0</span>] == <span class="string">'*'</span>) {</span><br><span class="line"> value[<span class="number">0</span>].len--;</span><br><span class="line"> value[<span class="number">0</span>].data++;</span><br><span class="line"> rc.options = NGX_REGEX_CASELESS;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rc.pattern = value[<span class="number">0</span>];</span><br><span class="line"> rc.err.len = NGX_MAX_CONF_ERRSTR;</span><br><span class="line"> rc.err.data = errstr;</span><br><span class="line"></span><br><span class="line"> regex->regex = ngx_http_regex_compile(ctx->cf, &rc);</span><br><span class="line"> <span class="keyword">if</span> (regex->regex == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> regex->value = var;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (value[<span class="number">0</span>].len && value[<span class="number">0</span>].data[<span class="number">0</span>] == <span class="string">'\\'</span>) {</span><br><span class="line"> value[<span class="number">0</span>].len--;</span><br><span class="line"> value[<span class="number">0</span>].data++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> rv = ngx_hash_add_key(&ctx->keys, &value[<span class="number">0</span>], var,</span><br><span class="line"> (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rv == NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rv == NGX_DECLINED) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid hostname or wildcard \"%V\""</span>, &value[<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rv == NGX_BUSY) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"conflicting parameter \"%V\""</span>, &value[<span class="number">0</span>]);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line">}s</span><br></pre></td></tr></table></figure><h2 id="3、总结"><a href="#3、总结" class="headerlink" title="3、总结"></a>3、总结</h2><blockquote><p>map模块生成的变量遵循nginx的变量规则,获取变量值的方式也与nginx其他变量类似</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、相关配置"><a href="#1、相关配置" class="headerlink" title="1、相关配置"></a>1、相
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
<entry>
<title>Nginx变量详解</title>
<link href="https://weeweetan.github.io/2019/10/12/Nginx%E5%8F%98%E9%87%8F%E8%AF%A6%E8%A7%A3/"/>
<id>https://weeweetan.github.io/2019/10/12/Nginx变量详解/</id>
<published>2019-10-12T01:19:08.000Z</published>
<updated>2022-09-13T13:50:23.274Z</updated>
<content type="html"><![CDATA[<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、源码解析"><a href="#1、源码解析" class="headerlink" title="1、源码解析"></a>1、源码解析</h2><h3 id="1-1-变量分类"><a href="#1-1-变量分类" class="headerlink" title="1.1 变量分类"></a>1.1 变量分类</h3><blockquote><p>nginx变量分为两种,一种是nginx内置变量,可以通过<a href="http://nginx.org/en/docs/varindex.html" target="_blank" rel="noopener">官方网站</a>查询到的含义,另外一种则是在nginx配置文件中通过set指令设置的变量,首先来看一下nginx的内置变量实现方式。</p></blockquote><h4 id="1-1-1-nginx内置变量"><a href="#1-1-1-nginx内置变量" class="headerlink" title="1.1.1 nginx内置变量"></a>1.1.1 nginx内置变量</h4><blockquote><p>首先看看定义内置变量的结构体<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ngx_http_variable_s</span> {</span></span><br><span class="line"> <span class="keyword">ngx_str_t</span> name; <span class="comment">/* must be first to build the hash */</span></span><br><span class="line"> ngx_http_set_variable_pt set_handler;</span><br><span class="line"> ngx_http_get_variable_pt get_handler;</span><br><span class="line"> <span class="keyword">uintptr_t</span> data;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> flags;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> index;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><br>上面这个结构体中,name代表变量名称,比如$request_uri,$args等,set_handler暂时没有使用到,get_handler获取变量值,data一般表示为变量值来自于这里,flags表示此变量遵循的一些规则,比如NGX_HTTP_VAR_CHANGEABLE,index表示此变量在整个nginx变量系统中的索引。<p></p></blockquote><blockquote><p>接下来就是将变量添加到nginx的变量系统中了,这里以http模块的核心变量为例进行说明。<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ngx_http_variable_t</span> *</span><br><span class="line">ngx_http_add_variable(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_str_t</span> *name, <span class="keyword">ngx_uint_t</span> flags)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_int_t</span> rc;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i;</span><br><span class="line"> <span class="keyword">ngx_hash_key_t</span> *key;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *v;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (name->len == <span class="number">0</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid variable name \"$\""</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 前缀变量,例如http_,arg_ 等</span></span><br><span class="line"> <span class="keyword">if</span> (flags & NGX_HTTP_VAR_PREFIX) {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_add_prefix_variable(cf, name, flags);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);</span><br><span class="line"></span><br><span class="line"> key = cmcf->variables_keys->keys.elts;</span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < cmcf->variables_keys->keys.nelts; i++) {</span><br><span class="line"> <span class="keyword">if</span> (name->len != key[i].key.len</span><br><span class="line"> || ngx_strncasecmp(name->data, key[i].key.data, name->len) != <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> v = key[i].value;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"the duplicate \"%V\" variable"</span>, name);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!(flags & NGX_HTTP_VAR_WEAK)) {</span><br><span class="line"> v->flags &= ~NGX_HTTP_VAR_WEAK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> v;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> v = ngx_palloc(cf->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (v == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> v->name.len = name->len;</span><br><span class="line"> v->name.data = ngx_pnalloc(cf->pool, name->len);</span><br><span class="line"> <span class="keyword">if</span> (v->name.data == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_strlow(v->name.data, name->data, name->len);</span><br><span class="line"></span><br><span class="line"> v->set_handler = <span class="literal">NULL</span>;</span><br><span class="line"> v->get_handler = <span class="literal">NULL</span>;</span><br><span class="line"> v->data = <span class="number">0</span>;</span><br><span class="line"> v->flags = flags;</span><br><span class="line"> v->index = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rc == NGX_BUSY) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"conflicting variable name \"%V\""</span>, name);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> v;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>这个函数的作用就是将定义的变量添加到http核心配置中,为获取变量的值做好准备,其他变量类似。接下来就是如何获取变量值了,http的日志模块提供了一个很好的范本。<br>接下来看看ngx_http_variables_init_vars函数的实现,这个函数的主要功能是设置变量的get_handler,从各个模块初始化的变量key中寻找<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ngx_int_t</span></span><br><span class="line">ngx_http_variables_init_vars(<span class="keyword">ngx_conf_t</span> *cf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n;</span><br><span class="line"> <span class="keyword">ngx_hash_key_t</span> *key;</span><br><span class="line"> <span class="keyword">ngx_hash_init_t</span> hash;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *v, *av, *pv;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* set the handlers for the indexed http variables */</span></span><br><span class="line"></span><br><span class="line"> cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);</span><br><span class="line"></span><br><span class="line"> v = cmcf->variables.elts;</span><br><span class="line"> pv = cmcf->prefix_variables.elts;</span><br><span class="line"> key = cmcf->variables_keys->keys.elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// cmcf->variable变量是配置文件中使用的变量</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < cmcf->variables.nelts; i++) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 这个key是所有模块定义的变量key</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < cmcf->variables_keys->keys.nelts; n++) {</span><br><span class="line"></span><br><span class="line"> av = key[n].value;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (v[i].name.len == key[n].key.len</span><br><span class="line"> && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)</span><br><span class="line"> == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// 设置get_handler</span></span><br><span class="line"> v[i].get_handler = av->get_handler;</span><br><span class="line"> v[i].data = av->data;</span><br><span class="line"></span><br><span class="line"> av->flags |= NGX_HTTP_VAR_INDEXED;</span><br><span class="line"> v[i].flags = av->flags;</span><br><span class="line"></span><br><span class="line"> av->index = i;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (av->get_handler == <span class="literal">NULL</span></span><br><span class="line"> || (av->flags & NGX_HTTP_VAR_WEAK))</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> next;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> len = <span class="number">0</span>;</span><br><span class="line"> av = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 设置前缀变量get_handler</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < cmcf->prefix_variables.nelts; n++) {</span><br><span class="line"> <span class="keyword">if</span> (v[i].name.len >= pv[n].name.len && v[i].name.len > len</span><br><span class="line"> && ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)</span><br><span class="line"> == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> av = &pv[n];</span><br><span class="line"> len = pv[n].name.len;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (av) {</span><br><span class="line"> v[i].get_handler = av->get_handler;</span><br><span class="line"> v[i].data = (<span class="keyword">uintptr_t</span>) &v[i].name;</span><br><span class="line"> v[i].flags = av->flags;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">goto</span> next;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果变量get_handler为NULL,报错</span></span><br><span class="line"> <span class="keyword">if</span> (v[i].get_handler == <span class="literal">NULL</span>) {</span><br><span class="line"> ngx_log_error(NGX_LOG_EMERG, cf-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"unknown \"%V\" variable"</span>, &v[i].name);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> next:</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果带有nohash的标识,则将key.data置为NULL,在ngx_hash_init就不会将该key放在hash桶里面,比如proxy模块的几个变量</span></span><br><span class="line"> <span class="keyword">for</span> (n = <span class="number">0</span>; n < cmcf->variables_keys->keys.nelts; n++) {</span><br><span class="line"> av = key[n].value;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (av->flags & NGX_HTTP_VAR_NOHASH) {</span><br><span class="line"> key[n].key.data = <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> hash.hash = &cmcf->variables_hash;</span><br><span class="line"> hash.key = ngx_hash_key;</span><br><span class="line"> hash.max_size = cmcf->variables_hash_max_size;</span><br><span class="line"> hash.bucket_size = cmcf->variables_hash_bucket_size;</span><br><span class="line"> hash.name = <span class="string">"variables_hash"</span>;</span><br><span class="line"> hash.pool = cf->pool;</span><br><span class="line"> hash.temp_pool = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 开始初始化变量hash表</span></span><br><span class="line"> <span class="keyword">if</span> (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,</span><br><span class="line"> cmcf->variables_keys->keys.nelts)</span><br><span class="line"> != NGX_OK)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">return</span> NGX_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cmcf->variables_keys = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br>http模块如何获取变量,接下来看看ngx_http_get_variable函数实现<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ngx_http_variable_value_t</span> *</span><br><span class="line">ngx_http_get_variable(<span class="keyword">ngx_http_request_t</span> *r, <span class="keyword">ngx_str_t</span> *name, <span class="keyword">ngx_uint_t</span> key)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">size_t</span> len;</span><br><span class="line"> <span class="keyword">ngx_uint_t</span> i, n;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *v;</span><br><span class="line"> <span class="keyword">ngx_http_variable_value_t</span> *vv;</span><br><span class="line"> <span class="keyword">ngx_http_core_main_conf_t</span> *cmcf;</span><br><span class="line"></span><br><span class="line"> cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);</span><br><span class="line"> <span class="comment">// 从全局变量hash表中根据key找到对应变量</span></span><br><span class="line"> v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (v) {</span><br><span class="line"> <span class="keyword">if</span> (v->flags & NGX_HTTP_VAR_INDEXED) {</span><br><span class="line"> <span class="keyword">return</span> ngx_http_get_flushed_variable(r, v->index);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_variable_depth == <span class="number">0</span>) {</span><br><span class="line"> ngx_log_error(NGX_LOG_ERR, r->connection-><span class="built_in">log</span>, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"cycle while evaluating variable \"%V\""</span>, name);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_http_variable_depth--;</span><br><span class="line"></span><br><span class="line"> vv = ngx_palloc(r->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_value_t</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (vv && v->get_handler(r, vv, v->data) == NGX_OK) {</span><br><span class="line"> ngx_http_variable_depth++;</span><br><span class="line"> <span class="keyword">return</span> vv;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ngx_http_variable_depth++;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> vv = ngx_palloc(r->pool, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_variable_value_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (vv == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> len = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"> v = cmcf->prefix_variables.elts;</span><br><span class="line"> n = cmcf->prefix_variables.nelts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从前缀变量中查找</span></span><br><span class="line"> <span class="keyword">for</span> (i = <span class="number">0</span>; i < cmcf->prefix_variables.nelts; i++) {</span><br><span class="line"> <span class="keyword">if</span> (name->len >= v[i].name.len && name->len > len</span><br><span class="line"> && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == <span class="number">0</span>)</span><br><span class="line"> {</span><br><span class="line"> len = v[i].name.len;</span><br><span class="line"> n = i;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 从前缀变量中找到该变量</span></span><br><span class="line"> <span class="keyword">if</span> (n != cmcf->prefix_variables.nelts) {</span><br><span class="line"> <span class="keyword">if</span> (v[n].get_handler(r, vv, (<span class="keyword">uintptr_t</span>) name) == NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> vv;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> vv->not_found = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> vv;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><h3 id="1-1-2-配置文件变量"><a href="#1-1-2-配置文件变量" class="headerlink" title="1.1.2 配置文件变量"></a>1.1.2 配置文件变量</h3><blockquote><p>配置文件变量是指set指令设置的变量,<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">set</span> $a value;</span><br></pre></td></tr></table></figure><p></p></blockquote><p>具体可以参考<a href="http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#set" target="_blank" rel="noopener">set</a>,</p><blockquote><p>首先来看看set指令解析函数<br></p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_rewrite_set(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_command_t</span> *cmd, <span class="keyword">void</span> *conf)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_http_rewrite_loc_conf_t</span> *lcf = conf;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">ngx_int_t</span> index;</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value;</span><br><span class="line"> <span class="keyword">ngx_http_variable_t</span> *v;</span><br><span class="line"> <span class="keyword">ngx_http_script_var_code_t</span> *vcode;</span><br><span class="line"> <span class="keyword">ngx_http_script_var_handler_code_t</span> *vhcode;</span><br><span class="line"></span><br><span class="line"> value = cf->args->elts;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 如果没有带$符号,则返回错误</span></span><br><span class="line"> <span class="keyword">if</span> (value[<span class="number">1</span>].data[<span class="number">0</span>] != <span class="string">'$'</span>) {</span><br><span class="line"> ngx_conf_log_error(NGX_LOG_EMERG, cf, <span class="number">0</span>,</span><br><span class="line"> <span class="string">"invalid variable name \"%V\""</span>, &value[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> value[<span class="number">1</span>].len--;</span><br><span class="line"> value[<span class="number">1</span>].data++;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 将变量添加到全局变量中</span></span><br><span class="line"> v = ngx_http_add_variable(cf, &value[<span class="number">1</span>],</span><br><span class="line"> NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_WEAK);</span><br><span class="line"> <span class="keyword">if</span> (v == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 获取变量索引</span></span><br><span class="line"> index = ngx_http_get_variable_index(cf, &value[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (index == NGX_ERROR) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (v->get_handler == <span class="literal">NULL</span>) {</span><br><span class="line"> v->get_handler = ngx_http_rewrite_var;</span><br><span class="line"> v->data = index;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_rewrite_value(cf, lcf, &value[<span class="number">2</span>]) != NGX_CONF_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//处理set_handler</span></span><br><span class="line"> <span class="keyword">if</span> (v->set_handler) {</span><br><span class="line"> vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_var_handler_code_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (vhcode == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> vhcode->code = ngx_http_script_var_set_handler_code;</span><br><span class="line"> vhcode->handler = v->set_handler;</span><br><span class="line"> vhcode->data = v->data;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_var_code_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (vcode == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> vcode->code = ngx_http_script_set_var_code;</span><br><span class="line"> vcode->index = (<span class="keyword">uintptr_t</span>) index;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p></p></blockquote><blockquote><p>这个函数首先解析出第一个变量的名字,并将其加入到nginx的变量系统中,其次解析作为第一个值的变量(第二个变量),但是第二个变量可能是一个普通的字符串也有可能是多个变量组成的字符串,都是在ngx_http_rewrite_value函数中进行处理,接下来看看ngx_http_rewrite_value函数实现。</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">char</span> *</span><br><span class="line">ngx_http_rewrite_value(<span class="keyword">ngx_conf_t</span> *cf, <span class="keyword">ngx_http_rewrite_loc_conf_t</span> *lcf,</span><br><span class="line"> <span class="keyword">ngx_str_t</span> *value)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">ngx_int_t</span> n;</span><br><span class="line"> <span class="keyword">ngx_http_script_compile_t</span> sc;</span><br><span class="line"> <span class="keyword">ngx_http_script_value_code_t</span> *val;</span><br><span class="line"> <span class="keyword">ngx_http_script_complex_value_code_t</span> *<span class="keyword">complex</span>;</span><br><span class="line"></span><br><span class="line"> n = ngx_http_script_variables_count(value);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n == <span class="number">0</span>) {</span><br><span class="line"> val = ngx_http_script_start_code(cf->pool, &lcf->codes,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_value_code_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (val == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> n = ngx_atoi(value->data, value->len);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (n == NGX_ERROR) {</span><br><span class="line"> n = <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> val->code = ngx_http_script_value_code;</span><br><span class="line"> val->value = (<span class="keyword">uintptr_t</span>) n;</span><br><span class="line"> val->text_len = (<span class="keyword">uintptr_t</span>) value->len;</span><br><span class="line"> val->text_data = (<span class="keyword">uintptr_t</span>) value->data;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//带有$的变量,value也是变量,如set $aa $bb,这里的$bb就是变量,</span></span><br><span class="line"> <span class="keyword">complex</span> = ngx_http_script_start_code(cf->pool, &lcf->codes,</span><br><span class="line"> <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_complex_value_code_t</span>));</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">complex</span> == <span class="literal">NULL</span>) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">complex</span>->code = ngx_http_script_complex_value_code;</span><br><span class="line"> <span class="keyword">complex</span>->lengths = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> ngx_memzero(&sc, <span class="keyword">sizeof</span>(<span class="keyword">ngx_http_script_compile_t</span>));</span><br><span class="line"></span><br><span class="line"> sc.cf = cf;</span><br><span class="line"> sc.source = value;</span><br><span class="line"> sc.lengths = &<span class="keyword">complex</span>->lengths;</span><br><span class="line"> sc.values = &lcf->codes;</span><br><span class="line"> sc.variables = n;</span><br><span class="line"> sc.complete_lengths = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (ngx_http_script_compile(&sc) != NGX_OK) {</span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_ERROR;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> NGX_CONF_OK;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><blockquote><p>这个函数中,n为0表示value不包含变量,为纯字符串,否则表示value中包含变量,采用复杂变量解析方式。</p></blockquote><h2 id="2、总结"><a href="#2、总结" class="headerlink" title="2、总结"></a>2、总结</h2><blockquote><p>以上就是Nginx变量的相关解释,Nginx变量在nginx.conf配置文件中有着至关重要的作用,可定制性强。</p></blockquote><!-- rebuild by neat -->]]></content>
<summary type="html">
<!-- build time:Thu Nov 28 2024 21:53:03 GMT+0800 (GMT+08:00) --><h2 id="1、源码解析"><a href="#1、源码解析" class="headerlink" title="1、源码解析"></a>1、源
</summary>
<category term="Nginx" scheme="https://weeweetan.github.io/categories/Nginx/"/>
<category term="Nginx" scheme="https://weeweetan.github.io/tags/Nginx/"/>
</entry>
</feed>