Torque3D Documentation / _generateds / netInterface.cpp

netInterface.cpp

Engine/source/sim/netInterface.cpp

More...

Public Defines

define
F1(x, y, z) (z ^ (x & (y ^ z)))
define
F2(x, y, z) (z, x, y)
define
F3(x, y, z) (x ^ y ^ z)
define
F4(x, y, z) (y ^ (x | ~z))
define
MD5STEP(f, w, x, y, z, data, s) w = (w + f(x, y, z) + data, s) + x

Public Variables

The global net interface instance.

Public Functions

ConsoleFunctionGroupBegin(NetInterface , "Global <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> functions <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the netInterfaces." )
DefineEngineFunction(allowConnections , void , (bool allow) , "allowConnections(bool allow)" "@brief Sets whether or not the global <a href="/coding/class/classnetinterface/">NetInterface</a> allows connections from remote <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">hosts.\n\n</a>" "@param allow Set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow remote <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">connections.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Networking\n</a>" )

Detailed Description

Public Defines

F1(x, y, z) (z ^ (x & (y ^ z)))
F2(x, y, z) (z, x, y)
F3(x, y, z) (x ^ y ^ z)
F4(x, y, z) (y ^ (x | ~z))
MD5STEP(f, w, x, y, z, data, s) w = (w + f(x, y, z) + data, s) + x

Public Variables

NetInterface * GNet 

The global net interface instance.

Public Functions

ConsoleFunctionGroupBegin(NetInterface , "Global <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> functions <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the netInterfaces." )

ConsoleFunctionGroupEnd(NetInterface )

DefineEngineFunction(allowConnections , void , (bool allow) , "allowConnections(bool allow)" "@brief Sets whether or not the global <a href="/coding/class/classnetinterface/">NetInterface</a> allows connections from remote <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">hosts.\n\n</a>" "@param allow Set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> allow remote <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">connections.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Networking\n</a>" )

