2 * Copyright (c) 2013 Larisa Grigore. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <sys/param.h>
30 #include <sys/types.h>
41 #include "sysvipc_utils.h"
42 #include "sysvipc_sockets.h"
47 init_socket(const char *sockfile
)
49 struct sockaddr_un un_addr
;
52 /* create server socket */
53 if ( (sock
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0) {
54 sysv_print_err("init socket");
59 memset(&un_addr
, 0, sizeof(un_addr
));
60 un_addr
.sun_len
= sizeof(un_addr
);
61 un_addr
.sun_family
= AF_UNIX
;
62 strcpy(un_addr
.sun_path
, sockfile
);
64 unlink(un_addr
.sun_path
);
66 if (bind(sock
, (struct sockaddr
*)&un_addr
, sizeof(un_addr
)) < 0) {
68 sysv_print_err("bind");
72 if (listen(sock
, MAX_CONN
) < 0) {
74 sysv_print_err("listen");
78 /* turn on credentials passing */
83 handle_new_connection(int sock
)
88 fd
= accept(sock
, NULL
, NULL
);
89 } while (fd
< 0 && errno
== EINTR
);
92 sysv_print_err("accept");
96 flags
= fcntl(fd
, F_GETFL
, 0);
97 fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
);
103 connect_to_daemon(const char *sockfile
)
106 struct sockaddr_un serv_addr
;
108 if ((sock
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0) {
109 sysv_print_err("socket(%d)\n", sock
);
113 flags
= fcntl(sock
, F_GETFL
, 0);
114 fcntl(sock
, F_SETFL
, flags
& ~O_NONBLOCK
);
116 memset(&serv_addr
, 0, sizeof(serv_addr
));
117 serv_addr
.sun_family
= AF_UNIX
;
118 strcpy(serv_addr
.sun_path
, sockfile
);
120 if (connect(sock
, (struct sockaddr
*)&serv_addr
,
121 sizeof(serv_addr
)) < 0) {
123 sysv_print_err("connect(%d)\n", sock
);
131 send_fd(int sock
, int fd
)
135 #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
138 char buf
[CMSG_SPACE(sizeof(int))];
140 struct cmsghdr
*cmsg
;
145 memset(&msg
, 0, sizeof(msg
));
150 #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
151 msg
.msg_accrights
= (caddr_t
)&fd
;
152 msg
.msg_accrightslen
= sizeof(fd
);
154 msg
.msg_control
= (caddr_t
)cmsgbuf
.buf
;
155 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
156 cmsg
= CMSG_FIRSTHDR(&msg
);
157 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
158 cmsg
->cmsg_level
= SOL_SOCKET
;
159 cmsg
->cmsg_type
= SCM_RIGHTS
;
160 *(int *)CMSG_DATA(cmsg
) = fd
;
164 vec
.iov_base
= (caddr_t
)&result
;
165 vec
.iov_len
= sizeof(int);
169 if ((n
= sendmsg(sock
, &msg
, 0)) == -1) {
170 sysv_print_err("sendmsg(%d)\n",
174 if (n
!= sizeof(int)) {
175 sysv_print_err("sendmsg: expected sent 1 got %ld\n",
189 #ifndef HAVE_ACCRIGHTS_IN_MSGHDR
192 char buf
[CMSG_SPACE(sizeof(int))];
194 struct cmsghdr
*cmsg
;
200 memset(&msg
, 0, sizeof(msg
));
201 vec
.iov_base
= (caddr_t
)&result
;
202 vec
.iov_len
= sizeof(int);
206 #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
207 msg
.msg_accrights
= (caddr_t
)&fd
;
208 msg
.msg_accrightslen
= sizeof(fd
);
210 msg
.msg_control
= &cmsgbuf
.buf
;
211 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
214 if ((n
= recvmsg(sock
, &msg
, 0)) == -1)
215 sysv_print_err("recvmsg\n");
216 if (n
!= sizeof(int)) {
217 sysv_print_err("recvmsg: expected received 1 got %ld\n",
221 cmsg
= CMSG_FIRSTHDR(&msg
);
223 sysv_print_err("no message header\n");
226 if (cmsg
->cmsg_type
!= SCM_RIGHTS
)
227 sysv_print_err("expected type %d got %d\n",
228 SCM_RIGHTS
, cmsg
->cmsg_type
);
230 fd
= (*(int *)CMSG_DATA(cmsg
));
239 close_fds(int *fds
, int num_fds
) {
242 for (i
=0; i
< num_fds
; i
++)
246 /* Send with the message, credentials too. */
248 send_msg_with_cred(int sock
, char *buffer
, size_t size
) {
255 char cred
[CMSG_SPACE(sizeof(struct cmsgcred
))];
258 memset(&cmsg
, 0, sizeof(cmsg
));
259 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct cmsgcred
));
260 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
261 cmsg
.hdr
.cmsg_type
= SCM_CREDS
;
263 memset(&msg
, 0, sizeof(struct msghdr
));
266 msg
.msg_control
= (caddr_t
)&cmsg
;
267 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct cmsgcred
));
269 vec
.iov_base
= buffer
;
272 if ((n
= sendmsg(sock
, &msg
, 0)) == -1) {
273 sysv_print_err("sendmsg on fd %d\n", sock
);
280 /* Receive a message and the credentials of the sender. */
282 receive_msg_with_cred(int sock
, char *buffer
, size_t size
,
283 struct cmsgcred
*cred
) {
284 struct msghdr msg
= { .msg_name
= NULL
};
291 char cred
[CMSG_SPACE(sizeof(struct cmsgcred
))];
294 memset(&msg
, 0, sizeof(msg
));
295 vec
.iov_base
= buffer
;
300 msg
.msg_control
= &cmsg
;
301 msg
.msg_controllen
= sizeof(cmsg
);
304 n
= recvmsg(sock
, &msg
, 0);
305 } while (n
< 0 && errno
== EINTR
);
308 sysv_print_err("recvmsg on fd %d\n", sock
);
317 cmp
= CMSG_FIRSTHDR(&msg
);
320 if (cmp
->cmsg_level
== SOL_SOCKET
321 && cmp
->cmsg_type
== SCM_CREDS
) {
323 memcpy(cred
, CMSG_DATA(cmp
), sizeof(*cred
));
325 } else if (cmp
->cmsg_level
== SOL_SOCKET
326 && cmp
->cmsg_type
== SCM_RIGHTS
) {
327 close_fds((int *) CMSG_DATA(cmp
),
328 (cmp
->cmsg_len
- CMSG_LEN(0))
331 cmp
= CMSG_NXTHDR(&msg
, cmp
);