upstream nginx-0.7.31
[nginx.git] / nginx / src / os / unix / ngx_channel.c
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
12 ngx_int_t
13 ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
14     ngx_log_t *log)
15 {
16     ssize_t             n;
17     ngx_err_t           err;
18     struct iovec        iov[1];
19     struct msghdr       msg;
20
21 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
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 = CMSG_LEN(sizeof(int));
37         cmsg.cm.cmsg_level = SOL_SOCKET;
38         cmsg.cm.cmsg_type = SCM_RIGHTS;
39         *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
40     }
41
42     msg.msg_flags = 0;
43
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
81 ngx_int_t
82 ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
83 {
84     ssize_t             n;
85     ngx_err_t           err;
86     struct iovec        iov[1];
87     struct msghdr       msg;
88
89 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
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
106 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
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
126     if (n == 0) {
127         ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero");
128         return NGX_ERROR;
129     }
130
131     if ((size_t) n < sizeof(ngx_channel_t)) {
132         ngx_log_error(NGX_LOG_ALERT, log, 0,
133                       "recvmsg() returned not enough data: %uz", n);
134         return NGX_ERROR;
135     }
136
137 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
138
139     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
140
141         if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
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)) {
168             ngx_log_error(NGX_LOG_ALERT, log, 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
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)
185 {
186     ngx_event_t       *ev, *rev, *wev;
187     ngx_connection_t  *c;
188
189     c = ngx_get_connection(fd, cycle->log);
190
191     if (c == NULL) {
192         return NGX_ERROR;
193     }
194
195     c->pool = cycle->pool;
196
197     rev = c->read;
198     wev = c->write;
199
200     rev->log = cycle->log;
201     wev->log = cycle->log;
202
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
210     rev->channel = 1;
211     wev->channel = 1;
212
213     ev = (event == NGX_READ_EVENT) ? rev : wev;
214
215     ev->handler = handler;
216
217     if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
218         if (ngx_add_conn(c) == NGX_ERROR) {
219             ngx_free_connection(c);
220             return NGX_ERROR;
221         }
222
223     } else {
224         if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
225             ngx_free_connection(c);
226             return NGX_ERROR;
227         }
228     }
229
230     return NGX_OK;
231 }
232
233
234 void
235 ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
236 {
237     if (close(fd[0]) == -1) {
238         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
239     }
240
241     if (close(fd[1]) == -1) {
242         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
243     }
244 }