VANetServerImpl.cpp 26.3 KB
Newer Older
Jonas Stienen's avatar
Jonas Stienen committed
1
/*
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
2
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
3
 *
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
4
5
6
 *    VVV        VVV A           Virtual Acoustics (VA) | http://www.virtualacoustics.org
 *     VVV      VVV AAA          Licensed under the Apache License, Version 2.0
 *      VVV    VVV   AAA
7
 *       VVV  VVV     AAA        Copyright 2015-2020
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
8
9
 *        VVVVVV       AAA       Institute of Technical Acoustics (ITA)
 *         VVVV         AAA      RWTH Aachen University
Jonas Stienen's avatar
Jonas Stienen committed
10
 *
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
11
 *  --------------------------------------------------------------------------------------------
Jonas Stienen's avatar
Jonas Stienen committed
12
 */
13

Jonas Stienen's avatar
Jonas Stienen committed
14
15
16
17
18
19
#include "VANetServerImpl.h"

#include "VANetNetworkProtocol.h"
#include "VANetMessage.h"
#include "VANetVistaCompatibility.h"

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
20
#include <VA.h>
Jonas Stienen's avatar
Jonas Stienen committed
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <VistaInterProcComm/Concurrency/VistaThreadLoop.h>
#include <VistaInterProcComm/Connections/VistaConnectionIP.h>
#include <VistaInterProcComm/Concurrency/VistaMutex.h>
#include <VistaInterProcComm/IPNet/VistaTCPServer.h>
#include <VistaInterProcComm/IPNet/VistaTCPSocket.h>
#include <VistaInterProcComm/AsyncIO/VistaIOHandleBasedMultiplexer.h>

#include <VistaBase/VistaTimerImp.h>
#include <VistaBase/VistaDefaultTimerImp.h>
#include <VistaBase/VistaExceptionBase.h>

#include <cassert>
#include <algorithm>


/***********************************************************************/
/**** class CConnectionAccepter                                     ****/
/***********************************************************************/
40

Jonas Stienen's avatar
Jonas Stienen committed
41
42
43
class CVANetServerImpl::CConnectionAccepter : public VistaThreadLoop
{
public:
44
45
46
47
48
	inline CConnectionAccepter( CVANetServerImpl* pParent, const std::string& sServerIP, const unsigned int iServerPort )
		: VistaThreadLoop()
		, m_pParent( pParent )
		, m_sServerIP( sServerIP )
		, m_iServerPort( iServerPort )
Jonas Stienen's avatar
Jonas Stienen committed
49
50
51
52
53
54
	{
		SetThreadName( "VAServer::ConnectionAccepter" );

		m_pServer = new VistaTCPServer( m_sServerIP, m_iServerPort, 3 );
		if( m_pServer->GetIsValid() )
		{
55
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
56
57
58
59
60
61
			std::cout << "VA Server: listening for client connections on IP "
				<< m_sServerIP << ":" << m_iServerPort << std::endl;
#endif
		}
		else
		{
62
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
63
64
65
66
			std::cerr << "VA Server: could not establish client connector socket on IP "
				<< m_sServerIP << ":" << m_iServerPort << std::endl;
#endif
		}
67
	};
Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
68

69
	inline ~CConnectionAccepter()
Jonas Stienen's avatar
Jonas Stienen committed
70
71
	{
		delete m_pServer;
72
	};
Jonas Stienen's avatar
Jonas Stienen committed
73

74
	inline bool GetIsValid()
Jonas Stienen's avatar
Jonas Stienen committed
75
76
	{
		return m_pServer->GetIsValid();
77
	};
Jonas Stienen's avatar
Jonas Stienen committed
78

79
	inline virtual bool LoopBody()
Jonas Stienen's avatar
Jonas Stienen committed
80
81
82
83
84
85
86
	{
		if( m_pServer->GetIsValid() == false )
		{
			std::cerr << "VA Server: Connection Accepter failed - TCPServer is invalid" << std::endl;
			IndicateLoopEnd();
			return false;
		}
87

Jonas Stienen's avatar
Jonas Stienen committed
88
89
90
91
92
93
94
		VistaTCPSocket* pSocket = m_pServer->GetNextClient( 3 );
		if( pSocket == NULL )
		{
			std::cerr << "VA Server: Connection Accepter failed - TCPServer returned invalid socket" << std::endl;
			IndicateLoopEnd();
			return false;
		}
95

Jonas Stienen's avatar
Jonas Stienen committed
96
97
98
99
100
101
		VistaConnectionIP* pConnection = new VistaConnectionIP( pSocket );
		pConnection->SetIsBlocking( true );
		pConnection->SetByteorderSwapFlag( VistaSerializingToolset::DOES_NOT_SWAP_MULTIBYTE_VALUES );
		m_pParent->AddNewClient( pConnection );
		pConnection->Close();
		delete pConnection;
102

Jonas Stienen's avatar
Jonas Stienen committed
103
		return false;
104
	};
Jonas Stienen's avatar
Jonas Stienen committed
105

106
107
108
	inline virtual void PreLoop()
	{
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
109
110
		std::cout << "VA Server: starting connection accepter thread\n" << std::flush;
#endif
111
	};
Jonas Stienen's avatar
Jonas Stienen committed
112

113
	inline virtual void PostLoop()
Jonas Stienen's avatar
Jonas Stienen committed
114
	{
115
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
116
117
118
119
		std::cout << "VA Server: stopping connection accepter thread\n" << std::flush;
#endif
		m_pServer->StopAccept();
		delete m_pServer;
120
121
	};

Jonas Stienen's avatar
Jonas Stienen committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
private:
	VistaTCPServer*				m_pServer;
	std::string					m_sServerIP;
	unsigned int				m_iServerPort;

