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