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
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-07-25 23:23:23 +0400
committerCorinna Vinschen <corinna@vinschen.de>2006-07-25 23:23:23 +0400
commit70e476d27be8e49146c49e8d6e1319100b84d5eb (patch)
tree1827e4d9dec3e1eb523db1df6a53e64c1c234518 /winsup
parente9d500b6a04e842ffaf04fd1cb6048b44fb99e67 (diff)
2006-07-25 Corinna Vinschen <corinna@vinschen.de>
* include/cygwin/version.h: Bump DLL version to 1.7.0. 2006-07-25 Corinna Vinschen <corinna@vinschen.de> * select.h: Remove. * fhandler_socket.cc: Don't include select.h. * select.cc: Ditto. 2006-07-25 Corinna Vinschen <corinna@vinschen.de> * cygtls.h: Drop socket related includes. (struct _local_storage): Remove exitsock and exitsock_sin. Add select_sockevt. * cygtls.cc: Accomodate above change throughout. * fhandler.h (class fhandler_socket): Make wsock_evt public. * fhandler_socket.cc (fhandler_socket::fhandler_socket): Accomodate reordering members. (fhandler_socket::evaluate_events): Drop FD_CONNECT event as soon as it gets read once. Never remove FD_WRITE event here. (fhandler_socket::wait_for_events): Wait 50 ms instead of INFINITE for socket events. (fhandler_socket::accept): Fix conditional. Set wsock_events members of accepted socket to useful start values. (fhandler_socket::recv_internal): Always drop FD_READ/FD_OOB events from wsock_events after the call to WSARecvFrom. (fhandler_socket::send_internal): Drop FD_WRITE event from wsock_events if the call to WSASendTo fails with WSAEWOULDBLOCK. Fix return value condition. * select.cc (struct socketinf): Change to accomodate using socket event handling. (peek_socket): Use event handling for peeking socket. (thread_socket): Ditto. (start_thread_socket): Ditto. (socket_cleanup): Same here. * tlsoffsets.h: Regenerate. 2006-07-20 Corinna Vinschen <corinna@vinschen.de> * fhandler.h (class fhandler_socket): Rearrange slightly to keep event handling methods and members together. Drop owner status flag. Split wait method. Rename event handling methods for readability. * fhandler_socket.cc (struct wsa_event): Add owner field. (LOCK_EVENTS): New macro. (UNLOCK_EVENTS): Ditto. (fhandler_socket::init_events): rename from prepare. (fhandler_socket::evaluate_events): First half of former wait method. Do everything but wait. Allow specifiying whether or not events from event_mask should be erased from wsock_events->events. Simplify OOB handling. Allow sending SIGURG to any process (group). (fhandler_socket::wait_for_events): Second half of former wait method. Call evaluate_events and wait in a loop if socket is blocking. (fhandler_socket::release_events): Rename from release. (fhandler_socket::connect): Accomodate above name changes. (fhandler_socket::accept): Ditto. (fhandler_socket::recv_internal): Ditto. (fhandler_socket::send_internal): Ditto. (fhandler_socket::close): Ditto. (fhandler_socket::fcntl): Always set owner to given input value on F_SETOWN. Handle F_GETOWN. * net.cc (fdsock): Accomodate above name changes. 2006-07-20 Corinna Vinschen <corinna@vinschen.de> * fhandler_socket.cc (fhandler_socket::wait): Set Winsock errno to WSAEWOULDBLOCK instead of WSAEINPROGRESS. 2006-07-18 Brian Ford <Brian.Ford@FlightSafety.com> Corinna Vinschen <corinna@vinschen.de> * winsup.h (mmap_region_status): New enum. (mmap_is_attached_or_noreserve_page): Adjust prototype and rename as below. * mmap.cc (mmap_is_attached_or_noreserve_page): Rename mmap_is_attached_or_noreserve. Add region length parameter. Return enum above. * exceptions.cc (_cygtls::handle_exceptions): Accomodate above. * fhandler.cc (fhandler_base::raw_read): Call above for NOACCESS errors and retry on success to allow reads into untouched MAP_NORESERVE buffers. 2006-07-18 Corinna Vinschen <corinna@vinschen.de> * cygwin.din (posix_openpt): Export. * tty.cc (posix_openpt): New function. * include/cygwin/stdlib.h (posix_openpt): Declare. * include/cygwin/version.h: Bump API minor number. 2006-07-14 Corinna Vinschen <corinna@vinschen.de> * security.cc (get_token_group_sidlist): Always add the interactive group to the token. Add comment. Create logon_id group SID by copying it from incoming group list. (create_token): Add subauth_token parameter. Use information in subauth_token if present. Tweak SourceIdentifier if subauth_token is present for debugging purposes. * security.h (create_token): Add subauth_token parameter in declaration. * syscalls.cc (seteuid32): Call subauth first. Call create_token regardless. Use subauth token in call to create_token if subauth succeeded. 2006-07-13 Corinna Vinschen <corinna@vinschen.de> * include/netinet/in.h: Update copyright. 2006-07-13 Corinna Vinschen <corinna@vinschen.de> * fhandler_socket.cc (fhandler_socket::wait): Rework function so that WaitForMultipleObjects is really only called when necessary. 2006-07-12 Corinna Vinschen <corinna@vinschen.de> * include/netdb.h: Declare rcmd, rcmd_af, rexec, rresvport, rresvport_af, iruserok, iruserok_sa, ruserok. 2006-07-12 Corinna Vinschen <corinna@vinschen.de> * Makefile.in (DLL_OFILES): Drop iruserok.o. Add rcmd.o. * autoload.cc (rcmd): Drop definition. * cygwin.din: Export bindresvport, bindresvport_sa, iruserok_sa, rcmd_af, rresvport_af. * net.cc (cygwin_rcmd): Remove. (last_used_bindresvport): Rename from last_used_rrecvport. (cygwin_bindresvport_sa): New function implementing bindresvport_sa. (cygwin_bindresvport): New function implementing bindresvport. (cygwin_rresvport): Remove. * include/cygwin/version.h: Bump API minor number. * include/netinet/in.h: Declare bindresvport and bindresvport_sa. * libc/iruserok.c: Remove file. * libc/rcmd.cc: New file implementing rcmd, rcmd_af, rresvport, rresvport_af, iruserok_sa, iruserok and ruserok. 2006-07-12 Corinna Vinschen <corinna@vinschen.de> * fhandler_socket.cc (fhandler_socket::getsockname): Return valid result for unbound sockets. 2006-07-11 Corinna Vinschen <corinna@vinschen.de> * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Handle wsock_mtx and wsock_evt on fork, thus handling close_on_exec correctly. (fhandler_socket::fixup_after_exec): Drop misguided attempt to handle close_on_exec here. (fhandler_socket::dup): Call fixup_after_fork with NULL parent. Add comment. (fhandler_socket::set_close_on_exec): Handle wsock_mtx and wsock_evt. 2006-07-10 Corinna Vinschen <corinna@vinschen.de> * fhandler.h (class fhandler_socket): Add wsock_mtx, wsock_evt and wsock_events members. Remove closed status flag, add listener status flag. Accomodate new implementation of socket event handling methods. Declare recv* and send* functions ssize_t as the POSIX equivalents. (fhandler_socket::recv_internal): Declare. (fhandler_socket::send_internal): Ditto. * fhandler_socket.cc (EVENT_MASK): Define mask of selected events. (fhandler_socket::fhandler_socket): Initialize new members. (fhandler_socket::af_local_setblocking): Don't actually set the socket to blocking mode. Keep sane event selection. (fhandler_socket::af_local_unsetblocking): Don't actually set the socket to previous blocking setting, just remember it. (struct wsa_event): New structure to keep event data per shared socket. (NUM_SOCKS): Define number of shared sockets concurrently handled by all active Cygwin processes. (wsa_events): New shared datastructure keeping all wsa_event records. (socket_serial_number): New shared variable to identify shared sockets. (wsa_slot_mtx): Global mutex to serialize wsa_events access. (search_wsa_event_slot): New static function to select a new wsa_event slot for a new socket. (fhandler_socket::prepare): Rewrite. Prepare event selection per new socket. (fhandler_socket::wait): Rewrite. Wait for socket events in thread safe and multiple process safe. (fhandler_socket::release): Rewrite. Close per-socket descriptor mutex handle and event handle. (fhandler_socket::dup): Duplicate wsock_mtx and wsock_evt. Fix copy-paste error in debug output. (fhandler_socket::connect): Accomodate new event handling. (fhandler_socket::listen): Set listener flag on successful listen. (fhandler_socket::accept): Accomodate new event handling. (fhandler_socket::recv_internal): New inline method centralizing common recv code. (fhandler_socket::recvfrom): Call recv_internal now. (fhandler_socket::recvmsg): Ditto. Streamline copying from iovec to WSABUF. (fhandler_socket::send_internal): New inline method centralizing common send code. (fhandler_socket::sendto): Call send_internal now. (fhandler_socket::sendmsg): Ditto. Streamline copying from iovec to WSABUF. (fhandler_socket::close): Call release now. (fhandler_socket::ioctl): Never actually switch to blocking mode. Just keep track of the setting. * net.cc (fdsock): Call prepare now. (cygwin_connect): Revert again to event driven technique. (cygwin_accept): Ditto. * poll.cc (poll): Don't call recvfrom on a listening socket. Remove special case for failing recvfrom. * include/sys/socket.h: Declare recv* and send* functions ssize_t as requested by POSIX. 2006-07-07 Corinna Vinschen <corinna@vinschen.de> * net.cc (cygwin_inet_ntop): Fix data type of forth parameter. 2006-07-06 Corinna Vinschen <corinna@vinschen.de> * include/cygwin/in6.h (struct in6_addr): Fix typo. 2006-07-06 Corinna Vinschen <corinna@vinschen.de> * cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo, gai_strerror, getaddrinfo, getnameinfo. * fhandler_socket.cc: Include cygwin/in6.h. (get_inet_addr): Accomodate AF_INET6 usage. (fhandler_socket::connect): Ditto. (fhandler_socket::listen): Ditto. (fhandler_socket::sendto): Ditto. * net.cc: Include cygwin/in6.h. (in6addr_any): Define. (in6addr_loopback): Define. (cygwin_socket): Accomodate AF_INET6 usage. (socketpair): Bind socketpairs only to loopback for security. (inet_pton4): New static function. (inet_pton6): Ditto. (cygwin_inet_pton): New AF_INET6 aware inet_pton implementation. (inet_ntop4): New static function. (inet_ntop6): Ditto. (cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation. (ga_aistruct): New static function. (ga_clone): Ditto. (ga_echeck): Ditto. (ga_nsearch): Ditto. (ga_port): Ditto. (ga_serv): Ditto. (ga_unix): Ditto. (gn_ipv46): Ditto. (ipv4_freeaddrinfo): Ditto. (ipv4_getaddrinfo): Ditto. (ipv4_getnameinfo): Ditto. (gai_errmap_t): New structure holding error code - error string mapping. (cygwin_gai_strerror): New function implementing gai_strerror. (w32_to_gai_err): New static function. (get_ipv6_funcs): Ditto. (load_ipv6_funcs): Ditto. (cygwin_freeaddrinfo): New function implementing freeaddrinfo. (cygwin_getaddrinfo): New function implementing getaddrinfo. (cygwin_getnameinfo): New function implementing getnameinfo. * include/netdb.h: Include stdint.h and cygwin/socket.h. Define data types and macros used by getaddrinfo and friends. Declare freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo. * include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition of struct sockaddr_in6. Include cygwin/in6.h instead. * include/cygwin/in6.h: New header file defining IPv6 releated data types and macros. * include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add IPv6 related socket options. * include/cygwin/version.h: Bump API minor number. 2006-07-06 Corinna Vinschen <corinna@vinschen.de> * autoload.cc (DsGetDcNameA): Define. (NetGetAnyDCName): Define. * security.cc: Include dsgetdc.h. (DsGetDcNameA): Declare. (DS_FORCE_REDISCOVERY): Define. (get_logon_server): Add bool parameter to control rediscovery of DC. Use DsGetDcNameA function if supported, NetGetDCName/NetGetAnyDCName otherwise. (get_server_groups): Rediscover DC if get_user_groups fails and try again. (get_reg_security): Use correct error code macro when testing RegGetKeySecurity return value. * security.h (get_logon_server): Remove default vaue from wserver parameter. Add rediscovery parameter. * uinfo.cc (cygheap_user::env_logsrv): Accomodate rediscovery parameter in call to get_logon_server.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog281
-rw-r--r--winsup/cygwin/Makefile.in10
-rw-r--r--winsup/cygwin/autoload.cc5
-rw-r--r--winsup/cygwin/cygtls.cc12
-rw-r--r--winsup/cygwin/cygtls.h7
-rw-r--r--winsup/cygwin/cygwin.din12
-rw-r--r--winsup/cygwin/exceptions.cc9
-rw-r--r--winsup/cygwin/fhandler.cc16
-rw-r--r--winsup/cygwin/fhandler.h39
-rw-r--r--winsup/cygwin/fhandler_socket.cc782
-rw-r--r--winsup/cygwin/include/cygwin/in.h36
-rw-r--r--winsup/cygwin/include/cygwin/in6.h119
-rw-r--r--winsup/cygwin/include/cygwin/socket.h15
-rw-r--r--winsup/cygwin/include/cygwin/stdlib.h2
-rw-r--r--winsup/cygwin/include/cygwin/version.h11
-rw-r--r--winsup/cygwin/include/netdb.h73
-rw-r--r--winsup/cygwin/include/netinet/in.h14
-rw-r--r--winsup/cygwin/include/sys/socket.h16
-rw-r--r--winsup/cygwin/libc/iruserok.c270
-rw-r--r--winsup/cygwin/libc/rcmd.cc782
-rw-r--r--winsup/cygwin/mmap.cc90
-rw-r--r--winsup/cygwin/net.cc1652
-rw-r--r--winsup/cygwin/poll.cc18
-rw-r--r--winsup/cygwin/security.cc126
-rw-r--r--winsup/cygwin/security.h6
-rw-r--r--winsup/cygwin/select.cc214
-rw-r--r--winsup/cygwin/select.h55
-rw-r--r--winsup/cygwin/syscalls.cc19
-rw-r--r--winsup/cygwin/tlsoffsets.h98
-rw-r--r--winsup/cygwin/tty.cc6
-rw-r--r--winsup/cygwin/uinfo.cc2
-rw-r--r--winsup/cygwin/winsup.h8
32 files changed, 3543 insertions, 1262 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index ffa55a87d..ec6966ecb 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,7 +1,75 @@
+2006-07-25 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/cygwin/version.h: Bump DLL version to 1.7.0.
+
+2006-07-25 Corinna Vinschen <corinna@vinschen.de>
+
+ * select.h: Remove.
+ * fhandler_socket.cc: Don't include select.h.
+ * select.cc: Ditto.
+
+2006-07-25 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygtls.h: Drop socket related includes.
+ (struct _local_storage): Remove exitsock and exitsock_sin. Add
+ select_sockevt.
+ * cygtls.cc: Accomodate above change throughout.
+ * fhandler.h (class fhandler_socket): Make wsock_evt public.
+ * fhandler_socket.cc (fhandler_socket::fhandler_socket): Accomodate
+ reordering members.
+ (fhandler_socket::evaluate_events): Drop FD_CONNECT event as soon as
+ it gets read once. Never remove FD_WRITE event here.
+ (fhandler_socket::wait_for_events): Wait 50 ms instead of INFINITE for
+ socket events.
+ (fhandler_socket::accept): Fix conditional. Set wsock_events members
+ of accepted socket to useful start values.
+ (fhandler_socket::recv_internal): Always drop FD_READ/FD_OOB events from
+ wsock_events after the call to WSARecvFrom.
+ (fhandler_socket::send_internal): Drop FD_WRITE event from wsock_events
+ if the call to WSASendTo fails with WSAEWOULDBLOCK. Fix return value
+ condition.
+ * select.cc (struct socketinf): Change to accomodate using socket event
+ handling.
+ (peek_socket): Use event handling for peeking socket.
+ (thread_socket): Ditto.
+ (start_thread_socket): Ditto.
+ (socket_cleanup): Same here.
+ * tlsoffsets.h: Regenerate.
+
2006-07-23 Christopher Faylor <cgf@timesys.com>
* include/cygwin/version.h: Bump DLL minor version number to 22.
+2006-07-20 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler.h (class fhandler_socket): Rearrange slightly to keep
+ event handling methods and members together. Drop owner status flag.
+ Split wait method. Rename event handling methods for readability.
+ * fhandler_socket.cc (struct wsa_event): Add owner field.
+ (LOCK_EVENTS): New macro.
+ (UNLOCK_EVENTS): Ditto.
+ (fhandler_socket::init_events): rename from prepare.
+ (fhandler_socket::evaluate_events): First half of former wait method.
+ Do everything but wait. Allow specifiying whether or not events from
+ event_mask should be erased from wsock_events->events. Simplify
+ OOB handling. Allow sending SIGURG to any process (group).
+ (fhandler_socket::wait_for_events): Second half of former wait method.
+ Call evaluate_events and wait in a loop if socket is blocking.
+ (fhandler_socket::release_events): Rename from release.
+ (fhandler_socket::connect): Accomodate above name changes.
+ (fhandler_socket::accept): Ditto.
+ (fhandler_socket::recv_internal): Ditto.
+ (fhandler_socket::send_internal): Ditto.
+ (fhandler_socket::close): Ditto.
+ (fhandler_socket::fcntl): Always set owner to given input value on
+ F_SETOWN. Handle F_GETOWN.
+ * net.cc (fdsock): Accomodate above name changes.
+
+2006-07-20 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_socket.cc (fhandler_socket::wait): Set Winsock errno to
+ WSAEWOULDBLOCK instead of WSAEINPROGRESS.
+
2006-07-19 Corinna Vinschen <corinna@vinschen.de>
* pinfo.cc (commune_process): Don't add extra \0 to cmdline.
@@ -26,11 +94,32 @@
* sec_acl.cc (acltotext32): Add missing handling of default ACL entry
types.
+2006-07-18 Brian Ford <Brian.Ford@FlightSafety.com>
+ Corinna Vinschen <corinna@vinschen.de>
+
+ * winsup.h (mmap_region_status): New enum.
+ (mmap_is_attached_or_noreserve_page): Adjust prototype and rename
+ as below.
+ * mmap.cc (mmap_is_attached_or_noreserve_page): Rename
+ mmap_is_attached_or_noreserve. Add region length parameter.
+ Return enum above.
+ * exceptions.cc (_cygtls::handle_exceptions): Accomodate above.
+ * fhandler.cc (fhandler_base::raw_read): Call above for NOACCESS
+ errors and retry on success to allow reads into untouched
+ MAP_NORESERVE buffers.
+
2006-07-18 Corinna Vinschen <corinna@vinschen.de>
* fhandler_floppy.cc (fhandler_dev_floppy::ioctl): Fix typo in lint
directive.
+2006-07-18 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygwin.din (posix_openpt): Export.
+ * tty.cc (posix_openpt): New function.
+ * include/cygwin/stdlib.h (posix_openpt): Declare.
+ * include/cygwin/version.h: Bump API minor number.
+
2006-07-17 Christopher Faylor <cgf@timesys.com>
GCC 4.1 fixes.
@@ -69,6 +158,19 @@
* dllfixdbg: Accommodate newer binutils which put the gnu_debuglink at
the end rather than at the beginning.
+2006-07-14 Corinna Vinschen <corinna@vinschen.de>
+
+ * security.cc (get_token_group_sidlist): Always add the interactive
+ group to the token. Add comment. Create logon_id group SID by
+ copying it from incoming group list.
+ (create_token): Add subauth_token parameter. Use information in
+ subauth_token if present. Tweak SourceIdentifier if subauth_token
+ is present for debugging purposes.
+ * security.h (create_token): Add subauth_token parameter in declaration.
+ * syscalls.cc (seteuid32): Call subauth first. Call create_token
+ regardless. Use subauth token in call to create_token if subauth
+ succeeded.
+
2006-07-13 Christopher Faylor <cgf@timesys.com>
* sigproc.cc (waitq_head): Don't initialize to zero.
@@ -83,11 +185,20 @@
2006-07-13 Corinna Vinschen <corinna@vinschen.de>
+ * include/netinet/in.h: Update copyright.
+
+2006-07-13 Corinna Vinschen <corinna@vinschen.de>
+
* fhandler_socket.cc: Update copyright.
* include/pthread.h: Ditto.
2006-07-13 Corinna Vinschen <corinna@vinschen.de>
+ * fhandler_socket.cc (fhandler_socket::wait): Rework function so that
+ WaitForMultipleObjects is really only called when necessary.
+
+2006-07-13 Corinna Vinschen <corinna@vinschen.de>
+
* mmap.cc (mmap64): Drop MAP_NORESERVE flag for non-anonymous,
non-private mappings.
(mmap_record::unmap_pages): Only check noreserve flag which now implies
@@ -118,9 +229,102 @@
2006-07-12 Corinna Vinschen <corinna@vinschen.de>
+ * include/netdb.h: Declare rcmd, rcmd_af, rexec, rresvport,
+ rresvport_af, iruserok, iruserok_sa, ruserok.
+
+2006-07-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in (DLL_OFILES): Drop iruserok.o. Add rcmd.o.
+ * autoload.cc (rcmd): Drop definition.
+ * cygwin.din: Export bindresvport, bindresvport_sa, iruserok_sa,
+ rcmd_af, rresvport_af.
+ * net.cc (cygwin_rcmd): Remove.
+ (last_used_bindresvport): Rename from last_used_rrecvport.
+ (cygwin_bindresvport_sa): New function implementing bindresvport_sa.
+ (cygwin_bindresvport): New function implementing bindresvport.
+ (cygwin_rresvport): Remove.
+ * include/cygwin/version.h: Bump API minor number.
+ * include/netinet/in.h: Declare bindresvport and bindresvport_sa.
+ * libc/iruserok.c: Remove file.
+ * libc/rcmd.cc: New file implementing rcmd, rcmd_af, rresvport,
+ rresvport_af, iruserok_sa, iruserok and ruserok.
+
+2006-07-12 Corinna Vinschen <corinna@vinschen.de>
+
* include/pthread.h: Define PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT and
PTHREAD_PRIO_PROTECT only if _POSIX_THREAD_PRIO_INHERIT is defined.
+2006-07-12 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_socket.cc (fhandler_socket::getsockname): Return valid
+ result for unbound sockets.
+
+2006-07-11 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler_socket.cc (fhandler_socket::fixup_after_fork): Handle
+ wsock_mtx and wsock_evt on fork, thus handling close_on_exec correctly.
+ (fhandler_socket::fixup_after_exec): Drop misguided attempt to handle
+ close_on_exec here.
+ (fhandler_socket::dup): Call fixup_after_fork with NULL parent.
+ Add comment.
+ (fhandler_socket::set_close_on_exec): Handle wsock_mtx and wsock_evt.
+
+2006-07-10 Corinna Vinschen <corinna@vinschen.de>
+
+ * fhandler.h (class fhandler_socket): Add wsock_mtx, wsock_evt
+ and wsock_events members. Remove closed status flag, add listener
+ status flag. Accomodate new implementation of socket event handling
+ methods. Declare recv* and send* functions ssize_t as the POSIX
+ equivalents.
+ (fhandler_socket::recv_internal): Declare.
+ (fhandler_socket::send_internal): Ditto.
+ * fhandler_socket.cc (EVENT_MASK): Define mask of selected events.
+ (fhandler_socket::fhandler_socket): Initialize new members.
+ (fhandler_socket::af_local_setblocking): Don't actually set the
+ socket to blocking mode. Keep sane event selection.
+ (fhandler_socket::af_local_unsetblocking): Don't actually set the
+ socket to previous blocking setting, just remember it.
+ (struct wsa_event): New structure to keep event data per shared
+ socket.
+ (NUM_SOCKS): Define number of shared sockets concurrently handled by
+ all active Cygwin processes.
+ (wsa_events): New shared datastructure keeping all wsa_event records.
+ (socket_serial_number): New shared variable to identify shared sockets.
+ (wsa_slot_mtx): Global mutex to serialize wsa_events access.
+ (search_wsa_event_slot): New static function to select a new wsa_event
+ slot for a new socket.
+ (fhandler_socket::prepare): Rewrite. Prepare event selection
+ per new socket.
+ (fhandler_socket::wait): Rewrite. Wait for socket events in thread
+ safe and multiple process safe.
+ (fhandler_socket::release): Rewrite. Close per-socket descriptor
+ mutex handle and event handle.
+ (fhandler_socket::dup): Duplicate wsock_mtx and wsock_evt. Fix
+ copy-paste error in debug output.
+ (fhandler_socket::connect): Accomodate new event handling.
+ (fhandler_socket::listen): Set listener flag on successful listen.
+ (fhandler_socket::accept): Accomodate new event handling.
+ (fhandler_socket::recv_internal): New inline method centralizing
+ common recv code.
+ (fhandler_socket::recvfrom): Call recv_internal now.
+ (fhandler_socket::recvmsg): Ditto. Streamline copying from iovec
+ to WSABUF.
+ (fhandler_socket::send_internal): New inline method centralizing
+ common send code.
+ (fhandler_socket::sendto): Call send_internal now.
+ (fhandler_socket::sendmsg): Ditto. Streamline copying from iovec
+ to WSABUF.
+ (fhandler_socket::close): Call release now.
+ (fhandler_socket::ioctl): Never actually switch to blocking mode.
+ Just keep track of the setting.
+ * net.cc (fdsock): Call prepare now.
+ (cygwin_connect): Revert again to event driven technique.
+ (cygwin_accept): Ditto.
+ * poll.cc (poll): Don't call recvfrom on a listening socket.
+ Remove special case for failing recvfrom.
+ * include/sys/socket.h: Declare recv* and send* functions ssize_t as
+ requested by POSIX.
+
2006-07-10 Corinna Vinschen <corinna@vinschen.de>
* libc/inet_addr.c: Define __INSIDE_CYGWIN_NET__.
@@ -133,6 +337,10 @@
2006-07-07 Corinna Vinschen <corinna@vinschen.de>
+ * net.cc (cygwin_inet_ntop): Fix data type of forth parameter.
+
+2006-07-07 Corinna Vinschen <corinna@vinschen.de>
+
* Makefile.in (DLL_OFILES): Add inet_addr.o and inet_network.o.
* autoload.cc (inet_addr): Drop definition.
(inet_ntoa): Ditto.
@@ -156,6 +364,79 @@
* child_info.h: Update copyright.
* fork.cc: Ditto.
+2006-07-06 Corinna Vinschen <corinna@vinschen.de>
+
+ * include/cygwin/in6.h (struct in6_addr): Fix typo.
+
+2006-07-06 Corinna Vinschen <corinna@vinschen.de>
+
+ * cygwin.din: Export in6addr_any, in6addr_loopback, freeaddrinfo,
+ gai_strerror, getaddrinfo, getnameinfo.
+ * fhandler_socket.cc: Include cygwin/in6.h.
+ (get_inet_addr): Accomodate AF_INET6 usage.
+ (fhandler_socket::connect): Ditto.
+ (fhandler_socket::listen): Ditto.
+ (fhandler_socket::sendto): Ditto.
+ * net.cc: Include cygwin/in6.h.
+ (in6addr_any): Define.
+ (in6addr_loopback): Define.
+ (cygwin_socket): Accomodate AF_INET6 usage.
+ (socketpair): Bind socketpairs only to loopback for security.
+ (inet_pton4): New static function.
+ (inet_pton6): Ditto.
+ (cygwin_inet_pton): New AF_INET6 aware inet_pton implementation.
+ (inet_ntop4): New static function.
+ (inet_ntop6): Ditto.
+ (cygwin_inet_ntop): New AF_INET6 aware inet_ntop implementation.
+ (ga_aistruct): New static function.
+ (ga_clone): Ditto.
+ (ga_echeck): Ditto.
+ (ga_nsearch): Ditto.
+ (ga_port): Ditto.
+ (ga_serv): Ditto.
+ (ga_unix): Ditto.
+ (gn_ipv46): Ditto.
+ (ipv4_freeaddrinfo): Ditto.
+ (ipv4_getaddrinfo): Ditto.
+ (ipv4_getnameinfo): Ditto.
+ (gai_errmap_t): New structure holding error code - error string mapping.
+ (cygwin_gai_strerror): New function implementing gai_strerror.
+ (w32_to_gai_err): New static function.
+ (get_ipv6_funcs): Ditto.
+ (load_ipv6_funcs): Ditto.
+ (cygwin_freeaddrinfo): New function implementing freeaddrinfo.
+ (cygwin_getaddrinfo): New function implementing getaddrinfo.
+ (cygwin_getnameinfo): New function implementing getnameinfo.
+ * include/netdb.h: Include stdint.h and cygwin/socket.h. Define
+ data types and macros used by getaddrinfo and friends. Declare
+ freeaddrinfo, gai_strerror, getaddrinfo and getnameinfo.
+ * include/cygwin/in.h: Add IPv6 related IPPROTOs. Remove definition
+ of struct sockaddr_in6. Include cygwin/in6.h instead.
+ * include/cygwin/in6.h: New header file defining IPv6 releated
+ data types and macros.
+ * include/cygwin/socket.h: Enable AF_INET6 and PF_INET6. Add
+ IPv6 related socket options.
+ * include/cygwin/version.h: Bump API minor number.
+
+2006-07-06 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc (DsGetDcNameA): Define.
+ (NetGetAnyDCName): Define.
+ * security.cc: Include dsgetdc.h.
+ (DsGetDcNameA): Declare.
+ (DS_FORCE_REDISCOVERY): Define.
+ (get_logon_server): Add bool parameter to control rediscovery of DC.
+ Use DsGetDcNameA function if supported, NetGetDCName/NetGetAnyDCName
+ otherwise.
+ (get_server_groups): Rediscover DC if get_user_groups fails and
+ try again.
+ (get_reg_security): Use correct error code macro when testing
+ RegGetKeySecurity return value.
+ * security.h (get_logon_server): Remove default vaue from wserver
+ parameter. Add rediscovery parameter.
+ * uinfo.cc (cygheap_user::env_logsrv): Accomodate rediscovery parameter
+ in call to get_logon_server.
+
2006-07-05 Christopher Faylor <cgf@timesys.com>
* sortdin: Ignore all leading underscores when deriving a sort key.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index b2ca09a66..bf7ea3de0 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -133,11 +133,11 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
fhandler_serial.o fhandler_socket.o fhandler_tape.o fhandler_termios.o \
fhandler_tty.o fhandler_virtual.o fhandler_windows.o fhandler_zero.o \
flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o grp.o heap.o \
- hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o iruserok.o \
- localtime.o lsearch.o malloc_wrapper.o memmem.o miscfuncs.o mktemp.o \
- mmap.o msg.o net.o netdb.o nftw.o ntea.o passwd.o path.o pinfo.o pipe.o \
- poll.o pthread.o regcomp.o regerror.o regexec.o regfree.o registry.o \
- resource.o rexec.o scandir.o sched.o sec_acl.o sec_helper.o security.o \
+ hookapi.o inet_addr.o inet_network.o init.o ioctl.o ipc.o localtime.o \
+ lsearch.o malloc_wrapper.o memmem.o miscfuncs.o mktemp.o mmap.o msg.o \
+ net.o netdb.o nftw.o ntea.o passwd.o path.o pinfo.o pipe.o poll.o \
+ pthread.o regcomp.o regerror.o regexec.o regfree.o registry.o resource.o \
+ rexec.o rcmd.o scandir.o sched.o sec_acl.o sec_helper.o security.o \
select.o sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \
spawn.o strace.o strptime.o strsep.o strsig.o sync.o syscalls.o \
sysconf.o syslog.o termios.o thread.o timelocal.o timer.o times.o tty.o \
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index a914e19ae..4493db856 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -370,7 +370,10 @@ LoadDLLfunc (SetSecurityDescriptorOwner, 12, advapi32)
LoadDLLfunc (SetTokenInformation, 16, advapi32)
LoadDLLfunc (RegGetKeySecurity, 16, advapi32)
+/* 127 == ERROR_PROC_NOT_FOUND */
+LoadDLLfuncEx2 (DsGetDcNameA, 24, netapi32, 1, 127)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
+LoadDLLfuncEx (NetGetAnyDCName, 12, netapi32, 1)
LoadDLLfuncEx (NetGetDCName, 12, netapi32, 1)
LoadDLLfunc (NetLocalGroupEnum, 28, netapi32)
LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32)
@@ -456,8 +459,6 @@ LoadDLLfunc (SetProcessWindowStation, 4, user32)
LoadDLLfunc (SetTimer, 16, user32)
LoadDLLfunc (SetUserObjectSecurity, 12, user32)
-LoadDLLfunc (rcmd, 24, wsock32)
-
LoadDLLfunc (accept, 12, ws2_32)
LoadDLLfunc (bind, 12, ws2_32)
LoadDLLfunc (closesocket, 4, ws2_32)
diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc
index e03175a1f..ce794cd38 100644
--- a/winsup/cygwin/cygtls.cc
+++ b/winsup/cygwin/cygtls.cc
@@ -106,7 +106,7 @@ _cygtls::init_thread (void *x, DWORD (*func) (void *, void *))
thread_id = GetCurrentThreadId ();
initialized = CYGTLS_INITIALIZED;
- locals.exitsock = INVALID_SOCKET;
+ locals.select_sockevt = INVALID_HANDLE_VALUE;
errno_addr = &(local_clib._errno);
if ((void *) func == (void *) cygthread::stub
@@ -137,7 +137,7 @@ _cygtls::fixup_after_fork ()
sig = 0;
}
stacklock = spinning = 0;
- locals.exitsock = INVALID_SOCKET;
+ locals.select_sockevt = INVALID_HANDLE_VALUE;
wq.thread_ev = NULL;
}
@@ -152,7 +152,7 @@ void
_cygtls::remove (DWORD wait)
{
initialized = 0;
- if (!locals.exitsock || exit_state >= ES_FINAL)
+ if (!locals.select_sockevt || exit_state >= ES_FINAL)
return;
debug_printf ("wait %p", wait);
@@ -160,10 +160,10 @@ _cygtls::remove (DWORD wait)
{
/* FIXME: Need some sort of atthreadexit function to allow things like
select to control this themselves. */
- if (locals.exitsock != INVALID_SOCKET)
+ if (locals.select_sockevt != INVALID_HANDLE_VALUE)
{
- closesocket (locals.exitsock);
- locals.exitsock = (SOCKET) NULL;
+ CloseHandle (locals.select_sockevt);
+ locals.select_sockevt = (HANDLE) NULL;
}
free_local (process_ident);
free_local (ntoa_buf);
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index 97800a701..d42ccc6f7 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -18,10 +18,6 @@ details. */
#undef _NOMNTENT_FUNCS
#include <setjmp.h>
#include <exceptions.h>
-#ifndef _WINSOCK_H
-#include <netinet/in.h>
-typedef unsigned int SOCKET;
-#endif
#define CYGTLS_INITIALIZED 0xc763173f
@@ -69,8 +65,7 @@ struct _local_storage
char mnt_dir[CYG_MAX_PATH];
/* select.cc */
- SOCKET exitsock;
- struct sockaddr_in exitsock_sin;
+ HANDLE select_sockevt;
/* strerror */
char strerror_buf[sizeof ("Unknown error 4294967295")];
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 09b34454e..a80ea388f 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -11,6 +11,8 @@ __cygwin_user_data DATA
_daylight DATA
h_errno DATA
_impure_ptr DATA
+in6addr_any DATA
+in6addr_loopback DATA
__mb_cur_max DATA
optarg DATA
opterr DATA
@@ -145,6 +147,8 @@ _bcmp = bcmp NOSIGFE
bcopy NOSIGFE
_bcopy = bcopy NOSIGFE
bind = cygwin_bind SIGFE
+bindresvport = cygwin_bindresvport SIGFE
+bindresvport_sa = cygwin_bindresvport_sa SIGFE
bsearch NOSIGFE
_bsearch = bsearch NOSIGFE
btowc NOSIGFE
@@ -471,6 +475,7 @@ fread SIGFE
_fread = fread SIGFE
free SIGFE
_free = free SIGFE
+freeaddrinfo = cygwin_freeaddrinfo SIGFE
freopen SIGFE
_freopen = freopen SIGFE
_freopen64 = freopen64 SIGFE
@@ -524,6 +529,7 @@ funlockfile SIGFE
futimes SIGFE
fwrite SIGFE
_fwrite = fwrite SIGFE
+gai_strerror = cygwin_gai_strerror NOSIGFE
gamma NOSIGFE
_gamma = gamma NOSIGFE
gamma_r NOSIGFE
@@ -538,6 +544,7 @@ gcvtf SIGFE
_gcvtf = gcvtf SIGFE
get_osfhandle SIGFE
_get_osfhandle = get_osfhandle SIGFE
+getaddrinfo = cygwin_getaddrinfo SIGFE
getc SIGFE
_getc = getc SIGFE
getc_unlocked SIGFE
@@ -594,6 +601,7 @@ getmntent SIGFE
_getmntent = getmntent SIGFE
getmode SIGFE
_getmode = getmode SIGFE
+getnameinfo = cygwin_getnameinfo SIGFE
getopt SIGFE
getopt_long SIGFE
getopt_long_only SIGFE
@@ -714,6 +722,7 @@ _ioctl = ioctl SIGFE
iprintf SIGFE
_iprintf = iprintf SIGFE
iruserok SIGFE
+iruserok_sa SIGFE
isalnum NOSIGFE
_isalnum = isalnum NOSIGFE
isalpha NOSIGFE
@@ -967,6 +976,7 @@ poll SIGFE
_poll = poll SIGFE
popen SIGFE
_popen = popen SIGFE
+posix_openpt SIGFE
posix_regcomp SIGFE
posix_regerror SIGFE
posix_regexec SIGFE
@@ -1086,6 +1096,7 @@ _rand = rand NOSIGFE
rand_r NOSIGFE
random NOSIGFE
rcmd = cygwin_rcmd SIGFE
+rcmd_af = cygwin_rcmd_af SIGFE
read SIGFE
_read = read SIGFE
readdir SIGFE
@@ -1128,6 +1139,7 @@ _rmdir = rmdir SIGFE
round NOSIGFE
roundf NOSIGFE
rresvport = cygwin_rresvport SIGFE
+rresvport_af = cygwin_rresvport_af SIGFE
ruserok SIGFE
sbrk SIGFE
_sbrk = sbrk SIGFE
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index e5345f13e..9b49d5e70 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -526,12 +526,13 @@ _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT
break;
case STATUS_ACCESS_VIOLATION:
- switch (mmap_is_attached_or_noreserve_page (e->ExceptionInformation[1]))
+ switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
+ 1))
{
- case 2: /* MAP_NORESERVE page, now commited. */
+ case MMAP_NORESERVE_COMMITED:
return 0;
- case 1: /* MAP_NORESERVE page, commit failed, or
- access to mmap page beyond EOF. */
+ case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
+ access to mmap page beyond EOF. */
si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR;
break;
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 539c2e8fa..d33b28d94 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -223,8 +223,10 @@ fhandler_base::raw_read (void *ptr, size_t& ulen)
HANDLE h = NULL; /* grumble */
int prio = 0; /* ditto */
+ int try_noreserve = 1;
DWORD len = ulen;
+retry:
ulen = (size_t) -1;
if (read_state)
{
@@ -259,6 +261,20 @@ fhandler_base::raw_read (void *ptr, size_t& ulen)
bytes_read = 0;
break;
}
+ if (try_noreserve)
+ {
+ try_noreserve = 0;
+ switch (mmap_is_attached_or_noreserve (ptr, len))
+ {
+ case MMAP_NORESERVE_COMMITED:
+ goto retry;
+ case MMAP_RAISE_SIGBUS:
+ raise(SIGBUS);
+ case MMAP_NONE:
+ break;
+ }
+ }
+ /*FALLTHRU*/
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_HANDLE:
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 7b637c85a..6468560b3 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -378,6 +378,8 @@ class fhandler_mailslot : public fhandler_base
select_record *select_read (select_record *s);
};
+struct wsa_event;
+
class fhandler_socket: public fhandler_base
{
private:
@@ -385,6 +387,16 @@ class fhandler_socket: public fhandler_base
int type;
int connect_secret[4];
+ wsa_event *wsock_events;
+ HANDLE wsock_mtx;
+ public:
+ HANDLE wsock_evt;
+ bool init_events ();
+ int evaluate_events (const long event_mask, long &events, bool erase);
+ private:
+ int wait_for_events (const long event_mask);
+ void release_events ();
+
pid_t sec_pid;
__uid32_t sec_uid;
__gid32_t sec_gid;
@@ -414,20 +426,15 @@ class fhandler_socket: public fhandler_base
unsigned saw_shutdown_read : 1; /* Socket saw a SHUT_RD */
unsigned saw_shutdown_write : 1; /* Socket saw a SHUT_WR */
unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */
- unsigned closed : 1;
- unsigned owner : 1;
+ unsigned listener : 1; /* listen called */
unsigned connect_state : 2;
public:
status_flags () :
async_io (0), saw_shutdown_read (0), saw_shutdown_write (0),
- closed (0), owner (0), connect_state (unconnected)
+ listener (0), connect_state (unconnected)
{}
} status;
- bool prepare (HANDLE &event, long event_mask);
- int wait (HANDLE event, int flags, DWORD timeout = 10);
- void release (HANDLE event);
-
public:
fhandler_socket ();
~fhandler_socket ();
@@ -438,8 +445,7 @@ class fhandler_socket: public fhandler_base
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write)
IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr)
- IMPLEMENT_STATUS_FLAG (bool, closed)
- IMPLEMENT_STATUS_FLAG (bool, owner)
+ IMPLEMENT_STATUS_FLAG (bool, listener)
IMPLEMENT_STATUS_FLAG (conn_state, connect_state)
int bind (const struct sockaddr *name, int namelen);
@@ -452,14 +458,19 @@ class fhandler_socket: public fhandler_base
int open (int flags, mode_t mode = 0);
ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
- int recvfrom (void *ptr, size_t len, int flags,
- struct sockaddr *from, int *fromlen);
- int recvmsg (struct msghdr *msg, int flags, ssize_t tot = -1);
+ inline ssize_t recv_internal (struct _WSABUF *wsabuf, DWORD wsacnt,
+ DWORD flags,
+ struct sockaddr *from, int *fromlen);
+ ssize_t recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen);
+ ssize_t recvmsg (struct msghdr *msg, int flags, ssize_t tot = -1);
ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
- int sendto (const void *ptr, size_t len, int flags,
+ inline ssize_t send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags,
+ const struct sockaddr *to, int tolen);
+ ssize_t sendto (const void *ptr, size_t len, int flags,
const struct sockaddr *to, int tolen);
- int sendmsg (const struct msghdr *msg, int flags, ssize_t tot = -1);
+ ssize_t sendmsg (const struct msghdr *msg, int flags, ssize_t tot = -1);
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, void *);
diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc
index 7ca4ed10f..63858206d 100644
--- a/winsup/cygwin/fhandler_socket.cc
+++ b/winsup/cygwin/fhandler_socket.cc
@@ -30,15 +30,17 @@
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "shared_info.h"
#include "sigproc.h"
#include "cygthread.h"
-#include "select.h"
#include "wininfo.h"
#include <unistd.h>
#include <sys/acl.h>
#include "cygtls.h"
+#include "cygwin/in6.h"
#define ASYNC_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT)
+#define EVENT_MASK (FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE)
extern bool fdsock (cygheap_fdmanip& fd, const device *, SOCKET soc);
extern "C" {
@@ -50,15 +52,15 @@ fhandler_dev_random* entropy_source;
/* 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,
+ struct sockaddr_storage *out, int *outlen,
int *type = NULL, int *secret = NULL)
{
int secret_buf [4];
int* secret_ptr = (secret ? : secret_buf);
- if (in->sa_family == AF_INET)
+ if (in->sa_family == AF_INET || in->sa_family == AF_INET6)
{
- *out = * (struct sockaddr_in *)in;
+ memcpy (out, in, inlen);
*outlen = inlen;
return 1;
}
@@ -102,7 +104,7 @@ get_inet_addr (const struct sockaddr *in, int inlen,
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;
+ memcpy (out, &sin, sizeof sin);
*outlen = sizeof sin;
if (type)
*type = (ctype == 's' ? SOCK_STREAM :
@@ -127,6 +129,9 @@ get_inet_addr (const struct sockaddr *in, int inlen,
fhandler_socket::fhandler_socket () :
fhandler_base (),
+ wsock_events (NULL),
+ wsock_mtx (NULL),
+ wsock_evt (NULL),
sun_path (NULL),
status ()
{
@@ -178,10 +183,11 @@ fhandler_socket::af_local_setblocking (bool &async, bool &nonblocking)
{
async = async_io ();
nonblocking = is_nonblocking ();
- if (async || nonblocking)
- WSAAsyncSelect (get_socket (), winmsg, 0, 0);
- unsigned long p = 0;
- ioctlsocket (get_socket (), FIONBIO, &p);
+ if (async)
+ {
+ WSAAsyncSelect (get_socket (), winmsg, 0, 0);
+ WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK);
+ }
set_nonblocking (false);
async_io (false);
}
@@ -190,11 +196,7 @@ void
fhandler_socket::af_local_unsetblocking (bool async, bool nonblocking)
{
if (nonblocking)
- {
- unsigned long p = 1;
- ioctlsocket (get_socket (), FIONBIO, &p);
- set_nonblocking (true);
- }
+ set_nonblocking (true);
if (async)
{
WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, ASYNC_MASK);
@@ -392,6 +394,210 @@ fhandler_socket::af_local_set_secret (char *buf)
connect_secret [2], connect_secret [3]);
}
+struct wsa_event
+{
+ LONG serial_number;
+ long events;
+ int connect_errorcode;
+ pid_t owner;
+};
+
+/* Maximum number of concurrently opened sockets from all Cygwin processes
+ on a machine. Note that shared sockets (through dup/fork/exec) are
+ counted as one socket. */
+#define NUM_SOCKS (65536 / sizeof (wsa_event))
+
+#define LOCK_EVENTS WaitForSingleObject (wsock_mtx, INFINITE)
+#define UNLOCK_EVENTS ReleaseMutex (wsock_mtx)
+
+static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared)) = { 0 };
+
+static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared)) = 0;
+
+static HANDLE wsa_slot_mtx;
+
+static wsa_event *
+search_wsa_event_slot (LONG new_serial_number)
+{
+ char name[CYG_MAX_PATH], searchname[CYG_MAX_PATH];
+
+ if (!wsa_slot_mtx)
+ {
+ wsa_slot_mtx = CreateMutex (&sec_all, FALSE,
+ shared_name (name, "sock", 0));
+ if (!wsa_slot_mtx)
+ api_fatal ("Couldn't create/open shared socket mutex, %E");
+ }
+ switch (WaitForSingleObject (wsa_slot_mtx, INFINITE))
+ {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ break;
+ default:
+ api_fatal ("WFSO failed for shared socket mutex, %E");
+ break;
+ }
+ unsigned int slot = new_serial_number % NUM_SOCKS;
+ while (wsa_events[slot].serial_number)
+ {
+ HANDLE searchmtx = OpenMutex (STANDARD_RIGHTS_READ, FALSE,
+ shared_name (searchname, "sock", wsa_events[slot].serial_number));
+ if (!searchmtx)
+ break;
+ /* Mutex still exists, attached socket is active, try next slot. */
+ CloseHandle (searchmtx);
+ slot = (slot + 1) % NUM_SOCKS;
+ if (slot == (new_serial_number % NUM_SOCKS))
+ {
+ /* Did the whole array once. Too bad. */
+ debug_printf ("No free socket slot");
+ ReleaseMutex (wsa_slot_mtx);
+ return NULL;
+ }
+ }
+ wsa_events[slot].serial_number = new_serial_number;
+ ReleaseMutex (wsa_slot_mtx);
+ return wsa_events + slot;
+}
+
+bool
+fhandler_socket::init_events ()
+{
+ LONG new_serial_number;
+ char name[CYG_MAX_PATH];
+ DWORD err = 0;
+
+ do
+ {
+ new_serial_number = InterlockedIncrement (&socket_serial_number);
+ if (!new_serial_number) /* 0 is reserved for global mutex */
+ InterlockedIncrement (&socket_serial_number);
+ wsock_mtx = CreateMutex (&sec_all, FALSE,
+ shared_name (name, "sock", new_serial_number));
+ if (!wsock_mtx)
+ {
+ debug_printf ("CreateMutex, %E");
+ set_errno (ENOBUFS);
+ return false;
+ }
+ err = GetLastError ();
+ if (err == ERROR_ALREADY_EXISTS)
+ CloseHandle (wsock_mtx);
+ }
+ while (err == ERROR_ALREADY_EXISTS);
+ if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL))
+ == WSA_INVALID_EVENT)
+ {
+ debug_printf ("WSACreateEvent, %E");
+ set_errno (ENOBUFS);
+ CloseHandle (wsock_mtx);
+ return false;
+ }
+ if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR)
+ {
+ debug_printf ("WSAEventSelect, %E");
+ set_winsock_errno ();
+ CloseHandle (wsock_evt);
+ CloseHandle (wsock_mtx);
+ return false;
+ }
+ wsock_events = search_wsa_event_slot (new_serial_number);
+ memset (wsock_events, 0, sizeof *wsock_events);
+ return true;
+}
+
+int
+fhandler_socket::evaluate_events (const long event_mask, long &events,
+ bool erase)
+{
+ int ret = 0;
+
+ WSANETWORKEVENTS evts = { 0 };
+ if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts)))
+ {
+ if (evts.lNetworkEvents)
+ {
+ LOCK_EVENTS;
+ wsock_events->events |= evts.lNetworkEvents;
+ if (evts.lNetworkEvents & FD_CONNECT)
+ wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
+ UNLOCK_EVENTS;
+ if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner)
+ kill (wsock_events->owner, SIGURG);
+ }
+ }
+
+ LOCK_EVENTS;
+ if ((events = (wsock_events->events & event_mask)) != 0)
+ {
+ if (events & FD_CONNECT)
+ {
+ int wsa_err = 0;
+ if ((wsa_err = wsock_events->connect_errorcode) != 0)
+ {
+ WSASetLastError (wsa_err);
+ ret = SOCKET_ERROR;
+ }
+ wsock_events->connect_errorcode = 0;
+ wsock_events->events &= ~FD_CONNECT;
+ }
+ if (erase)
+ wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
+ }
+ UNLOCK_EVENTS;
+
+ return ret;
+}
+
+int
+fhandler_socket::wait_for_events (const long event_mask)
+{
+ if (async_io ())
+ return 0;
+
+ int ret;
+ long events;
+
+ while (!(ret = evaluate_events (event_mask, events, true)) && !events)
+ {
+ if (is_nonblocking ())
+ {
+ WSASetLastError (WSAEWOULDBLOCK);
+ return SOCKET_ERROR;
+ }
+
+ WSAEVENT ev[2] = { wsock_evt, signal_arrived };
+ switch (WSAWaitForMultipleEvents (2, ev, FALSE, 50, FALSE))
+ {
+ case WSA_WAIT_TIMEOUT:
+ case WSA_WAIT_EVENT_0:
+ break;
+
+ case WSA_WAIT_EVENT_0 + 1:
+ if (_my_tls.call_signal_handler ())
+ {
+ sig_dispatch_pending ();
+ break;
+ }
+ WSASetLastError (WSAEINTR);
+ return SOCKET_ERROR;
+
+ default:
+ WSASetLastError (WSAEFAULT);
+ return SOCKET_ERROR;
+ }
+ }
+
+ return ret;
+}
+
+void
+fhandler_socket::release_events ()
+{
+ CloseHandle (wsock_evt);
+ CloseHandle (wsock_mtx);
+}
+
void
fhandler_socket::fixup_before_fork_exec (DWORD win_proc_id)
{
@@ -437,6 +643,11 @@ fhandler_socket::fixup_after_fork (HANDLE parent)
set_io_handle ((HANDLE) new_sock);
}
+ if (parent) /* fork, not exec or dup */
+ {
+ fork_fixup (parent, wsock_mtx, "wsock_mtx");
+ fork_fixup (parent, wsock_evt, "wsock_evt");
+ }
}
void
@@ -453,6 +664,24 @@ fhandler_socket::dup (fhandler_base *child)
debug_printf ("here");
fhandler_socket *fhs = (fhandler_socket *) child;
+
+ if (!DuplicateHandle (hMainProc, wsock_mtx, hMainProc, &fhs->wsock_mtx, 0,
+ TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("DuplicateHandle(%x) failed, %E", wsock_mtx);
+ __seterrno ();
+ return -1;
+ }
+ if (!DuplicateHandle (hMainProc, wsock_evt, hMainProc, &fhs->wsock_evt, 0,
+ TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ system_printf ("DuplicateHandle(%x) failed, %E", wsock_evt);
+ __seterrno ();
+ CloseHandle (fhs->wsock_mtx);
+ return -1;
+ }
+ fhs->wsock_events = wsock_events;
+
fhs->addr_family = addr_family;
fhs->set_socket_type (get_socket_type ());
if (get_addr_family () == AF_LOCAL)
@@ -483,7 +712,9 @@ fhandler_socket::dup (fhandler_base *child)
cygheap->user.reimpersonate ();
if (!WSAGetLastError ())
{
- fhs->fixup_after_fork (hMainProc);
+ /* Call with NULL parent, otherwise wsock_mtx and wsock_evt are
+ duplicated again with wrong close_on_exec settings. */
+ fhs->fixup_after_fork (NULL);
if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET)
{
cygheap->fdtab.inc_need_fixup_before ();
@@ -499,8 +730,10 @@ fhandler_socket::dup (fhandler_base *child)
if (!DuplicateHandle (hMainProc, get_io_handle (), hMainProc, &nh, 0,
FALSE, DUPLICATE_SAME_ACCESS))
{
- system_printf ("!DuplicateHandle(%x) failed, %E", get_io_handle ());
+ system_printf ("DuplicateHandle(%x) failed, %E", get_io_handle ());
__seterrno ();
+ CloseHandle (fhs->wsock_evt);
+ CloseHandle (fhs->wsock_mtx);
return -1;
}
VerifyHandle (nh);
@@ -739,11 +972,11 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
{
int res = -1;
bool in_progress = false;
- struct sockaddr_in sin;
+ struct sockaddr_storage sst;
DWORD err;
int type;
- if (!get_inet_addr (name, namelen, &sin, &namelen, &type, connect_secret))
+ if (!get_inet_addr (name, namelen, &sst, &namelen, &type, connect_secret))
return -1;
if (get_addr_family () == AF_LOCAL && get_socket_type () != type)
@@ -753,7 +986,11 @@ fhandler_socket::connect (const struct sockaddr *name, int namelen)
return -1;
}
- res = ::connect (get_socket (), (struct sockaddr *) &sin, namelen);
+ res = ::connect (get_socket (), (struct sockaddr *) &sst, namelen);
+ if (!is_nonblocking ()
+ && res == SOCKET_ERROR
+ && WSAGetLastError () == WSAEWOULDBLOCK)
+ res = wait_for_events (FD_CONNECT | FD_CLOSE);
if (!res)
err = 0;
@@ -804,25 +1041,42 @@ int
fhandler_socket::listen (int backlog)
{
int res = ::listen (get_socket (), backlog);
- if (res && WSAGetLastError () == WSAEINVAL && get_addr_family () == AF_INET)
+ if (res && WSAGetLastError () == WSAEINVAL)
{
/* It's perfectly valid to call listen on an unbound INET socket.
In this case the socket is automatically bound to an unused
port number, listening on all interfaces. On Winsock, listen
fails with WSAEINVAL when it's called on an unbound socket.
So we have to bind manually here to have POSIX semantics. */
- struct sockaddr_in sa;
- sa.sin_family = AF_INET;
- sa.sin_port = 0;
- sa.sin_addr.s_addr = INADDR_ANY;
- if (!::bind (get_socket (), (struct sockaddr *) &sa, sizeof sa))
- res = ::listen (get_socket (), backlog);
+ if (get_addr_family () == AF_INET)
+ {
+ struct sockaddr_in sin;
+ sin.sin_family = AF_INET;
+ sin.sin_port = 0;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ if (!::bind (get_socket (), (struct sockaddr *) &sin, sizeof sin))
+ res = ::listen (get_socket (), backlog);
+ }
+ else if (get_addr_family () == AF_INET6)
+ {
+ struct sockaddr_in6 sin6 =
+ {
+ sin6_family: AF_INET6,
+ sin6_port: 0,
+ sin6_flowinfo: 0,
+ sin6_addr: IN6ADDR_ANY_INIT,
+ sin6_scope_id: 0
+ };
+ if (!::bind (get_socket (), (struct sockaddr *) &sin6, sizeof sin6))
+ res = ::listen (get_socket (), backlog);
+ }
}
if (!res)
{
if (get_addr_family () == AF_LOCAL && get_socket_type () == SOCK_STREAM)
af_local_set_cred ();
connect_state (connected);
+ listener (true);
}
else
set_winsock_errno ();
@@ -832,8 +1086,6 @@ fhandler_socket::listen (int backlog)
int
fhandler_socket::accept (struct sockaddr *peer, int *len)
{
- int res = -1;
-
/* Allows NULL peer and len parameters. */
struct sockaddr_in peer_dummy;
int len_dummy;
@@ -852,8 +1104,12 @@ fhandler_socket::accept (struct sockaddr *peer, int *len)
if (len && ((unsigned) *len < sizeof (struct sockaddr_in)))
*len = sizeof (struct sockaddr_in);
- res = ::accept (get_socket (), peer, len);
+ int res = 0;
+ while (!(res = wait_for_events (FD_ACCEPT | FD_CLOSE))
+ && (res = ::accept (get_socket (), peer, len)) == SOCKET_ERROR
+ && WSAGetLastError () == WSAEWOULDBLOCK)
+ ;
if (res == (int) INVALID_SOCKET)
set_winsock_errno ();
else
@@ -884,6 +1140,9 @@ fhandler_socket::accept (struct sockaddr *peer, int *len)
}
}
}
+ /* No locking necessary at this point. */
+ sock->wsock_events->events = wsock_events->events | FD_WRITE;
+ sock->wsock_events->owner = wsock_events->owner;
sock->connect_state (connected);
res = res_fd;
}
@@ -928,7 +1187,36 @@ fhandler_socket::getsockname (struct sockaddr *name, int *namelen)
{
res = ::getsockname (get_socket (), name, namelen);
if (res)
- set_winsock_errno ();
+ {
+ if (WSAGetLastError () == WSAEINVAL)
+ {
+ /* Winsock returns WSAEINVAL if the socket is locally
+ unbound. Per SUSv3 this is not an error condition.
+ We're faking a valid return value here by creating the
+ same content in the sockaddr structure as on Linux. */
+ switch (get_addr_family ())
+ {
+ case AF_INET:
+ res = 0;
+ *namelen = sizeof (struct sockaddr_in);
+ break;
+ case AF_INET6:
+ res = 0;
+ *namelen = sizeof (struct sockaddr_in6);
+ break;
+ default:
+ WSASetLastError (WSAEOPNOTSUPP);
+ break;
+ }
+ if (!res)
+ {
+ memset (name, 0, *namelen);
+ name->sa_family = get_addr_family ();
+ }
+ }
+ if (res)
+ set_winsock_errno ();
+ }
}
return res;
@@ -944,139 +1232,6 @@ fhandler_socket::getpeername (struct sockaddr *name, int *namelen)
return res;
}
-bool
-fhandler_socket::prepare (HANDLE &event, long event_mask)
-{
- WSASetLastError (0);
- closed (false);
- if ((event = WSACreateEvent ()) == WSA_INVALID_EVENT)
- {
- debug_printf ("WSACreateEvent, %E");
- return false;
- }
- if (WSAEventSelect (get_socket (), event, event_mask) == SOCKET_ERROR)
- {
- debug_printf ("WSAEventSelect(evt), %d", WSAGetLastError ());
- return false;
- }
- return true;
-}
-
-int
-fhandler_socket::wait (HANDLE event, int flags, DWORD timeout)
-{
- int ret = SOCKET_ERROR;
- int wsa_err = 0;
- WSAEVENT ev[2] = { event, signal_arrived };
- WSANETWORKEVENTS evts;
-
-#if 0 /* Not yet. Not this way. */
-/* If WSAWaitForMultipleEvents is interrupted by a signal, and the signal
- has the SA_RESTART flag set, return to this label and... restart. */
-sa_restart:
-#endif
-
- switch (WSAWaitForMultipleEvents (2, ev, FALSE, timeout, FALSE))
- {
- case WSA_WAIT_TIMEOUT:
- ret = 0;
- break;
- case WSA_WAIT_EVENT_0:
- if (!WSAEnumNetworkEvents (get_socket (), event, &evts))
- {
- if (!evts.lNetworkEvents)
- {
- ret = 0;
- break;
- }
- if (evts.lNetworkEvents & FD_OOB)
- {
- if (evts.iErrorCode[FD_OOB_BIT])
- wsa_err = evts.iErrorCode[FD_OOB_BIT];
- else if (flags & MSG_OOB)
- ret = 0;
- else
- {
- raise (SIGURG);
- WSASetLastError (WSAEINTR);
- break;
- }
- }
- if (evts.lNetworkEvents & FD_ACCEPT)
- {
- if (evts.iErrorCode[FD_ACCEPT_BIT])
- wsa_err = evts.iErrorCode[FD_ACCEPT_BIT];
- else
- ret = 0;
- }
- if (evts.lNetworkEvents & FD_CONNECT)
- {
- if (evts.iErrorCode[FD_CONNECT_BIT])
- wsa_err = evts.iErrorCode[FD_CONNECT_BIT];
- else
- ret = 0;
- }
- else if (evts.lNetworkEvents & FD_READ)
- {
- if (evts.iErrorCode[FD_READ_BIT])
- wsa_err = evts.iErrorCode[FD_READ_BIT];
- else
- ret = 0;
- }
- else if (evts.lNetworkEvents & FD_WRITE)
- {
- if (evts.iErrorCode[FD_WRITE_BIT])
- wsa_err = evts.iErrorCode[FD_WRITE_BIT];
- else
- ret = 0;
- }
- if (evts.lNetworkEvents & FD_CLOSE)
- {
- closed (true);
- if (!wsa_err)
- {
- if (evts.iErrorCode[FD_CLOSE_BIT])
- wsa_err = evts.iErrorCode[FD_CLOSE_BIT];
- else
- ret = 0;
- }
- }
- if (wsa_err)
- WSASetLastError (wsa_err);
- }
- break;
- case WSA_WAIT_EVENT_0 + 1:
-#if 0 /* Not yet. Not this way. */
- if (_my_tls.call_signal_handler ())
- {
- sig_dispatch_pending ();
- goto sa_restart;
- }
-#endif
- WSASetLastError (WSAEINTR);
- break;
- default:
- WSASetLastError (WSAEFAULT);
- break;
- }
- return ret;
-}
-
-void
-fhandler_socket::release (HANDLE event)
-{
- int last_err = WSAGetLastError ();
- /* KB 168349: NT4 fails if the event parameter is not NULL. */
- if (WSAEventSelect (get_socket (), NULL, 0) == SOCKET_ERROR)
- debug_printf ("WSAEventSelect(NULL), %d", WSAGetLastError ());
- WSACloseEvent (event);
- unsigned long non_block = 0;
- if (ioctlsocket (get_socket (), FIONBIO, &non_block))
- debug_printf ("return to blocking failed: %d", WSAGetLastError ());
- else
- WSASetLastError (last_err);
-}
-
int
fhandler_socket::readv (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
@@ -1095,38 +1250,36 @@ fhandler_socket::readv (const struct iovec *const iov, const int iovcnt,
return recvmsg (&msg, 0, tot);
}
-int
-fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
- struct sockaddr *from, int *fromlen)
+inline ssize_t
+fhandler_socket::recv_internal (WSABUF *wsabuf, DWORD wsacnt, DWORD flags,
+ struct sockaddr *from, int *fromlen)
{
- int res = SOCKET_ERROR;
+ ssize_t res = 0;
DWORD ret = 0;
+ int evt_mask = FD_READ | ((flags & MSG_OOB) ? FD_OOB : 0);
- WSABUF wsabuf = { len, (char *) ptr };
-
- if (is_nonblocking () || closed () || async_io ())
+ flags &= MSG_WINMASK;
+ if (flags & MSG_PEEK)
{
- DWORD lflags = (DWORD) (flags & MSG_WINMASK);
- res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret,
- &lflags, from, fromlen, NULL, NULL);
+ LOCK_EVENTS;
+ res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &ret,
+ &flags, from, fromlen, NULL, NULL);
+ wsock_events->events &= ~evt_mask;
+ UNLOCK_EVENTS;
}
else
{
- HANDLE evt;
- if (prepare (evt, FD_CLOSE | FD_READ | (owner () ? FD_OOB : 0)))
- {
- do
- {
- DWORD lflags = (DWORD) (flags & MSG_WINMASK);
- res = WSARecvFrom (get_socket (), &wsabuf, 1, &ret, &lflags,
- from, fromlen, NULL, NULL);
- }
- while (res == SOCKET_ERROR
- && WSAGetLastError () == WSAEWOULDBLOCK
- && !closed ()
- && !(res = wait (evt, flags)));
- release (evt);
+ do
+ {
+ LOCK_EVENTS;
+ res = WSARecvFrom (get_socket (), wsabuf, wsacnt, &ret,
+ &flags, from, fromlen, NULL, NULL);
+ wsock_events->events &= ~evt_mask;
+ UNLOCK_EVENTS;
}
+ while (res && WSAGetLastError () == WSAEWOULDBLOCK
+ && !(res = wait_for_events (evt_mask | FD_CLOSE)))
+ ;
}
if (res == SOCKET_ERROR)
@@ -1134,7 +1287,7 @@ fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
/* According to SUSv3, errno isn't set in that case and no error
condition is returned. */
if (WSAGetLastError () == WSAEMSGSIZE)
- return len;
+ return ret;
/* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned
in this case. */
@@ -1150,6 +1303,14 @@ fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
}
int
+fhandler_socket::recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen)
+{
+ WSABUF wsabuf = { len, (char *) ptr };
+ return recv_internal (&wsabuf, 1, flags, from, fromlen);
+}
+
+int
fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot)
{
if (CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR)
@@ -1169,73 +1330,19 @@ fhandler_socket::recvmsg (struct msghdr *msg, int flags, ssize_t tot)
/*TODO*/
}
- struct iovec *const iov = msg->msg_iov;
- const int iovcnt = msg->msg_iovlen;
-
- struct sockaddr *from = (struct sockaddr *) msg->msg_name;
- int *fromlen = from ? &msg->msg_namelen : NULL;
-
- int res = SOCKET_ERROR;
-
- WSABUF wsabuf[iovcnt];
- unsigned long len = 0L;
-
- const struct iovec *iovptr = iov + iovcnt;
- WSABUF *wsaptr = wsabuf + iovcnt;
- do
+ WSABUF wsabuf[msg->msg_iovlen];
+ WSABUF *wsaptr = wsabuf + msg->msg_iovlen;
+ const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen;
+ while (--wsaptr >= wsabuf)
{
- iovptr -= 1;
- wsaptr -= 1;
- len += wsaptr->len = iovptr->iov_len;
+ wsaptr->len = (--iovptr)->iov_len;
wsaptr->buf = (char *) iovptr->iov_base;
}
- while (wsaptr != wsabuf);
-
- DWORD ret = 0;
-
- if (is_nonblocking () || closed () || async_io ())
- {
- DWORD lflags = (DWORD) (flags & MSG_WINMASK);
- res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret,
- &lflags, from, fromlen, NULL, NULL);
- }
- else
- {
- HANDLE evt;
- if (prepare (evt, FD_CLOSE | FD_READ | (owner () ? FD_OOB : 0)))
- {
- do
- {
- DWORD lflags = (DWORD) (flags & MSG_WINMASK);
- res = WSARecvFrom (get_socket (), wsabuf, iovcnt, &ret,
- &lflags, from, fromlen, NULL, NULL);
- }
- while (res == SOCKET_ERROR
- && WSAGetLastError () == WSAEWOULDBLOCK
- && !closed ()
- && !(res = wait (evt, flags)));
- release (evt);
- }
- }
-
- if (res == SOCKET_ERROR)
- {
- /* According to SUSv3, errno isn't set in that case and no error
- condition is returned. */
- if (WSAGetLastError () == WSAEMSGSIZE)
- return len;
- /* ESHUTDOWN isn't defined for recv in SUSv3. Simply EOF is returned
- in this case. */
- if (WSAGetLastError () == WSAESHUTDOWN)
- return 0;
-
- set_winsock_errno ();
- }
- else
- res = ret;
+ struct sockaddr *from = (struct sockaddr *) msg->msg_name;
+ int *fromlen = from ? &msg->msg_namelen : NULL;
- return res;
+ return recv_internal (wsabuf, msg->msg_iovlen, flags, from, fromlen);
}
int
@@ -1256,44 +1363,23 @@ fhandler_socket::writev (const struct iovec *const iov, const int iovcnt,
return sendmsg (&msg, 0, tot);
}
-int
-fhandler_socket::sendto (const void *ptr, size_t len, int flags,
- const struct sockaddr *to, int tolen)
+inline ssize_t
+fhandler_socket::send_internal (struct _WSABUF *wsabuf, DWORD wsacnt, int flags,
+ const struct sockaddr *to, int tolen)
{
- struct sockaddr_in sin;
-
- if (to && !get_inet_addr (to, tolen, &sin, &tolen))
- return SOCKET_ERROR;
-
- int res = SOCKET_ERROR;
- DWORD ret = 0;
-
- WSABUF wsabuf = { len, (char *) ptr };
+ int res = 0;
+ DWORD ret = 0, err = 0;
- if (is_nonblocking () || closed () || async_io ())
- res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
- flags & MSG_WINMASK,
- (to ? (const struct sockaddr *) &sin : NULL), tolen,
- NULL, NULL);
- else
+ do
{
- HANDLE evt;
- if (prepare (evt, FD_CLOSE | FD_WRITE | (owner () ? FD_OOB : 0)))
- {
- do
- {
- res = WSASendTo (get_socket (), &wsabuf, 1, &ret,
- flags & MSG_WINMASK,
- (to ? (const struct sockaddr *) &sin : NULL),
- tolen, NULL, NULL);
- }
- while (res == SOCKET_ERROR
- && WSAGetLastError () == WSAEWOULDBLOCK
- && !(res = wait (evt, 0))
- && !closed ());
- release (evt);
- }
+ LOCK_EVENTS;
+ if ((res = WSASendTo (get_socket (), wsabuf, wsacnt, &ret,
+ flags & MSG_WINMASK, to, tolen, NULL, NULL))
+ && (err = WSAGetLastError ()) == WSAEWOULDBLOCK)
+ wsock_events->events &= ~FD_WRITE;
+ UNLOCK_EVENTS;
}
+ while (res && err && !(res = wait_for_events (FD_WRITE | FD_CLOSE)));
if (res == SOCKET_ERROR)
set_winsock_errno ();
@@ -1316,6 +1402,20 @@ fhandler_socket::sendto (const void *ptr, size_t len, int flags,
return res;
}
+ssize_t
+fhandler_socket::sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen)
+{
+ struct sockaddr_storage sst;
+
+ if (to && !get_inet_addr (to, tolen, &sst, &tolen))
+ return SOCKET_ERROR;
+
+ WSABUF wsabuf = { len, (char *) ptr };
+ return send_internal (&wsabuf, 1, flags,
+ (to ? (const struct sockaddr *) &sst : NULL), tolen);
+}
+
int
fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot)
{
@@ -1328,69 +1428,17 @@ fhandler_socket::sendmsg (const struct msghdr *msg, int flags, ssize_t tot)
/*TODO*/
}
- struct iovec *const iov = msg->msg_iov;
- const int iovcnt = msg->msg_iovlen;
-
- int res = SOCKET_ERROR;
-
- WSABUF wsabuf[iovcnt];
-
- const struct iovec *iovptr = iov + iovcnt;
- WSABUF *wsaptr = wsabuf + iovcnt;
- do
+ WSABUF wsabuf[msg->msg_iovlen];
+ WSABUF *wsaptr = wsabuf + msg->msg_iovlen;
+ const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen;
+ while (--wsaptr >= wsabuf)
{
- iovptr -= 1;
- wsaptr -= 1;
- wsaptr->len = iovptr->iov_len;
+ wsaptr->len = (--iovptr)->iov_len;
wsaptr->buf = (char *) iovptr->iov_base;
}
- while (wsaptr != wsabuf);
-
- DWORD ret = 0;
-
- if (is_nonblocking () || closed () || async_io ())
- res = WSASendTo (get_socket (), wsabuf, iovcnt, &ret,
- flags & MSG_WINMASK, (struct sockaddr *) msg->msg_name,
- msg->msg_namelen, NULL, NULL);
- else
- {
- HANDLE evt;
- if (prepare (evt, FD_CLOSE | FD_WRITE | (owner () ? FD_OOB : 0)))
- {
- do
- {
- res = WSASendTo (get_socket (), wsabuf, iovcnt,
- &ret, flags & MSG_WINMASK,
- (struct sockaddr *) msg->msg_name,
- msg->msg_namelen, NULL, NULL);
- }
- while (res == SOCKET_ERROR
- && WSAGetLastError () == WSAEWOULDBLOCK
- && !(res = wait (evt, 0))
- && !closed ());
- release (evt);
- }
- }
-
- if (res == SOCKET_ERROR)
- set_winsock_errno ();
- else
- res = ret;
-
- /* Special handling for EPIPE and SIGPIPE.
-
- EPIPE is generated if the local end has been shut down on a connection
- oriented socket. In this case the process will also receive a SIGPIPE
- unless MSG_NOSIGNAL is set. */
- if (res == SOCKET_ERROR && get_errno () == ESHUTDOWN
- && get_socket_type () == SOCK_STREAM)
- {
- set_errno (EPIPE);
- if (! (flags & MSG_NOSIGNAL))
- raise (SIGPIPE);
- }
- return res;
+ return send_internal (wsabuf, msg->msg_iovlen, flags,
+ (struct sockaddr *) msg->msg_name, msg->msg_namelen);
}
int
@@ -1431,6 +1479,7 @@ fhandler_socket::close ()
setsockopt (get_socket (), SOL_SOCKET, SO_LINGER,
(const char *)&linger, sizeof linger);
+ release_events ();
while ((res = closesocket (get_socket ())) != 0)
{
if (WSAGetLastError () != WSAEWOULDBLOCK)
@@ -1559,6 +1608,9 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
syscall_printf ("Async I/O on socket %s",
*(int *) p ? "started" : "cancelled");
async_io (*(int *) p != 0);
+ /* If async_io is switched off, revert the event handling. */
+ if (*(int *) p == 0)
+ WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK);
break;
case FIONREAD:
res = ioctlsocket (get_socket (), FIONREAD, (unsigned long *) p);
@@ -1566,31 +1618,17 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
set_winsock_errno ();
break;
default:
- /* We must cancel WSAAsyncSelect (if any) before setting socket to
- * blocking mode
- */
- if (cmd == FIONBIO && *(int *) p == 0)
- {
- if (async_io ())
- WSAAsyncSelect (get_socket (), winmsg, 0, 0);
- if (WSAEventSelect (get_socket (), NULL, 0) == SOCKET_ERROR)
- debug_printf ("WSAEventSelect(NULL), %d", WSAGetLastError ());
- }
- res = ioctlsocket (get_socket (), cmd, (unsigned long *) p);
- if (res == SOCKET_ERROR)
- set_winsock_errno ();
+ /* Sockets are always non-blocking internally. So we just note the
+ state here. */
if (cmd == FIONBIO)
{
- if (!res)
- {
- syscall_printf ("socket is now %sblocking",
- *(int *) p ? "non" : "");
- set_nonblocking (*(int *) p);
- }
- /* Start AsyncSelect if async socket unblocked */
- if (*(int *) p && async_io ())
- WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO, ASYNC_MASK);
- }
+ syscall_printf ("socket is now %sblocking",
+ *(int *) p ? "non" : "");
+ set_nonblocking (*(int *) p);
+ res = 0;
+ }
+ else
+ res = ioctlsocket (get_socket (), cmd, (unsigned long *) p);
break;
}
syscall_printf ("%d = ioctl_socket (%x, %x)", res, cmd, p);
@@ -1607,12 +1645,16 @@ fhandler_socket::fcntl (int cmd, void *arg)
{
case F_SETOWN:
{
- /* Urgh! Bad hack! */
pid_t pid = (pid_t) arg;
- owner (pid == getpid ());
- debug_printf ("owner set to %d", owner ());
+ LOCK_EVENTS;
+ wsock_events->owner = pid;
+ UNLOCK_EVENTS;
+ debug_printf ("owner set to %d", pid);
}
break;
+ case F_GETOWN:
+ res = wsock_events->owner;
+ break;
case F_SETFL:
{
/* Carefully test for the O_NONBLOCK or deprecated OLD_O_NDELAY flag.
@@ -1638,6 +1680,8 @@ fhandler_socket::fcntl (int cmd, void *arg)
void
fhandler_socket::set_close_on_exec (bool val)
{
+ set_no_inheritance (wsock_mtx, val);
+ set_no_inheritance (wsock_evt, val);
close_on_exec (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
diff --git a/winsup/cygwin/include/cygwin/in.h b/winsup/cygwin/include/cygwin/in.h
index a932ec6bf..619d47a30 100644
--- a/winsup/cygwin/include/cygwin/in.h
+++ b/winsup/cygwin/include/cygwin/in.h
@@ -28,6 +28,7 @@ typedef uint32_t in_addr_t;
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP */
+ IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options */
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
@@ -36,12 +37,21 @@ enum
IPPROTO_PUP = 12, /* PUP protocol */
IPPROTO_UDP = 17, /* User Datagram Protocol */
IPPROTO_IDP = 22, /* XNS IDP protocol */
+ IPPROTO_IPV6 = 41, /* IPv6 header */
+ IPPROTO_ROUTING = 43, /* IPv6 Routing header */
+ IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header */
+ IPPROTO_ESP = 50, /* encapsulating security payload */
+ IPPROTO_AH = 51, /* authentication header */
+ IPPROTO_ICMPV6 = 58, /* ICMPv6 */
+ IPPROTO_NONE = 59, /* IPv6 no next header */
+ IPPROTO_DSTOPTS = 60, /* IPv6 Destination options */
IPPROTO_RAW = 255, /* Raw IP packets */
IPPROTO_MAX
};
/* Define IPPROTO_xxx values to accomodate SUSv3 */
#define IPPROTO_IP IPPROTO_IP
+#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
#define IPPROTO_ICMP IPPROTO_ICMP
#define IPPROTO_IGMP IPPROTO_IGMP
#define IPPROTO_IPIP IPPROTO_IPIP
@@ -51,6 +61,14 @@ enum
#define IPPROTO_UDP IPPROTO_UDP
#define IPPROTO_IDP IPPROTO_IDP
#define IPPROTO_RAW IPPROTO_RAW
+#define IPPROTO_IPV6 IPPROTO_IPV6
+#define IPPROTO_ROUTING IPPROTO_ROUTING
+#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
+#define IPPROTO_ESP IPPROTO_ESP
+#define IPPROTO_AH IPPROTO_AH
+#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
+#define IPPROTO_NONE IPPROTO_NONE
+#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
/* Standard well-known ports. *//* from winsup/include/netinet/in.h */
enum
@@ -185,21 +203,7 @@ struct sockaddr_in
#endif
-#ifdef USE_IPV6
-/* IPv6 definitions as we start to include them. This is just
- a beginning dont get excited 8) */
-struct in6_addr
-{
- uint8_t s6_addr[16];
-};
-
-struct sockaddr_in6
-{
- sa_family_t sin6_family; /* AF_INET6 */
- in_port_t sin6_port; /* Port number. */
- uint32_t sin6_flowinfo; /* Traffic class and flow inf. */
- struct in6_addr sin6_addr; /* IPv6 address. */
- uint32_t sin6_scope_id; /* Set of interfaces for a scope. */
-};
+#ifdef AF_INET6
+#include <cygwin/in6.h>
#endif
#endif /* _CYGWIN_IN_H */
diff --git a/winsup/cygwin/include/cygwin/in6.h b/winsup/cygwin/include/cygwin/in6.h
new file mode 100644
index 000000000..c01aefa06
--- /dev/null
+++ b/winsup/cygwin/include/cygwin/in6.h
@@ -0,0 +1,119 @@
+/* cygwin/in6.h
+
+ Copyright 2006 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. */
+
+/* NOTE: This file is NOT for direct inclusion. Use netinet/in.h. */
+
+#ifndef _CYGWIN_IN6_H
+#define _CYGWIN_IN6_H
+
+#define INET6_ADDRSTRLEN 46
+
+#define IN6_ARE_ADDR_EQUAL(a, b) \
+ (((const uint32_t *)(a))[0] == ((const uint32_t *)(b))[0] \
+ && ((const uint32_t *)(a))[1] == ((const uint32_t *)(b))[1] \
+ && ((const uint32_t *)(a))[2] == ((const uint32_t *)(b))[2] \
+ && ((const uint32_t *)(a))[3] == ((const uint32_t *)(b))[3])
+
+#define IN6_IS_ADDR_UNSPECIFIED(addr) \
+ (((const uint32_t *)(addr))[0] == 0 \
+ && ((const uint32_t *)(addr))[1] == 0 \
+ && ((const uint32_t *)(addr))[2] == 0 \
+ && ((const uint32_t *)(addr))[3] == 0)
+
+#define IN6_IS_ADDR_LOOPBACK(addr) \
+ (((const uint32_t *)(addr))[0] == 0 \
+ && ((const uint32_t *)(addr))[1] == 0 \
+ && ((const uint32_t *)(addr))[2] == 0 \
+ && ((const uint32_t *)(addr))[3] == htonl (1))
+
+#define IN6_IS_ADDR_MULTICAST(addr) (((const uint8_t *) (addr))[0] == 0xff)
+
+#define IN6_IS_ADDR_LINKLOCAL(addr) \
+ ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfe80))
+
+#define IN6_IS_ADDR_SITELOCAL(addr) \
+ ((((const uint16_t *)(addr))[0] & htons (0xffc0)) == htons (0xfec0))
+
+#define IN6_IS_ADDR_V4MAPPED(addr) \
+ (((const uint32_t *)(addr))[0] == 0 \
+ && ((const uint32_t *)(addr))[1] == 0 \
+ && ((const uint32_t *)(addr))[2] == htonl (0xffff))
+
+#define IN6_IS_ADDR_V4COMPAT(addr) \
+ (((const uint32_t *)(addr))[0] == 0 \
+ && ((const uint32_t *)(addr))[1] == 0 \
+ && ((const uint32_t *)(addr))[2] == 0 \
+ && ntohl (((const uint32_t *)(addr))[3]) > 1)
+
+#define IN6_IS_ADDR_MC_NODELOCAL(addr) \
+ (IN6_IS_ADDR_MULTICAST(addr) \
+ && (((const uint8_t *)(addr))[1] & 0xf) == 0x1)
+
+#define IN6_IS_ADDR_MC_LINKLOCAL(addr) \
+ (IN6_IS_ADDR_MULTICAST (addr) \
+ && (((const uint8_t *)(addr))[1] & 0xf) == 0x2)
+
+#define IN6_IS_ADDR_MC_SITELOCAL(addr) \
+ (IN6_IS_ADDR_MULTICAST(addr) \
+ && (((const uint8_t *)(addr))[1] & 0xf) == 0x5)
+
+#define IN6_IS_ADDR_MC_ORGLOCAL(addr) \
+ (IN6_IS_ADDR_MULTICAST(addr) \
+ && (((const uint8_t *)(addr))[1] & 0xf) == 0x8)
+
+#define IN6_IS_ADDR_MC_GLOBAL(addr) \
+ (IN6_IS_ADDR_MULTICAST(addr) \
+ && (((const uint8_t *)(addr))[1] & 0xf) == 0xe)
+
+struct in6_addr
+{
+ union
+ {
+ uint8_t __s6_addr[16];
+ uint16_t __s6_addr16[8];
+ uint32_t __s6_addr32[4];
+ } __u6;
+#define s6_addr __u6.__s6_addr
+#define s6_addr16 __u6.__s6_addr16
+#define s6_addr32 __u6.__s6_addr32
+};
+
+struct ipv6_mreq
+{
+ struct in6_addr ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+};
+
+struct in6_pktinfo
+{
+ struct in6_addr ipi6_addr;
+ unsigned int ipi6_ifindex;
+};
+
+#ifdef __INSIDE_CYGWIN__
+typedef uint16_t in_port_t;
+#endif
+
+struct sockaddr_in6
+{
+ sa_family_t sin6_family; /* AF_INET6 */
+ in_port_t sin6_port; /* Port number. */
+ uint32_t sin6_flowinfo; /* Traffic class and flow inf. */
+ struct in6_addr sin6_addr; /* IPv6 address. */
+ uint32_t sin6_scope_id; /* Set of interfaces for a scope. */
+};
+
+#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
+#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+
+extern const struct in6_addr in6addr_any;
+extern const struct in6_addr in6addr_loopback;
+
+#endif /* _CYGWIN_IN6_H */
diff --git a/winsup/cygwin/include/cygwin/socket.h b/winsup/cygwin/include/cygwin/socket.h
index 11dc6595f..33aec8c63 100644
--- a/winsup/cygwin/include/cygwin/socket.h
+++ b/winsup/cygwin/include/cygwin/socket.h
@@ -152,9 +152,7 @@ struct OLD_msghdr
#define AF_HYLINK 15 /* NSC Hyperchannel */
#define AF_APPLETALK 16 /* AppleTalk */
#define AF_NETBIOS 17 /* NetBios-style addresses */
-#if 0 /* Not yet */
#define AF_INET6 23 /* IP version 6 */
-#endif
#define AF_MAX 32
/*
@@ -180,9 +178,7 @@ struct OLD_msghdr
#define PF_HYLINK AF_HYLINK
#define PF_APPLETALK AF_APPLETALK
#define PF_NETBIOS AF_NETBIOS
-#if 0
#define PF_INET6 AF_INET6
-#endif
#define PF_MAX AF_MAX
@@ -236,6 +232,17 @@ struct OLD_msghdr
#define IP_UNBLOCK_SOURCE 18
#define IP_PKTINFO 19
+/* IPv6 options for use with getsockopt/setsockopt */
+#define IPV6_UNICAST_HOPS 4
+#define IPV6_MULTICAST_IF 9
+#define IPV6_MULTICAST_HOPS 10
+#define IPV6_MULTICAST_LOOP 11
+#define IPV6_ADD_MEMBERSHIP 12
+#define IPV6_DROP_MEMBERSHIP 13
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#define IPV6_PKTINFO 19
+
/* Old WinSock1 values, needed internally */
#ifdef __INSIDE_CYGWIN__
#define _WS1_IP_OPTIONS 1
diff --git a/winsup/cygwin/include/cygwin/stdlib.h b/winsup/cygwin/include/cygwin/stdlib.h
index 880051018..e034fe895 100644
--- a/winsup/cygwin/include/cygwin/stdlib.h
+++ b/winsup/cygwin/include/cygwin/stdlib.h
@@ -31,6 +31,8 @@ int grantpt (int);
int unlockpt (int);
#endif /*__STRICT_ANSI__*/
+int posix_openpt (int);
+
#ifdef _COMPILING_NEWLIB
#define unsetenv UNUSED_unsetenv
#define _unsetenv_r UNUSED__unsetenv_r
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index f00f85347..be660c61a 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -42,8 +42,8 @@ details. */
the Cygwin shared library". This version is used to track important
changes to the DLL and is mainly informative in nature. */
-#define CYGWIN_VERSION_DLL_MAJOR 1005
-#define CYGWIN_VERSION_DLL_MINOR 22
+#define CYGWIN_VERSION_DLL_MAJOR 1007
+#define CYGWIN_VERSION_DLL_MINOR 0
/* Major numbers before CYGWIN_VERSION_DLL_EPOCH are
incompatible. */
@@ -289,12 +289,17 @@ details. */
154: Export sigset, sigignore.
155: Export __isinff, __isinfd, __isnanf, __isnand.
156: Export __srbuf_r, __swget_r.
+ 157: Export gai_strerror, getaddrinfo, getnameinfo, freeaddrinfo,
+ in6addr_any, in6addr_loopback.
+ 158: Export bindresvport, bindresvport_sa, iruserok_sa, rcmd_af,
+ rresvport_af.
+ 159: Export posix_openpt.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 156
+#define CYGWIN_VERSION_API_MINOR 159
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/include/netdb.h b/winsup/cygwin/include/netdb.h
index f49a94379..74c205990 100644
--- a/winsup/cygwin/include/netdb.h
+++ b/winsup/cygwin/include/netdb.h
@@ -63,6 +63,9 @@
extern "C" {
#endif
+#include <stdint.h>
+#include <cygwin/socket.h>
+
/*
* Structures returned by network data base library. All addresses are
* supplied in host order, and returned in network order (suitable for
@@ -88,7 +91,7 @@ struct netent {
char *n_name; /* official name of net */
char **n_aliases; /* alias list */
short n_addrtype; /* net address type */
- unsigned long n_net; /* network # */
+ uint32_t n_net; /* network # */
};
struct servent {
@@ -111,6 +114,17 @@ struct rpcent {
int r_number; /* rpc program number */
};
+struct addrinfo {
+ int ai_flags; /* input flags */
+ int ai_family; /* address family of socket */
+ int ai_socktype; /* socket type */
+ int ai_protocol; /* ai_protocol */
+ socklen_t ai_addrlen; /* length of socket address */
+ char *ai_canonname; /* canonical name of service location */
+ struct sockaddr *ai_addr; /* socket address of socket */
+ struct addrinfo *ai_next; /* pointer to next in list */
+};
+
/*
* Error return codes from gethostbyname() and gethostbyaddr()
* (left in extern int h_errno).
@@ -130,6 +144,45 @@ extern __declspec(dllimport) int h_errno;
#define NO_DATA 4 /* Valid name, no data record of requested type */
#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+#define AI_PASSIVE 1
+#define AI_CANONNAME 2
+#define AI_NUMERICHOST 4
+/*
+ * These are not available in the WinSock implementation. It wouldn't make
+ * sense to support them in the ipv4 only case, so we drop them entirely.
+ * We can define them if we run into problems but they are non-functional, so...
+ */
+#if 0
+#define AI_V4MAPPED 16
+#define AI_ALL 32
+#define AI_ADDRCONFIG 64
+#endif
+
+#define NI_NOFQDN 1
+#define NI_NUMERICHOST 2
+#define NI_NAMEREQD 4
+#define NI_NUMERICSERV 8
+#define NI_DGRAM 16
+
+#define NI_MAXHOST 1025
+#define NI_MAXSERV 32
+
+#define EAI_ADDRFAMILY 1
+#define EAI_AGAIN 2
+#define EAI_BADFLAGS 3
+#define EAI_FAIL 4
+#define EAI_FAMILY 5
+#define EAI_MEMORY 6
+#define EAI_NODATA 7
+#define EAI_NONAME 8
+#define EAI_SERVICE 9
+#define EAI_SOCKTYPE 10
+#define EAI_SYSTEM 11
+#define EAI_BADHINTS 12
+#define EAI_PROTOCOL 13
+
+#define EAI_MAX 14
+
#ifndef __INSIDE_CYGWIN_NET__
void endhostent (void);
void endnetent (void);
@@ -158,6 +211,24 @@ void setnetent (int);
void setprotoent (int);
void setservent (int);
void setrpcent (int);
+void freeaddrinfo (struct addrinfo *);
+const char *gai_strerror (int);
+int getaddrinfo (const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+int getnameinfo (const struct sockaddr *, socklen_t, char *,
+ socklen_t, char *, socklen_t, int);
+
+int rcmd (char **, uint16_t, const char *, const char *,
+ const char *, int *);
+int rcmd_af (char **, uint16_t, const char *, const char *,
+ const char *, int *, int);
+int rexec (char **, uint16_t rport, char *, char *, char *, int *);
+int rresvport (int *);
+int rresvport_af (int *, int);
+int iruserok (unsigned long, int, const char *, const char *);
+int iruserok_sa (const void *, int, int, const char *,
+ const char *);
+int ruserok (const char *, int, const char *, const char *);
#endif
#ifdef __cplusplus
diff --git a/winsup/cygwin/include/netinet/in.h b/winsup/cygwin/include/netinet/in.h
index 7081282a7..027ac2cd1 100644
--- a/winsup/cygwin/include/netinet/in.h
+++ b/winsup/cygwin/include/netinet/in.h
@@ -1,6 +1,6 @@
/* netinet/in.h
- Copyright 1998, 2001 Red Hat, Inc.
+ Copyright 1998, 2001, 2006 Red Hat, Inc.
This file is part of Cygwin.
@@ -13,4 +13,16 @@ details. */
#include <cygwin/in.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern int bindresvport (int, struct sockaddr_in *);
+extern int bindresvport_sa (int, struct sockaddr *);
+
+#ifdef __cplusplus
+};
+#endif
+
#endif /* _NETINET_IN_H */
diff --git a/winsup/cygwin/include/sys/socket.h b/winsup/cygwin/include/sys/socket.h
index bcd8eeb1b..d4b1227ba 100644
--- a/winsup/cygwin/include/sys/socket.h
+++ b/winsup/cygwin/include/sys/socket.h
@@ -32,14 +32,14 @@ extern "C"
int getpeername (int, struct sockaddr *__peer, socklen_t *);
int getsockname (int, struct sockaddr *__addr, socklen_t *);
int listen (int, int __n);
- int recv (int, void *__buff, size_t __len, int __flags);
- int recvfrom (int, void *__buff, size_t __len, int __flags,
- struct sockaddr *__from, socklen_t *__fromlen);
- int recvmsg(int s, struct msghdr *msg, int flags);
- int send (int, const void *__buff, size_t __len, int __flags);
- int sendmsg(int s, const struct msghdr *msg, int flags);
- int sendto (int, const void *, size_t __len, int __flags,
- const struct sockaddr *__to, socklen_t __tolen);
+ ssize_t recv (int, void *__buff, size_t __len, int __flags);
+ ssize_t recvfrom (int, void *__buff, size_t __len, int __flags,
+ struct sockaddr *__from, socklen_t *__fromlen);
+ ssize_t recvmsg(int s, struct msghdr *msg, int flags);
+ ssize_t send (int, const void *__buff, size_t __len, int __flags);
+ ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
+ ssize_t sendto (int, const void *, size_t __len, int __flags,
+ const struct sockaddr *__to, socklen_t __tolen);
int setsockopt (int __s, int __level, int __optname, const void *optval,
socklen_t __optlen);
int getsockopt (int __s, int __level, int __optname, void *__optval,
diff --git a/winsup/cygwin/libc/iruserok.c b/winsup/cygwin/libc/iruserok.c
deleted file mode 100644
index 8326dd0a5..000000000
--- a/winsup/cygwin/libc/iruserok.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/* Based on the rcmd.c.new file distributed with linux libc 5.4.19
- Adapted to inetutils by Bernhard Rosenkraenzer <bero@startrek.in-trier.de>
-
- Note that a lot in this file is superfluous; hopefully it won't be a
- problem for systems that need it for iruserok &c.... */
-/*
- * Copyright (c) 1983, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "winsup.h"
-#include <pwd.h>
-#include <sys/stat.h>
-#include <malloc.h>
-#include <string.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
-
-#ifndef PATH_HEQUIV
-# define PATH_HEQUIV "/etc/hosts.equiv"
-#endif
-
-int __check_rhosts_file = 1;
-const char *__rcmd_errstr;
-
-/*
- * Returns "true" if match, 0 if no match.
- */
-static int
-__icheckhost(raddr, lhost)
- u_long raddr;
- register char *lhost;
-{
- register struct hostent *hp;
- register u_long laddr;
- register char **pp;
-
- /* Try for raw ip address first. */
- if (isdigit(*lhost) && (long)(laddr = cygwin_inet_addr(lhost)) != -1)
- return (raddr == laddr);
-
- /* Better be a hostname. */
- if ((hp = cygwin_gethostbyname(lhost)) == NULL)
- return (0);
-
- /* Spin through ip addresses. */
- for (pp = hp->h_addr_list; *pp; ++pp)
- if (!bcmp(&raddr, *pp, sizeof(u_long)))
- return (1);
-
- /* No match. */
- return (0);
-}
-
-/*
- * XXX
- * Don't make static, used by lpd(8).
- *
- * Returns 0 if ok, -1 if not ok.
- */
-static int
-__ivaliduser(hostf, raddr, luser, ruser)
- struct __sFILE64 *hostf;
- u_long raddr;
- const char *luser;
- const char *ruser;
-{
- size_t buf_offs = 0;
- size_t buf_len = 256;
- char *buf = malloc (buf_len);
-
- if (! buf)
- return -1;
-
- while (fgets(buf + buf_offs, buf_len - buf_offs, hostf)) {
- /*int ch;*/
- register char *user, *p;
-
- if (strchr(buf + buf_offs, '\n') == NULL) {
- /* No newline yet, read some more. */
- buf_offs += strlen (buf + buf_offs);
-
- if (buf_offs >= buf_len - 1) {
- /* Make more room in BUF. */
- char *new_buf;
-
- buf_len += buf_len;
- new_buf = realloc (buf, buf_len);
-
- if (! new_buf) {
- free (buf);
- return -1;
- }
-
- buf = new_buf;
- }
-
- continue;
- }
-
- buf_offs = 0; /* Start at beginning next time around. */
-
- p = buf;
- while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
- /* *p = isupper(*p) ? tolower(*p) : *p; -- Uli */
- *p = tolower(*p); /* works for linux libc */
- p++;
- }
- if (*p == ' ' || *p == '\t') {
- *p++ = '\0';
- while (*p == ' ' || *p == '\t')
- p++;
- user = p;
- while (*p != '\n' && *p != ' ' &&
- *p != '\t' && *p != '\0')
- p++;
- } else
- user = p;
- *p = '\0';
-
- if (__icheckhost(raddr, buf) && !strcmp(ruser, *user ? user : luser)) {
- free (buf);
- return (0);
- }
- }
-
- free (buf);
-
- return (-1);
-}
-
-/*
- * New .rhosts strategy: We are passed an ip address. We spin through
- * hosts.equiv and .rhosts looking for a match. When the .rhosts only
- * has ip addresses, we don't have to trust a nameserver. When it
- * contains hostnames, we spin through the list of addresses the nameserver
- * gives us and look for a match.
- *
- * Returns 0 if ok, -1 if not ok.
- */
-int
-iruserok(raddr, superuser, ruser, luser)
- u_long raddr;
- int superuser;
- const char *ruser;
- const char *luser;
-{
- register const char *cp;
- struct __stat64 sbuf;
- struct passwd *pwd;
- struct __sFILE64 *hostf;
-
- uid_t uid;
- int first = 1;
- char *pbuf;
-
- first = 1;
- hostf = superuser ? NULL : fopen64(PATH_HEQUIV, "rt");
-again:
- if (hostf) {
- if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
- (void) fclose(hostf);
- return(0);
- }
- (void) fclose(hostf);
- }
- if (first == 1 && (__check_rhosts_file || superuser)) {
- first = 0;
- if ((pwd = getpwnam(luser)) == NULL)
- return(-1);
-
- pbuf = malloc (strlen (pwd->pw_dir) + sizeof "/.rhosts");
- if (! pbuf)
- {
- errno = ENOMEM;
- return -1;
- }
- strcpy (pbuf, pwd->pw_dir);
- strcat (pbuf, "/.rhosts");
-
- /*
- * Change effective uid while opening .rhosts. If root and
- * reading an NFS mounted file system, can't read files that
- * are protected read/write owner only.
- */
- uid = geteuid32();
- (void)seteuid32(pwd->pw_uid);
- hostf = fopen64(pbuf, "rt");
- (void)seteuid32(uid);
-
- if (hostf == NULL)
- return(-1);
- /*
- * If not a regular file, or is owned by someone other than
- * user or root or if writeable by anyone but the owner, quit.
- */
- cp = NULL;
- if (lstat64(pbuf, &sbuf) < 0)
- cp = ".rhosts not regular file";
- else if (!S_ISREG(sbuf.st_mode))
- cp = ".rhosts not regular file";
- else if (fstat64(fileno(hostf), &sbuf) < 0)
- cp = ".rhosts fstat failed";
- else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
- cp = "bad .rhosts owner";
- else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
- cp = ".rhosts writeable by other than owner";
- /* If there were any problems, quit. */
- if (cp) {
- __rcmd_errstr = (char *) cp;
- fclose(hostf);
- return(-1);
- }
- goto again;
- }
- return (-1);
-}
-
-int
-ruserok(rhost, superuser, ruser, luser)
- const char *rhost;
- int superuser;
- const char *ruser;
- const char *luser;
-{
- struct hostent *hp;
- u_long addr;
- char **ap;
-
- if ((hp = cygwin_gethostbyname(rhost)) == NULL)
- return (-1);
- for (ap = hp->h_addr_list; *ap; ++ap) {
- bcopy(*ap, &addr, sizeof(addr));
- if (iruserok(addr, superuser, ruser, luser) == 0)
- return (0);
- }
- return (-1);
-}
diff --git a/winsup/cygwin/libc/rcmd.cc b/winsup/cygwin/libc/rcmd.cc
new file mode 100644
index 000000000..0e484c515
--- /dev/null
+++ b/winsup/cygwin/libc/rcmd.cc
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+#ifndef __CYGWIN__
+__FBSDID("$FreeBSD$");
+#else
+#define __INSIDE_CYGWIN_NET__
+#include "winsup.h"
+#endif
+
+#ifndef __CYGWIN__
+#include "namespace.h"
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#ifndef __CYGWIN__
+#include <rpc/rpc.h>
+#endif
+#ifdef YP
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#ifndef __CYGWIN__
+#include <arpa/nameser.h>
+#include "un-namespace.h"
+#endif
+
+#ifndef __CYGWIN__
+extern int innetgr( const char *, const char *, const char *, const char * );
+
+#define max(a, b) ((a > b) ? a : b)
+#else
+#include "wininet.h"
+#include "cygwin/in6.h"
+
+#ifndef _PATH_HEQUIV
+# define _PATH_HEQUIV "/etc/hosts.equiv"
+#endif
+
+#define innetgr(a,b,c,d) (0)
+
+extern int rcmdsh(char **, int, const char *, const char *, const char *,
+ const char *);
+
+extern "C" {
+ int cygwin_accept (int, struct sockaddr *, socklen_t *);
+ int cygwin_bindresvport_sa (int, struct sockaddr *);
+ int cygwin_connect (int, const struct sockaddr *, socklen_t);
+ void cygwin_freeaddrinfo (struct addrinfo *);
+ const char * cygwin_gai_strerror (int);
+ int cygwin_getaddrinfo (const char *, const char *, const struct addrinfo *,
+ struct addrinfo **);
+ int cygwin_getnameinfo (const struct sockaddr *, socklen_t, char *, size_t,
+ char *, size_t, int);
+ struct servent *cygwin_getservbyname (const char *, const char *);
+ int cygwin_listen (int, int);
+ int cygwin_rresvport_af(int *alport, int family);
+ int cygwin_select (int, fd_set *, fd_set *, fd_set *, struct timeval *);
+ int cygwin_socket (int, int, int);
+ int seteuid32 (__uid32_t);
+}
+#endif
+
+#ifndef __CYGWIN__
+static int __ivaliduser(FILE *, u_int32_t, const char *, const char *);
+static int __ivaliduser_af(FILE *,const void *, const char *, const char *,
+ int, int);
+#endif
+static int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t,
+ const char *, const char *);
+static int __icheckhost(const struct sockaddr *, socklen_t, const char *);
+
+char paddr[NI_MAXHOST];
+
+extern "C" int
+cygwin_rcmd_af(char **ahost, in_port_t rport, const char *locuser,
+ const char *remuser, const char *cmd, int *fd2p, int af)
+{
+ struct addrinfo hints, *res, *ai;
+ struct sockaddr_storage from;
+ fd_set reads;
+ sigset_t oldmask, newmask;
+ pid_t pid;
+ int s, aport, lport, timo, error;
+ char c;//, *p;
+ int refused, nres;
+ char num[8];
+ static char canonnamebuf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; /* is it proper here? */
+#ifndef __CYGWIN__
+ /* call rcmdsh() with specified remote shell if appropriate. */
+ if (!issetugid() && (p = getenv("RSH"))) {
+ struct servent *sp = cygwin_getservbyname("shell", "tcp");
+
+ if (sp && sp->s_port == rport)
+ return (rcmdsh(ahost, rport, locuser, remuser,
+ cmd, p));
+ }
+
+ /* use rsh(1) if non-root and remote port is shell. */
+ if (geteuid()) {
+ struct servent *sp = cygwin_getservbyname("shell", "tcp");
+
+ if (sp && sp->s_port == rport)
+ return (rcmdsh(ahost, rport, locuser, remuser,
+ cmd, NULL));
+ }
+#endif
+ pid = getpid();
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ (void)snprintf(num, sizeof(num), "%d", ntohs(rport));
+ error = cygwin_getaddrinfo(*ahost, num, &hints, &res);
+ if (error) {
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ cygwin_gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "rcmd: getaddrinfo: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+
+ if (res->ai_canonname
+ && strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) {
+ strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf));
+ *ahost = canonnamebuf;
+ }
+ nres = 0;
+ for (ai = res; ai; ai = ai->ai_next)
+ nres++;
+ ai = res;
+ refused = 0;
+ sigemptyset(&newmask);
+ sigaddset(&newmask, SIGURG);
+ sigprocmask(SIG_BLOCK, (const sigset_t *)&newmask, &oldmask);
+ for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
+ s = cygwin_rresvport_af(&lport, ai->ai_family);
+ if (s < 0) {
+ if (errno != EAGAIN && ai->ai_next) {
+ ai = ai->ai_next;
+ continue;
+ }
+ if (errno == EAGAIN)
+ (void)fprintf(stderr,
+ "rcmd: socket: All ports in use\n");
+ else
+ (void)fprintf(stderr, "rcmd: socket: %s\n",
+ strerror(errno));
+ cygwin_freeaddrinfo(res);
+ sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
+ NULL);
+ return (-1);
+ }
+ fcntl(s, F_SETOWN, pid);
+ if (cygwin_connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
+ break;
+ (void)close(s);
+ if (errno == EADDRINUSE) {
+ lport--;
+ continue;
+ }
+ if (errno == ECONNREFUSED)
+ refused = 1;
+ if (ai->ai_next == NULL && (!refused || timo > 16)) {
+ (void)fprintf(stderr, "%s: %s\n",
+ *ahost, strerror(errno));
+ cygwin_freeaddrinfo(res);
+ sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
+ NULL);
+ return (-1);
+ }
+ if (nres > 1) {
+ int oerrno = errno;
+
+ cygwin_getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
+ sizeof(paddr), NULL, 0, NI_NUMERICHOST);
+ (void)fprintf(stderr, "connect to address %s: ",
+ paddr);
+ errno = oerrno;
+ perror(0);
+ }
+ if ((ai = ai->ai_next) == NULL) {
+ /* refused && timo <= 16 */
+ struct timespec time_to_sleep, time_remaining;
+
+ time_to_sleep.tv_sec = timo;
+ time_to_sleep.tv_nsec = 0;
+ (void)nanosleep(&time_to_sleep, &time_remaining);
+ timo *= 2;
+ ai = res;
+ refused = 0;
+ }
+ if (nres > 1) {
+ cygwin_getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
+ sizeof(paddr), NULL, 0, NI_NUMERICHOST);
+ fprintf(stderr, "Trying %s...\n", paddr);
+ }
+ }
+ lport--;
+ if (fd2p == 0) {
+ write(s, "", 1);
+ lport = 0;
+ } else {
+ int s2 = cygwin_rresvport_af(&lport, ai->ai_family), s3;
+ socklen_t len = ai->ai_addrlen;
+ int nfds;
+
+ if (s2 < 0)
+ goto bad;
+ cygwin_listen(s2, 1);
+ (void)snprintf(num, sizeof(num), "%d", lport);
+ if (write(s, num, strlen(num)+1) != (int)strlen(num)+1) {
+ (void)fprintf(stderr,
+ "rcmd: write (setting up stderr): %s\n",
+ strerror(errno));
+ (void)close(s2);
+ goto bad;
+ }
+ nfds = max(s, s2)+1;
+ if(nfds > FD_SETSIZE) {
+ fprintf(stderr, "rcmd: too many files\n");
+ (void)close(s2);
+ goto bad;
+ }
+again:
+ FD_ZERO(&reads);
+ FD_SET(s, &reads);
+ FD_SET(s2, &reads);
+ errno = 0;
+ if (cygwin_select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
+ if (errno != 0)
+ (void)fprintf(stderr,
+ "rcmd: select (setting up stderr): %s\n",
+ strerror(errno));
+ else
+ (void)fprintf(stderr,
+ "select: protocol failure in circuit setup\n");
+ (void)close(s2);
+ goto bad;
+ }
+ s3 = cygwin_accept(s2, (struct sockaddr *)&from, &len);
+ switch (from.ss_family) {
+ case AF_INET:
+ aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
+ break;
+#endif
+ default:
+ aport = 0; /* error */
+ break;
+ }
+ /*
+ * XXX careful for ftp bounce attacks. If discovered, shut them
+ * down and check for the real auxiliary channel to connect.
+ */
+ if (aport == 20) {
+ close(s3);
+ goto again;
+ }
+ (void)close(s2);
+ if (s3 < 0) {
+ (void)fprintf(stderr,
+ "rcmd: accept: %s\n", strerror(errno));
+ lport = 0;
+ goto bad;
+ }
+ *fd2p = s3;
+ if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
+ (void)fprintf(stderr,
+ "socket: protocol failure in circuit setup.\n");
+ goto bad2;
+ }
+ }
+ (void)write(s, locuser, strlen(locuser)+1);
+ (void)write(s, remuser, strlen(remuser)+1);
+ (void)write(s, cmd, strlen(cmd)+1);
+ if (read(s, &c, 1) != 1) {
+ (void)fprintf(stderr,
+ "rcmd: %s: %s\n", *ahost, strerror(errno));
+ goto bad2;
+ }
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void)write(STDERR_FILENO, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad2;
+ }
+ sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ cygwin_freeaddrinfo(res);
+ return (s);
+bad2:
+ if (lport)
+ (void)close(*fd2p);
+bad:
+ (void)close(s);
+ sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
+ cygwin_freeaddrinfo(res);
+ return (-1);
+}
+
+extern "C" int
+cygwin_rcmd(char **ahost, in_port_t rport, const char *locuser,
+ const char *remuser, const char *cmd, int *fd2p)
+{
+ return cygwin_rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p,
+ AF_INET);
+}
+
+extern "C" int
+cygwin_rresvport_af(int *alport, int family)
+{
+ int s;
+ struct sockaddr_storage ss;
+ u_short *sport;
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = family;
+ switch (family) {
+ case AF_INET:
+ sport = &((struct sockaddr_in *)&ss)->sin_port;
+ ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ s = cygwin_socket(ss.ss_family, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+#if 0 /* compat_exact_traditional_rresvport_semantics */
+ sin.sin_port = htons((u_short)*alport);
+ if (_bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
+ return (s);
+ if (errno != EADDRINUSE) {
+ (void)_close(s);
+ return (-1);
+ }
+#endif
+ *sport = 0;
+ if (cygwin_bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
+ (void)close(s);
+ return (-1);
+ }
+ *alport = (int)ntohs(*sport);
+ return (s);
+}
+
+extern "C" int
+cygwin_rresvport(int *port)
+{
+ return cygwin_rresvport_af(port, AF_INET);
+}
+
+int __check_rhosts_file = 1;
+char *__rcmd_errstr;
+
+/*
+ * AF independent extension of iruserok.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+extern "C" int
+iruserok_sa(const void *ra, int rlen, int superuser, const char *ruser,
+ const char *luser)
+{
+ const char *cp;
+ struct __stat64 sbuf;
+ struct passwd *pwd;
+ FILE *hostf;
+ uid_t uid;
+ int first;
+ char pbuf[MAXPATHLEN];
+ const struct sockaddr *raddr;
+ struct sockaddr_storage ss;
+
+ /* avoid alignment issue */
+ if (rlen > (int) sizeof(ss))
+ return(-1);
+ memcpy(&ss, ra, rlen);
+ raddr = (struct sockaddr *)&ss;
+
+ first = 1;
+ hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "rt");
+again:
+ if (hostf) {
+ if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) {
+ (void)fclose(hostf);
+ return (0);
+ }
+ (void)fclose(hostf);
+ }
+ if (first == 1 && (__check_rhosts_file || superuser)) {
+ first = 0;
+ if ((pwd = getpwnam(luser)) == NULL)
+ return (-1);
+ (void)strcpy(pbuf, pwd->pw_dir);
+ (void)strcat(pbuf, "/.rhosts");
+
+ /*
+ * Change effective uid while opening .rhosts. If root and
+ * reading an NFS mounted file system, can't read files that
+ * are protected read/write owner only.
+ */
+ uid = geteuid32();
+ (void)seteuid32(pwd->pw_uid);
+ hostf = fopen(pbuf, "rt");
+ (void)seteuid32(uid);
+
+ if (hostf == NULL)
+ return (-1);
+ /*
+ * If not a regular file, or is owned by someone other than
+ * user or root or if writeable by anyone but the owner, quit.
+ */
+ cp = NULL;
+ if (lstat64(pbuf, &sbuf) < 0)
+ cp = ".rhosts lstat failed";
+ else if (!S_ISREG(sbuf.st_mode))
+ cp = ".rhosts not regular file";
+ else if (fstat64(fileno(hostf), &sbuf) < 0)
+ cp = ".rhosts fstat failed";
+ else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
+ cp = "bad .rhosts owner";
+ else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
+ cp = ".rhosts writeable by other than owner";
+ /* If there were any problems, quit. */
+ if (cp) {
+ __rcmd_errstr = (char *) cp;
+ (void)fclose(hostf);
+ return (-1);
+ }
+ goto again;
+ }
+ return (-1);
+}
+
+/*
+ * New .rhosts strategy: We are passed an ip address. We spin through
+ * hosts.equiv and .rhosts looking for a match. When the .rhosts only
+ * has ip addresses, we don't have to trust a nameserver. When it
+ * contains hostnames, we spin through the list of addresses the nameserver
+ * gives us and look for a match.
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+extern "C" int
+iruserok(unsigned long raddr, int superuser, const char *ruser,
+ const char *luser)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return iruserok_sa((struct sockaddr *)&sin, sizeof(struct sockaddr_in),
+ superuser, ruser, luser);
+}
+
+extern "C" int
+ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
+{
+ struct addrinfo hints, *res, *r;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ error = cygwin_getaddrinfo(rhost, "0", &hints, &res);
+ if (error)
+ return (-1);
+
+ for (r = res; r; r = r->ai_next) {
+ if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
+ luser) == 0) {
+ cygwin_freeaddrinfo(res);
+ return (0);
+ }
+ }
+ cygwin_freeaddrinfo(res);
+ return (-1);
+}
+
+#ifndef __CYGWIN__
+/*
+ * XXX
+ * Don't make static, used by lpd(8).
+ *
+ * Returns 0 if ok, -1 if not ok.
+ */
+static int
+__ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
+ return __ivaliduser_sa(hostf, (struct sockaddr *)&sin,
+ sizeof(struct sockaddr_in), luser, ruser);
+}
+
+/*
+ * Returns 0 if ok, -1 if not ok.
+ *
+ * XXX obsolete API.
+ */
+static int
+__ivaliduser_af(FILE *hostf, const void *raddr, const char *luser,
+ const char *ruser, int af, int len)
+{
+ struct sockaddr *sa = NULL;
+ struct sockaddr_in *sin = NULL;
+#ifdef INET6
+ struct sockaddr_in6 *sin6 = NULL;
+#endif
+ struct sockaddr_storage ss;
+ int salen = 0;
+
+ memset(&ss, 0, sizeof(ss));
+ switch (af) {
+ case AF_INET:
+ if (len != sizeof(sin->sin_addr))
+ return -1;
+ sin = (struct sockaddr_in *)&ss;
+ sin->sin_family = AF_INET;
+ salen = sizeof(struct sockaddr_in);
+ memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (len != sizeof(sin6->sin6_addr))
+ return -1;
+ /* you will lose scope info */
+ sin6 = (struct sockaddr_in6 *)&ss;
+ sin6->sin6_family = AF_INET6;
+ salen = sizeof(struct sockaddr_in6);
+ memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr));
+ break;
+#endif
+ default:
+ return -1;
+ }
+
+ sa = (struct sockaddr *)&ss;
+ return __ivaliduser_sa(hostf, sa, salen, luser, ruser);
+}
+#endif
+
+static int
+__ivaliduser_sa(FILE *hostf, const struct sockaddr *raddr, socklen_t salen,
+ const char *luser, const char *ruser)
+{
+ char *user, *p;
+ int ch;
+ char buf[MAXHOSTNAMELEN + 128]; /* host + login */
+ char hname[MAXHOSTNAMELEN];
+ /* Presumed guilty until proven innocent. */
+ int userok = 0, hostok = 0;
+#ifdef YP
+ char *ypdomain;
+
+ if (yp_get_default_domain(&ypdomain))
+ ypdomain = NULL;
+#else
+#define ypdomain NULL
+#endif
+ /* We need to get the damn hostname back for netgroup matching. */
+ if (cygwin_getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0,
+ NI_NAMEREQD) != 0)
+ hname[0] = '\0';
+
+ while (fgets(buf, sizeof(buf), hostf)) {
+ p = buf;
+ /* Skip lines that are too long. */
+ if (strchr(p, '\n') == NULL) {
+ while ((ch = getc(hostf)) != '\n' && ch != EOF);
+ continue;
+ }
+ if (*p == '\n' || *p == '#') {
+ /* comment... */
+ continue;
+ }
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p;
+ p++;
+ }
+ if (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ user = p;
+ while (*p != '\n' && *p != ' ' &&
+ *p != '\t' && *p != '\0')
+ p++;
+ } else
+ user = p;
+ *p = '\0';
+ /*
+ * Do +/- and +@/-@ checking. This looks really nasty,
+ * but it matches SunOS's behavior so far as I can tell.
+ */
+ switch(buf[0]) {
+ case '+':
+ if (!buf[1]) { /* '+' matches all hosts */
+ hostok = 1;
+ break;
+ }
+ if (buf[1] == '@') /* match a host by netgroup */
+ hostok = hname[0] != '\0' &&
+ innetgr(&buf[2], hname, NULL, ypdomain);
+ else /* match a host by addr */
+ hostok = __icheckhost(raddr, salen,
+ (char *)&buf[1]);
+ break;
+ case '-': /* reject '-' hosts and all their users */
+ if (buf[1] == '@') {
+ if (hname[0] == '\0' ||
+ innetgr(&buf[2], hname, NULL, ypdomain))
+ return(-1);
+ } else {
+ if (__icheckhost(raddr, salen,
+ (char *)&buf[1]))
+ return(-1);
+ }
+ break;
+ default: /* if no '+' or '-', do a simple match */
+ hostok = __icheckhost(raddr, salen, buf);
+ break;
+ }
+ switch(*user) {
+ case '+':
+ if (!*(user+1)) { /* '+' matches all users */
+ userok = 1;
+ break;
+ }
+ if (*(user+1) == '@') /* match a user by netgroup */
+ userok = innetgr(user+2, NULL, ruser, ypdomain);
+ else /* match a user by direct specification */
+ userok = !(strcmp(ruser, user+1));
+ break;
+ case '-': /* if we matched a hostname, */
+ if (hostok) { /* check for user field rejections */
+ if (!*(user+1))
+ return(-1);
+ if (*(user+1) == '@') {
+ if (innetgr(user+2, NULL,
+ ruser, ypdomain))
+ return(-1);
+ } else {
+ if (!strcmp(ruser, user+1))
+ return(-1);
+ }
+ }
+ break;
+ default: /* no rejections: try to match the user */
+ if (hostok)
+ userok = !(strcmp(ruser,*user ? user : luser));
+ break;
+ }
+ if (hostok && userok)
+ return(0);
+ }
+ return (-1);
+}
+
+/*
+ * Returns "true" if match, 0 if no match.
+ */
+static int
+__icheckhost(const struct sockaddr *raddr, socklen_t salen, const char *lhost)
+{
+ struct sockaddr_in sin;
+ struct sockaddr_in6 *sin6;
+ struct addrinfo hints, *res, *r;
+ int error;
+ char h1[NI_MAXHOST], h2[NI_MAXHOST];
+
+ if (raddr->sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)raddr;
+ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
+ sizeof(sin.sin_addr));
+ raddr = (struct sockaddr *)&sin;
+ salen = sizeof(struct sockaddr_in);
+ }
+ }
+
+ h1[0] = '\0';
+ if (cygwin_getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ return (0);
+
+ /* Resolve laddr into sockaddr */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = raddr->sa_family;
+ hints.ai_socktype = SOCK_DGRAM; /*XXX dummy*/
+ res = NULL;
+ error = cygwin_getaddrinfo(lhost, "0", &hints, &res);
+ if (error)
+ return (0);
+
+ for (r = res; r ; r = r->ai_next) {
+ h2[0] = '\0';
+ if (cygwin_getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
+ NULL, 0, NI_NUMERICHOST) != 0)
+ continue;
+ if (strcmp(h1, h2) == 0) {
+ cygwin_freeaddrinfo(res);
+ return (1);
+ }
+ }
+
+ /* No match. */
+ cygwin_freeaddrinfo(res);
+ return (0);
+}
diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc
index 97966515e..1c1afba57 100644
--- a/winsup/cygwin/mmap.cc
+++ b/winsup/cygwin/mmap.cc
@@ -900,44 +900,64 @@ map::del_list (unsigned i)
}
/* This function is called from exception_handler when a segmentation
- violation has happened. We have two cases to check here.
+ violation has occurred. It should also be called from all Cygwin
+ functions that want to support passing noreserve mmap page addresses
+ to Windows system calls. In that case, it should be called only after
+ a system call indicates that the application buffer passed had an
+ invalid virtual address to avoid any performance impact in non-noreserve
+ cases.
- First, is it an address within "attached" mmap pages (indicated by
- the __PROT_ATTACH protection, see there)? In this case the function
- returns 1 and the exception_handler raises SIGBUS, as demanded by the
- memory protection extension described in SUSv3 (see the mmap man
- page).
-
- Second, check if the address is within "noreserve" mmap pages
- (indicated by MAP_NORESERVE flag). If so, the function calls
- VirtualAlloc to commit the page and returns 2. The exception handler
- then just returns with 0 and the affected application retries the
- failing memory access. If VirtualAlloc fails, the function returns
- 1, so that the exception handler raises a SIGBUS, as described in the
- MAP_NORESERVE man pages for Linux and Solaris.
-
- In any other case 0 is returned and a normal SIGSEGV is raised. */
-int
-mmap_is_attached_or_noreserve_page (ULONG_PTR addr)
+ Check if the address range is all within noreserve mmap regions. If so,
+ call VirtualAlloc to commit the pages and return MMAP_NORESERVE_COMMITED
+ on success. If the page has __PROT_ATTACH (SUSv3 memory protection
+ extension), or if VirutalAlloc fails, return MMAP_RAISE_SIGBUS.
+ Otherwise, return MMAP_NONE if the address range is not covered by an
+ attached or noreserve map.
+
+ On MAP_NORESERVE_COMMITED, the exeception handler should return 0 to
+ allow the application to retry the memory access, or the calling Cygwin
+ function should retry the Windows system call. */
+mmap_region_status
+mmap_is_attached_or_noreserve (void *addr, size_t len)
{
- list *map_list;
- long record_idx;
- caddr_t u_addr;
- DWORD u_len;
- DWORD pagesize = getsystempagesize ();
+ list *map_list = mmapped_areas.get_list_by_fd (-1);
- addr = rounddown (addr, pagesize);
- if (!(map_list = mmapped_areas.get_list_by_fd (-1)))
- return 0;
- if ((record_idx = map_list->search_record ((caddr_t)addr, pagesize,
- u_addr, u_len, -1)) < 0)
- return 0;
- if (map_list->get_record (record_idx)->attached ())
- return 1;
- if (!map_list->get_record (record_idx)->noreserve ())
- return 0;
- DWORD new_prot = map_list->get_record (record_idx)->gen_protect ();
- return VirtualAlloc ((void *)addr, pagesize, MEM_COMMIT, new_prot) ? 2 : 1;
+ size_t pagesize = getpagesize ();
+ caddr_t start_addr = (caddr_t) rounddown ((uintptr_t) addr, pagesize);
+ len += ((caddr_t) addr - start_addr);
+ len = roundup2 (len, pagesize);
+
+ if (map_list == NULL)
+ return MMAP_NONE;
+
+ while (len > 0)
+ {
+ caddr_t u_addr;
+ DWORD u_len;
+ long record_idx = map_list->search_record (start_addr, len,
+ u_addr, u_len, -1);
+ if (record_idx < 0)
+ return MMAP_NONE;
+
+ mmap_record *rec = map_list->get_record (record_idx);
+ if (rec->attached ())
+ return MMAP_RAISE_SIGBUS;
+ if (!rec->noreserve ())
+ return MMAP_NONE;
+
+ size_t commit_len = u_len - (start_addr - u_addr);
+ if (commit_len > len)
+ commit_len = len;
+
+ if (!VirtualAlloc (start_addr, commit_len, MEM_COMMIT,
+ rec->gen_protect ()))
+ return MMAP_RAISE_SIGBUS;
+
+ start_addr += commit_len;
+ len -= commit_len;
+ }
+
+ return MMAP_NORESERVE_COMMITED;
}
static caddr_t
diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc
index 7db6c1abb..80f34a886 100644
--- a/winsup/cygwin/net.cc
+++ b/winsup/cygwin/net.cc
@@ -40,6 +40,7 @@ details. */
#include "pinfo.h"
#include "registry.h"
#include "cygtls.h"
+#include "cygwin/in6.h"
extern "C"
{
@@ -52,6 +53,9 @@ extern "C"
const char *cygwin_inet_ntop (int, const void *, char *, socklen_t);
} /* End of "C" section */
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
static fhandler_socket *
get (const int fd)
{
@@ -509,6 +513,8 @@ fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc)
if (!fd.isopen ())
return false;
fd->set_io_handle ((HANDLE) soc);
+ if (!((fhandler_socket *) fd)->init_events ())
+ return false;
fd->set_flags (O_RDWR | O_BINARY);
fd->uninterruptible_io (true);
cygheap->fdtab.inc_need_fixup_before ();
@@ -545,7 +551,8 @@ cygwin_socket (int af, int type, int protocol)
debug_printf ("socket (%d, %d, %d)", af, type, protocol);
- soc = socket (AF_INET, type, af == AF_LOCAL ? 0 : protocol);
+ soc = socket (af == AF_LOCAL ? AF_INET : af, type,
+ af == AF_LOCAL ? 0 : protocol);
if (soc == INVALID_SOCKET)
{
@@ -555,10 +562,10 @@ cygwin_socket (int af, int type, int protocol)
const device *dev;
- if (af == AF_INET)
- dev = type == SOCK_STREAM ? tcp_dev : udp_dev;
- else
+ if (af == AF_LOCAL)
dev = type == SOCK_STREAM ? stream_dev : dgram_dev;
+ else
+ dev = type == SOCK_STREAM ? tcp_dev : udp_dev;
{
cygheap_fdnew fd;
@@ -771,56 +778,7 @@ cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen)
if (efault.faulted (EFAULT) || !fh)
res = -1;
else
- {
- bool was_blocking = false;
- if (!fh->is_nonblocking ())
- {
- int nonblocking = 1;
- fh->ioctl (FIONBIO, &nonblocking);
- was_blocking = true;
- }
- res = fh->connect (name, namelen);
- if (was_blocking)
- {
- if (res == -1 && get_errno () == EINPROGRESS)
- {
- size_t fds_size = howmany (fd + 1, NFDBITS) * sizeof (fd_mask);
- fd_set *write_fds = (fd_set *) alloca (fds_size);
- fd_set *except_fds = (fd_set *) alloca (fds_size);
- memset (write_fds, 0, fds_size);
- memset (except_fds, 0, fds_size);
- FD_SET (fd, write_fds);
- FD_SET (fd, except_fds);
- res = cygwin_select (fd + 1, NULL, write_fds, except_fds, NULL);
- if (res > 0 && FD_ISSET (fd, except_fds))
- {
- res = -1;
- for (;;)
- {
- int err;
- int len = sizeof err;
- cygwin_getsockopt (fd, SOL_SOCKET, SO_ERROR,
- (void *) &err, &len);
- if (err)
- {
- set_errno (err);
- break;
- }
- low_priority_sleep (0);
- }
- }
- else if (res > 0)
- res = 0;
- else
- {
- WSASetLastError (WSAEINPROGRESS);
- set_winsock_errno ();
- }
- }
- int nonblocking = 0;
- fh->ioctl (FIONBIO, &nonblocking);
- }
- }
+ res = fh->connect (name, namelen);
syscall_printf ("%d = connect (%d, %p, %d)", res, fd, name, namelen);
@@ -954,19 +912,7 @@ cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len)
if (efault.faulted (EFAULT) || !fh)
res = -1;
else
- {
- if (!fh->is_nonblocking ())
- {
- size_t fds_size = howmany (fd + 1, NFDBITS) * sizeof (fd_mask);
- fd_set *read_fds = (fd_set *) alloca (fds_size);
- memset (read_fds, 0, fds_size);
- FD_SET (fd, read_fds);
- res = cygwin_select (fd + 1, read_fds, NULL, NULL, NULL);
- if (res == -1)
- return -1;
- }
- res = fh->accept (peer, len);
- }
+ res = fh->accept (peer, len);
syscall_printf ("%d = accept (%d, %p, %p)", res, fd, peer, len);
return res;
@@ -1816,146 +1762,92 @@ get_ifconf (struct ifconf *ifc, int what)
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;
-
- sig_dispatch_pending ();
-
- myfault efault;
- if (efault.faulted (EFAULT))
- return (int) INVALID_SOCKET;
- if (!*locuser)
- {
- set_errno (EINVAL);
- return (int) INVALID_SOCKET;
- }
-
- res = rcmd (ahost, inport, locuser, remuser, cmd, fd2p ? &fd2s : NULL);
- if (res != (int) INVALID_SOCKET)
- {
- cygheap_fdnew res_fd;
-
- if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res))
- {
- ((fhandler_socket *) res_fd)->connect_state (connected);
- res = res_fd;
- }
- else
- {
- closesocket (res);
- res = -1;
- }
-
- if (res >= 0 && fd2p)
- {
- cygheap_fdnew newfd (res_fd, false);
- cygheap_fdget fd (*fd2p);
-
- if (newfd >= 0 && fdsock (newfd, tcp_dev, fd2s))
- {
- *fd2p = newfd;
- ((fhandler_socket *) fd2p)->connect_state (connected);
- }
- else
- {
- closesocket (res);
- closesocket (fd2s);
- res = -1;
- }
- }
- }
-
- syscall_printf ("%d = rcmd (...)", res);
- return res;
-}
-
-/* The below implementation of rresvport looks pretty ugly, but there's
- a problem in Winsock. The bind(2) call does not fail if a local
- address is still in TIME_WAIT state, and there's no way to get this
- behaviour. Unfortunately the first time when this is detected is when
- the calling application tries to connect.
-
- One (also not really foolproof) way around this problem would be to use
- the iphlpapi function GetTcpTable and to check if the port in question is
- in TIME_WAIT state and if so, choose another port number. But this method
- is as prone to races as the below one, or any other method using random
- port numbers, etc. The below method at least tries to avoid races between
- multiple applications using rrecvport.
-
- As for the question "why don't you just use the Winsock rresvport?"...
- For some reason I do NOT understand, the call to WinSocks rresvport
- corrupts the stack when Cygwin is built using -fomit-frame-pointers.
- And then again, the Winsock rresvport function has the exact same
- problem with reusing ports in the TIME_WAIT state as the socket/bind
- method has. So there's no gain in using that function. */
-
#define PORT_LOW (IPPORT_EFSSERVER + 1)
#define PORT_HIGH (IPPORT_RESERVED - 1)
#define NUM_PORTS (PORT_HIGH - PORT_LOW + 1)
-LONG last_used_rrecvport __attribute__((section (".cygwin_dll_common"), shared)) = IPPORT_RESERVED;
+LONG last_used_bindresvport __attribute__((section (".cygwin_dll_common"), shared)) = IPPORT_RESERVED;
-/* exported as rresvport: standards? */
extern "C" int
-cygwin_rresvport (int *port)
+cygwin_bindresvport_sa (int fd, struct sockaddr *sa)
{
- int res;
+ struct sockaddr_storage sst;
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+ in_port_t port;
+ socklen_t salen;
+ int ret;
+
sig_dispatch_pending ();
myfault efault;
if (efault.faulted (EFAULT))
return -1;
- res = socket (AF_INET, SOCK_STREAM, 0);
- if (res != (int) INVALID_SOCKET)
+ fhandler_socket *fh = get (fd);
+ if (!fh)
+ return -1;
+
+ if (!sa)
{
- LONG myport;
- int ret = SOCKET_ERROR;
- struct sockaddr_in sin;
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
+ sa = (struct sockaddr *) &sst;
+ memset (&sst, 0, sizeof sst);
+ sa->sa_family = fh->get_addr_family ();
+ }
- for (int i = 0; i < NUM_PORTS; i++)
- {
- while ((myport = InterlockedExchange (&last_used_rrecvport, 0)) == 0)
- low_priority_sleep (0);
- if (--myport < PORT_LOW)
- myport = PORT_HIGH;
- InterlockedExchange (&last_used_rrecvport, myport);
-
- sin.sin_port = htons (myport);
- if (!(ret = bind (res, (struct sockaddr *) &sin, sizeof sin)))
- break;
- int err = WSAGetLastError ();
- if (err != WSAEADDRINUSE && err != WSAEINVAL)
- break;
- }
- if (ret == SOCKET_ERROR)
- {
- closesocket (res);
- res = (int) INVALID_SOCKET;
- }
- else if (port)
- *port = myport;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ salen = sizeof (struct sockaddr_in);
+ sin = (struct sockaddr_in *) sa;
+ port = sin->sin_port;
+ break;
+ case AF_INET6:
+ salen = sizeof (struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *) sa;
+ port = sin6->sin6_port;
+ break;
+ default:
+ set_errno (EPFNOSUPPORT);
+ return -1;
}
- if (res != (int) INVALID_SOCKET)
+ /* If a non-zero port number is given, try this first. If that succeeds,
+ or if the error message is serious, return. */
+ if (port)
{
- cygheap_fdnew res_fd;
+ ret = fh->bind (sa, salen);
+ if (!ret || (get_errno () != EADDRINUSE && get_errno () != EINVAL))
+ return ret;
+ }
- if (res_fd >= 0 && fdsock (res_fd, tcp_dev, res))
- res = res_fd;
+ LONG myport;
+
+ for (int i = 0; i < NUM_PORTS; i++)
+ {
+ while ((myport = InterlockedExchange (&last_used_bindresvport, 0)) == 0)
+ low_priority_sleep (0);
+ if (--myport < PORT_LOW)
+ myport = PORT_HIGH;
+ InterlockedExchange (&last_used_bindresvport, myport);
+
+ if (sa->sa_family == AF_INET6)
+ sin6->sin6_port = htons (myport);
else
- res = -1;
+ sin->sin_port = htons (myport);
+ if (!(ret = fh->bind (sa, salen)))
+ break;
+ if (get_errno () != EADDRINUSE && get_errno () != EINVAL)
+ break;
}
- syscall_printf ("%d = rresvport (%d)", res, port ? *port : 0);
- return res;
+ return ret;
+}
+
+extern "C" int
+cygwin_bindresvport (int fd, struct sockaddr_in *sin)
+{
+ return cygwin_bindresvport_sa (fd, (struct sockaddr *) sin);
}
/* socketpair: standards? */
@@ -2038,7 +1930,7 @@ socketpair (int family, int type, int protocol, int *sb)
{
sock_out.sin_family = AF_INET;
sock_out.sin_port = 0;
- sock_out.sin_addr.s_addr = INADDR_ANY;
+ sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0)
{
debug_printf ("bind failed");
@@ -2207,49 +2099,1381 @@ cygwin_sendmsg (int fd, const struct msghdr *msg, int flags)
return res;
}
-/* See "UNIX Network Programming, Networing APIs: Sockets and XTI",
- W. Richard Stevens, Prentice Hall PTR, 1998. */
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4 (const char *src, u_char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ u_char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0')
+ {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL)
+ {
+ u_int ret = *tp * 10 + (pch - digits);
+
+ if (ret > 255)
+ return (0);
+ *tp = ret;
+ if (! saw_digit)
+ {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ }
+ else if (ch == '.' && saw_digit)
+ {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ }
+ else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+
+ memcpy(dst, tmp, INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6 (const char *src, u_char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0')
+ {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL)
+ {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':')
+ {
+ curtok = src;
+ if (!saw_xdigit)
+ {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0)
+ {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit)
+ {
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (u_char) (val >> 8) & 0xff;
+ *tp++ = (u_char) val & 0xff;
+ }
+ if (colonp != NULL)
+ {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++)
+ {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
extern "C" int
-cygwin_inet_pton (int family, const char *strptr, void *addrptr)
+cygwin_inet_pton (int af, const char *src, void *dst)
{
- if (family == AF_INET)
+ switch (af)
{
- struct in_addr in_val;
+ case AF_INET:
+ return (inet_pton4(src, (u_char *) dst));
+ case AF_INET6:
+ return (inet_pton6(src, (u_char *) dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4 (const u_char *src, char *dst, size_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
- if (cygwin_inet_aton (strptr, &in_val))
+ __small_sprintf(tmp, fmt, src[0], src[1], src[2], src[3]);
+ if (strlen(tmp) > size)
+ {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6 (const u_char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ struct { int base, len; } best, cur;
+ u_int words[IN6ADDRSZ / INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, 0, sizeof words);
+ for (i = 0; i < IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+ {
+ if (words[i] == 0)
+ {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ }
+ else
+ {
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+ {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base && i < (best.base + best.len))
+ {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
{
- memcpy (addrptr, &in_val, sizeof (struct in_addr));
- return 1;
+ if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
}
- return 0;
+ __small_sprintf(tp, "%x", words[i]);
+ tp += strlen(tp);
}
- set_errno (EAFNOSUPPORT);
- return -1;
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t) (tp - tmp) > size)
+ {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
}
-/* See "UNIX Network Programming, Networing APIs: Sockets and XTI",
- W. Richard Stevens, Prentice Hall PTR, 1998. */
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
extern "C" const char *
-cygwin_inet_ntop (int family, const void *addrptr, char *strptr, socklen_t len)
+cygwin_inet_ntop (int af, const void *src, char *dst, socklen_t size)
{
- const u_char *p = (const u_char *) addrptr;
+ switch (af)
+ {
+ case AF_INET:
+ return (inet_ntop4((const u_char *) src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6((const u_char *) src, dst, size));
+ default:
+ errno = EAFNOSUPPORT;
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
- myfault efault;
- if (efault.faulted (EFAULT))
- return NULL;
- if (family == AF_INET)
+/* W. Richard STEVENS libgai implementation, slightly tweaked for inclusion
+ into Cygwin as pure IPv4 replacement. Please note that the code is
+ kept intact as much as possible. Especially the IPv6 and AF_UNIX code
+ is kept in, even though we can support neither of them. Please don't
+ activate them, they won't work correctly. */
+
+#define IPv4
+#undef IPv6
+#undef UNIXdomain
+
+#undef HAVE_SOCKADDR_SA_LEN
+#define gethostbyname2(host,family) cygwin_gethostbyname((host))
+
+#define AI_CLONE 0x8000 /* Avoid collision with AI_ values in netdb.h */
+
+/*
+ * Create and fill in an addrinfo{}.
+ */
+
+/* include ga_aistruct1 */
+static int
+ga_aistruct (struct addrinfo ***paipnext, const struct addrinfo *hintsp,
+ const void *addr, int family)
+{
+ struct addrinfo *ai;
+
+ if ((ai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL)
+ return (EAI_MEMORY);
+ ai->ai_next = NULL;
+ ai->ai_canonname = NULL;
+ **paipnext = ai;
+ *paipnext = &ai->ai_next;
+
+ if ((ai->ai_socktype = hintsp->ai_socktype) == 0)
+ ai->ai_flags |= AI_CLONE;
+
+ ai->ai_protocol = hintsp->ai_protocol;
+/* end ga_aistruct1 */
+
+/* include ga_aistruct2 */
+ switch ((ai->ai_family = family))
{
- char temp[64]; /* Big enough for 4 ints ... */
+#ifdef IPv4
+ case AF_INET:
+ {
+ struct sockaddr_in *sinptr;
+
+ /* 4allocate sockaddr_in{} and fill in all but port */
+ if ((sinptr = (struct sockaddr_in *)
+ calloc (1, sizeof (struct sockaddr_in))) == NULL)
+ return (EAI_MEMORY);
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sinptr->sin_len = sizeof (struct sockaddr_in);
+#endif
+ sinptr->sin_family = AF_INET;
+ memcpy (&sinptr->sin_addr, addr, sizeof (struct in_addr));
+ ai->ai_addr = (struct sockaddr *) sinptr;
+ ai->ai_addrlen = sizeof (struct sockaddr_in);
+ break;
+ }
+#endif /* IPV4 */
+#ifdef IPv6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6ptr;
- __small_sprintf (temp, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
- if (strlen (temp) >= (size_t) len)
+ /* 4allocate sockaddr_in6{} and fill in all but port */
+ if ((sin6ptr = calloc (1, sizeof (struct sockaddr_in6))) == NULL)
+ return (EAI_MEMORY);
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sin6ptr->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ sin6ptr->sin6_family = AF_INET6;
+ memcpy (&sin6ptr->sin6_addr, addr, sizeof (struct in6_addr));
+ ai->ai_addr = (struct sockaddr *) sin6ptr;
+ ai->ai_addrlen = sizeof (struct sockaddr_in6);
+ break;
+ }
+#endif /* IPV6 */
+#ifdef UNIXdomain
+ case AF_LOCAL:
+ {
+ struct sockaddr_un *unp;
+
+ /* 4allocate sockaddr_un{} and fill in */
+/* *INDENT-OFF* */
+ if (strlen(addr) >= sizeof(unp->sun_path))
+ return(EAI_SERVICE);
+ if ( (unp = calloc(1, sizeof(struct sockaddr_un))) == NULL)
+ return(EAI_MEMORY);
+/* *INDENT-ON* */
+ unp->sun_family = AF_LOCAL;
+ strcpy (unp->sun_path, addr);
+#ifdef HAVE_SOCKADDR_SA_LEN
+ unp->sun_len = SUN_LEN (unp);
+#endif
+ ai->ai_addr = (struct sockaddr *) unp;
+ ai->ai_addrlen = sizeof (struct sockaddr_un);
+ if (hintsp->ai_flags & AI_PASSIVE)
+ unlink (unp->sun_path); /* OK if this fails */
+ break;
+ }
+#endif /* UNIXDOMAIN */
+ }
+ return (0);
+}
+
+/* end ga_aistruct2 */
+
+/*
+ * Clone a new addrinfo structure from an existing one.
+ */
+
+/* include ga_clone */
+static struct addrinfo *
+ga_clone (struct addrinfo *ai)
+{
+ struct addrinfo *nai;
+
+ if ((nai = (struct addrinfo *) calloc (1, sizeof (struct addrinfo))) == NULL)
+ return (NULL);
+
+ nai->ai_next = ai->ai_next;
+ ai->ai_next = nai;
+
+ nai->ai_flags = 0; /* make sure AI_CLONE is off */
+ nai->ai_family = ai->ai_family;
+ nai->ai_socktype = ai->ai_socktype;
+ nai->ai_protocol = ai->ai_protocol;
+ nai->ai_canonname = NULL;
+ nai->ai_addrlen = ai->ai_addrlen;
+ if ((nai->ai_addr = (struct sockaddr *) malloc (ai->ai_addrlen)) == NULL)
+ return (NULL);
+ memcpy (nai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+ return (nai);
+}
+
+/* end ga_clone */
+
+/*
+ * Basic error checking of flags, family, socket type, and protocol.
+ */
+
+/* include ga_echeck */
+static int
+ga_echeck (const char *hostname, const char *servname,
+ int flags, int family, int socktype, int protocol)
+{
+ if (flags & ~(AI_PASSIVE | AI_CANONNAME))
+ return (EAI_BADFLAGS); /* unknown flag bits */
+
+ if (hostname == NULL || hostname[0] == '\0')
+ {
+ if (servname == NULL || servname[0] == '\0')
+ return (EAI_NONAME); /* host or service must be specified */
+ }
+
+ switch (family)
+ {
+ case AF_UNSPEC:
+ break;
+#ifdef IPv4
+ case AF_INET:
+ if (socktype != 0 &&
+ (socktype != SOCK_STREAM &&
+ socktype != SOCK_DGRAM && socktype != SOCK_RAW))
+ return (EAI_SOCKTYPE); /* invalid socket type */
+ break;
+#endif
+#ifdef IPv6
+ case AF_INET6:
+ if (socktype != 0 &&
+ (socktype != SOCK_STREAM &&
+ socktype != SOCK_DGRAM && socktype != SOCK_RAW))
+ return (EAI_SOCKTYPE); /* invalid socket type */
+ break;
+#endif
+#ifdef UNIXdomain
+ case AF_LOCAL:
+ if (socktype != 0 &&
+ (socktype != SOCK_STREAM && socktype != SOCK_DGRAM))
+ return (EAI_SOCKTYPE); /* invalid socket type */
+ break;
+#endif
+ default:
+ return (EAI_FAMILY); /* unknown protocol family */
+ }
+ return (0);
+}
+
+/* end ga_echeck */
+
+struct search {
+ const char *host; /* hostname or address string */
+ int family; /* AF_xxx */
+};
+
+/*
+ * Set up the search[] array with the hostnames and address families
+ * that we are to look up.
+ */
+
+/* include ga_nsearch1 */
+static int
+ga_nsearch (const char *hostname, const struct addrinfo *hintsp,
+ struct search *search)
+{
+ int nsearch = 0;
+
+ if (hostname == NULL || hostname[0] == '\0')
+ {
+ if (hintsp->ai_flags & AI_PASSIVE)
{
- set_errno (ENOSPC);
- return NULL;
+ /* 4no hostname and AI_PASSIVE: implies wildcard bind */
+ switch (hintsp->ai_family)
+ {
+#ifdef IPv4
+ case AF_INET:
+ search[nsearch].host = "0.0.0.0";
+ search[nsearch].family = AF_INET;
+ nsearch++;
+ break;
+#endif
+#ifdef IPv6
+ case AF_INET6:
+ search[nsearch].host = "0::0";
+ search[nsearch].family = AF_INET6;
+ nsearch++;
+ break;
+#endif
+ case AF_UNSPEC:
+#ifdef IPv6
+ search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */
+ search[nsearch].family = AF_INET6;
+ nsearch++;
+#endif
+#ifdef IPv4
+ search[nsearch].host = "0.0.0.0";
+ search[nsearch].family = AF_INET;
+ nsearch++;
+#endif
+ break;
+ }
+/* end ga_nsearch1 */
+/* include ga_nsearch2 */
+ }
+ else
+ {
+ /* 4no host and not AI_PASSIVE: connect to local host */
+ switch (hintsp->ai_family)
+ {
+#ifdef IPv4
+ case AF_INET:
+ search[nsearch].host = "localhost"; /* 127.0.0.1 */
+ search[nsearch].family = AF_INET;
+ nsearch++;
+ break;
+#endif
+#ifdef IPv6
+ case AF_INET6:
+ search[nsearch].host = "0::1";
+ search[nsearch].family = AF_INET6;
+ nsearch++;
+ break;
+#endif
+ case AF_UNSPEC:
+#ifdef IPv6
+ search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */
+ search[nsearch].family = AF_INET6;
+ nsearch++;
+#endif
+#ifdef IPv4
+ search[nsearch].host = "localhost";
+ search[nsearch].family = AF_INET;
+ nsearch++;
+#endif
+ break;
+ }
}
- strcpy (strptr, temp);
- return strptr;
+/* end ga_nsearch2 */
+/* include ga_nsearch3 */
}
- set_errno (EAFNOSUPPORT);
- return NULL;
+ else
+ { /* host is specified */
+ switch (hintsp->ai_family)
+ {
+#ifdef IPv4
+ case AF_INET:
+ search[nsearch].host = hostname;
+ search[nsearch].family = AF_INET;
+ nsearch++;
+ break;
+#endif
+#ifdef IPv6
+ case AF_INET6:
+ search[nsearch].host = hostname;
+ search[nsearch].family = AF_INET6;
+ nsearch++;
+ break;
+#endif
+ case AF_UNSPEC:
+#ifdef IPv6
+ search[nsearch].host = hostname;
+ search[nsearch].family = AF_INET6; /* IPv6 first */
+ nsearch++;
+#endif
+#ifdef IPv4
+ search[nsearch].host = hostname;
+ search[nsearch].family = AF_INET; /* then IPv4 */
+ nsearch++;
+#endif
+ break;
+ }
+ }
+ if (nsearch < 1 || nsearch > 2)
+ return -1;
+ return (nsearch);
+}
+
+/* end ga_nsearch3 */
+
+/*
+ * Go through all the addrinfo structures, checking for a match of the
+ * socket type and filling in the socket type, and then the port number
+ * in the corresponding socket address structures.
+ *
+ * The AI_CLONE flag works as follows. Consider a multihomed host with
+ * two IP addresses and no socket type specified by the caller. After
+ * the "host" search there are two addrinfo structures, one per IP address.
+ * Assuming a service supported by both TCP and UDP (say the daytime
+ * service) we need to return *four* addrinfo structures:
+ * IP#1, SOCK_STREAM, TCP port,
+ * IP#1, SOCK_DGRAM, UDP port,
+ * IP#2, SOCK_STREAM, TCP port,
+ * IP#2, SOCK_DGRAM, UDP port.
+ * To do this, when the "host" loop creates an addrinfo structure, if the
+ * caller has not specified a socket type (hintsp->ai_socktype == 0), the
+ * AI_CLONE flag is set. When the following function finds an entry like
+ * this it is handled as follows: If the entry's ai_socktype is still 0,
+ * this is the first use of the structure, and the ai_socktype field is set.
+ * But, if the entry's ai_socktype is nonzero, then we clone a new addrinfo
+ * structure and set it's ai_socktype to the new value. Although we only
+ * need two socket types today (SOCK_STREAM and SOCK_DGRAM) this algorithm
+ * will handle any number. Also notice that Posix.1g requires all socket
+ * types to be nonzero.
+ */
+
+/* include ga_port */
+static int
+ga_port (struct addrinfo *aihead, int port, int socktype)
+ /* port must be in network byte order */
+{
+ int nfound = 0;
+ struct addrinfo *ai;
+
+ for (ai = aihead; ai != NULL; ai = ai->ai_next)
+ {
+ if (ai->ai_flags & AI_CLONE)
+ {
+ if (ai->ai_socktype != 0)
+ {
+ if ((ai = ga_clone (ai)) == NULL)
+ return (-1); /* memory allocation error */
+ /* ai points to newly cloned entry, which is what we want */
+ }
+ }
+ else if (ai->ai_socktype != socktype)
+ continue; /* ignore if mismatch on socket type */
+
+ ai->ai_socktype = socktype;
+
+ switch (ai->ai_family)
+ {
+#ifdef IPv4
+ case AF_INET:
+ ((struct sockaddr_in *) ai->ai_addr)->sin_port = port;
+ nfound++;
+ break;
+#endif
+#ifdef IPv6
+ case AF_INET6:
+ ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port;
+ nfound++;
+ break;
+#endif
+ }
+ }
+ return (nfound);
+}
+
+/* end ga_port */
+
+/*
+ * This function handles the service string.
+ */
+
+/* include ga_serv */
+static int
+ga_serv (struct addrinfo *aihead, const struct addrinfo *hintsp,
+ const char *serv)
+{
+ int port, rc, nfound;
+ struct servent *sptr;
+
+ nfound = 0;
+ if (isdigit (serv[0]))
+ { /* check for port number string first */
+ port = htons (atoi (serv));
+ if (hintsp->ai_socktype)
+ {
+ /* 4caller specifies socket type */
+ if ((rc = ga_port (aihead, port, hintsp->ai_socktype)) < 0)
+ return (EAI_MEMORY);
+ nfound += rc;
+ }
+ else
+ {
+ /* 4caller does not specify socket type */
+ if ((rc = ga_port (aihead, port, SOCK_STREAM)) < 0)
+ return (EAI_MEMORY);
+ nfound += rc;
+ if ((rc = ga_port (aihead, port, SOCK_DGRAM)) < 0)
+ return (EAI_MEMORY);
+ nfound += rc;
+ }
+ }
+ else
+ {
+ /* 4try service name, TCP then UDP */
+ if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_STREAM)
+ {
+ if ((sptr = cygwin_getservbyname (serv, "tcp")) != NULL)
+ {
+ if ((rc = ga_port (aihead, sptr->s_port, SOCK_STREAM)) < 0)
+ return (EAI_MEMORY);
+ nfound += rc;
+ }
+ }
+ if (hintsp->ai_socktype == 0 || hintsp->ai_socktype == SOCK_DGRAM)
+ {
+ if ((sptr = cygwin_getservbyname (serv, "udp")) != NULL)
+ {
+ if ((rc = ga_port (aihead, sptr->s_port, SOCK_DGRAM)) < 0)
+ return (EAI_MEMORY);
+ nfound += rc;
+ }
+ }
+ }
+
+ if (nfound == 0)
+ {
+ if (hintsp->ai_socktype == 0)
+ return (EAI_NONAME); /* all calls to getservbyname() failed */
+ else
+ return (EAI_SERVICE); /* service not supported for socket type */
+ }
+ return (0);
+}
+
+/* end ga_serv */
+
+#ifdef UNIXdomain
+/* include ga_unix */
+static int
+ga_unix (const char *path, struct addrinfo *hintsp, struct addrinfo **result)
+{
+ int rc;
+ struct addrinfo *aihead, **aipnext;
+
+ aihead = NULL;
+ aipnext = &aihead;
+
+ if (hintsp->ai_family != AF_UNSPEC && hintsp->ai_family != AF_LOCAL)
+ return (EAI_ADDRFAMILY);
+
+ if (hintsp->ai_socktype == 0)
+ {
+ /* 4no socket type specified: return stream then dgram */
+ hintsp->ai_socktype = SOCK_STREAM;
+ if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0)
+ return (rc);
+ hintsp->ai_socktype = SOCK_DGRAM;
+ }
+
+ if ((rc = ga_aistruct (&aipnext, hintsp, path, AF_LOCAL)) != 0)
+ return (rc);
+
+ if (hintsp->ai_flags & AI_CANONNAME)
+ {
+ struct utsname myname;
+
+ if (uname (&myname) < 0)
+ return (EAI_SYSTEM);
+ if ((aihead->ai_canonname = strdup (myname.nodename)) == NULL)
+ return (EAI_MEMORY);
+ }
+
+ *result = aihead; /* pointer to first structure in linked list */
+ return (0);
+}
+
+/* end ga_unix */
+#endif /* UNIXdomain */
+
+/* include gn_ipv46 */
+static int
+gn_ipv46 (char *host, size_t hostlen, char *serv, size_t servlen,
+ void *aptr, size_t alen, int family, int port, int flags)
+{
+ char *ptr;
+ struct hostent *hptr;
+ struct servent *sptr;
+
+ if (host && hostlen > 0)
+ {
+ if (flags & NI_NUMERICHOST)
+ {
+ if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL)
+ return (1);
+ }
+ else
+ {
+ hptr = cygwin_gethostbyaddr ((const char *) aptr, alen, family);
+ if (hptr != NULL && hptr->h_name != NULL)
+ {
+ if (flags & NI_NOFQDN)
+ {
+ if ((ptr = strchr (hptr->h_name, '.')) != NULL)
+ *ptr = 0; /* overwrite first dot */
+ }
+ //snprintf (host, hostlen, "%s", hptr->h_name);
+ *host = '\0';
+ strncat (host, hptr->h_name, hostlen - 1);
+ }
+ else
+ {
+ if (flags & NI_NAMEREQD)
+ return (1);
+ if (cygwin_inet_ntop (family, aptr, host, hostlen) == NULL)
+ return (1);
+ }
+ }
+ }
+
+ if (serv && servlen > 0)
+ {
+ if (flags & NI_NUMERICSERV)
+ {
+ //snprintf (serv, servlen, "%d", ntohs (port));
+ char buf[32];
+ __small_sprintf (buf, "%d", ntohs (port));
+ *serv = '\0';
+ strncat (serv, buf, servlen - 1);
+ }
+ else
+ {
+ sptr = cygwin_getservbyport (port, (flags & NI_DGRAM) ? "udp" : NULL);
+ if (sptr != NULL && sptr->s_name != NULL)
+ {
+ //snprintf (serv, servlen, "%s", sptr->s_name);
+ *serv = '\0';
+ strncat (serv, sptr->s_name, servlen - 1);
+ }
+ else
+ {
+ //snprintf (serv, servlen, "%d", ntohs (port));
+ char buf[32];
+ __small_sprintf (buf, "%d", ntohs (port));
+ *serv = '\0';
+ strncat (serv, buf, servlen - 1);
+ }
+ }
+ }
+ return (0);
+}
+
+/* end gn_ipv46 */
+
+/* include freeaddrinfo */
+void
+ipv4_freeaddrinfo (struct addrinfo *aihead)
+{
+ struct addrinfo *ai, *ainext;
+
+ for (ai = aihead; ai != NULL; ai = ainext)
+ {
+ if (ai->ai_addr != NULL)
+ free (ai->ai_addr); /* socket address structure */
+
+ if (ai->ai_canonname != NULL)
+ free (ai->ai_canonname);
+
+ ainext = ai->ai_next; /* can't fetch ai_next after free() */
+ free (ai); /* the addrinfo{} itself */
+ }
+}
+
+/* end freeaddrinfo */
+
+/* include ga1 */
+
+int
+ipv4_getaddrinfo (const char *hostname, const char *servname,
+ const struct addrinfo *hintsp, struct addrinfo **result)
+{
+ int rc, error, nsearch;
+ char **ap, *canon;
+ struct hostent *hptr;
+ struct search search[3], *sptr;
+ struct addrinfo hints, *aihead, **aipnext;
+
+ /*
+ * If we encounter an error we want to free() any dynamic memory
+ * that we've allocated. This is our hack to simplify the code.
+ */
+#define error(e) { error = (e); goto bad; }
+
+ aihead = NULL; /* initialize automatic variables */
+ aipnext = &aihead;
+ canon = NULL;
+
+ if (hintsp == NULL)
+ {
+ bzero (&hints, sizeof (hints));
+ hints.ai_family = AF_UNSPEC;
+ }
+ else
+ hints = *hintsp; /* struct copy */
+
+ /* 4first some basic error checking */
+ if ((rc = ga_echeck (hostname, servname, hints.ai_flags, hints.ai_family,
+ hints.ai_socktype, hints.ai_protocol)) != 0)
+ error (rc);
+
+#ifdef UNIXdomain
+ /* 4special case Unix domain first */
+ if (hostname != NULL &&
+ (strcmp (hostname, "/local") == 0 || strcmp (hostname, "/unix") == 0) &&
+ (servname != NULL && servname[0] == '/'))
+ return (ga_unix (servname, &hints, result));
+#endif
+/* end ga1 */
+
+/* include ga3 */
+ /* 4remainder of function for IPv4/IPv6 */
+ nsearch = ga_nsearch (hostname, &hints, &search[0]);
+ if (nsearch == -1)
+ error (EAI_FAMILY);
+ for (sptr = &search[0]; sptr < &search[nsearch]; sptr++)
+ {
+#ifdef IPv4
+ /* 4check for an IPv4 dotted-decimal string */
+ if (isdigit (sptr->host[0]))
+ {
+ struct in_addr inaddr;
+
+ if (inet_pton4 (sptr->host, (u_char *) &inaddr) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+ error (EAI_ADDRFAMILY);
+ if (sptr->family != AF_INET)
+ continue; /* ignore */
+ rc = ga_aistruct (&aipnext, &hints, &inaddr, AF_INET);
+ if (rc != 0)
+ error (rc);
+ continue;
+ }
+ }
+#endif
+
+#ifdef IPv6
+ /* 4check for an IPv6 hex string */
+ if ((isxdigit (sptr->host[0]) || sptr->host[0] == ':') &&
+ (strchr (sptr->host, ':') != NULL))
+ {
+ struct in6_addr in6addr;
+
+ if (inet_pton6 (sptr->host, &in6addr) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
+ error (EAI_ADDRFAMILY);
+ if (sptr->family != AF_INET6)
+ continue; /* ignore */
+ rc = ga_aistruct (&aipnext, &hints, &in6addr, AF_INET6);
+ if (rc != 0)
+ error (rc);
+ continue;
+ }
+ }
+#endif
+/* end ga3 */
+/* include ga4 */
+#ifdef IPv6
+ /* 4remainder of for() to look up hostname */
+ if ((_res.options & RES_INIT) == 0)
+ res_init (); /* need this to set _res.options */
+#endif
+
+ if (nsearch == 2)
+ {
+#ifdef IPv6
+ _res.options &= ~RES_USE_INET6;
+#endif
+ hptr = gethostbyname2 (sptr->host, sptr->family);
+ }
+ else
+ {
+#ifdef IPv6
+ if (sptr->family == AF_INET6)
+ _res.options |= RES_USE_INET6;
+ else
+ _res.options &= ~RES_USE_INET6;
+#endif
+ hptr = gethostbyname (sptr->host);
+ }
+ if (hptr == NULL)
+ {
+ if (nsearch == 2)
+ continue; /* failure OK if multiple searches */
+
+ switch (h_errno)
+ {
+ case HOST_NOT_FOUND:
+ error (EAI_NONAME);
+ case TRY_AGAIN:
+ error (EAI_AGAIN);
+ case NO_RECOVERY:
+ error (EAI_FAIL);
+ case NO_DATA:
+ error (EAI_NODATA);
+ default:
+ error (EAI_NONAME);
+ }
+ }
+
+ /* 4check for address family mismatch if one specified */
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype)
+ error (EAI_ADDRFAMILY);
+
+ /* 4save canonical name first time */
+ if (hostname != NULL && hostname[0] != '\0' &&
+ (hints.ai_flags & AI_CANONNAME) && canon == NULL)
+ {
+ if ((canon = strdup (hptr->h_name)) == NULL)
+ error (EAI_MEMORY);
+ }
+
+ /* 4create one addrinfo{} for each returned address */
+ for (ap = hptr->h_addr_list; *ap != NULL; ap++)
+ {
+ rc = ga_aistruct (&aipnext, &hints, *ap, hptr->h_addrtype);
+ if (rc != 0)
+ error (rc);
+ }
+ }
+ if (aihead == NULL)
+ error (EAI_NONAME); /* nothing found */
+/* end ga4 */
+
+/* include ga5 */
+ /* 4return canonical name */
+ if (hostname != NULL && hostname[0] != '\0' &&
+ hints.ai_flags & AI_CANONNAME)
+ {
+ if (canon != NULL)
+ aihead->ai_canonname = canon; /* strdup'ed earlier */
+ else
+ {
+ if ((aihead->ai_canonname = strdup (search[0].host)) == NULL)
+ error (EAI_MEMORY);
+ }
+ }
+
+ /* 4now process the service name */
+ if (servname != NULL && servname[0] != '\0')
+ {
+ if ((rc = ga_serv (aihead, &hints, servname)) != 0)
+ error (rc);
+ }
+
+ *result = aihead; /* pointer to first structure in linked list */
+ return (0);
+
+bad:
+ ipv4_freeaddrinfo (aihead); /* free any alloc'ed memory */
+ return (error);
}
+
+/* end ga5 */
+
+/* include getnameinfo */
+int
+ipv4_getnameinfo (const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags)
+{
+
+ switch (sa->sa_family)
+ {
+#ifdef IPv4
+ case AF_INET:
+ {
+ struct sockaddr_in *sain = (struct sockaddr_in *) sa;
+
+ return (gn_ipv46 (host, hostlen, serv, servlen,
+ &sain->sin_addr, sizeof (struct in_addr),
+ AF_INET, sain->sin_port, flags));
+ }
+#endif
+
+#ifdef IPv6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa;
+
+ return (gn_ipv46 (host, hostlen, serv, servlen,
+ &sain->sin6_addr, sizeof (struct in6_addr),
+ AF_INET6, sain->sin6_port, flags));
+ }
+#endif
+
+#ifdef UNIXdomain
+ case AF_LOCAL:
+ {
+ struct sockaddr_un *un = (struct sockaddr_un *) sa;
+
+ if (hostlen > 0)
+ snprintf (host, hostlen, "%s", "/local");
+ if (servlen > 0)
+ snprintf (serv, servlen, "%s", un->sun_path);
+ return (0);
+ }
+#endif
+
+ default:
+ return (1);
+ }
+}
+
+/* end getnameinfo */
+
+/* Start of cygwin specific wrappers around the gai functions. */
+
+struct gai_errmap_t
+{
+ int w32_errval;
+ const char *errtxt;
+};
+
+static gai_errmap_t gai_errmap[] =
+{
+ {0, "Success"},
+ {0, "Address family for hostname not supported"},
+ {WSATRY_AGAIN, "Temporary failure in name resolution"},
+ {WSAEINVAL, "Invalid value for ai_flags"},
+ {WSANO_RECOVERY, "Non-recoverable failure in name resolution"},
+ {WSAEAFNOSUPPORT, "ai_family not supported"},
+ {WSA_NOT_ENOUGH_MEMORY, "Memory allocation failure"},
+ {WSANO_DATA, "No address associated with hostname"},
+ {WSAHOST_NOT_FOUND, "hostname nor servname provided, or not known"},
+ {WSATYPE_NOT_FOUND, "servname not supported for ai_socktype"},
+ {WSAESOCKTNOSUPPORT, "ai_socktype not supported"},
+ {0, "System error returned in errno"},
+ {0, "Invalid value for hints"},
+ {0, "Resolved protocol is unknown"}
+};
+
+extern "C" const char *
+cygwin_gai_strerror (int err)
+{
+ if (err >= 0 && err < EAI_MAX)
+ return gai_errmap[err].errtxt;
+ return "Unknown error";
+}
+
+static int
+w32_to_gai_err (int w32_err)
+{
+ if (w32_err >= WSABASEERR)
+ for (int i = 0; i < EAI_MAX; ++i)
+ if (gai_errmap[i].w32_errval == w32_err)
+ return i;
+ return w32_err;
+}
+
+/* We can't use autoload here because we don't know where the functions
+ are loaded from. On Win2K, the functions are available in the
+ ipv6 technology preview lib called wship6.dll, in XP and above they
+ are implemented in ws2_32.dll. For older systems we use the ipv4-only
+ version above. */
+
+static void (WINAPI *freeaddrinfo)(const struct addrinfo *);
+static int (WINAPI *getaddrinfo)(const char *, const char *,
+ const struct addrinfo *,
+ struct addrinfo **);
+static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t,
+ char *, size_t, char *, size_t, int);
+static bool
+get_ipv6_funcs (HMODULE lib)
+{
+ return ((freeaddrinfo = (void (WINAPI *)(const struct addrinfo *))
+ GetProcAddress(lib, "freeaddrinfo"))
+ && (getaddrinfo = (int (WINAPI *)(const char *, const char *,
+ const struct addrinfo *,
+ struct addrinfo **))
+ GetProcAddress(lib, "getaddrinfo"))
+ && (getnameinfo = (int (WINAPI *)(const struct sockaddr *,
+ socklen_t, char *, size_t,
+ char *, size_t, int))
+ GetProcAddress(lib, "getnameinfo")));
+}
+
+static NO_COPY muto load_ipv6_guard;
+static bool ipv6_inited = false;
+#define load_ipv6() if (!ipv6_inited) load_ipv6_funcs ();
+
+static void
+load_ipv6_funcs ()
+{
+
+ char lib_name[CYG_MAX_PATH];
+ size_t len;
+ HMODULE lib;
+
+ load_ipv6_guard.init ("klog_guard")->acquire ();
+ if (ipv6_inited)
+ goto out;
+ WSAGetLastError (); /* Kludge. Enforce WSAStartup call. */
+ if (GetSystemDirectory (lib_name, CYG_MAX_PATH))
+ {
+ len = strlen (lib_name);
+ strcpy (lib_name + len, "\\ws2_32.dll");
+ if ((lib = LoadLibrary (lib_name)))
+ {
+ if (get_ipv6_funcs (lib))
+ goto out;
+ FreeLibrary (lib);
+ }
+ strcpy (lib_name + len, "\\wship6.dll");
+ if ((lib = LoadLibrary (lib_name)))
+ {
+ if (get_ipv6_funcs (lib))
+ goto out;
+ FreeLibrary (lib);
+ }
+ freeaddrinfo = NULL;
+ getaddrinfo = NULL;
+ getnameinfo = NULL;
+ }
+out:
+ ipv6_inited = true;
+ load_ipv6_guard.release ();
+}
+
+extern "C" void
+cygwin_freeaddrinfo (struct addrinfo *addr)
+{
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return;
+ load_ipv6 ();
+ if (freeaddrinfo)
+ freeaddrinfo (addr);
+ else
+ ipv4_freeaddrinfo (addr);
+}
+
+extern "C" int
+cygwin_getaddrinfo (const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return EAI_SYSTEM;
+ load_ipv6 ();
+ if (getaddrinfo)
+ return w32_to_gai_err (getaddrinfo (hostname, servname, hints, res));
+ return ipv4_getaddrinfo (hostname, servname, hints, res);
+}
+
+extern "C" int
+cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv,
+ size_t servlen, int flags)
+{
+ myfault efault;
+ if (efault.faulted (EFAULT))
+ return EAI_SYSTEM;
+ load_ipv6 ();
+ if (getnameinfo)
+ {
+ /* When the incoming port number is set to 0, Winsock's getnameinfo
+ returns with error WSAENO_DATA instead of simply ignoring the port.
+ To avoid this strange behaviour, we check manually, if the port number
+ is 0. If so, set the NI_NUMERICSERV flag to avoid this problem. */
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (((struct sockaddr_in *) sa)->sin_port == 0)
+ flags |= NI_NUMERICSERV;
+ break;
+ case AF_INET6:
+ if (((struct sockaddr_in6 *) sa)->sin6_port == 0)
+ flags |= NI_NUMERICSERV;
+ break;
+ }
+ int ret = w32_to_gai_err (getnameinfo (sa, salen, host, hostlen, serv,
+ servlen, flags));
+ if (ret)
+ set_winsock_errno ();
+ return ret;
+ }
+ return ipv4_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags);
+}
+
diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc
index 0ff62379e..3ce46fab6 100644
--- a/winsup/cygwin/poll.cc
+++ b/winsup/cygwin/poll.cc
@@ -97,6 +97,10 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
sock = cygheap->fdtab[fds[i].fd]->is_socket ();
if (!sock)
fds[i].revents |= POLLIN;
+ else if (sock->listener ())
+ {
+ fds[i].revents |= POLLIN;
+ }
else
{
/* The following action can change errno. We have to
@@ -105,18 +109,8 @@ poll (struct pollfd *fds, unsigned int nfds, int timeout)
switch (sock->recvfrom (peek, sizeof (peek), MSG_PEEK,
NULL, NULL))
{
- case -1: /* Something weird happened */
- /* When select returns that data is available,
- that could mean that the socket is in
- listen mode and a client tries to connect.
- Unfortunately, recvfrom() doesn't make much
- sense then. It returns WSAENOTCONN in that
- case. Since that's not actually an error,
- we must not set POLLERR but POLLIN. */
- if (WSAGetLastError () != WSAENOTCONN)
- fds[i].revents |= POLLERR;
- else
- fds[i].revents |= POLLIN;
+ case -1:
+ fds[i].revents |= POLLERR;
break;
case 0: /* Closed on the read side... */
/* ...or shutdown(SHUT_WR) on the write side.
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 23f86e369..0970805ec 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -28,6 +28,7 @@ details. */
#include <ntsecapi.h>
#include <subauth.h>
#include <aclapi.h>
+#include <dsgetdc.h>
#include "cygerrno.h"
#include "security.h"
#include "path.h"
@@ -208,13 +209,21 @@ close_local_policy (LSA_HANDLE &lsa)
lsa = INVALID_HANDLE_VALUE;
}
+/* CV, 2006-07-06: Missing in w32api. */
+extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG,
+ PDOMAIN_CONTROLLER_INFOA *);
+#define DS_FORCE_REDISCOVERY 1
+
bool
-get_logon_server (const char *domain, char *server, WCHAR *wserver)
+get_logon_server (const char *domain, char *server, WCHAR *wserver,
+ bool rediscovery)
{
- WCHAR wdomain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
- NET_API_STATUS ret;
+ DWORD dret;
+ PDOMAIN_CONTROLLER_INFOA pci;
+ NET_API_STATUS nret;
WCHAR *buf;
DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ WCHAR wdomain[size];
/* Empty domain is interpreted as local system */
if ((GetComputerName (server + 2, &size)) &&
@@ -226,18 +235,37 @@ get_logon_server (const char *domain, char *server, WCHAR *wserver)
return true;
}
- /* Try to get the primary domain controller for the domain */
- sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
- if ((ret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf)) == STATUS_SUCCESS)
+ /* Try to get any available domain controller for this domain */
+ dret = DsGetDcNameA (NULL, domain, NULL, NULL,
+ rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
+ if (dret == ERROR_SUCCESS)
{
- sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
- if (wserver)
- for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
- ;
- NetApiBufferFree (buf);
+ strcpy (server, pci->DomainControllerName);
+ sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ NetApiBufferFree (pci);
+ debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server);
return true;
}
- __seterrno_from_win_error (ret);
+ else if (dret == ERROR_PROC_NOT_FOUND)
+ {
+ /* NT4 w/o DSClient */
+ sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (rediscovery)
+ nret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf);
+ else
+ nret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf);
+ if (nret == NERR_Success)
+ {
+ sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
+ if (wserver)
+ for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
+ ;
+ NetApiBufferFree (buf);
+ debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server);
+ return true;
+ }
+ }
+ __seterrno_from_win_error (nret);
return false;
}
@@ -473,7 +501,11 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
grp_list += well_known_network_sid;
if (sid_in_token_groups (my_grps, well_known_batch_sid))
grp_list += well_known_batch_sid;
- if (sid_in_token_groups (my_grps, well_known_interactive_sid))
+ /* This is a problem on 2K3 (only domain controllers?!?) which only
+ enables tools for selected special groups. A subauth token is
+ only NETWORK, but NETWORK has no access to these tools. Therefore
+ we always add INTERACTIVE here. */
+ /*if (sid_in_token_groups (my_grps, well_known_interactive_sid))*/
grp_list += well_known_interactive_sid;
if (sid_in_token_groups (my_grps, well_known_service_sid))
grp_list += well_known_service_sid;
@@ -485,11 +517,13 @@ get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
}
if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
{
- char buf[64];
- __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
- auth_luid.LowPart);
- grp_list += buf;
- auth_pos = grp_list.count - 1;
+ for (DWORD i = 0; i < my_grps->GroupCount; ++i)
+ if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
+ {
+ grp_list += my_grps->Groups[i].Sid;
+ auth_pos = grp_list.count - 1;
+ break;
+ }
}
}
@@ -511,7 +545,9 @@ get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
grp_list += well_known_world_sid;
grp_list += well_known_authenticated_users_sid;
extract_nt_dom_user (pw, domain, user);
- if (get_logon_server (domain, server, wserver))
+ if (get_logon_server (domain, server, wserver, false)
+ && !get_user_groups (wserver, grp_list, user, domain)
+ && get_logon_server (domain, server, wserver, true))
get_user_groups (wserver, grp_list, user, domain);
get_unix_group_sidlist (pw, grp_list);
return get_user_local_groups (grp_list, usersid);
@@ -780,7 +816,8 @@ done:
}
HANDLE
-create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
+create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw,
+ HANDLE subauth_token)
{
NTSTATUS ret;
LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
@@ -803,7 +840,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
TOKEN_STATISTICS stats;
memcpy (source.SourceName, "Cygwin.1", 8);
source.SourceIdentifier.HighPart = 0;
- source.SourceIdentifier.LowPart = 0x0101;
+ source.SourceIdentifier.LowPart = (subauth_token ? 0x0102 : 0x0101);
HANDLE token = INVALID_HANDLE_VALUE;
HANDLE primary_token = INVALID_HANDLE_VALUE;
@@ -824,33 +861,60 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
owner.Owner = usersid;
/* Retrieve authentication id and group list from own process. */
- if (hProcToken)
+ HANDLE get_token;
+ if (subauth_token)
+ {
+ debug_printf ("get_token = subauth_token");
+ get_token = subauth_token;
+ }
+ else
+ {
+ debug_printf ("get_token = hProcToken");
+ get_token = hProcToken;
+ }
+ if (get_token)
{
/* Switching user context to SYSTEM doesn't inherit the authentication
id of the user account running current process. */
if (usersid != well_known_system_sid)
- if (!GetTokenInformation (hProcToken, TokenStatistics,
+ if (!GetTokenInformation (get_token, TokenStatistics,
&stats, sizeof stats, &size))
debug_printf
- ("GetTokenInformation(hProcToken, TokenStatistics), %E");
+ ("GetTokenInformation(get_token, TokenStatistics), %E");
else
auth_luid = stats.AuthenticationId;
/* Retrieving current processes group list to be able to inherit
some important well known group sids. */
- if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size) &&
- GetLastError () != ERROR_INSUFFICIENT_BUFFER)
- debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
+ if (!GetTokenInformation (get_token, TokenGroups, NULL, 0, &size)
+ && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ debug_printf ("GetTokenInformation(get_token, TokenGroups), %E");
else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
debug_printf ("malloc (my_tok_gsids) failed.");
- else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
+ else if (!GetTokenInformation (get_token, TokenGroups, my_tok_gsids,
size, &size))
{
- debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
+ debug_printf ("GetTokenInformation(get_token, TokenGroups), %E");
free (my_tok_gsids);
my_tok_gsids = NULL;
}
}
+ if (subauth_token)
+ {
+ if (!GetTokenInformation (subauth_token, TokenPrivileges, NULL, 0, &size)
+ && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ debug_printf ("GetTokenInformation(subauth_token, TokenPrivileges), %E");
+ else if (!(privs = (PTOKEN_PRIVILEGES) malloc (size)))
+ debug_printf ("malloc (privs) failed.");
+ else if (!GetTokenInformation (subauth_token, TokenPrivileges, privs,
+ size, &size))
+ {
+ debug_printf ("GetTokenInformation(subauth_token, TokenPrivileges), %E");
+ free (privs);
+ privs = NULL;
+ }
+ }
+
/* Create list of groups, the user is member in. */
int auth_pos;
@@ -878,7 +942,7 @@ create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
/* Retrieve list of privileges of that user. */
- if (!(privs = get_priv_list (lsa, usersid, tmp_gsids)))
+ if (!privs && !(privs = get_priv_list (lsa, usersid, tmp_gsids)))
goto out;
/* Let's be heroic... */
@@ -1299,7 +1363,7 @@ get_reg_security (HANDLE handle, security_descriptor &sd_ret)
| OWNER_SECURITY_INFORMATION,
sd_ret, &len);
}
- if (ret != STATUS_SUCCESS)
+ if (ret != ERROR_SUCCESS)
{
__seterrno ();
return -1;
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index a55cc03d6..ef0871fdd 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -322,7 +322,8 @@ void __stdcall str2uni_cat (_UNICODE_STRING &, const char *) __attribute__ ((reg
/* Try a subauthentication. */
HANDLE subauth (struct passwd *pw);
/* Try creating a token directly. */
-HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw);
+HANDLE create_token (cygsid &usersid, user_groups &groups, struct passwd * pw,
+ HANDLE subauth_token);
/* Verify an existing token */
bool verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern = NULL);
/* Get groups of a user */
@@ -331,7 +332,8 @@ bool get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw);
/* Extract U-domain\user field from passwd entry. */
void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user);
/* Get default logonserver for a domain. */
-bool get_logon_server (const char * domain, char * server, WCHAR *wserver = NULL);
+bool get_logon_server (const char * domain, char * server, WCHAR *wserver,
+ bool rediscovery);
/* sec_helper.cc: Security helper functions. */
int set_privilege (HANDLE token, enum cygpriv_idx privilege, bool enable);
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 63215ca75..a1abba610 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -30,7 +30,6 @@ details. */
#define USE_SYS_TYPES_FD_SET
#include <winsock.h>
#include "cygerrno.h"
-#include "select.h"
#include "security.h"
#include "path.h"
#include "fhandler.h"
@@ -1260,105 +1259,69 @@ fhandler_base::select_except (select_record *s)
return s;
}
-struct socketinf
- {
- cygthread *thread;
- winsock_fd_set readfds, writefds, exceptfds;
- SOCKET exitsock;
- select_record *start;
- };
-
static int
peek_socket (select_record *me, bool)
{
- winsock_fd_set ws_readfds, ws_writefds, ws_exceptfds;
- struct timeval tv = {0, 0};
- WINSOCK_FD_ZERO (&ws_readfds);
- WINSOCK_FD_ZERO (&ws_writefds);
- WINSOCK_FD_ZERO (&ws_exceptfds);
-
- HANDLE h;
- set_handle_or_return_if_not_open (h, me);
- select_printf ("considering handle %p", h);
-
- if (me->read_selected && !me->read_ready)
- {
- select_printf ("adding read fd_set %s, fd %d", me->fh->get_name (),
- me->fd);
- WINSOCK_FD_SET (h, &ws_readfds);
- }
- if (me->write_selected && !me->write_ready)
- {
- select_printf ("adding write fd_set %s, fd %d", me->fh->get_name (),
- me->fd);
- WINSOCK_FD_SET (h, &ws_writefds);
- }
- if ((me->except_selected || me->except_on_write) && !me->except_ready)
- {
- select_printf ("adding except fd_set %s, fd %d", me->fh->get_name (),
- me->fd);
- WINSOCK_FD_SET (h, &ws_exceptfds);
- }
- int r;
- if ((me->read_selected && !me->read_ready)
- || (me->write_selected && !me->write_ready)
- || ((me->except_selected || me->except_on_write) && !me->except_ready))
+ fhandler_socket *fh = (fhandler_socket *) me->fh;
+ long events;
+ long evt_mask = (FD_CLOSE
+ | (me->read_selected ? (FD_READ | FD_ACCEPT) : 0)
+ | (me->write_selected ? (FD_WRITE | FD_CONNECT) : 0)
+ | (me->except_selected ? (FD_OOB | FD_CONNECT) : 0));
+ int ret = fh->evaluate_events (evt_mask, events, false);
+ if (me->read_selected)
+ me->read_ready |= !!(events & (FD_READ | FD_ACCEPT | FD_CLOSE));
+ if (me->write_selected)
{
- r = WINSOCK_SELECT (0, &ws_readfds, &ws_writefds, &ws_exceptfds, &tv);
- select_printf ("WINSOCK_SELECT returned %d", r);
- if (r == -1)
- {
- select_printf ("error %d", WSAGetLastError ());
- set_winsock_errno ();
- return 0;
- }
- if (WINSOCK_FD_ISSET (h, &ws_readfds))
- me->read_ready = true;
- if (WINSOCK_FD_ISSET (h, &ws_writefds))
+ if ((events & FD_CONNECT) && !ret)
me->write_ready = true;
- if (WINSOCK_FD_ISSET (h, &ws_exceptfds))
- me->except_ready = true;
+ else
+ me->write_ready |= !!(events & (FD_WRITE | FD_CLOSE));
}
+ if (me->except_selected)
+ me->except_ready |= ret || !!(events & (FD_OOB | FD_CLOSE));
+
return me->read_ready || me->write_ready || me->except_ready;
}
static int start_thread_socket (select_record *, select_stuff *);
+struct socketinf
+ {
+ cygthread *thread;
+ int num_w4;
+ HANDLE w4[MAXIMUM_WAIT_OBJECTS];
+ select_record *start;
+ };
+
static DWORD WINAPI
thread_socket (void *arg)
{
socketinf *si = (socketinf *) arg;
+ bool event = false;
- select_printf ("stuff_start %p", &si->start);
- int r = WINSOCK_SELECT (0, &si->readfds, &si->writefds, &si->exceptfds, NULL);
- select_printf ("Win32 select returned %d", r);
- if (r == -1)
- select_printf ("error %d", WSAGetLastError ());
- select_record *s = si->start;
- while ((s = s->next))
- if (s->startup == start_thread_socket)
- {
- HANDLE h = s->fh->get_handle ();
- select_printf ("s %p, testing fd %d (%s)", s, s->fd, s->fh->get_name ());
- if (WINSOCK_FD_ISSET (h, &si->readfds))
- {
- select_printf ("read_ready");
- s->read_ready = true;
- }
- if (WINSOCK_FD_ISSET (h, &si->writefds))
- {
- select_printf ("write_ready");
- s->write_ready = true;
- }
- if (WINSOCK_FD_ISSET (h, &si->exceptfds))
+ select_printf ("stuff_start %p", si->start);
+ while (!event)
+ {
+ for (select_record *s = si->start; (s = s->next); )
+ if (s->startup == start_thread_socket)
+ if (peek_socket (s, false))
+ event = true;
+ if (!event)
+ {
+ switch (WaitForMultipleObjects (si->num_w4, si->w4, FALSE, 50))
{
- select_printf ("except_ready");
- s->except_ready = true;
+ case WAIT_OBJECT_0:
+ case WAIT_FAILED:
+ goto out;
+ case WAIT_TIMEOUT:
+ default:
+ break;
}
}
-
- if (WINSOCK_FD_ISSET (si->exitsock, &si->readfds))
- select_printf ("saw exitsock read");
+ }
+out:
+ select_printf ("leaving thread_socket");
return 0;
}
@@ -1374,68 +1337,29 @@ start_thread_socket (select_record *me, select_stuff *stuff)
}
si = new socketinf;
- WINSOCK_FD_ZERO (&si->readfds);
- WINSOCK_FD_ZERO (&si->writefds);
- WINSOCK_FD_ZERO (&si->exceptfds);
select_record *s = &stuff->start;
+ if (_my_tls.locals.select_sockevt != INVALID_HANDLE_VALUE)
+ si->w4[0] = _my_tls.locals.select_sockevt;
+ else if (!(si->w4[0] = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL)))
+ return 1;
+ else
+ _my_tls.locals.select_sockevt = si->w4[0];
+ si->num_w4 = 1;
while ((s = s->next))
if (s->startup == start_thread_socket)
{
- HANDLE h = s->fh->get_handle ();
- select_printf ("Handle %p", h);
- if (s->read_selected && !s->read_ready)
- {
- WINSOCK_FD_SET (h, &si->readfds);
- select_printf ("Added to readfds");
- }
- if (s->write_selected && !s->write_ready)
- {
- WINSOCK_FD_SET (h, &si->writefds);
- select_printf ("Added to writefds");
- }
- if ((s->except_selected || s->except_on_write) && !s->except_ready)
- {
- WINSOCK_FD_SET (h, &si->exceptfds);
- select_printf ("Added to exceptfds");
- }
- }
-
- if (_my_tls.locals.exitsock != INVALID_SOCKET)
- si->exitsock = _my_tls.locals.exitsock;
- else
- {
- si->exitsock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (si->exitsock == INVALID_SOCKET)
- {
- set_winsock_errno ();
- select_printf ("cannot create socket, %E");
- return 0;
- }
- int sin_len = sizeof (_my_tls.locals.exitsock_sin);
- memset (&_my_tls.locals.exitsock_sin, 0, sin_len);
- _my_tls.locals.exitsock_sin.sin_family = AF_INET;
- _my_tls.locals.exitsock_sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
- if (bind (si->exitsock, (struct sockaddr *) &_my_tls.locals.exitsock_sin, sin_len) < 0)
- {
- select_printf ("cannot bind socket %p, %E", si->exitsock);
+ HANDLE evt = ((fhandler_socket *) me->fh)->wsock_evt;
+ /* No event/socket should show up multiple times. */
+ for (int i = 1; i < si->num_w4; ++i)
+ if (si->w4[i] == evt)
+ goto continue_outer_loop;
+ if (si->num_w4 < MAXIMUM_WAIT_OBJECTS)
+ si->w4[si->num_w4++] = evt;
+ else /* for now */
goto err;
- }
-
- if (getsockname (si->exitsock, (struct sockaddr *) &_my_tls.locals.exitsock_sin, &sin_len) < 0)
- {
- select_printf ("getsockname error");
- goto err;
- }
- if (wincap.has_set_handle_information ())
- SetHandleInformation ((HANDLE) si->exitsock, HANDLE_FLAG_INHERIT, 0);
- /* else
- too bad? */
- select_printf ("opened new socket %p", si->exitsock);
- _my_tls.locals.exitsock = si->exitsock;
- }
-
- select_printf ("exitsock %p", si->exitsock);
- WINSOCK_FD_SET ((HANDLE) si->exitsock, &si->readfds);
+ continue_outer_loop:
+ ;
+ }
stuff->device_specific_socket = (void *) si;
si->start = &stuff->start;
select_printf ("stuff_start %p", &stuff->start);
@@ -1444,8 +1368,7 @@ start_thread_socket (select_record *me, select_stuff *stuff)
return 1;
err:
- set_winsock_errno ();
- closesocket (si->exitsock);
+ CloseHandle (si->w4[0]);
return 0;
}
@@ -1456,17 +1379,10 @@ socket_cleanup (select_record *, select_stuff *stuff)
select_printf ("si %p si->thread %p", si, si ? si->thread : NULL);
if (si && si->thread)
{
- char buf[] = "";
- int res = sendto (_my_tls.locals.exitsock, buf, 1, 0,
- (sockaddr *) &_my_tls.locals.exitsock_sin,
- sizeof (_my_tls.locals.exitsock_sin));
- select_printf ("sent a byte to exitsock %p, res %d", _my_tls.locals.exitsock, res);
+ SetEvent (si->w4[0]);
/* Wait for thread to go away */
si->thread->detach ();
- /* empty the socket */
- select_printf ("reading a byte from exitsock %p", si->exitsock);
- res = recv (si->exitsock, buf, 1, 0);
- select_printf ("recv returned %d", res);
+ ResetEvent (si->w4[0]);
stuff->device_specific_socket = NULL;
delete si;
}
diff --git a/winsup/cygwin/select.h b/winsup/cygwin/select.h
deleted file mode 100644
index 0938708f2..000000000
--- a/winsup/cygwin/select.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* select.h
-
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 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. */
-
-/* Winsock select() types and macros */
-
-/*
- * Use this struct to interface to
- * the system provided select.
- */
-typedef struct winsock_fd_set
-{
- unsigned int fd_count;
- HANDLE fd_array[1024]; /* Dynamically allocated. */
-} winsock_fd_set;
-
-/*
- * Define the Win32 winsock definitions to have a prefix WINSOCK_
- * so we can be explicit when we are using them.
- */
-#define WINSOCK_FD_ISSET(fd, set) __WSAFDIsSet ((SOCKET)fd, (fd_set *)set)
-#define WINSOCK_FD_SET(fd, set) do { \
- (set)->fd_array[(set)->fd_count++]=fd;\
-} while(0)
-#define WINSOCK_FD_ZERO(set) ((set)->fd_count = 0)
-#define WINSOCK_FD_CLR(fd, set) do { \
- u_int __i; \
- for (__i = 0; __i < (set)->fd_count ; __i++) { \
- if ((set)->fd_array[__i] == fd) { \
- while (__i < (set)->fd_count-1) { \
- (set)->fd_array[__i] = \
- (set)->fd_array[__i+1]; \
- __i++; \
- } \
- (set)->fd_count--; \
- break; \
- } \
- } \
-} while(0)
-
-extern "C" int PASCAL __WSAFDIsSet(SOCKET, fd_set*);
-extern "C" int PASCAL win32_select(int, fd_set*, fd_set*, fd_set*, const struct timeval*);
-
-/*
- * call to winsock's select() -
- * type coercion need to appease confused prototypes
- */
-#define WINSOCK_SELECT(nfd, rd, wr, ex, timeo) \
- win32_select (nfd, (fd_set *) rd, (fd_set *) wr, (fd_set *) ex, timeo)
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 6faa09f00..a8b7aa815 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -2172,18 +2172,29 @@ seteuid32 (__uid32_t uid)
authenticate using NtCreateToken () or subauthentication. */
if (new_token == INVALID_HANDLE_VALUE)
{
- new_token = create_token (usersid, groups, pw_new);
+ new_token = subauth (pw_new);
if (new_token == INVALID_HANDLE_VALUE)
{
- /* create_token failed. Try subauthentication. */
- debug_printf ("create token failed, try subauthentication.");
- new_token = subauth (pw_new);
+ debug_printf ("subauthentication failed, try create token.");
+ new_token = create_token (usersid, groups, pw_new, NULL);
if (new_token == INVALID_HANDLE_VALUE)
{
cygheap->user.reimpersonate ();
return -1;
}
}
+ else
+ {
+ debug_printf ("subauthentication succeeded, try create token.");
+ HANDLE new_token2 = create_token (usersid, groups, pw_new, new_token);
+ if (new_token2 == INVALID_HANDLE_VALUE)
+ debug_printf ("create token failed, use original token");
+ else
+ {
+ CloseHandle (new_token);
+ new_token = new_token2;
+ }
+ }
/* Keep at most one internal token */
if (cygheap->user.internal_token != NO_IMPERSONATION)
CloseHandle (cygheap->user.internal_token);
diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h
index 3ee482280..5fa884ecb 100644
--- a/winsup/cygwin/tlsoffsets.h
+++ b/winsup/cygwin/tlsoffsets.h
@@ -1,6 +1,6 @@
//;# autogenerated: Do not edit.
-//; $tls::sizeof__cygtls = 4212;
+//; $tls::sizeof__cygtls = 4196;
//; $tls::func = -12700;
//; $tls::pfunc = 0;
//; $tls::el = -12696;
@@ -39,30 +39,30 @@
//; $tls::p__dontuse = 420;
//; $tls::locals = -11216;
//; $tls::plocals = 1484;
-//; $tls::_ctinfo = -9584;
-//; $tls::p_ctinfo = 3116;
-//; $tls::andreas = -9580;
-//; $tls::pandreas = 3120;
-//; $tls::wq = -9572;
-//; $tls::pwq = 3128;
-//; $tls::prev = -9544;
-//; $tls::pprev = 3156;
-//; $tls::next = -9540;
-//; $tls::pnext = 3160;
-//; $tls::sig = -9536;
-//; $tls::psig = 3164;
-//; $tls::incyg = -9532;
-//; $tls::pincyg = 3168;
-//; $tls::spinning = -9528;
-//; $tls::pspinning = 3172;
-//; $tls::stacklock = -9524;
-//; $tls::pstacklock = 3176;
-//; $tls::stackptr = -9520;
-//; $tls::pstackptr = 3180;
-//; $tls::stack = -9516;
-//; $tls::pstack = 3184;
-//; $tls::initialized = -8492;
-//; $tls::pinitialized = 4208;
+//; $tls::_ctinfo = -9600;
+//; $tls::p_ctinfo = 3100;
+//; $tls::andreas = -9596;
+//; $tls::pandreas = 3104;
+//; $tls::wq = -9588;
+//; $tls::pwq = 3112;
+//; $tls::prev = -9560;
+//; $tls::pprev = 3140;
+//; $tls::next = -9556;
+//; $tls::pnext = 3144;
+//; $tls::sig = -9552;
+//; $tls::psig = 3148;
+//; $tls::incyg = -9548;
+//; $tls::pincyg = 3152;
+//; $tls::spinning = -9544;
+//; $tls::pspinning = 3156;
+//; $tls::stacklock = -9540;
+//; $tls::pstacklock = 3160;
+//; $tls::stackptr = -9536;
+//; $tls::pstackptr = 3164;
+//; $tls::stack = -9532;
+//; $tls::pstack = 3168;
+//; $tls::initialized = -8508;
+//; $tls::pinitialized = 4192;
//; __DATA__
#define tls_func (-12700)
@@ -103,27 +103,27 @@
#define tls_p__dontuse (420)
#define tls_locals (-11216)
#define tls_plocals (1484)
-#define tls__ctinfo (-9584)
-#define tls_p_ctinfo (3116)
-#define tls_andreas (-9580)
-#define tls_pandreas (3120)
-#define tls_wq (-9572)
-#define tls_pwq (3128)
-#define tls_prev (-9544)
-#define tls_pprev (3156)
-#define tls_next (-9540)
-#define tls_pnext (3160)
-#define tls_sig (-9536)
-#define tls_psig (3164)
-#define tls_incyg (-9532)
-#define tls_pincyg (3168)
-#define tls_spinning (-9528)
-#define tls_pspinning (3172)
-#define tls_stacklock (-9524)
-#define tls_pstacklock (3176)
-#define tls_stackptr (-9520)
-#define tls_pstackptr (3180)
-#define tls_stack (-9516)
-#define tls_pstack (3184)
-#define tls_initialized (-8492)
-#define tls_pinitialized (4208)
+#define tls__ctinfo (-9600)
+#define tls_p_ctinfo (3100)
+#define tls_andreas (-9596)
+#define tls_pandreas (3104)
+#define tls_wq (-9588)
+#define tls_pwq (3112)
+#define tls_prev (-9560)
+#define tls_pprev (3140)
+#define tls_next (-9556)
+#define tls_pnext (3144)
+#define tls_sig (-9552)
+#define tls_psig (3148)
+#define tls_incyg (-9548)
+#define tls_pincyg (3152)
+#define tls_spinning (-9544)
+#define tls_pspinning (3156)
+#define tls_stacklock (-9540)
+#define tls_pstacklock (3160)
+#define tls_stackptr (-9536)
+#define tls_pstackptr (3164)
+#define tls_stack (-9532)
+#define tls_pstack (3168)
+#define tls_initialized (-8508)
+#define tls_pinitialized (4192)
diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc
index cfc4b086a..9793c8cc7 100644
--- a/winsup/cygwin/tty.cc
+++ b/winsup/cygwin/tty.cc
@@ -28,6 +28,12 @@ details. */
extern fhandler_tty_master *tty_master;
extern "C" int
+posix_openpt (int oflags)
+{
+ return open ("/dev/ptmx", oflags);
+}
+
+extern "C" int
grantpt (int fd)
{
return 0;
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index d649733b0..b8519cfbc 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -377,7 +377,7 @@ cygheap_user::env_logsrv (const char *name, size_t namelen)
char logsrv[INTERNET_MAX_HOST_NAME_LENGTH + 3];
cfree_and_set (plogsrv, almost_null);
- if (get_logon_server (mydomain, logsrv, NULL))
+ if (get_logon_server (mydomain, logsrv, NULL, false))
plogsrv = cstrdup (logsrv);
return plogsrv;
}
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 727151406..ff7037a65 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -299,7 +299,13 @@ size_t getsystempagesize ();
/* mmap functions. */
void mmap_init ();
-int mmap_is_attached_or_noreserve_page (ULONG_PTR addr);
+enum mmap_region_status
+ {
+ MMAP_NONE,
+ MMAP_RAISE_SIGBUS,
+ MMAP_NORESERVE_COMMITED
+ };
+mmap_region_status mmap_is_attached_or_noreserve (void *addr, size_t len);
int winprio_to_nice (DWORD) __attribute__ ((regparm (1)));
DWORD nice_to_winprio (int &) __attribute__ ((regparm (1)));