Remove more eye sores
[mono.git] / mono / io-layer / daemon-messages.c
1 /*
2  * daemon-messages.c:  Communications to and from the handle daemon
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <pthread.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 /* Freebsd needs this included explicitly, but it doesn't hurt on Linux */
18 #ifdef HAVE_SYS_UIO_H
19 #    include <sys/uio.h>
20 #endif
21
22 #ifndef HAVE_MSG_NOSIGNAL
23 #include <signal.h>
24 #endif
25
26 #include <mono/io-layer/wapi.h>
27 #include <mono/io-layer/daemon-messages.h>
28
29 /* Solaris doesn't define these */
30 #ifndef CMSG_LEN
31 #define CMSG_LEN(size)    (sizeof (struct cmsghdr) + (size))
32 #endif
33 #ifndef CMSG_SPACE
34 #define CMSG_SPACE(size)  (sizeof (struct cmsghdr) + (size))
35 #endif
36
37 #define LOGDEBUG(...)
38 // #define LOGDEBUG(...) g_message(__VA_ARGS__)
39
40 static mono_mutex_t req_mutex;
41 static mono_once_t attr_key_once = MONO_ONCE_INIT;
42 static mono_mutexattr_t attr;
43
44 static void attr_init (void)
45 {
46         int ret;
47
48         ret = mono_mutexattr_init (&attr);
49         g_assert (ret == 0);
50
51         ret = mono_mutexattr_settype (&attr, MONO_MUTEX_RECURSIVE);
52         g_assert (ret == 0);
53
54         ret = mono_mutex_init (&req_mutex, &attr);
55         g_assert (ret == 0);
56 }
57
58 /* Send request on fd, wait for response (called by applications, not
59  * the daemon, indirectly through _wapi_daemon_request_response and
60  * _wapi_daemon_request_response_with_fds)
61  */
62 static void _wapi_daemon_request_response_internal (int fd,
63                                                     struct msghdr *msg,
64                                                     WapiHandleResponse *resp)
65 {
66         int ret;
67 #ifndef HAVE_MSG_NOSIGNAL
68         void (*old_sigpipe)(int);
69 #endif
70
71         mono_once (&attr_key_once, attr_init);
72
73         /* Serialise requests to the daemon from the same process.  We
74          * rely on request turnaround time being minimal anyway, so
75          * performance shouldnt suffer from the mutex.
76          */
77         pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
78                               (void *)&req_mutex);
79         ret = mono_mutex_lock (&req_mutex);
80         g_assert (ret == 0);
81         
82 #ifdef HAVE_MSG_NOSIGNAL
83         do {
84                 ret=sendmsg (fd, msg, MSG_NOSIGNAL);
85         }
86         while (ret==-1 && errno==EINTR);
87 #else
88         old_sigpipe = signal (SIGPIPE, SIG_IGN);
89         do {
90                 ret=sendmsg (fd, msg, 0);
91         }
92         while (ret==-1 && errno==EINTR);
93 #endif
94
95         if(ret!=sizeof(WapiHandleRequest)) {
96                 if(errno==EPIPE) {
97                         g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
98                         exit (-1);
99                 } else {
100                         g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
101                                    strerror (errno));
102                         g_assert_not_reached ();
103                 }
104         }
105
106 #ifdef HAVE_MSG_NOSIGNAL
107         do {
108                 ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
109         }
110         while (ret==-1 && errno==EINTR);
111 #else
112         do {
113                 ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
114         }
115         while (ret==-1 && errno==EINTR);
116         signal (SIGPIPE, old_sigpipe);
117 #endif
118
119         if(ret==-1) {
120                 if(errno==EPIPE) {
121                         g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
122                         exit (-1);
123                 } else {
124                         g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
125                                    strerror (errno));
126                         g_assert_not_reached ();
127                 }
128         }
129                 
130         ret = mono_mutex_unlock (&req_mutex);
131         g_assert (ret == 0);
132         
133         pthread_cleanup_pop (0);
134 }
135
136 /* Send request on fd with filedescriptors, wait for response (called
137  * by applications, not the daemon)
138  */
139 void _wapi_daemon_request_response_with_fds (int fd, WapiHandleRequest *req,
140                                              WapiHandleResponse *resp,
141                                              int in_fd, int out_fd, int err_fd)
142 {
143         struct msghdr msg={0};
144         struct cmsghdr *cmsg;
145         struct iovec iov;
146         char cmsgdata[CMSG_SPACE (sizeof(int)*3)];
147         int *fdptr;
148         
149         msg.msg_name=NULL;
150         msg.msg_namelen=0;
151         msg.msg_iov=&iov;
152         msg.msg_iovlen=1;
153         msg.msg_control=cmsgdata;
154         msg.msg_controllen=sizeof(cmsgdata);
155         msg.msg_flags=0;
156
157         iov.iov_base=req;
158         iov.iov_len=sizeof(WapiHandleRequest);
159
160         cmsg=CMSG_FIRSTHDR (&msg);
161         cmsg->cmsg_len=CMSG_LEN (sizeof(int)*3);
162         cmsg->cmsg_level=SOL_SOCKET;
163         cmsg->cmsg_type=SCM_RIGHTS;
164         fdptr=(int *)CMSG_DATA (cmsg);
165         fdptr[0]=in_fd;
166         fdptr[1]=out_fd;
167         fdptr[2]=err_fd;
168
169         msg.msg_controllen=CMSG_SPACE (sizeof(int)*3);
170
171         _wapi_daemon_request_response_internal (fd, &msg, resp);
172 }
173
174 /* Send request on fd, wait for response (called by applications, not
175  * the daemon)
176  */
177 void _wapi_daemon_request_response (int fd, WapiHandleRequest *req,
178                                     WapiHandleResponse *resp)
179 {
180         struct msghdr msg={0};
181         struct iovec iov;
182         
183         msg.msg_name=NULL;
184         msg.msg_namelen=0;
185         msg.msg_iov=&iov;
186         msg.msg_iovlen=1;
187         msg.msg_control=NULL;
188         msg.msg_controllen=0;
189         msg.msg_flags=0;
190
191         iov.iov_base=req;
192         iov.iov_len=sizeof(WapiHandleRequest);
193
194         _wapi_daemon_request_response_internal (fd, &msg, resp);
195 }
196
197 /* Read request on fd (called by the daemon) */
198 int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
199                           gboolean *has_fds)
200 {
201         int ret;
202         struct msghdr msg;
203         struct iovec iov;
204         struct cmsghdr *cmsg;
205         guchar cmsgdata[CMSG_SPACE (sizeof(int)*3)];
206         
207         msg.msg_name=NULL;
208         msg.msg_namelen=0;
209         msg.msg_iov=&iov;
210         msg.msg_iovlen=1;
211         msg.msg_control=cmsgdata;
212         msg.msg_controllen=sizeof(cmsgdata);
213         msg.msg_flags=0;
214         iov.iov_base=req;
215         iov.iov_len=sizeof(WapiHandleRequest);
216         
217         do {
218 #ifdef HAVE_MSG_NOSIGNAL
219                 ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
220 #else
221                 ret=recvmsg (fd, &msg, 0);
222 #endif
223         }
224         while (ret==-1 && errno==EINTR);
225
226         if(ret==-1 || ret!= sizeof(WapiHandleRequest)) {
227                 /* Make sure we dont do anything with this response */
228                 req->type=WapiHandleRequestType_Error;
229                 
230                 g_warning (G_GNUC_PRETTY_FUNCTION ": Recv error: %s",
231                            strerror (errno));
232                 /* The next loop around poll() should tidy up */
233         }
234
235 #ifdef DEBUG
236         if(msg.msg_flags & MSG_OOB) {
237                 g_message (G_GNUC_PRETTY_FUNCTION ": OOB data received");
238         }
239         if(msg.msg_flags & MSG_CTRUNC) {
240                 g_message (G_GNUC_PRETTY_FUNCTION ": ancillary data was truncated");
241         }
242         g_message (G_GNUC_PRETTY_FUNCTION ": msg.msg_controllen=%d",
243                    msg.msg_controllen);
244 #endif
245
246         cmsg=CMSG_FIRSTHDR (&msg);
247         if(cmsg!=NULL && cmsg->cmsg_level==SOL_SOCKET &&
248            cmsg->cmsg_type==SCM_RIGHTS) {
249                 LOGDEBUG (G_GNUC_PRETTY_FUNCTION ": cmsg->cmsg_len=%d", cmsg->cmsg_len);
250                 LOGDEBUG (G_GNUC_PRETTY_FUNCTION ": cmsg->level=%d cmsg->type=%d", cmsg->cmsg_level, cmsg->cmsg_type);
251
252                 memcpy (fds, (int *)CMSG_DATA (cmsg), sizeof(int)*3);
253                 *has_fds=TRUE;
254
255                 LOGDEBUG (G_GNUC_PRETTY_FUNCTION ": fd[0]=%d, fd[1]=%d, fd[2]=%d", fds[0], fds[1], fds[2]);
256         } else {
257                 LOGDEBUG (G_GNUC_PRETTY_FUNCTION ": no ancillary data");
258                 *has_fds=FALSE;
259         }
260
261         return(ret);
262 }
263
264 /* Send response on fd (called by the daemon) */
265 int _wapi_daemon_response (int fd, WapiHandleResponse *resp)
266 {
267         int ret;
268
269         do {
270 #ifdef HAVE_MSG_NOSIGNAL
271                 ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
272 #else
273                 ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
274 #endif
275         }
276         while (ret==-1 && errno==EINTR);
277
278 #ifdef DEBUG
279         if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
280                 g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
281                            strerror (errno));
282                 /* The next loop around poll() should tidy up */
283         }
284 #endif
285
286         return(ret);
287 }