282113ba89
throughout. * Makefile.in: Accomodate all new files and name changes. Add a *.d dependency. (sbindir): Add. (etcdir): Drop in favor of more appropriate sysconfdir definition. (sysconfdir): Add. (CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition. (.SUFFIXES): Add. (install): Add action items. (libclean): New target. (fullclean): Ditto. * bsd_helper.cc: New file. * bsd_helper.h: Ditto. * bsd_log.cc: Ditto. * bsd_log.h: Ditto. * bsd_mutex.cc: Ditto. * bsd_mutex.h: Ditto. * client.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. (client_request::handle_request): Add Message Queue and Semaphore handling. * cygserver.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. Use new debug/log/panic logging functions. (DEF_CONFIG_FILE): New definition for configuration file. Use throughout. (getfunc): Remove. (__cygserver__printf): Remove. (client_request_attach_tty::serve): Return error if impersonation fails. (print_usage): Pump up help message. (print_version): Add output of default configuration file. (main): Accommodate new options. Allow overwrite of threading options from config file. Call several new initialization functions. Drop printing dots. Don't define SIGHANDLE inline. * cygserver.conf: New file. * cygserver_process.h: Rename to process.h. * cygserver_transport.h: Rename to transport.h. * cygserver_transport_pipes.h: Rename to transport_pipes.h. * cygserver_transport_sockets.h: Rename to transport_sockets.h. * msg.cc: Rewrite. * sem.cc: Rewrite. * shm.cc: Rewrite. * sysv_msg.cc: New file, derived from FreeBSD version 1.52. * sysv_sem.cc: New file, derived from FreeBSD version 1.66. * sysv_shm.cc: New file, derived from FreeBSD version 1.89. * threaded_queue.cc: Rearrange to build as less as possible if __INSIDE_CYGWIN__. * transport.cc (transport_layer_base::impersonate_client): Define bool. (transport_layer_base::revert_to_self): Ditto. * transport.h (transport_layer_base::impersonate_client): Declare bool. (transport_layer_base::revert_to_self): Ditto. * transport_pipes.cc (transport_layer_pipes::transport_layer_pipes): Don't call init_security. (init_security): Remove. (transport_layer_pipes::accept): Use global sec_all_nih. (transport_layer_pipes::connect): Ditto. (transport_layer_pipes::impersonate_client): Define bool. (transport_layer_pipes::revert_to_self): Ditt. * transport_pipes.h (transport_layer_pipes::impersonate_client): Declare bool. (transport_layer_pipes::revert_to_self): Ditto. * woutsup.h: Include bsd compatibility headers. (SIGHANDLE): Add definition. (__cygserver__printf): Remove definition. (__noop_printf): Ditto. (debug_printf): Define using debug. (syscall_printf): Define using log. (system_printf): Ditto. Drop all other _printf definitions.
388 lines
8.7 KiB
C++
388 lines
8.7 KiB
C++
/* transport_sockets.cc
|
|
|
|
Copyright 2001, 2002 Red Hat Inc.
|
|
|
|
Written by Robert Collins <rbtcollins@hotmail.com>
|
|
|
|
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. */
|
|
|
|
/* to allow this to link into cygwin and the .dll, a little magic is needed. */
|
|
#ifdef __OUTSIDE_CYGWIN__
|
|
#include "woutsup.h"
|
|
#else
|
|
#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 "transport.h"
|
|
#include "transport_sockets.h"
|
|
|
|
/* to allow this to link into cygwin and the .dll, a little magic is needed. */
|
|
#ifndef __OUTSIDE_CYGWIN__
|
|
|
|
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__ */
|
|
|
|
#define cygwin_accept(A,B,C) ::accept (A,B,C)
|
|
#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__ */
|
|
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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 ()
|
|
{
|
|
close ();
|
|
}
|
|
|
|
#ifndef __INSIDE_CYGWIN__
|
|
|
|
int
|
|
transport_layer_sockets::listen ()
|
|
{
|
|
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)
|
|
{
|
|
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 ("failed to accept connection: %s", strerror (errno));
|
|
switch (errno)
|
|
{
|
|
case ECONNABORTED:
|
|
case EINTR:
|
|
case EMFILE:
|
|
case ENFILE:
|
|
case ENOBUFS:
|
|
case ENOMEM:
|
|
*recoverable = true;
|
|
break;
|
|
|
|
default:
|
|
*recoverable = false;
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd);
|
|
|
|
return new transport_layer_sockets (accept_fd);
|
|
}
|
|
|
|
#endif /* !__INSIDE_CYGWIN__ */
|
|
|
|
void
|
|
transport_layer_sockets::close ()
|
|
{
|
|
debug_printf ("close () [this = %p, fd = %d]", this, _fd);
|
|
|
|
if (_is_listening_endpoint)
|
|
(void) unlink (_addr.sun_path);
|
|
|
|
if (_fd != -1)
|
|
{
|
|
(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 *const buf, const size_t 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 *const buf, const size_t 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;
|
|
}
|
|
|
|
int
|
|
transport_layer_sockets::connect ()
|
|
{
|
|
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++)
|
|
{
|
|
_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.
|
|
}
|
|
|
|
debug_printf ("failed to connect to server: %s", strerror (errno));
|
|
return -1;
|
|
}
|