2010-02-13 Jb Evain <jbevain@novell.com>
[mono-project.git] / mono / io-layer / daemon-messages.c
blob812d435de5b7735dfc799e8b5d42c1017ef9a2d1
1 /*
2 * daemon-messages.c: Communications to and from the handle daemon
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 */
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
22 #ifndef HAVE_MSG_NOSIGNAL
23 #include <signal.h>
24 #endif
26 #include <mono/io-layer/wapi.h>
27 #include <mono/io-layer/daemon-messages.h>
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
37 #define LOGDEBUG(...)
38 // #define LOGDEBUG(...) g_message(__VA_ARGS__)
40 static mono_mutex_t req_mutex;
41 static mono_once_t attr_key_once = MONO_ONCE_INIT;
42 static mono_mutexattr_t attr;
44 static void attr_init (void)
46 int ret;
48 ret = mono_mutexattr_init (&attr);
49 g_assert (ret == 0);
51 ret = mono_mutexattr_settype (&attr, MONO_MUTEX_RECURSIVE);
52 g_assert (ret == 0);
54 ret = mono_mutex_init (&req_mutex, &attr);
55 g_assert (ret == 0);
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)
62 static void _wapi_daemon_request_response_internal (int fd,
63 struct msghdr *msg,
64 WapiHandleResponse *resp)
66 int ret;
67 #ifndef HAVE_MSG_NOSIGNAL
68 void (*old_sigpipe)(int);
69 #endif
71 mono_once (&attr_key_once, attr_init);
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.
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);
82 #ifdef HAVE_MSG_NOSIGNAL
83 do {
84 ret=sendmsg (fd, msg, MSG_NOSIGNAL);
86 while (ret==-1 && errno==EINTR);
87 #else
88 old_sigpipe = signal (SIGPIPE, SIG_IGN);
89 do {
90 ret=sendmsg (fd, msg, 0);
92 while (ret==-1 && errno==EINTR);
93 #endif
95 if(ret!=sizeof(WapiHandleRequest)) {
96 if(errno==EPIPE) {
97 g_critical ("%s: The handle daemon vanished!", __func__);
98 exit (-1);
99 } else {
100 g_warning ("%s: Send error: %s", __func__,
101 strerror (errno));
102 g_assert_not_reached ();
106 #ifdef HAVE_MSG_NOSIGNAL
107 do {
108 ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
110 while (ret==-1 && errno==EINTR);
111 #else
112 do {
113 ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
115 while (ret==-1 && errno==EINTR);
116 signal (SIGPIPE, old_sigpipe);
117 #endif
119 if(ret==-1) {
120 if(errno==EPIPE) {
121 g_critical ("%s: The handle daemon vanished!", __func__);
122 exit (-1);
123 } else {
124 g_warning ("%s: Send error: %s", __func__, strerror (errno));
125 g_assert_not_reached ();
129 ret = mono_mutex_unlock (&req_mutex);
130 g_assert (ret == 0);
132 pthread_cleanup_pop (0);
135 /* Send request on fd with filedescriptors, wait for response (called
136 * by applications, not the daemon)
138 void _wapi_daemon_request_response_with_fds (int fd, WapiHandleRequest *req,
139 WapiHandleResponse *resp,
140 int in_fd, int out_fd, int err_fd)
142 struct msghdr msg={0};
143 struct cmsghdr *cmsg;
144 struct iovec iov;
145 char cmsgdata[CMSG_SPACE (sizeof(int)*3)];
146 int *fdptr;
148 msg.msg_name=NULL;
149 msg.msg_namelen=0;
150 msg.msg_iov=&iov;
151 msg.msg_iovlen=1;
152 msg.msg_control=cmsgdata;
153 msg.msg_controllen=sizeof(cmsgdata);
154 msg.msg_flags=0;
156 iov.iov_base=req;
157 iov.iov_len=sizeof(WapiHandleRequest);
159 cmsg=CMSG_FIRSTHDR (&msg);
160 cmsg->cmsg_len=CMSG_LEN (sizeof(int)*3);
161 cmsg->cmsg_level=SOL_SOCKET;
162 cmsg->cmsg_type=SCM_RIGHTS;
163 fdptr=(int *)CMSG_DATA (cmsg);
164 fdptr[0]=in_fd;
165 fdptr[1]=out_fd;
166 fdptr[2]=err_fd;
168 msg.msg_controllen=CMSG_SPACE (sizeof(int)*3);
170 _wapi_daemon_request_response_internal (fd, &msg, resp);
173 /* Send request on fd, wait for response (called by applications, not
174 * the daemon)
176 void _wapi_daemon_request_response (int fd, WapiHandleRequest *req,
177 WapiHandleResponse *resp)
179 struct msghdr msg={0};
180 struct iovec iov;
182 msg.msg_name=NULL;
183 msg.msg_namelen=0;
184 msg.msg_iov=&iov;
185 msg.msg_iovlen=1;
186 msg.msg_control=NULL;
187 msg.msg_controllen=0;
188 msg.msg_flags=0;
190 iov.iov_base=req;
191 iov.iov_len=sizeof(WapiHandleRequest);
193 _wapi_daemon_request_response_internal (fd, &msg, resp);
196 /* Read request on fd (called by the daemon) */
197 int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
198 gboolean *has_fds)
200 int ret;
201 struct msghdr msg;
202 struct iovec iov;
203 struct cmsghdr *cmsg;
204 guchar cmsgdata[CMSG_SPACE (sizeof(int)*3)];
206 msg.msg_name=NULL;
207 msg.msg_namelen=0;
208 msg.msg_iov=&iov;
209 msg.msg_iovlen=1;
210 msg.msg_control=cmsgdata;
211 msg.msg_controllen=sizeof(cmsgdata);
212 msg.msg_flags=0;
213 iov.iov_base=req;
214 iov.iov_len=sizeof(WapiHandleRequest);
216 do {
217 #ifdef HAVE_MSG_NOSIGNAL
218 ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
219 #else
220 ret=recvmsg (fd, &msg, 0);
221 #endif
223 while (ret==-1 && errno==EINTR);
225 if(ret==-1 || ret!= sizeof(WapiHandleRequest)) {
226 /* Make sure we dont do anything with this response */
227 req->type=WapiHandleRequestType_Error;
229 g_warning ("%s: Recv error: %s", __func__, strerror (errno));
230 /* The next loop around poll() should tidy up */
233 #ifdef DEBUG
234 if(msg.msg_flags & MSG_OOB) {
235 g_message ("%s: OOB data received", __func__);
237 if(msg.msg_flags & MSG_CTRUNC) {
238 g_message ("%s: ancillary data was truncated", __func__);
240 g_message ("%s: msg.msg_controllen=%d", __func__, msg.msg_controllen);
241 #endif
243 cmsg=CMSG_FIRSTHDR (&msg);
244 if(cmsg!=NULL && cmsg->cmsg_level==SOL_SOCKET &&
245 cmsg->cmsg_type==SCM_RIGHTS) {
246 LOGDEBUG ("%s: cmsg->cmsg_len=%d", __func__, cmsg->cmsg_len);
247 LOGDEBUG ("%s: cmsg->level=%d cmsg->type=%d", __func__, cmsg->cmsg_level, cmsg->cmsg_type);
249 memcpy (fds, (int *)CMSG_DATA (cmsg), sizeof(int)*3);
250 *has_fds=TRUE;
252 LOGDEBUG ("%s: fd[0]=%d, fd[1]=%d, fd[2]=%d", __func__, fds[0], fds[1], fds[2]);
253 } else {
254 LOGDEBUG ("%s: no ancillary data", __func__);
255 *has_fds=FALSE;
258 return(ret);
261 /* Send response on fd (called by the daemon) */
262 int _wapi_daemon_response (int fd, WapiHandleResponse *resp)
264 int ret;
266 do {
267 #ifdef HAVE_MSG_NOSIGNAL
268 ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
269 #else
270 ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
271 #endif
273 while (ret==-1 && errno==EINTR);
275 #ifdef DEBUG
276 if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
277 g_warning ("%s: Send error: %s", __func__, strerror (errno));
278 /* The next loop around poll() should tidy up */
280 #endif
282 return(ret);