~ubuntu-branches/ubuntu/precise/libpgm/precise

« back to all changes in this revision

Viewing changes to openpgm/pgm/.svn/text-base/engine.c.svn-base

  • Committer: Bazaar Package Importer
  • Author(s): Gabriel de Perthuis
  • Date: 2011-04-07 16:48:52 UTC
  • Revision ID: james.westby@ubuntu.com-20110407164852-8uamem42ojeptj6l
Tags: upstream-5.1.116~dfsg
ImportĀ upstreamĀ versionĀ 5.1.116~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
 
2
 *
 
3
 * PGM engine.
 
4
 *
 
5
 * Copyright (c) 2006-2010 Miru Limited.
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 */
 
21
 
 
22
/* getprotobyname_r */
 
23
#ifndef _BSD_SOURCE
 
24
#       define _BSD_SOURCE      1
 
25
#endif
 
26
 
 
27
#ifndef _WIN32
 
28
#       include <netdb.h>
 
29
#endif
 
30
#include <impl/i18n.h>
 
31
#include <impl/framework.h>
 
32
#include <impl/engine.h>
 
33
#include <impl/mem.h>
 
34
#include <impl/socket.h>
 
35
#include <pgm/engine.h>
 
36
#include <pgm/version.h>
 
37
 
 
38
 
 
39
//#define ENGINE_DEBUG
 
40
 
 
41
 
 
42
/* globals */
 
43
int                     pgm_ipproto_pgm PGM_GNUC_READ_MOSTLY = IPPROTO_PGM;
 
44
 
 
45
#ifdef _WIN32
 
46
LPFN_WSARECVMSG         pgm_WSARecvMsg PGM_GNUC_READ_MOSTLY = NULL;
 
47
#endif
 
48
 
 
49
#ifdef PGM_DEBUG
 
50
unsigned                pgm_loss_rate PGM_GNUC_READ_MOSTLY = 0;
 
51
#endif
 
52
 
 
53
/* locals */
 
54
static bool             pgm_is_supported = FALSE;
 
55
static volatile uint32_t pgm_ref_count   = 0;
 
56
 
 
57
#ifdef _WIN32
 
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}}
 
61
#       endif
 
62
#endif
 
63
 
 
64
 
 
65
/* startup PGM engine, mainly finding PGM protocol definition, if any from NSS
 
66
 *
 
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.
 
69
 *
 
70
 * NB: Valgrind loves generating errors in getprotobyname().
 
71
 */
 
72
bool
 
73
pgm_init (
 
74
        pgm_error_t**   error
 
75
        )
 
76
{
 
77
        if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, 1) > 0)
 
78
                return TRUE;
 
79
 
 
80
/* initialise dependent modules */
 
81
        pgm_messages_init();
 
82
 
 
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);
 
87
 
 
88
        pgm_thread_init();
 
89
        pgm_mem_init();
 
90
        pgm_rand_init();
 
91
 
 
92
#ifdef _WIN32
 
93
        WORD wVersionRequested = MAKEWORD (2, 2);
 
94
        WSADATA wsaData;
 
95
        if (WSAStartup (wVersionRequested, &wsaData) != 0)
 
96
        {
 
97
                const int save_errno = WSAGetLastError ();
 
98
                pgm_set_error (error,
 
99
                             PGM_ERROR_DOMAIN_ENGINE,
 
100
                             pgm_error_from_wsa_errno (save_errno),
 
101
                             _("WSAStartup failure: %s"),
 
102
                             pgm_wsastrerror (save_errno));
 
103
                goto err_shutdown;
 
104
        }
 
105
 
 
106
        if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2)
 
107
        {
 
108
                WSACleanup();
 
109
                pgm_set_error (error,
 
110
                               PGM_ERROR_DOMAIN_ENGINE,
 
111
                               PGM_ERROR_FAILED,
 
112
                               _("WSAStartup failed to provide requested version 2.2."));
 
113
                goto err_shutdown;
 
114
        }
 
115
 
 
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) {
 
123
                        WSACleanup();
 
124
                        pgm_set_error (error,
 
125
                                       PGM_ERROR_DOMAIN_ENGINE,
 
126
                                       PGM_ERROR_FAILED,
 
127
                                       _("Cannot open socket."));
 
128
                        goto err_shutdown;
 
129
                }
 
130
                if (SOCKET_ERROR == WSAIoctl (sock,
 
131
                                              SIO_GET_EXTENSION_FUNCTION_POINTER,
 
132
                                              &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID),
 
133
                                              &pgm_WSARecvMsg, sizeof(pgm_WSARecvMsg),
 
134
                                              &cbBytesReturned,
 
135
                                              NULL,
 
136
                                              NULL))
 
