? cygwin/cygserver_handle.cc ? cygwin/cygserver_handle.h Index: cygwin/Makefile.in =================================================================== RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v retrieving revision 1.94 diff -u -p -r1.94 Makefile.in --- cygwin/Makefile.in 22 Jun 2002 02:56:56 -0000 1.94 +++ cygwin/Makefile.in 26 Jun 2002 18:28:12 -0000 @@ -203,7 +203,7 @@ install-man: install_target: cygserver.exe $(INSTALL_PROGRAM) cygserver.exe $(bindir)/cygserver.exe - + install_host: @@ -322,7 +322,10 @@ cygserver_client_outside.o: cygserver_cl cygserver_shm.o: cygserver_shm.cc $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< -cygserver.exe: cygserver.o cygserver_shm.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o +cygserver_handle.o: cygserver_handle.cc + $(COMPILE_CXX) -D__OUTSIDE_CYGWIN__ -o $@ $< + +cygserver.exe: cygserver.o cygserver_shm.o cygserver_handle.o cygserver_transport_outside.o cygserver_transport_pipes_outside.o cygserver_transport_sockets_outside.o cygserver_client_outside.o cygserver_process.o threaded_queue.o wincap.o version.o smallprint.o $(CXX) -o $@ $^ #ifdef VERBOSE # $(CXX) $(MINGW_CXXFLAGS) -o $@ ${wordlist 1,3,$^} -B$(mingw_build)/ $(MINGW_LDFLAGS) Index: cygwin/cygserver.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/cygserver.cc,v retrieving revision 1.4 diff -u -p -r1.4 cygserver.cc --- cygwin/cygserver.cc 15 Mar 2002 21:52:05 -0000 1.4 +++ cygwin/cygserver.cc 26 Jun 2002 18:28:12 -0000 @@ -31,6 +31,7 @@ #include "cygwin/cygserver_process.h" #include "cygwin/cygserver.h" #include "cygserver_shm.h" +#include "cygserver_handle.h" /* for quieter operation, set to 0 */ #define DEBUG 0 @@ -364,6 +365,10 @@ server_request::process () req = new client_request_attach_tty (); break; case CYGSERVER_REQUEST_SHUTDOWN: req = new client_request_shutdown (); break; + case CYGSERVER_REQUEST_HOLD_HANDLE: + req = new client_request_hold_handle(); break; + case CYGSERVER_REQUEST_RELEASE_HANDLE: + req = new client_request_release_handle(); break; case CYGSERVER_REQUEST_SHM_GET: req = new client_request_shm (); break; default: Index: cygwin/cygserver_client.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/cygserver_client.cc,v retrieving revision 1.3 diff -u -p -r1.3 cygserver_client.cc --- cygwin/cygserver_client.cc 13 Mar 2002 02:34:03 -0000 1.3 +++ cygwin/cygserver_client.cc 26 Jun 2002 18:28:12 -0000 @@ -30,6 +30,7 @@ #include "cygwin/cygserver_transport_pipes.h" #include "cygwin/cygserver_transport_sockets.h" #include "cygwin/cygserver.h" +#include "cygserver_handle.h" /* 0 = untested, 1 = running, 2 = dead */ int cygserver_running=CYGSERVER_UNKNOWN; @@ -58,6 +59,23 @@ client_request_attach_tty::client_reques req.from_master = nfrom_master; req.to_master = nto_master; } + +client_request_hold_handle::client_request_hold_handle(DWORD pid, HANDLE from) : client_request(CYGSERVER_REQUEST_HOLD_HANDLE, sizeof(req)) +{ + buffer = (char*)&req; + req.pid = pid; + req.from_handle = from; + req.cygserver_handle = NULL; +} + +client_request_release_handle::client_request_release_handle(DWORD pid, HANDLE cyghandle) : client_request(CYGSERVER_REQUEST_RELEASE_HANDLE, sizeof(req)) +{ + buffer = (char*)&req; + req.pid = pid; + req.cygserver_handle = cyghandle; + req.to_handle = NULL; +} + client_request_shutdown::client_request_shutdown () : client_request (CYGSERVER_REQUEST_SHUTDOWN, 0) { Index: cygwin/net.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/net.cc,v retrieving revision 1.113 diff -u -p -r1.113 net.cc --- cygwin/net.cc 10 Jun 2002 19:58:19 -0000 1.113 +++ cygwin/net.cc 26 Jun 2002 18:28:13 -0000 @@ -34,6 +34,7 @@ details. */ #include "registry.h" #include "wsock_event.h" #include +#include "cygserver_handle.h" extern "C" { int h_errno; @@ -2474,66 +2475,266 @@ endhostent (void) { } +struct passfd { + unsigned int uiMagic; // Magic number to recognize header data + HANDLE hHandle; // Handle value valid in cygserver + BOOL bBinary; // Binary or Text mode + BOOL bRead; // Read access? + BOOL bWrite; // Write access? + int iDevice; // Device Type + int iAF; // If iDevice is FH_SOCKET Address Family of Socket +}; + + +// Currently only FH_PIPER, FH_PIPEW, and FH_SOCKET are supported +// Because of this bRead and bWrite are ignored. +// Socket name on AF_LOCAL will be set to "". +// Returns the fd or -1 if there's an error +static int +cygwin_handle_to_fd (HANDLE handle, struct passfd *fdp) +{ + DWORD myaccess = (fdp->bRead ? GENERIC_READ : 0) | (fdp->bWrite ? GENERIC_WRITE : 0); + int devn = fdp->iDevice & FH_DEVMASK; + + int fd = -1; + switch (devn) { + case FH_PIPER: + { + fd = cygheap->fdtab.find_unused_handle (); + fhandler_pipe *fhr = (fhandler_pipe *) + cygheap->fdtab.build_fhandler (fd,FH_PIPER, "/dev/piper"); + fhr->init (handle, GENERIC_READ, fdp->bBinary); + } + break; + case FH_PIPEW: + { + fd = cygheap->fdtab.find_unused_handle (); + fhandler_pipe *fhw = (fhandler_pipe *) + cygheap->fdtab.build_fhandler (fd, FH_PIPEW, "/dev/pipew"); + fhw->init (handle, GENERIC_WRITE, fdp->bBinary); + } + break; + case FH_SOCKET: + { + fd = cygheap->fdtab.find_unused_handle (); + const char *name; + int type; + + WSAPROTOCOL_INFO ProtInfo; + int size = sizeof(ProtInfo); + getsockopt((SOCKET)handle, SOL_SOCKET, + SO_PROTOCOL_INFO, (char*)&ProtInfo, &size); + + if (ProtInfo.iProtocol == IPPROTO_TCP) + type = SOCK_STREAM; + else // XXX are there any others Protocols? + type = SOCK_DGRAM; + + if (fdp->iAF == AF_INET) + name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp"); + else + name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket"); + + fhandler_socket* fh = (fhandler_socket *) + cygheap->fdtab.build_fhandler (fd, FH_SOCKET, name); + if (fh) + { + fh->set_io_handle (handle); + fh->set_flags (O_RDWR, O_BINARY); + fh->set_addr_family (fdp->iAF); + fh->set_socket_type (type); + } + } + break; + } + return fd; +} + + /* exported as recvmsg: standards? */ extern "C" int cygwin_recvmsg(int s, struct msghdr *msg, int flags) { - int ret, nb; - size_t tot = 0; - int i; - char *buf, *p; - struct iovec *iov = msg->msg_iov; - - for(i = 0; i < msg->msg_iovlen; ++i) - tot += iov[i].iov_len; - buf = (char *) malloc(tot); - if (tot != 0 && buf == NULL) + int ret, nb; + size_t tot = 0; + int i; + char *buf, *p; + struct iovec *iov = msg->msg_iov; + struct passfd fdp[1]; + int extradata = 0; + + for(i = 0; i < msg->msg_iovlen; ++i) + tot += iov[i].iov_len; + + if (msg->msg_accrightslen) + (*(int *)msg->msg_accrights) = -1; + + fhandler_socket *sock = get (s); + + if (sock && sock->get_addr_family () == AF_LOCAL) { + // We only worry about message headers under AF_LOCAL + // I know that using MSG_PEEK is considered incorrect sometimes, + // but not in this case because we're not trying to buffer data. + + // XXX - We need to add this check to the other recv calls so that + // they can strip off this extra data, i.e. somebody sends a descriptor, + // the other calls recv instead of recv_msg + + if (cygwin_recv(s, (char*) fdp, sizeof(fdp), MSG_PEEK) == sizeof (fdp) && + fdp->uiMagic == 0xAABBCCDD) { + extradata = sizeof(fdp); + + } + } + + buf = (char *) malloc(tot + extradata); + if (tot != 0 && buf == NULL) + { + errno = ENOMEM; + return -1; + } + + if (msg->msg_name) + nb = ret = cygwin_recvfrom (s, buf, tot + extradata, flags, + (struct sockaddr *) msg->msg_name, + (int *) &msg->msg_namelen); + else + nb = ret = cygwin_recv (s, buf, tot + extradata, flags); + + nb = nb - extradata; + + if (extradata) { + debug_printf("Handle in cygserver: 0x%X\n", fdp->hHandle); + client_request_release_handle *request = + new client_request_release_handle((DWORD) GetCurrentProcessId(), + (HANDLE) fdp->hHandle); + if (cygserver_request (request) == 0 && + request->header.error_code == 0) { - errno = ENOMEM; - return -1; + // We now have a handle that we want to turn into an fd. + debug_printf("Local Handle: 0x%X\n", request->to_handle()); + if (msg->msg_accrightslen) + { + (*(int *)msg->msg_accrights) = cygwin_handle_to_fd(request->to_handle(), fdp); + debug_printf("New fd: %d", (*(int *)msg->msg_accrights)); + } + else + { + // If the user didn't leave room for an fd just close the handle, we don't want extra handles floating around. + CloseHandle(request->to_handle()); + } } - nb = ret = cygwin_recvfrom (s, buf, tot, flags, - (struct sockaddr *) msg->msg_name, (int *) &msg->msg_namelen); - p = buf; - while (nb > 0) - { - ssize_t cnt = min(nb, iov->iov_len); + delete request; + } - memcpy (iov->iov_base, p, cnt); - p += cnt; - nb -= cnt; - ++iov; - } - free(buf); - return ret; + p = buf + extradata; + while (nb > 0) + { + ssize_t cnt = min(nb, iov->iov_len); + + memcpy (iov->iov_base, p, cnt); + p += cnt; + nb -= cnt; + ++iov; + } + free(buf); + return ret-extradata; } /* exported as sendmsg: standards? */ extern "C" int cygwin_sendmsg(int s, const struct msghdr *msg, int flags) { - int ret; - size_t tot = 0; - int i; - char *buf, *p; - struct iovec *iov = msg->msg_iov; - - for(i = 0; i < msg->msg_iovlen; ++i) - tot += iov[i].iov_len; - buf = (char *) malloc(tot); - if (tot != 0 && buf == NULL) - { - errno = ENOMEM; - return -1; - } - p = buf; - for (i = 0; i < msg->msg_iovlen; ++i) + int ret; + size_t tot = 0; + int i; + char *buf, *p; + struct iovec *iov = msg->msg_iov; + struct passfd fdp[1]; + int extradata = 0; + + fhandler_socket *sock = get (s); + syscall_printf ("send_msg (%d, %d, %d)", s, msg->msg_accrightslen, sock ? sock->get_addr_family(): -1); + + + if (msg->msg_accrightslen && sock && sock->get_addr_family () == AF_LOCAL) { + int wfd = *((int*) msg->msg_accrights); + + //fhandler_socket *h = get (wfd); + cygheap_fdget cfd (wfd); + syscall_printf("Sending socket: %d %u\n",wfd, cfd); + if (cfd) { - memcpy (p, iov[i].iov_base, iov[i].iov_len); - p += iov[i].iov_len; - } - ret = cygwin_sendto (s, buf, tot, flags, - (struct sockaddr *) msg->msg_name, msg->msg_namelen); - free (buf); - return ret; + debug_printf("Sending handle: 0x%X\n",cfd->get_handle()); + fdp->uiMagic = 0xAABBCCDD; + client_request_hold_handle *request = + new client_request_hold_handle((DWORD) GetCurrentProcessId(), + cfd->get_handle()); + int res = cygserver_request(request); + syscall_printf("Request: %d, %d\n", res, request->header.error_code); + if (res == 0 && request->header.error_code == 0) + { + fdp->hHandle = request->cygserver_handle(); + debug_printf("Handle in cygserver: 0x%X\n", fdp->hHandle); + fdp->bBinary = cfd->get_flags () & (O_BINARY | O_TEXT); + fdp->iDevice = cfd->get_device(); + fdp->bRead = 1; + fdp->bWrite =1; + + switch (fdp->iDevice) { + case FH_PIPER: + fdp->bWrite = 0; + break; + case FH_PIPEW: + fdp->bRead = 0; + break; + case FH_SOCKET: + fdp->iAF = cfd->is_socket()->get_addr_family (); + break; + default: + break; + } + extradata = sizeof (struct passfd); + } + delete request; + } + } + + for(i = 0; i < msg->msg_iovlen; ++i) + tot += iov[i].iov_len; + + buf = (char*) malloc (tot + extradata); + if (tot != 0 && buf == NULL) + { + errno = ENOMEM; + return -1; + } + + if (extradata) + memcpy (buf, fdp, sizeof (struct passfd)); + p = buf + extradata; + + for (i = 0; i < msg->msg_iovlen; ++i) + { + memcpy (p, iov[i].iov_base, iov[i].iov_len); + p += iov[i].iov_len; + } + if (msg->msg_name) + { + // Sending an OOB message makes winsock preserve message boundaries + if (extradata) + cygwin_sendto (s, "k", 1, MSG_OOB, (struct sockaddr *) msg->msg_name, + msg->msg_namelen); + ret = cygwin_sendto (s, buf, tot+ extradata, flags, + (struct sockaddr *) msg->msg_name, msg->msg_namelen); + } + else + { + // Sending an OOB message makes winsock preserve message boundaries + if (extradata) + cygwin_send (s, "k", 1, MSG_OOB); + ret = cygwin_send (s, buf, tot + extradata, flags); + } + free (buf); + return ret-extradata; } Index: cygwin/include/cygwin/cygserver.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/cygserver.h,v retrieving revision 1.3 diff -u -p -r1.3 cygserver.h --- cygwin/include/cygwin/cygserver.h 13 Mar 2002 02:34:05 -0000 1.3 +++ cygwin/include/cygwin/cygserver.h 26 Jun 2002 18:28:13 -0000 @@ -33,6 +33,8 @@ typedef enum { CYGSERVER_REQUEST_ATTACH_TTY, CYGSERVER_REQUEST_SHUTDOWN, CYGSERVER_REQUEST_SHM_GET, + CYGSERVER_REQUEST_HOLD_HANDLE, + CYGSERVER_REQUEST_RELEASE_HANDLE, CYGSERVER_REQUEST_LAST } cygserver_request_code; @@ -82,6 +84,27 @@ struct request_attach_tty __attribute__ ((packed)) #endif ; + +struct request_hold_handle +{ + DWORD pid; + HANDLE from_handle, cygserver_handle; +} +#ifdef __GNUC__ + __attribute__ ((packed)) +#endif +; + +struct request_release_handle +{ + DWORD pid; + HANDLE cygserver_handle, to_handle; +} +#ifdef __GNUC__ + __attribute__ ((packed)) +#endif +; + class client_request {