X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fdaemon-messages.c;h=c7c929cd348b4341b8be8c56d40730a3e237e875;hb=e3ff010fe311fd3487484bf1b6b61ed8c989077a;hp=1ee85e087e53f127bd3ea1b39674610470f29304;hpb=a4df47fdd4832437055f49598243fe619f932315;p=mono.git diff --git a/mono/io-layer/daemon-messages.c b/mono/io-layer/daemon-messages.c index 1ee85e087e5..c7c929cd348 100644 --- a/mono/io-layer/daemon-messages.c +++ b/mono/io-layer/daemon-messages.c @@ -1,31 +1,95 @@ +/* + * daemon-messages.c: Communications to and from the handle daemon + * + * Author: + * Dick Porter (dick@ximian.com) + * + * (C) 2002 Ximian, Inc. + */ + #include #include #include #include #include +#include +#include +/* Freebsd needs this included explicitly, but it doesn't hurt on Linux */ +#include + +#ifndef HAVE_MSG_NOSIGNAL +#include +#endif #include #include +/* Solaris doesn't define these */ +#ifndef CMSG_LEN +#define CMSG_LEN(size) (sizeof (struct cmsghdr) + (size)) +#endif +#ifndef CMSG_SPACE +#define CMSG_SPACE(size) (sizeof (struct cmsghdr) + (size)) +#endif + +static mono_mutex_t req_mutex; +static mono_once_t attr_key_once = MONO_ONCE_INIT; +static mono_mutexattr_t attr; + +static void attr_init (void) +{ + int ret; + + ret = mono_mutexattr_init (&attr); + g_assert (ret == 0); + + ret = mono_mutexattr_settype (&attr, MONO_MUTEX_RECURSIVE); + g_assert (ret == 0); + + ret = mono_mutex_init (&req_mutex, &attr); + g_assert (ret == 0); +} + /* Send request on fd, wait for response (called by applications, not - * the daemon) -*/ -void _wapi_daemon_request_response (int fd, WapiHandleRequest *req, - WapiHandleResponse *resp) + * the daemon, indirectly through _wapi_daemon_request_response and + * _wapi_daemon_request_response_with_fds) + */ +static void _wapi_daemon_request_response_internal (int fd, + struct msghdr *msg, + WapiHandleResponse *resp) { - static pthread_mutex_t req_mutex=PTHREAD_MUTEX_INITIALIZER; int ret; - +#ifndef HAVE_MSG_NOSIGNAL + void (*old_sigpipe)(int); +#endif + + mono_once (&attr_key_once, attr_init); + /* Serialise requests to the daemon from the same process. We * rely on request turnaround time being minimal anyway, so * performance shouldnt suffer from the mutex. */ - pthread_mutex_lock (&req_mutex); + pthread_cleanup_push ((void(*)(void *))mono_mutex_unlock_in_cleanup, + (void *)&req_mutex); + ret = mono_mutex_lock (&req_mutex); + g_assert (ret == 0); - ret=send (fd, req, sizeof(WapiHandleRequest), MSG_NOSIGNAL); +#ifdef HAVE_MSG_NOSIGNAL + do { + ret=sendmsg (fd, msg, MSG_NOSIGNAL); + } + while (ret==-1 && errno==EINTR); +#else + old_sigpipe = signal (SIGPIPE, SIG_IGN); + do { + ret=sendmsg (fd, msg, 0); + } + while (ret==-1 && errno==EINTR); +#endif + if(ret!=sizeof(WapiHandleRequest)) { if(errno==EPIPE) { - g_warning (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!"); + g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!"); exit (-1); } else { g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s", @@ -34,10 +98,22 @@ void _wapi_daemon_request_response (int fd, WapiHandleRequest *req, } } - ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL); +#ifdef HAVE_MSG_NOSIGNAL + do { + ret=recv (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL); + } + while (ret==-1 && errno==EINTR); +#else + do { + ret=recv (fd, resp, sizeof(WapiHandleResponse), 0); + } + while (ret==-1 && errno==EINTR); + signal (SIGPIPE, old_sigpipe); +#endif + if(ret==-1) { if(errno==EPIPE) { - g_warning (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!"); + g_critical (G_GNUC_PRETTY_FUNCTION ": The handle daemon vanished!"); exit (-1); } else { g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s", @@ -45,36 +121,176 @@ void _wapi_daemon_request_response (int fd, WapiHandleRequest *req, g_assert_not_reached (); } } + + ret = mono_mutex_unlock (&req_mutex); + g_assert (ret == 0); + + pthread_cleanup_pop (0); +} + +/* Send request on fd with filedescriptors, wait for response (called + * by applications, not the daemon) + */ +void _wapi_daemon_request_response_with_fds (int fd, WapiHandleRequest *req, + WapiHandleResponse *resp, + int in_fd, int out_fd, int err_fd) +{ + struct msghdr msg={0}; + struct cmsghdr *cmsg; + struct iovec iov; + char cmsgdata[CMSG_SPACE (sizeof(int)*3)]; + int *fdptr; + + msg.msg_name=NULL; + msg.msg_namelen=0; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=cmsgdata; + msg.msg_controllen=sizeof(cmsgdata); + msg.msg_flags=0; + + iov.iov_base=req; + iov.iov_len=sizeof(WapiHandleRequest); + + cmsg=CMSG_FIRSTHDR (&msg); + cmsg->cmsg_len=CMSG_LEN (sizeof(int)*3); + cmsg->cmsg_level=SOL_SOCKET; + cmsg->cmsg_type=SCM_RIGHTS; + fdptr=(int *)CMSG_DATA (cmsg); + fdptr[0]=in_fd; + fdptr[1]=out_fd; + fdptr[2]=err_fd; + + msg.msg_controllen=CMSG_SPACE (sizeof(int)*3); + + _wapi_daemon_request_response_internal (fd, &msg, resp); +} - pthread_mutex_unlock (&req_mutex); +/* Send request on fd, wait for response (called by applications, not + * the daemon) + */ +void _wapi_daemon_request_response (int fd, WapiHandleRequest *req, + WapiHandleResponse *resp) +{ + struct msghdr msg={0}; + struct iovec iov; + + msg.msg_name=NULL; + msg.msg_namelen=0; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=NULL; + msg.msg_controllen=0; + msg.msg_flags=0; + + iov.iov_base=req; + iov.iov_len=sizeof(WapiHandleRequest); + + _wapi_daemon_request_response_internal (fd, &msg, resp); } /* Read request on fd (called by the daemon) */ -void _wapi_daemon_request (int fd, WapiHandleRequest *req) +int _wapi_daemon_request (int fd, WapiHandleRequest *req, int *fds, + gboolean *has_fds) { int ret; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + guchar cmsgdata[CMSG_SPACE (sizeof(int)*3)]; - ret=recv (fd, req, sizeof(WapiHandleRequest), MSG_NOSIGNAL); - if(ret==-1) { + msg.msg_name=NULL; + msg.msg_namelen=0; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=cmsgdata; + msg.msg_controllen=sizeof(cmsgdata); + msg.msg_flags=0; + iov.iov_base=req; + iov.iov_len=sizeof(WapiHandleRequest); + + do { +#ifdef HAVE_MSG_NOSIGNAL + ret=recvmsg (fd, &msg, MSG_NOSIGNAL); +#else + ret=recvmsg (fd, &msg, 0); +#endif + } + while (ret==-1 && errno==EINTR); + + if(ret==-1 || ret!= sizeof(WapiHandleRequest)) { + /* Make sure we dont do anything with this response */ + req->type=WapiHandleRequestType_Error; + #ifdef DEBUG g_warning (G_GNUC_PRETTY_FUNCTION ": Recv error: %s", strerror (errno)); #endif /* The next loop around poll() should tidy up */ } + +#ifdef DEBUG + if(msg.msg_flags & MSG_OOB) { + g_message (G_GNUC_PRETTY_FUNCTION ": OOB data received"); + } + if(msg.msg_flags & MSG_CTRUNC) { + g_message (G_GNUC_PRETTY_FUNCTION ": ancillary data was truncated"); + } + g_message (G_GNUC_PRETTY_FUNCTION ": msg.msg_controllen=%d", + msg.msg_controllen); +#endif + + cmsg=CMSG_FIRSTHDR (&msg); + if(cmsg!=NULL && cmsg->cmsg_level==SOL_SOCKET && + cmsg->cmsg_type==SCM_RIGHTS) { +#ifdef DEBUG + g_message (G_GNUC_PRETTY_FUNCTION ": cmsg->cmsg_len=%d", + cmsg->cmsg_len); + g_message (G_GNUC_PRETTY_FUNCTION + ": cmsg->level=%d cmsg->type=%d", cmsg->cmsg_level, + cmsg->cmsg_type); +#endif + + memcpy (fds, (int *)CMSG_DATA (cmsg), sizeof(int)*3); + *has_fds=TRUE; + +#ifdef DEBUG + g_message (G_GNUC_PRETTY_FUNCTION + ": fd[0]=%d, fd[1]=%d, fd[2]=%d", fds[0], fds[1], + fds[2]); +#endif + } else { +#ifdef DEBUG + g_message (G_GNUC_PRETTY_FUNCTION ": no ancillary data"); +#endif + *has_fds=FALSE; + } + + return(ret); } /* Send response on fd (called by the daemon) */ -void _wapi_daemon_response (int fd, WapiHandleResponse *resp) +int _wapi_daemon_response (int fd, WapiHandleResponse *resp) { int ret; - - ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL); - if(ret==-1) { + + do { +#ifdef HAVE_MSG_NOSIGNAL + ret=send (fd, resp, sizeof(WapiHandleResponse), MSG_NOSIGNAL); +#else + ret=send (fd, resp, sizeof(WapiHandleResponse), 0); +#endif + } + while (ret==-1 && errno==EINTR); + #ifdef DEBUG + + if(ret==-1 || ret != sizeof(WapiHandleResponse)) { g_warning (G_GNUC_PRETTY_FUNCTION ": Send error: %s", strerror (errno)); -#endif /* The next loop around poll() should tidy up */ } +#endif + + return(ret); }