rob@76
|
1 /*
|
rob@76
|
2 OSCgroups -- open sound control groupcasting infrastructure
|
rob@76
|
3 Copyright (C) 2005 Ross Bencina
|
rob@76
|
4
|
rob@76
|
5 This program is free software; you can redistribute it and/or
|
rob@76
|
6 modify it under the terms of the GNU General Public License
|
rob@76
|
7 as published by the Free Software Foundation; either version 2
|
rob@76
|
8 of the License, or (at your option) any later version.
|
rob@76
|
9
|
rob@76
|
10 This program is distributed in the hope that it will be useful,
|
rob@76
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
rob@76
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
rob@76
|
13 GNU General Public License for more details.
|
rob@76
|
14
|
rob@76
|
15 You should have received a copy of the GNU General Public License
|
rob@76
|
16 along with this program; if not, write to the Free Software
|
rob@76
|
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
rob@76
|
18 */
|
rob@76
|
19
|
rob@76
|
20
|
rob@76
|
21 #include "OscGroupClient.h"
|
rob@76
|
22
|
rob@76
|
23 #include <cstring>
|
rob@76
|
24 #include <iostream>
|
rob@76
|
25 #include <vector>
|
rob@76
|
26 #include <ctime>
|
rob@76
|
27 #include <string>
|
rob@76
|
28 #include <cassert>
|
rob@76
|
29 #include <cstdlib>
|
rob@76
|
30
|
rob@76
|
31 #include "osc/OscReceivedElements.h"
|
rob@76
|
32 #include "osc/OscOutboundPacketStream.h"
|
rob@76
|
33 #include "osc/OscPacketListener.h"
|
rob@76
|
34
|
rob@76
|
35 #include "ip/UdpSocket.h"
|
rob@76
|
36 #include "ip/IpEndpointName.h"
|
rob@76
|
37 #include "ip/PacketListener.h"
|
rob@76
|
38 #include "ip/TimerListener.h"
|
rob@76
|
39
|
rob@76
|
40 #include "md5.h"
|
rob@76
|
41
|
rob@76
|
42 #if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug
|
rob@76
|
43 namespace std {
|
rob@76
|
44 using ::__strcmp__; // avoid error: E2316 '__strcmp__' is not a member of 'std'.
|
rob@76
|
45 }
|
rob@76
|
46 #endif
|
rob@76
|
47
|
rob@76
|
48 /*
|
rob@76
|
49 There are three sockets:
|
rob@76
|
50 externalSocket is used to send and receive data from the network
|
rob@76
|
51 including the server and other peers
|
rob@76
|
52
|
rob@76
|
53 localRxSocket is used to forward data to the local (client)
|
rob@76
|
54 application from other peers
|
rob@76
|
55
|
rob@76
|
56 localTxSocket is used to recieve data from the local (client)
|
rob@76
|
57 application to be forwarded to other peers
|
rob@76
|
58
|
rob@76
|
59
|
rob@76
|
60 Some behavioral rules:
|
rob@76
|
61
|
rob@76
|
62 the choice of which peer endpoint to forward traffic to is made based
|
rob@76
|
63 on which endpoints we have received pings from. if pings have been
|
rob@76
|
64 received from multiple endpoints preference is given to the private
|
rob@76
|
65 endpoint. as soon as a ping has been received we start forwarding data
|
rob@76
|
66
|
rob@76
|
67 during the establishment phase we ping all endpoints repeatedly
|
rob@76
|
68 even if we have already received pings from an endpoint.
|
rob@76
|
69
|
rob@76
|
70 during the establishment phase we initially send pings faster, and then
|
rob@76
|
71 gradually return to a slower rate.
|
rob@76
|
72
|
rob@76
|
73 the establishment phase ends when:
|
rob@76
|
74 - we receive a ping from the private endpoint
|
rob@76
|
75
|
rob@76
|
76 - we receive a ping from any endpoint, and
|
rob@76
|
77 ESTABLISHMENT_PING_PERIOD_COUNT ping periods have elapsed
|
rob@76
|
78
|
rob@76
|
79 if the server indicates that any of the port or address information of
|
rob@76
|
80 the peer has changed, we restart the establishment process.
|
rob@76
|
81
|
rob@76
|
82 if a ping is received from an endpoint which we haven't received from
|
rob@76
|
83 before we restart the establishment phase.
|
rob@76
|
84
|
rob@76
|
85 pings are sent less frequently if the channel is being kept open
|
rob@76
|
86 by forwarded traffic. We ensure that some traffic is sent accross
|
rob@76
|
87 the link every IDLE_PING_PERIOD_SECONDS and that a ping is sent
|
rob@76
|
88 accross the link at least every ACTIVE_PING_PERIOD_SECONDS
|
rob@76
|
89
|
rob@76
|
90
|
rob@76
|
91 if the last time at which the server has heard from a peer
|
rob@76
|
92 AND the last time from which we received a ping from the peer
|
rob@76
|
93 exceeds PURGE_PEER_TIMEOUT_SECONDS then the peer is removed from
|
rob@76
|
94 the peers list.
|
rob@76
|
95
|
rob@76
|
96
|
rob@76
|
97 if we havn't received a ping from a peer in
|
rob@76
|
98 PEER_ESTABLISHMENT_RETRY_TIME_SECONDS then we attempt to re-establish
|
rob@76
|
99 the connection.
|
rob@76
|
100
|
rob@76
|
101
|
rob@76
|
102
|
rob@76
|
103 TODO:
|
rob@76
|
104
|
rob@76
|
105 o- report ping times (requires higher resolution timer i think)
|
rob@76
|
106
|
rob@76
|
107
|
rob@76
|
108 -----------
|
rob@76
|
109
|
rob@76
|
110
|
rob@76
|
111
|
rob@76
|
112 */
|
rob@76
|
113
|
rob@76
|
114
|
rob@76
|
115
|
rob@76
|
116
|
rob@76
|
117 #define PURGE_PEER_TIMEOUT_SECONDS 180 // time before removing peer from active list
|
rob@76
|
118
|
rob@76
|
119 #define PEER_ESTABLISHMENT_RETRY_TIME_SECONDS 60
|
rob@76
|
120
|
rob@76
|
121 #define IDLE_PING_PERIOD_SECONDS 6 // seconds between pings when the link is idle
|
rob@76
|
122
|
rob@76
|
123 #define ACTIVE_PING_PERIOD_SECONDS 30 // seconds between pings when the link is active
|
rob@76
|
124
|
rob@76
|
125 #define ESTABLISHMENT_PING_PERIOD_COUNT 5 // 5 pings are always sent to all peer endpoints
|
rob@76
|
126
|
rob@76
|
127
|
rob@76
|
128
|
rob@76
|
129 struct PeerEndpoint{
|
rob@76
|
130 PeerEndpoint()
|
rob@76
|
131 : pingReceived( false )
|
rob@76
|
132 , sentPingsCount( 0 )
|
rob@76
|
133 , forwardedPacketsCount( 0 ) {}
|
rob@76
|
134
|
rob@76
|
135 IpEndpointName endpointName;
|
rob@76
|
136 bool pingReceived;
|
rob@76
|
137 std::time_t lastPingReceiveTime;
|
rob@76
|
138
|
rob@76
|
139 int sentPingsCount;
|
rob@76
|
140 std::time_t lastPingSendTime;
|
rob@76
|
141
|
rob@76
|
142 int forwardedPacketsCount;
|
rob@76
|
143 std::time_t lastPacketForwardTime;
|
rob@76
|
144 };
|
rob@76
|
145
|
rob@76
|
146
|
rob@76
|
147 struct Peer{
|
rob@76
|
148 Peer( const char *userName )
|
rob@76
|
149 : name( userName )
|
rob@76
|
150 , pingPeriodCount( 0 ) {}
|
rob@76
|
151
|
rob@76
|
152 std::string name;
|
rob@76
|
153
|
rob@76
|
154 std::time_t lastUserInfoReceiveTime;
|
rob@76
|
155 int secondsSinceLastAliveReceivedByServer;
|
rob@76
|
156
|
rob@76
|
157 /*
|
rob@76
|
158 we maintain three addresses for each peer. the private address is the
|
rob@76
|
159 address the peer thinks it is, the public is the address that the
|
rob@76
|
160 peer appears as to the server, and the ping address is the address
|
rob@76
|
161 that the client appears as to us when we receive a ping from it. this
|
rob@76
|
162 last address is necessary for half cone (symmetric) NATs which assign
|
rob@76
|
163 the peer a different port to talk to us than the one they assigned to
|
rob@76
|
164 talk to the server.
|
rob@76
|
165 */
|
rob@76
|
166
|
rob@76
|
167 PeerEndpoint privateEndpoint;
|
rob@76
|
168 PeerEndpoint publicEndpoint;
|
rob@76
|
169 PeerEndpoint pingEndpoint;
|
rob@76
|
170
|
rob@76
|
171 int pingPeriodCount;
|
rob@76
|
172 std::time_t lastPingPeriodTime;
|
rob@76
|
173
|
rob@76
|
174 std::time_t MostRecentActivityTime() const
|
rob@76
|
175 {
|
rob@76
|
176 // the most recent activity time is the most recent time either the
|
rob@76
|
177 // server heard from the peer, or we received a ping from the peer
|
rob@76
|
178
|
rob@76
|
179 std::time_t lastUserInfoReceivedByTheServerTime =
|
rob@76
|
180 lastUserInfoReceiveTime - secondsSinceLastAliveReceivedByServer; // FIXME: assumes time_t is in seconds
|
rob@76
|
181
|
rob@76
|
182 std::time_t result = lastUserInfoReceivedByTheServerTime;
|
rob@76
|
183 if( privateEndpoint.pingReceived )
|
rob@76
|
184 result = std::max( result, privateEndpoint.lastPingReceiveTime );
|
rob@76
|
185 if( publicEndpoint.pingReceived )
|
rob@76
|
186 result = std::max( result, publicEndpoint.lastPingReceiveTime );
|
rob@76
|
187 if( pingEndpoint.pingReceived )
|
rob@76
|
188 result = std::max( result, pingEndpoint.lastPingReceiveTime );
|
rob@76
|
189
|
rob@76
|
190 return result;
|
rob@76
|
191 }
|
rob@76
|
192
|
rob@76
|
193 };
|
rob@76
|
194
|
rob@76
|
195
|
rob@76
|
196 static std::vector<Peer> peers_;
|
rob@76
|
197
|
rob@76
|
198
|
rob@76
|
199 class ExternalCommunicationsSender : public TimerListener {
|
rob@76
|
200 #define IP_MTU_SIZE 1536
|
rob@76
|
201 char aliveBuffer_[IP_MTU_SIZE];
|
rob@76
|
202 std::size_t aliveSize_;
|
rob@76
|
203 std::time_t lastAliveSentTime_;
|
rob@76
|
204
|
rob@76
|
205 char pingBuffer_[IP_MTU_SIZE];
|
rob@76
|
206 std::size_t pingSize_;
|
rob@76
|
207
|
rob@76
|
208 UdpSocket& externalSocket_;
|
rob@76
|
209 IpEndpointName remoteServerEndpoint_;
|
rob@76
|
210 IpEndpointName localToServerEndpoint_;
|
rob@76
|
211
|
rob@76
|
212 std::string userName_;
|
rob@76
|
213 std::string userPassword_;
|
rob@76
|
214 std::string groupName_;
|
rob@76
|
215 std::string groupPassword_;
|
rob@76
|
216
|
rob@76
|
217 void PrepareAliveBuffer()
|
rob@76
|
218 {
|
rob@76
|
219 osc::OutboundPacketStream p( aliveBuffer_, IP_MTU_SIZE );
|
rob@76
|
220
|
rob@76
|
221 p << osc::BeginBundle();
|
rob@76
|
222
|
rob@76
|
223 p << osc::BeginMessage( "/groupserver/user_alive" )
|
rob@76
|
224 << userName_.c_str()
|
rob@76
|
225 << userPassword_.c_str()
|
rob@76
|
226 << ~((osc::int32)localToServerEndpoint_.address)
|
rob@76
|
227 << (osc::int32)localToServerEndpoint_.port
|
rob@76
|
228 << groupName_.c_str()
|
rob@76
|
229 << groupPassword_.c_str()
|
rob@76
|
230 << osc::EndMessage;
|
rob@76
|
231
|
rob@76
|
232 p << osc::BeginMessage( "/groupserver/get_group_users_info" )
|
rob@76
|
233 << groupName_.c_str()
|
rob@76
|
234 << groupPassword_.c_str()
|
rob@76
|
235 << osc::EndMessage;
|
rob@76
|
236
|
rob@76
|
237 p << osc::EndBundle;
|
rob@76
|
238
|
rob@76
|
239 aliveSize_ = p.Size();
|
rob@76
|
240 }
|
rob@76
|
241
|
rob@76
|
242 void SendAlive( std::time_t currentTime )
|
rob@76
|
243 {
|
rob@76
|
244 int secondsSinceLastAliveSent = (int)std::difftime(currentTime, lastAliveSentTime_);
|
rob@76
|
245 if( secondsSinceLastAliveSent >= IDLE_PING_PERIOD_SECONDS ){
|
rob@76
|
246
|
rob@76
|
247 externalSocket_.SendTo( remoteServerEndpoint_, aliveBuffer_, aliveSize_ );
|
rob@76
|
248
|
rob@76
|
249 lastAliveSentTime_ = currentTime;
|
rob@76
|
250 }
|
rob@76
|
251 }
|
rob@76
|
252
|
rob@76
|
253 void PreparePingBuffer()
|
rob@76
|
254 {
|
rob@76
|
255 osc::OutboundPacketStream p( pingBuffer_, IP_MTU_SIZE );
|
rob@76
|
256
|
rob@76
|
257 p << osc::BeginBundle();
|
rob@76
|
258
|
rob@76
|
259 p << osc::BeginMessage( "/groupclient/ping" )
|
rob@76
|
260 << userName_.c_str()
|
rob@76
|
261 << osc::EndMessage;
|
rob@76
|
262
|
rob@76
|
263 p << osc::EndBundle;
|
rob@76
|
264
|
rob@76
|
265 pingSize_ = p.Size();
|
rob@76
|
266 }
|
rob@76
|
267
|
rob@76
|
268 void SendPing( PeerEndpoint& to, std::time_t currentTime )
|
rob@76
|
269 {
|
rob@76
|
270 char addressString[ IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH ];
|
rob@76
|
271 to.endpointName.AddressAndPortAsString( addressString );
|
rob@76
|
272
|
rob@76
|
273 std::cout << "sending ping to " << addressString << "\n";
|
rob@76
|
274
|
rob@76
|
275 externalSocket_.SendTo( to.endpointName, pingBuffer_, pingSize_ );
|
rob@76
|
276 ++to.sentPingsCount;
|
rob@76
|
277 to.lastPingSendTime = currentTime;
|
rob@76
|
278 }
|
rob@76
|
279
|
rob@76
|
280
|
rob@76
|
281 PeerEndpoint* SelectEndpoint( Peer& peer )
|
rob@76
|
282 {
|
rob@76
|
283 if( peer.privateEndpoint.pingReceived ){
|
rob@76
|
284
|
rob@76
|
285 return &peer.privateEndpoint;
|
rob@76
|
286
|
rob@76
|
287 }else if( peer.publicEndpoint.pingReceived ){
|
rob@76
|
288
|
rob@76
|
289 return &peer.publicEndpoint;
|
rob@76
|
290
|
rob@76
|
291 }else if( peer.pingEndpoint.pingReceived ){
|
rob@76
|
292
|
rob@76
|
293 return &peer.pingEndpoint;
|
rob@76
|
294 }
|
rob@76
|
295
|
rob@76
|
296 return 0;
|
rob@76
|
297 }
|
rob@76
|
298
|
rob@76
|
299
|
rob@76
|
300 void PollPeerPingTimer( Peer& peer, std::time_t currentTime, bool executeNowIgnoringTimeouts=false )
|
rob@76
|
301 {
|
rob@76
|
302 bool noPingsReceivedYet =
|
rob@76
|
303 !peer.privateEndpoint.pingReceived
|
rob@76
|
304 && !peer.publicEndpoint.pingReceived
|
rob@76
|
305 && !peer.pingEndpoint.pingReceived;
|
rob@76
|
306
|
rob@76
|
307 if( !noPingsReceivedYet ){
|
rob@76
|
308 // check whether we should attempt to re-establish the link
|
rob@76
|
309 // due to no traffic arriving for PEER_ESTABLISHMENT_RETRY_TIME_SECONDS
|
rob@76
|
310
|
rob@76
|
311 std::time_t mostRecentPingTime = 0;
|
rob@76
|
312 if( peer.privateEndpoint.pingReceived )
|
rob@76
|
313 mostRecentPingTime = std::max( mostRecentPingTime, peer.privateEndpoint.lastPingReceiveTime );
|
rob@76
|
314 if( peer.publicEndpoint.pingReceived )
|
rob@76
|
315 mostRecentPingTime = std::max( mostRecentPingTime, peer.publicEndpoint.lastPingReceiveTime );
|
rob@76
|
316 if( peer.pingEndpoint.pingReceived )
|
rob@76
|
317 mostRecentPingTime = std::max( mostRecentPingTime, peer.pingEndpoint.lastPingReceiveTime );
|
rob@76
|
318
|
rob@76
|
319 if( (int)std::difftime(currentTime, mostRecentPingTime) > PEER_ESTABLISHMENT_RETRY_TIME_SECONDS ){
|
rob@76
|
320
|
rob@76
|
321 peer.pingPeriodCount = 0;
|
rob@76
|
322 executeNowIgnoringTimeouts = true;
|
rob@76
|
323 }
|
rob@76
|
324 }
|
rob@76
|
325
|
rob@76
|
326
|
rob@76
|
327 bool inEstablishmentPhase =
|
rob@76
|
328 ( ( peer.pingPeriodCount < ESTABLISHMENT_PING_PERIOD_COUNT )
|
rob@76
|
329 && ( !peer.privateEndpoint.pingReceived ) )
|
rob@76
|
330 || noPingsReceivedYet;
|
rob@76
|
331
|
rob@76
|
332 if( inEstablishmentPhase ){
|
rob@76
|
333 int pingPeriod;
|
rob@76
|
334 if( peer.pingPeriodCount < ESTABLISHMENT_PING_PERIOD_COUNT ){
|
rob@76
|
335
|
rob@76
|
336 pingPeriod = (int) (IDLE_PING_PERIOD_SECONDS *
|
rob@76
|
337 ((double)(peer.pingPeriodCount + 1) / (double) ESTABLISHMENT_PING_PERIOD_COUNT));
|
rob@76
|
338
|
rob@76
|
339 }else{
|
rob@76
|
340 pingPeriod = IDLE_PING_PERIOD_SECONDS;
|
rob@76
|
341 }
|
rob@76
|
342
|
rob@76
|
343 if( currentTime >= (peer.lastPingPeriodTime + pingPeriod)
|
rob@76
|
344 || executeNowIgnoringTimeouts ){
|
rob@76
|
345 SendPing( peer.privateEndpoint, currentTime );
|
rob@76
|
346 SendPing( peer.publicEndpoint, currentTime );
|
rob@76
|
347 if( peer.pingEndpoint.pingReceived )
|
rob@76
|
348 SendPing( peer.pingEndpoint, currentTime );
|
rob@76
|
349
|
rob@76
|
350 peer.lastPingPeriodTime = currentTime;
|
rob@76
|
351 ++peer.pingPeriodCount;
|
rob@76
|
352 }
|
rob@76
|
353
|
rob@76
|
354 }else{
|
rob@76
|
355
|
rob@76
|
356 PeerEndpoint *peerEndpointToUse = SelectEndpoint( peer );
|
rob@76
|
357 assert( peerEndpointToUse != 0 );
|
rob@76
|
358
|
rob@76
|
359 bool sendPing = false;
|
rob@76
|
360
|
rob@76
|
361 if( executeNowIgnoringTimeouts ){
|
rob@76
|
362
|
rob@76
|
363 sendPing = true;
|
rob@76
|
364
|
rob@76
|
365 }else{
|
rob@76
|
366
|
rob@76
|
367 if( peerEndpointToUse->sentPingsCount == 0 ){
|
rob@76
|
368
|
rob@76
|
369 sendPing = true;
|
rob@76
|
370
|
rob@76
|
371 }else{
|
rob@76
|
372
|
rob@76
|
373 int secondsSinceLastPing = (int)std::difftime(currentTime, peerEndpointToUse->lastPingSendTime);
|
rob@76
|
374
|
rob@76
|
375 if( peerEndpointToUse->forwardedPacketsCount == 0 ){
|
rob@76
|
376
|
rob@76
|
377 if( secondsSinceLastPing >= IDLE_PING_PERIOD_SECONDS ){
|
rob@76
|
378
|
rob@76
|
379 sendPing = true;
|
rob@76
|
380 }
|
rob@76
|
381
|
rob@76
|
382 }else{
|
rob@76
|
383
|
rob@76
|
384 int secondsSinceLastForwardedTraffic =
|
rob@76
|
385 (int)std::difftime(currentTime, peerEndpointToUse->lastPacketForwardTime);
|
rob@76
|
386
|
rob@76
|
387 if( secondsSinceLastForwardedTraffic >= IDLE_PING_PERIOD_SECONDS ){
|
rob@76
|
388
|
rob@76
|
389 if( secondsSinceLastPing >= IDLE_PING_PERIOD_SECONDS ){
|
rob@76
|
390 sendPing = true;
|
rob@76
|
391 }
|
rob@76
|
392
|
rob@76
|
393 }else if( secondsSinceLastPing >= ACTIVE_PING_PERIOD_SECONDS ){
|
rob@76
|
394 sendPing = true;
|
rob@76
|
395 }
|
rob@76
|
396 }
|
rob@76
|
397 }
|
rob@76
|
398 }
|
rob@76
|
399
|
rob@76
|
400 if( sendPing ){
|
rob@76
|
401 SendPing( *peerEndpointToUse, currentTime );
|
rob@76
|
402 peer.lastPingPeriodTime = currentTime;
|
rob@76
|
403 ++peer.pingPeriodCount;
|
rob@76
|
404 }
|
rob@76
|
405 }
|
rob@76
|
406 }
|
rob@76
|
407
|
rob@76
|
408 ExternalCommunicationsSender(); // no default ctor
|
rob@76
|
409 ExternalCommunicationsSender( const ExternalCommunicationsSender& ); // no copy ctor
|
rob@76
|
410 ExternalCommunicationsSender& operator=( const ExternalCommunicationsSender& ); // no assignment operator
|
rob@76
|
411
|
rob@76
|
412 public:
|
rob@76
|
413 ExternalCommunicationsSender( UdpSocket& externalSocket,
|
rob@76
|
414 IpEndpointName remoteServerEndpoint,
|
rob@76
|
415 int localToRemotePort,
|
rob@76
|
416 const char *userName, const char *userPassword,
|
rob@76
|
417 const char *groupName, const char *groupPassword )
|
rob@76
|
418 : lastAliveSentTime_( 0 )
|
rob@76
|
419 , externalSocket_( externalSocket )
|
rob@76
|
420 , remoteServerEndpoint_( remoteServerEndpoint )
|
rob@76
|
421 , localToServerEndpoint_(
|
rob@76
|
422 externalSocket.LocalEndpointFor( remoteServerEndpoint ).address,
|
rob@76
|
423 localToRemotePort )
|
rob@76
|
424 , userName_( userName )
|
rob@76
|
425 , userPassword_( userPassword )
|
rob@76
|
426 , groupName_( groupName )
|
rob@76
|
427 , groupPassword_( groupPassword )
|
rob@76
|
428 {
|
rob@76
|
429 PrepareAliveBuffer();
|
rob@76
|
430 PreparePingBuffer();
|
rob@76
|
431 }
|
rob@76
|
432
|
rob@76
|
433
|
rob@76
|
434 void RestartPeerCommunicationEstablishment( Peer& peer, std::time_t currentTime )
|
rob@76
|
435 {
|
rob@76
|
436 peer.pingPeriodCount = 0;
|
rob@76
|
437 PollPeerPingTimer( peer, currentTime, true );
|
rob@76
|
438 }
|
rob@76
|
439
|
rob@76
|
440
|
rob@76
|
441 void ForwardPacketToAllPeers( const char *data, int size )
|
rob@76
|
442 {
|
rob@76
|
443 std::time_t currentTime = std::time(0);
|
rob@76
|
444
|
rob@76
|
445 for( std::vector<Peer>::iterator i = peers_.begin(); i != peers_.end(); ++i ){
|
rob@76
|
446
|
rob@76
|
447 PeerEndpoint *peerEndpointToUse = SelectEndpoint( *i );
|
rob@76
|
448 if( peerEndpointToUse ){
|
rob@76
|
449 externalSocket_.SendTo( peerEndpointToUse->endpointName, data, size );
|
rob@76
|
450 ++peerEndpointToUse->forwardedPacketsCount;
|
rob@76
|
451 peerEndpointToUse->lastPacketForwardTime = currentTime;
|
rob@76
|
452 }
|
rob@76
|
453 }
|
rob@76
|
454 }
|
rob@76
|
455
|
rob@76
|
456
|
rob@76
|
457 virtual void TimerExpired()
|
rob@76
|
458 {
|
rob@76
|
459 std::time_t currentTime = std::time(0);
|
rob@76
|
460
|
rob@76
|
461 SendAlive( currentTime );
|
rob@76
|
462
|
rob@76
|
463 // check for peers to purge,
|
rob@76
|
464 std::vector<Peer>::iterator i = peers_.begin();
|
rob@76
|
465 while( i != peers_.end() ){
|
rob@76
|
466
|
rob@76
|
467 if( std::difftime(currentTime,i->MostRecentActivityTime()) > PURGE_PEER_TIMEOUT_SECONDS ){
|
rob@76
|
468
|
rob@76
|
469 i = peers_.erase( i );
|
rob@76
|
470
|
rob@76
|
471 }else{
|
rob@76
|
472 PollPeerPingTimer( *i, currentTime );
|
rob@76
|
473 ++i;
|
rob@76
|
474 }
|
rob@76
|
475 }
|
rob@76
|
476 }
|
rob@76
|
477 };
|
rob@76
|
478
|
rob@76
|
479
|
rob@76
|
480 class ExternalSocketListener : public osc::OscPacketListener {
|
rob@76
|
481
|
rob@76
|
482 void user_alive_status( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
|
rob@76
|
483 {
|
rob@76
|
484 // only accept user_alive_status from the server
|
rob@76
|
485 if( remoteEndpoint != remoteServerEndpoint_ )
|
rob@76
|
486 return;
|
rob@76
|
487
|
rob@76
|
488 // /groupclient/user_alive_status userName userPassword status
|
rob@76
|
489
|
rob@76
|
490 osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
rob@76
|
491
|
rob@76
|
492 const char *userName, *userPassword, *status;
|
rob@76
|
493
|
rob@76
|
494 args >> userName >> userPassword >> status;
|
rob@76
|
495
|
rob@76
|
496 if( std::strcmp( userName, userName_ ) == 0
|
rob@76
|
497 && std::strcmp( userPassword, userPassword_ ) == 0 ){
|
rob@76
|
498 // message really is for us
|
rob@76
|
499
|
rob@76
|
500 if( std::strcmp( status, "ok" ) == 0 ){
|
rob@76
|
501
|
rob@76
|
502 std::cout << "ok: user '" << userName << "' is registered with server\n";
|
rob@76
|
503
|
rob@76
|
504 }else{
|
rob@76
|
505 std::cout << "user registration error: server returned status of '" << status
|
rob@76
|
506 << "' for user '" << userName << "'\n";
|
rob@76
|
507 }
|
rob@76
|
508 }
|
rob@76
|
509 }
|
rob@76
|
510
|
rob@76
|
511 void user_group_status( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
|
rob@76
|
512 {
|
rob@76
|
513 // only accept user_alive_status from the server
|
rob@76
|
514 if( remoteEndpoint != remoteServerEndpoint_ )
|
rob@76
|
515 return;
|
rob@76
|
516
|
rob@76
|
517 // /groupclient/user_group_status userName userPassword groupName groupPassword status
|
rob@76
|
518
|
rob@76
|
519 osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
rob@76
|
520
|
rob@76
|
521 const char *userName, *userPassword, *groupName, *groupPassword, *status;
|
rob@76
|
522
|
rob@76
|
523 args >> userName >> userPassword >> groupName >> groupPassword >> status;
|
rob@76
|
524
|
rob@76
|
525 if( std::strcmp( userName, userName_ ) == 0
|
rob@76
|
526 && std::strcmp( userPassword, userPassword_ ) == 0
|
rob@76
|
527 && std::strcmp( groupName, groupName_ ) == 0
|
rob@76
|
528 && std::strcmp( groupPassword, groupPassword_ ) == 0 ){
|
rob@76
|
529 // message really is for us
|
rob@76
|
530
|
rob@76
|
531 if( std::strcmp( status, "ok" ) == 0 ){
|
rob@76
|
532
|
rob@76
|
533 std::cout << "ok: user '" << userName << "' is a member of group '" << groupName << "'\n";
|
rob@76
|
534
|
rob@76
|
535 }else{
|
rob@76
|
536 std::cout << "group membership error: server returned status of '" << status
|
rob@76
|
537 << "' for user '" << userName
|
rob@76
|
538 << "' membership of group '" << groupName << "'\n";
|
rob@76
|
539 }
|
rob@76
|
540 }
|
rob@76
|
541 }
|
rob@76
|
542
|
rob@76
|
543 void user_info( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
|
rob@76
|
544 {
|
rob@76
|
545 // only accept user_info from the server
|
rob@76
|
546 if( remoteEndpoint != remoteServerEndpoint_ )
|
rob@76
|
547 return;
|
rob@76
|
548
|
rob@76
|
549 // /groupclient/user_info userName privateIpAddress privatePort
|
rob@76
|
550 // publicIpAddress publicPort secondsSinceLastAlive group0 group1 ...
|
rob@76
|
551
|
rob@76
|
552 osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
rob@76
|
553
|
rob@76
|
554 const char *userName;
|
rob@76
|
555 osc::int32 privateAddress;
|
rob@76
|
556 osc::int32 privatePort;
|
rob@76
|
557 osc::int32 publicAddress;
|
rob@76
|
558 osc::int32 publicPort;
|
rob@76
|
559 osc::int32 secondsSinceLastAlive;
|
rob@76
|
560
|
rob@76
|
561 args >> userName >> privateAddress >> privatePort >>
|
rob@76
|
562 publicAddress >> publicPort >> secondsSinceLastAlive;
|
rob@76
|
563
|
rob@76
|
564 // addresses are transmitted as ones complement (bit inverse)
|
rob@76
|
565 // to avoid problems with buggy NATs trying to re-write addresses
|
rob@76
|
566 privateAddress = ~privateAddress;
|
rob@76
|
567 publicAddress = ~publicAddress;
|
rob@76
|
568
|
rob@76
|
569 IpEndpointName privateEndpoint( privateAddress, privatePort );
|
rob@76
|
570 IpEndpointName publicEndpoint( publicAddress, publicPort );
|
rob@76
|
571
|
rob@76
|
572 char privateAddressString[ IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH ];
|
rob@76
|
573 privateEndpoint.AddressAndPortAsString( privateAddressString );
|
rob@76
|
574 char publicAddressString[ IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH ];
|
rob@76
|
575 publicEndpoint.AddressAndPortAsString( publicAddressString );
|
rob@76
|
576
|
rob@76
|
577 std::cout << "user info received for '" << userName << "', "
|
rob@76
|
578 << "private: " << privateAddressString
|
rob@76
|
579 << " public: " << publicAddressString
|
rob@76
|
580 << "\n";
|
rob@76
|
581
|
rob@76
|
582 if( std::strcmp( userName, userName_ ) == 0 )
|
rob@76
|
583 return; // discard info referring to ourselves
|
rob@76
|
584
|
rob@76
|
585
|
rob@76
|
586 bool userIsInGroup = false;
|
rob@76
|
587 while( !args.Eos() ){
|
rob@76
|
588 const char *groupName;
|
rob@76
|
589 args >> groupName;
|
rob@76
|
590 if( std::strcmp( groupName, groupName_ ) == 0 ){
|
rob@76
|
591 userIsInGroup = true;
|
rob@76
|
592 break;
|
rob@76
|
593 }
|
rob@76
|
594 }
|
rob@76
|
595
|
rob@76
|
596
|
rob@76
|
597 if( userIsInGroup ){
|
rob@76
|
598 bool restartPeerCommunicationEstablishment = false;
|
rob@76
|
599
|
rob@76
|
600 bool found = false;
|
rob@76
|
601 std::vector<Peer>::iterator peer;
|
rob@76
|
602 for( std::vector<Peer>::iterator i = peers_.begin(); i != peers_.end(); ++i ){
|
rob@76
|
603
|
rob@76
|
604 if( i->name.compare( userName ) == 0 ){
|
rob@76
|
605 peer = i;
|
rob@76
|
606 found = true;
|
rob@76
|
607 break;
|
rob@76
|
608 }
|
rob@76
|
609 }
|
rob@76
|
610
|
rob@76
|
611 if( !found ){
|
rob@76
|
612 peers_.push_back( Peer( userName ) );
|
rob@76
|
613 peer = peers_.end() - 1;
|
rob@76
|
614 restartPeerCommunicationEstablishment = true;
|
rob@76
|
615 }
|
rob@76
|
616
|
rob@76
|
617 if( peer->privateEndpoint.endpointName != privateEndpoint ){
|
rob@76
|
618 peer->privateEndpoint.endpointName = privateEndpoint;
|
rob@76
|
619 peer->privateEndpoint.pingReceived = false;
|
rob@76
|
620 peer->privateEndpoint.forwardedPacketsCount = 0;
|
rob@76
|
621 peer->pingEndpoint.pingReceived = false;
|
rob@76
|
622 peer->pingEndpoint.forwardedPacketsCount = 0;
|
rob@76
|
623 restartPeerCommunicationEstablishment = true;
|
rob@76
|
624 }
|
rob@76
|
625
|
rob@76
|
626 if( peer->publicEndpoint.endpointName != publicEndpoint ){
|
rob@76
|
627 peer->publicEndpoint.endpointName = publicEndpoint;
|
rob@76
|
628 peer->publicEndpoint.pingReceived = false;
|
rob@76
|
629 peer->publicEndpoint.forwardedPacketsCount = 0;
|
rob@76
|
630 peer->pingEndpoint.pingReceived = false;
|
rob@76
|
631 peer->pingEndpoint.forwardedPacketsCount = 0;
|
rob@76
|
632 restartPeerCommunicationEstablishment = true;
|
rob@76
|
633 }
|
rob@76
|
634
|
rob@76
|
635
|
rob@76
|
636 peer->secondsSinceLastAliveReceivedByServer = secondsSinceLastAlive;
|
rob@76
|
637
|
rob@76
|
638 std::time_t currentTime = std::time(0);
|
rob@76
|
639 peer->lastUserInfoReceiveTime = currentTime;
|
rob@76
|
640
|
rob@76
|
641 if( restartPeerCommunicationEstablishment )
|
rob@76
|
642 externalCommunicationsSender_.RestartPeerCommunicationEstablishment( *peer, currentTime );
|
rob@76
|
643
|
rob@76
|
644 }else{
|
rob@76
|
645 // fixme should remove user from peer list if it is present
|
rob@76
|
646 }
|
rob@76
|
647 }
|
rob@76
|
648
|
rob@76
|
649 void ping( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint )
|
rob@76
|
650 {
|
rob@76
|
651 osc::ReceivedMessageArgumentStream args = m.ArgumentStream();
|
rob@76
|
652
|
rob@76
|
653 const char *userName;
|
rob@76
|
654 // osc::TimeTag timeSent;
|
rob@76
|
655
|
rob@76
|
656 // TODO:
|
rob@76
|
657 // support 3 variants of the ping message:
|
rob@76
|
658 // /ping userName (basic version, only one needed for compatibility)
|
rob@76
|
659 // /ping userName timeSent
|
rob@76
|
660 // response -> /ping userName timeSent inResponseToUserName inResponseToTimeSent
|
rob@76
|
661
|
rob@76
|
662 args >> userName >> osc::EndMessage;
|
rob@76
|
663
|
rob@76
|
664 char sourceAddressString[ IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH ];
|
rob@76
|
665 remoteEndpoint.AddressAndPortAsString( sourceAddressString );
|
rob@76
|
666
|
rob@76
|
667 std::cout << "ping recieved from '" << userName << "' at "
|
rob@76
|
668 << sourceAddressString << "\n";
|
rob@76
|
669
|
rob@76
|
670 for( std::vector<Peer>::iterator i = peers_.begin(); i != peers_.end(); ++i ){
|
rob@76
|
671
|
rob@76
|
672 if( i->name.compare( userName ) == 0 ){
|
rob@76
|
673 bool restartPeerCommunicationEstablishment = false;
|
rob@76
|
674
|
rob@76
|
675 std::time_t currentTime = std::time(0);
|
rob@76
|
676
|
rob@76
|
677 if( remoteEndpoint == i->privateEndpoint.endpointName ){
|
rob@76
|
678
|
rob@76
|
679 restartPeerCommunicationEstablishment = !i->privateEndpoint.pingReceived;
|
rob@76
|
680 i->privateEndpoint.pingReceived = true;
|
rob@76
|
681 i->privateEndpoint.lastPingReceiveTime = currentTime;
|
rob@76
|
682
|
rob@76
|
683 }else if( remoteEndpoint == i->publicEndpoint.endpointName ){
|
rob@76
|
684
|
rob@76
|
685 restartPeerCommunicationEstablishment = !i->publicEndpoint.pingReceived;
|
rob@76
|
686 i->publicEndpoint.pingReceived = true;
|
rob@76
|
687 i->publicEndpoint.lastPingReceiveTime = currentTime;
|
rob@76
|
688
|
rob@76
|
689 }else{
|
rob@76
|
690 // otherwise assume the messages is coming from the ping endpoint
|
rob@76
|
691
|
rob@76
|
692 restartPeerCommunicationEstablishment = ( !i->pingEndpoint.pingReceived
|
rob@76
|
693 || i->pingEndpoint.endpointName != remoteEndpoint );
|
rob@76
|
694
|
rob@76
|
695 i->pingEndpoint.endpointName = remoteEndpoint;
|
rob@76
|
696 i->pingEndpoint.pingReceived = true;
|
rob@76
|
697 i->pingEndpoint.lastPingReceiveTime = currentTime;
|
rob@76
|
698 }
|
rob@76
|
699
|
rob@76
|
700 if( restartPeerCommunicationEstablishment )
|
rob@76
|
701 externalCommunicationsSender_.RestartPeerCommunicationEstablishment( *i, currentTime );
|
rob@76
|
702
|
rob@76
|
703 break;
|
rob@76
|
704 }
|
rob@76
|
705 }
|
rob@76
|
706 }
|
rob@76
|
707
|
rob@76
|
708 protected:
|
rob@76
|
709
|
rob@76
|
710 virtual void ProcessMessage( const osc::ReceivedMessage& m,
|
rob@76
|
711 const IpEndpointName& remoteEndpoint )
|
rob@76
|
712 {
|
rob@76
|
713 try{
|
rob@76
|
714
|
rob@76
|
715 if( std::strcmp( m.AddressPattern(), "/groupclient/user_info" ) == 0 ){
|
rob@76
|
716 user_info( m, remoteEndpoint );
|
rob@76
|
717 }else if( std::strcmp( m.AddressPattern(), "/groupclient/ping" ) == 0 ){
|
rob@76
|
718 ping( m, remoteEndpoint );
|
rob@76
|
719 }else if( std::strcmp( m.AddressPattern(), "/groupclient/user_alive_status" ) == 0 ){
|
rob@76
|
720 user_alive_status( m, remoteEndpoint );
|
rob@76
|
721 }else if( std::strcmp( m.AddressPattern(), "/groupclient/user_group_status" ) == 0 ){
|
rob@76
|
722 user_group_status( m, remoteEndpoint );
|
rob@76
|
723 }
|
rob@76
|
724
|
rob@76
|
725 }catch( osc::Exception& e ){
|
rob@76
|
726 std::cout << "error while parsing message: " << e.what() << "\n";
|
rob@76
|
727 }
|
rob@76
|
728 }
|
rob@76
|
729
|
rob@76
|
730 IpEndpointName remoteServerEndpoint_;
|
rob@76
|
731
|
rob@76
|
732 const char *userName_;
|
rob@76
|
733 const char *userPassword_;
|
rob@76
|
734 const char *groupName_;
|
rob@76
|
735 const char *groupPassword_;
|
rob@76
|
736
|
rob@76
|
737 UdpTransmitSocket localRxSocket_;
|
rob@76
|
738
|
rob@76
|
739 ExternalCommunicationsSender& externalCommunicationsSender_;
|
rob@76
|
740
|
rob@76
|
741 ExternalSocketListener(); // no default ctor
|
rob@76
|
742 ExternalSocketListener( const ExternalSocketListener& ); // no copy ctor
|
rob@76
|
743 ExternalSocketListener& operator=( const ExternalSocketListener& ); // no assignment operator
|
rob@76
|
744
|
rob@76
|
745 public:
|
rob@76
|
746 ExternalSocketListener( const IpEndpointName& remoteServerEndpoint,
|
rob@76
|
747 int localRxPort, const char *userName, const char *userPassword,
|
rob@76
|
748 const char *groupName, const char *groupPassword,
|
rob@76
|
749 ExternalCommunicationsSender& externalCommunicationsSender )
|
rob@76
|
750 : remoteServerEndpoint_( remoteServerEndpoint )
|
rob@76
|
751 , userName_( userName )
|
rob@76
|
752 , userPassword_( userPassword )
|
rob@76
|
753 , groupName_( groupName )
|
rob@76
|
754 , groupPassword_( groupPassword )
|
rob@76
|
755 , localRxSocket_( IpEndpointName( "localhost", localRxPort ) )
|
rob@76
|
756 , externalCommunicationsSender_( externalCommunicationsSender )
|
rob@76
|
757 {
|
rob@76
|
758 }
|
rob@76
|
759
|
rob@76
|
760 virtual void ProcessPacket( const char *data, int size,
|
rob@76
|
761 const IpEndpointName& remoteEndpoint )
|
rob@76
|
762 {
|
rob@76
|
763 // for now we parse _all_ packets, and pass all those on to clients
|
rob@76
|
764 // except those which come from the server. ideally we should avoid
|
rob@76
|
765 // parsing most packets except the ones containing pings, or perhaps
|
rob@76
|
766 // only process non-bundled pings.
|
rob@76
|
767
|
rob@76
|
768 // in the future it could be useful to register which peer a packet
|
rob@76
|
769 // is coming from so that we can keep track of channel activity
|
rob@76
|
770 // not just by receiving pings but also by recieving other traffic
|
rob@76
|
771 // this would also allow us to reject packets from unknown sources
|
rob@76
|
772
|
rob@76
|
773
|
rob@76
|
774 osc::OscPacketListener::ProcessPacket( data, size, remoteEndpoint );
|
rob@76
|
775
|
rob@76
|
776 if( remoteEndpoint != remoteServerEndpoint_ ){
|
rob@76
|
777
|
rob@76
|
778 // forward packet to local receive socket
|
rob@76
|
779
|
rob@76
|
780 localRxSocket_.Send( data, size );
|
rob@76
|
781 }
|
rob@76
|
782 }
|
rob@76
|
783 };
|
rob@76
|
784
|
rob@76
|
785
|
rob@76
|
786 class LocalTxSocketListener : public PacketListener {
|
rob@76
|
787
|
rob@76
|
788 ExternalCommunicationsSender& externalCommunicationsSender_;
|
rob@76
|
789
|
rob@76
|
790 LocalTxSocketListener(); // no default ctor
|
rob@76
|
791 LocalTxSocketListener( const LocalTxSocketListener& ); // no copy ctor
|
rob@76
|
792 LocalTxSocketListener& operator=( const LocalTxSocketListener& ); // no assignment operator
|
rob@76
|
793
|
rob@76
|
794 public:
|
rob@76
|
795 LocalTxSocketListener( ExternalCommunicationsSender& externalCommunicationsSender )
|
rob@76
|
796 : externalCommunicationsSender_( externalCommunicationsSender )
|
rob@76
|
797 {
|
rob@76
|
798 }
|
rob@76
|
799
|
rob@76
|
800 virtual void ProcessPacket( const char *data, int size,
|
rob@76
|
801 const IpEndpointName& remoteEndpoint )
|
rob@76
|
802 {
|
rob@76
|
803 (void) remoteEndpoint; // suppress unused parameter warning
|
rob@76
|
804 externalCommunicationsSender_.ForwardPacketToAllPeers( data, size );
|
rob@76
|
805 }
|
rob@76
|
806 };
|
rob@76
|
807
|
rob@76
|
808
|
rob@76
|
809 char IntToHexDigit( int n )
|
rob@76
|
810 {
|
rob@76
|
811 if( n < 10 )
|
rob@76
|
812 return (char)('0' + n);
|
rob@76
|
813 else
|
rob@76
|
814 return (char)('a' + (n-10));
|
rob@76
|
815 }
|
rob@76
|
816
|
rob@76
|
817 void MakeHashString( char *dest, const char *src )
|
rob@76
|
818 {
|
rob@76
|
819 MD5_CTX md5Context;
|
rob@76
|
820 MD5Init( &md5Context );
|
rob@76
|
821 MD5Update( &md5Context, (unsigned char*)src, (unsigned int)std::strlen(src) );
|
rob@76
|
822 unsigned char numericHash[16];
|
rob@76
|
823 MD5Final( numericHash, &md5Context );
|
rob@76
|
824 char *p = dest;
|
rob@76
|
825 for( int i=0; i < 16; ++i ){
|
rob@76
|
826
|
rob@76
|
827 *p++ = IntToHexDigit(((unsigned char)numericHash[i] >> 4) & 0x0F);
|
rob@76
|
828 *p++ = IntToHexDigit((unsigned char)numericHash[i] & 0x0F);
|
rob@76
|
829 }
|
rob@76
|
830 *p = '\0';
|
rob@76
|
831
|
rob@76
|
832 //printf( "src: %s dest: %s\n", src, dest );
|
rob@76
|
833 }
|
rob@76
|
834
|
rob@76
|
835 void SanityCheckMd5()
|
rob@76
|
836 {
|
rob@76
|
837 // if anything in this function fails there's a problem with your build configuration
|
rob@76
|
838
|
rob@76
|
839 // check that the size of types declared in md5.h are correct
|
rob@76
|
840 assert( sizeof(UINT2) == 2 );
|
rob@76
|
841 assert( sizeof(UINT4) == 4 );
|
rob@76
|
842
|
rob@76
|
843 // sanity check that the hash is working by comparing to a known good hash:
|
rob@76
|
844 char testHash[33];
|
rob@76
|
845 MakeHashString( testHash, "0123456789" );
|
rob@76
|
846 assert( std::strcmp( testHash, "781e5e245d69b566979b86e28d23f2c7" ) == 0 );
|
rob@76
|
847 }
|
rob@76
|
848
|
rob@76
|
849 void RunOscGroupClientUntilSigInt(
|
rob@76
|
850 const IpEndpointName& serverRemoteEndpoint,
|
rob@76
|
851 int localToRemotePort, int localTxPort, int localRxPort,
|
rob@76
|
852 const char *userName, const char *userPassword,
|
rob@76
|
853 const char *groupName, const char *groupPassword )
|
rob@76
|
854 {
|
rob@76
|
855 // used hashed passwords instead of the user supplied ones
|
rob@76
|
856
|
rob@76
|
857 char userPasswordHash[33];
|
rob@76
|
858 MakeHashString( userPasswordHash, userPassword );
|
rob@76
|
859
|
rob@76
|
860 char groupPasswordHash[33];
|
rob@76
|
861 MakeHashString( groupPasswordHash, groupPassword );
|
rob@76
|
862
|
rob@76
|
863 UdpReceiveSocket externalSocket(
|
rob@76
|
864 IpEndpointName( IpEndpointName::ANY_ADDRESS, localToRemotePort ) );
|
rob@76
|
865
|
rob@76
|
866 UdpReceiveSocket localTxSocket( localTxPort );
|
rob@76
|
867
|
rob@76
|
868 ExternalCommunicationsSender externalCommunicationsSender( externalSocket,
|
rob@76
|
869 serverRemoteEndpoint, localToRemotePort,
|
rob@76
|
870 userName, userPasswordHash, groupName, groupPasswordHash );
|
rob@76
|
871
|
rob@76
|
872 ExternalSocketListener externalSocketListener(
|
rob@76
|
873 serverRemoteEndpoint, localRxPort,
|
rob@76
|
874 userName, userPasswordHash, groupName, groupPasswordHash,
|
rob@76
|
875 externalCommunicationsSender );
|
rob@76
|
876
|
rob@76
|
877 LocalTxSocketListener localTxSocketListener( externalCommunicationsSender );
|
rob@76
|
878
|
rob@76
|
879 SocketReceiveMultiplexer mux;
|
rob@76
|
880 mux.AttachPeriodicTimerListener( 0, (IDLE_PING_PERIOD_SECONDS * 1000) / 10, &externalCommunicationsSender );
|
rob@76
|
881 mux.AttachSocketListener( &externalSocket, &externalSocketListener );
|
rob@76
|
882 mux.AttachSocketListener( &localTxSocket, &localTxSocketListener );
|
rob@76
|
883
|
rob@76
|
884 std::cout << "running...\n";
|
rob@76
|
885 std::cout << "press ctrl-c to end\n";
|
rob@76
|
886
|
rob@76
|
887 mux.RunUntilSigInt();
|
rob@76
|
888
|
rob@76
|
889 std::cout << "finishing.\n";
|
rob@76
|
890 }
|
rob@76
|
891
|
rob@76
|
892
|
rob@76
|
893 int oscgroupclient_main(int argc, char* argv[])
|
rob@76
|
894 {
|
rob@76
|
895 SanityCheckMd5();
|
rob@76
|
896
|
rob@76
|
897 try{
|
rob@76
|
898 if( argc != 10 ){
|
rob@76
|
899 std::cout << "usage: oscgroupclient serveraddress serverport localtoremoteport localtxport localrxport username password groupname grouppassword\n";
|
rob@76
|
900 std::cout << "users should send data to localhost:localtxport and listen on localhost:localrxport\n";
|
rob@76
|
901 return 0;
|
rob@76
|
902 }
|
rob@76
|
903
|
rob@76
|
904 IpEndpointName serverRemoteEndpoint( argv[1], atoi( argv[2] ) );
|
rob@76
|
905 int localToRemotePort = std::atoi( argv[3] );
|
rob@76
|
906 int localTxPort = std::atoi( argv[4] );
|
rob@76
|
907 int localRxPort = std::atoi( argv[5] );
|
rob@76
|
908 const char *userName = argv[6];
|
rob@76
|
909 const char *userPassword = argv[7];
|
rob@76
|
910 const char *groupName = argv[8];
|
rob@76
|
911 const char *groupPassword = argv[9];
|
rob@76
|
912
|
rob@76
|
913 char serverAddressString[ IpEndpointName::ADDRESS_AND_PORT_STRING_LENGTH ];
|
rob@76
|
914 serverRemoteEndpoint.AddressAndPortAsString( serverAddressString );
|
rob@76
|
915
|
rob@76
|
916 std::cout << "oscgroupclient\n";
|
rob@76
|
917 std::cout << "connecting to group '" << groupName << "' as user '" << userName << "'.\n";
|
rob@76
|
918 std::cout << "using server at " << serverAddressString
|
rob@76
|
919 << " with external traffic on local port " << localToRemotePort << "\n";
|
rob@76
|
920 std::cout << "--> send outbound traffic to localhost port " << localTxPort << "\n";
|
rob@76
|
921 std::cout << "<-- listen for inbound traffic on localhost port " << localRxPort << "\n";
|
rob@76
|
922
|
rob@76
|
923 RunOscGroupClientUntilSigInt( serverRemoteEndpoint, localToRemotePort,
|
rob@76
|
924 localTxPort, localRxPort, userName, userPassword, groupName, groupPassword );
|
rob@76
|
925
|
rob@76
|
926 }catch( std::exception& e ){
|
rob@76
|
927 std::cout << e.what() << std::endl;
|
rob@76
|
928 }
|
rob@76
|
929
|
rob@76
|
930 return 0;
|
rob@76
|
931 }
|
rob@76
|
932
|
rob@76
|
933
|
rob@76
|
934 #ifndef NO_MAIN
|
rob@76
|
935
|
rob@76
|
936 int main(int argc, char* argv[])
|
rob@76
|
937 {
|
rob@76
|
938 return oscgroupclient_main( argc, argv );
|
rob@76
|
939 }
|
rob@76
|
940
|
rob@76
|
941 #endif /* NO_MAIN */
|
rob@76
|
942
|