rotlFixed(U32 x, U32 y)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "sim/netConnection.h"
 26#include "sim/netInterface.h"
 27#include "core/stream/bitStream.h"
 28#include "math/mRandom.h"
 29#include "core/util/journal/journal.h"
 30#include "console/engineAPI.h"
 31
 32#ifdef GGC_PLUGIN
 33#include "GGCNatTunnel.h" 
 34extern void HandleGGCPacket(NetAddress* addr, unsigned char* data, U32 dataSize);
 35#endif
 36
 37NetInterface *GNet = NULL;
 38
 39NetInterface::NetInterface()
 40{
 41   AssertFatal(GNet == NULL, "ERROR: Multiple net interfaces declared.");
 42   GNet = this;
 43
 44   mLastTimeoutCheckTime = 0;
 45   mAllowConnections = false;
 46   dMemset(mRandomHashData, 0, sizeof(mRandomHashData));
 47   mRandomDataInitialized = false;
 48}
 49
 50void NetInterface::initRandomData()
 51{
 52   mRandomDataInitialized = true;
 53   U32 seed = Platform::getRealMilliseconds();
 54
 55   if(Journal::IsPlaying())
 56      Journal::Read(&seed);
 57   else if(Journal::IsRecording())
 58      Journal::Write(seed);
 59
 60   MRandomR250 myRandom(seed);
 61   for(U32 i = 0; i < 12; i++)
 62      mRandomHashData[i] = myRandom.randI();
 63}
 64
 65void NetInterface::addPendingConnection(NetConnection *connection)
 66{
 67   Con::printf("Adding a pending connection");
 68   mPendingConnections.push_back(connection);
 69}
 70
 71void NetInterface::removePendingConnection(NetConnection *connection)
 72{
 73   for(U32 i = 0; i < mPendingConnections.size(); i++)
 74      if(mPendingConnections[i] == connection)
 75         mPendingConnections.erase(i);
 76}
 77
 78NetConnection *NetInterface::findPendingConnection(const NetAddress *address, U32 connectSequence)
 79{
 80   for(U32 i = 0; i < mPendingConnections.size(); i++)
 81      if(Net::compareAddresses(address, mPendingConnections[i]->getNetAddress()) &&
 82            connectSequence == mPendingConnections[i]->getSequence())
 83         return mPendingConnections[i];
 84   return NULL;
 85}
 86
 87void NetInterface::processPacketReceiveEvent(NetAddress srcAddress, RawData packetData)
 88{
 89
 90   U32 dataSize = packetData.size;
 91   BitStream pStream(packetData.data, dataSize);
 92
 93   // Determine what to do with this packet:
 94
 95   if(packetData.data[0] & 0x01) // it's a protocol packet...
 96   {
 97      // if the LSB of the first byte is set, it's a game data packet
 98      // so pass it to the appropriate connection.
 99
100      // lookup the connection in the addressTable
101      NetConnection *conn = NetConnection::lookup(&srcAddress);
102      if(conn)
103         conn->processRawPacket(&pStream);
104   }
105   else
106   {
107      // Otherwise, it's either a game info packet or a
108      // connection handshake packet.
109
110      U8 packetType;
111      pStream.read(&packetType);
112      NetAddress *addr = &srcAddress;
113
114      if(packetType <= GameHeartbeat || packetType == MasterServerExtendedListResponse)
115         handleInfoPacket(addr, packetType, &pStream);
116#ifdef GGC_PLUGIN
117      else if (packetType == GGCPacket)
118      {
119         HandleGGCPacket(addr, (U8*)packetData.data, dataSize);
120      }
121#endif
122      else
123      {
124         // check if there's a connection already:
125         switch(packetType)
126         {
127            case ConnectChallengeRequest:
128               handleConnectChallengeRequest(addr, &pStream);
129               break;
130            case ConnectRequest:
131               handleConnectRequest(addr, &pStream);
132               break;
133            case ConnectChallengeResponse:
134               handleConnectChallengeResponse(addr, &pStream);
135               break;
136            case ConnectAccept:
137               handleConnectAccept(addr, &pStream);
138               break;
139            case Disconnect:
140               handleDisconnect(addr, &pStream);
141               break;
142            case ConnectReject:
143               handleConnectReject(addr, &pStream);
144               break;
145         }
146      }
147   }
148}
149
150//-----------------------------------------------------------------------------
151//-----------------------------------------------------------------------------
152// Connection handshaking basic overview:
153// The torque engine does a two phase connect handshake to
154// prevent a spoofed source address Denial-of-Service (DOS) attack
155//
156// Basically, the initiator of a connection (client) sends a
157// Connect Challenge Request packet to the server to initiate the connection
158// The server then hashes the source address of the client request
159// with some random magic server data to come up with a 16-byte key that
160// the client can then use to gain entry to the server.
161// This way there are no partially active connection records on the
162// server at all.
163//
164// The client then sends a Connect Request packet to the server,
165// including any game specific data necessary to start a connection (a
166// server password, for instance), along with the key the server sent
167// on the Connect Challenge Response packet.
168//
169// The server, on receipt of the Connect Request, compares the
170// entry key with a computed key, makes sure it can create the requested
171// NetConnection subclass, and then passes all processing on to the connection
172// instance.
173//
174// If the subclass reads and accepts he connect request successfully, the
175// server sends a Connect Accept packet - otherwise the connection
176// is rejected with the sendConnectReject function
177//-----------------------------------------------------------------------------
178//-----------------------------------------------------------------------------
179
180
181void NetInterface::sendConnectChallengeRequest(NetConnection *conn)
182{
183   Con::printf("Sending Connect challenge Request");
184   BitStream *out = BitStream::getPacketStream();
185
186   out->write(U8(ConnectChallengeRequest));
187   out->write(conn->getSequence());
188
189   conn->mConnectSendCount++;
190   conn->mConnectLastSendTime = Platform::getVirtualMilliseconds();
191
192   BitStream::sendPacketStream(conn->getNetAddress());
193}
194
195void NetInterface::handleConnectChallengeRequest(const NetAddress *addr, BitStream *stream)
196{
197   char buf[256];
198   Net::addressToString(addr, buf);
199   Con::printf("Got Connect challenge Request from %s", buf);
200   if(!mAllowConnections)
201      return;
202
203   U32 connectSequence;
204   stream->read(&connectSequence);
205
206   if(!mRandomDataInitialized)
207      initRandomData();
208
209   U32 addressDigest[4];
210   computeNetMD5(addr, connectSequence, addressDigest);
211
212   BitStream *out = BitStream::getPacketStream();
213   out->write(U8(ConnectChallengeResponse));
214   out->write(connectSequence);
215   out->write(addressDigest[0]);
216   out->write(addressDigest[1]);
217   out->write(addressDigest[2]);
218   out->write(addressDigest[3]);
219
220   BitStream::sendPacketStream(addr);
221}
222
223//-----------------------------------------------------------------------------
224
225void NetInterface::handleConnectChallengeResponse(const NetAddress *address, BitStream *stream)
226{
227   Con::printf("Got Connect challenge Response");
228   U32 connectSequence;
229   stream->read(&connectSequence);
230
231   NetConnection *conn = findPendingConnection(address, connectSequence);
232   if(!conn || conn->getConnectionState() != NetConnection::AwaitingChallengeResponse)
233      return;
234
235   U32 addressDigest[4];
236   stream->read(&addressDigest[0]);
237   stream->read(&addressDigest[1]);
238   stream->read(&addressDigest[2]);
239   stream->read(&addressDigest[3]);
240   conn->setAddressDigest(addressDigest);
241
242   conn->setConnectionState(NetConnection::AwaitingConnectResponse);
243   conn->mConnectSendCount = 0;
244   Con::printf("Sending Connect Request");
245   sendConnectRequest(conn);
246}
247
248//-----------------------------------------------------------------------------
249
250void NetInterface::sendConnectRequest(NetConnection *conn)
251{
252   BitStream *out = BitStream::getPacketStream();
253   out->write(U8(ConnectRequest));
254   out->write(conn->getSequence());
255
256   U32 addressDigest[4];
257   conn->getAddressDigest(addressDigest);
258   out->write(addressDigest[0]);
259   out->write(addressDigest[1]);
260   out->write(addressDigest[2]);
261   out->write(addressDigest[3]);
262
263   out->writeString(conn->getClassName());
264   conn->writeConnectRequest(out);
265   conn->mConnectSendCount++;
266   conn->mConnectLastSendTime = Platform::getVirtualMilliseconds();
267
268   BitStream::sendPacketStream(conn->getNetAddress());
269}
270
271//-----------------------------------------------------------------------------
272
273void NetInterface::handleConnectRequest(const NetAddress *address, BitStream *stream)
274{
275   if(!mAllowConnections)
276      return;
277   Con::printf("Got Connect Request");
278   U32 connectSequence;
279   stream->read(&connectSequence);
280
281   // see if the connection is in the main connection table:
282
283   NetConnection *connect = NetConnection::lookup(address);
284   if(connect && connect->getSequence() == connectSequence)
285   {
286      sendConnectAccept(connect);
287      return;
288   }
289   U32 addressDigest[4];
290   U32 computedAddressDigest[4];
291
292   stream->read(&addressDigest[0]);
293   stream->read(&addressDigest[1]);
294   stream->read(&addressDigest[2]);
295   stream->read(&addressDigest[3]);
296
297   computeNetMD5(address, connectSequence, computedAddressDigest);
298   if(addressDigest[0] != computedAddressDigest[0] ||
299      addressDigest[1] != computedAddressDigest[1] ||
300      addressDigest[2] != computedAddressDigest[2] ||
301      addressDigest[3] != computedAddressDigest[3])
302      return; // bogus connection attempt
303
304   if(connect)
305   {
306      if(connect->getSequence() > connectSequence)
307         return; // the existing connection should be kept - the incoming request is stale.
308      else
309         connect->deleteObject(); // disconnect this one, and allow the new one to be created.
310   }
311
312   char connectionClass[255];
313   stream->readString(connectionClass);
314
315   ConsoleObject *co = ConsoleObject::create(connectionClass);
316   NetConnection *conn = dynamic_cast<NetConnection *>(co);
317   if(!conn || !conn->canRemoteCreate())
318   {
319      delete co;
320      return;
321   }
322   conn->registerObject();
323   conn->setNetAddress(address);
324   conn->setNetworkConnection(true);
325   conn->setSequence(connectSequence);
326
327   const char *errorString = NULL;
328   if(!conn->readConnectRequest(stream, &errorString))
329   {
330      sendConnectReject(conn, errorString);
331      conn->deleteObject();
332      return;
333   }
334   conn->setNetworkConnection(true);
335   conn->onConnectionEstablished(false);
336   conn->setEstablished();
337   conn->setConnectSequence(connectSequence);
338   sendConnectAccept(conn);
339}
340
341//-----------------------------------------------------------------------------
342
343void NetInterface::sendConnectAccept(NetConnection *conn)
344{
345   BitStream *out = BitStream::getPacketStream();
346   out->write(U8(ConnectAccept));
347   out->write(conn->getSequence());
348   conn->writeConnectAccept(out);
349   BitStream::sendPacketStream(conn->getNetAddress());
350}
351
352void NetInterface::handleConnectAccept(const NetAddress *address, BitStream *stream)
353{
354   U32 connectSequence;
355   stream->read(&connectSequence);
356   NetConnection *conn = findPendingConnection(address, connectSequence);
357   if(!conn || conn->getConnectionState() != NetConnection::AwaitingConnectResponse)
358      return;
359   const char *errorString = NULL;
360   if(!conn->readConnectAccept(stream, &errorString))
361   {
362      conn->handleStartupError(errorString);
363      removePendingConnection(conn);
364      conn->deleteObject();
365      return;
366   }
367
368   removePendingConnection(conn); // remove from the pending connection list
369   conn->setNetworkConnection(true);
370   conn->onConnectionEstablished(true); // notify the connection that it has been established
371   conn->setEstablished(); // installs the connection in the connection table, and causes pings/timeouts to happen
372   conn->setConnectSequence(connectSequence);
373}
374
375void NetInterface::sendConnectReject(NetConnection *conn, const char *reason)
376{
377   if(!reason)
378      return; // if the stream is NULL, we reject silently
379
380   BitStream *out = BitStream::getPacketStream();
381   out->write(U8(ConnectReject));
382   out->write(conn->getSequence());
383   out->writeString(reason);
384   BitStream::sendPacketStream(conn->getNetAddress());
385}
386
387void NetInterface::handleConnectReject(const NetAddress *address, BitStream *stream)
388{
389   U32 connectSequence;
390   stream->read(&connectSequence);
391   NetConnection *conn = findPendingConnection(address, connectSequence);
392   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
393                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
394      return;
395   removePendingConnection(conn);
396   char reason[256];
397   stream->readString(reason);
398   conn->onConnectionRejected(reason);
399   conn->deleteObject();
400}
401
402void NetInterface::handleDisconnect(const NetAddress *address, BitStream *stream)
403{
404   NetConnection *conn = NetConnection::lookup(address);
405   if(!conn)
406      return;
407
408   U32 connectSequence;
409   char reason[256];
410
411   stream->read(&connectSequence);
412   stream->readString(reason);
413
414   if(conn->getSequence() != connectSequence)
415      return;
416
417   conn->onDisconnect(reason);
418   conn->deleteObject();
419}
420
421void NetInterface::handleInfoPacket(const NetAddress *address, U8 packetType, BitStream *stream)
422{
423}
424
425void NetInterface::processClient()
426{
427   NetObject::collapseDirtyList(); // collapse all the mask bits...
428   for(NetConnection *walk = NetConnection::getConnectionList();
429      walk; walk = walk->getNext())
430   {
431      if(walk->isConnectionToServer() && (walk->isLocalConnection() || walk->isNetworkConnection()))
432         walk->checkPacketSend(false);
433   }
434}
435
436void NetInterface::processServer()
437{
438   NetObject::collapseDirtyList(); // collapse all the mask bits...
439   for(NetConnection *walk = NetConnection::getConnectionList();
440      walk; walk = walk->getNext())
441   {
442      if(!walk->isConnectionToServer() && (walk->isLocalConnection() || walk->isNetworkConnection()))
443         walk->checkPacketSend(false);
444   }
445}
446
447void NetInterface::startConnection(NetConnection *conn)
448{
449   addPendingConnection(conn);
450   conn->mConnectionSendCount = 0;
451   conn->setConnectSequence(Platform::getVirtualMilliseconds());
452   conn->setConnectionState(NetConnection::AwaitingChallengeResponse);
453
454   // This is a the client side of the connection, so set the connection to
455   // server flag. We need to set this early so that if the connection times
456   // out, its onRemove() will handle the cleanup properly.
457   conn->setIsConnectionToServer();
458
459   // Everything set, so send off the request.
460   sendConnectChallengeRequest(conn);
461}
462
463void NetInterface::sendDisconnectPacket(NetConnection *conn, const char *reason)
464{
465   Con::printf("Issuing Disconnect packet.");
466
467   // send a disconnect packet...
468   U32 connectSequence = conn->getSequence();
469
470   BitStream *out = BitStream::getPacketStream();
471   out->write(U8(Disconnect));
472   out->write(connectSequence);
473   out->writeString(reason);
474
475   BitStream::sendPacketStream(conn->getNetAddress());
476}
477
478void NetInterface::checkTimeouts()
479{
480   U32 time = Platform::getVirtualMilliseconds();
481   if(time > mLastTimeoutCheckTime + TimeoutCheckInterval)
482   {
483      for(U32 i = 0; i < mPendingConnections.size();)
484      {
485         NetConnection *pending = mPendingConnections[i];
486
487         if(pending->getConnectionState() == NetConnection::AwaitingChallengeResponse &&
488            time > pending->mConnectLastSendTime + ChallengeRetryTime)
489         {
490            if(pending->mConnectSendCount > ChallengeRetryCount)
491            {
492               pending->onConnectTimedOut();
493               removePendingConnection(pending);
494               pending->deleteObject();
495               continue;
496            }
497            else
498               sendConnectChallengeRequest(pending);
499         }
500         else if(pending->getConnectionState() == NetConnection::AwaitingConnectResponse &&
501            time > pending->mConnectLastSendTime + ConnectRetryTime)
502         {
503            if(pending->mConnectSendCount > ConnectRetryCount)
504            {
505               pending->onConnectTimedOut();
506               removePendingConnection(pending);
507               pending->deleteObject();
508               continue;
509            }
510            else
511               sendConnectRequest(pending);
512         }
513         i++;
514      }
515      mLastTimeoutCheckTime = time;
516      NetConnection *walk = NetConnection::getConnectionList();
517
518      while(walk)
519      {
520         NetConnection *next = walk->getNext();
521         if(walk->checkTimeout(time))
522         {
523            // this baddie timed out
524            walk->onTimedOut();
525            walk->deleteObject();
526         }
527         walk = next;
528      }
529   }
530}
531
532#define F1(x, y, z) (z ^ (x & (y ^ z)))
533#define F2(x, y, z) F1(z, x, y)
534#define F3(x, y, z) (x ^ y ^ z)
535#define F4(x, y, z) (y ^ (x | ~z))
536
537inline U32 rotlFixed(U32 x, U32 y)
538{
539   return (x >> y) | (x << (32 - y));
540}
541
542#define MD5STEP(f, w, x, y, z, data, s) w = rotlFixed(w + f(x, y, z) + data, s) + x
543
544void NetInterface::computeNetMD5(const NetAddress *address, U32 connectSequence, U32 digest[4])
545{
546   digest[0] = 0x67452301L;
547   digest[1] = 0xefcdab89L;
548   digest[2] = 0x98badcfeL;
549   digest[3] = 0x10325476L;
550
551
552   U32 a, b, c, d;
553
554   a=digest[0];
555   b=digest[1];
556   c=digest[2];
557   d=digest[3];
558
559   U32 in[16];
560   in[0] = address->type;
561   in[1] = address->getHash();
562   in[2] = address->port;
563   in[3] = connectSequence;
564   for(U32 i = 0; i < 12; i++)
565      in[i + 4] = mRandomHashData[i];
566
567   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
568   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
569   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
570   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
571   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
572   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
573   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
574   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
575   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
576   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
577   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
578   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
579   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
580   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
581   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
582   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
583
584   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
585   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
586   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
587   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
588   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
589   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
590   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
591   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
592   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
593   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
594   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
595   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
596   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
597   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
598   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
599   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
600
601   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
602   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
603   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
604   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
605   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
606   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
607   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
608   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
609   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
610   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
611   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
612   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
613   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
614   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
615   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
616   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
617
618   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
619   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
620   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
621   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
622   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
623   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
624   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
625   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
626   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
627   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
628   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
629   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
630   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
631   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
632   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
633   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
634
635   digest[0]+=<a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a>;
636   digest[1]+=<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a91b64995742fd30063314f12340b4b5a">b</a>;
637   digest[2]+=c;
638   digest[3]+=d;
639}
640
641ConsoleFunctionGroupBegin(NetInterface, "Global control functions for the netInterfaces.");
642
643DefineEngineFunction( allowConnections, void, ( bool allow ), , "allowConnections(bool allow)"
644   "@brief Sets whether or not the global NetInterface allows connections from remote hosts.\n\n"
645
646   "@param allow Set to true to allow remote connections.\n"
647
648   "@ingroup Networking\n")
649{
650   GNet->setAllowsConnections(allow);
651}
652
653ConsoleFunctionGroupEnd(NetInterface);
654
655