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