├── .gitignore ├── Dockerfile ├── HISTORY ├── LICENSE ├── Makefile ├── README ├── client ├── Makefile └── clientmain.cpp ├── common.inc ├── common ├── Makefile ├── atomichelpers.cpp ├── atomichelpers.h ├── chkmacros.h ├── cmdlineparser.cpp ├── cmdlineparser.h ├── common.cpp ├── commonincludes.hpp ├── fasthash.cpp ├── fasthash.h ├── getconsolewidth.cpp ├── getmillisecondcounter.cpp ├── hresult.h ├── logger.cpp ├── logger.h ├── objectfactory.h ├── oshelper.h ├── prettyprint.cpp ├── prettyprint.h ├── refcountobject.cpp ├── refcountobject.h ├── stringhelper.cpp └── stringhelper.h ├── networkutils ├── Makefile ├── adapters.cpp ├── adapters.h ├── polling.cpp ├── polling.h ├── ratelimiter.cpp ├── ratelimiter.h ├── recvfromex.cpp ├── recvfromex.h ├── resolvehostname.cpp ├── resolvehostname.h ├── stunsocket.cpp └── stunsocket.h ├── resources ├── Makefile ├── README ├── makecodefile.sh ├── package.bat ├── readme.src ├── stunclient.1 ├── stunclient.md ├── stunclient.txtcode ├── stunclient_lite.txt ├── stunclient_lite.txtcode ├── stunserver.1 ├── stunserver.md ├── stunserver.txtcode ├── stunserver_lite.txt ├── stunserver_lite.txtcode └── xxdperl.pl ├── server ├── Makefile ├── main.cpp ├── sampleauthprovider.cpp ├── sampleauthprovider.h ├── server.cpp ├── server.h ├── stunconnection.cpp ├── stunconnection.h ├── stunsocketthread.cpp ├── stunsocketthread.h ├── tcpserver.cpp └── tcpserver.h ├── stuncore ├── Makefile ├── buffer.cpp ├── buffer.h ├── datastream.cpp ├── datastream.h ├── messagehandler.cpp ├── messagehandler.h ├── socketaddress.cpp ├── socketaddress.h ├── socketrole.h ├── stunauth.h ├── stunbuilder.cpp ├── stunbuilder.h ├── stunclientlogic.cpp ├── stunclientlogic.h ├── stunclienttests.cpp ├── stunclienttests.h ├── stuncore.h ├── stunreader.cpp ├── stunreader.h ├── stuntypes.h ├── stunutils.cpp └── stunutils.h └── testcode ├── Makefile ├── packet.bin ├── stun.conf ├── testatomichelpers.cpp ├── testatomichelpers.h ├── testbuilder.cpp ├── testbuilder.h ├── testclientlogic.cpp ├── testclientlogic.h ├── testcmdline.cpp ├── testcmdline.h ├── testcode.cpp ├── testdatastream.cpp ├── testdatastream.h ├── testfasthash.cpp ├── testfasthash.h ├── testintegrity.cpp ├── testintegrity.h ├── testmessagehandler.cpp ├── testmessagehandler.h ├── testpolling.cpp ├── testpolling.h ├── testratelimiter.cpp ├── testratelimiter.h ├── testreader.cpp ├── testreader.h ├── testrecvfromex.cpp ├── testrecvfromex.h └── unittest.h /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | 3 | *.o 4 | *.gch 5 | *.a 6 | callgrind.out.* 7 | 8 | stunclient 9 | stunserver 10 | stuntestcode 11 | 12 | stunclient.exe 13 | stunserver.exe 14 | stuntestcode.exe 15 | 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 as build 2 | 3 | RUN set -ex && \ 4 | apt-get update && \ 5 | apt-get install -y build-essential && \ 6 | apt-get install -y libboost-all-dev && \ 7 | apt-get install -y libssl-dev && \ 8 | apt-get install -y g++ && \ 9 | apt-get install -y make && \ 10 | apt-get install -y git && \ 11 | apt-get clean -y && \ 12 | rm -rf /var/lib/apt/lists/* 13 | 14 | RUN cd /opt && git clone https://github.com/jselbie/stunserver.git && cd stunserver && make 15 | 16 | FROM ubuntu:18.04 17 | 18 | EXPOSE 3478/tcp 3478/udp 19 | 20 | RUN apt update && apt install libssl1.1 && apt-get clean 21 | 22 | RUN mkdir /opt/stunserver 23 | COPY --from=build /opt/stunserver/stunclient /opt/stunserver/stunclient 24 | COPY --from=build /opt/stunserver/stunserver /opt/stunserver/stunserver 25 | 26 | WORKDIR /opt/stunserver 27 | 28 | HEALTHCHECK CMD /opt/stunserver/stunclient localhost 29 | 30 | ENTRYPOINT ["/opt/stunserver/stunserver"] 31 | 32 | 33 | -------------------------------------------------------------------------------- /HISTORY: -------------------------------------------------------------------------------- 1 | 2 | Version 1.0 - Initial release. 3 | 4 | Version 1.1.0 - TCP support added. Better interop support 5 | 6 | Version 1.1.1 - Fix for padding and response-port attribute id values. 7 | 8 | Version 1.1.2 - Fix compile issues for older linux and macos distributions 9 | 10 | Version 1.1.3 - Fix compile issue for clang on MacOSX 11 | 12 | Version 1.2.0 - Amazon EC2 support added 13 | 14 | Version 1.2.1 - Fixed various compile and test issues, including the sync_add_fetch_4 linker error 15 | 16 | Version 1.2.2 - Fixed regression with regards to compiling with 32-bit clang++ 17 | 18 | Version 1.2.3 - Globally disable SIGPIPE 19 | 20 | Version 1.2.4 - Fix a socket bug unique to Windows. 21 | 22 | Version 1.2.5 - Block IPv6 sockets from receiving IPv4 traffic 23 | 24 | Version 1.2.5a - Rebuilt Windows binaries with new CygWin DLL. Code signing applied to EXE files. 25 | 26 | Version 1.2.6 - Fix compiler warning around unused local typedefs. 27 | 28 | Version 1.2.7 - Fix compiler warning around unused local variable. Fixed the case where filtering test would report failure if the behavior test failed before it. 29 | 30 | Version 1.2.8 - New command line parameter, --ddp, which enables DDOS (distributed denial of service) protection 31 | 32 | Version 1.2.9 - Merged github pull requests, Mac now uses CommonCrypto instead of OpenSSL 33 | 34 | Version 1.2.10 - TCP mode allows the client to keep the connection open longer and send multiple binding requests 35 | 36 | Version 1.2.11 - stunclient will now initiate filtering tests before behavior testst in full mode. "--mode full" is now deprecaed as a parameter for stunclient in favor of running "--mode behavior" and "--mode filtering" separately. 37 | 38 | Version 1.2.11a - Fix compiler error for musl and Alpine Linux 39 | 40 | Version 1.2.12 - When printing addresses, use correct delimiter (IP:port for IPv4 and IP.port for IPv6) 41 | 42 | Version 1.2.13 - Support config file and multiple protocols in the same process with --configfile option 43 | 44 | Version 1.2.14 - Docker support and OpenSSL compile issue 45 | 46 | Version 1.2.15 - For for --ddp command line option. 47 | 48 | Version 1.2.16 - ASLR Support on Cygwin builds 49 | 50 | Version 1.2.17 - Client fix for filtering test (does not impact server) 51 | 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all everything copybin debug clean 2 | 3 | all: everything copybin 4 | 5 | everything: 6 | $(MAKE) $(T) --directory=common 7 | $(MAKE) $(T) --directory=stuncore 8 | $(MAKE) $(T) --directory=networkutils 9 | $(MAKE) $(T) --directory=testcode 10 | $(MAKE) $(T) --directory=client 11 | $(MAKE) $(T) --directory=server 12 | 13 | copybin: everything 14 | rm -f ./stunserver ./stunclient ./stuntestcode 15 | cp server/stunserver . 16 | cp client/stunclient . 17 | cp testcode/stuntestcode . 18 | 19 | 20 | debug: T := debug 21 | debug: all 22 | 23 | profile: T := profile 24 | profile: all 25 | 26 | pgo1: T := pgo1 27 | pgo1: all 28 | 29 | pgo2: T := pgo2 30 | pgo2: all 31 | 32 | clean: T := clean 33 | clean: everything 34 | rm -f stunserver stunclient stuntestcode 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /client/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.inc 2 | 3 | PROJECT_TARGET := stunclient 4 | PROJECT_OBJS := clientmain.o 5 | 6 | 7 | INCLUDES := $(BOOST_INCLUDE) -I../common -I../stuncore -I../networkutils -I../resources 8 | LIB_PATH := -L../common -L../stuncore -L../networkutils 9 | LIBS := -lnetworkutils -lstuncore -lcommon 10 | 11 | 12 | all: $(PROJECT_TARGET) 13 | 14 | clean: 15 | rm -f $(PROJECT_OBJS) $(PROJECT_TARGET) 16 | 17 | $(PROJECT_TARGET): $(PROJECT_OBJS) 18 | $(LINK.cpp) -o $@ $^ $(LIB_PATH) $(LIBS) $(SOCKET_LIBS) $(CRYPTO_LIBS) $(ASLR_FLAGS) $(PGO_LINK_FLAGS) 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /common.inc: -------------------------------------------------------------------------------- 1 | #BOOST_INCLUDE := -I/home/jselbie/boost_1_73_0 2 | #OPENSSL_INCLUDE := -I/Users/jselbie/openssl/include 3 | 4 | DEFINES := -DNDEBUG 5 | 6 | # CLANG compiler works fine 7 | # CXX := /usr/bin/clang++ 8 | 9 | STANDARD_FLAGS := -Wall -Wuninitialized 10 | 11 | RELEASE_FLAGS := -O3 12 | DEBUG_FLAGS := -g 13 | PROFILE_FLAGS := -O3 -g 14 | FLAVOR_FLAGS = $(RELEASE_FLAGS) 15 | CRYPTO_LIBS := -lcrypto 16 | PGO1_FLAGS := -fprofile-generate -fprofile-dir=/home/jselbie/profile 17 | PGO2_FLAGS := -fprofile-use -fprofile-dir=/home/jselbie/profile 18 | 19 | 20 | #SOLARIS HACK 21 | UNAME := $(shell uname -s) 22 | UNAMEOS := $(shell uname -o) 23 | 24 | ifeq ($(UNAME),SunOS) 25 | SOCKET_LIBS := -lsocket -lnsl 26 | endif 27 | 28 | #Mac hack 29 | ifeq ($(UNAME),Darwin) 30 | CRYPTO_LIBS := 31 | endif 32 | 33 | #Cygwin hack for ASLR 34 | ifeq ($(UNAMEOS), Cygwin) 35 | ASLR_FLAGS := -Xlinker --dynamicbase 36 | endif 37 | 38 | .PHONY: all clean debug 39 | 40 | %.hpp.gch: %.hpp 41 | echo Building precompiled header: $@ 42 | $(COMPILE.cpp) $(INCLUDES) $(DEFINES) $(STANDARD_FLAGS) $(FLAVOR_FLAGS) $^ 43 | 44 | %.o: %.cpp 45 | $(COMPILE.cpp) $(INCLUDES) $(DEFINES) $(STANDARD_FLAGS) $(FLAVOR_FLAGS) $^ 46 | 47 | # put "all" target first so that it is the default 48 | all: 49 | 50 | debug: FLAVOR_FLAGS = $(DEBUG_FLAGS) 51 | debug: DEFINES = -DDEBUG 52 | debug: all 53 | 54 | 55 | profile: FLAVOR_FLAGS = $(PROFILE_FLAGS) 56 | profile: all 57 | 58 | 59 | pgo1: FLAVOR_FLAGS = $(PGO1_FLAGS) $(RELEASE_FLAGS) 60 | pgo1: PGO_LINK_FLAGS = $(PGO1_FLAGS) 61 | pgo1: all 62 | 63 | 64 | pgo2: FLAVOR_FLAGS = $(PGO2_FLAGS) $(RELEASE_FLAGS) 65 | pgo2: PGO_LINK_FLAGS = $(PGO2_FLAGS) 66 | pgo2: all 67 | 68 | 69 | -------------------------------------------------------------------------------- /common/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.inc 2 | 3 | PROJECT_TARGET := libcommon.a 4 | PROJECT_SRCS := atomichelpers.cpp cmdlineparser.cpp common.cpp fasthash.cpp getconsolewidth.cpp getmillisecondcounter.cpp logger.cpp prettyprint.cpp refcountobject.cpp stringhelper.cpp 5 | PROJECT_OBJS := $(subst .cpp,.o,$(PROJECT_SRCS)) 6 | INCLUDES := $(BOOST_INCLUDE) 7 | PRECOMP_H_GCH := commonincludes.hpp.gch 8 | 9 | 10 | 11 | 12 | all: $(PRECOMP_H_GCH) $(PROJECT_TARGET) 13 | 14 | clean: 15 | rm -f $(PROJECT_OBJS) $(PROJECT_TARGET) $(PRECOMP_H_GCH) 16 | 17 | $(PROJECT_TARGET): $(PROJECT_OBJS) 18 | rm -f $@ 19 | $(AR) rv $@ $^ 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /common/atomichelpers.cpp: -------------------------------------------------------------------------------- 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 | 18 | #include "commonincludes.hpp" 19 | #include "atomichelpers.h" 20 | 21 | 22 | 23 | #if defined(i386) || defined(__i386) || defined(__i386__) 24 | #define ATOMICS_USE_XADD 25 | #endif 26 | 27 | 28 | #ifdef ATOMICS_USE_XADD 29 | 30 | unsigned int xadd_4(volatile void* pVal, unsigned int inc) 31 | { 32 | unsigned int result; 33 | unsigned int* pValInt = (unsigned int*)pVal; 34 | 35 | asm volatile( 36 | "lock; xaddl %%eax, %2;" 37 | :"=a" (result) 38 | : "a" (inc), "m" (*pValInt) 39 | :"memory" ); 40 | 41 | return (result); 42 | } 43 | 44 | int AtomicIncrement(int* pInt) 45 | { 46 | COMPILE_TIME_ASSERT(sizeof(int)==4); 47 | // InterlockedIncrement 48 | unsigned int result = xadd_4(pInt, 1) + 1; 49 | return (int)result; 50 | } 51 | 52 | int AtomicDecrement(int* pInt) 53 | { 54 | // InterlockedDecrement 55 | unsigned int result = xadd_4(pInt, -1) - 1; 56 | return (int)result; 57 | } 58 | 59 | #else 60 | 61 | int AtomicIncrement(int* pInt) 62 | { 63 | COMPILE_TIME_ASSERT(sizeof(int)==4); 64 | // InterlockedIncrement 65 | return __sync_add_and_fetch(pInt, 1); 66 | } 67 | 68 | int AtomicDecrement(int* pInt) 69 | { 70 | // InterlockedDecrement 71 | return __sync_sub_and_fetch(pInt, 1); 72 | } 73 | 74 | #endif 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /common/atomichelpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2013 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 | 18 | #ifndef ATOMICHELPERS_H 19 | #define ATOMICHELPERS_H 20 | 21 | 22 | int AtomicIncrement(int* pInt); 23 | int AtomicDecrement(int* pInt); 24 | 25 | 26 | #endif /* ATOMICHELPERS_H */ 27 | 28 | -------------------------------------------------------------------------------- /common/chkmacros.h: -------------------------------------------------------------------------------- 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 | 18 | #ifndef CHKMACROS_H 19 | #define CHKMACROS_H 20 | 21 | #include "hresult.h" 22 | 23 | 24 | 25 | template 26 | inline HRESULT CheckCore(const T t) 27 | { 28 | t.What_You_Passed_To_Chk_Is_Not_HRESULT(); 29 | return E_FAIL; 30 | } 31 | 32 | template 33 | inline bool CheckIfCore(const T t) 34 | { 35 | t.What_You_Passed_To_ChkIf_Is_Not_bool(); 36 | return false; 37 | } 38 | 39 | 40 | template <> 41 | inline HRESULT CheckCore(const HRESULT t) 42 | { 43 | return t; 44 | } 45 | 46 | template <> 47 | inline bool CheckIfCore(const bool t) 48 | { 49 | return t; 50 | } 51 | 52 | 53 | #define Chk(expr) \ 54 | { \ 55 | ((void)hr); \ 56 | hr = CheckCore((expr)); \ 57 | if (FAILED(hr)) \ 58 | { \ 59 | goto Cleanup; \ 60 | } \ 61 | } 62 | 63 | #define ChkIf(expr, hrerror) \ 64 | { \ 65 | ((void)hr); \ 66 | if (CheckIfCore((expr))) \ 67 | { \ 68 | hr = (hrerror); \ 69 | goto Cleanup; \ 70 | } \ 71 | } 72 | 73 | #define ChkA(expr) \ 74 | { \ 75 | ((void)hr); \ 76 | hr = CheckCore((expr)); \ 77 | if (FAILED(hr)) \ 78 | { \ 79 | ASSERT(false); \ 80 | goto Cleanup; \ 81 | } \ 82 | } 83 | 84 | #define ChkIfA(expr, hrerror) \ 85 | { \ 86 | ((void)hr); \ 87 | if (CheckIfCore((expr))) \ 88 | { \ 89 | ASSERT(false); \ 90 | hr = (hrerror); \ 91 | goto Cleanup; \ 92 | } \ 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /common/cmdlineparser.cpp: -------------------------------------------------------------------------------- 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 | 18 | #include "commonincludes.hpp" 19 | #include 20 | 21 | #include "cmdlineparser.h" 22 | 23 | 24 | const option* CCmdLineParser::GenerateOptions() 25 | { 26 | _options.clear(); 27 | 28 | size_t len = _listOptionDetails.size(); 29 | for (size_t index = 0; index < len; index++) 30 | { 31 | option opt = {}; 32 | opt.has_arg = _listOptionDetails[index].has_arg; 33 | 34 | // Solaris 11 (released in 2011), only sees fit to include header files from 2004 where "option::name" is just a char* and not const char* 35 | opt.name = (char*)(_listOptionDetails[index].strName.c_str()); 36 | 37 | 38 | _options.push_back(opt); 39 | } 40 | 41 | option zero = {0,0,0,0}; 42 | _options.push_back(zero); 43 | 44 | 45 | return &_options.front(); 46 | } 47 | 48 | 49 | 50 | HRESULT CCmdLineParser::AddOption(const char* pszName, int has_arg, std::string* pStrResult) 51 | { 52 | HRESULT hr = S_OK; 53 | OptionDetail od; 54 | 55 | ChkIfA(pszName==NULL, E_INVALIDARG); 56 | ChkIfA(has_arg < 0, E_INVALIDARG); 57 | ChkIfA(has_arg > 2, E_INVALIDARG); 58 | ChkIfA(pStrResult==NULL, E_INVALIDARG); 59 | 60 | od.has_arg = has_arg; 61 | od.pStrResult = pStrResult; 62 | od.strName = pszName; 63 | 64 | _listOptionDetails.push_back(od); 65 | 66 | Cleanup: 67 | return hr; 68 | 69 | } 70 | 71 | HRESULT CCmdLineParser::AddNonOption(std::string* pStrResult) 72 | { 73 | _namelessArgs.push_back(pStrResult); 74 | return S_OK; 75 | } 76 | 77 | 78 | HRESULT CCmdLineParser::ParseCommandLine(int argc, char** argv, int startindex, bool* pErrorFlag) 79 | { 80 | 81 | int oldopterr = ::opterr; 82 | size_t offset = 0; 83 | 84 | 85 | ::opterr = 0; 86 | ::optind = startindex; 87 | 88 | 89 | 90 | const option* longopts = GenerateOptions(); 91 | 92 | if (pErrorFlag) 93 | { 94 | *pErrorFlag = false; 95 | } 96 | 97 | while (true) 98 | { 99 | int index = 0; 100 | int ret; 101 | 102 | ret = ::getopt_long_only(argc, argv, "", longopts, &index); 103 | 104 | if (ret < 0) 105 | { 106 | break; 107 | } 108 | 109 | if ((ret == '?') || (ret == ':')) 110 | { 111 | if (pErrorFlag) 112 | { 113 | *pErrorFlag = true; 114 | } 115 | continue; 116 | } 117 | 118 | if ((longopts[index].has_arg != 0) && (optarg != NULL)) 119 | { 120 | _listOptionDetails[index].pStrResult->assign(optarg); 121 | } 122 | else 123 | { 124 | _listOptionDetails[index].pStrResult->assign("1"); 125 | } 126 | } 127 | 128 | offset = 0; 129 | for (int j = ::optind; j < argc; j++) 130 | { 131 | if (strcmp("--", argv[j]) == 0) 132 | { 133 | continue; 134 | } 135 | 136 | if (_namelessArgs.size() <= offset) 137 | { 138 | // should we set the error flag if we don't have a binding for this arg? 139 | break; 140 | } 141 | 142 | _namelessArgs[offset]->assign(argv[j]); 143 | offset++; 144 | } 145 | 146 | 147 | ::opterr = oldopterr; 148 | return S_OK; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /common/cmdlineparser.h: -------------------------------------------------------------------------------- 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 | 18 | #ifndef CMDLINEPARSER_H 19 | #define CMDLINEPARSER_H 20 | 21 | #include 22 | 23 | class CCmdLineParser 24 | { 25 | const option* GenerateOptions(); 26 | 27 | std::vector