summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1135/pgm/net.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/openpgm-svn-r1135/pgm/net.c')
-rw-r--r--3rdparty/openpgm-svn-r1135/pgm/net.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1135/pgm/net.c b/3rdparty/openpgm-svn-r1135/pgm/net.c
new file mode 100644
index 0000000..eb5f403
--- /dev/null
+++ b/3rdparty/openpgm-svn-r1135/pgm/net.c
@@ -0,0 +1,181 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * network send wrapper.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#ifdef CONFIG_HAVE_POLL
+# include <poll.h>
+#endif
+#ifndef _WIN32
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+#endif
+#include <impl/i18n.h>
+#include <impl/framework.h>
+#include <impl/net.h>
+#include <impl/socket.h>
+
+
+#define NET_DEBUG
+
+
+#if !defined(ENETUNREACH) && defined(WSAENETUNREACH)
+# define ENETUNREACH WSAENETUNREACH
+#endif
+#if !defined(EHOSTUNREACH) && defined(WSAEHOSTUNREACH)
+# define EHOSTUNREACH WSAEHOSTUNREACH
+#endif
+#if !defined(ENOBUFS) && defined(WSAENOBUFS)
+# define ENOBUFS WSAENOBUFS
+#endif
+
+
+/* locked and rate regulated sendto
+ *
+ * on success, returns number of bytes sent. on error, -1 is returned, and
+ * errno set appropriately.
+ */
+
+ssize_t
+pgm_sendto_hops (
+ pgm_sock_t* sock,
+ bool use_rate_limit,
+ bool use_router_alert,
+ int hops, /* -1 == system default */
+ const void* restrict buf,
+ size_t len,
+ const struct sockaddr* restrict to,
+ socklen_t tolen
+ )
+{
+ pgm_assert( NULL != sock );
+ pgm_assert( NULL != buf );
+ pgm_assert( len > 0 );
+ pgm_assert( NULL != to );
+ pgm_assert( tolen > 0 );
+
+#ifdef NET_DEBUG
+ char saddr[INET_ADDRSTRLEN];
+ pgm_sockaddr_ntop (to, saddr, sizeof(saddr));
+ pgm_debug ("pgm_sendto (sock:%p use_rate_limit:%s use_router_alert:%s buf:%p len:%zu to:%s [toport:%d] tolen:%d)",
+ (const void*)sock,
+ use_rate_limit ? "TRUE" : "FALSE",
+ use_router_alert ? "TRUE" : "FALSE",
+ (const void*)buf,
+ len,
+ saddr,
+ ntohs (((const struct sockaddr_in*)to)->sin_port),
+ (int)tolen);
+#endif
+
+ const int send_sock = use_router_alert ? sock->send_with_router_alert_sock : sock->send_sock;
+
+ if (use_rate_limit &&
+ !pgm_rate_check (&sock->rate_control, len, sock->is_nonblocking))
+ {
+ errno = ENOBUFS;
+ return (const ssize_t)-1;
+ }
+
+ if (!use_router_alert && sock->can_send_data)
+ pgm_mutex_lock (&sock->send_mutex);
+ if (-1 != hops)
+ pgm_sockaddr_multicast_hops (send_sock, sock->send_gsr.gsr_group.ss_family, hops);
+
+ ssize_t sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen);
+ pgm_debug ("sendto returned %zd", sent);
+ if (sent < 0) {
+ int save_errno = pgm_sock_errno();
+ if (PGM_UNLIKELY(errno != ENETUNREACH && /* Network is unreachable */
+ errno != EHOSTUNREACH && /* No route to host */
+ errno != EAGAIN)) /* would block on non-blocking send */
+ {
+#ifdef CONFIG_HAVE_POLL
+/* poll for cleared socket */
+ struct pollfd p = {
+ .fd = send_sock,
+ .events = POLLOUT,
+ .revents = 0
+ };
+ const int ready = poll (&p, 1, 500 /* ms */);
+#else
+ fd_set writefds;
+ FD_ZERO(&writefds);
+ FD_SET(send_sock, &writefds);
+ struct timeval tv = {
+ .tv_sec = 0,
+ .tv_usec = 500 /* ms */ * 1000
+ };
+ const int ready = select (1, NULL, &writefds, NULL, &tv);
+#endif /* CONFIG_HAVE_POLL */
+ if (ready > 0)
+ {
+ sent = sendto (send_sock, buf, len, 0, to, (socklen_t)tolen);
+ if ( sent < 0 )
+ {
+ save_errno = pgm_sock_errno();
+ pgm_warn (_("sendto() %s failed: %s"),
+ inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr ),
+ pgm_sock_strerror (save_errno));
+ }
+ }
+ else if (ready == 0)
+ {
+ pgm_warn (_("sendto() %s failed: socket timeout."),
+ inet_ntoa( ((const struct sockaddr_in*)to)->sin_addr ));
+ }
+ else
+ {
+ save_errno = pgm_sock_errno();
+ pgm_warn (_("blocked socket failed: %s"),
+ pgm_sock_strerror (save_errno));
+ }
+ }
+ }
+
+/* revert to default value hop limit */
+ if (-1 != hops)
+ pgm_sockaddr_multicast_hops (send_sock, sock->send_gsr.gsr_group.ss_family, sock->hops);
+ if (!use_router_alert && sock->can_send_data)
+ pgm_mutex_unlock (&sock->send_mutex);
+ return sent;
+}
+
+/* socket helper, for setting pipe ends non-blocking
+ *
+ * on success, returns 0. on error, returns -1, and sets errno appropriately.
+ */
+
+int
+pgm_set_nonblocking (
+ int fd[2]
+ )
+{
+/* pre-conditions */
+ pgm_assert (fd[0]);
+ pgm_assert (fd[1]);
+
+ pgm_sockaddr_nonblocking (fd[0], TRUE);
+ pgm_sockaddr_nonblocking (fd[1], TRUE);
+ return 0;
+}
+
+/* eof */