137
                {
 
138
                        closesocket (sock);
 
139
                        WSACleanup();
 
140
                        pgm_set_error (error,
 
141
                                       PGM_ERROR_DOMAIN_ENGINE,
 
142
                                       PGM_ERROR_FAILED,
 
143
                                       _("WSARecvMsg function not found."));
 
144
                        goto err_shutdown;
 
145
                }
 
146
                pgm_debug ("Retrieved address of WSARecvMsg.");
 
147
                closesocket (sock);
 
148
        }
 
149
#       endif
 
150
#endif /* _WIN32 */
 
151
 
 
152
/* find PGM protocol id overriding default value, use first value from NIS */
 
153
        const struct pgm_protoent_t *proto = pgm_getprotobyname ("pgm");
 
154
        if (proto != NULL) {
 
155
                if (proto->p_proto != pgm_ipproto_pgm) {
 
156
                        pgm_minor (_("Setting PGM protocol number to %i from the protocols database."),
 
157
                                proto->p_proto);
 
158
                        pgm_ipproto_pgm = proto->p_proto;
 
159
                }
 
160
        }
 
161
 
 
162
/* ensure timing enabled */
 
163
        pgm_error_t* sub_error = NULL;
 
164
        if (!pgm_time_init (&sub_error)) {
 
165
                if (sub_error)
 
166
                        pgm_propagate_error (error, sub_error);
 
167
#ifdef _WIN32
 
168
                WSACleanup();
 
169
#endif
 
170
                goto err_shutdown;
 
171
        }
 
172
 
 
173
/* receiver simulated loss rate */
 
174
#ifdef PGM_DEBUG
 
175
        char* env;
 
176
        size_t envlen;
 
177
 
 
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);
 
184
                }
 
185
                pgm_free (env);
 
186
        }
 
187
#endif
 
188
 
 
189
/* create global sock list lock */
 
190
        pgm_rwlock_init (&pgm_sock_list_lock);
 
191
 
 
192
        pgm_is_supported = TRUE;
 
193
        return TRUE;
 
194
 
 
195
err_shutdown:
 
196
        pgm_rand_shutdown();
 
197
        pgm_mem_shutdown();
 
198
        pgm_thread_shutdown();
 
199
        pgm_messages_shutdown();
 
200
        pgm_atomic_dec32 (&pgm_ref_count);
 
201
        return FALSE;
 
202
}
 
203
 
 
204
/* returns TRUE if PGM engine has been initialized
 
205
 */
 
206
 
 
207
bool
 
208
pgm_supported (void)
 
209
{
 
210
        return ( pgm_is_supported == TRUE );
 
211
}
 
212
 
 
213
/* returns TRUE on success, returns FALSE if an error occurred.
 
214
 */
 
215
 
 
216
bool
 
217
pgm_shutdown (void)
 
218
{
 
219
/* cannot use pgm_return_val_if_fail() as logging may not be started */
 
220
        if (0 == pgm_atomic_read32 (&pgm_ref_count))
 
221
                return FALSE;
 
222
 
 
223
        if (pgm_atomic_exchange_and_add32 (&pgm_ref_count, (uint32_t)-1) != 1)
 
224
                return TRUE;
 
225
 
 
226
        pgm_is_supported = FALSE;
 
227
 
 
228
/* destroy all open socks */
 
229
        while (pgm_sock_list) {
 
230
                pgm_close ((pgm_sock_t*)pgm_sock_list->data, FALSE);
 
231
        }
 
232
 
 
233
        pgm_rwlock_free (&pgm_sock_list_lock);
 
234
 
 
235
        pgm_time_shutdown();
 
236
 
 
237
#ifdef _WIN32
 
238
        WSACleanup();
 
239
#endif
 
240
 
 
241
        pgm_rand_shutdown();
 
242
        pgm_mem_shutdown();
 
243
        pgm_thread_shutdown();
 
244
        pgm_messages_shutdown();
 
245
        return TRUE;
 
246
}
 
247
 
 
248
/* helper to drop out of setuid 0 after creating PGM sockets
 
249
 */
 
250
void
 
251
pgm_drop_superuser (void)
 
252
{
 
253
#ifndef _WIN32
 
254
        if (0 == getuid()) {
 
255
                setuid((gid_t)65534);
 
256
                setgid((uid_t)65534);
 
257
        }
 
258
#endif
 
259
}
 
260
 
 
261
/* eof */