1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program 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
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "fe_receive_task.h"
28 # ifndef NL_COMP_MINGW
32 #elif defined NL_OS_UNIX
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
40 #define WSAGetLastError() 0
45 using namespace NLMISC
;
46 using namespace NLNET
;
49 volatile uint32
CFEReceiveTask::LastUDPPacketReceived
= 0;
56 TReceivedMessage::TReceivedMessage()
58 VAddrFrom
.resize( sizeof(sockaddr_in
) );
61 /// Return a vector containing the address info
62 void TReceivedMessage::addressToVector()
64 memcpy( &*VAddrFrom
.begin(), AddrFrom
.sockAddr(), sizeof(sockaddr_in
) );
67 /// Set address with address info from specified vector
68 void TReceivedMessage::vectorToAddress()
70 AddrFrom
.setSockAddr( (sockaddr_in
*)&*VAddrFrom
.begin() );
75 * Constructor (note: called from the main thread)
77 CFEReceiveTask::CFEReceiveTask( uint16 firstAcceptablePort
, uint16 lastAcceptablePort
, uint32 msgsize
) :
79 _WriteQueue( "WriteQueue" ), // value unspecified
80 _DatagramLength( msgsize
),
81 _ExitRequired( false ),
82 _NbRejectedDatagrams( 0 )
85 DataSock
= new CUdpSock( false );
88 // Test of multihomed host: bind the first address
89 /* vector<CInetAddress> addrlist;
90 addrlist = CInetAddress::localAddresses();
91 vector<CInetAddress>::iterator ivi;
92 nlinfo( "Listing local interfaces:" );
93 for ( ivi=addrlist.begin(); ivi!=addrlist.end(); ++ivi )
95 nlinfo( "%s", (*ivi).asIPString().c_str() );
97 addrlist[0].setPort( port );
98 DataSock->bind( addrlist[0] );
101 // Bind on all network interfaces (TODO: find a simple way to bind only on the external interface; note: change releaase code for Linux in fe_receive_sub.cpp as well)
103 for ( actualPort
=firstAcceptablePort
; actualPort
<=lastAcceptablePort
; ++actualPort
)
107 DataSock
->bind( actualPort
);
110 catch (const ESocket
&e
)
112 nlinfo( "Port %u not available: %s", actualPort
, e
.what() );
115 if ( actualPort
> lastAcceptablePort
)
116 nlerror( "Could not find an available port between %hu and %hu", firstAcceptablePort
, lastAcceptablePort
);
117 nlinfo( "Binding all network interfaces on port %hu (%hu asked)", actualPort
, firstAcceptablePort
);
125 CFEReceiveTask::~CFEReceiveTask()
127 nlassert( DataSock
!= NULL
);
136 void CFEReceiveTask::run()
138 uint maxrecvlength
= _DatagramLength
;
139 while ( ! _ExitRequired
)
141 #ifndef SIMUL_CLIENTS
143 #ifdef MEASURE_RECEIVE_TASK
144 static sint32 loopcount
= 0;
146 static TTime lastdisplay
= CTime::getLocalTime();
147 TTime tn
= CTime::getLocalTime();
148 uint32 diff
= (uint32
)(tn
- lastdisplay
);
151 nlinfo("Reads by second: %.1f => LoopTime = %.2f ms LoopCount = %u Diff = %u ms",(float)loopcount
* 1000.0f
/ (float)diff
, (float)diff
/ loopcount
, loopcount
, diff
);
159 // Receive into _ReceivedMessage
160 _DatagramLength
= maxrecvlength
;
161 _ReceivedMessage
.resizeData( _DatagramLength
);
162 _ReceivedMessage
.setTypeEvent( TReceivedMessage::User
);
163 DataSock
->receivedFrom( _ReceivedMessage
.userDataW(), _DatagramLength
, _ReceivedMessage
.AddrFrom
);
165 catch (const ESocket
&)
167 // Remove the client corresponding to the address
168 _ReceivedMessage
.setTypeEvent( TReceivedMessage::RemoveClient
);
172 // update the last datagram receive date
173 LastUDPPacketReceived
= CTime::getSecondsSince1970();
175 // Check the size. Consider a big size as a hacked message
176 // if ( _DatagramLength < 512 )
178 // Push into the write queue
179 _ReceivedMessage
.addressToVector();
180 _ReceivedMessage
.resizeData( _DatagramLength
); // _DatagramLength was modified by receivedFrom()
182 CSynchronized
<CBufFIFO
*>::CAccessor
wq( &_WriteQueue
);
183 wq
.value()->push( _ReceivedMessage
.data() );
184 wq
.value()->push( _ReceivedMessage
.VAddrFrom
);
190 // ++_NbRejectedDatagrams;
198 nlinfo( "Exiting from front-end receive task" );
203 * Set new write queue
205 void CFEReceiveTask::setWriteQueue( CBufFIFO
*writequeue
)
207 CSynchronized
<CBufFIFO
*>::CAccessor
wq( &_WriteQueue
);
208 wq
.value() = writequeue
;