]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/hastd/proto_common.c
MFC r219351, r219354, r219369, r219370, r219371, r219372, r219373,
[FreeBSD/stable/8.git] / sbin / hastd / proto_common.c
1 /*-
2  * Copyright (c) 2009-2010 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <strings.h>
39
40 #include "pjdlog.h"
41 #include "proto_impl.h"
42
43 /* Maximum size of packet we want to use when sending data. */
44 #ifndef MAX_SEND_SIZE
45 #define MAX_SEND_SIZE   32768
46 #endif
47
48 static int
49 proto_descriptor_send(int sock, int fd)
50 {
51         unsigned char ctrl[CMSG_SPACE(sizeof(fd))];
52         struct msghdr msg;
53         struct cmsghdr *cmsg;
54
55         PJDLOG_ASSERT(sock >= 0);
56         PJDLOG_ASSERT(fd >= 0);
57
58         bzero(&msg, sizeof(msg));
59         bzero(&ctrl, sizeof(ctrl));
60
61         msg.msg_iov = NULL;
62         msg.msg_iovlen = 0;
63         msg.msg_control = ctrl;
64         msg.msg_controllen = sizeof(ctrl);
65
66         cmsg = CMSG_FIRSTHDR(&msg);
67         cmsg->cmsg_level = SOL_SOCKET;
68         cmsg->cmsg_type = SCM_RIGHTS;
69         cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
70         bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
71
72         if (sendmsg(sock, &msg, 0) == -1)
73                 return (errno);
74
75         return (0);
76 }
77
78 int
79 proto_common_send(int sock, const unsigned char *data, size_t size, int fd)
80 {
81         ssize_t done;
82         size_t sendsize;
83
84         PJDLOG_ASSERT(sock >= 0);
85         PJDLOG_ASSERT(data != NULL);
86         PJDLOG_ASSERT(size > 0);
87
88         do {
89                 sendsize = size < MAX_SEND_SIZE ? size : MAX_SEND_SIZE;
90                 done = send(sock, data, sendsize, MSG_NOSIGNAL);
91                 if (done == 0)
92                         return (ENOTCONN);
93                 else if (done < 0) {
94                         if (errno == EINTR)
95                                 continue;
96                         return (errno);
97                 }
98                 data += done;
99                 size -= done;
100         } while (size > 0);
101
102         if (fd == -1)
103                 return (0);
104         return (proto_descriptor_send(sock, fd));
105 }
106
107 static int
108 proto_descriptor_recv(int sock, int *fdp)
109 {
110         unsigned char ctrl[CMSG_SPACE(sizeof(*fdp))];
111         struct msghdr msg;
112         struct cmsghdr *cmsg;
113
114         PJDLOG_ASSERT(sock >= 0);
115         PJDLOG_ASSERT(fdp != NULL);
116
117         bzero(&msg, sizeof(msg));
118         bzero(&ctrl, sizeof(ctrl));
119
120         msg.msg_iov = NULL;
121         msg.msg_iovlen = 0;
122         msg.msg_control = ctrl;
123         msg.msg_controllen = sizeof(ctrl);
124
125         if (recvmsg(sock, &msg, 0) == -1)
126                 return (errno);
127
128         cmsg = CMSG_FIRSTHDR(&msg);
129         if (cmsg->cmsg_level != SOL_SOCKET ||
130             cmsg->cmsg_type != SCM_RIGHTS) {
131                 return (EINVAL);
132         }
133         bcopy(CMSG_DATA(cmsg), fdp, sizeof(*fdp));
134
135         return (0);
136 }
137
138 int
139 proto_common_recv(int sock, unsigned char *data, size_t size, int *fdp)
140 {
141         ssize_t done;
142
143         PJDLOG_ASSERT(sock >= 0);
144         PJDLOG_ASSERT(data != NULL);
145         PJDLOG_ASSERT(size > 0);
146
147         do {
148                 done = recv(sock, data, size, MSG_WAITALL);
149         } while (done == -1 && errno == EINTR);
150         if (done == 0)
151                 return (ENOTCONN);
152         else if (done < 0)
153                 return (errno);
154         if (fdp == NULL)
155                 return (0);
156         return (proto_descriptor_recv(sock, fdp));
157 }