pidl/python: Calculate maximum integer values using a lookup table
[Samba.git] / source3 / lib / msghdr.c
blobde0eed46264b18adfc00a49775c14b175e5442c0
1 /*
2 * Unix SMB/CIFS implementation.
3 * Copyright (C) Volker Lendecke 2014
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "replace.h"
20 #include "lib/msghdr.h"
21 #include "lib/util/iov_buf.h"
22 #include <sys/socket.h>
24 ssize_t msghdr_prep_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
25 const int *fds, size_t num_fds)
27 size_t fds_size = sizeof(int) * MIN(num_fds, INT8_MAX);
28 size_t cmsg_len = CMSG_LEN(fds_size);
29 size_t cmsg_space = CMSG_SPACE(fds_size);
30 struct cmsghdr *cmsg;
31 void *fdptr;
33 if (num_fds == 0) {
34 if (msg != NULL) {
35 msg->msg_control = NULL;
36 msg->msg_controllen = 0;
38 return 0;
40 if (num_fds > INT8_MAX) {
41 return -1;
43 if ((msg == NULL) || (cmsg_space > bufsize)) {
44 return cmsg_space;
47 msg->msg_control = buf;
48 msg->msg_controllen = cmsg_space;
50 cmsg = CMSG_FIRSTHDR(msg);
51 cmsg->cmsg_level = SOL_SOCKET;
52 cmsg->cmsg_type = SCM_RIGHTS;
53 cmsg->cmsg_len = cmsg_len;
54 fdptr = CMSG_DATA(cmsg);
55 memcpy(fdptr, fds, fds_size);
56 msg->msg_controllen = cmsg->cmsg_len;
58 return cmsg_space;
61 struct msghdr_buf {
62 struct msghdr msg;
63 struct sockaddr_storage addr;
64 struct iovec iov;
65 uint8_t buf[];
68 ssize_t msghdr_copy(struct msghdr_buf *msg, size_t msgsize,
69 const void *addr, socklen_t addrlen,
70 const struct iovec *iov, int iovcnt,
71 const int *fds, size_t num_fds)
73 ssize_t fd_len;
74 size_t iov_len, needed, bufsize;
76 bufsize = (msgsize > offsetof(struct msghdr_buf, buf)) ?
77 msgsize - offsetof(struct msghdr_buf, buf) : 0;
79 fd_len = msghdr_prep_fds(&msg->msg, msg->buf, bufsize, fds, num_fds);
81 if (fd_len == -1) {
82 return -1;
85 if (bufsize >= fd_len) {
86 bufsize -= fd_len;
87 } else {
88 bufsize = 0;
91 if (msg != NULL) {
93 if (addr != NULL) {
94 if (addrlen > sizeof(struct sockaddr_storage)) {
95 errno = EMSGSIZE;
96 return -1;
98 memcpy(&msg->addr, addr, addrlen);
99 msg->msg.msg_name = &msg->addr;
100 msg->msg.msg_namelen = addrlen;
101 } else {
102 msg->msg.msg_name = NULL;
103 msg->msg.msg_namelen = 0;
106 msg->iov.iov_base = msg->buf + fd_len;
107 msg->iov.iov_len = iov_buf(
108 iov, iovcnt, msg->iov.iov_base, bufsize);
109 iov_len = msg->iov.iov_len;
111 msg->msg.msg_iov = &msg->iov;
112 msg->msg.msg_iovlen = 1;
113 } else {
114 iov_len = iov_buflen(iov, iovcnt);
117 needed = offsetof(struct msghdr_buf, buf) + fd_len;
118 if (needed < fd_len) {
119 return -1;
121 needed += iov_len;
122 if (needed < iov_len) {
123 return -1;
126 return needed;
129 struct msghdr *msghdr_buf_msghdr(struct msghdr_buf *msg)
131 return &msg->msg;
134 size_t msghdr_prep_recv_fds(struct msghdr *msg, uint8_t *buf, size_t bufsize,
135 size_t num_fds)
137 size_t ret = CMSG_SPACE(sizeof(int) * num_fds);
139 if (bufsize < ret) {
140 return ret;
142 if (msg != NULL) {
143 if (num_fds != 0) {
144 msg->msg_control = buf;
145 msg->msg_controllen = ret;
146 } else {
147 msg->msg_control = NULL;
148 msg->msg_controllen = 0;
151 return ret;
154 size_t msghdr_extract_fds(struct msghdr *msg, int *fds, size_t fds_size)
156 struct cmsghdr *cmsg;
157 size_t num_fds;
159 for(cmsg = CMSG_FIRSTHDR(msg);
160 cmsg != NULL;
161 cmsg = CMSG_NXTHDR(msg, cmsg))
163 if ((cmsg->cmsg_type == SCM_RIGHTS) &&
164 (cmsg->cmsg_level == SOL_SOCKET)) {
165 break;
169 if (cmsg == NULL) {
170 return 0;
173 num_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
175 if ((num_fds != 0) && (fds != NULL) && (fds_size >= num_fds)) {
176 memcpy(fds, CMSG_DATA(cmsg), num_fds * sizeof(int));
179 return num_fds;