diff options
Diffstat (limited to '3rdparty/openpgm-svn-r1135/pgm/engine.c')
-rw-r--r-- | 3rdparty/openpgm-svn-r1135/pgm/engine.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1135/pgm/engine.c b/3rdparty/openpgm-svn-r1135/pgm/engine.c new file mode 100644 index 0000000..dbe50b4 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/engine.c @@ -0,0 +1,282 @@ +/* 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 + */ + +/* getprotobyname_r */ +#ifndef _BSD_SOURCE +# define _BSD_SOURCE 1 +#endif + +#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 */ |