⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhandler_socket.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* fhandler_socket.cc. See fhandler.h for a description of the fhandler classes.   Copyright 2000, 2001, 2002 Red Hat, Inc.   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__#include "winsup.h"#include <errno.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/uio.h>#include <asm/byteorder.h>#include <stdlib.h>#define USE_SYS_TYPES_FD_SET#include <winsock2.h>#include "cygerrno.h"#include "security.h"#include "cygwin/version.h"#include "perprocess.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"#include "sigproc.h"#include "wsock_event.h"#include <unistd.h>#define SECRET_EVENT_NAME "cygwin.local_socket.secret.%d.%08x-%08x-%08x-%08x"#define ENTROPY_SOURCE_NAME "/dev/urandom"#define ENTROPY_SOURCE_DEV_UNIT 9extern fhandler_socket *fdsock (int& fd, const char *name, SOCKET soc);extern "C" {int sscanf (const char *, const char *, ...);} /* End of "C" section */fhandler_dev_random* entropy_source;/* cygwin internal: map sockaddr into internet domain address */static intget_inet_addr (const struct sockaddr *in, int inlen,	       struct sockaddr_in *out, int *outlen, int* secret = 0){  int secret_buf [4];  int* secret_ptr = (secret ? : secret_buf);  if (in->sa_family == AF_INET)    {      *out = * (sockaddr_in *)in;      *outlen = inlen;      return 1;    }  else if (in->sa_family == AF_LOCAL)    {      int fd = open (in->sa_data, O_RDONLY);      if (fd == -1)	return 0;      int ret = 0;      char buf[128];      memset (buf, 0, sizeof buf);      if (read (fd, buf, sizeof buf) != -1)	{	  sockaddr_in sin;	  sin.sin_family = AF_INET;	  sscanf (buf + strlen (SOCKET_COOKIE), "%hu %08x-%08x-%08x-%08x",		  &sin.sin_port,		  secret_ptr, secret_ptr + 1, secret_ptr + 2, secret_ptr + 3);	  sin.sin_port = htons (sin.sin_port);	  sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);	  *out = sin;	  *outlen = sizeof sin;	  ret = 1;	}      close (fd);      return ret;    }  else    {      set_errno (EAFNOSUPPORT);      return 0;    }}/**********************************************************************//* fhandler_socket */fhandler_socket::fhandler_socket ()  : fhandler_base (FH_SOCKET), sun_path (NULL){  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);  if (sun_path)    cfree (sun_path);}voidfhandler_socket::set_connect_secret (){  if (!entropy_source)    {      void *buf = malloc (sizeof (fhandler_dev_random));      entropy_source = new (buf) fhandler_dev_random (ENTROPY_SOURCE_DEV_UNIT);    }  if (entropy_source &&      !entropy_source->open (NULL, O_RDONLY))    {      delete entropy_source;      entropy_source = NULL;    }  if (!entropy_source ||      (entropy_source->read (connect_secret, sizeof (connect_secret)) !=					     sizeof (connect_secret)))    bzero ((char*) connect_secret, sizeof (connect_secret));}voidfhandler_socket::get_connect_secret (char* buf){  __small_sprintf (buf, "%08x-%08x-%08x-%08x",		   connect_secret [0], connect_secret [1],		   connect_secret [2], connect_secret [3]);}HANDLEfhandler_socket::create_secret_event (int* secret){  char buf [128];  int* secret_ptr = (secret ? : connect_secret);  struct sockaddr_in sin;  int sin_len = sizeof (sin);  if (::getsockname (get_socket (), (struct sockaddr*) &sin, &sin_len))    {      debug_printf ("error getting local socket name (%d)", WSAGetLastError ());      return NULL;    }  __small_sprintf (buf, SECRET_EVENT_NAME, sin.sin_port,		   secret_ptr [0], secret_ptr [1],		   secret_ptr [2], secret_ptr [3]);  LPSECURITY_ATTRIBUTES sec = get_inheritance (true);  secret_event = CreateEvent (sec, FALSE, FALSE, buf);  if (!secret_event && GetLastError () == ERROR_ALREADY_EXISTS)    secret_event = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);  if (!secret_event)    /* nothing to do */;  else if (sec == &sec_all_nih || sec == &sec_none_nih)    ProtectHandle (secret_event);  else    ProtectHandleINH (secret_event);  return secret_event;}voidfhandler_socket::signal_secret_event (){  if (!secret_event)    debug_printf ("no secret event?");  else    {      SetEvent (secret_event);      debug_printf ("signaled secret_event");    }}voidfhandler_socket::close_secret_event (){  if (secret_event)    ForceCloseHandle (secret_event);  secret_event = NULL;}intfhandler_socket::check_peer_secret_event (struct sockaddr_in* peer, int* secret){  char buf [128];  HANDLE ev;  int* secret_ptr = (secret ? : connect_secret);  __small_sprintf (buf, SECRET_EVENT_NAME, peer->sin_port,		  secret_ptr [0], secret_ptr [1],		  secret_ptr [2], secret_ptr [3]);  ev = CreateEvent (&sec_all_nih, FALSE, FALSE, buf);  if (!ev && GetLastError () == ERROR_ALREADY_EXISTS)    {      debug_printf ("event \"%s\" already exists", buf);      ev = OpenEvent (EVENT_ALL_ACCESS, FALSE, buf);    }  signal_secret_event ();  if (ev)    {      DWORD rc = WaitForSingleObject (ev, 10000);      debug_printf ("WFSO rc=%d", rc);      CloseHandle (ev);      return (rc == WAIT_OBJECT_0 ? 1 : 0 );    }  else    return 0;}voidfhandler_socket::fixup_before_fork_exec (DWORD win_proc_id){  if (!winsock2_active)    {      fhandler_base::fixup_before_fork_exec (win_proc_id);      debug_printf ("Without Winsock 2.0");    }  else if (!WSADuplicateSocketA (get_socket (), win_proc_id, prot_info_ptr))    debug_printf ("WSADuplicateSocket went fine, sock %p, win_proc_id %d, prot_info_ptr %p",		  get_socket (), win_proc_id, prot_info_ptr);  else    {      debug_printf ("WSADuplicateSocket error, sock %p, win_proc_id %d, prot_info_ptr %p",		    get_socket (), win_proc_id, prot_info_ptr);      set_winsock_errno ();    }}extern "C" void __stdcall load_wsock32 ();voidfhandler_socket::fixup_after_fork (HANDLE parent){  SOCKET new_sock;  debug_printf ("WSASocket begin, dwServiceFlags1=%d",		prot_info_ptr->dwServiceFlags1);  if ((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 ();    }  else if (!new_sock && !winsock2_active)    {      load_wsock32 ();      fhandler_base::fixup_after_fork (parent);      debug_printf ("Without Winsock 2.0");    }  else    {      debug_printf ("WSASocket went fine new_sock %p, old_sock %p", new_sock, get_io_handle ());      set_io_handle ((HANDLE) new_sock);    }  if (secret_event)    fork_fixup (parent, secret_event, "secret_event");}voidfhandler_socket::fixup_after_exec (HANDLE parent){  debug_printf ("here");  if (!get_close_on_exec ())    fixup_after_fork (parent);#if 0  else if (!winsock2_active)    closesocket (get_socket ());#endif}intfhandler_socket::dup (fhandler_base *child){  debug_printf ("here");  fhandler_socket *fhs = (fhandler_socket *) child;  fhs->addr_family = addr_family;  fhs->set_io_handle (get_io_handle ());  if (get_addr_family () == AF_LOCAL)    fhs->set_sun_path (get_sun_path ());  fhs->fixup_before_fork_exec (GetCurrentProcessId ());  if (winsock2_active)    {      fhs->fixup_after_fork (hMainProc);      return 0;    }  return fhandler_base::dup (child);}int __stdcallfhandler_socket::fstat (struct __stat64 *buf, path_conv *pc){  int res = fhandler_base::fstat (buf, pc);  if (!res)    {      buf->st_mode &= ~_IFMT;      buf->st_mode |= _IFSOCK;      buf->st_ino = (ino_t) get_handle ();    }  return res;}intfhandler_socket::bind (const struct sockaddr *name, int namelen){  int res = -1;  if (name->sa_family == AF_LOCAL)    {#define un_addr ((struct sockaddr_un *) name)      struct sockaddr_in sin;      int len = sizeof sin;      int fd;      if (strlen (un_addr->sun_path) >= UNIX_PATH_LEN)	{	  set_errno (ENAMETOOLONG);	  goto out;	}      sin.sin_family = AF_INET;      sin.sin_port = 0;      sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);      if (::bind (get_socket (), (sockaddr *) &sin, len))	{	  syscall_printf ("AF_LOCAL: bind failed %d", get_errno ());	  set_winsock_errno ();	  goto out;	}      if (::getsockname (get_socket (), (sockaddr *) &sin, &len))	{	  syscall_printf ("AF_LOCAL: getsockname failed %d", get_errno ());	  set_winsock_errno ();	  goto out;	}      sin.sin_port = ntohs (sin.sin_port);      debug_printf ("AF_LOCAL: socket bound to port %u", sin.sin_port);      /* bind must fail if file system socket object already exists	 so _open () is called with O_EXCL flag. */      fd = ::open (un_addr->sun_path, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0);      if (fd < 0)	{	  if (get_errno () == EEXIST)	    set_errno (EADDRINUSE);	  goto out;	}      set_connect_secret ();      char buf[sizeof (SOCKET_COOKIE) + 80];      __small_sprintf (buf, "%s%u ", SOCKET_COOKIE, sin.sin_port);      get_connect_secret (strchr (buf, '\0'));      len = strlen (buf) + 1;      /* Note that the terminating nul is written.  */      if (::write (fd, buf, len) != len)	{	  save_errno here;	  ::close (fd);	  unlink (un_addr->sun_path);	}      else	{	  ::close (fd);	  chmod (un_addr->sun_path,		 (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO) & ~cygheap->umask);	  set_sun_path (un_addr->sun_path);	  res = 0;	}#undef un_addr    }  else if (::bind (get_socket (), name, namelen))    set_winsock_errno ();  else    res = 0;out:  return res;}intfhandler_socket::connect (const struct sockaddr *name, int namelen){  int res = -1;  BOOL secret_check_failed = FALSE;  BOOL in_progress = FALSE;  sockaddr_in sin;  int secret [4];  if (!get_inet_addr (name, namelen, &sin, &namelen, secret))    return -1;  res = ::connect (get_socket (), (sockaddr *) &sin, namelen);  if (res)    {      /* Special handling for connect to return the correct error code	 when called on a non-blocking socket. */      if (is_nonblocking ())	{	  DWORD err = WSAGetLastError ();	  if (err == WSAEWOULDBLOCK || err == WSAEALREADY)	    {	      WSASetLastError (WSAEINPROGRESS);	      in_progress = TRUE;	    }	  else if (err == WSAEINVAL)	    WSASetLastError (WSAEISCONN);	}      set_winsock_errno ();    }  if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)    {      if (!res || in_progress)	{	  if (!create_secret_event (secret))	    {	      secret_check_failed = TRUE;	    }	  else if (in_progress)	    signal_secret_event ();	}      if (!secret_check_failed && !res)	{	  if (!check_peer_secret_event (&sin, secret))	    {	      debug_printf ( "accept from unauthorized server" );	      secret_check_failed = TRUE;	    }       }      if (secret_check_failed)	{	  close_secret_event ();	  if (res)	    closesocket (res);	  set_errno (ECONNREFUSED);	  res = -1;	}    }  if (WSAGetLastError () == WSAEINPROGRESS)    set_connect_state (CONNECT_PENDING);  else    set_connect_state (CONNECTED);  return res;}intfhandler_socket::listen (int backlog){  int res = ::listen (get_socket (), backlog);  if (res)    set_winsock_errno ();  else    set_connect_state (CONNECTED);  return res;}intfhandler_socket::accept (struct sockaddr *peer, int *len){  int res = -1;  WSAEVENT ev[2] = { WSA_INVALID_EVENT, signal_arrived };  BOOL secret_check_failed = FALSE;  BOOL in_progress = FALSE;  /* Allows NULL peer and len parameters. */  struct sockaddr_in peer_dummy;  int len_dummy;  if (!peer)    peer = (struct sockaddr *) &peer_dummy;  if (!len)    {      len_dummy = sizeof (struct sockaddr_in);      len = &len_dummy;    }  /* accept on NT fails if len < sizeof (sockaddr_in)   * some programs set len to   * sizeof (name.sun_family) + strlen (name.sun_path) for UNIX domain   */  if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))    *len = sizeof (struct sockaddr_in);  if (!is_nonblocking ())    {      ev[0] = WSACreateEvent ();      if (ev[0] != WSA_INVALID_EVENT &&	  !WSAEventSelect (get_socket (), ev[0], FD_ACCEPT))	{	  WSANETWORKEVENTS sock_event;	  int wait_result;	  wait_result = WSAWaitForMultipleEvents (2, ev, FALSE, WSA_INFINITE,						  FALSE);	  if (wait_result == WSA_WAIT_EVENT_0)	    WSAEnumNetworkEvents (get_socket (), ev[0], &sock_event);	  /* Unset events for listening socket and	     switch back to blocking mode */	  WSAEventSelect (get_socket (), ev[0], 0);	  unsigned long nonblocking = 0;	  ioctlsocket (get_socket (), FIONBIO, &nonblocking);	  switch (wait_result)	    {	    case WSA_WAIT_EVENT_0:	      if (sock_event.lNetworkEvents & FD_ACCEPT)		{		  if (sock_event.iErrorCode[FD_ACCEPT_BIT])		    {		      WSASetLastError (sock_event.iErrorCode[FD_ACCEPT_BIT]);		      set_winsock_errno ();		      res = -1;		      goto done;		    }		}	      /* else; : Should never happen since FD_ACCEPT is the only event		 that has been selected */	      break;	    case WSA_WAIT_EVENT_0 + 1:	      debug_printf ("signal received during accept");	      set_errno (EINTR);	      res = -1;	      goto done;	    case WSA_WAIT_FAILED:	    default: /* Should never happen */	      WSASetLastError (WSAEFAULT);	      set_winsock_errno ();	      res = -1;	      goto done;	    }	}    }  res = ::accept (get_socket (), peer, len);  if ((SOCKET) res == (SOCKET) INVALID_SOCKET &&      WSAGetLastError () == WSAEWOULDBLOCK)    in_progress = TRUE;  if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)    {      if ((SOCKET) res != (SOCKET) INVALID_SOCKET || in_progress)	{	  if (!create_secret_event ())	    secret_check_failed = TRUE;	  else if (in_progress)	    signal_secret_event ();	}      if (!secret_check_failed &&	  (SOCKET) res != (SOCKET) INVALID_SOCKET)	{	  if (!check_peer_secret_event ((struct sockaddr_in*) peer))	    {	      debug_printf ("connect from unauthorized client");	      secret_check_failed = TRUE;	    }	}      if (secret_check_failed)	{	  close_secret_event ();	  if ((SOCKET) res != (SOCKET) INVALID_SOCKET)	    closesocket (res);	  set_errno (ECONNABORTED);	  res = -1;	  goto done;	}    }  {    cygheap_fdnew res_fd;    if (res_fd < 0)      /* FIXME: what is correct errno? */;    else if ((SOCKET) res == (SOCKET) INVALID_SOCKET)      set_winsock_errno ();    else      {	fhandler_socket* res_fh = fdsock (res_fd, get_name (), res);	if (get_addr_family () == AF_LOCAL)	  res_fh->set_sun_path (get_sun_path ());	res_fh->set_addr_family (get_addr_family ());	res_fh->set_socket_type (get_socket_type ());	res = res_fd;      }  }done:  if (ev[0] != WSA_INVALID_EVENT)    WSACloseEvent (ev[0]);  return res;}intfhandler_socket::getsockname (struct sockaddr *name, int *namelen){  int res = -1;  if (get_addr_family () == AF_LOCAL)    {      struct sockaddr_un *sun = (struct sockaddr_un *) name;      memset (sun, 0, *namelen);      sun->sun_family = AF_LOCAL;      if (!get_sun_path ())	sun->sun_path[0] = '\0';      else	/* According to SUSv2 "If the actual length of the address is	   greater than the length of the supplied sockaddr structure, the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -