Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
tcpserver.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2011 John Selbie
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #include "commonincludes.hpp"
18 #include "tcpserver.h"
19 #include "server.h"
20 #include "stunsocket.h"
21 
22 #include "stunsocketthread.h"
23 
24 // client sockets are now level triggered
26 
28 
29 // listen sockets are always level triggered (that way, when we recover from
30 // hitting a max connections condition, we don't have to worry about
31 // missing a notification
33 
34 // notification pipe could go either way
36 
38 
39 
41 {
42  _pipe[0] = _pipe[1] = -1;
43  _pthread = (pthread_t)-1;
44  Reset();
45 }
46 
48 {
50 
52  ClosePipes();
53 
54  _fListenSocketsOnEpoll = false;
55 
56  memset(&_tsaListen, '\0', sizeof(_tsaListen));
57 
58  _fNeedToExit = false;
60  _role = RolePP;
61 
62  memset(&_tsa, '\0', sizeof(_tsa));
63 
65 
66  _pthread = (pthread_t)-1;
67  _fThreadIsValid = false;
68 
69 
71 
72  // the thread should have closed all the connections
77 
80 
81  _timeLastSweep = time(NULL);
82 }
83 
84 
85 
87 {
88  Stop(); // calls Reset
89  ASSERT(_pipe[0] == -1); // quick assert to make sure reset was called
90 }
91 
92 
94 {
95  HRESULT hr = S_OK;
96  int ret;
97 
98  ASSERT(_pipe[0] == -1);
99  ASSERT(_pipe[1] == -1);
100 
101  ret = ::pipe(_pipe);
102 
103  ChkIf(ret == -1, ERRNOHR);
104 
105 Cleanup:
106  return hr;
107 }
108 
110 {
111  if (_pipe[0] != -1)
112  {
113  close(_pipe[0]);
114  _pipe[0] = -1;
115  }
116 
117  if (_pipe[1] != -1)
118  {
119  close(_pipe[1]);
120  _pipe[1] = -1;
121  }
122 }
123 
125 {
126  ASSERT(_pipe[1] != -1);
127  int ret;
128 
129  // _pipe[1] is the write end of the pipe
130  char ch = 'x';
131  ret = write(_pipe[1], &ch, 1);
132  return (ret > 0) ? S_OK : S_FALSE;
133 }
134 
135 
136 
137 
139 {
140  HRESULT hr = S_OK;
141 
142  if (fEnable != _fListenSocketsOnEpoll)
143  {
144  for (int role = 0; role < 4; role++)
145  {
146  int sock = _socketTable[role];
147 
148  if (sock == -1)
149  {
150  continue;
151  }
152 
153  if (fEnable)
154  {
156  }
157  else
158  {
159  ChkA(_spPolling->Remove(sock));
160  }
161  }
162 
163  _fListenSocketsOnEpoll = fEnable;
164  }
165 
166 Cleanup:
167  return hr;
168 }
169 
170 
172 {
173  HRESULT hr = S_OK;
174  int ret;
175 
176 
177  for (int r = (int)RolePP; r <= (int)RoleAA; r++)
178  {
179  if (_tsaListen.set[r].fValid)
180  {
181  ChkA(_socketListenArray[r].TCPInit(_tsaListen.set[r].addr, (SocketRole)r, true));
183  ChkA(_socketListenArray[r].SetNonBlocking(true));
184  ret = listen(_socketTable[r], 128); // 128 - large backlog.
185  ChkIfA(ret == -1, ERRNOHR);
186  _countSocks++;
187  }
188  else
189  {
190  _socketTable[r] = -1;
191  }
192  }
193 
194  _fListenSocketsOnEpoll = false;
195 
196 Cleanup:
197  return hr;
198 }
199 
201 {
202  for (size_t r = 0; r < ARRAYSIZE(_socketTable); r++)
203  {
205  _socketTable[r] = -1;
206  }
207  _countSocks = 0;
208 
209 }
210 
212 {
213  ASSERT(sock != -1);
214 
215  if (sock != -1)
216  {
217  for (size_t i = 0; i < ARRAYSIZE(_socketTable); i++)
218  {
219  if (_socketTable[i] == sock)
220  {
221  return &_socketListenArray[i];
222  }
223  }
224  }
225  return NULL;
226 }
227 
228 
229 
230 HRESULT CTCPStunThread::Init(const TransportAddressSet& tsaListen, const TransportAddressSet& tsaHandler, IStunAuth* pAuth, int maxConnections, boost::shared_ptr<RateLimiter>& spLimiter)
231 {
232  HRESULT hr = S_OK;
233  int ret;
234  int countListen = 0;
235  int countHandler = 0;
236 
237  // we shouldn't be initialized at this point
238  ChkIfA(_pipe[0] != -1, E_UNEXPECTED);
240 
241  _maxConnections = (maxConnections > 0) ? maxConnections : c_MaxNumberOfConnectionsDefault;
242 
243  // Max sure we didn't accidently pass in anything crazy
244  ChkIfA(_maxConnections >= 100000, E_INVALIDARG);
245 
246  for (size_t i = 0; i < ARRAYSIZE(_tsa.set); i++)
247  {
248  countListen += tsaListen.set[i].fValid ? 1 : 0;
249  countHandler += tsaHandler.set[i].fValid ? 1 : 0;
250  }
251 
252  ChkIfA(countListen == 0, E_INVALIDARG);
253  ChkIfA(countHandler == 0, E_INVALIDARG);
254 
255  _tsaListen = tsaListen;
256  _tsa = tsaHandler;
257 
258  _spAuth.Attach(pAuth);
259 
261 
262  ChkA(CreatePipes());
263 
264  // +5 for listening sockets and pipe
266 
267 
268  // add listen socket to epoll
269  ASSERT(_fListenSocketsOnEpoll == false);
271 
272 
273  // add read end of pipe to epoll so we can get notified of when a signal to exit has occurred
275 
277  ChkIfA(ret == -1, E_FAIL);
278 
280  ChkIfA(ret == -1, E_FAIL);
281 
284 
285  _spLimiter = spLimiter;
286 
287  _fNeedToExit = false;
288 
289 Cleanup:
290  if (FAILED(hr))
291  {
292  Reset();
293  }
294  return hr;
295 }
296 
297 
299 {
300  int ret;
301  HRESULT hr = S_OK;
302 
304 
305  ChkIf(_pipe[0] == -1, E_UNEXPECTED); // Init hasn't been called
306 
307  _fNeedToExit = false;
308  ret = ::pthread_create(&_pthread, NULL, ThreadFunction, this);
309  ChkIfA(ret != 0, ERRNO_TO_HRESULT(ret));
310 
311  _fThreadIsValid = true;
312 
313 Cleanup:
314  return hr;
315 }
316 
317 
319 {
320  void* pRetValueFromThread = NULL;
321 
322  if (_fThreadIsValid)
323  {
324  _fNeedToExit = true;
325 
326  // signal the thread to exit
328 
329  // wait for the thread to exit
330  ::pthread_join(_pthread, &pRetValueFromThread);
331 
332  _fThreadIsValid = false;
333  }
334 
335  // we don't support restarting a thread (as that would require flushing _pipe)
336  // so go ahead and make it impossible for that to happen
337  Reset();
338  return S_OK;
339 }
340 
342 {
343  ((CTCPStunThread*)pThis)->Run();
344  return NULL;
345 }
346 
348 {
349  size_t connCount = _pNewConnList->Size() + _pOldConnList->Size();
350  return (connCount == 0) ? -1 : (int)c_sweepTimeoutSeconds;
351 }
352 
354 {
355  size_t size1 = _pNewConnList->Size();
356  size_t size2 = _pOldConnList->Size();
357 
358  return ((size1 + size2) >= (size_t)_maxConnections);
359 }
360 
361 
363 {
364  HRESULT hrPoll;
365 
366  Logging::LogMsg(LL_DEBUG, "Starting TCP listening thread (%d sockets)\n", _countSocks);
367 
368  _timeLastSweep = time(NULL);
369 
370  while (_fNeedToExit == false)
371  {
372  PollEvent pollevent = {};
373  // wait for a notification
374  int timeout = GetTimeoutSeconds();
375  CStunSocket* pListenSocket = NULL;
376 
377  // turn off epoll eventing from the listen sockets if we are at max connections
378  // otherwise, make sure it is enabled.
380 
381  hrPoll = _spPolling->WaitForNextEvent(&pollevent, timeout);
382 
383  if ( _fNeedToExit || (pollevent.fd == _pipe[0]) )
384  {
385  break;
386  }
387 
388  // hrPoll will be S_OK if there was an event. S_FALSE otherwise
389  ASSERT(SUCCEEDED(hrPoll));
390 
391  if (hrPoll == S_OK)
392  {
394  {
395  Logging::LogMsg(LL_VERBOSE, "socket %d: %x (%s%s%s%s%s%s)", pollevent.fd, pollevent.eventflags,
396  (pollevent.eventflags&IPOLLING_READ) ? " IPOLLING_READ " : "",
397  (pollevent.eventflags&IPOLLING_WRITE) ? " IPOLLING_WRITE " : "",
398  (pollevent.eventflags&IPOLLING_RDHUP) ? " IPOLLING_RDHUP " : "",
399  (pollevent.eventflags&IPOLLING_HUP) ? " IPOLLING_HUP " : "",
400  (pollevent.eventflags&IPOLLING_ERROR) ? " IPOLLING_ERROR " : "",
401  (pollevent.eventflags&IPOLLING_PRI) ? " IPOLLING_PRI " : "");
402  }
403 
404  pListenSocket = GetListenSocket(pollevent.fd);
405  if (pListenSocket)
406  {
407  StunConnection* pConn = AcceptConnection(pListenSocket);
408 
409  // as an optimization - see if we can do a read on the new connection
410  if (pConn)
411  {
413  }
414  }
415  else
416  {
417  ProcessConnectionEvent(pollevent.fd, pollevent.eventflags);
418  }
419  }
420 
421  // close any connection that we haven't heard from in a while
423  }
424 
425  ThreadCleanup();
426 
427  Logging::LogMsg(LL_DEBUG, "TCP Thread exiting");
428 }
429 
430 void CTCPStunThread::ProcessConnectionEvent(int sock, uint32_t eventflags)
431 {
432  StunConnection** ppConn = NULL;
433  StunConnection* pConn = NULL;
434 
435  ppConn = _pNewConnList->Lookup(sock);
436  if (ppConn == NULL)
437  {
438  ppConn = _pOldConnList->Lookup(sock);
439  }
440 
441  if ((ppConn == NULL) || (*ppConn == NULL))
442  {
443  Logging::LogMsg(LL_DEBUG, "Warning - ProcessConnectionEvent could not resolve socket into connection (socket == %d)", sock);
444  return;
445  }
446 
447  pConn = *ppConn;
448 
449  // if event flags is an error or a hangup, that's ok, the subsequent call below will consume the error and close the connection as appropriate
450 
451  if (pConn->_state == ConnectionState_Receiving)
452  {
454  }
455  else if (pConn->_state == ConnectionState_Transmitting)
456  {
458  }
459 
460 
461 }
462 
464 {
465  bool result = true;
466  if (_spLimiter.get())
467  {
468  result = _spLimiter->RateCheck(addr);
469 
470  if (result == false)
471  {
473  {
474  char szIP[100];
475  addr.ToStringBuffer(szIP, 100);
476  Logging::LogMsg(LL_VERBOSE, "Rate Limiter has blocked incoming connection from IP %s", szIP);
477  }
478  }
479  }
480  return result;
481 }
482 
483 
485 {
486  int listensock = pListenSocket->GetSocketHandle();
487  SocketRole role = pListenSocket->GetRole();
488  int clientsock = -1;
489  int socktmp = -1;
490  sockaddr_storage addrClient;
491  socklen_t socklen = sizeof(addrClient);
492  StunConnection* pConn = NULL;
493  HRESULT hr = S_OK;
494  int insertresult;
495  int err;
496  bool allowed_to_pass = true;
497 
498  ASSERT(listensock != -1);
499  ASSERT(::IsValidSocketRole(role));
500 
501  socktmp = ::accept(listensock, (sockaddr*)&addrClient, &socklen);
502 
503  err = errno;
504  Logging::LogMsg(LL_VERBOSE, "accept returns %d (errno == %d)", socktmp, (socktmp<0)?err:0);
505  ChkIfA(socktmp == -1, E_FAIL);
506 
507  // --- rate limit check-------
508  allowed_to_pass = RateCheck(CSocketAddress(addrClient));
509  ChkIf(allowed_to_pass==false, E_FAIL); // this will trigger the socket to be immediately closed
510  // --------------------------
511 
512 
513  clientsock = socktmp;
514 
515  pConn = _connectionpool.GetConnection(clientsock, role);
516  ChkIfA(pConn == NULL, E_FAIL); // Our connection pool has nothing left to give, only thing to do is abort this connection and close the socket
517  socktmp = -1;
518 
519  ChkA(pConn->_stunsocket.SetNonBlocking(true));
520 
522 
523  // add connection to our tracking tables
524  pConn->_idHashTable = (_pNewConnList == &_hashConnections1) ? 1 : 2;
525  insertresult = _pNewConnList->Insert(clientsock, pConn);
526 
527  // out of space in the lookup tables?
528  ChkIfA(insertresult == -1, E_FAIL);
529 
531  {
532  char szIPRemote[100];
533  char szIPLocal[100];
534  pConn->_stunsocket.GetLocalAddress().ToStringBuffer(szIPLocal, ARRAYSIZE(szIPLocal));
535  pConn->_stunsocket.GetRemoteAddress().ToStringBuffer(szIPRemote, ARRAYSIZE(szIPRemote));
536  Logging::LogMsg(LL_VERBOSE, "accepting new connection on socket %d from %s on interface %s", pConn->_stunsocket.GetSocketHandle(), szIPRemote, szIPLocal);
537  }
538 
539 
540 Cleanup:
541 
542  if (FAILED(hr))
543  {
544  CloseConnection(pConn);
545  pConn = NULL;
546  if (socktmp != -1)
547  {
548  close(socktmp);
549  }
550  }
551 
552  return pConn;
553 }
554 
556 {
557  uint8_t buffer[MAX_STUN_MESSAGE_SIZE];
558  size_t bytesneeded;
559  int bytesread;
560  HRESULT hr = S_OK;
562  int err;
563  bool allowed_to_pass = true;
564 
565  int sock = pConn->_stunsocket.GetSocketHandle();
566 
567  while (true)
568  {
572 
573  bytesneeded = pConn->_reader.HowManyBytesNeeded();
574 
575  ChkIfA(bytesneeded == 0, E_UNEXPECTED);
576 
577  bytesread = recv(sock, buffer, bytesneeded, 0);
578 
579  err = errno;
580  Logging::LogMsg(LL_VERBOSE, "recv on socket %d returns %d (errno=%d)", sock, bytesread, (bytesread<0)?err:0);
581 
582 
583  if ((bytesread < 0) && ((err == EWOULDBLOCK) || (err==EAGAIN)) )
584  {
585  // no more bytes to be consumed - bail out of here and return success
586  break;
587  }
588 
589 
590  // any other error (or an EOF/shutdown notification) means the connection is dead
591  ChkIf(bytesread <= 0, E_FAIL);
592 
593  // we got data, now let's feed it into the reader
594  readerstate = pConn->_reader.AddBytes(buffer, bytesread);
595 
597 
598  if (readerstate == CStunMessageReader::BodyValidated)
599  {
600  StunMessageIn msgIn;
601  StunMessageOut msgOut;
602 
603  msgIn.addrLocal = pConn->_stunsocket.GetLocalAddress();
604  msgIn.addrRemote = pConn->_stunsocket.GetRemoteAddress();
605  msgIn.fConnectionOriented = true;
606  msgIn.pReader = &pConn->_reader;
607  msgIn.socketrole = pConn->_stunsocket.GetRole();
608 
609  msgOut.spBufferOut = pConn->_spOutputBuffer;
610 
611  allowed_to_pass = this->RateCheck(msgIn.addrRemote);
612  ChkIf(allowed_to_pass == false, E_FAIL);
613 
615 
616  // success - transition to the response state
618 
619  // change the socket such that we only listen for "write events"
621 
622  // optimization - go ahead and try to send the response
624  // WriteBytesForConnection will close the connection on error
625 
626  // so we can't assume the connection is still alive. And if it's not alive, pConn likely got deleted
627  // either refetch from the hash tables, or invent an out parameter on WriteBytesForConnection and ConsumeRemoteClose to better propagate the close state of the connection
628  pConn = NULL;
629 
630  break;
631  }
632 
633  // keep trying to read more bytes
634  }
635 
636 Cleanup:
637  if (FAILED(hr))
638  {
639  CloseConnection(pConn);
640  }
641 
642  return hr;
643 }
644 
646 {
647  HRESULT hr = S_OK;
648  int sock = pConn->_stunsocket.GetSocketHandle();
649  int sent = -1;
650  uint8_t* pData = NULL;
651  size_t bytestotal, bytesremaining;
652  bool fForceClose = false;
653  int err;
654 
655 
656 
657  ASSERT(pConn != NULL);
658 
659  pData = pConn->_spOutputBuffer->GetData();
660  bytestotal = pConn->_spOutputBuffer->GetSize();
661 
662 
663  while (true)
664  {
666  ASSERT(bytestotal > pConn->_txCount);
667 
668  bytesremaining = bytestotal - pConn->_txCount;
669 
670  sent = ::send(sock, pData + pConn->_txCount, bytesremaining, 0);
671 
672  err = errno;
673 
674  // Can't send any more bytes, come back again later
675  ChkIf( ((sent == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))), S_OK);
676 
677  Logging::LogMsg(LL_VERBOSE, "send on socket %d returns %d (errno=%d)", sock, sent, (sent<0)?err:0);
678 
679  // general connection error
680  ChkIf(sent == -1, E_FAIL);
681 
682  // can "send" ever return 0?
683  ChkIfA(sent == 0, E_UNEXPECTED);
684 
685  pConn->_txCount += sent;
686 
687  // txCount should never exceed the total output message size, right?
688  ASSERT(pConn->_txCount <= bytestotal);
689 
690  if (pConn->_txCount >= bytestotal)
691  {
694 
695  // go back to listening for read events
697 
698  pConn = NULL;
699  break;
700  }
701  // loop back and try to send the remaining bytes
702  }
703 
704 Cleanup:
705  if ((FAILED(hr) || fForceClose))
706  {
707  CloseConnection(pConn);
708  }
709 
710  return hr;
711 }
712 
714 {
715  if (pConn)
716  {
717  int sock = pConn->_stunsocket.GetSocketHandle();
718 
719  Logging::LogMsg(LL_VERBOSE, "Closing socket %d\n", sock);
720 
722  pConn->_stunsocket.Close();
723 
724  // now figure out which hash table we were in
725  if (pConn->_idHashTable == 1)
726  {
727  VERIFY(_hashConnections1.Remove(sock) != -1);
728  }
729  else if (pConn->_idHashTable == 2)
730  {
731  VERIFY(_hashConnections2.Remove(sock) != -1);
732  }
733  else
734  {
735  ASSERT(pConn->_idHashTable == -1);
736  }
737 
739  }
740 }
741 
742 
744 {
745  StunThreadConnectionMap::Item* pItem = pConnMap->LookupByIndex(0);
746  while (pItem)
747  {
748  CloseConnection(pItem->value);
749  pItem = pConnMap->LookupByIndex(0);
750  }
751 }
752 
754 {
755  time_t timeCurrent = time(NULL);
756  StunThreadConnectionMap* pSwap = NULL;
757 
758  // should we try to scale the timeout based on the active number of connections?
759 
760  if ((timeCurrent - _timeLastSweep) >= c_sweepTimeoutSeconds)
761  {
762  if (_pOldConnList->Size())
763  {
764  Logging::LogMsg(LL_VERBOSE, "SweepDeadConnections closing %d connections", _pOldConnList->Size());
765  }
766 
768 
769  _timeLastSweep = time(NULL);
770 
771 
772  pSwap = _pOldConnList;
774  _pNewConnList = pSwap;
775  }
776 }
777 
778 
780 {
783 }
784 
785 
786 
787 
788 
789 // ------------------------------------------------------------------
790 
792 {
793  for (size_t i = 0; i < ARRAYSIZE(_threads); i++)
794  {
795  _threads[i] = NULL;
796  }
797 }
798 
800 {
801  Logging::LogMsg(LL_DEBUG, "~CTCPServer() - exiting");
802  Stop();
803 }
804 
805 
806 void CTCPServer::InitTSA(TransportAddressSet* pTSA, SocketRole role, bool fValid, const CSocketAddress& addrListen, const CSocketAddress& addrAdvertise)
807 {
808  if (fValid == false)
809  {
810  pTSA->set[role].fValid = false;
811  pTSA->set[role].addr = CSocketAddress();
812  }
813  else
814  {
815  pTSA->set[role].fValid = true;
816 
817  if (addrAdvertise.IsIPAddressZero())
818  {
819  pTSA->set[role].addr = addrListen;
820  }
821  else
822  {
823  pTSA->set[role].addr = addrAdvertise;
824  pTSA->set[role].addr.SetPort(addrListen.GetPort());
825  }
826  }
827 
828 }
829 
831 {
832  HRESULT hr = S_OK;
833  TransportAddressSet tsaListenAll;
834  TransportAddressSet tsaHandler;
835  boost::shared_ptr<RateLimiter> spLimiter;
836 
837  ChkIfA(_threads[0] != NULL, E_UNEXPECTED); // we can't already be initialized, right?
838 
839  // optional code: create an authentication provider and initialize it here (if you want authentication)
840  // set the _spAuth member to reference it
841  // Chk(CYourAuthProvider::CreateInstanceNoInit(&_spAuth));
842 
843  // tsaHandler is sort of a hack for TCP. It's really just a glorified indication to the the
844  // CStunRequestHandler code to figure out if it can offer a CHANGED-ADDRESS attribute.
845 
846  InitTSA(&tsaHandler, RolePP, config.fHasPP, config.addrPP, config.addrPrimaryAdvertised);
847  InitTSA(&tsaHandler, RolePA, config.fHasPA, config.addrPA, config.addrPrimaryAdvertised);
848  InitTSA(&tsaHandler, RoleAP, config.fHasAP, config.addrAP, config.addrAlternateAdvertised);
849  InitTSA(&tsaHandler, RoleAA, config.fHasAA, config.addrAA, config.addrAlternateAdvertised);
850 
851  InitTSA(&tsaListenAll, RolePP, config.fHasPP, config.addrPP, CSocketAddress());
852  InitTSA(&tsaListenAll, RolePA, config.fHasPA, config.addrPA, CSocketAddress());
853  InitTSA(&tsaListenAll, RoleAP, config.fHasAP, config.addrAP, CSocketAddress());
854  InitTSA(&tsaListenAll, RoleAA, config.fHasAA, config.addrAA, CSocketAddress());
855 
856  if (config.fEnableDosProtection)
857  {
858  spLimiter = boost::shared_ptr<RateLimiter>(new RateLimiter(20000, config.fMultiThreadedMode));
859  }
860 
861  if (config.fMultiThreadedMode == false)
862  {
863  _threads[0] = new CTCPStunThread();
864 
865  ChkA(_threads[0]->Init(tsaListenAll, tsaHandler, _spAuth, config.nMaxConnections, spLimiter));
866  }
867  else
868  {
869  for (int threadindex = 0; threadindex < 4; threadindex++)
870  {
871 
872  if (tsaHandler.set[threadindex].fValid)
873  {
874  TransportAddressSet tsaListen = tsaListenAll;
875  // Since we already initialized tsaListenAll above,
876  // make a copy and uninit each one that isn't going to be managed
877  // by the thread we are about to create
878  for (int temp = 0; temp < 4; temp++)
879  {
880  if (temp != threadindex)
881  {
882  tsaListen.set[temp].fValid = false;
883  tsaListen.set[temp].addr = CSocketAddress();
884  }
885  }
886 
887  _threads[threadindex] = new CTCPStunThread();
888 
889  Chk(_threads[threadindex]->Init(tsaListen, tsaHandler, _spAuth, config.nMaxConnections, spLimiter));
890  }
891  }
892  }
893 
894 Cleanup:
895  if (FAILED(hr))
896  {
897  Shutdown();
898  }
899  return hr;
900 }
901 
903 {
904  for (int role = (int)RolePP; role <= (int)RoleAA; role++)
905  {
906  // destructor of each TCP thread will stop the thread before returning
907  delete _threads[role];
908  _threads[role] = NULL;
909  }
910 
912 
913  return S_OK;
914 }
915 
917 {
918  HRESULT hr = S_OK;
919 
920  for (int role = (int)RolePP; role <= (int)RoleAA; role++)
921  {
922  if (_threads[role])
923  {
924  ChkA(_threads[role]->Start());
925  }
926  }
927 Cleanup:
928  return hr;
929 }
930 
932 {
933  // for now shutdown and stop are equivalent (something about the notification "pipe" thing would need to get reset to restart the thread
934  // we don't really support restarting a server anyway
935  Shutdown();
936  return S_OK;
937 }
938 
939 
940 
941 
942 
const uint32_t MAX_STUN_MESSAGE_SIZE
Definition: stuntypes.h:178
#define S_OK
Definition: hresult.h:46
int GetTimeoutSeconds()
Definition: tcpserver.cpp:347
#define ASSERT(expr)
bool IsValidSocketRole(SocketRole sr)
Definition: socketrole.h:31
void CloseAllConnections(StunThreadConnectionMap *pConnMap)
Definition: tcpserver.cpp:743
void CloseConnection(StunConnection *pConn)
Definition: tcpserver.cpp:713
bool _fNeedToExit
Definition: tcpserver.h:59
HRESULT Start()
Definition: tcpserver.cpp:298
HRESULT NotifyThreadViaPipe()
Definition: tcpserver.cpp:124
HRESULT Stop()
Definition: tcpserver.cpp:931
const uint32_t LL_DEBUG
Definition: logger.h:24
HRESULT Stop()
Definition: tcpserver.cpp:318
virtual HRESULT WaitForNextEvent(PollEvent *pPollEvent, int timeoutMilliseconds)=0
void ThreadCleanup()
Definition: tcpserver.cpp:779
const uint32_t IPOLLING_PRI
Definition: polling.h:34
const uint32_t IPOLLING_RDHUP
Definition: polling.h:32
void Close()
Definition: stunsocket.cpp:41
virtual HRESULT ChangeEventSet(int fd, uint32_t eventflags)=0
SocketRole socketrole
#define Chk(expr)
Definition: chkmacros.h:53
static const int c_sweepTimeoutSeconds
Definition: tcpserver.h:34
HRESULT CreatePollingInstance(uint32_t type, size_t maxSockets, IPolling **ppPolling)
Definition: polling.cpp:519
HRESULT CreatePipes()
Definition: tcpserver.cpp:93
const uint32_t EPOLL_PIPE_EVENT_SET
Definition: tcpserver.cpp:35
void LogMsg(uint32_t level, const char *pszFormat,...)
Definition: logger.cpp:44
StunThreadConnectionMap _hashConnections2
Definition: tcpserver.h:85
const uint32_t IPOLLING_TYPE_BEST
Definition: polling.h:50
int _pipe[2]
Definition: tcpserver.h:37
void ClosePipes()
Definition: tcpserver.cpp:109
TransportAddressSet _tsaListen
Definition: tcpserver.h:50
CSocketAddress addr
const uint32_t IPOLLING_ERROR
Definition: polling.h:35
#define S_FALSE
Definition: hresult.h:47
void ProcessConnectionEvent(int sock, uint32_t eventflags)
Definition: tcpserver.cpp:430
pthread_t _pthread
Definition: tcpserver.h:66
uint32_t eventflags
Definition: polling.h:24
#define VERIFY(expr)
bool _fListenSocketsOnEpoll
Definition: tcpserver.h:43
SocketRole _role
Definition: tcpserver.h:61
void SweepDeadConnections()
Definition: tcpserver.cpp:753
HRESULT Shutdown()
Definition: tcpserver.cpp:902
StunThreadConnectionMap * _pOldConnList
Definition: tcpserver.h:88
CStunMessageReader _reader
HRESULT WriteBytesForConnection(StunConnection *pConn)
Definition: tcpserver.cpp:645
CSocketAddress addrAlternateAdvertised
Definition: server.h:49
boost::shared_ptr< RateLimiter > _spLimiter
Definition: tcpserver.h:45
virtual ~CTCPServer()
Definition: tcpserver.cpp:799
uint16_t GetPort() const
const uint32_t IPOLLING_WRITE
Definition: polling.h:30
#define ARRAYSIZE(arr)
const uint32_t EPOLL_CLIENT_READ_EVENT_SET
Definition: tcpserver.cpp:25
int Insert(const K &key, V &value)
Definition: fasthash.h:284
void CloseListenSockets()
Definition: tcpserver.cpp:200
HRESULT Initialize(const CStunServerConfig &config)
Definition: tcpserver.cpp:830
#define ERRNO_TO_HRESULT(err)
Definition: hresult.h:41
#define ChkIf(expr, hrerror)
Definition: chkmacros.h:63
ReaderParseState AddBytes(const uint8_t *pData, uint32_t size)
Definition: stunreader.cpp:750
StunConnection * AcceptConnection(CStunSocket *pListenSocket)
Definition: tcpserver.cpp:484
void ReleaseConnection(StunConnection *pConn)
#define E_UNEXPECTED
Definition: hresult.h:48
CStunSocket _socketListenArray[4]
Definition: tcpserver.h:51
CSocketAddress addrRemote
What local IP address the message was received on (useful if the socket binded to INADDR_ANY) ...
#define SUCCEEDED(hr)
Definition: hresult.h:28
CSocketAddress addrLocal
which socket id did the message arrive on
virtual HRESULT Add(int fd, uint32_t eventflags)=0
Item * LookupByIndex(size_t index)
Definition: fasthash.h:368
const uint32_t IPOLLING_READ
Definition: polling.h:29
void ResetTable()
Definition: fasthash.h:501
TransportAddressSet _tsa
Definition: tcpserver.h:63
void SetPort(uint16_t)
int GetSocketHandle() const
Definition: stunsocket.cpp:82
StunThreadConnectionMap * _pNewConnList
Definition: tcpserver.h:87
virtual HRESULT Remove(int fd)=0
const int c_MaxNumberOfConnectionsDefault
Definition: tcpserver.cpp:37
CSocketAddress addrPA
Definition: server.h:44
ReaderParseState GetState()
Definition: stunreader.cpp:820
static void * ThreadFunction(void *pThis)
Definition: tcpserver.cpp:341
SocketRole GetRole() const
Definition: stunsocket.cpp:98
StunThreadConnectionMap _hashConnections1
Definition: tcpserver.h:84
T ** GetPointerPointer()
CSocketAddress addrAA
Definition: server.h:46
V * Lookup(const K &key)
Definition: fasthash.h:351
SocketRole
Definition: socketrole.h:22
void ReleaseAndClear()
int32_t HRESULT
Definition: hresult.h:22
FastHashBase< int, StunConnection * >::Item Item
Definition: fasthash.h:435
CRefCountedBuffer _spOutputBuffer
int _maxConnections
Definition: tcpserver.h:64
HRESULT SetListenSocketsOnEpoll(bool fEnable)
Definition: tcpserver.cpp:138
bool fMultiThreadedMode
Definition: server.h:38
int _socketTable[4]
Definition: tcpserver.h:52
HRESULT ReceiveBytesForConnection(StunConnection *pConn)
Definition: tcpserver.cpp:555
CStunSocket * GetListenSocket(int sock)
Definition: tcpserver.cpp:211
HRESULT CreateListenSockets()
Definition: tcpserver.cpp:171
HRESULT ToStringBuffer(char *pszAddrBytes, size_t length) const
bool IsConnectionCountAtMax()
Definition: tcpserver.cpp:353
#define E_INVALIDARG
Definition: hresult.h:51
CStunMessageReader * pReader
the address of the node that sent us the message
#define E_FAIL
Definition: hresult.h:56
int InitTable(size_t fsize, size_t tsize)
Definition: fasthash.h:471
bool _fThreadIsValid
Definition: tcpserver.h:67
int Remove(const K &key)
Definition: fasthash.h:316
#define FAILED(hr)
Definition: hresult.h:29
uint32_t nMaxConnections
Definition: server.h:41
static HRESULT ProcessRequest(const StunMessageIn &msgIn, StunMessageOut &msgOut, TransportAddressSet *pAddressSet, IStunAuth *pAuth)
HRESULT Init(const TransportAddressSet &tsaListen, const TransportAddressSet &tsaHandler, IStunAuth *pAuth, int maxConnections, boost::shared_ptr< RateLimiter > &spLimiter)
Definition: tcpserver.cpp:230
const CSocketAddress & GetRemoteAddress() const
Definition: stunsocket.cpp:92
#define ChkA(expr)
Definition: chkmacros.h:73
CRefCountedPtr< IPolling > _spPolling
Definition: tcpserver.h:42
void Attach(T *ptr)
size_t Size()
Definition: fasthash.h:269
const uint32_t LL_VERBOSE
Definition: logger.h:25
const uint32_t IPOLLING_HUP
Definition: polling.h:33
uint32_t GetLogLevel()
Definition: logger.cpp:33
CSocketAddress addrPrimaryAdvertised
Definition: server.h:48
time_t _timeLastSweep
Definition: tcpserver.h:89
CConnectionPool _connectionpool
Definition: tcpserver.h:69
bool fEnableDosProtection
Definition: server.h:51
StunConnection * GetConnection(int sock, SocketRole role)
TransportAddress set[4]
const uint32_t EPOLL_CLIENT_WRITE_EVENT_SET
Definition: tcpserver.cpp:27
CRefCountedBuffer spBufferOut
HRESULT SetNonBlocking(bool fEnable)
Definition: stunsocket.cpp:217
CStunSocket _stunsocket
CSocketAddress addrAP
Definition: server.h:45
CRefCountedPtr< IStunAuth > _spAuth
Definition: tcpserver.h:60
bool RateCheck(const CSocketAddress &addr)
Definition: tcpserver.cpp:463
void ResetConnection(StunConnection *pConn)
int fd
Definition: polling.h:23
bool IsIPAddressZero() const
uint16_t HowManyBytesNeeded()
Definition: stunreader.cpp:76
void InitTSA(TransportAddressSet *pTSA, SocketRole role, bool fValid, const CSocketAddress &addrListen, const CSocketAddress &addrAdvertise)
Definition: tcpserver.cpp:806
#define ChkIfA(expr, hrerror)
Definition: chkmacros.h:84
#define ERRNOHR
Definition: hresult.h:42
bool fConnectionOriented
reader containing a valid stun message
const CSocketAddress & GetLocalAddress() const
Definition: stunsocket.cpp:87
HRESULT Start()
Definition: tcpserver.cpp:916
const uint32_t EPOLL_LISTEN_SOCKET_EVENT_SET
Definition: tcpserver.cpp:32
CSocketAddress addrPP
Definition: server.h:43
StunConnectionState _state