Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2000-10-27 13:50:33 +0400
committerCorinna Vinschen <corinna@vinschen.de>2000-10-27 13:50:33 +0400
commitafd5033d83e5871f96c15cd72d790692f643c4bd (patch)
tree5f00f39b22e5bd2d375aae794b94ef248f94b044 /winsup/cygwin/fhandler_socket.cc
parentdd4f0b2343d5b25894824635281fe88d85281824 (diff)
* fhandler_socket.cc: New file.
* Makefile.in: Add fhandler_socket.o to dependencies. * fhandler.h: Change comment. * net.cc Move all fhandler_socket methods to fhandler_socket.cc. * winsup.h: Add declaration for `ws2_32_handle'.
Diffstat (limited to 'winsup/cygwin/fhandler_socket.cc')
-rw-r--r--winsup/cygwin/fhandler_socket.cc310
1 files changed, 310 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
new file mode 100644
index 000000000..f859f0936
--- /dev/null
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -0,0 +1,310 @@
+/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.
+
+ Copyright 2000 Cygnus Solutions.
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+ details. */
+
+/* #define DEBUG_NEST_ON 1 */
+
+#define __INSIDE_CYGWIN_NET__
+
+#define Win32_Winsock
+#include "winsup.h"
+#include <errno.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <winsock2.h>
+#include "cygheap.h"
+#include "cygerrno.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "sigproc.h"
+
+/**********************************************************************/
+/* fhandler_socket */
+
+fhandler_socket::fhandler_socket (const char *name) :
+ fhandler_base (FH_SOCKET, name)
+{
+ set_cb (sizeof *this);
+ set_need_fork_fixup ();
+ prot_info_ptr = (LPWSAPROTOCOL_INFOA) cmalloc (HEAP_BUF,
+ sizeof (WSAPROTOCOL_INFOA));
+}
+
+fhandler_socket::~fhandler_socket ()
+{
+ if (prot_info_ptr)
+ cfree (prot_info_ptr);
+}
+
+void
+fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
+{
+ int ret = 1;
+
+ if (prot_info_ptr &&
+ (ret = WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr)))
+ {
+ debug_printf ("WSADuplicateSocket error");
+ set_winsock_errno ();
+ }
+ if (!ret && ws2_32_handle)
+ {
+ debug_printf ("WSADuplicateSocket went fine, dwServiceFlags1=%d",
+ prot_info_ptr->dwServiceFlags1);
+ }
+ else
+ {
+ fhandler_base::fixup_before_fork_exec (win_proc_id);
+ debug_printf ("Without Winsock 2.0");
+ }
+}
+
+void
+fhandler_socket::fixup_after_fork (HANDLE parent)
+{
+ SOCKET new_sock = INVALID_SOCKET;
+
+ debug_printf ("WSASocket begin, dwServiceFlags1=%d",
+ prot_info_ptr->dwServiceFlags1);
+ if (prot_info_ptr &&
+ (new_sock = WSASocketA (FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ prot_info_ptr, 0, 0)) == INVALID_SOCKET)
+ {
+ debug_printf ("WSASocket error");
+ set_winsock_errno ();
+ }
+ if (new_sock != INVALID_SOCKET && ws2_32_handle)
+ {
+ debug_printf ("WSASocket went fine");
+ set_io_handle ((HANDLE) new_sock);
+ }
+ else
+ {
+ fhandler_base::fixup_after_fork (parent);
+ debug_printf ("Without Winsock 2.0");
+ }
+}
+
+int
+fhandler_socket::dup (fhandler_base *child)
+{
+ fhandler_socket *fhs = (fhandler_socket *) child;
+ fhs->set_io_handle (get_io_handle ());
+ fhs->fixup_before_fork_exec (GetCurrentProcessId ());
+ if (ws2_32_handle)
+ {
+ fhs->fixup_after_fork (hMainProc);
+ return 0;
+ }
+ return fhandler_base::dup (child);
+}
+
+int
+fhandler_socket::read (void *ptr, size_t len)
+{
+ sigframe thisframe (mainthread);
+ int res = recv (get_socket (), (char *) ptr, len, 0);
+ if (res == SOCKET_ERROR)
+ {
+ set_winsock_errno ();
+ }
+ return res;
+}
+
+int
+fhandler_socket::write (const void *ptr, size_t len)
+{
+ sigframe thisframe (mainthread);
+ int res = send (get_socket (), (const char *) ptr, len, 0);
+ if (res == SOCKET_ERROR)
+ {
+ set_winsock_errno ();
+ if (get_errno () == ECONNABORTED || get_errno () == ECONNRESET)
+ _raise (SIGPIPE);
+ }
+ return res;
+}
+
+/* Cygwin internal */
+int
+fhandler_socket::close ()
+{
+ int res = 0;
+ sigframe thisframe (mainthread);
+
+ if (closesocket (get_socket ()))
+ {
+ set_winsock_errno ();
+ res = -1;
+ }
+
+ return res;
+}
+
+#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
+
+/* Cygwin internal */
+int
+fhandler_socket::ioctl (unsigned int cmd, void *p)
+{
+ extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */
+ int res;
+ struct ifconf *ifc;
+ struct ifreq *ifr;
+ sigframe thisframe (mainthread);
+
+ switch (cmd)
+ {
+ case SIOCGIFCONF:
+ ifc = (struct ifconf *) p;
+ if (ifc == 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ res = get_ifconf (ifc, cmd);
+ if (res)
+ debug_printf ("error in get_ifconf\n");
+ break;
+ case SIOCGIFFLAGS:
+ ifr = (struct ifreq *) p;
+ if (ifr == 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ ifr->ifr_flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING;
+ if (((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr
+ == INADDR_LOOPBACK)
+ ifr->ifr_flags |= IFF_LOOPBACK;
+ else
+ ifr->ifr_flags |= IFF_BROADCAST;
+ res = 0;
+ break;
+ case SIOCGIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCGIFADDR:
+ {
+ char buf[2048];
+ struct ifconf ifc;
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ struct ifreq *ifrp;
+
+ struct ifreq *ifr = (struct ifreq *) p;
+ if (ifr == 0)
+ {
+ debug_printf ("ifr == NULL\n");
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ res = get_ifconf (&ifc, cmd);
+ if (res)
+ {
+ debug_printf ("error in get_ifconf\n");
+ break;
+ }
+
+ debug_printf (" name: %s\n", ifr->ifr_name);
+ for (ifrp = ifc.ifc_req;
+ (caddr_t) ifrp < ifc.ifc_buf + ifc.ifc_len;
+ ++ifrp)
+ {
+ debug_printf ("testname: %s\n", ifrp->ifr_name);
+ if (! strcmp (ifrp->ifr_name, ifr->ifr_name))
+ {
+ switch (cmd)
+ {
+ case SIOCGIFADDR:
+ ifr->ifr_addr = ifrp->ifr_addr;
+ break;
+ case SIOCGIFBRDADDR:
+ ifr->ifr_broadaddr = ifrp->ifr_broadaddr;
+ break;
+ case SIOCGIFNETMASK:
+ ifr->ifr_netmask = ifrp->ifr_netmask;
+ break;
+ }
+ break;
+ }
+ }
+ if ((caddr_t) ifrp >= ifc.ifc_buf + ifc.ifc_len)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ break;
+ }
+ case FIOASYNC:
+ res = WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO,
+ *(int *) p ? ASYNC_MASK : 0);
+ syscall_printf ("Async I/O on socket %s",
+ *(int *) p ? "started" : "cancelled");
+ set_async (*(int *) p);
+ break;
+ default:
+ /* We must cancel WSAAsyncSelect (if any) before setting socket to
+ * blocking mode
+ */
+ if (cmd == FIONBIO && *(int *) p == 0)
+ WSAAsyncSelect (get_socket (), gethwnd (), 0, 0);
+ res = ioctlsocket (get_socket (), cmd, (unsigned long *) p);
+ if (res == SOCKET_ERROR)
+ set_winsock_errno ();
+ if (cmd == FIONBIO)
+ {
+ syscall_printf ("socket is now %sblocking",
+ *(int *) p ? "un" : "");
+ /* Start AsyncSelect if async socket unblocked */
+ if (*(int *) p && get_async ())
+ WSAAsyncSelect (get_socket (), gethwnd (), WM_ASYNCIO, ASYNC_MASK);
+ }
+ break;
+ }
+ syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p);
+ return res;
+}
+
+int
+fhandler_socket::fcntl (int cmd, void *arg)
+{
+ int res = 0;
+ int request, current;
+
+ switch (cmd)
+ {
+ case F_SETFL:
+ {
+ /* Care for the old O_NDELAY flag. If one of the flags is set,
+ both flags are set. */
+ int new_flags = (int) arg;
+ if (new_flags & (O_NONBLOCK | OLD_O_NDELAY))
+ new_flags |= O_NONBLOCK | OLD_O_NDELAY;
+ request = (new_flags & O_NONBLOCK) ? 1 : 0;
+ current = (get_flags () & O_NONBLOCK) ? 1 : 0;
+ if (request != current && (res = ioctl (FIONBIO, &request)))
+ break;
+ if (request)
+ set_flags (get_flags () | O_NONBLOCK | OLD_O_NDELAY);
+ else
+ set_flags (get_flags () & ~(O_NONBLOCK | OLD_O_NDELAY));
+ break;
+ }
+ default:
+ res = fhandler_base::fcntl (cmd, arg);
+ break;
+ }
+ return res;
+}
+