Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
main.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 
19 #include <boost/property_tree/ptree.hpp>
20 #include <boost/property_tree/json_parser.hpp>
21 
22 #include "stuncore.h"
23 #include "server.h"
24 #include "tcpserver.h"
25 #include "adapters.h"
26 #include "cmdlineparser.h"
27 
28 #include <getopt.h>
29 
30 #include "prettyprint.h"
31 #include "oshelper.h"
32 #include "stringhelper.h"
33 
34 
35 // these are auto-generated files made from markdown sources. See ../resources
36 #include "stunserver.txtcode"
37 #include "stunserver_lite.txtcode"
38 #include "resolvehostname.h"
39 
40 
41 using namespace boost::property_tree;
42 
43 
44 void PrintUsage(bool fSummaryUsage)
45 {
46  size_t width = GetConsoleWidth();
47  const char* psz = fSummaryUsage ? stunserver_lite_text : stunserver_text;
48 
49  // save some margin space
50  if (width > 2)
51  {
52  width -= 2;
53  }
54 
55  PrettyPrint(psz, width);
56 }
57 
58 
59 // Because strerror_r has two versions (one that returns an int and another that returns char*)
60 // we wrap the result into an overloaded function
61 char* strerror_helper(int result, char* msg, int err)
62 {
63  if (result != 0)
64  {
65  sprintf(msg, "Unknown error %d", err);
66  }
67  return msg;
68 }
69 
70 char* strerror_helper(char* pszResult, char*, int)
71 {
72  return pszResult;
73 }
74 
75 
76 void LogHR(uint16_t level, HRESULT hr)
77 {
78  uint32_t facility = HRESULT_FACILITY(hr);
79  char msg[400];
80  const char* pMsg = NULL;
81  bool fGotMsg = false;
82 
83  if (facility == FACILITY_ERRNO)
84  {
85  msg[0] = '\0';
86  int err = (int)(HRESULT_CODE(hr));
87 
88  pMsg = strerror_helper(strerror_r(err, msg, ARRAYSIZE(msg)), msg, err);
89 
90  if (pMsg)
91  {
92  Logging::LogMsg(level, "Error: %s", pMsg);
93  fGotMsg = true;
94  }
95 
96  if (err == EADDRINUSE)
97  {
98  Logging::LogMsg(level,
99  "This error likely means another application is listening on one\n"
100  "or more of the same ports you are attempting to configure this\n"
101  "server to listen on. Run \"netstat -a -p -t -u\" to see a list\n"
102  "of all ports in use and associated process id for each");
103  }
104 
105  }
106 
107  if (fGotMsg == false)
108  {
109  Logging::LogMsg(level, "Error: %x", hr);
110  }
111 }
112 
113 
114 
116 {
117  std::string strMode;
118  std::string strPrimaryInterface;
119  std::string strAltInterface;
120  std::string strPrimaryPort;
121  std::string strAltPort;
122  std::string strPrimaryAdvertised;
124  std::string strFamily;
125  std::string strProtocol;
126  std::string strHelp;
127  std::string strVerbosity;
128  std::string strMaxConnections;
129  std::string strDosProtect;
130  std::string strConfigFile;
131 
132 };
133 
134 #define PRINTARG(member) Logging::LogMsg(LL_DEBUG, "%s = %s", #member, args.member.length() ? args.member.c_str() : "<empty>");
135 
137 {
138  Logging::LogMsg(LL_DEBUG, "\n\n--------------------------");
139  PRINTARG(strMode);
140  PRINTARG(strPrimaryInterface);
141  PRINTARG(strAltInterface);
142  PRINTARG(strPrimaryAdvertised);
143  PRINTARG(strAlternateAdvertised);
144  PRINTARG(strPrimaryPort);
145  PRINTARG(strAltPort);
146  PRINTARG(strFamily);
147  PRINTARG(strProtocol);
148  PRINTARG(strHelp);
149  PRINTARG(strVerbosity);
150  PRINTARG(strMaxConnections);
151  PRINTARG(strDosProtect);
152  Logging::LogMsg(LL_DEBUG, "--------------------------\n");
153 }
154 
155 
156 
158 {
159  std::string strSocket;
160 
161 
162  if (config.fHasPP)
163  {
164  config.addrPP.ToString(&strSocket);
165  Logging::LogMsg(LL_DEBUG, "PP = %s", strSocket.c_str());
166  }
167  if (config.fHasPA)
168  {
169  config.addrPA.ToString(&strSocket);
170  Logging::LogMsg(LL_DEBUG, "PA = %s", strSocket.c_str());
171  }
172  if (config.fHasAP)
173  {
174  config.addrAP.ToString(&strSocket);
175  Logging::LogMsg(LL_DEBUG, "AP = %s", strSocket.c_str());
176  }
177  if (config.fHasAA)
178  {
179  config.addrAA.ToString(&strSocket);
180  Logging::LogMsg(LL_DEBUG, "AA = %s", strSocket.c_str());
181  }
182 
183  if (config.addrPrimaryAdvertised.IsIPAddressZero() == false)
184  {
185  config.addrPrimaryAdvertised.ToString(&strSocket);
186  Logging::LogMsg(LL_DEBUG, "Primary IP will be advertised as %s", strSocket.c_str());
187  }
188 
189  if (config.addrAlternateAdvertised.IsIPAddressZero() == false)
190  {
191  config.addrAlternateAdvertised.ToString(&strSocket);
192  Logging::LogMsg(LL_DEBUG, "Alternate IP will be advertised as %s", strSocket.c_str());
193  }
194 
195  Logging::LogMsg(LL_DEBUG, "Protocol = %s", config.fTCP ? "TCP" : "UDP");
196  if (config.fTCP && (config.nMaxConnections>0))
197  {
198  Logging::LogMsg(LL_DEBUG, "Max TCP Connections per thread: %d", config.nMaxConnections);
199  }
200 }
201 
202 
203 HRESULT ResolveAdapterName(bool fPrimary, int family, std::string& strAdapterName, uint16_t port, CSocketAddress* pAddr)
204 {
205  HRESULT hr = S_OK;
206 
207 
208  if (strAdapterName.length() == 0)
209  {
210  hr = GetBestAddressForSocketBind(fPrimary, family, port, pAddr);
211  if (SUCCEEDED(hr))
212  {
213  pAddr->ToString(&strAdapterName);
214  // strip off the port suffix
215  size_t x = strAdapterName.find_last_of(':');
216  if (x != std::string::npos)
217  {
218  strAdapterName = strAdapterName.substr(0, x);
219  }
220  }
221  }
222  else
223  {
224  hr = GetSocketAddressForAdapter(family, strAdapterName.c_str(), port, pAddr);
225  }
226 
227  return hr;
228 }
229 
230 
231 
233 {
234  HRESULT hr = S_OK;
235 
236  // default values;
237  int family = AF_INET;
238  // bool fIsUdp = true;
239  int nPrimaryPort = DEFAULT_STUN_PORT;
240  int nAltPort = DEFAULT_STUN_PORT + 1;
241  bool fHasAtLeastTwoAdapters = false;
242  CStunServerConfig config;
243  int nMaxConnections = 0;
244  const char* pszPrimaryAdvertised = argsIn.strPrimaryAdvertised.c_str();
245  const char* pszAltAdvertised = argsIn.strAlternateAdvertised.c_str();
246 
247  enum ServerMode
248  {
249  Basic,
250  Full
251  };
252  ServerMode mode=Basic;
253 
254  StartupArgs args = argsIn;
255 
256 
257 
258  ChkIfA(pConfigOut == NULL, E_INVALIDARG);
259 
260 
261  // normalize the args. The "trim" is not needed for command line args, but will be useful when we have an "init file" for initializing the server
264 
266 
268 
270 
272 
274 
277 
280 
281 
282 
283  // ---- MODE ----------------------------------------------------------
284  if (args.strMode.length() > 0)
285  {
286  if (args.strMode == "basic")
287  {
288  mode = Basic;
289  }
290  else if (args.strMode == "full")
291  {
292  mode = Full;
293  }
294  else
295  {
296  Logging::LogMsg(LL_ALWAYS, "Mode must be \"full\" or \"basic\".");
297  Chk(E_INVALIDARG);
298  }
299  }
300 
301 
302  // ---- FAMILY --------------------------------------------------------
303  family = AF_INET;
304  if (args.strFamily.length() > 0)
305  {
306  if (args.strFamily == "4")
307  {
308  family = AF_INET;
309  }
310  else if (args.strFamily == "6")
311  {
312  family = AF_INET6;
313  }
314  else
315  {
316  Logging::LogMsg(LL_ALWAYS, "Family argument must be '4' or '6'");
317  Chk(E_INVALIDARG);
318  }
319  }
320 
321  // ---- PROTOCOL --------------------------------------------------------
322  if (args.strProtocol.length() > 0)
323  {
324  if ((args.strProtocol != "udp") && (args.strProtocol != "tcp"))
325  {
326  Logging::LogMsg(LL_ALWAYS, "Protocol argument must be 'udp' or 'tcp'. 'tls' is not supported yet");
327  Chk(E_INVALIDARG);
328  }
329 
330  config.fTCP = (args.strProtocol == "tcp");
331  }
332 
333 
334  // ---- MAX Connections -----------------------------------------------------
335  nMaxConnections = 0;
336  if (args.strMaxConnections.length() > 0)
337  {
338  if (config.fTCP == false)
339  {
340  Logging::LogMsg(LL_ALWAYS, "Max connections parameter has no meaning in UDP mode. Did you mean to specify \"--protocol=tcp ?\"");
341  }
342  else
343  {
344  hr = StringHelper::ValidateNumberString(args.strMaxConnections.c_str(), 1, 100000, &nMaxConnections);
345  if (FAILED(hr))
346  {
347  Logging::LogMsg(LL_ALWAYS, "Max connections must be between 1-100000");
348  Chk(hr);
349  }
350  }
351  config.nMaxConnections = nMaxConnections;
352  }
353 
354 
355  // ---- PRIMARY PORT --------------------------------------------------------
356  nPrimaryPort = DEFAULT_STUN_PORT;
357  if (args.strPrimaryPort.length() > 0)
358  {
359  hr = StringHelper::ValidateNumberString(args.strPrimaryPort.c_str(), 0x0001, 0xffff, &nPrimaryPort);
360  if (FAILED(hr))
361  {
362  Logging::LogMsg(LL_ALWAYS, "Primary port value is invalid. Value must be between 1-65535");
363  Chk(hr);
364  }
365  }
366 
367  // ---- ALT PORT --------------------------------------------------------
368  nAltPort = DEFAULT_STUN_PORT + 1;
369  if (args.strAltPort.length() > 0)
370  {
371  hr = StringHelper::ValidateNumberString(args.strAltPort.c_str(), 0x0001, 0xffff, &nAltPort);
372  if (FAILED(hr))
373  {
374  Logging::LogMsg(LL_ALWAYS, "Alt port value is invalid. Value must be between 1-65535");
375  Chk(hr);
376  }
377  }
378 
379  if (nPrimaryPort == nAltPort)
380  {
381  Logging::LogMsg(LL_ALWAYS, "Primary port and alternate port must be different values");
382  Chk(E_INVALIDARG);
383  }
384 
385 
386  // ---- Adapters and mode adjustment
387 
388 
389  fHasAtLeastTwoAdapters = ::HasAtLeastTwoAdapters(family);
390 
391  if (mode == Basic)
392  {
393  uint16_t port = (uint16_t)((int16_t)nPrimaryPort);
394  // in basic mode, if no adapter is specified, bind to all of them
395  if (args.strPrimaryInterface.length() == 0)
396  {
397  if (family == AF_INET)
398  {
399  config.addrPP = CSocketAddress(0, port);
400  config.fHasPP = true;
401  }
402  else if (family == AF_INET6)
403  {
404  sockaddr_in6 addr6 = {}; // zero-init
405  addr6.sin6_family = AF_INET6;
406  config.addrPP = CSocketAddress(addr6);
407  config.addrPP.SetPort(port);
408  config.fHasPP = true;
409  }
410  }
411  else
412  {
413  CSocketAddress addr;
414  hr = GetSocketAddressForAdapter(family, args.strPrimaryInterface.c_str(), port, &addr);
415  if (FAILED(hr))
416  {
417  Logging::LogMsg(LL_ALWAYS, "No matching primary adapter found for %s", args.strPrimaryInterface.c_str());
418  Chk(hr);
419  }
420  config.addrPP = addr;
421  config.fHasPP = true;
422  }
423  }
424  else // Full mode
425  {
426  CSocketAddress addrPrimary;
427  CSocketAddress addrAlternate;
428  uint16_t portPrimary = (uint16_t)((int16_t)nPrimaryPort);
429  uint16_t portAlternate = (uint16_t)((int16_t)nAltPort);
430 
431  // in full mode, we can't bind to all adapters
432  // so if one isn't specified, it's best guess - just avoid duplicates
433  if (fHasAtLeastTwoAdapters == false)
434  {
435  Logging::LogMsg(LL_ALWAYS, "There does not appear to be two or more unique IP addresses to run in full mode");
436  Chk(E_UNEXPECTED);
437  }
438 
439  hr = ResolveAdapterName(true, family, args.strPrimaryInterface, 0, &addrPrimary);
440  if (FAILED(hr))
441  {
442  Logging::LogMsg(LL_ALWAYS, "Can't find address for primary interface");
443  Chk(hr);
444  }
445 
446  hr = ResolveAdapterName(false, family, args.strAltInterface, 0, &addrAlternate);
447  if (FAILED(hr))
448  {
449  Logging::LogMsg(LL_ALWAYS, "Can't find address for alternate interface");
450  Chk(hr);
451  }
452 
453  if (addrPrimary.IsSameIP(addrAlternate))
454  {
455  Logging::LogMsg(LL_ALWAYS, "Error - Primary interface and Alternate Interface appear to have the same IP address. Full mode requires two IP addresses that are unique");
456  Chk(E_INVALIDARG);
457  }
458 
459 
460  config.addrPP = addrPrimary;
461  config.addrPP.SetPort(portPrimary);
462  config.fHasPP = true;
463 
464  config.addrPA = addrPrimary;
465  config.addrPA.SetPort(portAlternate);
466  config.fHasPA = true;
467 
468  config.addrAP = addrAlternate;
469  config.addrAP.SetPort(portPrimary);
470  config.fHasAP = true;
471 
472  config.addrAA = addrAlternate;
473  config.addrAA.SetPort(portAlternate);
474  config.fHasAA = true;
475 
476  }
477 
478 
479  // ---- Address advertisement --------------------------------------------------------
480  // handle the advertised address parameters and make sure they are valid IP address strings
481 
482  if (!StringHelper::IsNullOrEmpty(pszPrimaryAdvertised))
483  {
484  hr = ::NumericIPToAddress(family, pszPrimaryAdvertised, &config.addrPrimaryAdvertised);
485  if (FAILED(hr))
486  {
487  Logging::LogMsg(LL_ALWAYS, "Error with --primaryadvertised. %s is not a valid IP address string", pszPrimaryAdvertised);
488  Chk(hr);
489  }
490  }
491 
492  if (!StringHelper::IsNullOrEmpty(pszAltAdvertised))
493  {
494  if (mode != Full)
495  {
496  Logging::LogMsg(LL_ALWAYS, "Error. --altadvertised was specified, but --mode param was not set to FULL.");
497  ChkIf(config.fHasAA, E_INVALIDARG);
498  }
499 
500  hr = ::NumericIPToAddress(family, pszAltAdvertised, &config.addrAlternateAdvertised);
501  if (FAILED(hr))
502  {
503  Logging::LogMsg(LL_ALWAYS, "Error with --altadvertised. %s is not a valid IP address string", pszAltAdvertised);
504  Chk(hr);
505  }
506  }
507 
508  // ---- DDOS PROTECTION SWITCH -------------------------------------------
509  config.fEnableDosProtection = (argsIn.strDosProtect.length() > 0);
510 
511  *pConfigOut = config;
512  hr = S_OK;
513 
514 Cleanup:
515  return hr;
516 }
517 
518 
519 HRESULT ParseCommandLineArgs(int argc, char** argv, int startindex, StartupArgs* pStartupArgs)
520 {
521  CCmdLineParser cmdline;
522  std::string strHelp;
523  bool fError = false;
524 
525  cmdline.AddOption("mode", required_argument, &pStartupArgs->strMode);
526  cmdline.AddOption("primaryinterface", required_argument, &pStartupArgs->strPrimaryInterface);
527  cmdline.AddOption("altinterface", required_argument, &pStartupArgs->strAltInterface);
528  cmdline.AddOption("primaryadvertised", required_argument, &pStartupArgs->strPrimaryAdvertised);
529  cmdline.AddOption("altadvertised", required_argument, &pStartupArgs->strAlternateAdvertised);
530  cmdline.AddOption("primaryport", required_argument, &pStartupArgs->strPrimaryPort);
531  cmdline.AddOption("altport", required_argument, &pStartupArgs->strAltPort);
532  cmdline.AddOption("family", required_argument, &pStartupArgs->strFamily);
533  cmdline.AddOption("protocol", required_argument, &pStartupArgs->strProtocol);
534  cmdline.AddOption("maxconn", required_argument, &pStartupArgs->strMaxConnections);
535  cmdline.AddOption("help", no_argument, &pStartupArgs->strHelp);
536  cmdline.AddOption("verbosity", required_argument, &pStartupArgs->strVerbosity);
537  cmdline.AddOption("ddp", no_argument, &pStartupArgs->strDosProtect);
538  cmdline.AddOption("configfile", required_argument, &pStartupArgs->strConfigFile);
539 
540  cmdline.ParseCommandLine(argc, argv, startindex, &fError);
541 
542  return fError ? E_INVALIDARG : S_OK;
543 }
544 
545 
546 HRESULT LoadConfigsFromFile(const std::string& filename, std::vector<StartupArgs>& configurations)
547 {
548  ptree tree;
549  bool error = false;
550  std::string errorMessage;
551 
552  /* EXAMPLE configuration file
553  {
554  "configurations": [
555  {
556  "description" : "UDP Full Mode listening on default ports",
557  "mode": "full",
558  "family": "4",
559  "protocol": "udp",
560  "ddp": "1"
561  },
562  {
563  "description" : "TCP Full Mode listening on default port",
564  "mode": "full",
565  "family": "6",
566  "protocol": "tcp",
567  "ddp": "1"
568  }
569  ]
570  }
571  */
572 
573  try
574  {
575  read_json(filename, tree);
576  ptree root = tree.get_child("configurations");
577 
578  for (ptree::iterator itor = root.begin(); itor != root.end(); itor++)
579  {
580  const ptree& child = itor->second;
581  StartupArgs args;
582 
583  args.strMode = child.get("mode", "");
584  args.strPrimaryInterface = child.get("primaryinterface", "");
585  args.strAltInterface = child.get("altinterface", "");
586  args.strPrimaryAdvertised = child.get("primaryadvertised", "");
587  args.strAlternateAdvertised = child.get("altadvertised", "");
588  args.strPrimaryPort = child.get("primaryport", "");
589  args.strAltPort = child.get("altport", "");
590  args.strFamily = child.get("family", "");
591  args.strProtocol = child.get("protocol", "");
592  args.strMaxConnections = child.get("maxconn", "");
593  args.strDosProtect = child.get("ddp", "");
594 
595  configurations.push_back(args);
596  }
597  }
598  catch(ptree_error ex1)
599  {
600  Logging::LogMsg(LL_ALWAYS, "Error processing configuration file: %s", ex1.what());
601  error = true;
602  }
603 
604  if (!error && configurations.size() == 0)
605  {
606  Logging::LogMsg(LL_ALWAYS, "File is valid json, but no configurations found");
607  error = true;
608  }
609 
610  if (error)
611  {
612  configurations.clear();
613  return E_FAIL;
614  }
615 
616  return S_OK;
617 }
618 
620 {
621  HRESULT hr = S_OK;
622  int result = 0;
623  sigset_t signalset;
624  sigset_t oldset;
625 
626  sigemptyset(&signalset);
627  sigemptyset(&oldset);
628 
629  sigaddset(&signalset, sig);
630 
631  // blocks the signal on *this* thread and all child threads spawned with pthread_create
632  result = pthread_sigmask(SIG_BLOCK, &signalset, &oldset);
633 
634  if (result != 0)
635  {
636  hr = ERRNO_TO_HRESULT(result);
637  Logging::LogMsg(LL_DEBUG, "BlockSignal: x%x", hr);
638  }
639 
640  return hr;
641 }
642 
643 
644 // after all the child threads have initialized with a signal mask that blocks SIGINT and SIGTERM
645 // then the main thread UI can just sit on WaitForAppExitSignal and wait for CTRL-C to get pressed
647 {
648  while (true)
649  {
650  sigset_t sigs;
651  sigemptyset(&sigs);
652  sigaddset(&sigs, SIGINT);
653  sigaddset(&sigs, SIGTERM);
654  int sig = 0;
655 
656  int ret = sigwait(&sigs, &sig);
657  Logging::LogMsg(LL_DEBUG, "sigwait returns %d (errno==%d)", ret, (ret==-1)?0:errno);
658  if ((sig == SIGINT) || (sig == SIGTERM))
659  {
660  break;
661  }
662  }
663 }
664 
665 
666 
668 {
669  HRESULT hr;
670 
671  hr = CStunServer::CreateInstance(config, spServer.GetPointerPointer());
672  if (FAILED(hr))
673  {
674  Logging::LogMsg(LL_ALWAYS, "Unable to initialize UDP server (error code = x%x)", hr);
675  LogHR(LL_ALWAYS, hr);
676  return hr;
677  }
678 
679  hr = spServer->Start();
680  if (FAILED(hr))
681  {
682  Logging::LogMsg(LL_ALWAYS, "Unable to start UDP server (error code = x%x)", hr);
683  LogHR(LL_ALWAYS, hr);
684  return hr;
685  }
686 
687  return S_OK;
688 }
689 
691 {
692  HRESULT hr;
693 
694  hr = CTCPServer::CreateInstance(config, spTCPServer.GetPointerPointer());
695  if (FAILED(hr))
696  {
697  Logging::LogMsg(LL_ALWAYS, "Unable to initialize TCP server (error code = x%x)", hr);
698  LogHR(LL_ALWAYS, hr);
699  return hr;
700  }
701 
702  hr = spTCPServer->Start();
703  if (FAILED(hr))
704  {
705  Logging::LogMsg(LL_ALWAYS, "Unable to start TCP server (error code = x%x)", hr);
706  LogHR(LL_ALWAYS, hr);
707  return hr;
708  }
709 
710  return S_OK;
711 
712 }
713 
714 int main(int argc, char** argv)
715 {
716  HRESULT hr = S_OK;
717  StartupArgs args;
718  std::vector<StartupArgs> argsVector;
719  int serverindex = 1;
720 
721  typedef CRefCountedPtr<CStunServer> UdpServerPtr;
722  typedef CRefCountedPtr<CTCPServer> TcpServerPtr;
723 
724  std::vector<UdpServerPtr> udpServers;
725  std::vector<TcpServerPtr> tcpServers;
726 
727  // block sigpipe so that socket send calls from raising SIGPIPE
728  signal(SIGPIPE, SIG_IGN);
729  BlockSignal(SIGPIPE);
730 
731  // Block SIGTERM and SIGINT such that the child threads will never get that signal (so that subsequent WaitForAppExitSignal hooks on *this* thread)
732  BlockSignal(SIGTERM);
733  BlockSignal(SIGINT);
734 
735 
736 #ifdef DEBUG
738 #else
740 #endif
741 
742 
743  hr = ParseCommandLineArgs(argc, argv, 1, &args);
744  if (FAILED(hr))
745  {
746  PrintUsage(true);
747  return -1;
748  }
749 
750  if (args.strHelp.length() > 0)
751  {
752  PrintUsage(false);
753  return -2;
754  }
755 
756  if (args.strVerbosity.length() > 0)
757  {
758  int loglevel = (uint32_t)atoi(args.strVerbosity.c_str());
759 
760  if (loglevel >= 0)
761  {
762  Logging::SetLogLevel((uint32_t)loglevel);
763  }
764  }
765 
766  if (args.strConfigFile.empty() == false)
767  {
768  hr = LoadConfigsFromFile(args.strConfigFile, argsVector);
769  if (FAILED(hr))
770  {
771  Logging::LogMsg(LL_ALWAYS, "Can't process configuration file");
772  return -3;
773  }
774  }
775  else
776  {
777  argsVector.push_back(args);
778  }
779 
780  if (SUCCEEDED(hr))
781  {
782  for (std::vector<StartupArgs>::iterator itor = argsVector.begin(); itor != argsVector.end(); itor++)
783  {
784  CStunServerConfig config;
785  StartupArgs args = *itor;
786 
787  Logging::LogMsg(LL_DEBUG, "Starting server %d", serverindex);
788  serverindex++;
789 
790  ::DumpStartupArgs(args);
791  hr = BuildServerConfigurationFromArgs(args, &config);
792  if (FAILED(hr))
793  {
794  Logging::LogMsg(LL_ALWAYS, "Error building configuration from options given");
795  break;
796  }
797  DumpConfig(config);
798 
799  if (config.fTCP)
800  {
801  TcpServerPtr spTcpServer;
802  hr = StartTCP(spTcpServer, config);
803 
804  if (SUCCEEDED(hr))
805  {
806  tcpServers.push_back(spTcpServer);
807  }
808  }
809  else
810  {
811  UdpServerPtr spUdpServer;
812  hr = StartUDP(spUdpServer, config);
813  if (SUCCEEDED(hr))
814  {
815  udpServers.push_back(spUdpServer);
816  }
817  }
818 
819  if (FAILED(hr))
820  {
821  break;
822  }
823  }
824  }
825 
826 
827  if (SUCCEEDED(hr))
828  {
829  Logging::LogMsg(LL_DEBUG, "Successfully started server.");
831  }
832 
833 
834  Logging::LogMsg(LL_DEBUG, "Server is exiting");
835 
836 
837  for (std::vector<UdpServerPtr>::iterator itor = udpServers.begin(); itor != udpServers.end(); itor++)
838  {
839  Logging::LogMsg(LL_DEBUG, "Shutting down UDP server");
840  UdpServerPtr server = *itor;
841  server->Stop();
842  }
843 
844  for (std::vector<TcpServerPtr>::iterator itor = tcpServers.begin(); itor != tcpServers.end(); itor++)
845  {
846  Logging::LogMsg(LL_DEBUG, "Shutting down TCP server");
847  TcpServerPtr server = *itor;
848  server->Stop();
849  }
850 
851  return 0;
852 }
853 
#define S_OK
Definition: hresult.h:46
std::string strPrimaryAdvertised
Definition: main.cpp:122
const uint32_t LL_DEBUG
Definition: logger.h:24
std::string strProtocol
Definition: main.cpp:125
int ValidateNumberString(const char *psz, int nMinValue, int nMaxValue, int *pnResult)
#define Chk(expr)
Definition: chkmacros.h:53
void PrintUsage(bool fSummaryUsage)
Definition: main.cpp:44
int main(int argc, char **argv)
Definition: main.cpp:714
std::string strAltPort
Definition: main.cpp:121
void LogMsg(uint32_t level, const char *pszFormat,...)
Definition: logger.cpp:44
std::string strMode
Definition: main.cpp:117
CSocketAddress addrAlternateAdvertised
Definition: server.h:49
void DumpConfig(CStunServerConfig &config)
Definition: main.cpp:157
#define ARRAYSIZE(arr)
bool IsNullOrEmpty(const char *psz)
#define ERRNO_TO_HRESULT(err)
Definition: hresult.h:41
std::string strFamily
Definition: main.cpp:124
#define ChkIf(expr, hrerror)
Definition: chkmacros.h:63
std::string strMaxConnections
Definition: main.cpp:128
HRESULT BuildServerConfigurationFromArgs(StartupArgs &argsIn, CStunServerConfig *pConfigOut)
Definition: main.cpp:232
HRESULT GetSocketAddressForAdapter(int family, const char *pszAdapterName, uint16_t port, CSocketAddress *pSocketAddr)
Definition: adapters.cpp:111
std::string strPrimaryPort
Definition: main.cpp:120
#define E_UNEXPECTED
Definition: hresult.h:48
std::string strVerbosity
Definition: main.cpp:127
#define SUCCEEDED(hr)
Definition: hresult.h:28
std::string strPrimaryInterface
Definition: main.cpp:118
HRESULT StartTCP(CRefCountedPtr< CTCPServer > &spTCPServer, CStunServerConfig &config)
Definition: main.cpp:690
#define FACILITY_ERRNO
Definition: hresult.h:40
HRESULT GetBestAddressForSocketBind(bool fPrimary, int family, uint16_t port, CSocketAddress *pSocketAddr)
Definition: adapters.cpp:83
void SetPort(uint16_t)
HRESULT NumericIPToAddress(int family, const char *pszIP, CSocketAddress *pAddr)
HRESULT ParseCommandLineArgs(int argc, char **argv, int startindex, StartupArgs *pStartupArgs)
Definition: main.cpp:519
CSocketAddress addrPA
Definition: server.h:44
void SetLogLevel(uint32_t level)
Definition: logger.cpp:38
void ToLower(std::string &str)
HRESULT LoadConfigsFromFile(const std::string &filename, std::vector< StartupArgs > &configurations)
Definition: main.cpp:546
bool IsSameIP(const CSocketAddress &other) const
void Trim(std::string &str)
T ** GetPointerPointer()
size_t GetConsoleWidth()
CSocketAddress addrAA
Definition: server.h:46
int32_t HRESULT
Definition: hresult.h:22
const uint16_t DEFAULT_STUN_PORT
Definition: stuntypes.h:29
HRESULT ParseCommandLine(int argc, char **argv, int startindex, bool *fParseError)
char * strerror_helper(int result, char *msg, int err)
Definition: main.cpp:61
void ToString(std::string *pStr) const
#define HRESULT_CODE(hr)
Definition: hresult.h:34
std::string strAltInterface
Definition: main.cpp:119
#define E_INVALIDARG
Definition: hresult.h:51
#define E_FAIL
Definition: hresult.h:56
void LogHR(uint16_t level, HRESULT hr)
Definition: main.cpp:76
HRESULT StartUDP(CRefCountedPtr< CStunServer > &spServer, CStunServerConfig &config)
Definition: main.cpp:667
#define FAILED(hr)
Definition: hresult.h:29
uint32_t nMaxConnections
Definition: server.h:41
std::string strAlternateAdvertised
Definition: main.cpp:123
void WaitForAppExitSignal()
Definition: main.cpp:646
CSocketAddress addrPrimaryAdvertised
Definition: server.h:48
void DumpStartupArgs(StartupArgs &args)
Definition: main.cpp:136
const uint32_t LL_ALWAYS
Definition: logger.h:23
bool HasAtLeastTwoAdapters(int family)
Definition: adapters.cpp:54
HRESULT Start()
Definition: server.cpp:217
#define PRINTARG(member)
Definition: main.cpp:134
HRESULT AddOption(const char *pszName, int has_arg, std::string *pStrResult)
bool fEnableDosProtection
Definition: server.h:51
std::string strConfigFile
Definition: main.cpp:130
std::string strDosProtect
Definition: main.cpp:129
static HRESULT CreateInstance(I **ppI)
Definition: objectfactory.h:52
CSocketAddress addrAP
Definition: server.h:45
HRESULT ResolveAdapterName(bool fPrimary, int family, std::string &strAdapterName, uint16_t port, CSocketAddress *pAddr)
Definition: main.cpp:203
bool IsIPAddressZero() const
std::string strHelp
Definition: main.cpp:126
#define ChkIfA(expr, hrerror)
Definition: chkmacros.h:84
void PrettyPrint(const char *pszInput, size_t width)
HRESULT BlockSignal(int sig)
Definition: main.cpp:619
#define HRESULT_FACILITY(hr)
Definition: hresult.h:35
HRESULT Start()
Definition: tcpserver.cpp:916
CSocketAddress addrPP
Definition: server.h:43