updated browser capabilities file
[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 #include <sys/uio.h>
19
20 #ifndef HAVE_MSG_NOSIGNAL
21 #include <signal.h>
22 #endif
23
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/daemon-messages.h>
26
27 /* Solaris doesn't define these */
28 #ifndef CMSG_LEN
29 #define CMSG_LEN(size)    (sizeof (struct cmsghdr) + (size))
30 #endif
31 #ifndef CMSG_SPACE
32 #define CMSG_SPACE(size)  (sizeof (struct cmsghdr) + (size))
33 #endif
34
35 /* Send request on fd, wait for response (called by applications, not
36  * the daemon, indirectly through _wapi_daemon_request_response and
37  * _wapi_daemon_request_response_with_fds)
38  */
39 static void _wapi_daemon_request_response_internal (int fd,
40                                                     struct msghdr *msg,
41                                                     WapiHandleResponse *resp)
42 {
43         static pthread_mutex_t req_mutex=PTHREAD_MUTEX_INITIALIZER;
44         int ret;
45 #ifndef HAVE_MSG_NOSIGNAL
46         void (*old_sigpipe)(int);
47 #endif
48
49         /* Serialise requests to the daemon from the same process.  We
50          * rely on request turnaround time being minimal anyway, so
51          * performance shouldnt suffer from the mutex.
52          */
53         pthread_mutex_lock (&req_mutex);
54         
55 #ifdef HAVE_MSG_NOSIGNAL
56         ret=sendmsg (fd, msg, MSG_NOSIGNAL);
57 #else
58         old_sigpipe = signal (SIGPIPE, SIG_IGN);
59         ret=sendmsg (fd, msg, 0);
60 #endif
61         if(ret!=sizeof(WapiHandleRequest)) {
62                 if(errno==EPIPE) {
63                         g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
64                         exit (-1);
65                 } else {
66                         g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
67                                    strerror (errno));
68                         g_assert_not_reached ();
69                 }
70         }
71
72 #ifdef HAVE_MSG_NOSIGNAL
73         ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
74 #else
75         ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
76         signal (SIGPIPE, old_sigpipe);
77 #endif
78         if(ret==-1) {
79                 if(errno==EPIPE) {
80                         g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
81                         exit (-1);
82                 } else {
83                         g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
84                                    strerror (errno));
85                         g_assert_not_reached ();
86                 }
87         }
88
89         pthread_mutex_unlock (&req_mutex);
90 }
91
92 /* Send request on fd with filedescriptors, wait for response (called
93  * by applications, not the daemon)
94  */
95 void _wapi_daemon_request_response_with_fds (int fd, WapiHandleRequest *req,
96                                              WapiHandleResponse *resp,
97                                              int in_fd, int out_fd, int err_fd)
98 {
99         struct msghdr msg={0};
100         struct cmsghdr *cmsg;
101         struct iovec iov;
102         char cmsgdata[CMSG_SPACE (sizeof(int)*3)];
103         int *fdptr;
104         
105         msg.msg_name=NULL;
106         msg.msg_namelen=0;
107         msg.msg_iov=&iov;
108         msg.msg_iovlen=1;
109         msg.msg_control=cmsgdata;
110         msg.msg_controllen=sizeof(cmsgdata);
111         msg.msg_flags=0;
112
113         iov.iov_base=req;
114         iov.iov_len=sizeof(WapiHandleRequest);
115
116         cmsg=CMSG_FIRSTHDR (&msg);
117         cmsg->cmsg_len=CMSG_LEN (sizeof(int)*3);
118         cmsg->cmsg_level=SOL_SOCKET;
119         cmsg->cmsg_type=SCM_RIGHTS;
120         fdptr=(int *)CMSG_DATA (cmsg);
121         fdptr[0]=in_fd;
122         fdptr[1]=out_fd;
123         fdptr[2]=err_fd;
124
125         msg.msg_controllen=CMSG_SPACE (sizeof(int)*3);
126
127         _wapi_daemon_request_response_internal (fd, &msg, resp);
128 }
129
130 /* Send request on fd, wait for response (called by applications, not
131  * the daemon)
132  */
133 void _wapi_daemon_request_response (int fd, WapiHandleRequest *req,
134                                     WapiHandleResponse *resp)
135 {
136         struct msghdr msg={0};
137         struct iovec iov;
138         
139         msg.msg_name=NULL;
140         msg.msg_namelen=0;
141         msg.msg_iov=&iov;
142         msg.msg_iovlen=1;
143         msg.msg_control=NULL;
144         msg.msg_controllen=0;
145         msg.msg_flags=0;
146
147         iov.iov_base=req;
148         iov.iov_len=sizeof(WapiHandleRequest);
149
150         _wapi_daemon_request_response_internal (fd, &msg, resp);
151 }
152
153 /* Read request on fd (called by the daemon) */
154 int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
155                           gboolean *has_fds)
156 {
157         int ret;
158         struct msghdr msg;
159         struct iovec iov;
160         struct cmsghdr *cmsg;
161         guchar cmsgdata[CMSG_SPACE (sizeof(int)*3)];
162         
163         msg.msg_name=NULL;
164         msg.msg_namelen=0;
165         msg.msg_iov=&iov;
166         msg.msg_iovlen=1;
167         msg.msg_control=cmsgdata;
168         msg.msg_controllen=sizeof(cmsgdata);
169         msg.msg_flags=0;
170         iov.iov_base=req;
171         iov.iov_len=sizeof(WapiHandleRequest);
172         
173 #ifdef HAVE_MSG_NOSIGNAL
174         ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
175 #else
176         ret=recvmsg (fd, &msg, 0);
177 #endif
178         if(ret==-1 || ret!= sizeof(WapiHandleRequest)) {
179                 /* Make sure we dont do anything with this response */
180                 req->type=WapiHandleRequestType_Error;
181                 
182 #ifdef DEBUG
183                 g_warning (G_GNUC_PRETTY_FUNCTION ": Recv error: %s",
184                            strerror (errno));
185 #endif
186                 /* The next loop around poll() should tidy up */
187         }
188
189 #ifdef DEBUG
190         if(msg.msg_flags & MSG_OOB) {
191                 g_message (G_GNUC_PRETTY_FUNCTION ": OOB data received");
192         }
193         if(msg.msg_flags & MSG_CTRUNC) {
194                 g_message (G_GNUC_PRETTY_FUNCTION ": ancillary data was truncated");
195         }
196         g_message (G_GNUC_PRETTY_FUNCTION ": msg.msg_controllen=%d",
197                    msg.msg_controllen);
198 #endif
199
200         cmsg=CMSG_FIRSTHDR (&msg);
201         if(cmsg!=NULL && cmsg->cmsg_level==SOL_SOCKET &&
202            cmsg->cmsg_type==SCM_RIGHTS) {
203 #ifdef DEBUG
204                 g_message (G_GNUC_PRETTY_FUNCTION ": cmsg->cmsg_len=%d",
205                            cmsg->cmsg_len);
206                 g_message (G_GNUC_PRETTY_FUNCTION
207                            ": cmsg->level=%d cmsg->type=%d", cmsg->cmsg_level,
208                            cmsg->cmsg_type);
209 #endif
210
211                 memcpy (fds, (int *)CMSG_DATA (cmsg), sizeof(int)*3);
212                 *has_fds=TRUE;
213
214 #ifdef DEBUG
215                 g_message (G_GNUC_PRETTY_FUNCTION
216                            ": fd[0]=%d, fd[1]=%d, fd[2]=%d", fds[0], fds[1],
217                            fds[2]);
218 #endif
219         } else {
220 #ifdef DEBUG
221                 g_message (G_GNUC_PRETTY_FUNCTION ": no ancillary data");
222 #endif
223                 *has_fds=FALSE;
224         }
225
226         return(ret);
227 }
228
229 /* Send response on fd (called by the daemon) */
230 int _wapi_daemon_response (int fd, WapiHandleResponse *resp)
231 {
232         int ret;
233         
234 #ifdef HAVE_MSG_NOSIGNAL
235         ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
236 #else
237         ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
238 #endif
239 #ifdef DEBUG
240         if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
241                 g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
242                            strerror (errno));
243                 /* The next loop around poll() should tidy up */
244         }
245 #endif
246
247         return(ret);
248 }