xref: /unit/src/nxt_socket_msg.h (revision 1996:35873fa78fed)
1 /*
2  * Copyright (C) NGINX, Inc.
3  */
4 
5 #ifndef _NXT_SOCKET_MSG_H_INCLUDED_
6 #define _NXT_SOCKET_MSG_H_INCLUDED_
7 
8 #if (NXT_HAVE_UCRED)
9 #include <sys/un.h>
10 #endif
11 
12 
13 #if (NXT_HAVE_UCRED)
14 #define NXT_CRED_USECMSG    1
15 #define NXT_CRED_CMSGTYPE   SCM_CREDENTIALS
16 #define NXT_CRED_GETPID(u)  (u->pid)
17 
18 typedef struct ucred        nxt_socket_cred_t;
19 
20 #elif (NXT_HAVE_MSGHDR_CMSGCRED)
21 #define NXT_CRED_USECMSG    1
22 #define NXT_CRED_CMSGTYPE   SCM_CREDS
23 #define NXT_CRED_GETPID(u)  (u->cmcred_pid)
24 
25 typedef struct cmsgcred     nxt_socket_cred_t;
26 #endif
27 
28 #if (NXT_CRED_USECMSG)
29 #define NXT_OOB_RECV_SIZE                                                     \
30     (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t)))
31 #else
32 #define NXT_OOB_RECV_SIZE                                                     \
33     CMSG_SPACE(2 * sizeof(int))
34 #endif
35 
36 #if (NXT_HAVE_MSGHDR_CMSGCRED)
37 #define NXT_OOB_SEND_SIZE                                                     \
38     (CMSG_SPACE(2 * sizeof(int)) + CMSG_SPACE(sizeof(nxt_socket_cred_t)))
39 #else
40 #define NXT_OOB_SEND_SIZE                                                     \
41     CMSG_SPACE(2 * sizeof(int))
42 #endif
43 
44 
45 typedef struct {
46     size_t  size;
47     u_char  buf[NXT_OOB_RECV_SIZE];
48 } nxt_recv_oob_t;
49 
50 
51 typedef struct {
52     size_t  size;
53     u_char  buf[NXT_OOB_SEND_SIZE];
54 } nxt_send_oob_t;
55 
56 
57 /**
58  * The nxt_sendmsg is a wrapper for sendmsg.
59  * The oob struct must be initialized using nxt_socket_msg_oob_init().
60  */
61 NXT_EXPORT ssize_t nxt_sendmsg(nxt_socket_t s, nxt_iobuf_t *iob,
62     nxt_uint_t niob, const nxt_send_oob_t *oob);
63 
64 /**
65  * The nxt_recvmsg is a wrapper for recvmsg.
66  * The oob buffer must be consumed by using nxt_socket_msg_oob_get().
67  */
68 NXT_EXPORT ssize_t nxt_recvmsg(nxt_socket_t s,
69     nxt_iobuf_t *iob, nxt_uint_t niob, nxt_recv_oob_t *oob);
70 
71 
72 nxt_inline void
nxt_socket_msg_oob_init(nxt_send_oob_t * oob,int * fds)73 nxt_socket_msg_oob_init(nxt_send_oob_t *oob, int *fds)
74 {
75     int             nfds;
76     struct cmsghdr  *cmsg;
77 
78 #if (NXT_HAVE_MSGHDR_CMSGCRED)
79     cmsg = (struct cmsghdr *) (oob->buf);
80     /*
81      * Fill all padding fields with 0.
82      * Code in Go 1.11 validate cmsghdr using padding field as part of len.
83      * See Cmsghdr definition and socketControlMessageHeaderAndData function.
84      */
85     nxt_memzero(cmsg, sizeof(struct cmsghdr));
86 
87     cmsg->cmsg_len = CMSG_LEN(sizeof(nxt_socket_cred_t));
88     cmsg->cmsg_level = SOL_SOCKET;
89     cmsg->cmsg_type = NXT_CRED_CMSGTYPE;
90 
91     oob->size = CMSG_SPACE(sizeof(nxt_socket_cred_t));
92 
93 #else
94     oob->size = 0;
95 #endif
96 
97     nfds = (fds[0] != -1 ? 1 : 0) + (fds[1] != -1 ? 1 : 0);
98 
99     if (nfds == 0) {
100         return;
101     }
102 
103     cmsg = (struct cmsghdr *) (oob->buf + oob->size);
104 
105     nxt_memzero(cmsg, sizeof(struct cmsghdr));
106 
107     cmsg->cmsg_len = CMSG_LEN(nfds * sizeof(int));
108     cmsg->cmsg_level = SOL_SOCKET;
109     cmsg->cmsg_type = SCM_RIGHTS;
110 
111     /*
112      * nxt_memcpy() is used instead of simple
113      *   *(int *) CMSG_DATA(&cmsg.cm) = fd;
114      * because GCC 4.4 with -O2/3/s optimization may issue a warning:
115      *   dereferencing type-punned pointer will break strict-aliasing rules
116      *
117      * Fortunately, GCC with -O1 compiles this nxt_memcpy()
118      * in the same simple assignment as in the code above.
119      */
120     nxt_memcpy(CMSG_DATA(cmsg), fds, nfds * sizeof(int));
121 
122     oob->size += CMSG_SPACE(nfds * sizeof(int));
123 }
124 
125 
126 nxt_inline nxt_int_t
nxt_socket_msg_oob_get_fds(nxt_recv_oob_t * oob,nxt_fd_t * fd)127 nxt_socket_msg_oob_get_fds(nxt_recv_oob_t *oob, nxt_fd_t *fd)
128 {
129     size_t          size;
130     struct msghdr   msg;
131     struct cmsghdr  *cmsg;
132 
133     msg.msg_control = oob->buf;
134     msg.msg_controllen = oob->size;
135 
136     for (cmsg = CMSG_FIRSTHDR(&msg);
137          cmsg != NULL;
138          cmsg = CMSG_NXTHDR(&msg, cmsg))
139     {
140         size = cmsg->cmsg_len - CMSG_LEN(0);
141 
142         if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
143             if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) {
144                 return NXT_ERROR;
145             }
146 
147             nxt_memcpy(fd, CMSG_DATA(cmsg), size);
148 
149             return NXT_OK;
150         }
151     }
152 
153     return NXT_OK;
154 }
155 
156 
157 nxt_inline nxt_int_t
nxt_socket_msg_oob_get(nxt_recv_oob_t * oob,nxt_fd_t * fd,nxt_pid_t * pid)158 nxt_socket_msg_oob_get(nxt_recv_oob_t *oob, nxt_fd_t *fd, nxt_pid_t *pid)
159 {
160     size_t          size;
161     struct msghdr   msg;
162     struct cmsghdr  *cmsg;
163 
164     if (oob->size == 0) {
165         return NXT_OK;
166     }
167 
168 #if (NXT_CRED_USECMSG)
169     *pid = -1;
170 #endif
171 
172     msg.msg_control = oob->buf;
173     msg.msg_controllen = oob->size;
174 
175     for (cmsg = CMSG_FIRSTHDR(&msg);
176          cmsg != NULL;
177          cmsg = CMSG_NXTHDR(&msg, cmsg))
178     {
179         size = cmsg->cmsg_len - CMSG_LEN(0);
180 
181         if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
182             if (nxt_slow_path(size != sizeof(int) && size != 2 * sizeof(int))) {
183                 return NXT_ERROR;
184             }
185 
186             nxt_memcpy(fd, CMSG_DATA(cmsg), size);
187 
188 #if (!NXT_CRED_USECMSG)
189             break;
190 #endif
191         }
192 
193 #if (NXT_CRED_USECMSG)
194         else if (cmsg->cmsg_level == SOL_SOCKET
195                  && cmsg->cmsg_type == NXT_CRED_CMSGTYPE)
196         {
197             nxt_socket_cred_t  *creds;
198 
199             if (nxt_slow_path(size != sizeof(nxt_socket_cred_t))) {
200                 return NXT_ERROR;
201             }
202 
203             creds = (nxt_socket_cred_t *) CMSG_DATA(cmsg);
204             *pid = NXT_CRED_GETPID(creds);
205         }
206 #endif
207     }
208 
209 #if (NXT_CRED_USECMSG)
210     /* For platforms supporting credential passing, it's enforced */
211     if (nxt_slow_path(*pid == -1)) {
212         return NXT_ERROR;
213     }
214 #endif
215 
216     return NXT_OK;
217 }
218 
219 
220 #endif /* _NXT_SOCKET_MSG_H_INCLUDED_ */
221