	CVANetServerImpl*	m_pParent;
};

/***********************************************************************/
/**** class CConnectionObserver                                     ****/
/***********************************************************************/

class CVANetServerImpl::CConnectionObserver : public VistaThreadLoop
{
public:
137
138
139
140
141
142
	CConnectionObserver( CVANetServerImpl* pParent, CVANetNetworkProtocol* pProtocol )
		: VistaThreadLoop()
		, m_pParent( pParent )
		, m_oConnMultiplexer()
		, m_iIDCounter( 2 ) // our minumum ticket number
		, m_pProtocol( pProtocol )
Jonas Stienen's avatar
Jonas Stienen committed
143
144
145
146
	{
		SetThreadName( "VAServer::ConnectionObserver" );
	}

147
	inline bool AddObservedConnection( VistaConnectionIP* pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
148
	{
149
		m_mapConnections[ m_iIDCounter ] = pConnection;
Jonas Stienen's avatar
Jonas Stienen committed
150
		if( m_oConnMultiplexer.AddMultiplexPoint( pConnection->GetConnectionWaitForDescriptor(),
151
152
			m_iIDCounter, VistaIOMultiplexer::eIODir(
			VistaIOMultiplexer::MP_IOALL ) ) == false )
Jonas Stienen's avatar
Jonas Stienen committed
153
154
155
156
157
158
		{
			m_mapConnections.erase( m_mapConnections.find( m_iIDCounter ) );
			return false;
		}
		++m_iIDCounter;
		return true;
159
	};
Jonas Stienen's avatar
Jonas Stienen committed
160

161
	inline bool RemoveObservedConnection( VistaConnectionIP* pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
162
	{
163
		std::map<int, VistaConnectionIP*>::iterator itEntry = m_mapConnections.begin();
Jonas Stienen's avatar
Jonas Stienen committed
164
165
166
		bool bFound = false;
		while( itEntry != m_mapConnections.end() )
		{
167
			if( ( *itEntry ).second == pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
168
169
170
171
172
173
174
175
176
177
178
179
180
			{
				bFound = true;
				break;
			}
			else
			{
				++itEntry;
			}
		}

		if( bFound == false )
			return false;

181
		if( m_oConnMultiplexer.RemMultiplexPointByTicket( ( *itEntry ).first ) == false )
Jonas Stienen's avatar
Jonas Stienen committed
182
183
184
185
			return false;

		m_mapConnections.erase( itEntry );
		return true;
186
	};
Jonas Stienen's avatar
Jonas Stienen committed
187

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
188
	inline bool LoopBody()
Jonas Stienen's avatar
Jonas Stienen committed
189
190
191
192
193
194
195
196
197
198
199
200
201
	{
		int nUpdateID = m_oConnMultiplexer.Demultiplex();
		if( nUpdateID == 0 )
			return false;
		else if( nUpdateID < 0 )
		{
			std::cerr << "VA Server: Connection Observer encountered Demultiplex error" << std::endl;
			IndicateLoopEnd();
			return false;
		}

		try
		{
202
203
			m_mapConnections[ nUpdateID ]->SetWaitForDescriptorEventSelectIsEnabled( false );
			if( m_pProtocol->ProcessMessageFromClient( m_mapConnections[ nUpdateID ] ) == false )
Jonas Stienen's avatar
Jonas Stienen committed
204
			{
205
				m_pParent->RemoveClient( m_mapConnections[ nUpdateID ], CVANetNetworkProtocol::VA_NET_SERVER_DISCONNECT );
Jonas Stienen's avatar
Jonas Stienen committed
206
207
208
			}
			else
			{
209
210
				if( m_mapConnections[ nUpdateID ] )
					m_mapConnections[ nUpdateID ]->SetWaitForDescriptorEventSelectIsEnabled( true );
Jonas Stienen's avatar
Jonas Stienen committed
211
212
			}
		}
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
213
#ifdef VANET_SERVER_VERBOSE
214
		catch( CVAException& e )
Jonas Stienen's avatar
Jonas Stienen committed
215
		{
216
			std::cerr << "VA Server: caught exception and will disconnect now (" << e << ")" << std::endl;
217
			m_pParent->RemoveClient( m_mapConnections[ nUpdateID ], CVANetNetworkProtocol::VA_NET_SERVER_DISCONNECT );
Jonas Stienen's avatar
Jonas Stienen committed
218
		}
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
219
220
221
222
223
224
#else
		catch( CVAException& )
		{
			m_pParent->RemoveClient( m_mapConnections[ nUpdateID ], CVANetNetworkProtocol::VA_NET_SERVER_DISCONNECT );
		}
#endif
Jonas Stienen's avatar
Jonas Stienen committed
225
		return false;
226
	};
Jonas Stienen's avatar
Jonas Stienen committed
227

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
228
	inline void PreLoop()
229
230
231
	{
#ifdef VANET_SERVER_VERBOSE
		std::cout << "VA Server: starting connection update loop" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
232
#endif
233
	};
Jonas Stienen's avatar
Jonas Stienen committed
234

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
235
	inline void PostRun()
Jonas Stienen's avatar
Jonas Stienen committed
236
	{
237
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
238
239
240
		std::cout << "VA Server: starting connection update loop" << std::endl;
#endif
		m_oConnMultiplexer.Shutdown();
241
242
	};

Jonas Stienen's avatar
Jonas Stienen committed
243
244
private:
	int									m_iIDCounter;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
245
	std::map< int, VistaConnectionIP* >	m_mapConnections;
Jonas Stienen's avatar
Jonas Stienen committed
246
247
248
249
250
251
252
253
254
	CVANetServerImpl*			m_pParent;
	VistaIOHandleBasedIOMultiplexer		m_oConnMultiplexer;
	CVANetNetworkProtocol*				m_pProtocol;
};

/***********************************************************************/
/**** class CEventHandler                                           ****/
/***********************************************************************/

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
255
class CVANetServerImpl::CEventHandler : public IVAEventHandler
Jonas Stienen's avatar
Jonas Stienen committed
256
257
{
public:
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
258
259
	inline CEventHandler( CVANetServerImpl* pParent, CVANetNetworkProtocol* pProtocol, VistaMutex* pEventChannelLock, IVAInterface* pRealCore )
		: IVAEventHandler()
260
261
262
263
264
265
266
		, m_pProtocol( pProtocol )
		, m_pEventChannelLock( pEventChannelLock )
		, m_pRealCore( pRealCore )
		, m_pParent( pParent )
		, m_pMessage( new CVANetMessage( VistaSerializingToolset::DOES_NOT_SWAP_MULTIBYTE_VALUES ) )
	{
	};
Jonas Stienen's avatar
Jonas Stienen committed
267

268
	inline ~CEventHandler()
Jonas Stienen's avatar
Jonas Stienen committed
269
	{
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
270
		m_pRealCore->DetachEventHandler( this );
271
	};
Jonas Stienen's avatar
Jonas Stienen committed
272

273
	inline bool AddClientConnection( VistaConnectionIP* pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
274
275
276
	{
		VistaMutexLock oLock( *m_pEventChannelLock );
		std::vector<VistaConnectionIP*>::iterator itEntry = std::find(
277
278
279
			m_vecRegisteredClients.begin(),
			m_vecRegisteredClients.end(),
			pConnection );
Jonas Stienen's avatar
Jonas Stienen committed
280
281
282
283
		if( itEntry != m_vecRegisteredClients.end() )
			return false;

		if( m_vecRegisteredClients.empty() )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
284
			m_pRealCore->AttachEventHandler( this );
Jonas Stienen's avatar
Jonas Stienen committed
285
286
287

		m_vecRegisteredClients.push_back( pConnection );
		return true;
288
	};
Jonas Stienen's avatar
Jonas Stienen committed
289

290
	inline bool RemoveClientConnection( VistaConnectionIP* pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
291
292
	{
		VistaMutexLock oLock( *m_pEventChannelLock );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
293
		std::vector<VistaConnectionIP*>::iterator itEntry = std::find( m_vecRegisteredClients.begin(), m_vecRegisteredClients.end(), pConnection );
Jonas Stienen's avatar
Jonas Stienen committed
294
295
296
297
298
		if( itEntry == m_vecRegisteredClients.end() )
			return false;
		m_vecRegisteredClients.erase( itEntry );

		if( m_vecRegisteredClients.empty() )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
299
			m_pRealCore->DetachEventHandler( this );
Jonas Stienen's avatar
Jonas Stienen committed
300
		return true;
301
	};
Jonas Stienen's avatar
Jonas Stienen committed
302

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
303
	inline void HandleVAEvent( const CVAEvent* pEvent )
Jonas Stienen's avatar
Jonas Stienen committed
304
305
306
307
	{
		VistaMutexLock oLock( *m_pEventChannelLock );
		m_pProtocol->ServerPrepareEventMessage( pEvent, m_pMessage );
		std::list<VistaConnectionIP*> liDeadConnections;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
308
		for( std::vector<VistaConnectionIP*>::iterator itCon = m_vecRegisteredClients.begin(); itCon != m_vecRegisteredClients.end(); ++itCon )
309
		{
Jonas Stienen's avatar
Jonas Stienen committed
310
311
			try
			{
312
				m_pMessage->SetConnection( ( *itCon ) );
Jonas Stienen's avatar
Jonas Stienen committed
313
314
315
316
				m_pMessage->WriteMessage();
			}
			catch( VistaExceptionBase& oException )
			{
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
317
				std::cerr << "VANetServer: caught connection exception - " << oException.GetExceptionText() << std::endl;
318
				liDeadConnections.push_back( ( *itCon ) );
Jonas Stienen's avatar
Jonas Stienen committed
319
320
321
			}
			catch( CVAException& oException )
			{
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
322
				std::cerr << "VANetServer: caught connection exception - " << oException.ToString() << std::endl;
323
				liDeadConnections.push_back( ( *itCon ) );
Jonas Stienen's avatar
Jonas Stienen committed
324
325
			}
		}
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
326
		for( std::list<VistaConnectionIP*>::iterator itDead = liDeadConnections.begin(); itDead != liDeadConnections.end(); ++itDead )
Jonas Stienen's avatar
Jonas Stienen committed
327
		{
328
			m_pParent->RemoveClient( ( *itDead ), CVANetNetworkProtocol::VA_NET_SERVER_DISCONNECT );
Jonas Stienen's avatar
Jonas Stienen committed
329
330
		}

331
		if( pEvent->iEventID == CVAEvent::DESTROY )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
332
		{
Jonas Stienen's avatar
Jonas Stienen committed
333
334
335
			// Important: Core instance was deleted. We should disable the server now
			// TODO: Implement
		}
336
337
	};

Jonas Stienen's avatar
Jonas Stienen committed
338
339
340
341
342
343
private:
	CVANetServerImpl*				m_pParent;
	VistaMutex*						m_pEventChannelLock;
	std::vector<VistaConnectionIP*>	m_vecRegisteredClients;
	CVANetNetworkProtocol*			m_pProtocol;
	CVANetMessage*					m_pMessage;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
344
	IVAInterface*					m_pRealCore;
Jonas Stienen's avatar
Jonas Stienen committed
345
346
347
348
349
350
351
};

/***********************************************************************/
/**** class CVANetServerImpl                                 ****/
/***********************************************************************/

CVANetServerImpl::CVANetServerImpl()
352
353
354
355
356
357
358
359
360
361
362
363
364
	: m_pConnectionAccepter( NULL )
	, m_pProtocol( NULL )
	, m_pEventHandler( NULL )
	, m_pConnObserver( NULL )
	, m_pEventChannelLock( new VistaMutex )
	, m_pServerChangeLock( new VistaMutex )
	, m_pEventHandlerLock( new VistaMutex )
	, m_iServerPort( -1 )
	, m_bRunning( false )
	, m_bInitialized( false )
	, m_iMaxNumClients( -1 )
	, m_pRealCore( NULL )
{
Jonas Stienen's avatar
Jonas Stienen committed
365
366
}

367
368
CVANetServerImpl::~CVANetServerImpl()
{
Jonas Stienen's avatar
Jonas Stienen committed
369
370
371
372
373
374
	Finalize();
	delete m_pEventChannelLock;
	delete m_pServerChangeLock;
	delete m_pEventHandlerLock;
}

375
376
int CVANetServerImpl::Initialize( const std::string& sInterface, int iServerPort, int iFreePortMin, int iFreePortMax, int iMaxNumClients )
{
Jonas Stienen's avatar
Jonas Stienen committed
377
	assert( iServerPort > 0 );
378
	assert( ( iFreePortMin > 0 ) && ( iFreePortMax > 0 ) && ( iFreePortMin <= iFreePortMax ) );
Jonas Stienen's avatar
Jonas Stienen committed
379
380
381
382
383

	// Create the port list
	tPortList liFreePorts;
	liFreePorts.push_back( tPortRange( iFreePortMin, iFreePortMax ) );

384
	return Initialize( sInterface, iServerPort, liFreePorts, iMaxNumClients );
Jonas Stienen's avatar
Jonas Stienen committed
385
386
}

387
388
int CVANetServerImpl::Initialize( const std::string& sInterface, int iServerPort, const tPortList& liFreePorts, int iMaxNumClients )
{
Jonas Stienen's avatar
Jonas Stienen committed
389
390
391
392
393
	VistaMutexLock oLock( *m_pServerChangeLock );

	m_pProtocol = new CVANetNetworkProtocol;

	m_iMaxNumClients = iMaxNumClients;
394

Jonas Stienen's avatar
Jonas Stienen committed
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
	if( m_bInitialized )
		return VA_ALREADY_INITIALIZED;

	if( IVistaTimerImp::GetSingleton() == NULL )
		IVistaTimerImp::SetSingleton( new VistaDefaultTimerImp );

	m_sServerIP = sInterface;
	m_iServerPort = iServerPort;
	m_liFreePorts = liFreePorts;

	m_pConnectionAccepter = new CConnectionAccepter( this, m_sServerIP, iServerPort );
	if( m_pConnectionAccepter->GetIsValid() == false )
	{
		delete m_pConnectionAccepter;
		return VA_CONNECTION_FAILED;
	}

	m_pConnObserver = new CConnectionObserver( this, m_pProtocol );

	m_pProtocol->SetRealVACore( m_pRealCore );
	m_pProtocol->InitializeAsServer( this );

	m_pConnectionAccepter->Run();
	m_pConnObserver->Run();

	m_bInitialized = true;

	return VA_NO_ERROR;
}

425
426
int CVANetServerImpl::Finalize()
{
Jonas Stienen's avatar
Jonas Stienen committed
427
428
429
430
	VistaMutexLock oLock( *m_pServerChangeLock );
	if( m_bInitialized == false )
		return VA_NOT_INITIALIZED;

431
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
432
433
434
	std::cout << "VANetServer: Shutting down" << std::endl;
#endif

435
436
	if( m_pConnectionAccepter )
		m_pConnectionAccepter->Abort();
Jonas Stienen's avatar
Jonas Stienen committed
437
438
	delete m_pConnectionAccepter;
	m_pConnectionAccepter = NULL;
439

Jonas Stienen's avatar
Jonas Stienen committed
440
441
442
443
444
445
446
447
	oLock.Unlock();
	while( m_vecClients.empty() == false )
	{
		RemoveClient( 0, CVANetNetworkProtocol::VA_NET_SERVER_CLOSE );
	}
	oLock.Lock();

	if( m_pEventHandler )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
448
		m_pRealCore->DetachEventHandler( m_pEventHandler );
Jonas Stienen's avatar
Jonas Stienen committed
449
450
451
452
453
454
455
	delete m_pEventHandler;
	m_pEventHandler = NULL;

	/** @todo: detach */

	delete m_pProtocol;
	m_pProtocol = NULL;
456

Jonas Stienen's avatar
Jonas Stienen committed
457
458
459
460
461
462
463
464
465
466
	m_pConnObserver->Abort();
	delete m_pConnObserver;
	m_pConnObserver = NULL;

	m_bRunning = false;
	m_bInitialized = false;

	return VA_NO_ERROR;
}

467
468
void CVANetServerImpl::Reset()
{
Jonas Stienen's avatar
Jonas Stienen committed
469
	VistaMutexLock oLock( *m_pServerChangeLock );
470
#ifdef VANET_SERVER_VERBOSE
Jonas Stienen's avatar
Jonas Stienen committed
471
472
473
474
475
476
477
478
479
480
481
	std::cout << "VANetServer: Resetting" << std::endl;
#endif

	while( m_vecClients.empty() == false )
	{
		RemoveClient( 0, CVANetNetworkProtocol::VA_NET_SERVER_RESET );
	}

	/** @todo: reset core? */
}

Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
482
483
std::string CVANetServerImpl::GetServerAdress() const
{
Jonas Stienen's avatar
Jonas Stienen committed
484
485
486
	return m_sServerIP;
}

Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
487
488
int CVANetServerImpl::GetServerPort() const
{
Jonas Stienen's avatar
Jonas Stienen committed
489
490
491
	return m_iServerPort;
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
492
IVAInterface* CVANetServerImpl::GetCoreInstance() const
Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
493
{
Jonas Stienen's avatar
Jonas Stienen committed
494
495
496
	return m_pRealCore;
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
497
498
void CVANetServerImpl::SetCoreInstance( IVAInterface* pCore )
{
Jonas Stienen's avatar
Jonas Stienen committed
499
500
501
502
503
	m_pRealCore = pCore;
	if( m_pProtocol )
		m_pProtocol->SetRealVACore( pCore );
}

Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
504
505
bool CVANetServerImpl::IsClientConnected() const
{
Jonas Stienen's avatar
Jonas Stienen committed
506
507
508
	return ( m_vecClients.empty() == false );
}

Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
509
510
int CVANetServerImpl::GetNumConnectedClients() const
{
511
	return ( int ) m_vecClients.size();
Jonas Stienen's avatar
Jonas Stienen committed
512
}
Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
513
514
515

std::string CVANetServerImpl::GetClientHostname( const int iClientIndex ) const
{
Jonas Stienen's avatar
Jonas Stienen committed
516
	VistaMutexLock oLock( *m_pServerChangeLock );
517
	if( iClientIndex < 0 || iClientIndex >( int )m_vecClients.size() )
Jonas Stienen's avatar
Jonas Stienen committed
518
		return "";
519
	return m_vecClients[ iClientIndex ].m_sHost;
Jonas Stienen's avatar
Jonas Stienen committed
520
521
}

Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
522
523
bool CVANetServerImpl::AttachEventHandler( IEventHandler* pHandler )
{
Jonas Stienen's avatar
Jonas Stienen committed
524
525
	VistaMutexLock oLock( *m_pEventChannelLock );
	std::list<IEventHandler*>::iterator itEntry = std::find( m_liEventHandlers.begin(),
526
		m_liEventHandlers.end(), pHandler );
Jonas Stienen's avatar
Jonas Stienen committed
527
528
529
530
531
	if( itEntry != m_liEventHandlers.end() )
		return false;
	m_liEventHandlers.push_back( pHandler );
	return true;
}
Dipl.-Ing. Jonas Stienen's avatar
Style    
Dipl.-Ing. Jonas Stienen committed
532
533
bool CVANetServerImpl::DetachEventHandler( IEventHandler* pHandler )
{
Jonas Stienen's avatar
Jonas Stienen committed
534
535
	VistaMutexLock oLock( *m_pEventChannelLock );
	std::list<IEventHandler*>::iterator itEntry = std::find( m_liEventHandlers.begin(),
536
		m_liEventHandlers.end(), pHandler );
Jonas Stienen's avatar
Jonas Stienen committed
537
538
539
540
541
542
543
544
545
546
547
	if( itEntry == m_liEventHandlers.end() )
		return false;
	m_liEventHandlers.erase( itEntry );
	return true;
}

int CVANetServerImpl::AddNewClient( VistaConnectionIP* pTemporaryConnection )
{
	VistaMutexLock oLock( *m_pServerChangeLock );

	pTemporaryConnection->WriteInt32( 1 ); // we write an initial defined value
548
	// to check if there's an endianess difference
Jonas Stienen's avatar
Jonas Stienen committed
549
550

	// we write our protocol to ensure that it is the same
551
552
	pTemporaryConnection->WriteInt32( ( VANetCompat::sint32 )CVANetNetworkProtocol::VA_NET_PROTOCOL_VERSION_MAJOR );
	pTemporaryConnection->WriteInt32( ( VANetCompat::sint32 )CVANetNetworkProtocol::VA_NET_PROTOCOL_VERSION_MINOR );
Jonas Stienen's avatar
Jonas Stienen committed
553
554
555
556
557
558
559
560

	bool bVersionMatch = false;
	pTemporaryConnection->ReadBool( bVersionMatch );
	if( bVersionMatch == false )
		return VA_CONNECTION_FAILED;

	CClientData oNewData;

561
	if( m_iMaxNumClients >= 0 && ( int ) m_vecClients.size() >= m_iMaxNumClients )
Jonas Stienen's avatar
Jonas Stienen committed
562
563
564
565
566
567
568
569
570
571
572
573
574
	{
		std::cerr << "VA Server: Client applied, but too many clients already connected" << std::endl;
		pTemporaryConnection->WriteInt32( -2 );
		return VA_CONNECTION_FAILED;
	}

	VANetCompat::sint32 iCommandPort = GetNextFreePort();
	if( iCommandPort == -1 )
	{
		std::cerr << "VA Server: Client applied, but no more free ports available" << std::endl;
		pTemporaryConnection->WriteInt32( -1 );
		return VA_CONNECTION_FAILED;
	}
575
576

	VistaTCPServer oCommandServer( m_sServerIP, iCommandPort );
Jonas Stienen's avatar
Jonas Stienen committed
577
578
579
	if( oCommandServer.GetIsValid() == false )
	{
		std::cerr << "VA Server: Client applied, but could not open "
580
			<< "command socket on port [" << iCommandPort << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
581
582
583
584
		pTemporaryConnection->WriteInt32( -1 );
		return VA_CONNECTION_FAILED;
	}

585
	pTemporaryConnection->WriteInt32( iCommandPort );
Jonas Stienen's avatar
Jonas Stienen committed
586
587
588
589
590
591

	VistaTCPSocket* pCommandSocket = oCommandServer.GetNextClient();
	oCommandServer.StopAccept();
	if( pCommandSocket == NULL )
	{
		std::cerr << "VA Server: Client applied, but did not connect to "
592
			<< "command socket on port [" << iCommandPort << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
593
		return VA_CONNECTION_FAILED;
594
595
596

	}
	oNewData.m_pCommandChannel = new VistaConnectionIP( pCommandSocket );
Jonas Stienen's avatar
Jonas Stienen committed
597
598
	oNewData.m_pCommandChannel->SetIsBlocking( true );
	oNewData.m_pCommandChannel->SetByteorderSwapFlag( VistaSerializingToolset::DOES_NOT_SWAP_MULTIBYTE_VALUES );
599
600
601
602
603
#ifdef VANET_SERVER_SHOW_RAW_TRAFFIC
	oNewData.m_pCommandChannel->SetShowRawSendAndReceive( true );
#else
	oNewData.m_pCommandChannel->SetShowRawSendAndReceive( false );
#endif
Jonas Stienen's avatar
Jonas Stienen committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620

	// check for optional head connection
	VANetCompat::sint32 iHeadChannelMode;
	pTemporaryConnection->ReadInt32( iHeadChannelMode );
	if( iHeadChannelMode == 0 )
	{
		// no separate head connection
		oNewData.m_pHeadChannel = NULL; // only created upon client request
	}
	else if( iHeadChannelMode == 1 )
	{
		// separate TCP connection
		VANetCompat::sint32 iHeadPort = GetNextFreePort();
		VistaTCPServer oHeadServer( m_sServerIP, iHeadPort );
		if( oCommandServer.GetIsValid() == false )
		{
			std::cerr << "VA Server: Client applied, but could not open "
621
622
				<< "head socket on port [" << iHeadPort << "]" << std::endl;
			pTemporaryConnection->WriteInt32( -1 );
Jonas Stienen's avatar
Jonas Stienen committed
623
624
625
626
627
628
629
630
631
632
			delete oNewData.m_pCommandChannel;
			oNewData.m_pCommandChannel = NULL;
			return VA_CONNECTION_FAILED;
		}
		pTemporaryConnection->WriteInt32( iHeadPort );
		VistaTCPSocket* pHeadSocket = oHeadServer.GetNextClient();
		oHeadServer.StopAccept();
		if( pHeadSocket == NULL )
		{
			std::cerr << "VA Server: Client applied, but did not connect to "
633
				<< "head socket on port [" << iHeadPort << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
634
			delete oNewData.m_pCommandChannel;
635
636
			oNewData.m_pCommandChannel = NULL;
			return VA_CONNECTION_FAILED;
Jonas Stienen's avatar
Jonas Stienen committed
637
		}
638
		oNewData.m_pHeadChannel = new VistaConnectionIP( pHeadSocket );
Jonas Stienen's avatar
Jonas Stienen committed
639
640
641
642
643
644
645
646
647
	}
	else if( iHeadChannelMode == 2 )
	{
		// separate UDP connection
		VANetCompat::sint32 iHeadPort = GetNextFreePort();
		oNewData.m_pHeadChannel = new VistaConnectionIP( m_sServerIP, iHeadPort );
		if( oNewData.m_pHeadChannel->GetIsConnected() == false )
		{
			std::cerr << "VA Server: Client applied, but could not open "
648
				<< "UDP receiver on port [" << iHeadPort << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
649
650
651
652
653
654
655
656
657
			pTemporaryConnection->WriteInt32( -1 );
			delete oNewData.m_pHeadChannel;
			oNewData.m_pHeadChannel = NULL;
			delete oNewData.m_pCommandChannel;
			oNewData.m_pCommandChannel = NULL;
			return VA_CONNECTION_FAILED;
		}
		pTemporaryConnection->WriteInt32( iHeadPort );
	}
658

Jonas Stienen's avatar
Jonas Stienen committed
659
660
661
662
663
664
665
666
667
	// Create Event Channel - while the client may not necessarily want to receive
	// core events/progress updatzes, we still need this to pass other net-specific
	// events like server close/reset

	VANetCompat::sint32 iEventPort = GetNextFreePort();
	if( iEventPort == -1 )
	{
		std::cerr << "VA Server: Client applied, but no more free ports available" << std::endl;
	}
668
669

	VistaTCPServer oEventServer( m_sServerIP, iEventPort );
Jonas Stienen's avatar
Jonas Stienen committed
670
671
672
	if( oEventServer.GetIsValid() == false )
	{
		std::cerr << "VA Server: Client applied, but could not open "
673
674
			<< "event socket on port [" << iEventPort << "]" << std::endl;
		pTemporaryConnection->WriteInt32( -1 );
Jonas Stienen's avatar
Jonas Stienen committed
675
676
677
678
679
680
681
		delete oNewData.m_pHeadChannel;
		oNewData.m_pHeadChannel = NULL;
		delete oNewData.m_pCommandChannel;
		oNewData.m_pCommandChannel = NULL;
		return VA_CONNECTION_FAILED;
	}

682
	pTemporaryConnection->WriteInt32( iEventPort );
Jonas Stienen's avatar
Jonas Stienen committed
683
684
685
686
687
688

	VistaTCPSocket* pEventSocket = oEventServer.GetNextClient();
	oEventServer.StopAccept();
	if( pEventSocket == NULL )
	{
		std::cerr << "VA Server: Client applied, but did not connect to "
689
			<< "event socket on port [" << iEventPort << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
690
691
692
693
694
		delete oNewData.m_pHeadChannel;
		oNewData.m_pHeadChannel = NULL;
		delete oNewData.m_pCommandChannel;
		oNewData.m_pCommandChannel = NULL;
		return VA_CONNECTION_FAILED;
695
696
697

	}
	oNewData.m_pEventChannel = new VistaConnectionIP( pEventSocket );
Jonas Stienen's avatar
Jonas Stienen committed
698
699
700
701
702
703
	oNewData.m_pEventChannel->SetIsBlocking( true );
	oNewData.m_pEventChannel->SetByteorderSwapFlag( VistaSerializingToolset::DOES_NOT_SWAP_MULTIBYTE_VALUES );

	m_pConnObserver->AddObservedConnection( oNewData.m_pCommandChannel );
	if( oNewData.m_pHeadChannel )
	{
704
		m_pConnObserver->AddObservedConnection( oNewData.m_pHeadChannel );
Jonas Stienen's avatar
Jonas Stienen committed
705
706
707
708
709
710
		oNewData.m_pHeadChannel->SetIsBlocking( true );
		oNewData.m_pHeadChannel->SetByteorderSwapFlag( VistaSerializingToolset::DOES_NOT_SWAP_MULTIBYTE_VALUES );
	}

	oNewData.m_sHost = pTemporaryConnection->GetPeerName();
	m_vecClients.push_back( oNewData );
711

Jonas Stienen's avatar
Jonas Stienen committed
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
	CEvent oEvent( CEvent::EVENT_CLIENT_CONNECT, oNewData.m_sHost );
	EmitEvent( oEvent );

	return VA_NO_ERROR;
}

int CVANetServerImpl::GetNextFreePort()
{
	/** @todo: race - although unlikely */
	if( m_liFreePorts.empty() )
		return -1;

	int iPort = m_liFreePorts.front().first;
	++m_liFreePorts.front().first;
	if( m_liFreePorts.front().first > m_liFreePorts.front().second )
		m_liFreePorts.pop_front();

	return iPort;
}

bool CVANetServerImpl::AttachCoreEventHandler( VistaConnectionIP* pConnection )
{
	VistaMutexLock oLock( *m_pServerChangeLock );
	// first, we look for the client entry
	std::vector<CClientData>::iterator itClient;
	for( itClient = m_vecClients.begin(); itClient != m_vecClients.end(); ++itClient )
	{
739
		if( ( *itClient ).m_pCommandChannel == pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
740
741
742
743
744
745
746
			break;
	}
	if( itClient == m_vecClients.end() )
		return false;

	if( m_pEventHandler == NULL )
		m_pEventHandler = new CEventHandler( this, m_pProtocol, m_pEventChannelLock, m_pRealCore );
747
748
	assert( ( *itClient ).m_pEventChannel != NULL );
	m_pEventHandler->AddClientConnection( ( *itClient ).m_pEventChannel );
Jonas Stienen's avatar
Jonas Stienen committed
749
750
751
752
753
754
755
756
757
758
	return true;
}

bool CVANetServerImpl::DetachCoreEventHandler( VistaConnectionIP* pConnection )
{
	VistaMutexLock oLock( *m_pServerChangeLock );
	// first, we look for the client entry
	std::vector<CClientData>::iterator itClient;
	for( itClient = m_vecClients.begin(); itClient != m_vecClients.end(); ++itClient )
	{
759
		if( ( *itClient ).m_pCommandChannel == pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
760
761
762
763
764
			break;
	}
	if( itClient == m_vecClients.end() )
		return false;

765
766
	assert( ( *itClient ).m_pEventChannel != NULL );
	m_pEventHandler->RemoveClientConnection( ( *itClient ).m_pEventChannel );
Jonas Stienen's avatar
Jonas Stienen committed
767
768
769
770
	return true;
}

void CVANetServerImpl::RemoveClient( VistaConnectionIP* pConnection,
771
	int iStatusCode )
Jonas Stienen's avatar
Jonas Stienen committed
772
773
774
775
776
{
	std::vector<CClientData>::iterator itClient;
	int iID = 0;
	for( itClient = m_vecClients.begin(); itClient != m_vecClients.end(); ++itClient, ++iID )
	{
777
778
779
		if( ( *itClient ).m_pCommandChannel == pConnection
			|| ( *itClient ).m_pEventChannel == pConnection
			|| ( *itClient ).m_pHeadChannel == pConnection )
Jonas Stienen's avatar
Jonas Stienen committed
780
781
782
783
784
785
786
787
788
789
790
791
792
		{
			RemoveClient( iID, iStatusCode );
			return;
		}
	}
}

void CVANetServerImpl::RemoveClient( int iClientID, int iStatusCode )
{
	VistaMutexLock oServerLock( *m_pServerChangeLock );
	VistaMutexLock oEventChannelLock( *m_pEventChannelLock );
	VistaMutexLock oHandlerLock( *m_pEventHandlerLock );

793
794
795
	if( m_vecClients.size() == 0 )
		return; // Clients already gone ...

Jonas Stienen's avatar
Jonas Stienen committed
796
797
	std::vector<CClientData>::iterator itClient = m_vecClients.begin() + iClientID;

798
799
#ifdef VANET_SERVER_VERBOSE
	std::cout << "VANetServer: Removing client [" << ( *itClient ).m_sHost << "]" << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
800
801
#endif

802
	if( iStatusCode != 0 && ( *itClient ).m_pEventChannel && ( *itClient ).m_pEventChannel->GetIsConnected() )
Jonas Stienen's avatar
Jonas Stienen committed
803
804
805
	{
		try
		{
806
807
			CVANetMessage oMessage( ( *itClient ).m_pEventChannel->GetByteorderSwapFlag() );
			oMessage.SetConnection( ( *itClient ).m_pEventChannel );
Jonas Stienen's avatar
Jonas Stienen committed
808
809
810
			oMessage.SetMessageType( CVANetNetworkProtocol::VA_EVENT_NET_EVENT );
			oMessage.WriteInt( iStatusCode );
			oMessage.WriteMessage();
811
			( *itClient ).m_pEventChannel->WaitForSendFinish();
Jonas Stienen's avatar
Jonas Stienen committed
812
813
814
815
816
817
818
819
820
821
822
823
824
825
		}
		catch( VistaExceptionBase& )
		{
			// nothing tho do, we're already cleaning up
		}
		catch( CVAException& )
		{
			// nothing tho do, we're already cleaning up
		}
	}

	// we assume that all invalidated connections have been closed, but not deleted before

	// first, we try to send the client the close command
826
	if( ( *itClient ).m_pCommandChannel != NULL )
Jonas Stienen's avatar
Jonas Stienen committed
827
	{
828
829
830
831
		m_pConnObserver->RemoveObservedConnection( ( *itClient ).m_pCommandChannel );
		m_pProtocol->HandleConnectionClose( ( *itClient ).m_pCommandChannel );
		if( ( *itClient ).m_pCommandChannel->GetIsConnected()
			&& ( *itClient ).m_pCommandChannel->GetIsOpen() )
Jonas Stienen's avatar
Jonas Stienen committed
832
		{
833
			( *itClient ).m_pCommandChannel->Close();
Jonas Stienen's avatar
Jonas Stienen committed
834
		}
835
		delete ( *itClient ).m_pCommandChannel;
Jonas Stienen's avatar
Jonas Stienen committed
836
837
	}

838
	if( ( *itClient ).m_pHeadChannel != NULL )
Jonas Stienen's avatar
Jonas Stienen committed
839
	{
840
841
842
843
		m_pConnObserver->RemoveObservedConnection( ( *itClient ).m_pHeadChannel );
		m_pConnObserver->RemoveObservedConnection( ( *itClient ).m_pHeadChannel );
		if( ( *itClient ).m_pHeadChannel->GetIsConnected()
			&& ( *itClient ).m_pHeadChannel->GetIsOpen() )
Jonas Stienen's avatar
Jonas Stienen committed
844
		{
845
			( *itClient ).m_pHeadChannel->Close();
Jonas Stienen's avatar
Jonas Stienen committed
846
		}
847
		delete ( *itClient ).m_pHeadChannel;
Jonas Stienen's avatar
Jonas Stienen committed
848
849
	}

850
	if( ( *itClient ).m_pEventChannel != NULL )
Jonas Stienen's avatar
Jonas Stienen committed
851
852
	{
		if( m_pEventHandler )
853
854
855
856
			m_pEventHandler->RemoveClientConnection( ( *itClient ).m_pEventChannel );
		m_pConnObserver->RemoveObservedConnection( ( *itClient ).m_pEventChannel );
		if( ( *itClient ).m_pEventChannel->GetIsConnected()
			&& ( *itClient ).m_pEventChannel->GetIsOpen() )
Jonas Stienen's avatar
Jonas Stienen committed
857
		{
858
			( *itClient ).m_pEventChannel->Close();
Jonas Stienen's avatar
Jonas Stienen committed
859
		}
860
861
		delete ( *itClient ).m_pEventChannel;
	}
Jonas Stienen's avatar
Jonas Stienen committed
862

863
	CEvent oEvent( CEvent::EVENT_CLIENT_DISCONNECT, ( *itClient ).m_sHost );
Jonas Stienen's avatar
Jonas Stienen committed
864
865
866
	m_vecClients.erase( itClient );

	// to avoid deadlocks, we unlock before emitting the event
867
868
869
	oServerLock.Unlock();
	oHandlerLock.Unlock();
	oEventChannelLock.Unlock();
Jonas Stienen's avatar
Jonas Stienen committed
870
871
872
873
874
875
876
877
878
	EmitEvent( oEvent );
}

void CVANetServerImpl::EmitEvent( const CEvent& oEvent )
{
	if( m_liEventHandlers.empty() )
		return;
	VistaMutexLock oLock( *m_pEventChannelLock );
	for( std::list<IEventHandler*>::iterator itHandler = m_liEventHandlers.begin();
879
		itHandler != m_liEventHandlers.end(); ++itHandler )
Jonas Stienen's avatar
Jonas Stienen committed
880
	{
881
		( *itHandler )->HandleEvent( oEvent );
Jonas Stienen's avatar
Jonas Stienen committed
882
883
884
885
886
887
888
	}
}

void CVANetServerImpl::HandleClientEvent( int iEventID, VistaConnectionIP* pConnection )
{
	switch( iEventID )
	{
889
890
891
892
893
894
895
896
897
	case CVANetNetworkProtocol::VA_NET_CLIENT_CLOSE:
	{
		RemoveClient( pConnection );
		break;
	}
	default:
	{
#ifdef VANET_SERVER_VERBOSE
		std::cout << "VANetServer: Event from client with unknown ID " << iEventID << std::endl;
Jonas Stienen's avatar
Jonas Stienen committed
898
#endif
899
900
		break;
	}
901
}
Jonas Stienen's avatar
Jonas Stienen committed
902
}