0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9 #include <ngx_channel.h>
|
|
10
|
|
11
|
92
|
12 ngx_int_t
|
|
13 ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
|
126
|
14 ngx_log_t *log)
|
0
|
15 {
|
|
16 ssize_t n;
|
|
17 ngx_err_t err;
|
|
18 struct iovec iov[1];
|
|
19 struct msghdr msg;
|
|
20
|
18
|
21 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
0
|
22
|
|
23 union {
|
|
24 struct cmsghdr cm;
|
|
25 char space[CMSG_SPACE(sizeof(int))];
|
|
26 } cmsg;
|
|
27
|
|
28 if (ch->fd == -1) {
|
|
29 msg.msg_control = NULL;
|
|
30 msg.msg_controllen = 0;
|
|
31
|
|
32 } else {
|
|
33 msg.msg_control = (caddr_t) &cmsg;
|
|
34 msg.msg_controllen = sizeof(cmsg);
|
|
35
|
|
36 cmsg.cm.cmsg_len = sizeof(cmsg);
|
126
|
37 cmsg.cm.cmsg_level = SOL_SOCKET;
|
0
|
38 cmsg.cm.cmsg_type = SCM_RIGHTS;
|
|
39 *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
|
|
40 }
|
|
41
|
32
|
42 msg.msg_flags = 0;
|
|
43
|
0
|
44 #else
|
|
45
|
|
46 if (ch->fd == -1) {
|
|
47 msg.msg_accrights = NULL;
|
|
48 msg.msg_accrightslen = 0;
|
|
49
|
|
50 } else {
|
|
51 msg.msg_accrights = (caddr_t) &ch->fd;
|
|
52 msg.msg_accrightslen = sizeof(int);
|
|
53 }
|
|
54
|
|
55 #endif
|
|
56
|
|
57 iov[0].iov_base = (char *) ch;
|
|
58 iov[0].iov_len = size;
|
|
59
|
|
60 msg.msg_name = NULL;
|
|
61 msg.msg_namelen = 0;
|
|
62 msg.msg_iov = iov;
|
|
63 msg.msg_iovlen = 1;
|
|
64
|
|
65 n = sendmsg(s, &msg, 0);
|
|
66
|
|
67 if (n == -1) {
|
|
68 err = ngx_errno;
|
|
69 if (err == NGX_EAGAIN) {
|
|
70 return NGX_AGAIN;
|
|
71 }
|
|
72
|
|
73 ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");
|
|
74 return NGX_ERROR;
|
|
75 }
|
|
76
|
|
77 return NGX_OK;
|
|
78 }
|
|
79
|
|
80
|
92
|
81 ngx_int_t
|
|
82 ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
|
126
|
83 {
|
0
|
84 ssize_t n;
|
|
85 ngx_err_t err;
|
|
86 struct iovec iov[1];
|
|
87 struct msghdr msg;
|
|
88
|
18
|
89 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
0
|
90 union {
|
|
91 struct cmsghdr cm;
|
|
92 char space[CMSG_SPACE(sizeof(int))];
|
|
93 } cmsg;
|
|
94 #else
|
|
95 int fd;
|
|
96 #endif
|
|
97
|
|
98 iov[0].iov_base = (char *) ch;
|
|
99 iov[0].iov_len = size;
|
|
100
|
|
101 msg.msg_name = NULL;
|
|
102 msg.msg_namelen = 0;
|
|
103 msg.msg_iov = iov;
|
|
104 msg.msg_iovlen = 1;
|
|
105
|
18
|
106 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
0
|
107 msg.msg_control = (caddr_t) &cmsg;
|
|
108 msg.msg_controllen = sizeof(cmsg);
|
|
109 #else
|
|
110 msg.msg_accrights = (caddr_t) &fd;
|
|
111 msg.msg_accrightslen = sizeof(int);
|
|
112 #endif
|
|
113
|
|
114 n = recvmsg(s, &msg, 0);
|
|
115
|
|
116 if (n == -1) {
|
|
117 err = ngx_errno;
|
|
118 if (err == NGX_EAGAIN) {
|
|
119 return NGX_AGAIN;
|
|
120 }
|
|
121
|
|
122 ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed");
|
|
123 return NGX_ERROR;
|
|
124 }
|
|
125
|
10
|
126 if (n == 0) {
|
|
127 ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero");
|
|
128 return NGX_ERROR;
|
|
129 }
|
|
130
|
0
|
131 if ((size_t) n < sizeof(ngx_channel_t)) {
|
|
132 ngx_log_error(NGX_LOG_ALERT, log, 0,
|
10
|
133 "recvmsg() returned not enough data: %uz", n);
|
0
|
134 return NGX_ERROR;
|
|
135 }
|
|
136
|
18
|
137 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
|
0
|
138
|
|
139 if (ch->command == NGX_CMD_OPEN_CHANNEL) {
|
|
140
|
58
|
141 if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) {
|
0
|
142 ngx_log_error(NGX_LOG_ALERT, log, 0,
|
|
143 "recvmsg() returned too small ancillary data");
|
|
144 return NGX_ERROR;
|
|
145 }
|
|
146
|
|
147 if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS)
|
|
148 {
|
|
149 ngx_log_error(NGX_LOG_ALERT, log, 0,
|
|
150 "recvmsg() returned invalid ancillary data "
|
|
151 "level %d or type %d",
|
|
152 cmsg.cm.cmsg_level, cmsg.cm.cmsg_type);
|
|
153 return NGX_ERROR;
|
|
154 }
|
|
155
|
|
156 ch->fd = *(int *) CMSG_DATA(&cmsg.cm);
|
|
157 }
|
|
158
|
|
159 if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
|
|
160 ngx_log_error(NGX_LOG_ALERT, log, 0,
|
|
161 "recvmsg() truncated data");
|
|
162 }
|
|
163
|
|
164 #else
|
|
165
|
|
166 if (ch->command == NGX_CMD_OPEN_CHANNEL) {
|
|
167 if (msg.msg_accrightslen != sizeof(int)) {
|
126
|
168 ngx_log_error(NGX_LOG_ALERT, log, 0,
|
0
|
169 "recvmsg() returned no ancillary data");
|
|
170 return NGX_ERROR;
|
|
171 }
|
|
172
|
|
173 ch->fd = fd;
|
|
174 }
|
|
175
|
|
176 #endif
|
|
177
|
|
178 return n;
|
|
179 }
|
|
180
|
|
181
|
92
|
182 ngx_int_t
|
|
183 ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event,
|
|
184 ngx_event_handler_pt handler)
|
0
|
185 {
|
|
186 ngx_event_t *ev, *rev, *wev;
|
|
187 ngx_connection_t *c;
|
|
188
|
92
|
189 c = ngx_get_connection(fd, cycle->log);
|
|
190
|
|
191 if (c == NULL) {
|
|
192 return NGX_ERROR;
|
|
193 }
|
|
194
|
110
|
195 c->pool = cycle->pool;
|
|
196
|
92
|
197 rev = c->read;
|
|
198 wev = c->write;
|
0
|
199
|
|
200 rev->log = cycle->log;
|
|
201 wev->log = cycle->log;
|
92
|
202
|
0
|
203 #if (NGX_THREADS)
|
|
204 rev->lock = &c->lock;
|
|
205 wev->lock = &c->lock;
|
|
206 rev->own_lock = &c->lock;
|
|
207 wev->own_lock = &c->lock;
|
|
208 #endif
|
|
209
|
112
|
210 rev->channel = 1;
|
|
211 wev->channel = 1;
|
|
212
|
0
|
213 ev = (event == NGX_READ_EVENT) ? rev : wev;
|
|
214
|
58
|
215 ev->handler = handler;
|
0
|
216
|
|
217 if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
|
|
218 if (ngx_add_conn(c) == NGX_ERROR) {
|
92
|
219 ngx_free_connection(c);
|
0
|
220 return NGX_ERROR;
|
|
221 }
|
126
|
222
|
|
223 } else {
|
0
|
224 if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
|
92
|
225 ngx_free_connection(c);
|
0
|
226 return NGX_ERROR;
|
|
227 }
|
|
228 }
|
|
229
|
|
230 return NGX_OK;
|
|
231 }
|
|
232
|
|
233
|
92
|
234 void
|
|
235 ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
|
0
|
236 {
|
|
237 if (close(fd[0]) == -1) {
|
14
|
238 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
|
0
|
239 }
|
|
240
|
|
241 if (close(fd[1]) == -1) {
|
14
|
242 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
|
0
|
243 }
|
|
244 }
|