/*
This file is part of GNUnet.
- (C) 2009-2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2009-2013 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
}
+#ifndef WINDOWS
+/**
+ * If services crash, they can leave a unix domain socket file on the
+ * disk. This needs to be manually removed, because otherwise both
+ * bind() and connect() for the respective address will fail. In this
+ * function, we test if such a left-over file exists, and if so,
+ * remove it (unless there is a listening service at the address).
+ *
+ * @param un unix domain socket address to check
+ */
+void
+GNUNET_NETWORK_unix_precheck (const struct sockaddr_un *un)
+{
+ int s;
+ int eno;
+ struct stat sbuf;
+ int ret;
+
+ s = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (-1 == s)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to open AF_UNIX socket");
+ return;
+ }
+ ret = connect (s,
+ (struct sockaddr *) un,
+ sizeof (struct sockaddr_un));
+ eno = errno;
+ GNUNET_break (0 == close (s));
+ if (0 == ret)
+ return; /* another process is listening, do not remove! */
+ if (ECONNREFUSED != eno)
+ return; /* some other error, likely "no such file or directory" -- all well */
+ /* should unlink, but sanity checks first */
+ if (0 != stat (un->sun_path,
+ &sbuf))
+ return; /* failed to 'stat', likely does not exist after all */
+ if (S_IFSOCK != (S_IFMT & sbuf.st_mode))
+ return; /* refuse to unlink anything except sockets */
+ /* finally, really unlink */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Removing left-over `%s' from previous exeuction\n",
+ un->sun_path);
+ if (0 != unlink (un->sun_path))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "unlink",
+ un->sun_path);
+}
+#endif
+
+
+
#ifndef FD_COPY
-#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
+#define FD_COPY(s, d) do { GNUNET_memcpy ((d), (s), sizeof (fd_set)); } while (0)
#endif
int af,
int type)
{
+ int eno;
+
h->af = af;
h->type = type;
if (h->fd == INVALID_SOCKET)
#ifdef MINGW
SetErrnoFromWinsockError (WSAGetLastError ());
#endif
+ eno = errno;
GNUNET_free (h);
+ errno = eno;
return GNUNET_SYSERR;
}
#ifndef MINGW
if (GNUNET_SYSERR == GNUNET_NETWORK_socket_set_blocking (h, GNUNET_NO))
{
+ eno = errno;
GNUNET_break (0);
GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (h));
+ errno = eno;
return GNUNET_SYSERR;
}
#ifdef DARWIN
socklen_t *address_len)
{
struct GNUNET_NETWORK_Handle *ret;
+ int eno;
ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
#if DEBUG_NETWORK
{
- struct sockaddr name;
+ struct sockaddr_storage name;
socklen_t namelen = sizeof (name);
+
int gsn = getsockname (desc->fd,
- &name,
+ (struct sockaddr *) &name,
&namelen);
- if (gsn == 0)
+ if (0 == gsn)
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Accepting connection on `%s'\n",
- GNUNET_a2s (&name, namelen));
+ GNUNET_a2s ((const struct sockaddr *) &name,
+ namelen));
}
#endif
ret->fd = accept (desc->fd,
address_len);
if (-1 == ret->fd)
{
+ eno = errno;
GNUNET_free (ret);
+ errno = eno;
return NULL;
}
if (GNUNET_OK !=
initialize_network_handle (ret,
(NULL != address) ? address->sa_family : desc->af,
SOCK_STREAM))
+ {
+
return NULL;
+ }
return ret;
}
#endif
#endif
#ifndef WINDOWS
+ if (AF_UNIX == address->sa_family)
+ GNUNET_NETWORK_unix_precheck ((const struct sockaddr_un *) address);
{
const int on = 1;
LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
"setsockopt");
}
-#endif
-#ifndef WINDOWS
{
/* set permissions of newly created non-abstract UNIX domain socket to
"user-only"; applications can choose to relax this later */
old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH);
#endif
- ret = bind (desc->fd, address, address_len);
+ ret = bind (desc->fd,
+ address,
+ address_len);
+
#ifndef WINDOWS
if (not_abstract)
(void) umask (old_mask);
if (SOCKET_ERROR == ret)
SetErrnoFromWinsockError (WSAGetLastError ());
#endif
- if (ret != 0)
+ if (0 != ret)
return GNUNET_SYSERR;
#ifndef MINGW
desc->addr = GNUNET_malloc (address_len);
- memcpy (desc->addr, address, address_len);
+ GNUNET_memcpy (desc->addr, address, address_len);
desc->addrlen = address_len;
#endif
return GNUNET_OK;
int protocol)
{
struct GNUNET_NETWORK_Handle *ret;
+ int fd;
- ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
- ret->fd = socket (domain, type, protocol);
- if (-1 == ret->fd)
- {
- GNUNET_free (ret);
+ fd = socket (domain, type, protocol);
+ if (-1 == fd)
return NULL;
- }
+ ret = GNUNET_new (struct GNUNET_NETWORK_Handle);
+ ret->fd = fd;
if (GNUNET_OK !=
initialize_network_handle (ret,
domain,
ret = shutdown (desc->fd, how);
#ifdef MINGW
- if (ret != 0)
+ if (0 != ret)
SetErrnoFromWinsockError (WSAGetLastError ());
#endif
- return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
+ return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR;
}
GNUNET_array_grow (to->handles,
to->handles_size,
from->handles_pos * 2);
- memcpy (to->handles,
+ GNUNET_memcpy (to->handles,
from->handles,
from->handles_pos * sizeof (struct GNUNET_NETWORK_Handle *));
to->handles_pos = from->handles_pos;
}
+/**
+ * Add a file handle to the fd set
+ * @param fds fd set
+ * @param h the file handle to add
+ */
+void
+GNUNET_NETWORK_fdset_handle_set_first (struct GNUNET_NETWORK_FDSet *fds,
+ const struct GNUNET_DISK_FileHandle *h)
+{
+#ifdef MINGW
+ if (fds->handles_pos == fds->handles_size)
+ GNUNET_array_grow (fds->handles,
+ fds->handles_size,
+ fds->handles_size * 2 + 2);
+ fds->handles[fds->handles_pos] = h;
+ if (fds->handles[0] != h)
+ {
+ const struct GNUNET_DISK_FileHandle *bak = fds->handles[0];
+ fds->handles[0] = h;
+ fds->handles[fds->handles_pos] = bak;
+ }
+ fds->handles_pos++;
+#else
+ GNUNET_NETWORK_fdset_handle_set (fds, h);
+#endif
+}
+
+
/**
* Check if a file handle is part of an fd set
*
* @return #GNUNET_YES if the pipe is ready for reading
*/
static int
-pipe_read_ready (struct GNUNET_DISK_FileHandle *fh)
+pipe_read_ready (const struct GNUNET_DISK_FileHandle *fh)
{
DWORD error;
BOOL bret;
* @return #GNUNET_YES if the pipe is having an IO exception.
*/
static int
-pipe_except_ready (struct GNUNET_DISK_FileHandle *fh)
+pipe_except_ready (const struct GNUNET_DISK_FileHandle *fh)
{
DWORD dwBytes;
* @param except GNUNET_NO if fds should be checked for readiness to read,
* GNUNET_YES if fds should be checked for exceptions
* (there is no way to check for write-readiness - pipes are always write-ready)
+ * @param set_for_sure a HANDLE that is known to be set already,
+ * because WaitForMultipleObjects() returned its index.
* @return number of ready handles
*/
static int
-check_handles_status (struct GNUNET_NETWORK_FDSet *fds, int except)
+check_handles_status (struct GNUNET_NETWORK_FDSet *fds,
+ int except,
+ HANDLE set_for_sure)
{
- struct GNUNET_DISK_FileHandle *fh;
+ const struct GNUNET_DISK_FileHandle *fh;
unsigned int roff;
unsigned int woff;
- int is_pipe;
for (woff = 0, roff = 0; roff < fds->handles_pos; roff++)
{
fh = fds->handles[roff];
- is_pipe = fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE;
- if ((except && is_pipe && pipe_except_ready (fh)) ||
- (!except && (!is_pipe || pipe_read_ready (fh))))
+ if (fh == set_for_sure)
+ {
fds->handles[woff++] = fh;
+ }
+ else if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
+ {
+ if ((except && pipe_except_ready (fh)) ||
+ (!except && pipe_read_ready (fh)))
+ fds->handles[woff++] = fh;
+ }
+ else if (fh->type == GNUNET_DISK_HANLDE_TYPE_FILE)
+ {
+ if (!except)
+ fds->handles[woff++] = fh;
+ }
+ else
+ {
+ if (WAIT_OBJECT_0 == WaitForSingleObject (fh->h, 0))
+ fds->handles[woff++] = fh;
+ }
}
fds->handles_pos = woff;
return woff;
struct GNUNET_NETWORK_FDSet *efds,
const struct GNUNET_TIME_Relative timeout)
{
- struct GNUNET_DISK_FileHandle *fh;
+ const struct GNUNET_DISK_FileHandle *fh;
int nfds;
int handles;
unsigned int i;
wfds ? awrite.fd_count : 0,
aexcept.fd_count,
GetLastError ());
- GNUNET_abort ();
+ GNUNET_assert (0);
}
/* Check aexcept, if something is in there and we copied that
/* Read Pipes */
if (rfds && (rfds->handles_pos > 0))
- retcode += check_handles_status (rfds, GNUNET_NO);
+ retcode += check_handles_status (rfds, GNUNET_NO, NULL);
/* wfds handles remain untouched, on W32
we pretend our pipes are "always" write-ready */
/* except pipes */
if (efds && (efds->handles_pos > 0))
- retcode += check_handles_status (efds, GNUNET_YES);
+ retcode += check_handles_status (efds, GNUNET_YES, NULL);
if (rfds)
{
for (i = 0; i <rfds->handles_pos; i++)
{
fh = rfds->handles[i];
+ if (fh->type == GNUNET_DISK_HANLDE_TYPE_EVENT)
+ {
+ handle_array[nhandles++] = fh->h;
+ continue;
+ }
if (fh->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
continue;
/* Read zero bytes to check the status of the pipe */
/* We may have some pipes ready for reading. */
if (returnedpos < read_pipes_off)
- retcode += check_handles_status (rfds, GNUNET_NO);
+ retcode += check_handles_status (rfds, GNUNET_NO, handle_array[returnedpos]);
else
rfds->handles_pos = 0;
}
if (efds)
{
- retcode += check_handles_status (rfds, GNUNET_YES);
+ retcode += check_handles_status (rfds,
+ GNUNET_YES,
+ returnedpos < nhandles ? handle_array[returnedpos] : NULL);
if (-1 != sp.status)
GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
}