summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/engine.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/openpgm-svn-r1085/pgm/engine.c')
-rw-r--r--3rdparty/openpgm-svn-r1085/pgm/engine.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1085/pgm/engine.c b/3rdparty/openpgm-svn-r1085/pgm/engine.c
new file mode 100644
index 0000000..994bca2
--- /dev/null
+++ b/3rdparty/openpgm-svn-r1085/pgm/engine.c
@@ -0,0 +1,277 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * PGM engine.
+ *
+ * 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
+ */
+
+#ifndef _WIN32
+# include <netdb.h>
+#endif
+#include <impl/i18n.h>
+#include <impl/framework.h>
+#include <impl/engine.h>
+#include <impl/mem.h>
+#include <impl/socket.h>
+#include <pgm/engine.h>
+#include <pgm/version.h>
+
+
+//#define ENGINE_DEBUG
+
+
+/* globals */
+int pgm_ipproto_pgm PGM_GNUC_READ_MOSTLY = IPPROTO_PGM;
+
+#ifdef _WIN32
+LPFN_WSARECVMSG pgm_WSARecvMsg PGM_GNUC_READ_MOSTLY = NULL;
+#endif
+
+#ifdef PGM_DEBUG
+unsigned pgm_loss_rate PGM_GNUC_READ_MOSTLY = 0;
+#endif
+
+/* locals */
+static bool pgm_is_supported = FALSE;
+static volatile uint32_t pgm_ref_count = 0;
+
+#ifdef _WIN32
+# ifndef WSAID_WSARECVMSG
+/* http://cvs.winehq.org/cvsweb/wine/include/mswsock.h */
+# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
+# endif
+#endif
+
+
+/* startup PGM engine, mainly finding PGM protocol definition, if any from NSS
+ *
+ * returns TRUE on success, returns FALSE if an error occurred, implying some form of
+ * system re-configuration is required to resolve before trying again.
+ *
+ * NB: Valgrind loves generating errors in getprotobyname().
+ */
+bool
+pgm_init (
+ pgm_error_t** error
+ )
+{
+ if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, 1) > 0)
+ return TRUE;
+
+/* initialise dependent modules */
+ pgm_messages_init();
+
+ pgm_minor ("OpenPGM %d.%d.%d%s%s%s %s %s %s %s",
+ pgm_major_version, pgm_minor_version, pgm_micro_version,
+ pgm_build_revision ? " (" : "", pgm_build_revision ? pgm_build_revision : "", pgm_build_revision ? ")" : "",
+ pgm_build_date, pgm_build_time, pgm_build_system, pgm_build_machine);
+
+ pgm_thread_init();
+ pgm_mem_init();
+ pgm_rand_init();
+
+#ifdef _WIN32
+ WORD wVersionRequested = MAKEWORD (2, 2);
+ WSADATA wsaData;
+ if (WSAStartup (wVersionRequested, &wsaData) != 0)
+ {
+ const int save_errno = WSAGetLastError ();
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_ENGINE,
+ pgm_error_from_wsa_errno (save_errno),
+ _("WSAStartup failure: %s"),
+ pgm_wsastrerror (save_errno));
+ goto err_shutdown;
+ }
+
+ if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2)
+ {
+ WSACleanup();
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_ENGINE,
+ PGM_ERROR_FAILED,
+ _("WSAStartup failed to provide requested version 2.2."));
+ goto err_shutdown;
+ }
+
+# ifndef CONFIG_TARGET_WINE
+/* find WSARecvMsg API */
+ if (NULL == pgm_WSARecvMsg) {
+ GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
+ DWORD cbBytesReturned;
+ const SOCKET sock = socket (AF_INET, SOCK_DGRAM, 0);
+ if (SOCKET_ERROR == sock) {
+ WSACleanup();
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_ENGINE,
+ PGM_ERROR_FAILED,
+ _("Cannot open socket."));
+ goto err_shutdown;
+ }
+ if (SOCKET_ERROR == WSAIoctl (sock,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
+ &pgm_WSARecvMsg, sizeof(pgm_WSARecvMsg),
+ &cbBytesReturned,
+ NULL,
+ NULL))
+ {
+ closesocket (sock);
+ WSACleanup();
+ pgm_set_error (error,
+ PGM_ERROR_DOMAIN_ENGINE,
+ PGM_ERROR_FAILED,
+ _("WSARecvMsg function not found."));
+ goto err_shutdown;
+ }
+ pgm_debug ("Retrieved address of WSARecvMsg.");
+ closesocket (sock);
+ }
+# endif
+#endif /* _WIN32 */
+
+/* find PGM protocol id overriding default value, use first value from NIS */
+#ifdef CONFIG_HAVE_GETPROTOBYNAME_R
+ char b[1024];
+ struct protoent protobuf;
+ const struct protoent* proto = getprotobyname_r ("pgm", &protobuf, b, sizeof(b));
+ if (NULL != proto) {
+ if (proto->p_proto != pgm_ipproto_pgm) {
+ pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."),
+ proto->p_proto);
+ pgm_ipproto_pgm = proto->p_proto;
+ }
+ }
+#elif defined(CONFIG_HAVE_GETPROTOBYNAME_R2)
+ char b[1024];
+ struct protoent protobuf, *proto;
+ const int e = getprotobyname_r ("pgm", &protobuf, b, sizeof(b), &proto);
+ if (e != -1 && proto != NULL) {
+ if (proto->p_proto != pgm_ipproto_pgm) {
+ pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."),
+ proto->p_proto);
+ pgm_ipproto_pgm = proto->p_proto;
+ }
+ }
+#else
+ const struct protoent *proto = getprotobyname ("pgm");
+ if (proto != NULL) {
+ if (proto->p_proto != pgm_ipproto_pgm) {
+#ifndef _WIN32
+ pgm_minor (_("Setting PGM protocol number to %i from /etc/protocols."),
+ proto->p_proto);
+#else
+ pgm_minor (_("Setting PGM protocol number to %i from %%SYSTEMROOT%%\\system32\\drivers\\etc\\protocols."),
+ proto->p_proto);
+#endif
+ pgm_ipproto_pgm = proto->p_proto;
+ }
+ }
+#endif
+
+/* ensure timing enabled */
+ pgm_error_t* sub_error = NULL;
+ if (!pgm_time_init (&sub_error)) {
+ if (sub_error)
+ pgm_propagate_error (error, sub_error);
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ goto err_shutdown;
+ }
+
+/* receiver simulated loss rate */
+#ifdef PGM_DEBUG
+ const char *loss_rate = getenv ("PGM_LOSS_RATE");
+ if (NULL != loss_rate) {
+ int value = atoi (loss_rate);
+ if (value > 0 && value <= 100) {
+ pgm_loss_rate = value;
+ pgm_minor (_("Setting PGM packet loss rate to %i%%."), pgm_loss_rate);
+ }
+ }
+#endif
+
+/* create global sock list lock */
+ pgm_rwlock_init (&pgm_sock_list_lock);
+
+ pgm_is_supported = TRUE;
+ return TRUE;
+
+err_shutdown:
+ pgm_rand_shutdown();
+ pgm_mem_shutdown();
+ pgm_thread_shutdown();
+ pgm_messages_shutdown();
+ pgm_atomic_dec32 (&pgm_ref_count);
+ return FALSE;
+}
+
+/* returns TRUE if PGM engine has been initialized
+ */
+
+bool
+pgm_supported (void)
+{
+ return ( pgm_is_supported == TRUE );
+}
+
+/* returns TRUE on success, returns FALSE if an error occurred.
+ */
+
+bool
+pgm_shutdown (void)
+{
+ pgm_return_val_if_fail (pgm_atomic_read32 (&pgm_ref_count) > 0, FALSE);
+
+ if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, (uint32_t)-1) != 1)
+ return TRUE;
+
+ pgm_is_supported = FALSE;
+
+/* destroy all open socks */
+ while (pgm_sock_list) {
+ pgm_close ((pgm_sock_t*)pgm_sock_list->data, FALSE);
+ }
+
+ pgm_time_shutdown();
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+
+ pgm_rand_shutdown();
+ pgm_mem_shutdown();
+ pgm_thread_shutdown();
+ pgm_messages_shutdown();
+ return TRUE;
+}
+
+/* helper to drop out of setuid 0 after creating PGM sockets
+ */
+void
+pgm_drop_superuser (void)
+{
+#ifndef _WIN32
+ if (0 == getuid()) {
+ setuid((gid_t)65534);
+ setgid((uid_t)65534);
+ }
+#endif
+}
+
+/* eof */