newlib/winsup/cygwin/net.cc

1868 lines
43 KiB
C++
Raw Normal View History

2000-02-17 20:38:33 +01:00
/* net.cc: network-related routines.
Copyright 1996, 1997, 1998, 1999, 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"
2000-02-17 20:38:33 +01:00
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
* include/cygwin/version.h: Bump DLL minor version number to 5 due to all of the changes below. Redefine process structure to avoid a fixed size table. Redefine pinfo/_pinfo classes. Use these throughout. * dcrt0.cc (dll_crt0_1): Accomodate set_myself argument change. (__api_fatal): Accomodate _pinfo::record_death argument change. * exceptions.cc (really_exit): Ditto. (sig_handle_tty_stop): Use pinfo constructor to access process info. (events_init): Don't create pinfo_mutex since it is no longer required. * external.cc (fillout_pinfo): Use winpids class to iterate over all system pids. (cygwin_internal): lock_pinfo_for_update and unlock_pinfo are now noops. * fhandler_termios.cc (fhandler_termios::set_ctty): Use pinfo constructor to access process info. * fork.cc (fork): Reorganize to initialize child info after the child has started since that is when we know the child's winpid, which is necessary to allocate the pinfo shared memory. * mmap.cc (recreate_mmaps_after_fork): Change arg type to _pinfo. * pinfo.cc: Rename pinfo methods to _pinfo throughout. Eliminate pinfo_list stuff. (set_myself): Accept a pid argument now. Call pinfo initializer to initialize myself. Detect when this is an "execed" process and create an "indirect" pid block. (pinfo_init): Accomodate set_myself arg change. (procinfo): Remove. (pinfo::lock_pinfo): Remove. (pinfo::unlock_pinfo): Remove. (pinfo::init): New method. Allocates shared memory space for process pinfo structure. (pinfo::record_death): Don't call locking functions. (cygwin_winpid_to_pid): Simplify by using new pinfo constructor. (EnumProcessesW95): New function for iterating over processes on Windows 95. (winpids::winpids): New constructor for winpids class. Sets up a list of process ids. (enum_init): Initialize w95/wnt pid enumerators. * shared.cc (shared-info::initialize): Remove pid initialization. * shared.h: Move pinfo stuff into pinfo.h. (class shared_info): Remove pinfo_list element. * signal.cc (kill_worker): Use pinfo constructor to access process info. (kill_pgrp): Ditto. Use winpids methods to access list of processes. * sigproc.cc: Throughout, modify to use _pinfo where appropriate. (proc_exists (pid_t)): New function. Determines if a process exists based on the pid. (proc_exists (_pinfo *p): Use new proc_exists function above. (proc_subproc): Copy pinfo stuff around rather than _pinfo pointers. Try to be careful about releasing shared memory when we don't need it anymore. Remove pinfo locks. (remove_zombies): Remove pinfo memory when zombie is going away. * sigproc.h: Reflect _pinfo/pinfo changes in sigproc.cc. * spawn.cc (spawn_guts): Eliminate pinfo *child argument. Reorganize to only initialize child pinfo after process has been started and we know the windows pid. (_spawnve): Reflect spawn_guts changes. * syscalls.cc (setpgid): Use pinfo constructor to access process info. (getpgid): Ditto. (internal_getlogin): Use _pinfo. * winsup.h: Eliminate pinfo_mutex. Eliminate spawn_guts declaration since it is static now. Reflect set_myself argument change. * include/sys/cygwin.h: Add some PID_* enums to accomodate new pinfo stuff. * include/cygwin/version.h: Update minor version for cygdrive changes below.
2000-07-29 18:24:59 +02:00
#include <unistd.h>
2000-02-17 20:38:33 +01:00
#include <netdb.h>
#include <fcntl.h>
#include "autoload.h"
#include <winsock.h>
#include "cygerrno.h"
#include "fhandler.h"
#include "path.h"
#include "dtable.h"
#include "thread.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
2000-02-17 20:38:33 +01:00
/* We only want to initialize WinSock in a child process if socket
handles are inheritted. This global allows us to know whether this
should be done or not */
int number_of_sockets = 0;
extern "C"
{
int h_errno;
int __stdcall rcmd (char **ahost, unsigned short inport, char *locuser,
char *remuser, char *cmd, SOCKET *fd2p);
int __stdcall rexec (char **ahost, unsigned short inport, char *locuser,
char *password, char *cmd, SOCKET *fd2p);
int __stdcall rresvport (int *);
int sscanf (const char *, const char *, ...);
} /* End of "C" section */
/* Cygwin internal */
static SOCKET
duplicate_socket (SOCKET sock)
{
/* Do not duplicate socket on Windows NT because of problems with
MS winsock proxy server.
*/
if (os_being_run == winNT)
return sock;
SOCKET newsock;
if (DuplicateHandle (hMainProc, (HANDLE) sock, hMainProc, (HANDLE *) &newsock,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
closesocket (sock);
sock = newsock;
}
else
small_printf ("DuplicateHandle failed %E");
return sock;
}
/* htonl: standards? */
extern "C"
unsigned long int
htonl (unsigned long int x)
{
MARK ();
return ((((x & 0x000000ffU) << 24) |
((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) |
((x & 0xff000000U) >> 24)));
}
/* ntohl: standards? */
extern "C"
unsigned long int
ntohl (unsigned long int x)
{
return htonl (x);
}
/* htons: standards? */
extern "C"
unsigned short
htons (unsigned short x)
{
MARK ();
return ((((x & 0x000000ffU) << 8) |
((x & 0x0000ff00U) >> 8)));
}
/* ntohs: standards? */
extern "C"
unsigned short
ntohs (unsigned short x)
{
return htons (x);
}
/* Cygwin internal */
static void
dump_protoent (struct protoent *p)
{
if (p)
debug_printf ("protoent %s %x %x", p->p_name, p->p_aliases, p->p_proto);
}
/* exported as inet_ntoa: standards? */
extern "C"
char *
cygwin_inet_ntoa (struct in_addr in)
{
char *res = inet_ntoa (in);
return res;
}
/* exported as inet_addr: standards? */
extern "C"
unsigned long
cygwin_inet_addr (const char *cp)
{
unsigned long res = inet_addr (cp);
return res;
}
/* undocumented in wsock32.dll */
extern "C" unsigned int WINAPI inet_network (const char *);
extern "C"
unsigned int
cygwin_inet_network (const char *cp)
{
unsigned int res = inet_network (cp);
return res;
}
2000-02-17 20:38:33 +01:00
/* inet_netof is in the standard BSD sockets library. It is useless
for modern networks, since it assumes network values which are no
longer meaningful, but some existing code calls it. */
extern "C"
unsigned long
inet_netof (struct in_addr in)
{
unsigned long i, res;
i = ntohl (in.s_addr);
if (IN_CLASSA (i))
res = (i & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT;
else if (IN_CLASSB (i))
res = (i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT;
else
res = (i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT;
return res;
}
/* inet_makeaddr is in the standard BSD sockets library. It is
useless for modern networks, since it assumes network values which
are no longer meaningful, but some existing code calls it. */
extern "C"
struct in_addr
inet_makeaddr (int net, int lna)
{
unsigned long i;
struct in_addr in;
if (net < IN_CLASSA_MAX)
i = (net << IN_CLASSA_NSHIFT) | (lna & IN_CLASSA_HOST);
else if (net < IN_CLASSB_MAX)
i = (net << IN_CLASSB_NSHIFT) | (lna & IN_CLASSB_HOST);
else if (net < 0x1000000)
i = (net << IN_CLASSC_NSHIFT) | (lna & IN_CLASSC_HOST);
else
i = net | lna;
in.s_addr = htonl (i);
return in;
}
struct tl
{
int w;
const char *s;
int e;
};
static struct tl errmap[] =
{
{WSAEWOULDBLOCK, "WSAEWOULDBLOCK", EWOULDBLOCK},
{WSAEINPROGRESS, "WSAEINPROGRESS", EINPROGRESS},
{WSAEALREADY, "WSAEALREADY", EALREADY},
{WSAENOTSOCK, "WSAENOTSOCK", ENOTSOCK},
{WSAEDESTADDRREQ, "WSAEDESTADDRREQ", EDESTADDRREQ},
{WSAEMSGSIZE, "WSAEMSGSIZE", EMSGSIZE},
{WSAEPROTOTYPE, "WSAEPROTOTYPE", EPROTOTYPE},
{WSAENOPROTOOPT, "WSAENOPROTOOPT", ENOPROTOOPT},
{WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", EPROTONOSUPPORT},
{WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", ESOCKTNOSUPPORT},
{WSAEOPNOTSUPP, "WSAEOPNOTSUPP", EOPNOTSUPP},
{WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", EPFNOSUPPORT},
{WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", EAFNOSUPPORT},
{WSAEADDRINUSE, "WSAEADDRINUSE", EADDRINUSE},
{WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", EADDRNOTAVAIL},
{WSAENETDOWN, "WSAENETDOWN", ENETDOWN},
{WSAENETUNREACH, "WSAENETUNREACH", ENETUNREACH},
{WSAENETRESET, "WSAENETRESET", ENETRESET},
{WSAECONNABORTED, "WSAECONNABORTED", ECONNABORTED},
{WSAECONNRESET, "WSAECONNRESET", ECONNRESET},
{WSAENOBUFS, "WSAENOBUFS", ENOBUFS},
{WSAEISCONN, "WSAEISCONN", EISCONN},
{WSAENOTCONN, "WSAENOTCONN", ENOTCONN},
{WSAESHUTDOWN, "WSAESHUTDOWN", ESHUTDOWN},
{WSAETOOMANYREFS, "WSAETOOMANYREFS", ETOOMANYREFS},
{WSAETIMEDOUT, "WSAETIMEDOUT", ETIMEDOUT},
{WSAECONNREFUSED, "WSAECONNREFUSED", ECONNREFUSED},
{WSAELOOP, "WSAELOOP", ELOOP},
{WSAENAMETOOLONG, "WSAENAMETOOLONG", ENAMETOOLONG},
{WSAEHOSTDOWN, "WSAEHOSTDOWN", EHOSTDOWN},
{WSAEHOSTUNREACH, "WSAEHOSTUNREACH", EHOSTUNREACH},
{WSAENOTEMPTY, "WSAENOTEMPTY", ENOTEMPTY},
{WSAEPROCLIM, "WSAEPROCLIM", EPROCLIM},
{WSAEUSERS, "WSAEUSERS", EUSERS},
{WSAEDQUOT, "WSAEDQUOT", EDQUOT},
{WSAESTALE, "WSAESTALE", ESTALE},
{WSAEREMOTE, "WSAEREMOTE", EREMOTE},
{WSAEINVAL, "WSAEINVAL", EINVAL},
{WSAEFAULT, "WSAEFAULT", EFAULT},
{0, NULL, 0}
2000-02-17 20:38:33 +01:00
};
/* Cygwin internal */
void
set_winsock_errno ()
{
int i;
int why = WSAGetLastError ();
for (i = 0; errmap[i].w != 0; ++i)
if (why == errmap[i].w)
break;
if (errmap[i].w != 0)
{
syscall_printf ("%d (%s) -> %d", why, errmap[i].s, errmap[i].e);
set_errno (errmap[i].e);
}
else
{
syscall_printf ("unknown error %d", why);
set_errno (EPERM);
}
}
static struct tl host_errmap[] =
{
{WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND", HOST_NOT_FOUND},
{WSATRY_AGAIN, "WSATRY_AGAIN", TRY_AGAIN},
{WSANO_RECOVERY, "WSANO_RECOVERY", NO_RECOVERY},
{WSANO_DATA, "WSANO_DATA", NO_DATA},
{0, NULL, 0}
2000-02-17 20:38:33 +01:00
};
/* Cygwin internal */
static void
set_host_errno ()
{
int i;
int why = WSAGetLastError ();
for (i = 0; i < host_errmap[i].w != 0; ++i)
if (why == host_errmap[i].w)
break;
if (host_errmap[i].w != 0)
h_errno = host_errmap[i].e;
else
h_errno = NETDB_INTERNAL;
}
/* exported as getprotobyname: standards? */
extern "C"
struct protoent *
cygwin_getprotobyname (const char *p)
{
struct protoent *res = getprotobyname (p);
if (!res)
set_winsock_errno ();
dump_protoent (res);
return res;
}
/* exported as getprotobynumber: standards? */
extern "C"
struct protoent *
cygwin_getprotobynumber (int number)
{
struct protoent *res = getprotobynumber (number);
if (!res)
set_winsock_errno ();
dump_protoent (res);
return res;
}
void
fdsock (int fd, const char *name, SOCKET soc)
{
fhandler_base *fh = fdtab.build_fhandler(fd, FH_SOCKET, name);
2000-02-17 20:38:33 +01:00
fh->set_io_handle ((HANDLE) soc);
fh->set_flags (O_RDWR);
}
/* exported as socket: standards? */
extern "C"
int
cygwin_socket (int af, int type, int protocol)
{
int res = -1;
SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socket");
SOCKET soc;
int fd = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (fd < 0)
{
set_errno (ENMFILE);
}
else
{
debug_printf ("socket (%d, %d, %d)", af, type, protocol);
soc = socket (AF_INET, type, 0);
if (soc == INVALID_SOCKET)
{
set_winsock_errno ();
goto done;
}
soc = duplicate_socket (soc);
const char *name;
if (af == AF_INET)
name = (type == SOCK_STREAM ? "/dev/tcp" : "/dev/udp");
else
name = (type == SOCK_STREAM ? "/dev/streamsocket" : "/dev/dgsocket");
fdsock (fd, name, soc);
res = fd;
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
2000-02-17 20:38:33 +01:00
h->set_addr_family (af);
}
done:
syscall_printf ("%d = socket (%d, %d, %d)", res, af, type, protocol);
ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socket");
return res;
}
/* cygwin internal: map sockaddr into internet domain address */
static int get_inet_addr (const struct sockaddr *in, int inlen,
struct sockaddr_in *out, int *outlen)
{
if (in->sa_family == AF_INET)
{
*out = * (sockaddr_in *)in;
*outlen = inlen;
return 1;
}
else if (in->sa_family == AF_UNIX)
{
sockaddr_in sin;
char buf[32];
memset (buf, 0, sizeof buf);
int fd = open (in->sa_data, O_RDONLY);
if (fd == -1)
return 0;
if (read (fd, buf, sizeof buf) == -1)
return 0;
sin.sin_family = AF_INET;
sscanf (buf + strlen (SOCKET_COOKIE), "%hu", &sin.sin_port);
sin.sin_port = htons (sin.sin_port);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
*out = sin;
*outlen = sizeof sin;
return 1;
}
else
{
set_errno (EAFNOSUPPORT);
return 0;
}
}
/* exported as sendto: standards? */
extern "C"
int
cygwin_sendto (int fd,
const void *buf,
int len,
unsigned int flags,
const struct sockaddr *to,
int tolen)
{
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
2000-02-17 20:38:33 +01:00
sockaddr_in sin;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
if (get_inet_addr (to, tolen, &sin, &tolen) == 0)
return -1;
int res = sendto (h->get_socket (), (const char *) buf, len,
flags, to, tolen);
if (res == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
return res;
}
/* exported as recvfrom: standards? */
extern "C"
int
cygwin_recvfrom (int fd,
char *buf,
int len,
int flags,
struct sockaddr *from,
int *fromlen)
{
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
debug_printf ("recvfrom %d", h->get_socket ());
int res = recvfrom (h->get_socket (), buf, len, flags, from, fromlen);
if (res == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
return res;
}
/* Cygwin internal */
fhandler_socket *
get (int fd)
{
if (fdtab.not_open (fd))
2000-02-17 20:38:33 +01:00
{
set_errno (EINVAL);
return 0;
}
return fdtab[fd]->is_socket ();
2000-02-17 20:38:33 +01:00
}
/* exported as setsockopt: standards? */
extern "C"
int
cygwin_setsockopt (int fd,
int level,
int optname,
const void *optval,
int optlen)
{
fhandler_socket *h = get (fd);
int res = -1;
const char *name = "error";
if (h)
{
/* For the following debug_printf */
switch (optname)
{
case SO_DEBUG:
name="SO_DEBUG";
break;
case SO_ACCEPTCONN:
name="SO_ACCEPTCONN";
break;
case SO_REUSEADDR:
name="SO_REUSEADDR";
break;
case SO_KEEPALIVE:
name="SO_KEEPALIVE";
break;
case SO_DONTROUTE:
name="SO_DONTROUTE";
break;
case SO_BROADCAST:
name="SO_BROADCAST";
break;
case SO_USELOOPBACK:
name="SO_USELOOPBACK";
break;
case SO_LINGER:
name="SO_LINGER";
break;
case SO_OOBINLINE:
name="SO_OOBINLINE";
break;
}
res = setsockopt (h->get_socket (), level, optname,
(const char *) optval, optlen);
if (optlen == 4)
syscall_printf ("setsockopt optval=%x", *(long *) optval);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = setsockopt (%d, %d, %x (%s), %x, %d)",
res, fd, level, optname, name, optval, optlen);
return res;
}
/* exported as getsockopt: standards? */
extern "C"
int
cygwin_getsockopt (int fd,
int level,
int optname,
void *optval,
int *optlen)
{
fhandler_socket *h = get (fd);
int res = -1;
const char *name = "error";
if (h)
{
/* For the following debug_printf */
switch (optname)
{
case SO_DEBUG:
name="SO_DEBUG";
break;
case SO_ACCEPTCONN:
name="SO_ACCEPTCONN";
break;
case SO_REUSEADDR:
name="SO_REUSEADDR";
break;
case SO_KEEPALIVE:
name="SO_KEEPALIVE";
break;
case SO_DONTROUTE:
name="SO_DONTROUTE";
break;
case SO_BROADCAST:
name="SO_BROADCAST";
break;
case SO_USELOOPBACK:
name="SO_USELOOPBACK";
break;
case SO_LINGER:
name="SO_LINGER";
break;
case SO_OOBINLINE:
name="SO_OOBINLINE";
break;
}
res = getsockopt (h->get_socket (), level, optname,
(char *) optval, (int *) optlen);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = getsockopt (%d, %d, %x (%s), %x, %d)",
res, fd, level, optname, name, optval, optlen);
return res;
}
/* exported as connect: standards? */
extern "C"
int
cygwin_connect (int fd,
const struct sockaddr *name,
int namelen)
{
int res;
fhandler_socket *sock = get (fd);
sockaddr_in sin;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
if (get_inet_addr (name, namelen, &sin, &namelen) == 0)
return -1;
if (!sock)
{
res = -1;
}
else
{
res = connect (sock->get_socket (), (sockaddr *) &sin, namelen);
if (res)
set_winsock_errno ();
}
return res;
}
/* exported as getservbyname: standards? */
extern "C"
struct servent *
cygwin_getservbyname (const char *name, const char *proto)
{
struct servent *p = getservbyname (name, proto);
if (!p)
set_winsock_errno ();
syscall_printf ("%x = getservbyname (%s, %s)", p, name, proto);
return p;
}
/* exported as getservbyport: standards? */
extern "C"
struct servent *
cygwin_getservbyport (int port, const char *proto)
{
struct servent *p = getservbyport (port, proto);
if (!p)
set_winsock_errno ();
syscall_printf ("%x = getservbyport (%d, %s)", p, port, proto);
return p;
}
extern "C"
int
cygwin_gethostname (char *name, size_t len)
{
int PASCAL win32_gethostname(char*,int);
if (wsock32_handle == NULL ||
win32_gethostname (name, len) == SOCKET_ERROR)
{
DWORD local_len = len;
if (!GetComputerNameA (name, &local_len))
{
set_winsock_errno ();
return -1;
}
}
debug_printf ("name %s\n", name);
h_errno = 0;
return 0;
}
/* exported as gethostbyname: standards? */
extern "C"
struct hostent *
cygwin_gethostbyname (const char *name)
{
static unsigned char tmp_addr[4];
static struct hostent tmp;
static char *tmp_aliases[1] = {0};
static char *tmp_addr_list[2] = {0,0};
static int a, b, c, d;
if (sscanf(name, "%d.%d.%d.%d", &a, &b, &c, &d) == 4)
{
/* In case you don't have DNS, at least x.x.x.x still works */
memset(&tmp, 0, sizeof(tmp));
tmp_addr[0] = a;
tmp_addr[1] = b;
tmp_addr[2] = c;
tmp_addr[3] = d;
tmp_addr_list[0] = (char *)tmp_addr;
tmp.h_name = name;
tmp.h_aliases = tmp_aliases;
tmp.h_addrtype = 2;
tmp.h_length = 4;
tmp.h_addr_list = tmp_addr_list;
return &tmp;
}
struct hostent *ptr = gethostbyname (name);
if (!ptr)
{
set_winsock_errno ();
set_host_errno ();
}
else
{
debug_printf ("h_name %s", ptr->h_name);
h_errno = 0;
}
return ptr;
}
/* exported as accept: standards? */
extern "C"
int
cygwin_accept (int fd, struct sockaddr *peer, int *len)
{
int res = -1;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
fhandler_socket *sock = get (fd);
if (sock)
{
/* 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);
res = accept (sock->get_socket (), peer, len); // can't use a blocking call inside a lock
SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," accept");
int res_fd = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (res_fd == -1)
{
/* FIXME: what is correct errno? */
set_errno (EMFILE);
goto done;
}
if ((SOCKET) res == (SOCKET) INVALID_SOCKET)
set_winsock_errno ();
else
{
res = duplicate_socket (res);
fdsock (res_fd, sock->get_name (), res);
res = res_fd;
}
}
done:
syscall_printf ("%d = accept (%d, %x, %x)", res, fd, peer, len);
ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," accept");
return res;
}
/* exported as bind: standards? */
extern "C"
int
cygwin_bind (int fd, struct sockaddr *my_addr, int addrlen)
{
int res = -1;
fhandler_socket *sock = get (fd);
if (sock)
{
if (my_addr->sa_family == AF_UNIX)
{
#define un_addr ((struct sockaddr_un *) my_addr)
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 (sock->get_socket (), (sockaddr *) &sin, len))
{
syscall_printf ("AF_UNIX: bind failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
if (getsockname (sock->get_socket (), (sockaddr *) &sin, &len))
{
syscall_printf ("AF_UNIX: getsockname failed %d", get_errno ());
set_winsock_errno ();
goto out;
}
sin.sin_port = ntohs (sin.sin_port);
debug_printf ("AF_UNIX: 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;
}
char buf[sizeof (SOCKET_COOKIE) + 10];
__small_sprintf (buf, "%s%u", SOCKET_COOKIE, sin.sin_port);
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) & ~myself->umask);
res = 0;
}
#undef un_addr
}
else if (bind (sock->get_socket (), my_addr, addrlen))
set_winsock_errno ();
else
res = 0;
}
out:
syscall_printf ("%d = bind (%d, %x, %d)", res, fd, my_addr, addrlen);
return res;
}
/* exported as getsockname: standards? */
extern "C"
int
cygwin_getsockname (int fd, struct sockaddr *addr, int *namelen)
{
int res = -1;
fhandler_socket *sock = get (fd);
if (sock)
{
res = getsockname (sock->get_socket (), addr, namelen);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = getsockname (%d, %x, %d)", res, fd, addr, namelen);
return res;
}
/* exported as gethostbyaddr: standards? */
extern "C"
struct hostent *
cygwin_gethostbyaddr (const char *addr, int len, int type)
{
struct hostent *ptr = gethostbyaddr (addr, len, type);
if (!ptr)
{
set_winsock_errno ();
set_host_errno ();
}
else
{
debug_printf ("h_name %s", ptr->h_name);
h_errno = 0;
}
return ptr;
}
/* exported as listen: standards? */
extern "C"
int
cygwin_listen (int fd, int backlog)
{
int res = -1;
fhandler_socket *sock = get (fd);
if (sock)
{
res = listen (sock->get_socket (), backlog);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = listen (%d, %d)", res, fd, backlog);
return res;
}
/* exported as shutdown: standards? */
extern "C"
int
cygwin_shutdown (int fd, int how)
{
int res = -1;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
fhandler_socket *sock = get (fd);
if (sock)
{
res = shutdown (sock->get_socket (), how);
if (res)
set_winsock_errno ();
}
syscall_printf ("%d = shutdown (%d, %d)", res, fd, how);
return res;
}
/* exported as herror: standards? */
extern "C"
void
cygwin_herror (const char *)
2000-02-17 20:38:33 +01:00
{
debug_printf ("********%d*************", __LINE__);
}
/* exported as getpeername: standards? */
extern "C"
int
cygwin_getpeername (int fd, struct sockaddr *name, int *len)
{
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
2000-02-17 20:38:33 +01:00
debug_printf ("getpeername %d", h->get_socket ());
int res = getpeername (h->get_socket (), name, len);
if (res)
set_winsock_errno ();
debug_printf ("%d = getpeername %d", res, h->get_socket ());
return res;
}
/* exported as recv: standards? */
extern "C"
int
cygwin_recv (int fd, void *buf, int len, unsigned int flags)
{
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
int res = recv (h->get_socket (), (char *) buf, len, flags);
if (res == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
#if 0
if (res > 0 && res < 200)
for (int i=0; i < res; i++)
system_printf ("%d %x %c", i, ((char *) buf)[i], ((char *) buf)[i]);
#endif
syscall_printf ("%d = recv (%d, %x, %x, %x)", res, fd, buf, len, flags);
return res;
}
/* exported as send: standards? */
extern "C"
int
cygwin_send (int fd, const void *buf, int len, unsigned int flags)
{
fhandler_socket *h = (fhandler_socket *) fdtab[fd];
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
int res = send (h->get_socket (), (const char *) buf, len, flags);
if (res == SOCKET_ERROR)
{
set_winsock_errno ();
res = -1;
}
syscall_printf ("%d = send (%d, %x, %d, %x)", res, fd, buf, len, flags);
return res;
}
/* getdomainname: standards? */
extern "C"
int
getdomainname (char *domain, int len)
{
/*
* This works for Win95 only if the machine is configured to use MS-TCP.
* If a third-party TCP is being used this will fail.
* FIXME: On Win95, is there a way to portably check the TCP stack
* in use and include paths for the Domain name in each ?
* Punt for now and assume MS-TCP on Win95.
*/
reg_key r (HKEY_LOCAL_MACHINE, KEY_READ,
(os_being_run != winNT) ? "System" : "SYSTEM",
"CurrentControlSet", "Services",
(os_being_run != winNT) ? "MSTCP" : "Tcpip",
NULL);
/* FIXME: Are registry keys case sensitive? */
if (r.error () || r.get_string ("Domain", domain, len, "") != ERROR_SUCCESS)
{
__seterrno ();
return -1;
}
return 0;
}
/* Cygwin internal */
/* Fill out an ifconf struct.
*
* Windows NT:
* Look at the Bind value in
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\
* This is a REG_MULTI_SZ with strings of the form:
* \Device\<Netcard>, where netcard is the name of the net device.
* Then look under:
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<NetCard>\
* Parameters\Tcpip
* at the IPAddress, Subnetmask and DefaultGateway values for the
* required values.
*
* Windows 9x:
* We originally just did a gethostbyname, assuming that it's pretty
* unlikely Win9x will ever have more than one netcard. When this
* succeeded, we got the interface plus a loopback.
* Currently, we read all
* "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Class\NetTrans\*"
* entries from the Registry and use all entries that have legal
* "IPAddress" and "IPMask" values.
*/
static int
get_ifconf (struct ifconf *ifc, int what)
{
if (os_being_run == winNT)
{
HKEY key;
DWORD type, size;
unsigned long lip, lnp;
int cnt = 1;
char *binding = (char *) 0;
struct sockaddr_in *sa;
/* Union maps buffer to correct struct */
struct ifreq *ifr = ifc->ifc_req;
/* Ensure we have space for two struct ifreqs, fail if not. */
if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq)))
{
set_errno (EFAULT);
return -1;
}
/* Set up interface lo0 first */
strcpy (ifr->ifr_name, "lo0");
memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr));
switch (what)
{
case SIOCGIFCONF:
case SIOCGIFADDR:
sa = (struct sockaddr_in *) &ifr->ifr_addr;
sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
break;
case SIOCGIFBRDADDR:
lip = htonl (INADDR_LOOPBACK);
lnp = cygwin_inet_addr ("255.0.0.0");
sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
sa->sin_addr.s_addr = lip & lnp | ~lnp;
break;
case SIOCGIFNETMASK:
sa = (struct sockaddr_in *) &ifr->ifr_netmask;
sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0");
break;
default:
set_errno (EINVAL);
return -1;
}
sa->sin_family = AF_INET;
sa->sin_port = 0;
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
"SYSTEM\\"
"CurrentControlSet\\"
"Services\\"
"Tcpip\\"
"Linkage",
0, KEY_READ, &key) == ERROR_SUCCESS)
{
if (RegQueryValueEx (key, "Bind",
NULL, &type,
NULL, &size) == ERROR_SUCCESS)
{
binding = (char *) alloca (size);
if (RegQueryValueEx (key, "Bind",
NULL, &type,
(unsigned char *) binding,
&size) != ERROR_SUCCESS)
{
binding = NULL;
}
}
RegCloseKey (key);
}
if (binding)
{
char *bp, eth[2];
char cardkey[256], ipaddress[256], netmask[256];
eth[0] = '/';
eth[1] = '\0';
for (bp = binding; *bp; bp += strlen(bp) + 1)
{
bp += strlen ("\\Device\\");
strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\");
strcat (cardkey, bp);
strcat (cardkey, "\\Parameters\\Tcpip");
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey,
0, KEY_READ, &key) != ERROR_SUCCESS)
continue;
if (RegQueryValueEx (key, "IPAddress",
NULL, &type,
(unsigned char *) &ipaddress,
(size = 256, &size)) == ERROR_SUCCESS
&& RegQueryValueEx (key, "SubnetMask",
NULL, &type,
(unsigned char *) &netmask,
(size = 256, &size)) == ERROR_SUCCESS)
{
char *ip, *np;
char sub[2];
char dhcpaddress[256], dhcpnetmask[256];
sub[0] = '/';
sub[1] = '\0';
if (strncmp (bp, "NdisWan", 7))
++*eth;
for (ip = ipaddress, np = netmask;
*ip && *np;
ip += strlen (ip) + 1, np += strlen (np) + 1)
{
if ((caddr_t) ++ifr > ifc->ifc_buf
+ ifc->ifc_len
- sizeof (struct ifreq))
break;
if (! strncmp (bp, "NdisWan", 7))
{
strcpy (ifr->ifr_name, "ppp");
strcat (ifr->ifr_name, bp + 7);
}
else
{
strcpy (ifr->ifr_name, "eth");
strcat (ifr->ifr_name, eth);
}
++*sub;
if (*sub >= '1')
strcat (ifr->ifr_name, sub);
memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr);
if (cygwin_inet_addr (ip) == 0L
&& RegQueryValueEx (key, "DhcpIPAddress",
NULL, &type,
(unsigned char *) &dhcpaddress,
(size = 256, &size))
== ERROR_SUCCESS
&& RegQueryValueEx (key, "DhcpSubnetMask",
NULL, &type,
(unsigned char *) &dhcpnetmask,
(size = 256, &size))
== ERROR_SUCCESS)
{
switch (what)
{
case SIOCGIFCONF:
case SIOCGIFADDR:
sa = (struct sockaddr_in *) &ifr->ifr_addr;
sa->sin_addr.s_addr =
cygwin_inet_addr (dhcpaddress);
break;
case SIOCGIFBRDADDR:
lip = cygwin_inet_addr (dhcpaddress);
lnp = cygwin_inet_addr (dhcpnetmask);
sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
sa->sin_addr.s_addr = lip & lnp | ~lnp;
break;
case SIOCGIFNETMASK:
sa = (struct sockaddr_in *) &ifr->ifr_netmask;
sa->sin_addr.s_addr =
cygwin_inet_addr (dhcpnetmask);
break;
}
}
else
{
switch (what)
{
case SIOCGIFCONF:
case SIOCGIFADDR:
sa = (struct sockaddr_in *) &ifr->ifr_addr;
sa->sin_addr.s_addr = cygwin_inet_addr (ip);
break;
case SIOCGIFBRDADDR:
lip = cygwin_inet_addr (ip);
lnp = cygwin_inet_addr (np);
sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
sa->sin_addr.s_addr = lip & lnp | ~lnp;
break;
case SIOCGIFNETMASK:
sa = (struct sockaddr_in *) &ifr->ifr_netmask;
sa->sin_addr.s_addr = cygwin_inet_addr (np);
break;
}
}
sa->sin_family = AF_INET;
sa->sin_port = 0;
++cnt;
}
}
RegCloseKey (key);
}
}
/* Set the correct length */
ifc->ifc_len = cnt * sizeof (struct ifreq);
}
else /* Windows 9x */
{
HKEY key, subkey;
FILETIME update;
LONG res;
DWORD type, size;
unsigned long lip, lnp;
char ifname[256], ip[256], np[256];
int cnt = 1;
struct sockaddr_in *sa;
/* Union maps buffer to correct struct */
struct ifreq *ifr = ifc->ifc_req;
char eth[2];
eth[0] = '/';
eth[1] = '\0';
/* Ensure we have space for two struct ifreqs, fail if not. */
if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq)))
{
set_errno (EFAULT);
return -1;
}
/* Set up interface lo0 first */
strcpy (ifr->ifr_name, "lo0");
memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr);
switch (what)
{
case SIOCGIFCONF:
case SIOCGIFADDR:
sa = (struct sockaddr_in *) &ifr->ifr_addr;
sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
break;
case SIOCGIFBRDADDR:
lip = htonl(INADDR_LOOPBACK);
lnp = cygwin_inet_addr ("255.0.0.0");
sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
sa->sin_addr.s_addr = lip & lnp | ~lnp;
break;
case SIOCGIFNETMASK:
sa = (struct sockaddr_in *) &ifr->ifr_netmask;
sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0");
break;
default:
set_errno (EINVAL);
return -1;
}
sa->sin_family = AF_INET;
sa->sin_port = 0;
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
"SYSTEM\\"
"CurrentControlSet\\"
"Services\\"
"Class\\"
"NetTrans",
0, KEY_READ, &key) == ERROR_SUCCESS)
{
for (int i = 0;
(res = RegEnumKeyEx (key, i, ifname,
(size = sizeof ifname, &size),
0, 0, 0, &update)) != ERROR_NO_MORE_ITEMS;
++i)
{
if (res != ERROR_SUCCESS
|| RegOpenKeyEx (key, ifname, 0,
KEY_READ, &subkey) != ERROR_SUCCESS)
continue;
if (RegQueryValueEx (subkey, "IPAddress", 0,
&type, (unsigned char *) ip,
(size = sizeof ip, &size)) == ERROR_SUCCESS
|| RegQueryValueEx (subkey, "IPMask", 0,
&type, (unsigned char *) np,
(size = sizeof np, &size)) == ERROR_SUCCESS)
{
if ((caddr_t)++ifr > ifc->ifc_buf
+ ifc->ifc_len
- sizeof(struct ifreq))
break;
++*eth;
strcpy (ifr->ifr_name, "eth");
strcat (ifr->ifr_name, eth);
switch (what)
{
case SIOCGIFCONF:
case SIOCGIFADDR:
sa = (struct sockaddr_in *) &ifr->ifr_addr;
sa->sin_addr.s_addr = cygwin_inet_addr (ip);
break;
case SIOCGIFBRDADDR:
lip = cygwin_inet_addr (ip);
lnp = cygwin_inet_addr (np);
sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
sa->sin_addr.s_addr = lip & lnp | ~lnp;
break;
case SIOCGIFNETMASK:
sa = (struct sockaddr_in *) &ifr->ifr_netmask;
sa->sin_addr.s_addr = cygwin_inet_addr (np);
break;
}
sa->sin_family = AF_INET;
sa->sin_port = 0;
++cnt;
}
RegCloseKey (subkey);
}
}
/* Set the correct length */
ifc->ifc_len = cnt * sizeof (struct ifreq);
}
return 0;
}
/* exported as rcmd: standards? */
extern "C"
int
cygwin_rcmd (char **ahost, unsigned short inport, char *locuser,
char *remuser, char *cmd, int *fd2p)
{
int res = -1;
SOCKET fd2s;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
int res_fd = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (res_fd == -1)
goto done;
if (fd2p)
{
*fd2p = fdtab.find_unused_handle (res_fd + 1);
2000-02-17 20:38:33 +01:00
if (*fd2p == -1)
goto done;
}
res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p? &fd2s: NULL);
if (res == (int) INVALID_SOCKET)
goto done;
else
{
res = duplicate_socket (res);
fdsock (res_fd, "/dev/tcp", res);
res = res_fd;
}
if (fd2p)
{
fd2s = duplicate_socket (fd2s);
fdsock (*fd2p, "/dev/tcp", fd2s);
}
done:
syscall_printf ("%d = rcmd (...)", res);
return res;
}
/* exported as rresvport: standards? */
extern "C"
int
cygwin_rresvport (int *port)
{
int res = -1;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
int res_fd = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (res_fd == -1)
goto done;
res = rresvport (port);
if (res == (int) INVALID_SOCKET)
goto done;
else
{
res = duplicate_socket (res);
fdsock (res_fd, "/dev/tcp", res);
res = res_fd;
}
done:
syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0);
return res;
}
/* exported as rexec: standards? */
extern "C"
int
cygwin_rexec (char **ahost, unsigned short inport, char *locuser,
char *password, char *cmd, int *fd2p)
{
int res = -1;
SOCKET fd2s;
sigframe thisframe (mainthread, 0);
2000-02-17 20:38:33 +01:00
int res_fd = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (res_fd == -1)
goto done;
if (fd2p)
{
*fd2p = fdtab.find_unused_handle (res_fd + 1);
2000-02-17 20:38:33 +01:00
if (*fd2p == -1)
goto done;
}
res = rexec (ahost, inport, locuser, password, cmd, fd2p ? &fd2s : NULL);
if (res == (int) INVALID_SOCKET)
goto done;
else
{
res = duplicate_socket (res);
fdsock (res_fd, "/dev/tcp", res);
res = res_fd;
}
if (fd2p)
{
fd2s = duplicate_socket (fd2s);
fdsock (*fd2p, "/dev/tcp", fd2s);
#if 0 /* ??? */
fhandler_socket *h;
p->hmap.vec[*fd2p].h = h =
new (&p->hmap.vec[*fd2p].item) fhandler_socket (fd2s, "/dev/tcp");
#endif
}
done:
syscall_printf ("%d = rexec (...)", res);
return res;
}
/* socketpair: standards? */
/* Win32 supports AF_INET only, so ignore domain and protocol arguments */
extern "C"
int
socketpair (int, int type, int, int *sb)
{
int res = -1;
SOCKET insock, outsock, newsock;
struct sockaddr_in sock_in;
int len = sizeof (sock_in);
SetResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socketpair");
sb[0] = fdtab.find_unused_handle ();
2000-02-17 20:38:33 +01:00
if (sb[0] == -1)
{
set_errno (EMFILE);
goto done;
}
sb[1] = fdtab.find_unused_handle (sb[0] + 1);
2000-02-17 20:38:33 +01:00
if (sb[1] == -1)
{
set_errno (EMFILE);
goto done;
}
/* create a listening socket */
newsock = socket (AF_INET, type, 0);
if (newsock == INVALID_SOCKET)
{
set_winsock_errno ();
goto done;
}
/* bind the socket to any unused port */
sock_in.sin_family = AF_INET;
sock_in.sin_port = 0;
sock_in.sin_addr.s_addr = INADDR_ANY;
if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0)
{
set_winsock_errno ();
closesocket (newsock);
goto done;
}
if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0)
{
debug_printf ("getsockname error");
set_winsock_errno ();
closesocket (newsock);
goto done;
}
listen (newsock, 2);
/* create a connecting socket */
outsock = socket (AF_INET, type, 0);
if (outsock == INVALID_SOCKET)
{
debug_printf ("can't create outsock");
set_winsock_errno ();
closesocket (newsock);
goto done;
}
sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
/* Do a connect and accept the connection */
if (connect (outsock, (struct sockaddr *) &sock_in,
sizeof (sock_in)) < 0)
{
debug_printf ("connect error");
set_winsock_errno ();
closesocket (newsock);
closesocket (outsock);
goto done;
}
insock = accept (newsock, (struct sockaddr *) &sock_in, &len);
if (insock == INVALID_SOCKET)
{
debug_printf ("accept error");
set_winsock_errno ();
closesocket (newsock);
closesocket (outsock);
goto done;
}
closesocket (newsock);
res = 0;
insock = duplicate_socket (insock);
fdsock (sb[0], "/dev/tcp", insock);
outsock = duplicate_socket (outsock);
fdsock (sb[1], "/dev/tcp", outsock);
done:
syscall_printf ("%d = socketpair (...)", res);
ReleaseResourceLock(LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," socketpair");
return res;
}
/**********************************************************************/
/* fhandler_socket */
fhandler_socket::fhandler_socket (const char *name) :
fhandler_base (FH_SOCKET, name)
{
set_cb (sizeof *this);
number_of_sockets++;
}
/* sethostent: standards? */
extern "C"
void
sethostent (int)
{
}
/* endhostent: standards? */
extern "C"
void
endhostent (void)
{
}
fhandler_socket::~fhandler_socket ()
{
if (--number_of_sockets < 0)
{
number_of_sockets = 0;
system_printf("socket count < 0");
}
}
int
fhandler_socket::read (void *ptr, size_t len)
{
sigframe thisframe (mainthread);
2000-02-17 20:38:33 +01:00
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);
2000-02-17 20:38:33 +01:00
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);
2000-02-17 20:38:33 +01:00
if (closesocket (get_socket ()))
{
set_winsock_errno ();
res = -1;
}
return res;
}
/* Cygwin internal */
/*
* Return the flags settings for an interface.
*/
static int
get_if_flags (struct ifreq *ifr)
{
struct sockaddr_in *sa = (struct sockaddr_in *) &ifr->ifr_addr;
short flags = IFF_NOTRAILERS | IFF_UP | IFF_RUNNING;
if (sa->sin_addr.s_addr == INADDR_LOOPBACK)
flags |= IFF_LOOPBACK;
else
flags |= IFF_BROADCAST;
ifr->ifr_flags = flags;
return 0;
}
#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
/* Cygwin internal */
int
fhandler_socket::ioctl (unsigned int cmd, void *p)
{
int res;
struct ifconf *ifc;
struct ifreq *ifr;
sigframe thisframe (mainthread);
2000-02-17 20:38:33 +01:00
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;
}
res = get_if_flags (ifr);
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 settting 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;
}
extern "C" {
2000-02-17 20:38:33 +01:00
/* Initialize WinSock */
LoadDLLinitfunc (wsock32)
{
WSADATA p;
int res;
HANDLE h;
if ((h = LoadLibrary ("wsock32.dll")) != NULL)
wsock32_handle = h;
else if (!wsock32_handle)
api_fatal ("could not load wsock32.dll. Is TCP/IP installed?");
else
return 0; /* Already done by another thread? */
res = WSAStartup ((2<<8) | 2, &p);
debug_printf ("res %d", res);
debug_printf ("wVersion %d", p.wVersion);
debug_printf ("wHighVersion %d", p.wHighVersion);
debug_printf ("szDescription %s",p.szDescription);
debug_printf ("szSystemStatus %s",p.szSystemStatus);
debug_printf ("iMaxSockets %d", p.iMaxSockets);
debug_printf ("iMaxUdpDg %d", p.iMaxUdpDg);
debug_printf ("lpVendorInfo %d", p.lpVendorInfo);
if (FIONBIO != REAL_FIONBIO)
debug_printf ("**************** FIONBIO != REAL_FIONBIO");
return 0;
}
LoadDLLinit (wsock32)
static void dummy_autoload (void) __attribute__ ((unused));
static void
dummy_autoload (void)
{
LoadDLLfunc (WSAAsyncSelect, 16, wsock32)
LoadDLLfunc (WSACleanup, 0, wsock32)
LoadDLLfunc (WSAGetLastError, 0, wsock32)
LoadDLLfunc (WSAStartup, 8, wsock32)
LoadDLLfunc (__WSAFDIsSet, 8, wsock32)
LoadDLLfunc (accept, 12, wsock32)
LoadDLLfunc (bind, 12, wsock32)
LoadDLLfunc (closesocket, 4, wsock32)
LoadDLLfunc (connect, 12, wsock32)
LoadDLLfunc (gethostbyaddr, 12, wsock32)
LoadDLLfunc (gethostbyname, 4, wsock32)
LoadDLLfunc (gethostname, 8, wsock32)
LoadDLLfunc (getpeername, 12, wsock32)
LoadDLLfunc (getprotobyname, 4, wsock32)
LoadDLLfunc (getprotobynumber, 4, wsock32)
LoadDLLfunc (getservbyname, 8, wsock32)
LoadDLLfunc (getservbyport, 8, wsock32)
LoadDLLfunc (getsockname, 12, wsock32)
LoadDLLfunc (getsockopt, 20, wsock32)
LoadDLLfunc (inet_addr, 4, wsock32)
LoadDLLfunc (inet_network, 4, wsock32)
LoadDLLfunc (inet_ntoa, 4, wsock32)
LoadDLLfunc (ioctlsocket, 12, wsock32)
LoadDLLfunc (listen, 8, wsock32)
LoadDLLfunc (rcmd, 24, wsock32)
LoadDLLfunc (recv, 16, wsock32)
LoadDLLfunc (recvfrom, 24, wsock32)
LoadDLLfunc (rexec, 24, wsock32)
LoadDLLfunc (rresvport, 4, wsock32)
LoadDLLfunc (select, 20, wsock32)
LoadDLLfunc (send, 16, wsock32)
LoadDLLfunc (sendto, 24, wsock32)
LoadDLLfunc (setsockopt, 20, wsock32)
LoadDLLfunc (shutdown, 8, wsock32)
LoadDLLfunc (socket, 12, wsock32)
}
}