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

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConrad Scott <conrad.scott@dsl.pipex.com>2002-07-27 21:00:16 +0400
committerConrad Scott <conrad.scott@dsl.pipex.com>2002-07-27 21:00:16 +0400
commit23c9d3c7fef23c453edcc163dc0ceae1c5e1c377 (patch)
tree76c6ab841700acabfa12b9b25c471bfde345fa26
parent2ce7b3c000d4927f48b545a7927e67d7d1c03607 (diff)
* include/cygwin/cygserver_transport.h
(transport_layer_base::listen): Change return type. (transport_layer_base::connect): Ditto. * include/cygwin/cygserver_transport_pipes.h (transport_layer_pipes::listen): Change return type. (transport_layer_pipes::connect): Ditto. (transport_layer_pipes::_sec_none_nih): Remove unused field. (transport_layer_pipes::_is_listening_endpoint): New field. * cygserver_transport_pipes.cc: Synchronize with sockets code. (transport_layer_pipes::transport_layer_pipes): Initialise new field. Separate out asserts. (transport_layer_pipes::listen): Change return type. Add asserts. (transport_layer_pipes::accept): Add asserts. (transport_layer_pipes::read): Change conditional to an assert. Add assert. (transport_layer_pipes::write): Ditto. (transport_layer_pipes::connect): Change return type. Change conditional to an assert. Add asserts. Rationalize error code slightly. (transport_layer_pipes::impersonate_client): Add asserts. * include/cygwin/cygserver_transport_sockets.h (transport_layer_sockets::listen): Change return type. (transport_layer_sockets::connect): Ditto. (transport_layer_sockets::_addr): Change type of field. (transport_layer_sockets::_addr_len): Ditto. (transport_layer_sockets::_is_accepted_endpoint): New field. (transport_layer_sockets::_is_listening_endpoint): Ditto. * cygserver_transport_sockets.cc (MAX_CONNECT_RETRY): New constant. (transport_layer_sockets::transport_layer_sockets): Initialise new fields. Only initialise the socket address where necessary. (transport_layer_sockets::listen): Change return type. Rewrite. (transport_layer_sockets::accept): Add asserts. Add tracing statements. Use a local variable to hold the accepted address. (transport_layer_sockets::close): Add tracing statements. Unlink the UNIX domain socket file as appropriate. Close the socket cleanly. (transport_layer_sockets::read): Rewrite method. (transport_layer_sockets::write): Ditto. (transport_layer_sockets::connect): Change return type. Rewrite. * cygserver.cc (server_submission_loop::request_loop): Run the listening thread at high priority with special handling for shutdown. (main): Print the request error code rather than errno in shutdown request code. Install signal handlers with sigaction(2) to avoid setting SA_RESTART. Check value of the listen method call, now it has one. * cygserver_client.cc (client_request::make_request): Check new return value on connect method call.
-rw-r--r--winsup/cygwin/ChangeLog54
-rwxr-xr-xwinsup/cygwin/cygserver.cc65
-rwxr-xr-xwinsup/cygwin/cygserver_client.cc2
-rwxr-xr-xwinsup/cygwin/cygserver_transport_pipes.cc68
-rwxr-xr-xwinsup/cygwin/cygserver_transport_sockets.cc324
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport.h6
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport_pipes.h8
-rwxr-xr-xwinsup/cygwin/include/cygwin/cygserver_transport_sockets.h15
8 files changed, 437 insertions, 105 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 88afcf968..13b63e0bf 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,57 @@
2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+ * include/cygwin/cygserver_transport.h
+ (transport_layer_base::listen): Change return type.
+ (transport_layer_base::connect): Ditto.
+ * include/cygwin/cygserver_transport_pipes.h
+ (transport_layer_pipes::listen): Change return type.
+ (transport_layer_pipes::connect): Ditto.
+ (transport_layer_pipes::_sec_none_nih): Remove unused field.
+ (transport_layer_pipes::_is_listening_endpoint): New field.
+ * cygserver_transport_pipes.cc: Synchronize with sockets code.
+ (transport_layer_pipes::transport_layer_pipes): Initialise new
+ field. Separate out asserts.
+ (transport_layer_pipes::listen): Change return type. Add asserts.
+ (transport_layer_pipes::accept): Add asserts.
+ (transport_layer_pipes::read): Change conditional to an assert.
+ Add assert.
+ (transport_layer_pipes::write): Ditto.
+ (transport_layer_pipes::connect): Change return type. Change
+ conditional to an assert. Add asserts. Rationalize error code
+ slightly.
+ (transport_layer_pipes::impersonate_client): Add asserts.
+ * include/cygwin/cygserver_transport_sockets.h
+ (transport_layer_sockets::listen): Change return type.
+ (transport_layer_sockets::connect): Ditto.
+ (transport_layer_sockets::_addr): Change type of field.
+ (transport_layer_sockets::_addr_len): Ditto.
+ (transport_layer_sockets::_is_accepted_endpoint): New field.
+ (transport_layer_sockets::_is_listening_endpoint): Ditto.
+ * cygserver_transport_sockets.cc
+ (MAX_CONNECT_RETRY): New constant.
+ (transport_layer_sockets::transport_layer_sockets): Initialise new
+ fields. Only initialise the socket address where necessary.
+ (transport_layer_sockets::listen): Change return type. Rewrite.
+ (transport_layer_sockets::accept): Add asserts. Add tracing
+ statements. Use a local variable to hold the accepted address.
+ (transport_layer_sockets::close): Add tracing statements. Unlink
+ the UNIX domain socket file as appropriate. Close the socket
+ cleanly.
+ (transport_layer_sockets::read): Rewrite method.
+ (transport_layer_sockets::write): Ditto.
+ (transport_layer_sockets::connect): Change return type. Rewrite.
+ * cygserver.cc (server_submission_loop::request_loop): Run the
+ listening thread at high priority with special handling for
+ shutdown.
+ (main): Print the request error code rather than errno in shutdown
+ request code. Install signal handlers with sigaction(2) to avoid
+ setting SA_RESTART. Check value of the listen method call, now it
+ has one.
+ * cygserver_client.cc (client_request::make_request): Check new
+ return value on connect method call.
+
+2002-07-27 Conrad Scott <conrad.scott@dsl.pipex.com>
+
* include/cygwin/cygserver_transport_pipes.h
(cygserver_transport_pipes::_sd): Rename field.
(cygserver_transport_pipes::_sec_none_nih): Ditto.
@@ -412,7 +464,7 @@
the SHM_INFO command.
(server_shmmgr::shmget): Check `shmflg' against the mode of
existing segments as per Stevens 1990, p. 123.
- (server_shmmgr::server_shmmgr): Initialize the new `_shm_tot'
+ (server_shmmgr::server_shmmgr): Initialise the new `_shm_tot'
field.
(server_shmmgr::new_segment): Set ENOMEM if CreateFileMapping
fails. Pass `size' to new_segment.
diff --git a/winsup/cygwin/cygserver.cc b/winsup/cygwin/cygserver.cc
index 072c99cfd..12161072b 100755
--- a/winsup/cygwin/cygserver.cc
+++ b/winsup/cygwin/cygserver.cc
@@ -445,6 +445,20 @@ private:
void
server_submission_loop::request_loop ()
{
+ /* I'd like the accepting thread's priority to be above any "normal"
+ * thread in the system to avoid overflowing the listen queue (for
+ * sockets; similar issues exist for named pipes); but, for example,
+ * a normal priority thread in a foregrounded process is boosted to
+ * THREAD_PRIORITY_HIGHEST (AFAICT). Thus try to set the current
+ * thread's priority to a level one above that. This fails on
+ * win9x/ME so assume any failure in that call is due to that and
+ * simply call again at one priority level lower.
+ */
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
+ debug_printf ("failed to raise accept thread priority, error = %lu",
+ GetLastError ());
+
while (_running)
{
bool recoverable = false;
@@ -454,6 +468,24 @@ server_submission_loop::request_loop ()
system_printf ("fatal error on IPC transport: closing down");
return;
}
+ // EINTR probably implies a shutdown request; so back off for a
+ // moment to let the main thread take control, otherwise the
+ // server spins here receiving EINTR repeatedly since the signal
+ // handler in the main thread doesn't get a chance to be called.
+ if (!conn && errno == EINTR)
+ {
+ if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
+ debug_printf ("failed to reset thread priority, error = %lu",
+ GetLastError ());
+
+ Sleep (0);
+ if (!SetThreadPriority (GetCurrentThread (),
+ THREAD_PRIORITY_HIGHEST + 1))
+ if (!SetThreadPriority (GetCurrentThread (),
+ THREAD_PRIORITY_HIGHEST))
+ debug_printf ("failed to raise thread priority, error = %lu",
+ GetLastError ());
+ }
if (conn)
_queue->add (safe_new (server_request, conn, _cache));
}
@@ -650,7 +682,7 @@ main (const int argc, char *argv[])
if (req.make_request () == -1 || req.error_code ())
{
fprintf (stderr, "%s: shutdown request failed: %s\n",
- pgm, strerror (errno));
+ pgm, strerror (req.error_code ()));
exit (1);
}
@@ -659,12 +691,26 @@ main (const int argc, char *argv[])
return 0;
}
- if (signal (SIGINT, handle_signal) == SIG_ERR)
- {
- system_printf ("could not install signal handler (%d)- aborting startup",
- errno);
- exit (1);
- }
+#define SIGHANDLE(SIG) \
+ do \
+ { \
+ struct sigaction act; \
+ \
+ act.sa_handler = &handle_signal; \
+ act.sa_mask = 0; \
+ act.sa_flags = 0; \
+ \
+ if (sigaction (SIG, &act, NULL) == -1) \
+ { \
+ system_printf ("failed to install handler for " #SIG ": %s", \
+ strerror (errno)); \
+ exit (1); \
+ } \
+ } while (false)
+
+ SIGHANDLE (SIGHUP);
+ SIGHANDLE (SIGINT);
+ SIGHANDLE (SIGTERM);
print_version (pgm);
setbuf (stdout, NULL);
@@ -686,7 +732,10 @@ main (const int argc, char *argv[])
request_queue.add_submission_loop (&submission_loop);
printf (".");
- transport->listen ();
+ if (transport->listen () == -1)
+ {
+ exit (1);
+ }
printf (".");
cache.start ();
diff --git a/winsup/cygwin/cygserver_client.cc b/winsup/cygwin/cygserver_client.cc
index 9ae7f6ba4..859fbcb97 100755
--- a/winsup/cygwin/cygserver_client.cc
+++ b/winsup/cygwin/cygserver_client.cc
@@ -350,7 +350,7 @@ client_request::make_request ()
assert (transport);
- if (!transport->connect ())
+ if (transport->connect () == -1)
{
if (errno)
error_code (errno);
diff --git a/winsup/cygwin/cygserver_transport_pipes.cc b/winsup/cygwin/cygserver_transport_pipes.cc
index 7668d6cc9..6e6f0a666 100755
--- a/winsup/cygwin/cygserver_transport_pipes.cc
+++ b/winsup/cygwin/cygserver_transport_pipes.cc
@@ -59,9 +59,11 @@ initialise_pipe_instance_lock ()
transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
: _pipe_name (""),
_hPipe (hPipe),
- _is_accepted_endpoint (true)
+ _is_accepted_endpoint (true),
+ _is_listening_endpoint (false)
{
- assert (_hPipe && _hPipe != INVALID_HANDLE_VALUE);
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
init_security ();
}
@@ -71,7 +73,8 @@ transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
transport_layer_pipes::transport_layer_pipes ()
: _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
_hPipe (NULL),
- _is_accepted_endpoint (false)
+ _is_accepted_endpoint (false),
+ _is_listening_endpoint (false)
{
init_security ();
}
@@ -86,10 +89,9 @@ transport_layer_pipes::init_security ()
InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE);
- _sec_none_nih.nLength = _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
- _sec_none_nih.bInheritHandle = _sec_all_nih.bInheritHandle = FALSE;
- _sec_none_nih.lpSecurityDescriptor = NULL;
+ _sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
_sec_all_nih.lpSecurityDescriptor = &_sd;
+ _sec_all_nih.bInheritHandle = FALSE;
}
transport_layer_pipes::~transport_layer_pipes ()
@@ -99,19 +101,22 @@ transport_layer_pipes::~transport_layer_pipes ()
#ifndef __INSIDE_CYGWIN__
-void
+int
transport_layer_pipes::listen ()
{
- assert (!_is_accepted_endpoint);
assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
/* no-op */
+ return 0;
}
class transport_layer_pipes *
transport_layer_pipes::accept (bool *const recoverable)
{
- assert (!_is_accepted_endpoint);
assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (_is_listening_endpoint);
pthread_once (&pipe_instance_lock_once, &initialise_pipe_instance_lock);
@@ -145,8 +150,8 @@ transport_layer_pipes::accept (bool *const recoverable)
if (duplicate)
{
*recoverable = false;
- system_printf ("failure creating named pipe: "
- "is there another instance of the server running?");
+ system_printf ("failed to create named pipe: "
+ "is the daemon already running?");
return NULL;
}
@@ -213,13 +218,9 @@ transport_layer_pipes::read (void *const buf, const size_t len)
{
// verbose: debug_printf ("reading from pipe %p", _hPipe);
- if (!_hPipe)
- {
- set_errno (EBADF);
- return -1;
- }
-
+ assert (_hPipe);
assert (_hPipe != INVALID_HANDLE_VALUE);
+ assert (!_is_listening_endpoint);
DWORD count;
if (!ReadFile (_hPipe, buf, len, &count, NULL))
@@ -237,13 +238,9 @@ transport_layer_pipes::write (void *const buf, const size_t len)
{
// verbose: debug_printf ("writing to pipe %p", _hPipe);
- if (!_hPipe)
- {
- set_errno (EBADF);
- return -1;
- }
-
+ assert (_hPipe);
assert (_hPipe != INVALID_HANDLE_VALUE);
+ assert (!_is_listening_endpoint);
DWORD count;
if (!WriteFile (_hPipe, buf, len, &count, NULL))
@@ -265,16 +262,12 @@ transport_layer_pipes::write (void *const buf, const size_t len)
* congestion and overloading problems.
*/
-bool
+int
transport_layer_pipes::connect ()
{
- if (_hPipe)
- {
- assert (_hPipe != INVALID_HANDLE_VALUE);
-
- debug_printf ("Already have a pipe in this %p",this);
- return false;
- }
+ assert (!_hPipe);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
static bool assume_cygserver = false;
@@ -298,18 +291,17 @@ transport_layer_pipes::connect ()
ProtectHandle (_hPipe);
#endif
assume_cygserver = true;
- return true;
+ return 0;
}
+ _hPipe = NULL;
+
if (!assume_cygserver && GetLastError () != ERROR_PIPE_BUSY)
{
debug_printf ("Error opening the pipe (%lu)", GetLastError ());
- _hPipe = NULL;
- return false;
+ return -1;
}
- _hPipe = NULL;
-
/* Note: `If no instances of the specified named pipe exist, the
* WaitNamedPipe function returns immediately, regardless of the
* time-out value.' Thus the explicit Sleep if the call fails
@@ -332,7 +324,7 @@ transport_layer_pipes::connect ()
assume_cygserver = false;
- return false;
+ return -1;
}
#ifndef __INSIDE_CYGWIN__
@@ -340,6 +332,8 @@ transport_layer_pipes::connect ()
void
transport_layer_pipes::impersonate_client ()
{
+ assert (_hPipe);
+ assert (_hPipe != INVALID_HANDLE_VALUE);
assert (_is_accepted_endpoint);
// verbose: debug_printf ("impersonating pipe %p", _hPipe);
diff --git a/winsup/cygwin/cygserver_transport_sockets.cc b/winsup/cygwin/cygserver_transport_sockets.cc
index a2f8131db..17f0f9bce 100755
--- a/winsup/cygwin/cygserver_transport_sockets.cc
+++ b/winsup/cygwin/cygserver_transport_sockets.cc
@@ -17,12 +17,15 @@ details. */
#include "winsup.h"
#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
+
#include "cygwin/cygserver_transport.h"
#include "cygwin/cygserver_transport_sockets.h"
@@ -33,6 +36,7 @@ extern "C" int cygwin_accept (int fd, struct sockaddr *, int *len);
extern "C" int cygwin_bind (int fd, const struct sockaddr *, int len);
extern "C" int cygwin_connect (int fd, const struct sockaddr *, int len);
extern "C" int cygwin_listen (int fd, int backlog);
+extern "C" int cygwin_shutdown (int fd, int how);
extern "C" int cygwin_socket (int af, int type, int protocol);
#else /* __OUTSIDE_CYGWIN__ */
@@ -41,26 +45,38 @@ extern "C" int cygwin_socket (int af, int type, int protocol);
#define cygwin_bind(A,B,C) ::bind (A,B,C)
#define cygwin_connect(A,B,C) ::connect (A,B,C)
#define cygwin_listen(A,B) ::listen (A,B)
+#define cygwin_shutdown(A,B) ::shutdown (A,B)
#define cygwin_socket(A,B,C) ::socket (A,B,C)
#endif /* __OUTSIDE_CYGWIN__ */
-transport_layer_sockets::transport_layer_sockets (int newfd)
- : _fd (newfd)
+enum
+ {
+ MAX_CONNECT_RETRY = 64
+ };
+
+transport_layer_sockets::transport_layer_sockets (const int fd)
+ : _fd (fd),
+ _addr_len (0),
+ _is_accepted_endpoint (true),
+ _is_listening_endpoint (false)
{
- /* This may not be needed in this constructor - it's only used
- * when creating a connection via bind or connect
- */
- _addr.sa_family = AF_UNIX;
- strcpy (_addr.sa_data, "/tmp/cygdaemo");
- _addr_len = strlen (_addr.sa_data) + sizeof (_addr.sa_family);
-};
-
-transport_layer_sockets::transport_layer_sockets (): _fd (-1)
+ assert (_fd != -1);
+
+ memset (&_addr, '\0', sizeof (_addr));
+}
+
+transport_layer_sockets::transport_layer_sockets ()
+ : _fd (-1),
+ _addr_len (0),
+ _is_accepted_endpoint (false),
+ _is_listening_endpoint (false)
{
- _addr.sa_family = AF_UNIX;
- strcpy (_addr.sa_data, "/tmp/cygdaemo");
- _addr_len = strlen (_addr.sa_data) + sizeof (_addr.sa_family);
+ memset (&_addr, '\0', sizeof (_addr));
+
+ _addr.sun_family = AF_UNIX;
+ strcpy (_addr.sun_path, "/tmp/cygdaemo"); // FIXME: $TMP?
+ _addr_len = SUN_LEN (&_addr);
}
transport_layer_sockets::~transport_layer_sockets ()
@@ -70,28 +86,119 @@ transport_layer_sockets::~transport_layer_sockets ()
#ifndef __INSIDE_CYGWIN__
-void
+int
transport_layer_sockets::listen ()
{
- /* we want a thread pool based approach. */
- if ((_fd = cygwin_socket (AF_UNIX, SOCK_STREAM,0)) < 0)
- system_printf ("Socket not created error %d", errno);
- if (cygwin_bind (_fd, &_addr, _addr_len))
- system_printf ("Bind doesn't like you. Tsk Tsk. Bind said %d", errno);
- if (cygwin_listen (_fd, 5) < 0)
- system_printf ("And the OS just isn't listening, all it says is %d",
- errno);
+ assert (_fd == -1);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ debug_printf ("listen () [this = %p]", this);
+
+ struct stat sbuf;
+
+ if (stat (_addr.sun_path, &sbuf) == -1)
+ {
+ if (errno != ENOENT)
+ {
+ system_printf ("cannot access socket file `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+ }
+ else if (S_ISSOCK (sbuf.st_mode))
+ {
+ // The socket already exists: is a duplicate cygserver running?
+
+ const int newfd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (newfd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_connect (newfd, (struct sockaddr *) &_addr, _addr_len) == 0)
+ {
+ system_printf ("the daemon is already running");
+ (void) cygwin_shutdown (newfd, SHUT_WR);
+ char buf[BUFSIZ];
+ while (::read (newfd, buf, sizeof (buf)) > 0)
+ {}
+ (void) ::close (newfd);
+ return -1;
+ }
+
+ if (unlink (_addr.sun_path) == -1)
+ {
+ system_printf ("failed to remove `%s': %s",
+ _addr.sun_path, strerror (errno));
+ (void) ::close (newfd);
+ return -1;
+ }
+ }
+ else
+ {
+ system_printf ("cannot create socket `%s': File already exists",
+ _addr.sun_path);
+ return -1;
+ }
+
+ _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (_fd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_bind (_fd, (struct sockaddr *) &_addr, _addr_len) == -1)
+ {
+ const int saved_errno = errno;
+ close ();
+ errno = saved_errno;
+ system_printf ("failed to bind UNIX domain socket `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+
+ _is_listening_endpoint = true; // i.e. this really means "have bound".
+
+ if (cygwin_listen (_fd, SOMAXCONN) == -1)
+ {
+ const int saved_errno = errno;
+ close ();
+ errno = saved_errno;
+ system_printf ("failed to listen on UNIX domain socket `%s': %s",
+ _addr.sun_path, strerror (errno));
+ return -1;
+ }
+
+ debug_printf ("0 = listen () [this = %p, fd = %d]", this, _fd);
+
+ return 0;
}
class transport_layer_sockets *
transport_layer_sockets::accept (bool *const recoverable)
{
- /* FIXME: check we have listened */
- const int accept_fd = cygwin_accept (_fd, &_addr, &_addr_len);
+ assert (_fd != -1);
+ assert (!_is_accepted_endpoint);
+ assert (_is_listening_endpoint);
+
+ debug_printf ("accept () [this = %p, fd = %d]", this, _fd);
+
+ struct sockaddr_un client_addr;
+ socklen_t client_addr_len = sizeof (client_addr);
+
+ const int accept_fd =
+ cygwin_accept (_fd, (struct sockaddr *) &client_addr, &client_addr_len);
if (accept_fd == -1)
{
- system_printf ("Nup, couldn't accept. %d", errno);
+ system_printf ("failed to accept connection: %s", strerror (errno));
switch (errno)
{
case ECONNABORTED:
@@ -110,6 +217,8 @@ transport_layer_sockets::accept (bool *const recoverable)
return NULL;
}
+ debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd);
+
return safe_new (transport_layer_sockets, accept_fd);
}
@@ -118,40 +227,161 @@ transport_layer_sockets::accept (bool *const recoverable)
void
transport_layer_sockets::close ()
{
- /* FIXME - are we open? */
+ debug_printf ("close () [this = %p, fd = %d]", this, _fd);
+
+ if (_is_listening_endpoint)
+ (void) unlink (_addr.sun_path);
+
if (_fd != -1)
{
- ::close (_fd);
+ (void) cygwin_shutdown (_fd, SHUT_WR);
+ if (!_is_listening_endpoint)
+ {
+ char buf[BUFSIZ];
+ while (::read (_fd, buf, sizeof (buf)) > 0)
+ {}
+ }
+ (void) ::close (_fd);
_fd = -1;
}
+
+ _is_listening_endpoint = false;
}
ssize_t
-transport_layer_sockets::read (void *buf, size_t len)
+transport_layer_sockets::read (void *const buf, const size_t buf_len)
{
- /* FIXME: are we open? */
- return ::read (_fd, buf, len);
+ assert (_fd != -1);
+ assert (!_is_listening_endpoint);
+
+ assert (buf);
+ assert (buf_len > 0);
+
+ // verbose: debug_printf ("read (buf = %p, len = %u) [this = %p, fd = %d]",
+ // buf, buf_len, this, _fd);
+
+ char *read_buf = static_cast<char *>(buf);
+ size_t read_buf_len = buf_len;
+ ssize_t res = 0;
+
+ while (read_buf_len != 0
+ && (res = ::read (_fd, read_buf, read_buf_len)) > 0)
+ {
+ read_buf += res;
+ read_buf_len -= res;
+
+ assert (read_buf_len >= 0);
+ }
+
+ if (res != -1)
+ {
+ if (res == 0)
+ errno = EIO; // FIXME?
+
+ res = buf_len - read_buf_len;
+ }
+
+ if (res != static_cast<ssize_t>(buf_len))
+ debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]: %s",
+ res, buf, buf_len, this, _fd,
+ (res == -1 ? strerror (errno) : "EOF"));
+ else
+ {
+ // verbose: debug_printf ("%d = read (buf = %p, len = %u) [this = %p, fd = %d]",
+ // res, buf, buf_len, this, _fd);
+ }
+
+ return res;
}
ssize_t
-transport_layer_sockets::write (void *buf, size_t len)
+transport_layer_sockets::write (void *const buf, const size_t buf_len)
{
- /* FIXME: are we open? */
- return ::write (_fd, buf, len);
+ assert (_fd != -1);
+ assert (!_is_listening_endpoint);
+
+ assert (buf);
+ assert (buf_len > 0);
+
+ // verbose: debug_printf ("write (buf = %p, len = %u) [this = %p, fd = %d]",
+ // buf, buf_len, this, _fd);
+
+ char *write_buf = static_cast<char *>(buf);
+ size_t write_buf_len = buf_len;
+ ssize_t res = 0;
+
+ while (write_buf_len != 0
+ && (res = ::write (_fd, write_buf, write_buf_len)) > 0)
+ {
+ write_buf += res;
+ write_buf_len -= res;
+
+ assert (write_buf_len >= 0);
+ }
+
+ if (res != -1)
+ {
+ if (res == 0)
+ errno = EIO; // FIXME?
+
+ res = buf_len - write_buf_len;
+ }
+
+ if (res != static_cast<ssize_t>(buf_len))
+ debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]: %s",
+ res, buf, buf_len, this, _fd,
+ (res == -1 ? strerror (errno) : "EOF"));
+ else
+ {
+ // verbose: debug_printf ("%d = write (buf = %p, len = %u) [this = %p, fd = %d]",
+ // res, buf, buf_len, this, _fd);
+ }
+
+ return res;
}
-bool
+int
transport_layer_sockets::connect ()
{
- /* are we already connected? */
- if (_fd != -1)
- return false;
- _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
- if (cygwin_connect (_fd, &_addr, _addr_len) < 0)
+ assert (_fd == -1);
+ assert (!_is_accepted_endpoint);
+ assert (!_is_listening_endpoint);
+
+ static bool assume_cygserver = false;
+
+ debug_printf ("connect () [this = %p]", this);
+
+ for (int retries = 0; retries != MAX_CONNECT_RETRY; retries++)
{
- debug_printf ("client connect failure %d", errno);
- ::close (_fd);
- return false;
+ _fd = cygwin_socket (AF_UNIX, SOCK_STREAM, 0);
+
+ if (_fd == -1)
+ {
+ system_printf ("failed to create UNIX domain socket: %s",
+ strerror (errno));
+ return -1;
+ }
+
+ if (cygwin_connect (_fd, (struct sockaddr *) &_addr, _addr_len) == 0)
+ {
+ assume_cygserver = true;
+ debug_printf ("0 = connect () [this = %p, fd = %d]", this, _fd);
+ return 0;
+ }
+
+ if (!assume_cygserver || errno != ECONNREFUSED)
+ {
+ debug_printf ("failed to connect to server: %s", strerror (errno));
+ (void) ::close (_fd);
+ _fd = -1;
+ return -1;
+ }
+
+ (void) ::close (_fd);
+ _fd = -1;
+ Sleep (0); // Give the server a chance.
}
- return true;
+
+ debug_printf ("failed to connect to server: %s", strerror (errno));
+ return -1;
}
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport.h b/winsup/cygwin/include/cygwin/cygserver_transport.h
index c18486c1c..915f35e66 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport.h
@@ -13,20 +13,20 @@ details. */
#ifndef _CYGSERVER_TRANSPORT_
#define _CYGSERVER_TRANSPORT_
-class transport_layer_base *create_server_transport();
+class transport_layer_base *create_server_transport ();
class transport_layer_base
{
public:
#ifndef __INSIDE_CYGWIN__
- virtual void listen () = 0;
+ virtual int listen () = 0;
virtual class transport_layer_base *accept (bool *recoverable) = 0;
#endif
virtual void close () = 0;
virtual ssize_t read (void *buf, size_t len) = 0;
virtual ssize_t write (void *buf, size_t len) = 0;
- virtual bool connect () = 0;
+ virtual int connect () = 0;
#ifndef __INSIDE_CYGWIN__
virtual void impersonate_client ();
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h b/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
index fe571a770..4bea2eb13 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport_pipes.h
@@ -18,14 +18,14 @@ class transport_layer_pipes : public transport_layer_base
{
public:
#ifndef __INSIDE_CYGWIN__
- virtual void listen ();
+ virtual int listen ();
virtual class transport_layer_pipes *accept (bool *recoverable);
#endif
virtual void close ();
virtual ssize_t read (void *buf, size_t len);
virtual ssize_t write (void *buf, size_t len);
- virtual bool connect ();
+ virtual int connect ();
#ifndef __INSIDE_CYGWIN__
virtual void impersonate_client ();
@@ -38,12 +38,14 @@ public:
private:
/* for pipe based communications */
void init_security ();
+
//FIXME: allow inited, sd, all_nih_.. to be static members
SECURITY_DESCRIPTOR _sd;
- SECURITY_ATTRIBUTES _sec_none_nih, _sec_all_nih;
+ SECURITY_ATTRIBUTES _sec_all_nih;
const char *const _pipe_name;
HANDLE _hPipe;
const bool _is_accepted_endpoint;
+ bool _is_listening_endpoint;
transport_layer_pipes (HANDLE hPipe);
};
diff --git a/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h b/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
index 97d3baa23..d960f9c2c 100755
--- a/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
+++ b/winsup/cygwin/include/cygwin/cygserver_transport_sockets.h
@@ -13,18 +13,21 @@ details. */
#ifndef _CYGSERVER_TRANSPORT_SOCKETS_
#define _CYGSERVER_TRANSPORT_SOCKETS_
+#include <sys/socket.h>
+#include <sys/un.h>
+
class transport_layer_sockets : public transport_layer_base
{
public:
#ifndef __INSIDE_CYGWIN__
- virtual void listen ();
+ virtual int listen ();
virtual class transport_layer_sockets *accept (bool *recoverable);
#endif
virtual void close ();
virtual ssize_t read (void *buf, size_t len);
virtual ssize_t write (void *buf, size_t len);
- virtual bool connect ();
+ virtual int connect ();
transport_layer_sockets ();
virtual ~transport_layer_sockets ();
@@ -32,10 +35,12 @@ public:
private:
/* for socket based communications */
int _fd;
- struct sockaddr _addr;
- int _addr_len;
+ struct sockaddr_un _addr;
+ socklen_t _addr_len;
+ const bool _is_accepted_endpoint;
+ bool _is_listening_endpoint;
- transport_layer_sockets (int newfd);
+ transport_layer_sockets (int fd);
};
#endif /* _CYGSERVER_TRANSPORT_SOCKETS_ */