1
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
5
* Copyright (c) 2006-2010 Miru Limited.
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
/* getprotobyname_r */
24
# define _BSD_SOURCE 1
30
#include <impl/i18n.h>
31
#include <impl/framework.h>
32
#include <impl/engine.h>
34
#include <impl/socket.h>
35
#include <pgm/engine.h>
36
#include <pgm/version.h>
39
//#define ENGINE_DEBUG
43
int pgm_ipproto_pgm PGM_GNUC_READ_MOSTLY = IPPROTO_PGM;
46
LPFN_WSARECVMSG pgm_WSARecvMsg PGM_GNUC_READ_MOSTLY = NULL;
50
unsigned pgm_loss_rate PGM_GNUC_READ_MOSTLY = 0;
54
static bool pgm_is_supported = FALSE;
55
static volatile uint32_t pgm_ref_count = 0;
58
# ifndef WSAID_WSARECVMSG
59
/* http://cvs.winehq.org/cvsweb/wine/include/mswsock.h */
60
# define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
65
/* startup PGM engine, mainly finding PGM protocol definition, if any from NSS
67
* returns TRUE on success, returns FALSE if an error occurred, implying some form of
68
* system re-configuration is required to resolve before trying again.
70
* NB: Valgrind loves generating errors in getprotobyname().
77
if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, 1) > 0)
80
/* initialise dependent modules */
83
pgm_minor ("OpenPGM %d.%d.%d%s%s%s %s %s %s %s",
84
pgm_major_version, pgm_minor_version, pgm_micro_version,
85
pgm_build_revision ? " (" : "", pgm_build_revision ? pgm_build_revision : "", pgm_build_revision ? ")" : "",
86
pgm_build_date, pgm_build_time, pgm_build_system, pgm_build_machine);
93
WORD wVersionRequested = MAKEWORD (2, 2);
95
if (WSAStartup (wVersionRequested, &wsaData) != 0)
97
const int save_errno = WSAGetLastError ();
99
PGM_ERROR_DOMAIN_ENGINE,
100
pgm_error_from_wsa_errno (save_errno),
101
_("WSAStartup failure: %s"),
102
pgm_wsastrerror (save_errno));
106
if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2)
109
pgm_set_error (error,
110
PGM_ERROR_DOMAIN_ENGINE,
112
_("WSAStartup failed to provide requested version 2.2."));
116
# ifndef CONFIG_TARGET_WINE
117
/* find WSARecvMsg API */
118
if (NULL == pgm_WSARecvMsg) {
119
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
120
DWORD cbBytesReturned;
121
const SOCKET sock = socket (AF_INET, SOCK_DGRAM, 0);
122
if (INVALID_SOCKET == sock) {
124
pgm_set_error (error,
125
PGM_ERROR_DOMAIN_ENGINE,
127
_("Cannot open socket."));
130
if (SOCKET_ERROR == WSAIoctl (sock,
131
SIO_GET_EXTENSION_FUNCTION_POINTER,
132
&WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
133
&pgm_WSARecvMsg, sizeof(pgm_WSARecvMsg),
140
pgm_set_error (error,
141
PGM_ERROR_DOMAIN_ENGINE,
143
_("WSARecvMsg function not found."));
146
pgm_debug ("Retrieved address of WSARecvMsg.");
152
/* find PGM protocol id overriding default value, use first value from NIS */
153
const struct pgm_protoent_t *proto = pgm_getprotobyname ("pgm");
155
if (proto->p_proto != pgm_ipproto_pgm) {
156
pgm_minor (_("Setting PGM protocol number to %i from the protocols database."),
158
pgm_ipproto_pgm = proto->p_proto;
162
/* ensure timing enabled */
163
pgm_error_t* sub_error = NULL;
164
if (!pgm_time_init (&sub_error)) {
166
pgm_propagate_error (error, sub_error);
173
/* receiver simulated loss rate */
178
const errno_t err = pgm_dupenv_s (&env, &envlen, "PGM_LOSS_RATE");
179
if (0 == err && envlen > 0) {
180
const int loss_rate = atoi (env);
181
if (loss_rate > 0 && loss_rate <= 100) {
182
pgm_loss_rate = loss_rate;
183
pgm_minor (_("Setting PGM packet loss rate to %i%%."), pgm_loss_rate);
189
/* create global sock list lock */
190
pgm_rwlock_init (&pgm_sock_list_lock);
192
pgm_is_supported = TRUE;
198
pgm_thread_shutdown();
199
pgm_messages_shutdown();
200
pgm_atomic_dec32 (&pgm_ref_count);
204
/* returns TRUE if PGM engine has been initialized
210
return ( pgm_is_supported == TRUE );
213
/* returns TRUE on success, returns FALSE if an error occurred.
219
/* cannot use pgm_return_val_if_fail() as logging may not be started */
220
if (0 == pgm_atomic_read32 (&pgm_ref_count))
223
if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, (uint32_t)-1) != 1)
226
pgm_is_supported = FALSE;
228
/* destroy all open socks */
229
while (pgm_sock_list) {
230
pgm_close ((pgm_sock_t*)pgm_sock_list->data, FALSE);
233
pgm_rwlock_free (&pgm_sock_list_lock);
243
pgm_thread_shutdown();
244
pgm_messages_shutdown();
248
/* helper to drop out of setuid 0 after creating PGM sockets
251
pgm_drop_superuser (void)
255
setuid((gid_t)65534);
256
setgid((uid_t)65534);