2008-10-26 Zoltan Varga <vargaz@gmail.com>
[mono-project.git] / mono / io-layer / daemon-messages.c
blobc7c929cd348b4341b8be8c56d40730a3e237e875
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 #include <sys/uio.h>
20 #ifndef HAVE_MSG_NOSIGNAL
21 #include <signal.h>
22 #endif
24 #include <mono/io-layer/wapi.h>
25 #include <mono/io-layer/daemon-messages.h>
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
35 static mono_mutex_t req_mutex;
36 static mono_once_t attr_key_once = MONO_ONCE_INIT;
37 static mono_mutexattr_t attr;
39 static void attr_init (void)
41 int ret;
43 ret = mono_mutexattr_init (&attr);
44 g_assert (ret == 0);
46 ret = mono_mutexattr_settype (&attr, MONO_MUTEX_RECURSIVE);
47 g_assert (ret == 0);
49 ret = mono_mutex_init (&req_mutex, &attr);
50 g_assert (ret == 0);
53 /* Send request on fd, wait for response (called by applications, not
54 * the daemon, indirectly through _wapi_daemon_request_response and
55 * _wapi_daemon_request_response_with_fds)
57 static void _wapi_daemon_request_response_internal (int fd,
58 struct msghdr *msg,
59 WapiHandleResponse *resp)
61 int ret;
62 #ifndef HAVE_MSG_NOSIGNAL
63 void (*old_sigpipe)(int);
64 #endif
66 mono_once (&attr_key_once, attr_init);
68 /* Serialise requests to the daemon from the same process. We
69 * rely on request turnaround time being minimal anyway, so
70 * performance shouldnt suffer from the mutex.
72 pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup,
73 (void *)&req_mutex);
74 ret = mono_mutex_lock (&req_mutex);
75 g_assert (ret == 0);
77 #ifdef HAVE_MSG_NOSIGNAL
78 do {
79 ret=sendmsg (fd, msg, MSG_NOSIGNAL);
81 while (ret==-1 && errno==EINTR);
82 #else
83 old_sigpipe = signal (SIGPIPE, SIG_IGN);
84 do {
85 ret=sendmsg (fd, msg, 0);
87 while (ret==-1 && errno==EINTR);
88 #endif
90 if(ret!=sizeof(WapiHandleRequest)) {
91 if(errno==EPIPE) {
92 g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
93 exit (-1);
94 } else {
95 g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
96 strerror (errno));
97 g_assert_not_reached ();
101 #ifdef HAVE_MSG_NOSIGNAL
102 do {
103 ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
105 while (ret==-1 && errno==EINTR);
106 #else
107 do {
108 ret=recv (fd, resp, sizeof(WapiHandleResponse), 0);
110 while (ret==-1 && errno==EINTR);
111 signal (SIGPIPE, old_sigpipe);
112 #endif
114 if(ret==-1) {
115 if(errno==EPIPE) {
116 g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!");
117 exit (-1);
118 } else {
119 g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
120 strerror (errno));
121 g_assert_not_reached ();
125 ret = mono_mutex_unlock (&req_mutex);
126 g_assert (ret == 0);
128 pthread_cleanup_pop (0);
131 /* Send request on fd with filedescriptors, wait for response (called
132 * by applications, not the daemon)
134 void _wapi_daemon_request_response_with_fds (int fd, WapiHandleRequest *req,
135 WapiHandleResponse *resp,
136 int in_fd, int out_fd, int err_fd)
138 struct msghdr msg={0};
139 struct cmsghdr *cmsg;
140 struct iovec iov;
141 char cmsgdata[CMSG_SPACE (sizeof(int)*3)];
142 int *fdptr;
144 msg.msg_name=NULL;
145 msg.msg_namelen=0;
146 msg.msg_iov=&iov;
147 msg.msg_iovlen=1;
148 msg.msg_control=cmsgdata;
149 msg.msg_controllen=sizeof(cmsgdata);
150 msg.msg_flags=0;
152 iov.iov_base=req;
153 iov.iov_len=sizeof(WapiHandleRequest);
155 cmsg=CMSG_FIRSTHDR (&msg);
156 cmsg->cmsg_len=CMSG_LEN (sizeof(int)*3);
157 cmsg->cmsg_level=SOL_SOCKET;
158 cmsg->cmsg_type=SCM_RIGHTS;
159 fdptr=(int *)CMSG_DATA (cmsg);
160 fdptr[0]=in_fd;
161 fdptr[1]=out_fd;
162 fdptr[2]=err_fd;
164 msg.msg_controllen=CMSG_SPACE (sizeof(int)*3);
166 _wapi_daemon_request_response_internal (fd, &msg, resp);
169 /* Send request on fd, wait for response (called by applications, not
170 * the daemon)
172 void _wapi_daemon_request_response (int fd, WapiHandleRequest *req,
173 WapiHandleResponse *resp)
175 struct msghdr msg={0};
176 struct iovec iov;
178 msg.msg_name=NULL;
179 msg.msg_namelen=0;
180 msg.msg_iov=&iov;
181 msg.msg_iovlen=1;
182 msg.msg_control=NULL;
183 msg.msg_controllen=0;
184 msg.msg_flags=0;
186 iov.iov_base=req;
187 iov.iov_len=sizeof(WapiHandleRequest);
189 _wapi_daemon_request_response_internal (fd, &msg, resp);
192 /* Read request on fd (called by the daemon) */
193 int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds,
194 gboolean *has_fds)
196 int ret;
197 struct msghdr msg;
198 struct iovec iov;
199 struct cmsghdr *cmsg;
200 guchar cmsgdata[CMSG_SPACE (sizeof(int)*3)];
202 msg.msg_name=NULL;
203 msg.msg_namelen=0;
204 msg.msg_iov=&iov;
205 msg.msg_iovlen=1;
206 msg.msg_control=cmsgdata;
207 msg.msg_controllen=sizeof(cmsgdata);
208 msg.msg_flags=0;
209 iov.iov_base=req;
210 iov.iov_len=sizeof(WapiHandleRequest);
212 do {
213 #ifdef HAVE_MSG_NOSIGNAL
214 ret=recvmsg (fd, &msg, MSG_NOSIGNAL);
215 #else
216 ret=recvmsg (fd, &msg, 0);
217 #endif
219 while (ret==-1 && errno==EINTR);
221 if(ret==-1 || ret!= sizeof(WapiHandleRequest)) {
222 /* Make sure we dont do anything with this response */
223 req->type=WapiHandleRequestType_Error;
225 #ifdef DEBUG
226 g_warning (G_GNUC_PRETTY_FUNCTION ": Recv error: %s",
227 strerror (errno));
228 #endif
229 /* The next loop around poll() should tidy up */
232 #ifdef DEBUG
233 if(msg.msg_flags & MSG_OOB) {
234 g_message (G_GNUC_PRETTY_FUNCTION ": OOB data received");
236 if(msg.msg_flags & MSG_CTRUNC) {
237 g_message (G_GNUC_PRETTY_FUNCTION ": ancillary data was truncated");
239 g_message (G_GNUC_PRETTY_FUNCTION ": msg.msg_controllen=%d",
240 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 #ifdef DEBUG
247 g_message (G_GNUC_PRETTY_FUNCTION ": cmsg->cmsg_len=%d",
248 cmsg->cmsg_len);
249 g_message (G_GNUC_PRETTY_FUNCTION
250 ": cmsg->level=%d cmsg->type=%d", cmsg->cmsg_level,
251 cmsg->cmsg_type);
252 #endif
254 memcpy (fds, (int *)CMSG_DATA (cmsg), sizeof(int)*3);
255 *has_fds=TRUE;
257 #ifdef DEBUG
258 g_message (G_GNUC_PRETTY_FUNCTION
259 ": fd[0]=%d, fd[1]=%d, fd[2]=%d", fds[0], fds[1],
260 fds[2]);
261 #endif
262 } else {
263 #ifdef DEBUG
264 g_message (G_GNUC_PRETTY_FUNCTION ": no ancillary data");
265 #endif
266 *has_fds=FALSE;
269 return(ret);
272 /* Send response on fd (called by the daemon) */
273 int _wapi_daemon_response (int fd, WapiHandleResponse *resp)
275 int ret;
277 do {
278 #ifdef HAVE_MSG_NOSIGNAL
279 ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL);
280 #else
281 ret=send (fd, resp, sizeof(WapiHandleResponse), 0);
282 #endif
284 while (ret==-1 && errno==EINTR);
286 #ifdef DEBUG
288 if(ret==-1 || ret != sizeof(WapiHandleResponse)) {
289 g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s",
290 strerror (errno));
291 /* The next loop around poll() should tidy up */
293 #endif
295 return(ret);