Port: Add compat for platforms with no MSG_NOSIGNAL or SO_NOSIGPIPE
[lttng-tools.git] / src / common / compat / socket.h
1 /*
2 * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #ifndef _COMPAT_SOCKET_H
19 #define _COMPAT_SOCKET_H
20
21 #include <sys/socket.h>
22 #include <sys/un.h>
23
24 #include <common/macros.h>
25
26 #ifndef MSG_NOSIGNAL
27 # ifdef SO_NOSIGPIPE
28 # define MSG_NOSIGNAL SO_NOSIGPIPE
29 # endif
30 #endif
31
32 #if defined(MSG_NOSIGNAL)
33 static inline
34 ssize_t lttng_recvmsg_nosigpipe(int sockfd, struct msghdr *msg)
35 {
36 return recvmsg(sockfd, msg, MSG_NOSIGNAL);
37 }
38 #else
39
40 #include <signal.h>
41 #include <errno.h>
42
43 static inline
44 ssize_t lttng_recvmsg_nosigpipe(int sockfd, struct msghdr *msg)
45 {
46 ssize_t received;
47 int saved_err;
48 sigset_t sigpipe_set, pending_set, old_set;
49 int sigpipe_was_pending;
50
51 /*
52 * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
53 * that might be already pending. If a bogus SIGPIPE is sent to
54 * the entire process concurrently by a malicious user, it may
55 * be simply discarded.
56 */
57 if (sigemptyset(&pending_set)) {
58 return -1;
59 }
60 /*
61 * sigpending returns the mask of signals that are _both_
62 * blocked for the thread _and_ pending for either the thread or
63 * the entire process.
64 */
65 if (sigpending(&pending_set)) {
66 return -1;
67 }
68 sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
69 /*
70 * If sigpipe was pending, it means it was already blocked, so
71 * no need to block it.
72 */
73 if (!sigpipe_was_pending) {
74 if (sigemptyset(&sigpipe_set)) {
75 return -1;
76 }
77 if (sigaddset(&sigpipe_set, SIGPIPE)) {
78 return -1;
79 }
80 if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
81 return -1;
82 }
83 }
84
85 /* Send and save errno. */
86 received = recvmsg(sockfd, msg, 0);
87 saved_err = errno;
88
89 if (received == -1 && errno == EPIPE && !sigpipe_was_pending) {
90 struct timespec timeout = { 0, 0 };
91 int ret;
92
93 do {
94 ret = sigtimedwait(&sigpipe_set, NULL,
95 &timeout);
96 } while (ret == -1 && errno == EINTR);
97 }
98 if (!sigpipe_was_pending) {
99 if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
100 return -1;
101 }
102 }
103 /* Restore send() errno */
104 errno = saved_err;
105
106 return received;
107 }
108 #endif
109
110
111 #ifdef __linux__
112
113 #define LTTNG_SOCK_CREDS SCM_CREDENTIALS
114
115 typedef struct ucred lttng_sock_cred;
116
117 #define LTTNG_SOCK_SET_UID_CRED(c, u) LTTNG_REF(c)->uid = u
118 #define LTTNG_SOCK_SET_GID_CRED(c, g) LTTNG_REF(c)->gid = g
119 #define LTTNG_SOCK_SET_PID_CRED(c, p) LTTNG_REF(c)->pid = p
120
121 #define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid
122 #define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid
123 #define LTTNG_SOCK_GET_PID_CRED(c) LTTNG_REF(c)->pid
124
125 #elif (defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__sun__))
126
127 struct lttng_sock_cred {
128 uid_t uid;
129 gid_t gid;
130 };
131
132 typedef struct lttng_sock_cred lttng_sock_cred;
133
134 #define LTTNG_SOCK_GET_UID_CRED(c) LTTNG_REF(c)->uid
135 #define LTTNG_SOCK_GET_GID_CRED(c) LTTNG_REF(c)->gid
136 #define LTTNG_SOCK_GET_PID_CRED(c) -1
137
138 #else
139 #error "Please add support for your OS."
140 #endif /* __linux__ , __FreeBSD__ */
141
142
143 #ifdef __sun__
144
145 # ifndef CMSG_ALIGN
146 # ifdef _CMSG_DATA_ALIGN
147 # define CMSG_ALIGN(len) _CMSG_DATA_ALIGN(len)
148 # else
149 /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
150 # define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & ~(sizeof (long) - 1))
151 # endif
152 # ifndef CMSG_SPACE
153 # define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + CMSG_ALIGN (len))
154 # endif
155 # ifndef CMSG_LEN
156 # define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
157 # endif
158 # endif
159
160
161 #include <ucred.h>
162
163 static inline
164 int getpeereid(int s, uid_t *euid, gid_t *gid)
165 {
166 int ret = 0;
167 ucred_t *ucred = NULL;
168
169 ret = getpeerucred(s, &ucred);
170 if (ret == -1) {
171 goto end;
172 }
173
174 ret = ucred_geteuid(ucred);
175 if (ret == -1) {
176 goto free;
177 }
178 *euid = ret;
179
180 ret = ucred_getrgid(ucred);
181 if (ret == -1) {
182 goto free;
183 }
184 *gid = ret;
185 ret = 0;
186 free:
187 ucred_free(ucred);
188 end:
189 return ret;
190 }
191
192 #endif /* __sun__ */
193
194 #endif /* _COMPAT_SOCKET_H */
This page took 0.03361 seconds and 5 git commands to generate.