xref: /freebsd/sbin/hastd/proto_common.c (revision 8046c499abd461a51517067641dc7a13de88a1cb)
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 int
49 proto_common_send(int sock, const unsigned char *data, size_t size)
50 {
51 	ssize_t done;
52 	size_t sendsize;
53 
54 	PJDLOG_ASSERT(sock >= 0);
55 	PJDLOG_ASSERT(data != NULL);
56 	PJDLOG_ASSERT(size > 0);
57 
58 	do {
59 		sendsize = size < MAX_SEND_SIZE ? size : MAX_SEND_SIZE;
60 		done = send(sock, data, sendsize, MSG_NOSIGNAL);
61 		if (done == 0)
62 			return (ENOTCONN);
63 		else if (done < 0) {
64 			if (errno == EINTR)
65 				continue;
66 			return (errno);
67 		}
68 		data += done;
69 		size -= done;
70 	} while (size > 0);
71 
72 	return (0);
73 }
74 
75 int
76 proto_common_recv(int sock, unsigned char *data, size_t size)
77 {
78 	ssize_t done;
79 
80 	PJDLOG_ASSERT(sock >= 0);
81 	PJDLOG_ASSERT(data != NULL);
82 	PJDLOG_ASSERT(size > 0);
83 
84 	do {
85 		done = recv(sock, data, size, MSG_WAITALL);
86 	} while (done == -1 && errno == EINTR);
87 	if (done == 0)
88 		return (ENOTCONN);
89 	else if (done < 0)
90 		return (errno);
91 	return (0);
92 }
93 
94 int
95 proto_common_descriptor_send(int sock, int fd)
96 {
97 	unsigned char ctrl[CMSG_SPACE(sizeof(fd))];
98 	struct msghdr msg;
99 	struct cmsghdr *cmsg;
100 
101 	PJDLOG_ASSERT(sock >= 0);
102 	PJDLOG_ASSERT(fd >= 0);
103 
104 	bzero(&msg, sizeof(msg));
105 	bzero(&ctrl, sizeof(ctrl));
106 
107 	msg.msg_iov = NULL;
108 	msg.msg_iovlen = 0;
109 	msg.msg_control = ctrl;
110 	msg.msg_controllen = sizeof(ctrl);
111 
112 	cmsg = CMSG_FIRSTHDR(&msg);
113 	cmsg->cmsg_level = SOL_SOCKET;
114 	cmsg->cmsg_type = SCM_RIGHTS;
115 	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
116 	*((int *)CMSG_DATA(cmsg)) = fd;
117 
118 	if (sendmsg(sock, &msg, 0) == -1)
119 		return (errno);
120 
121 	return (0);
122 }
123 
124 int
125 proto_common_descriptor_recv(int sock, int *fdp)
126 {
127 	unsigned char ctrl[CMSG_SPACE(sizeof(*fdp))];
128 	struct msghdr msg;
129 	struct cmsghdr *cmsg;
130 
131 	PJDLOG_ASSERT(sock >= 0);
132 	PJDLOG_ASSERT(fdp != NULL);
133 
134 	bzero(&msg, sizeof(msg));
135 	bzero(&ctrl, sizeof(ctrl));
136 
137 	msg.msg_iov = NULL;
138 	msg.msg_iovlen = 0;
139 	msg.msg_control = ctrl;
140 	msg.msg_controllen = sizeof(ctrl);
141 
142 	if (recvmsg(sock, &msg, 0) == -1)
143 		return (errno);
144 
145 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
146 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
147 		if (cmsg->cmsg_level == SOL_SOCKET &&
148 		    cmsg->cmsg_type == SCM_RIGHTS) {
149 			*fdp = *((int *)CMSG_DATA(cmsg));
150 			return (0);
151 		}
152 	}
153 
154 	return (ENOENT);
155 }
156