Pol  Revision:4b29d2b
clientio.cpp
Go to the documentation of this file.
1 
8 #include <errno.h>
9 #include <mutex>
10 #include <stddef.h>
11 #include <string>
12 
13 #include <format/format.h>
14 #include "../../clib/fdump.h"
15 #include "../../clib/logfacility.h"
16 #include "../../clib/passert.h"
17 #include "../../clib/refptr.h"
18 #include "../../clib/spinlock.h"
19 #include "../crypt/cryptbase.h"
20 #include "../ctable.h"
21 #include "../globals/network.h"
22 #include "../globals/state.h"
23 #include "../packetscrobj.h"
24 #include "../polsem.h"
25 #include "../polsig.h"
26 #include "../sockets.h"
27 #include "client.h"
28 #include "clienttransmit.h"
29 #include "packethelper.h"
30 #include "packethooks.h"
31 #include "packets.h"
32 
33 namespace Pol
34 {
35 namespace Network
36 {
37 std::string Client::ipaddrAsString() const
38 {
39  return AddressToString( const_cast<struct sockaddr*>( &ipaddr ) );
40 }
41 
42 void Client::recv_remaining( int total_expected )
43 {
44  int count;
45  int max_expected = total_expected - bytes_received;
46 
47  {
48  std::lock_guard<std::mutex> lock( _SocketMutex );
49  count = cryptengine->Receive( &buffer[bytes_received], max_expected, csocket );
50  }
51 
52  if ( count > 0 )
53  {
54  passert( count <= max_expected );
55 
56  bytes_received += count;
57  counters.bytes_received += count;
59  }
60  else if ( count == 0 ) // graceful close
61  {
62  disconnect = true;
63  }
64  else
65  {
66  int errn = socket_errno;
67  if ( errn != SOCKET_ERRNO( EWOULDBLOCK ) )
68  disconnect = true;
69  }
70 }
71 
72 void Client::recv_remaining_nocrypt( int total_expected )
73 {
74  int count;
75 
76  {
77  std::lock_guard<std::mutex> lock( _SocketMutex );
78  count = recv( csocket, (char*)&buffer[bytes_received], total_expected - bytes_received, 0 );
79  }
80  if ( count > 0 )
81  {
82  bytes_received += count;
83  counters.bytes_received += count;
85  }
86  else if ( count == 0 ) // graceful close
87  {
88  disconnect = true;
89  }
90  else
91  {
92  int errn = socket_errno;
93  if ( errn != SOCKET_ERRNO( EWOULDBLOCK ) )
94  disconnect = true;
95  }
96 }
97 
98 
99 /* NOTE: If this changes, code in client.cpp must change - pause() and restart() use
100  pre-encrypted values of 33 00 and 33 01.
101  */
102 void Client::transmit_encrypted( const void* data, int len )
103 {
104  THREAD_CHECKPOINT( active_client, 100 );
105  const unsigned char* cdata = (const unsigned char*)data;
106  unsigned char* pch;
107  int i;
108  int bidx; // Offset in output byte
109  EncryptedPktBuffer* outbuffer =
110  PktHelper::RequestPacket<EncryptedPktBuffer>( ENCRYPTEDPKTBUFFER );
111  pch = reinterpret_cast<unsigned char*>( outbuffer->getBuffer() );
112  bidx = 0;
113  THREAD_CHECKPOINT( active_client, 101 );
114  for ( i = 0; i < len; i++ )
115  {
116  THREAD_CHECKPOINT( active_client, 102 );
117  unsigned char ch = cdata[i];
118  int nbits = Core::keydesc[ch].nbits;
119  unsigned short inval = Core::keydesc[ch].bits_reversed;
120 
121  THREAD_CHECKPOINT( active_client, 103 );
122 
123  while ( nbits-- )
124  {
125  THREAD_CHECKPOINT( active_client, 104 );
126  *pch <<= 1;
127  if ( inval & 1 )
128  *pch |= 1;
129  bidx++;
130  if ( bidx == 8 )
131  {
132  THREAD_CHECKPOINT( active_client, 105 );
133  pch++;
134  bidx = 0;
135  }
136  THREAD_CHECKPOINT( active_client, 106 );
137 
138  inval >>= 1;
139  }
140  THREAD_CHECKPOINT( active_client, 107 );
141  }
142  THREAD_CHECKPOINT( active_client, 108 );
143 
144  {
145  int nbits = Core::keydesc[0x100].nbits;
146  unsigned short inval = Core::keydesc[0x100].bits_reversed;
147 
148  THREAD_CHECKPOINT( active_client, 109 );
149 
150  while ( nbits-- )
151  {
152  THREAD_CHECKPOINT( active_client, 110 );
153  *pch <<= 1;
154  if ( inval & 1 )
155  *pch |= 1;
156  bidx++;
157  THREAD_CHECKPOINT( active_client, 111 );
158  if ( bidx == 8 )
159  {
160  pch++;
161  bidx = 0;
162  }
163  THREAD_CHECKPOINT( active_client, 112 );
164 
165  inval >>= 1;
166  }
167  }
168  THREAD_CHECKPOINT( active_client, 113 );
169 
170  if ( bidx == 0 )
171  {
172  pch--;
173  }
174  else
175  {
176  *pch <<= ( 8 - bidx );
177  }
178  THREAD_CHECKPOINT( active_client, 114 );
179 
180  passert_always( pch - reinterpret_cast<unsigned char*>( outbuffer->buffer ) + 1 <=
181  int( sizeof outbuffer->buffer ) );
182  THREAD_CHECKPOINT( active_client, 115 );
183  xmit( &outbuffer->buffer, static_cast<unsigned short>(
184  pch - reinterpret_cast<unsigned char*>( outbuffer->buffer ) + 1 ) );
185  PktHelper::ReAddPacket( outbuffer );
186  THREAD_CHECKPOINT( active_client, 116 );
187 }
188 
189 void Client::transmit( const void* data, int len, bool needslock )
190 {
192  bool handled = false;
193  // see if the outgoing packet has a SendFunction installed. If so call it. It may or may not
194  // want us to continue sending the packet. If it does, handled will be false, and data, len, and p
195  // will be altered. data has the new packet data to send, len the new length, and p, a ref counted
196  // pointer to the packet object.
197  //
198  // If there is no outgoing packet script, handled will be false, and the passed params will be
199  // unchanged.
200  {
201  PacketHookData* phd = nullptr;
202  handled = GetAndCheckPacketHooked( this, data, phd );
203  if ( handled )
204  {
205  if ( needslock )
206  {
207  Core::PolLock lock;
208  std::lock_guard<std::mutex> guard( _SocketMutex );
209  CallOutgoingPacketExportedFunction( this, data, len, p, phd, handled );
210  }
211  else
212  {
213  std::lock_guard<std::mutex> guard( _SocketMutex );
214  CallOutgoingPacketExportedFunction( this, data, len, p, phd, handled );
215  }
216  }
217  }
218 
219  if ( handled )
220  return;
221 
222  unsigned char msgtype = *(const char*)data;
223 
224  {
226  if ( !fpLog.empty() )
227  {
228  fmt::Writer tmp;
229  tmp << "Server -> Client: 0x" << fmt::hexu( msgtype ) << ", " << len << " bytes\n";
230  Clib::fdump( tmp, data, len );
231  FLEXLOG( fpLog ) << tmp.str() << "\n";
232  }
233  }
234 
235  std::lock_guard<std::mutex> guard( _SocketMutex );
236  if ( disconnect )
237  {
238  POLLOG_INFO << "Warning: Trying to send to a disconnected client! \n";
239  fmt::Writer tmp;
240  tmp << "Server -> Client: 0x" << fmt::hexu( msgtype ) << ", " << len << " bytes\n";
241  Clib::fdump( tmp, data, len );
242  POLLOG_INFO << tmp.str() << "\n";
243  return;
244  }
245 
246  if ( last_xmit_buffer )
247  {
250  }
252  Core::networkManager.iostats.sent[msgtype].bytes += len;
253 
254  if ( encrypt_server_stream )
255  {
256  pause();
257  transmit_encrypted( data, len );
258  }
259  else
260  {
261  xmit( data, static_cast<unsigned short>( len ) );
262  // _xmit( client->csocket, data, len );
263  }
264 }
265 
266 void Client::transmitmore( const void* data, int len )
267 {
268  {
270  if ( !fpLog.empty() )
271  {
272  fmt::Writer tmp;
273  tmp << "Server -> Client (" << len << " bytes)\n";
274  Clib::fdump( tmp, data, len );
275  FLEXLOG( fpLog ) << tmp.str() << "\n";
276  }
277  }
278 
279  if ( encrypt_server_stream )
280  {
281  pause();
282  transmit_encrypted( data, len );
283  }
284  else
285  {
286  xmit( data, static_cast<unsigned short>( len ) );
287  // _xmit( client->csocket, data, len );
288  }
289 }
290 
291 void transmit( Client* client, const void* data, int len )
292 {
293  Core::networkManager.clientTransmit->AddToQueue( client, data, len );
294 }
295 
297 {
298  if ( this->isConnected() )
299  {
300  this->preDisconnect = true;
301  Core::networkManager.clientTransmit->QueueDisconnection( this );
302  }
303 }
304 }
305 }
void CallOutgoingPacketExportedFunction(Client *client, const void *&data, int &inlength, ref_ptr< Core::BPacket > &outpacket, PacketHookData *phd, bool &handled)
unsigned short bits_reversed
Definition: ctable.h:16
Network::IOStats queuedmode_iostats
Definition: network.h:72
void recv_remaining_nocrypt(int total_expected)
Definition: clientio.cpp:72
sockaddr ipaddr
Definition: client.h:213
std::string fpLog
Definition: client.h:222
#define POLLOG_INFO
Definition: logfacility.h:213
#define THREAD_CHECKPOINT(thread, check)
Definition: polsig.h:48
Packet sent[256]
Definition: iostats.h:25
void fdump(fmt::Writer &writer, const void *data, int len)
Definition: fdump.cpp:40
unsigned int bytes_received
Definition: client.h:210
void recv_remaining(int total_expected)
Definition: clientio.cpp:42
void transmit(const void *data, int len, bool needslock=false)
Definition: clientio.cpp:189
void xmit(const void *data, unsigned short datalen)
Definition: client.cpp:486
#define FLEXLOG(id)
Definition: logfacility.h:245
bool isConnected() const
Definition: client.h:301
std::unique_ptr< Network::ClientTransmit > clientTransmit
Definition: network.h:97
std::atomic< u64 > bytes_received
Definition: polstats.h:20
virtual char * getBuffer() POL_OVERRIDE
Definition: packets.h:339
bool GetAndCheckPacketHooked(Client *client, const void *&data, PacketHookData *&phd)
Definition: refptr.h:65
virtual int Receive(void *buffer, int max_expected, SOCKET socket)=0
NetworkManager networkManager
Definition: network.cpp:28
void ReAddPacket(PacketInterface *msg)
Definition: packethelper.h:25
unsigned char buffer[MAXBUFFER]
Definition: client.h:208
#define socket_errno
Definition: wnsckt.cpp:34
#define SOCKET_ERRNO(x)
Definition: wnsckt.cpp:33
#define passert(exp)
Definition: passert.h:62
const char * AddressToString(struct sockaddr *addr)
Definition: sockio.cpp:212
void transmit_encrypted(const void *data, int len)
Definition: clientio.cpp:102
bool encrypt_server_stream
Definition: client.h:217
void transmitmore(const void *data, int len)
Definition: clientio.cpp:266
static std::mutex _SocketMutex
Definition: client.h:193
unsigned char nbits
Definition: ctable.h:14
std::unordered_map< u64, ScriptDiffData > data
Definition: osmod.cpp:966
Crypt::CCryptBase * cryptengine
Definition: client.h:215
Network::IOStats iostats
Definition: network.h:71
std::string ipaddrAsString() const
Definition: clientio.cpp:37
struct Pol::Network::Client::@12 counters
std::atomic< unsigned int > count
Definition: iostats.h:21
std::atomic< unsigned int > bytes
Definition: iostats.h:22
#define ENCRYPTEDPKTBUFFER
Definition: packets.h:349
SVR_KEYDESC keydesc[257]
Definition: ctable.cpp:14
#define passert_always(exp)
Definition: passert.h:80
std::lock_guard< SpinLock > SpinLockGuard
Definition: spinlock.h:33
Clib::SpinLock _fpLog_lock
Definition: client.h:221
Definition: berror.cpp:12
Core::XmitBuffer * last_xmit_buffer
Definition: client.h:241