├── example.config ├── .gitignore ├── README ├── Variables.cpp ├── URLEncode.h ├── URLEncodeTest.cpp ├── URLEncode.cpp ├── RegexpTest.cpp ├── F16Test.cpp ├── SelfDetect.h ├── ReportingTest.cpp ├── Regexp.h ├── Exit.h ├── TimevalTest.cpp ├── UnixSignal.h ├── LinkedLists.cpp ├── LogTest.cpp ├── VectorTest.cpp ├── SelfDetectTest.cpp ├── UnixSignalTest.cpp ├── SocketsTest.cpp ├── Defines.h ├── Timeval.cpp ├── Reporting.h ├── Timeval.h ├── MemoryLeak.h ├── LockTest.cpp ├── BitVectorTest.cpp ├── Makefile.am ├── UtilsTest.cpp ├── ConfigurationTest.cpp ├── F16.h ├── ThreadTest.cpp ├── SelfDetect.cpp ├── ScalarTypes.h ├── sqlite3util.h ├── LinkedLists.h ├── UnixSignal.cpp ├── InterthreadTest.cpp ├── Sockets.h ├── Reporting.cpp ├── Logger.h ├── Sockets.cpp ├── Threads.cpp ├── Threads.h ├── BitVector.cpp ├── BitVector.h ├── Utils.h └── Logger.cpp /example.config: -------------------------------------------------------------------------------- 1 | # example file 2 | key1 value1 3 | 4 | key2 123456 5 | $static key2 6 | key3 ssdf klsdf lkdf sf 7 | $optional key3 8 | 9 | key4 10 | 11 | key5 10 11 13 15 12 | 13 | # This file is also used to test the logging system. 14 | 15 | Log.Alarms.Max 20 16 | Log.Alarms.TargetIP 127.0.0.1 17 | Log.Alarms.TargetPort 10101 18 | Log.Level NOTICE 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .deps 3 | .libs 4 | *.o 5 | *.la 6 | *.lo 7 | *.in 8 | A51Test 9 | BitVectorTest 10 | ConfigurationTest 11 | F16Test 12 | InterthreadTest 13 | LockTest 14 | LogTest 15 | Makefile 16 | Makefile.in 17 | RegexpTest 18 | SocketsTest 19 | TimevalTest 20 | URLEncodeTest 21 | VectorTest 22 | SelfDetectTest 23 | UnixSignalTest 24 | ThreadTest 25 | UtilsTest 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This directory contains common-use classes, most of which are not specific to GSM. 2 | 3 | ``` 4 | Vector A vector class (NOT std::vector<>) that supports aliased subvectors. Not resizable. 5 | BitVector Bit-indexable vectors based on Vector. 6 | Interthread A set of C++ wrappers for pthread facilities. 7 | Sockets A set of C++ wrappers for Unix sockets. 8 | Timeval A C++ wraper for struct timeval. 9 | LinkLists Classes for simple linked lists of pointers. 10 | Logger A logging interface based on syslogd. 11 | Configuration A key-value configuration table. 12 | Regexp A C++ wrapper on stdlib regular expressions. 13 | ``` 14 | 15 | Do "make tests" to build a series of unit tests for these classes. 16 | 17 | -------------------------------------------------------------------------------- /Variables.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | 17 | 18 | #include "UnixSignal.h" 19 | #include "SelfDetect.h" 20 | 21 | // These variables all have constructors, and their may be some interaction 22 | // between them, so the order of construction is important. 23 | UnixSignal gSigVec; 24 | SelfDetect gSelf; 25 | -------------------------------------------------------------------------------- /URLEncode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | # include 30 | 31 | std::string URLEncode(const std::string&); 32 | -------------------------------------------------------------------------------- /URLEncodeTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | */ 24 | 25 | #include "URLEncode.h" 26 | #include 27 | #include 28 | 29 | 30 | using namespace std; 31 | 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | 36 | string test = string("Testing: !@#$%^&*() " TIMESTAMP_ISO); 37 | cout << test << endl; 38 | cout << URLEncode(test) << endl; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /URLEncode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | using namespace std; 31 | 32 | //based on javascript encodeURIComponent() 33 | string URLEncode(const string &c) 34 | { 35 | static const char *digits = "01234567890ABCDEF"; 36 | string retVal=""; 37 | for (size_t i=0; i>4) & 0x0f]; 45 | retVal += digits[ch & 0x0f]; 46 | } 47 | } 48 | return retVal; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /RegexpTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | #include "Regexp.h" 30 | #include 31 | 32 | using namespace std; 33 | 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | 38 | Regexp email("^[[:graph:]]+@[[:graph:]]+ "); 39 | Regexp simple("^dburgess@"); 40 | 41 | const char text1[] = "dburgess@jcis.net test message"; 42 | const char text2[] = "no address text message"; 43 | 44 | cout << email.match(text1) << " " << text1 << endl; 45 | cout << email.match(text2) << " " << text2 << endl; 46 | 47 | cout << simple.match(text1) << " " << text1 << endl; 48 | cout << simple.match(text2) << " " << text2 << endl; 49 | } 50 | -------------------------------------------------------------------------------- /F16Test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | #include "F16.h" 28 | 29 | 30 | #include 31 | 32 | using namespace std; 33 | 34 | int main(int argc, char **argv) 35 | { 36 | 37 | F16 a = 2.5; 38 | F16 b = 1.5; 39 | F16 c = 2.5 * 1.5; 40 | F16 d = c + a; 41 | F16 e = 10; 42 | cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' << e << endl; 43 | 44 | a *= 3; 45 | b *= 0.3; 46 | c *= e; 47 | cout << a << ' ' << b << ' ' << c << ' ' << d << endl; 48 | 49 | a /= 3; 50 | b /= 0.3; 51 | c = d * 0.05; 52 | cout << a << ' ' << b << ' ' << c << ' ' << d << endl; 53 | 54 | F16 f = a/d; 55 | cout << f << ' ' << f+0.5 << endl; 56 | } 57 | -------------------------------------------------------------------------------- /SelfDetect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013, 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | 17 | #ifndef SELFDETECT_H 18 | #define SELFDETECT_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /** A C++ wrapper for preventing 2 instances of a program from running. */ 26 | class SelfDetect 27 | { 28 | private: 29 | const char *mProg; // program name, which will map to /tmp/%s.pid 30 | const char *mFile; // file in /tmp for pid 31 | std::list mListFiles; // list of files to be removed at shutdown 32 | public: 33 | SelfDetect(void) 34 | { 35 | mProg = NULL; 36 | mFile = NULL; 37 | mListFiles.clear(); 38 | } 39 | 40 | ~SelfDetect(void) 41 | { 42 | if (mProg) { free((void *)mProg); mProg = NULL; } 43 | if (mFile) { free((void *)mFile); mFile = NULL; } 44 | mListFiles.clear(); 45 | } 46 | 47 | void RegisterProgram(const char *argv0); // register the program and validate 48 | void RegisterFile(const char *file); // register a file to be removed at shutdown / exit 49 | 50 | void Exit(int); // atexit() registration function -- called internally by real atexit() function that isn't in a class 51 | }; 52 | 53 | extern SelfDetect gSelf; 54 | #endif // SELFDETECT_H 55 | // vim: ts=4 sw=4 56 | -------------------------------------------------------------------------------- /ReportingTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012, 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | */ 24 | 25 | 26 | #include "stdlib.h" 27 | #include 28 | #include 29 | 30 | #include "Reporting.h" 31 | 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | 36 | srandom(time(NULL)); 37 | 38 | ReportingTable rpt("./test.db",LOG_LOCAL7); 39 | 40 | rpt.create("count1"); 41 | rpt.create("count2"); 42 | rpt.create("max1"); 43 | rpt.create("max2"); 44 | 45 | rpt.incr("count1"); 46 | rpt.incr("count2"); 47 | rpt.incr("count1"); 48 | 49 | rpt.clear("max1"); 50 | rpt.max("max1",random()); 51 | rpt.max("max2",random()); 52 | 53 | rpt.create("indexed",5,10); 54 | for (int i=0; i<20; i++) { 55 | rpt.incr("indexed",random()%6 + 5); 56 | } 57 | 58 | rpt.create("indexedMax",5,10); 59 | for (int i=5; i<=10; i++) { 60 | rpt.max("indexedMax", i, random()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Regexp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | 27 | #ifndef REGEXPW_H 28 | #define REGEXPW_H 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | 36 | class Regexp { 37 | 38 | private: 39 | 40 | regex_t mRegex; 41 | 42 | 43 | public: 44 | 45 | Regexp(const char* regexp, int flags=REG_EXTENDED) 46 | { 47 | int result = regcomp(&mRegex, regexp, flags); 48 | if (result) { 49 | char msg[256]; 50 | regerror(result,&mRegex,msg,255); 51 | std::cerr << "Regexp compilation of " << regexp << " failed: " << msg << std::endl; 52 | abort(); 53 | } 54 | } 55 | 56 | ~Regexp() 57 | { regfree(&mRegex); } 58 | 59 | bool match(const char *text, int flags=0) const 60 | { return regexec(&mRegex, text, 0, NULL, flags)==0; } 61 | 62 | }; 63 | 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /Exit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | 17 | #ifndef EXIT_H 18 | #define EXIT_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "Threads.h" 25 | 26 | /** A C++ wrapper for managing exit codes. Note that this is a helper class 27 | * without implementation. 28 | */ 29 | class Exit 30 | { 31 | public: 32 | enum eCodes 33 | { 34 | SUCCESS = 0, // no error 35 | DETECTFILE, // Unable to detect a required file: CommonLibs SelfDetect 36 | CREATEFILE, // Unable to create a required file: CommonLibs SelfDetect 37 | 38 | // Put all error codes above this line, to prevent error number values 39 | // from changing, put after the previous enum value (ie, preserve 40 | // the order. Also, provide a comment indicating which program(s) and 41 | // the purpose. 42 | 43 | LIMIT = 256 // all error codes must be less than this 44 | }; 45 | private: 46 | inline Exit(void) { /* cannot be constructed */; }; 47 | inline ~Exit(void) { /* cannot be destructed */; }; 48 | public: 49 | inline static void exit(int status) 50 | { 51 | if (status < SUCCESS || status >= LIMIT) 52 | { 53 | printf("INFO: Unsupported exit status of %d\n", status); 54 | } 55 | ::exit(status); 56 | /*NOTREACHED*/ 57 | } 58 | }; 59 | #endif // EXIT_H 60 | // vim: ts=4 sw=4 61 | -------------------------------------------------------------------------------- /TimevalTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | 30 | #include "Timeval.h" 31 | #include 32 | 33 | using namespace std; 34 | 35 | int main(int argc, char *argv[]) 36 | { 37 | 38 | Timeval then(10000); 39 | cout << then.elapsed() << endl; 40 | 41 | while (!then.passed()) { 42 | cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl; 43 | usleep(500000); 44 | } 45 | cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl; 46 | 47 | time_t t = time(NULL); 48 | std::string sLocal(""); 49 | std::string sGMT(""); 50 | Timeval::isoTime(t, sLocal, true); 51 | Timeval::isoTime(t, sGMT, false); 52 | cout << "Localtime: " << sLocal << ", GMT: " << sGMT << std::endl; 53 | } 54 | -------------------------------------------------------------------------------- /UnixSignal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | 17 | #ifndef UNIXSIGNAL_H 18 | #define UNIXSIGNAL_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "Threads.h" 25 | 26 | /** A C++ wrapper for managing unix signals. */ 27 | class UnixSignal 28 | { 29 | public: 30 | static const int C_NSIG = 64; 31 | private: 32 | std::list mListHandlers[C_NSIG]; // list of signal handlers to call for all signals 33 | Mutex mLock[C_NSIG]; 34 | bool mAddPid; // if true file is file.pid 35 | std::string mCoreFile; // name of file to save to 36 | bool mSaveFiles; // if true, save /proc related files in a compressed tarball 37 | std::string mTarFile; // tarball for proc files 38 | public: 39 | UnixSignal(void); 40 | ~UnixSignal(void); 41 | 42 | void Register(sighandler_t handler, int sig); // register a signal handler with the system 43 | void Handler(int sig); // main signal handler, iterates through mListHandlers 44 | void Dump(void); // debug dump of list 45 | inline void CoreName(const std::string &coreFile, bool addPid) { mCoreFile = coreFile; mAddPid = addPid; } 46 | inline void TarName(const std::string &tarFile, bool saveFiles) { mTarFile = tarFile; mSaveFiles = saveFiles; } 47 | }; 48 | 49 | extern UnixSignal gSigVec; 50 | #endif // UNIXSIGNAL_H 51 | // vim: ts=4 sw=4 52 | -------------------------------------------------------------------------------- /LinkedLists.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | 30 | #include "LinkedLists.h" 31 | 32 | 33 | void PointerFIFO::push_front(void* val) // by pat 34 | { 35 | // Pat added this routine for completeness, but never used or tested. 36 | // The first person to use this routine should remove this assert. 37 | ListNode *node = allocate(); 38 | node->data(val); 39 | node->next(mHead); 40 | mHead = node; 41 | if (!mTail) mTail=node; 42 | mSize++; 43 | } 44 | 45 | void PointerFIFO::put(void* val) 46 | { 47 | ListNode *node = allocate(); 48 | node->data(val); 49 | node->next(NULL); 50 | if (mTail!=NULL) mTail->next(node); 51 | mTail=node; 52 | if (mHead==NULL) mHead=node; 53 | mSize++; 54 | } 55 | 56 | /** Take an item from the FIFO. */ 57 | void* PointerFIFO::get() 58 | { 59 | // empty list? 60 | if (mHead==NULL) return NULL; 61 | // normal case 62 | ListNode* next = mHead->next(); 63 | void* retVal = mHead->data(); 64 | release(mHead); 65 | mHead = next; 66 | if (next==NULL) mTail=NULL; 67 | mSize--; 68 | return retVal; 69 | } 70 | 71 | 72 | ListNode *PointerFIFO::allocate() 73 | { 74 | if (mFreeList==NULL) return new ListNode; 75 | ListNode* retVal = mFreeList; 76 | mFreeList = mFreeList->next(); 77 | return retVal; 78 | } 79 | 80 | void PointerFIFO::release(ListNode* wNode) 81 | { 82 | wNode->next(mFreeList); 83 | mFreeList = wNode; 84 | } 85 | -------------------------------------------------------------------------------- /LogTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Free Software Foundation, Inc. 3 | * Copyright 2010 Kestrel Signal Processing, Inc. 4 | * Copyright 2014 Range Networks, Inc. 5 | * 6 | * 7 | * This software is distributed under the terms of the GNU Affero Public License. 8 | * See the COPYING file in the main directory for details. 9 | * 10 | * This use of this software may be subject to additional restrictions. 11 | * See the LEGAL file in the main directory for details. 12 | 13 | This program is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Affero General Public License as published by 15 | the Free Software Foundation, either version 3 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Affero General Public License for more details. 22 | 23 | You should have received a copy of the GNU Affero General Public License 24 | along with this program. If not, see . 25 | 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include "Logger.h" 32 | #include "Configuration.h" 33 | 34 | ConfigurationTable gConfig; 35 | //ConfigurationTable gConfig("example.config"); 36 | 37 | void printAlarms() 38 | { 39 | std::ostream_iterator output( std::cout, "\n" ); 40 | std::list alarms = gGetLoggerAlarms(); 41 | std::cout << "# alarms = " << alarms.size() << std::endl; 42 | std::copy( alarms.begin(), alarms.end(), output ); 43 | } 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | gLogInit("LogTest","NOTICE",LOG_LOCAL7); 48 | 49 | LOG(EMERG) << " testing the logger."; 50 | LOG(ALERT) << " testing the logger."; 51 | LOG(CRIT) << " testing the logger."; 52 | LOG(ERR) << " testing the logger."; 53 | LOG(WARNING) << " testing the logger."; 54 | LOG(NOTICE) << " testing the logger."; 55 | LOG(INFO) << " testing the logger."; 56 | LOG(DEBUG) << " testing the logger."; 57 | std::cout << "\n\n\n"; 58 | std::cout << "testing Alarms\n"; 59 | std::cout << "you should see three lines:" << std::endl; 60 | printAlarms(); 61 | std::cout << "----------- generating 20 alarms ----------" << std::endl; 62 | for (int i = 0 ; i < 20 ; ++i) { 63 | LOG(ALERT) << i; 64 | } 65 | std::cout << "you should see ten lines with the numbers 10..19:" << std::endl; 66 | printAlarms(); 67 | } 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /VectorTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | #define ENABLE_VECTORDEBUG 28 | 29 | #include "Vector.h" 30 | #include 31 | 32 | // We must have a gConfig now to include Vector. 33 | #include "Configuration.h" 34 | ConfigurationTable gConfig; 35 | 36 | using namespace std; 37 | 38 | typedef Vector TestVector; 39 | int barfo; 40 | void foo(TestVector a) 41 | { 42 | barfo = a.size(); // Do something so foo wont be optimized out. 43 | } 44 | void anotherTest() 45 | { 46 | cout << "START Vector anotherTest" << endl; 47 | TestVector v0(10); 48 | TestVector atest = v0.head(3); 49 | cout << atest << endl; 50 | cout << "calling head" << endl; 51 | cout << v0.head(3) << endl; 52 | cout << "Passing Vector" << endl; 53 | // This calls the Vector non-const copy constructor 54 | foo(v0); 55 | cout << "FINISH anotherTest" << endl; 56 | } 57 | 58 | int main(int argc, char *argv[]) 59 | { 60 | anotherTest(); 61 | TestVector test1(5); 62 | for (int i=0; i<5; i++) test1[i]=i; 63 | TestVector test2(5); 64 | for (int i=0; i<5; i++) test2[i]=10+i; 65 | 66 | cout << test1 << endl; 67 | cout << test2 << endl; 68 | 69 | { 70 | TestVector testC(test1,test2); 71 | cout << testC << endl; 72 | 73 | TestVector foo = testC.head(3); 74 | //cout << testC.head(3) << endl; 75 | cout << testC.tail(3) << endl; 76 | testC.fill(8); 77 | cout << testC << endl; 78 | test1.copyToSegment(testC,3); 79 | cout << testC << endl; 80 | 81 | TestVector testD(testC.segment(4,3)); 82 | cout << testD << endl; 83 | testD.fill(9); 84 | cout << testC << endl; 85 | cout << testD << endl; 86 | } 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /SelfDetectTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013, 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | */ 23 | 24 | #include 25 | #include "SelfDetect.h" 26 | #include "Configuration.h" 27 | #include "Logger.h" 28 | 29 | ConfigurationTable gConfig; 30 | 31 | // For best effects, run this program thrice: once with a pre-created 32 | // /var/run/argv.pid, and once without. First one should exit with an 33 | // error. Second should run this test. Third, with an argument, then type 34 | // Control-C. 35 | int main(int argc, char *argv[]) 36 | { 37 | int ret; 38 | gLogInit("SelfDetectTest","DEBUG",LOG_LOCAL7); 39 | gSelf.RegisterProgram(argv[0]); 40 | 41 | ret = system("touch /tmp/foo.1"); 42 | ret = system("touch /tmp/foo.2"); 43 | ret = system("touch /tmp/foo.3"); 44 | ret = system("touch /tmp/foo.4"); 45 | ret = system("touch /tmp/foo.5"); 46 | ret = system("touch /tmp/foo.6"); 47 | ret = system("touch /tmp/foo.7"); 48 | if (ret < 0) { ret = ret; } // warning eater 49 | 50 | gSelf.RegisterFile("/tmp/foo.0"); // ignored 51 | gSelf.RegisterFile("/tmp/foo.1"); // removed 52 | gSelf.RegisterFile("/tmp/foo.2"); // removed 53 | gSelf.RegisterFile("/tmp/foo.3"); // removed 54 | gSelf.RegisterFile("/tmp/foo.4"); // removed 55 | gSelf.RegisterFile("/tmp/foo.5"); // removed 56 | gSelf.RegisterFile("/tmp/foo.6"); // removed 57 | gSelf.RegisterFile("/tmp/foo.7"); // removed 58 | gSelf.RegisterFile("/tmp/foo.8"); // ignored 59 | gSelf.RegisterFile("/tmp/foo.9"); // ignored 60 | 61 | if (argv[1] != NULL) 62 | { 63 | printf("Use a Control-C to test in this mode, make sure\n"); 64 | printf("that the file goes away\n"); 65 | while(1) 66 | sleep(60); 67 | } 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /UnixSignalTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | */ 23 | 24 | #include 25 | #include "UnixSignal.h" 26 | #include "Configuration.h" 27 | #include "Logger.h" 28 | 29 | ConfigurationTable gConfig; 30 | 31 | void test1(int sig) { printf("Test 1, signal %d\n", sig); } 32 | void test2(int sig) { printf("Test 2, signal %d\n", sig); } 33 | void test3(int sig) { printf("Test 3, signal %d\n", sig); } 34 | void test4(int sig) { printf("Test 4, signal %d\n", sig); } 35 | void test5(int sig) { printf("Test 5, signal %d\n", sig); } 36 | void test6(int sig) { printf("Test 6, signal %d\n", sig); } 37 | 38 | void registerFuncs(int sig) 39 | { 40 | gSigVec.Register(test1, sig); 41 | gSigVec.Register(test2, sig); 42 | gSigVec.Register(test3, sig); 43 | gSigVec.Register(test4, sig); 44 | gSigVec.Register(test5, sig); 45 | gSigVec.Register(test6, sig); 46 | } 47 | 48 | int main(int argc, char *argv[]) 49 | { 50 | gLogInit("UnixSignalTest","DEBUG",LOG_LOCAL7); 51 | registerFuncs(SIGINT); 52 | registerFuncs(SIGHUP); 53 | registerFuncs(SIGTERM); 54 | printf("Test1 @ %p\n", test1); 55 | printf("Test2 @ %p\n", test2); 56 | printf("Test3 @ %p\n", test3); 57 | printf("Test4 @ %p\n", test4); 58 | printf("Test5 @ %p\n", test5); 59 | printf("Test6 @ %p\n", test6); 60 | printf("\n"); 61 | gSigVec.Dump(); 62 | 63 | printf("Run this three times. First time, do a 'kill %d' to test SIGTERM\n", getpid()); 64 | printf("Second time, do a 'kill -%d %d' to test SIGHUP\n", SIGHUP, getpid()); 65 | printf("Third time, do a Control-C to test SIGINT\n"); 66 | printf("\n"); 67 | printf("Output should iterate through tests 1-6 with the correct signal number\n"); 68 | printf("%d for SIGTERM, %d for SIGHUP, %d for SIGINT\n", 69 | SIGTERM, SIGHUP, SIGINT); 70 | while(true) 71 | sleep(60); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /SocketsTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | 30 | #include "Sockets.h" 31 | #include "Threads.h" 32 | #include 33 | #include 34 | 35 | #include "Configuration.h" 36 | ConfigurationTable gConfig; 37 | 38 | static const int gNumToSend = 10; 39 | 40 | 41 | void *testReaderIP(void *) 42 | { 43 | UDPSocket readSocket(5934, "localhost", 5061); 44 | readSocket.nonblocking(); 45 | int rc = 0; 46 | while (rc0) { 50 | COUT("read: " << buf); 51 | rc++; 52 | } else { 53 | sleep(2); 54 | } 55 | } 56 | return NULL; 57 | } 58 | 59 | 60 | 61 | void *testReaderUnix(void *) 62 | { 63 | UDDSocket readSocket("testDestination"); 64 | readSocket.nonblocking(); 65 | int rc = 0; 66 | while (rc0) { 70 | COUT("read: " << buf); 71 | rc++; 72 | } else { 73 | sleep(2); 74 | } 75 | } 76 | return NULL; 77 | } 78 | 79 | 80 | int main(int argc, char * argv[] ) 81 | { 82 | 83 | Thread readerThreadIP; 84 | readerThreadIP.start(testReaderIP,NULL); 85 | Thread readerThreadUnix; 86 | readerThreadUnix.start(testReaderUnix,NULL); 87 | 88 | UDPSocket socket1(5061, "127.0.0.1",5934); 89 | UDDSocket socket1U("testSource","testDestination"); 90 | 91 | COUT("socket1: " << socket1.port()); 92 | 93 | // give the readers time to open 94 | sleep(1); 95 | 96 | for (int i=0; i. 22 | 23 | */ 24 | 25 | // Pat added this file. 26 | // We need an include file that is included before any other include files. 27 | // Might I suggest that Range Networks specific global #defines be prefixed with RN_ 28 | 29 | #ifndef DEFINES_H 30 | #define DEFINES_H 31 | 32 | #define GPRS_ENCODER 1 // Use SharedL1Encoder and SharedL1Decoder 33 | #define GPRS_TESTSI4 1 34 | #define GPRS_TEST 1 // Compile in other GPRS stuff. 35 | #define GPRS_PAT 1 // Compile in GPRS code. Turn this off to get previous non-GRPS code, 36 | // although I am not maintaining it so you may have to fix compile 37 | // problems to use it. 38 | 39 | 40 | // (pat) This removes the constness from a pointer, eg: const T *barfo; T *notsobarfo = Unconst(barfo); 41 | template 42 | T* Unconst(const T*foo) { return const_cast(foo); } 43 | 44 | // (pat) Like assert() but dont core dump unless we are testing. 45 | // Note: to use this macro you must include the dependencies first. 46 | #define devassert(code) {if (IS_LOG_LEVEL(DEBUG)) {assert(code);} else if (!(code)) {LOG(ERR)<<"assertion failed:"<< #code;}} 47 | 48 | // __GNUG__ is true for g++ and __GNUC__ for gcc. 49 | #if __GNUC__&0==__GNUG__ 50 | 51 | #define RN_UNUSED __attribute__((unused)) 52 | 53 | #define RN_UNUSED_PARAM(var) RN_UNUSED var 54 | 55 | // Pack structs onto byte boundaries. 56 | // Note that if structs are nested, this must appear on all of them. 57 | #define RN_PACKED __attribute__((packed)) 58 | 59 | #else 60 | 61 | // Suppress warning message about a variable or function being unused. 62 | // In C++ you can leave out the variable name to suppress the 'unused variable' warning. 63 | #define RN_UNUSED_PARAM(var) /*nothing*/ 64 | #define RN_UNUSED /*not defined*/ 65 | #define RN_PACKED /*not defined*/ 66 | #endif 67 | 68 | // Bound value between min and max values. 69 | #define RN_BOUND(value,min,max) ( (value)<(min) ? (min) : (value)>(max) ? (max) : (value) ) 70 | 71 | #define RN_PRETTY_TEXT(name) (" " #name "=(") << name << ")" 72 | #define RN_PRETTY_TEXT1(name) (" " #name "=") << name 73 | #define RN_WRITE_TEXT(name) os << RN_PRETTY_TEXT(name) 74 | #define RN_WRITE_OPT_TEXT(name,flag) if (flag) { os << RN_WRITE_TEXT(name); } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /Timeval.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | #include 30 | #include "Timeval.h" 31 | 32 | using namespace std; 33 | 34 | void Timeval::future(unsigned offset) // In msecs 35 | { 36 | now(); 37 | unsigned sec = offset/1000; 38 | unsigned msec = offset%1000; 39 | mTimeval.tv_usec += msec*1000; 40 | mTimeval.tv_sec += sec; 41 | if (mTimeval.tv_usec>1000000) { 42 | mTimeval.tv_usec -= 1000000; 43 | mTimeval.tv_sec += 1; 44 | } 45 | } 46 | 47 | 48 | struct timespec Timeval::timespec() const 49 | { 50 | struct timespec retVal; 51 | retVal.tv_sec = mTimeval.tv_sec; 52 | retVal.tv_nsec = 1000 * (long)mTimeval.tv_usec; 53 | return retVal; 54 | } 55 | 56 | 57 | bool Timeval::passed() const 58 | { 59 | Timeval nowTime; 60 | if (nowTime.mTimeval.tv_sec < mTimeval.tv_sec) return false; 61 | if (nowTime.mTimeval.tv_sec > mTimeval.tv_sec) return true; 62 | if (nowTime.mTimeval.tv_usec > mTimeval.tv_usec) return true; 63 | return false; 64 | } 65 | 66 | double Timeval::seconds() const 67 | { 68 | return ((double)mTimeval.tv_sec) + 1e-6*((double)mTimeval.tv_usec); 69 | } 70 | 71 | 72 | 73 | long Timeval::delta(const Timeval& other) const 74 | { 75 | // 2^31 milliseconds is just over 4 years. 76 | int32_t deltaS = other.sec() - sec(); 77 | int32_t deltaUs = other.usec() - usec(); 78 | return 1000*deltaS + deltaUs/1000; 79 | } 80 | 81 | 82 | 83 | 84 | ostream& operator<<(ostream& os, const Timeval& tv) 85 | { 86 | os.setf( ios::fixed, ios::floatfield ); 87 | os << tv.seconds(); 88 | return os; 89 | } 90 | 91 | 92 | ostream& operator<<(ostream& os, const struct timespec& ts) 93 | { 94 | os << ts.tv_sec << "," << ts.tv_nsec; 95 | return os; 96 | } 97 | 98 | string Timeval::isoTime(time_t t, bool isLocal) 99 | { 100 | char buf[100]; 101 | struct tm tBuf; 102 | if (isLocal) 103 | localtime_r(&t, &tBuf); 104 | else 105 | gmtime_r(&t, &tBuf); 106 | snprintf(buf, sizeof(buf)-1, "%04d-%02d-%02dT%02d:%02d:%02d%s", 107 | tBuf.tm_year + 1900, tBuf.tm_mon + 1, tBuf.tm_mday, 108 | tBuf.tm_hour, tBuf.tm_min, tBuf.tm_sec, 109 | isLocal == false ? "Z" : ""); 110 | return string(buf); 111 | } 112 | 113 | void Timeval::isoTime(time_t t, std::string &result, bool isLocal) 114 | { 115 | result = isoTime(t,isLocal); 116 | } 117 | 118 | 119 | // vim: ts=4 sw=4 120 | -------------------------------------------------------------------------------- /Reporting.h: -------------------------------------------------------------------------------- 1 | /**@file Module for performance-reporting mechanisms. */ 2 | /* 3 | * Copyright 2012, 2013, 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | #ifndef REPORTING_H 27 | #define REPORTING_H 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | typedef std::map ReportBatch; 37 | 38 | /** 39 | Collect performance statistics into a database. 40 | Parameters are counters or max/min trackers, all integer. 41 | */ 42 | class ReportingTable { 43 | 44 | private: 45 | 46 | sqlite3* mDB; ///< database connection 47 | int mFacility; ///< rsyslogd facility 48 | ReportBatch mBatch; ///< batch of report updates, not yet stored in the db 49 | mutable Mutex mLock; ///< control for multithreaded read/write access to the batch 50 | Thread mBatchCommitter; ///< thread responsible for committing batches of report updates to the db 51 | 52 | 53 | 54 | public: 55 | bool mReportRunning; 56 | 57 | /** 58 | Open the database connection; 59 | create the table if it does not exist yet. 60 | */ 61 | ReportingTable(const char* filename); 62 | 63 | /** Create a new parameter. */ 64 | bool create(const char* paramName); 65 | 66 | /** Create an indexed parameter set. */ 67 | bool create(const char* baseBame, unsigned minIndex, unsigned maxIndex); 68 | 69 | /** Increment a counter. */ 70 | bool incr(const char* paramName); 71 | 72 | /** Increment an indexed counter. */ 73 | bool incr(const char* baseName, unsigned index); 74 | 75 | /** Take a max of a parameter. */ 76 | bool max(const char* paramName, unsigned newVal); 77 | 78 | /** Take a max of an indexed parameter. */ 79 | bool max(const char* paramName, unsigned index, unsigned newVal); 80 | 81 | /** Clear the whole table. */ 82 | bool clear(); 83 | 84 | /** Clear a value. */ 85 | bool clear(const char* paramName); 86 | 87 | /** Clear an indexed value. */ 88 | bool clear(const char* paramName, unsigned index); 89 | 90 | /** Dump the database to a stream. */ 91 | void dump(std::ostream&) const; 92 | 93 | /** Commit outstanding report updates to the database */ 94 | bool commit(); 95 | 96 | void reportShutdown() { mReportRunning = false; } 97 | }; 98 | 99 | /** Periodically triggers ReportingTable::commit(). */ 100 | void* reportingBatchCommitter(void*); 101 | extern ReportingTable gReports; 102 | 103 | #endif 104 | 105 | 106 | // vim: ts=4 sw=4 107 | -------------------------------------------------------------------------------- /Timeval.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | 27 | #ifndef TIMEVAL_H 28 | #define TIMEVAL_H 29 | 30 | #include 31 | #include "sys/time.h" 32 | #include 33 | #include 34 | 35 | 36 | 37 | /** A wrapper on usleep to sleep for milliseconds. */ 38 | inline void msleep(long v) { usleep(v*1000); } 39 | 40 | 41 | /** A C++ wrapper for struct timeval. */ 42 | class Timeval { 43 | 44 | private: 45 | 46 | struct timeval mTimeval; 47 | 48 | public: 49 | 50 | /** Set the value to gettimeofday. */ 51 | void now() { gettimeofday(&mTimeval,NULL); } 52 | 53 | /** Set the value to gettimeofday plus an offset. */ 54 | void future(unsigned ms); 55 | 56 | //@{ 57 | Timeval(unsigned sec, unsigned usec) 58 | { 59 | mTimeval.tv_sec = sec; 60 | mTimeval.tv_usec = usec; 61 | } 62 | 63 | Timeval(const struct timeval& wTimeval) 64 | :mTimeval(wTimeval) 65 | {} 66 | 67 | /** 68 | Create a Timeval offset into the future. 69 | @param offset milliseconds 70 | */ 71 | Timeval(unsigned offset=0) { future(offset); } 72 | //@} 73 | 74 | /** Convert to a struct timespec. */ 75 | struct timespec timespec() const; 76 | 77 | /** Return total seconds. */ 78 | double seconds() const; 79 | 80 | uint32_t sec() const { return mTimeval.tv_sec; } 81 | uint32_t usec() const { return mTimeval.tv_usec; } 82 | 83 | /** Return differnce from other (other-self), in ms. */ 84 | long delta(const Timeval& other) const; 85 | 86 | /** Elapsed time in ms. */ 87 | long elapsed() const { return delta(Timeval()); } 88 | 89 | /** Remaining time in ms. */ 90 | long remaining() const { return -elapsed(); } 91 | 92 | /** Return true if the time has passed, as per gettimeofday. */ 93 | bool passed() const; 94 | 95 | /** Add a given number of minutes to the time. */ 96 | void addMinutes(unsigned minutes) { mTimeval.tv_sec += minutes*60; } 97 | 98 | /** Convert a time_t into a formatted string, using the ISO 99 | * YYYY-MM-DDTHH:MM:SS[Z] format. If isLocal is true, use localtime, 100 | * otherwise, use gmtime. 101 | */ 102 | static std::string isoTime(time_t t, bool isLocal); 103 | static void isoTime(time_t t, std::string &result, bool isLocal); 104 | 105 | }; 106 | 107 | std::ostream& operator<<(std::ostream& os, const Timeval&); 108 | 109 | std::ostream& operator<<(std::ostream& os, const struct timespec&); 110 | 111 | 112 | #endif 113 | // vim: ts=4 sw=4 114 | -------------------------------------------------------------------------------- /MemoryLeak.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | #ifndef _MEMORYLEAK_ 17 | #define _MEMORYLEAK_ 1 18 | #include 19 | #include "ScalarTypes.h" 20 | #include "Logger.h" 21 | 22 | namespace Utils { 23 | 24 | struct MemStats { 25 | // Enumerates the classes that are checked. 26 | // Redundancies are ok, for example, we check BitVector and also 27 | // several descendants of BitVector. 28 | enum MemoryNames { 29 | mZeroIsUnused, 30 | mVector, 31 | mVectorData, 32 | mBitVector, 33 | mByteVector, 34 | mByteVectorData, 35 | mRLCRawBlock, 36 | mRLCUplinkDataBlock, 37 | mRLCMessage, 38 | mRLCMsgPacketDownlinkDummyControlBlock, // Redundant with RLCMessage 39 | mTBF, 40 | mLlcEngine, 41 | mSgsnDownlinkMsg, 42 | mRachInfo, 43 | mPdpPdu, 44 | mFECDispatchInfo, 45 | mL3Frame, 46 | msignalVector, 47 | mSoftVector, 48 | mScramblingCode, 49 | mURlcDownSdu, 50 | mURlcPdu, 51 | mSipBase, 52 | mSipDialog, 53 | mSipMessage, 54 | mSipTransaction, 55 | mMMContext, 56 | mMMUser, 57 | mTranEntry, 58 | mMachineBase, 59 | // Must be last: 60 | mMax, 61 | }; 62 | int mMemTotal[mMax]; // In elements, not bytes. 63 | int mMemNow[mMax]; 64 | const char *mMemName[mMax]; 65 | MemStats(); 66 | void memChkNew(MemoryNames memIndex, const char *id); 67 | void memChkDel(MemoryNames memIndex, const char *id); 68 | void text(std::ostream &os); 69 | // We would prefer to use an unordered_map, but that requires special compile switches. 70 | // What a super great language. 71 | typedef std::map MemMapType; 72 | MemMapType mMemMap; 73 | }; 74 | extern struct MemStats gMemStats; 75 | extern int gMemLeakDebug; 76 | 77 | // This is a memory leak detector. 78 | // Use by putting RN_MEMCHKNEW and RN_MEMCHKDEL in class constructors/destructors, 79 | // or use the DEFINE_MEMORY_LEAK_DETECTOR class and add the defined class 80 | // as an ancestor to the class to be memory leak checked. 81 | 82 | struct MemLabel { 83 | std::string mccKey; 84 | virtual ~MemLabel() { 85 | Int_z &tmp = Utils::gMemStats.mMemMap[mccKey]; tmp = tmp - 1; 86 | } 87 | }; 88 | 89 | #if RN_DISABLE_MEMORY_LEAK_TEST 90 | #define RN_MEMCHKNEW(type) 91 | #define RN_MEMCHKDEL(type) 92 | #define RN_MEMLOG(type,ptr) 93 | #define DEFINE_MEMORY_LEAK_DETECTOR_CLASS(subClass,checkerClass) \ 94 | struct checkerClass {}; 95 | #else 96 | 97 | #define RN_MEMCHKNEW(type) { Utils::gMemStats.memChkNew(Utils::MemStats::m##type,#type); } 98 | #define RN_MEMCHKDEL(type) { Utils::gMemStats.memChkDel(Utils::MemStats::m##type,#type); } 99 | 100 | #define RN_MEMLOG(type,ptr) { \ 101 | static std::string key = format("%s_%s:%d",#type,__FILE__,__LINE__); \ 102 | (ptr)->/* MemCheck##type:: */ mccKey = key; \ 103 | Utils::gMemStats.mMemMap[key]++; \ 104 | } 105 | 106 | // TODO: The above assumes that checkclass is MemCheck ## subClass 107 | #define DEFINE_MEMORY_LEAK_DETECTOR_CLASS(subClass,checkerClass) \ 108 | struct checkerClass : public virtual Utils::MemLabel { \ 109 | checkerClass() { RN_MEMCHKNEW(subClass); } \ 110 | virtual ~checkerClass() { \ 111 | RN_MEMCHKDEL(subClass); \ 112 | } \ 113 | }; 114 | 115 | #endif 116 | 117 | } // namespace Utils 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /LockTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | #include "Configuration.h" 8 | #include "Threads.h" 9 | 10 | ConfigurationTable gConfig; 11 | 12 | // LockTest starts three processes that lock and unlock three mutexes at random, to make sure no deadlock occurs. 13 | 14 | struct aprocess { 15 | string id; 16 | Thread t; 17 | Mutex m; 18 | void lockall(int lockOwnerBits); 19 | void runtest(); 20 | static void *pstart(void *v); 21 | void start1(); 22 | aprocess(string wid) : id(wid) {} 23 | }; 24 | 25 | aprocess a("a"), b("b"), c("c"); 26 | 27 | void aprocess::lockall(int lockOwnerBits) { 28 | if (id == "a") { 29 | ScopedLockMultiple lock(lockOwnerBits,a.m,b.m,c.m,__FILE__,__LINE__); 30 | } else if (id == "b") { 31 | ScopedLockMultiple lock(lockOwnerBits,b.m,a.m,c.m,__FILE__,__LINE__); 32 | } else if (id == "c") { 33 | ScopedLockMultiple lock(lockOwnerBits,c.m,a.m,b.m,__FILE__,__LINE__); 34 | } else { 35 | assert(0); 36 | } 37 | } 38 | 39 | static void waitabit() { 40 | // randomly return instantly. 41 | if (random() & 1) return; 42 | usleep(0xff&random()); 43 | } 44 | 45 | void aprocess::runtest() { 46 | for (int i = 0; i < 10000; i++) { 47 | waitabit(); 48 | //printf("%s %d here\n",id.c_str(),i); 49 | lockall(0); 50 | waitabit(); 51 | //printf("%s1:a=%d b=%d c=%d\n",id.c_str(),a.m.lockcnt(), b.m.lockcnt(), c.m.lockcnt()); 52 | // Add in some random locking behavior. 53 | if (random() & 1) { 54 | m.lock(__FILE__,__LINE__); 55 | waitabit(); 56 | m.unlock(); 57 | } 58 | //printf("%s2:a=%d b=%d c=%d\n",id.c_str(),a.m.lockcnt(), b.m.lockcnt(), c.m.lockcnt()); 59 | waitabit(); 60 | //printf("%s %d there\n",id.c_str(),i); 61 | { ScopedLock lock(m); 62 | lockall(1); 63 | waitabit(); 64 | //printf("%s3:a=%d b=%d c=%d\n",id.c_str(),a.m.lockcnt(), b.m.lockcnt(), c.m.lockcnt()); 65 | } 66 | //printf("%s4:a=%d b=%d c=%d\n",id.c_str(),a.m.lockcnt(), b.m.lockcnt(), c.m.lockcnt()); 67 | } 68 | printf("finished\n"); 69 | } 70 | 71 | void *aprocess::pstart(void *v) { // This is the interface for the Thread.start() method. 72 | aprocess *p = (aprocess*)v; 73 | p->runtest(); 74 | return 0; 75 | } 76 | 77 | void aprocess::start1() { 78 | this->t.start(&this->pstart,this); 79 | } 80 | 81 | typedef void *(*task_t)(void*); 82 | 83 | int main(int argc, char **argv) 84 | { 85 | // Start the three processes running. 86 | a.start1(); 87 | b.start1(); 88 | c.start1(); 89 | 90 | // And let the main process fight for the locks as well. 91 | // We also do a coverage check here: When we randomly sample the locks, all of them must have been locked at some point. 92 | int fndA=0, fndB=0, fndC=0; 93 | for (int n = 0; n < 1000; n++) { 94 | waitabit(); 95 | fndA += a.m.lockcnt(); 96 | fndB += b.m.lockcnt(); 97 | fndC += c.m.lockcnt(); 98 | //printf("loop %d: a=%d b=%d c=%d\n",n, a.m.lockcnt(), b.m.lockcnt(), c.m.lockcnt()); 99 | printf("loop %d: a=%s b=%s c=%s\n",n,a.m.mutext().c_str(), b.m.mutext().c_str(), c.m.mutext().c_str()); 100 | 101 | a.m.lock(__FILE__,__LINE__); 102 | b.m.lock(__FILE__,__LINE__); 103 | { ScopedLockMultiple tmp(3,a.m,b.m,c.m); waitabit(); } 104 | c.m.lock(__FILE__,__LINE__); 105 | 106 | waitabit(); 107 | a.m.unlock(); 108 | a.m.lock(__FILE__,__LINE__); 109 | 110 | waitabit(); 111 | b.m.unlock(); 112 | b.m.lock(__FILE__,__LINE__); 113 | 114 | waitabit(); 115 | a.m.unlock(); 116 | b.m.unlock(); 117 | c.m.unlock(); 118 | } 119 | //a.t.start(&a.pstart,&a); 120 | //b.t.start((void*)&b); 121 | //c.t.start((void*)&c); 122 | a.t.join(); // Wait for it to finish. 123 | b.t.join(); // Wait for it to finish. 124 | printf("Test Finished. During random sampling, locks held were: A %d, B %d, C %d\n", fndA, fndB, fndC); 125 | } 126 | -------------------------------------------------------------------------------- /BitVectorTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | #define ENABLE_VECTORDEBUG 29 | 30 | 31 | #include "BitVector.h" 32 | #include 33 | #include 34 | #include 35 | 36 | using namespace std; 37 | 38 | // We must have a gConfig now to include BitVector. 39 | #include "Configuration.h" 40 | ConfigurationTable gConfig; 41 | 42 | 43 | void origTest() 44 | { 45 | BitVector v0("0000111100111100101011110000"); 46 | cout << v0 << endl; 47 | // (pat) The conversion from a string was inserting garbage into the result BitVector. 48 | // Fixed now so only 0 or 1 are inserted, but lets check: 49 | for (char *cp = v0.begin(); cp < v0.end(); cp++) cout << (int)*cp<<" "; 50 | cout << endl; 51 | 52 | BitVector v1(v0); 53 | v1.LSB8MSB(); 54 | cout <. 20 | # 21 | 22 | include $(top_srcdir)/Makefile.common 23 | 24 | # AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) 25 | # AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread -lsqlite3 26 | 27 | EXTRA_DIST = \ 28 | example.config \ 29 | README.common 30 | 31 | noinst_LTLIBRARIES = libcommon.la 32 | 33 | libcommon_la_CXXFLAGS = $(AM_CXXFLAGS) -O3 -lsqlite3 34 | libcommon_la_SOURCES = \ 35 | Variables.cpp \ 36 | BitVector.cpp \ 37 | LinkedLists.cpp \ 38 | SelfDetect.cpp \ 39 | UnixSignal.cpp \ 40 | Sockets.cpp \ 41 | Threads.cpp \ 42 | Timeval.cpp \ 43 | Reporting.cpp \ 44 | Logger.cpp \ 45 | Configuration.cpp \ 46 | sqlite3util.cpp \ 47 | URLEncode.cpp \ 48 | Utils.cpp 49 | 50 | noinst_PROGRAMS = \ 51 | LockTest \ 52 | UtilsTest \ 53 | ThreadTest \ 54 | BitVectorTest \ 55 | InterthreadTest \ 56 | SelfDetectTest \ 57 | UnixSignalTest \ 58 | SocketsTest \ 59 | TimevalTest \ 60 | RegexpTest \ 61 | VectorTest \ 62 | ConfigurationTest \ 63 | LogTest \ 64 | URLEncodeTest \ 65 | F16Test 66 | 67 | # ReportingTest 68 | 69 | noinst_HEADERS = \ 70 | Defines.h \ 71 | BitVector.h \ 72 | Interthread.h \ 73 | LinkedLists.h \ 74 | SelfDetect.h \ 75 | UnixSignal.h \ 76 | Exit.h \ 77 | Sockets.h \ 78 | Threads.h \ 79 | Timeval.h \ 80 | Regexp.h \ 81 | Vector.h \ 82 | Configuration.h \ 83 | Reporting.h \ 84 | F16.h \ 85 | URLEncode.h \ 86 | Utils.h \ 87 | Logger.h \ 88 | sqlite3util.h 89 | 90 | ThreadTest_SOURCES = ThreadTest.cpp 91 | ThreadTest_LDADD = libcommon.la $(SQLITE_LA) 92 | 93 | URLEncodeTest_SOURCES = URLEncodeTest.cpp 94 | URLEncodeTest_LDADD = libcommon.la 95 | 96 | BitVectorTest_SOURCES = BitVectorTest.cpp 97 | BitVectorTest_LDADD = libcommon.la $(SQLITE_LA) 98 | 99 | InterthreadTest_SOURCES = InterthreadTest.cpp 100 | InterthreadTest_LDADD = libcommon.la $(SQLITE_LA) 101 | InterthreadTest_LDFLAGS = -lpthread -lcoredumper 102 | 103 | SocketsTest_SOURCES = SocketsTest.cpp 104 | SocketsTest_LDADD = libcommon.la $(SQLITE_LA) 105 | SocketsTest_LDFLAGS = -lpthread -lcoredumper 106 | 107 | TimevalTest_SOURCES = TimevalTest.cpp 108 | TimevalTest_LDADD = libcommon.la 109 | 110 | VectorTest_SOURCES = VectorTest.cpp 111 | VectorTest_LDADD = libcommon.la $(SQLITE_LA) 112 | 113 | RegexpTest_SOURCES = RegexpTest.cpp 114 | RegexpTest_LDADD = libcommon.la 115 | 116 | ConfigurationTest_SOURCES = ConfigurationTest.cpp 117 | ConfigurationTest_LDADD = libcommon.la $(SQLITE_LA) 118 | 119 | SelfDetectTest_SOURCES = SelfDetectTest.cpp 120 | SelfDetectTest_LDADD = libcommon.la $(SQLITE_LA) -lcoredumper 121 | 122 | UnixSignalTest_SOURCES = UnixSignalTest.cpp 123 | UnixSignalTest_LDADD = libcommon.la $(SQLITE_LA) -lcoredumper 124 | 125 | # ReportingTest_SOURCES = ReportingTest.cpp 126 | # ReportingTest_LDADD = libcommon.la $(SQLITE_LA) 127 | 128 | LogTest_SOURCES = LogTest.cpp 129 | LogTest_LDADD = libcommon.la $(SQLITE_LA) 130 | 131 | F16Test_SOURCES = F16Test.cpp 132 | 133 | UtilsTest_SOURCES = UtilsTest.cpp 134 | UtilsTest_LDADD = libcommon.la 135 | 136 | LockTest_SOURCES = LockTest.cpp 137 | LockTest_LDADD = libcommon.la 138 | 139 | MOSTLYCLEANFILES += testSource testDestination 140 | 141 | 142 | -------------------------------------------------------------------------------- /UtilsTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Configuration.h" 4 | #include "Utils.h" 5 | ConfigurationTable gConfig; // Needed for logger. 6 | using namespace std; 7 | 8 | 9 | struct foo : public RefCntBase { 10 | string id; 11 | foo(string wid) : id(wid) { printf("create foo %s %p\n",id.c_str(),this); } 12 | ~foo() { printf("delete foo %s %p\n",id.c_str(),this); } 13 | }; 14 | 15 | typedef RefCntPointer fooref; 16 | 17 | RefCntPointer refize(foo*f) 18 | { 19 | fooref ref(f); 20 | return ref; 21 | } 22 | 23 | void test1() // Basic test. 24 | { 25 | foo *b = new foo("b"); 26 | fooref bref(b); 27 | bref.free(); // Should free b. 28 | 29 | } 30 | 31 | void test2() // assignment 32 | { 33 | foo *c = new foo("c"); 34 | fooref cref = refize(c); 35 | 36 | foo *d = new foo("d"); 37 | fooref dref = d; 38 | fooref dref2 = d; 39 | 40 | dref = c; 41 | printf("here\n"); 42 | // d and c deleted when test2 returns. 43 | } 44 | 45 | void test3() // assignment 46 | { 47 | foo *c = new foo("c"); 48 | fooref cref = refize(c); 49 | 50 | foo *d = new foo("d"); 51 | fooref dref = d; 52 | 53 | dref = c; 54 | printf("here\n"); 55 | // d and c deleted when test2 returns. 56 | } 57 | 58 | void refcntpointertest() 59 | { 60 | test1(); 61 | test2(); 62 | test3(); 63 | } 64 | 65 | // Throw spaces into the string. 66 | string messup(string in) 67 | { 68 | string result; 69 | for (string::iterator it = in.begin(); it != in.end(); it++) { 70 | if (rand() & 1) result.push_back(' '); 71 | result.push_back(*it); 72 | } 73 | return result; 74 | } 75 | 76 | void asciiEncoderTest(bool verbose) 77 | { 78 | char tbuf[102]; // binary data to try encoding and then decoding. 79 | int numtests = 0; 80 | printf("asciiEncoderTest...\n"); 81 | for (unsigned len = 0; len < 100; len++) { // Length of binary data. 82 | for (unsigned testno = 0; testno < 100; testno++) { 83 | numtests++; 84 | for (unsigned charno = 0; charno < len; charno++) { 85 | tbuf[charno] = rand(); 86 | } 87 | string binaryinput = string(tbuf,len); 88 | 89 | for (unsigned type = 0; type < 2; type++) { 90 | const char *method = type ? "base64" : "hex"; 91 | string errorMessage; 92 | string encoded = encodeToString(tbuf,len,method,errorMessage); 93 | if (testno & 1) encoded = messup(encoded); 94 | string decoded = decodeToString(encoded.data(),encoded.size(),method,errorMessage); 95 | 96 | // Check our results. 97 | if (decoded.size() != len) { printf("FAIL %s len=%d size=%d encoded=%s\n",method,len,decoded.size(),encoded.c_str()); } 98 | if (binaryinput != decoded) { printf("FAIL %s testno=%d len=%d encoded=%s\n",method,testno,len,encoded.c_str()); } 99 | // Paranoid double check manually: 100 | for (unsigned j = 0; j < len; j++) { 101 | if (tbuf[j] != decoded[j]) { printf("FAIL %s len=%d j=%d\n",method,len,j); } 102 | } 103 | if (errorMessage.size()) { 104 | printf("%s error message=%s\n",method,errorMessage.c_str()); 105 | } 106 | if (verbose) printf("TEST %s len=%d test=%d encoded=%s\n",method,len,testno,encoded.c_str()); 107 | } 108 | 109 | /**** 110 | { // Hex encoder/decoder tests. 111 | string errorMessage = ""; 112 | string hexencoded = encodeToString(tbuf,len,"hex",errorMessage); 113 | if (hexencoded.size() != 2 * len) { 114 | printf("FAIL hex encoded size=%d expected=%d\n",hexencoded.size(),2*len); 115 | } 116 | string hexdecoded = decodeToString(hexencoded.data(),hexencoded.size(),"hex",errorMessage); 117 | //printf("input size=%d hexencoded size=%d hexdecoded size=%d %s\n",len,hexencoded.size(),hexdecoded.size(),hexencoded.c_str()); 118 | string e2 = encodeToString(hexdecoded.data(),hexdecoded.size(),"hex",errorMessage); 119 | //printf("in=%s out=%s\n",hexencoded.c_str(),e2.c_str()); 120 | if (e2 != hexencoded) { 121 | printf("FAIL hex here\n"); 122 | } 123 | if (binaryinput != hexdecoded) { printf("FAIL hex testno=%d len=%d\n",testno,len); } 124 | if (errorMessage.size()) { 125 | printf("base64 error message=%s\n",errorMessage.c_str()); 126 | } 127 | } 128 | ****/ 129 | } 130 | } 131 | printf("PASS %d tests\n",numtests); 132 | } 133 | 134 | 135 | int main(int argc, char **argv) 136 | { 137 | bool verbose = argc > 1; 138 | printf("Utils Test starting.\n"); 139 | refcntpointertest(); 140 | asciiEncoderTest(verbose); 141 | } 142 | -------------------------------------------------------------------------------- /ConfigurationTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009, 2010 Free Software Foundation, Inc. 3 | * Copyright 2010 Kestrel Signal Processing, Inc. 4 | * Copyright 2014 Range Networks, Inc. 5 | * 6 | * 7 | * This software is distributed under the terms of the GNU Affero Public License. 8 | * See the COPYING file in the main directory for details. 9 | * 10 | * This use of this software may be subject to additional restrictions. 11 | * See the LEGAL file in the main directory for details. 12 | 13 | This program is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Affero General Public License as published by 15 | the Free Software Foundation, either version 3 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Affero General Public License for more details. 22 | 23 | You should have received a copy of the GNU Affero General Public License 24 | along with this program. If not, see . 25 | 26 | */ 27 | 28 | 29 | 30 | #include "Configuration.h" 31 | #include 32 | #include 33 | 34 | using namespace std; 35 | 36 | ConfigurationKeyMap getConfigurationKeys(); 37 | ConfigurationTable gConfig("exampleconfig.db","test", getConfigurationKeys()); 38 | 39 | void purgeConfig(void*,int,char const*, char const*, sqlite3_int64) 40 | { 41 | //cout << "update hook" << endl; 42 | gConfig.purge(); 43 | } 44 | 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | 49 | gConfig.setUpdateHook(purgeConfig); 50 | 51 | const char *keys[5] = {"key1", "key2", "key3", "key4", "key5"}; 52 | 53 | for (int i=0; i<5; i++) { 54 | gConfig.set(keys[i],i); 55 | } 56 | 57 | for (int i=0; i<5; i++) { 58 | cout << "table[" << keys[i] << "]=" << gConfig.getStr(keys[i]) << endl; 59 | cout << "table[" << keys[i] << "]=" << gConfig.getNum(keys[i]) << endl; 60 | } 61 | 62 | for (int i=0; i<5; i++) { 63 | cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) << endl; 64 | } 65 | 66 | gConfig.set("key5","100 200 300 400 "); 67 | std::vector vect = gConfig.getVector("key5"); 68 | cout << "vect length " << vect.size() << ": "; 69 | for (unsigned i=0; i svect = gConfig.getVectorOfStrings("key5"); 72 | cout << "vect length " << svect.size() << ": "; 73 | for (unsigned i=0; igetName()] = *tmp; 125 | delete tmp; 126 | 127 | tmp = new ConfigurationKey("numnumber","42", 128 | "", 129 | ConfigurationKey::DEVELOPER, 130 | ConfigurationKey::VALRANGE, 131 | "0-100", 132 | false, 133 | "" 134 | ); 135 | map[tmp->getName()] = *tmp; 136 | delete tmp; 137 | 138 | tmp = new ConfigurationKey("newstring","new string value", 139 | "", 140 | ConfigurationKey::DEVELOPER, 141 | ConfigurationKey::STRING, 142 | "", 143 | false, 144 | "" 145 | ); 146 | map[tmp->getName()] = *tmp; 147 | delete tmp; 148 | 149 | return map; 150 | } 151 | -------------------------------------------------------------------------------- /F16.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | 27 | #ifndef F16_H 28 | #define F16_H 29 | 30 | #include 31 | #include 32 | 33 | 34 | 35 | /** Round a float to the appropriate F16 value. */ 36 | inline int32_t _f16_round(float f) 37 | { 38 | if (f>0.0F) return (int32_t)(f+0.5F); 39 | if (f<0.0F) return (int32_t)(f-0.5F); 40 | return 0; 41 | } 42 | 43 | 44 | 45 | /** A class for F15.16 fixed point arithmetic with saturation. */ 46 | class F16 { 47 | 48 | 49 | private: 50 | 51 | int32_t mV; 52 | 53 | 54 | public: 55 | 56 | F16() {} 57 | 58 | F16(int i) { mV = i<<16; } 59 | F16(float f) { mV = _f16_round(f*65536.0F); } 60 | F16(double f) { mV = _f16_round((float)f*65536.0F); } 61 | 62 | int32_t& raw() { return mV; } 63 | const int32_t& raw() const { return mV; } 64 | 65 | float f() const { return mV/65536.0F; } 66 | 67 | //operator float() const { return mV/65536.0F; } 68 | //operator int() const { return mV>>16; } 69 | 70 | F16 operator=(float f) 71 | { 72 | mV = _f16_round(f*65536.0F); 73 | return *this; 74 | } 75 | 76 | F16 operator=(int i) 77 | { 78 | mV = i<<16; 79 | return *this; 80 | } 81 | 82 | F16 operator=(const F16& other) 83 | { 84 | mV = other.mV; 85 | return mV; 86 | } 87 | 88 | F16 operator+(const F16& other) const 89 | { 90 | F16 retVal; 91 | retVal.mV = mV + other.mV; 92 | return retVal; 93 | } 94 | 95 | F16& operator+=(const F16& other) 96 | { 97 | mV += other.mV; 98 | return *this; 99 | } 100 | 101 | F16 operator-(const F16& other) const 102 | { 103 | F16 retVal; 104 | retVal.mV = mV - other.mV; 105 | return retVal; 106 | } 107 | 108 | F16& operator-=(const F16& other) 109 | { 110 | mV -= other.mV; 111 | return *this; 112 | } 113 | 114 | F16 operator*(const F16& other) const 115 | { 116 | F16 retVal; 117 | int64_t p = (int64_t)mV * (int64_t)other.mV; 118 | retVal.mV = p>>16; 119 | return retVal; 120 | } 121 | 122 | F16& operator*=(const F16& other) 123 | { 124 | int64_t p = (int64_t)mV * (int64_t)other.mV; 125 | mV = p>>16; 126 | return *this; 127 | } 128 | 129 | F16 operator*(float f) const 130 | { 131 | F16 retVal; 132 | retVal.mV = mV * f; 133 | return retVal; 134 | } 135 | 136 | F16& operator*=(float f) 137 | { 138 | mV *= f; 139 | return *this; 140 | } 141 | 142 | F16 operator/(const F16& other) const 143 | { 144 | F16 retVal; 145 | int64_t pV = (int64_t)mV << 16; 146 | retVal.mV = pV / other.mV; 147 | return retVal; 148 | } 149 | 150 | F16& operator/=(const F16& other) 151 | { 152 | int64_t pV = (int64_t)mV << 16; 153 | mV = pV / other.mV; 154 | return *this; 155 | } 156 | 157 | F16 operator/(float f) const 158 | { 159 | F16 retVal; 160 | retVal.mV = mV / f; 161 | return retVal; 162 | } 163 | 164 | F16& operator/=(float f) 165 | { 166 | mV /= f; 167 | return *this; 168 | } 169 | 170 | bool operator>(const F16& other) const 171 | { 172 | return mV>other.mV; 173 | } 174 | 175 | bool operator<(const F16& other) const 176 | { 177 | return mV(float f) const 186 | { 187 | return (mV/65536.0F) > f; 188 | } 189 | 190 | bool operator<(float f) const 191 | { 192 | return (mV/65536.0F) < f; 193 | } 194 | 195 | bool operator==(float f) const 196 | { 197 | return (mV/65536.0F) == f; 198 | } 199 | 200 | }; 201 | 202 | 203 | 204 | inline std::ostream& operator<<(std::ostream& os, const F16& v) 205 | { 206 | os << v.f(); 207 | return os; 208 | } 209 | 210 | #endif 211 | 212 | -------------------------------------------------------------------------------- /ThreadTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "Threads.h" 30 | #include "Utils.h" 31 | using namespace Utils; 32 | 33 | // We must have a gConfig now to include BitVector. 34 | #include "Configuration.h" 35 | ConfigurationTable gConfig; 36 | 37 | // pat 6-2014: Check how many threads we can create. 38 | 39 | #define NUM_THREADS 100000 40 | 41 | // Overwrite Thread::start() so we can see what is going on. 42 | 43 | class ThreadTest { 44 | 45 | protected: 46 | 47 | pthread_t mThread; 48 | pthread_attr_t mAttrib; 49 | // FIXME -- Can this be reduced now? 50 | size_t mStackSize; 51 | 52 | 53 | public: 54 | 55 | /** Create a thread in a non-running state. */ 56 | ThreadTest(size_t wStackSize = (65536*4)):mThread((pthread_t)0) { 57 | pthread_attr_init(&mAttrib); // (pat) moved this here. 58 | mStackSize=wStackSize; 59 | } 60 | 61 | /** 62 | Destroy the Thread. 63 | It should be stopped and joined. 64 | */ 65 | // (pat) If the Thread is destroyed without being started, then mAttrib is undefined. Oops. 66 | ~ThreadTest() { pthread_attr_destroy(&mAttrib); } 67 | 68 | 69 | /** Start the thread on a task. */ 70 | void start( void*(*task)(void*), void *arg) { 71 | assert(mThread==((pthread_t)0)); 72 | int res; 73 | res = pthread_attr_setstacksize(&mAttrib, mStackSize); 74 | if (res) { fprintf(stderr,"pthread_setstacksize(%u) failed: error=%d %s\n",mStackSize,res,strerror(res)); } 75 | assert(!res); 76 | //res = pthread_create(&mThread, &mAttrib, &thread_main, p); 77 | res = pthread_create(&mThread, &mAttrib, task, arg); 78 | if (res) { LOG(ALERT) << "pthread_create failed, error:" <start( (void*(*)(void*)) serviceLoop,&i); 131 | if (i && i % 1000 == 0) { 132 | printf("%d\n",i); fflush(stdout); 133 | printf("Created %d (%d total) threads in %.2g seconds mem=%lldM\n",1000,i,timef()-chunktime,totalmem/1000000); 134 | chunktime = timef(); 135 | } 136 | } 137 | 138 | double elapsed = timef() - start; 139 | printf("Created %d threads in %.2g seconds\n",NUM_THREADS,elapsed); 140 | } 141 | -------------------------------------------------------------------------------- /SelfDetect.cpp: -------------------------------------------------------------------------------- 1 | /**@file Module for preventing two instances of a program from running. */ 2 | /* 3 | * Copyright 2013, 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "UnixSignal.h" 36 | #include "SelfDetect.h" 37 | #include "Logger.h" 38 | #include "Exit.h" 39 | #include "Configuration.h" 40 | 41 | //SelfDetect gSelf; 42 | 43 | extern ConfigurationTable gConfig; 44 | 45 | static void e(void) 46 | { 47 | gSelf.Exit(-999); 48 | } 49 | 50 | static void sigfcn(int sig) 51 | { 52 | gSelf.Exit(sig); 53 | } 54 | 55 | void SelfDetect::RegisterProgram(const char *argv0) 56 | { 57 | const char *p = strrchr((char*)argv0,'/'); 58 | if (p == NULL) { p = argv0; } 59 | 60 | char buf[100]; 61 | snprintf(buf, sizeof(buf)-1, "/var/run/%s.pid", p); 62 | LOG(NOTICE) << "*** Registering program " << argv0 << " to " << buf; 63 | 64 | // first, verify we aren't already running. 65 | struct stat stbuf; 66 | if (stat(buf, &stbuf) >= 0) 67 | { 68 | LOG(CRIT) << "*** An instance of " << p << " is already running. "; 69 | LOG(CRIT) << "*** If this is not the case, deleting this file will allow " << p << " to start: " << buf << " exiting..."; 70 | Exit::exit(Exit::DETECTFILE); 71 | } 72 | 73 | FILE *fp = fopen(buf, "w"); 74 | if (fp == NULL) 75 | { 76 | LOG(CRIT) << "*** Unable to create " << buf << ": " << strerror(errno) << " exiting..."; 77 | Exit::exit(Exit::CREATEFILE); 78 | } 79 | fprintf(fp, "%d\n", getpid()); 80 | fclose(fp); 81 | atexit(e); 82 | gSigVec.CoreName(gConfig.getStr("Core.File"), gConfig.getBool("Core.Pid")); 83 | gSigVec.TarName(gConfig.getStr("Core.TarFile"), gConfig.getBool("Core.SaveFiles")); 84 | 85 | // Now, register for all signals to do the cleanup 86 | for (int i = 1; i < UnixSignal::C_NSIG; i++) 87 | { 88 | switch(i) 89 | { 90 | // Add any signals that need to bypass the signal handling behavior 91 | // here. Currently, SIGCHLD is needed because a signal is generated 92 | // when stuff related to the transciever (which is a child process) 93 | // occurs. In that case, the openbts log output was: 94 | // openbts: ALERT 3073816320 05:03:50.4 OpenBTS.cpp:491:main: starting the transceiver 95 | // openbts: NOTICE 3073816320 05:03:50.4 SelfDetect.cpp:91:Exit: *** Terminating because of signal 17 96 | // openbts: NOTICE 3031243584 05:03:50.4 OpenBTS.cpp:165:startTransceiver: starting transceiver ./transceiver w/ 1 ARFCNs and Args: 97 | // openbts: NOTICE 3073816320 05:03:50.4 SelfDetect.cpp:98:Exit: *** Terminating ./OpenBTS 98 | // openbts: NOTICE 3073816320 05:03:50.4 SelfDetect.cpp:105:Exit: *** Removing pid file /var/run/OpenBTS.pid 99 | case SIGCONT: 100 | case SIGCHLD: 101 | break; 102 | default: 103 | gSigVec.Register(sigfcn, i); 104 | break; 105 | } 106 | } 107 | mProg = strdup(argv0); 108 | mFile = strdup(buf); 109 | } 110 | 111 | void SelfDetect::Exit(int sig) 112 | { 113 | LOG(NOTICE) << "*** Terminating because of signal " << sig; 114 | 115 | if (mProg == NULL) 116 | { 117 | LOG(NOTICE) << "*** Terminating without registration of program"; 118 | } else 119 | { 120 | LOG(NOTICE) << "*** Terminating " << mProg; 121 | } 122 | if (mFile == NULL) 123 | { 124 | LOG(NOTICE) << "*** Terminating without pid file"; 125 | } else 126 | { 127 | LOG(NOTICE) << "*** Removing pid file " << mFile; 128 | unlink(mFile); 129 | } 130 | for (std::list::iterator i = mListFiles.begin(); 131 | i != mListFiles.end(); ++i) 132 | { 133 | LOG(NOTICE) << "*** Removing " << i->c_str(); 134 | unlink(i->c_str()); 135 | } 136 | } 137 | 138 | void SelfDetect::RegisterFile(const char *file) 139 | { 140 | LOG(NOTICE) << "*** Registering " << file << " for removal at program exit"; 141 | std::string s(file); 142 | mListFiles.push_back(s); 143 | } 144 | 145 | -------------------------------------------------------------------------------- /ScalarTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011, 2014 Range Networks, Inc. 3 | * All Rights Reserved. 4 | * 5 | * This software is distributed under multiple licenses; 6 | * see the COPYING file in the main directory for licensing 7 | * information for this specific distribution. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | */ 16 | 17 | #ifndef SCALARTYPES_H 18 | #define SCALARTYPES_H 19 | #include // For size_t 20 | #include 21 | //#include "GSMCommon.h" // Was included for Z100Timer 22 | 23 | // We dont bother to define *= /= etc.; you'll have to convert: a*=b; to: a=a*b; 24 | #define _INITIALIZED_SCALAR_BASE_FUNCS(Classname,Basetype,Init) \ 25 | Classname() : value(Init) {} \ 26 | Classname(Basetype wvalue) { value = wvalue; } /* Can set from basetype. */ \ 27 | operator Basetype(void) const { return value; } /* Converts from basetype. */ \ 28 | Basetype operator=(Basetype wvalue) { return value = wvalue; } \ 29 | Basetype* operator&() { return &value; } 30 | 31 | #define _INITIALIZED_SCALAR_ARITH_FUNCS(Basetype) \ 32 | Basetype operator++() { return ++value; } \ 33 | Basetype operator++(int) { return value++; } \ 34 | Basetype operator--() { return --value; } \ 35 | Basetype operator--(int) { return value--; } \ 36 | Basetype operator+=(Basetype wvalue) { return value = value + wvalue; } \ 37 | Basetype operator-=(Basetype wvalue) { return value = value - wvalue; } 38 | 39 | #define _INITIALIZED_SCALAR_FUNCS(Classname,Basetype,Init) \ 40 | _INITIALIZED_SCALAR_BASE_FUNCS(Classname,Basetype,Init) \ 41 | _INITIALIZED_SCALAR_ARITH_FUNCS(Basetype) 42 | 43 | 44 | #define _DECLARE_SCALAR_TYPE(Classname_i,Classname_z,Basetype) \ 45 | template \ 46 | struct Classname_i { \ 47 | Basetype value; \ 48 | _INITIALIZED_SCALAR_FUNCS(Classname_i,Basetype,Init) \ 49 | }; \ 50 | typedef Classname_i<0> Classname_z; 51 | 52 | 53 | // Usage: 54 | // Where 'classname' is one of the types listed below, then: 55 | // classname_z specifies a zero initialized type; 56 | // classname_i initializes the type to the specified value. 57 | // We also define Float_z. 58 | _DECLARE_SCALAR_TYPE(Int_i, Int_z, int) 59 | _DECLARE_SCALAR_TYPE(Char_i, Char_z, signed char) 60 | _DECLARE_SCALAR_TYPE(Int16_i, Int16_z, int16_t) 61 | _DECLARE_SCALAR_TYPE(Int32_i, Int32_z, int32_t) 62 | _DECLARE_SCALAR_TYPE(UInt_i, UInt_z, unsigned) 63 | _DECLARE_SCALAR_TYPE(UChar_i, UChar_z, unsigned char) 64 | _DECLARE_SCALAR_TYPE(UInt16_i, UInt16_z, uint16_t) 65 | _DECLARE_SCALAR_TYPE(UInt32_i, UInt32_z, uint32_t) 66 | _DECLARE_SCALAR_TYPE(Size_t_i, Size_t_z, size_t) 67 | 68 | // Bool is special because it cannot accept some arithmetic funcs 69 | //_DECLARE_SCALAR_TYPE(Bool_i, Bool_z, bool) 70 | template 71 | struct Bool_i { 72 | bool value; 73 | _INITIALIZED_SCALAR_BASE_FUNCS(Bool_i,bool,Init) 74 | }; 75 | typedef Bool_i<0> Bool_z; 76 | 77 | // float is special, because C++ does not permit the template initalization: 78 | struct Float_z { 79 | float value; 80 | _INITIALIZED_SCALAR_FUNCS(Float_z,float,0) 81 | }; 82 | struct Double_z { 83 | double value; 84 | _INITIALIZED_SCALAR_FUNCS(Double_z,double,0) 85 | }; 86 | 87 | template 88 | struct Enum_z { 89 | basetype value; 90 | _INITIALIZED_SCALAR_BASE_FUNCS(Enum_z,basetype,((basetype)0)) 91 | }; 92 | 93 | 94 | class ItemWithValueAndWidth { 95 | public: 96 | virtual unsigned getValue() const = 0; 97 | virtual unsigned getWidth() const = 0; 98 | }; 99 | 100 | // A Range Networks Field with a specified width. 101 | // See RLCMessages.h for examples. 102 | template 103 | class Field_i : public ItemWithValueAndWidth 104 | { 105 | public: 106 | unsigned value; 107 | _INITIALIZED_SCALAR_FUNCS(Field_i,unsigned,Init) 108 | unsigned getWidth() const { return Width; } 109 | unsigned getValue() const { return value; } 110 | }; 111 | 112 | // Synonym for Field_i, but no way to do it. 113 | template 114 | class Field_z : public ItemWithValueAndWidth 115 | { 116 | public: 117 | unsigned value; 118 | _INITIALIZED_SCALAR_FUNCS(Field_z,unsigned,Init) 119 | unsigned getWidth() const { return Width; } 120 | unsigned getValue() const { return value; } 121 | }; 122 | 123 | // This is an uninitialized field. 124 | template 125 | class Field : public ItemWithValueAndWidth 126 | { 127 | public: 128 | unsigned value; 129 | _INITIALIZED_SCALAR_FUNCS(Field,unsigned,Init) 130 | unsigned getWidth() const { return Width; } 131 | unsigned getValue() const { return value; } 132 | }; 133 | 134 | 135 | // A Z100Timer with an initial value specified. 136 | //template 137 | //class Z100Timer_i : public GSM::Z100Timer { 138 | // public: 139 | // Z100Timer_i() : GSM::Z100Timer(Init) {} 140 | //}; 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /sqlite3util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Range Networks, Inc. 3 | * 4 | * This software is distributed under the terms of the GNU Affero Public License. 5 | * See the COPYING file in the main directory for details. 6 | * 7 | * This use of this software may be subject to additional restrictions. 8 | * See the LEGAL file in the main directory for details. 9 | 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU Affero General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | This program is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU Affero General Public License for more details. 19 | 20 | You should have received a copy of the GNU Affero General Public License 21 | along with this program. If not, see . 22 | 23 | */ 24 | 25 | #ifndef SQLITE3UTIL_H 26 | #define SQLITE3UTIL_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | // (pat) Dont put statics in .h files - they generate a zillion g++ error messages. 33 | extern const char *enableWAL; 34 | //static const char* enableWAL = { 35 | // "PRAGMA journal_mode=WAL" 36 | //}; 37 | 38 | // Pat added. 39 | class sqlQuery { 40 | sqlite3 *mdb; 41 | sqlite3_stmt *mStmt; 42 | int mQueryRC; 43 | void queryStart(sqlite3*db, const char *tableName,const char *condition, const char*resultCols); 44 | 45 | public: 46 | std::string mQueryString; 47 | // Query for row(s) matching this condition. Can request one or more result columns, or "*" for all columns. 48 | sqlQuery(sqlite3*db, const char *tableName,const char*resultColumns,const char *condition); 49 | // Query for a row where keyName == keyData. 50 | sqlQuery(sqlite3*db, const char *tableName,const char*resultColumns,const char *keyName, const char*keyData); 51 | // Query for a row where keyName == keyData. 52 | sqlQuery(sqlite3*db, const char *tableName,const char*resultColumns,const char *keyName, unsigned keyData); 53 | // Did the query succeed and find a result row? 54 | bool sqlSuccess() { return mStmt && mQueryRC == SQLITE_ROW; } 55 | // Return the results as text or integer. 56 | std::string getResultText(int colNum=0); 57 | sqlite3_int64 getResultInt(int colNum=0); 58 | // Return the number of columns in the result, or 0 if the result did not contain any data. 59 | // Note: If the table is completely empty, sqlite3_column_count returns non-0, so check mQueryRC first. 60 | unsigned sqlResultSize() { return mStmt && mQueryRC == SQLITE_ROW ? sqlite3_column_count(mStmt) : 0; } 61 | // Step to the next row. Return false if there are no more rows. 62 | bool sqlStep(); 63 | ~sqlQuery(); 64 | }; 65 | 66 | // (pat) These functions should probably not begin with "sqlite3_" since that is reserved for sqlite3 itself... 67 | int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query, unsigned retries = 5); 68 | 69 | int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt, unsigned retries = 5); 70 | 71 | bool sqlite3_single_lookup(sqlite3* DB, const char *tableName, 72 | const char* keyName, const char* keyData, 73 | const char* valueName, unsigned &valueData, unsigned retries = 5); 74 | 75 | // This function returns an allocated string that must be free'd by the caller. 76 | bool sqlite3_single_lookup(sqlite3* DB, const char* tableName, 77 | const char* keyName, const char* keyData, 78 | const char* valueName, char* &valueData, unsigned retries = 5); 79 | 80 | // This function returns an allocated string that must be free'd by the caller. 81 | bool sqlite3_single_lookup(sqlite3* DB, const char* tableName, 82 | const char* keyName, unsigned keyData, 83 | const char* valueName, char* &valueData, unsigned retries = 5); 84 | 85 | bool sqlite_single_lookup(sqlite3* DB, const char* tableName, 86 | const char* keyName, const char* keyData, 87 | const char* valueName, std::string &valueData); 88 | bool sqlite_single_lookup(sqlite3* DB, const char* tableName, 89 | const char* keyName, unsigned keyData, 90 | const char* valueName, std::string &valueData); 91 | 92 | //std::vector sqlite_multi_lookup_vector(sqlite3* DB, const char* tableName, const char* keyName, const char* keyData, const char *resultColumns); 93 | std::string sqlite_single_lookup_string(sqlite3* DB, const char* tableName, const char* keyName, unsigned keyData, const char* valueName); 94 | 95 | // Get and set attributes on an sqlite database. Works by creating an ATTR_TABLE in the database. 96 | bool sqlite_set_attr(sqlite3*db,const char *attr_name,const char *attr_value); 97 | std::string sqlite_get_attr(sqlite3*db,const char *attr_name); 98 | 99 | bool sqlite3_exists(sqlite3* DB, const char* tableName, 100 | const char* keyName, const char* keyData, unsigned retries = 5); 101 | 102 | /** Run a query, ignoring the result; return true on success. */ 103 | bool sqlite_command(sqlite3* DB, const char* query, int *pResultCode = NULL, unsigned retries=5); 104 | bool inline sqlite3_command(sqlite3* DB, const char* query, unsigned retries = 5) { return sqlite_command(DB,query,NULL,retries); } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /LinkedLists.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution. 6 | * 7 | * This software is distributed under the terms of the GNU Affero Public License. 8 | * See the COPYING file in the main directory for details. 9 | * 10 | * This use of this software may be subject to additional restrictions. 11 | * See the LEGAL file in the main directory for details. 12 | 13 | This program is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU Affero General Public License as published by 15 | the Free Software Foundation, either version 3 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU Affero General Public License for more details. 22 | 23 | You should have received a copy of the GNU Affero General Public License 24 | along with this program. If not, see . 25 | 26 | */ 27 | 28 | 29 | 30 | #ifndef LINKEDLISTS_H 31 | #define LINKEDLISTS_H 32 | 33 | #include 34 | #include 35 | 36 | 37 | 38 | /** This node class is used to build singly-linked lists. */ 39 | class ListNode { 40 | 41 | private: 42 | 43 | ListNode* mNext; 44 | void* mData; 45 | 46 | public: 47 | 48 | ListNode* next() { return mNext; } 49 | void next(ListNode* wNext) { mNext=wNext; } 50 | 51 | void* data() { return mData; } 52 | void data(void* wData) { mData=wData; } 53 | }; 54 | 55 | 56 | 57 | 58 | /** A fast FIFO for pointer-based storage. */ 59 | class PointerFIFO { 60 | 61 | protected: 62 | 63 | ListNode* mHead; ///< points to next item out 64 | ListNode* mTail; ///< points to last item in 65 | ListNode* mFreeList; ///< pool of previously-allocated nodes 66 | unsigned mSize; ///< number of items in the FIFO 67 | 68 | public: 69 | 70 | PointerFIFO() 71 | :mHead(NULL),mTail(NULL),mFreeList(NULL), 72 | mSize(0) 73 | {} 74 | 75 | unsigned size() const { return mSize; } 76 | unsigned totalSize() const { return 0; } // Not used in this version. 77 | 78 | /** Put an item into the FIFO at the back of the queue. aka push_back */ 79 | void put(void* val); 80 | /** Push an item on the front of the FIFO. */ 81 | void push_front(void*val); // pat added. 82 | 83 | /** 84 | Take an item from the FIFO. aka pop_front, but returns NULL 85 | Returns NULL for empty list. 86 | */ 87 | void* get(); 88 | 89 | /** Peek at front item without removal. */ 90 | void *front() { return mHead ? mHead->data() : 0; } // pat added 91 | 92 | 93 | private: 94 | 95 | /** Allocate a new node to extend the FIFO. */ 96 | ListNode *allocate(); 97 | 98 | /** Release a node to the free pool after removal from the FIFO. */ 99 | void release(ListNode* wNode); 100 | 101 | }; 102 | 103 | // This is the default type for SingleLinkList Node element; 104 | // You can derive your class directly from this, but then you must add type casts 105 | // all over the place. 106 | class SingleLinkListNode 107 | { public: 108 | SingleLinkListNode *mNext; 109 | SingleLinkListNode *next() {return mNext;} 110 | void setNext(SingleLinkListNode *item) {mNext=item;} 111 | SingleLinkListNode() : mNext(0) {} 112 | virtual unsigned size() { return 0; } 113 | }; 114 | 115 | // A single-linked lists of elements with internal pointers. 116 | // The methods must match those from SingleLinkListNode. 117 | // This class also assumes the Node has a size() method, and accumulates 118 | // the total size of elements in the list in totalSize(). 119 | template 120 | class SingleLinkList 121 | { 122 | Node *mHead, *mTail; 123 | unsigned mSize; // Number of elements in list. 124 | unsigned mTotalSize; // Total of size() method of elements in list. 125 | 126 | public: 127 | typedef void iterator; // Does not exist for this class, but needs to be defined. 128 | typedef void const_iterator; // Does not exist for this class, but needs to be defined. 129 | SingleLinkList() : mHead(0), mTail(0), mSize(0), mTotalSize(0) {} 130 | unsigned size() const { return mSize; } 131 | unsigned totalSize() const { return mTotalSize; } 132 | 133 | Node *pop_back() { assert(0); } // Not efficient with this type of list. 134 | 135 | Node *pop_front() 136 | { 137 | if (!mHead) return NULL; 138 | Node *result = mHead; 139 | mHead = mHead->next(); 140 | if (mTail == result) { mTail = NULL; assert(mHead == NULL); } 141 | result->setNext(NULL); // be neat 142 | mSize--; 143 | mTotalSize -= result->size(); 144 | return result; 145 | } 146 | 147 | void push_front(Node *item) 148 | { 149 | item->setNext(mHead); 150 | mHead = item; 151 | if (!mTail) { mTail = item; } 152 | mSize++; 153 | mTotalSize += item->size(); 154 | } 155 | 156 | void push_back(Node *item) 157 | { 158 | item->setNext(NULL); 159 | if (mTail) { mTail->setNext(item); } 160 | mTail = item; 161 | if (!mHead) mHead = item; 162 | mSize++; 163 | mTotalSize += item->size(); 164 | } 165 | Node *front() const { return mHead; } 166 | Node *back() const { return mTail; } 167 | 168 | // Interface to InterthreadQueue so it can used SingleLinkList as the Fifo. 169 | void put(void *val) { push_back((Node*)val); } 170 | void *get() { return pop_front(); } 171 | }; 172 | 173 | 174 | 175 | 176 | 177 | #endif 178 | // vim: ts=4 sw=4 179 | -------------------------------------------------------------------------------- /UnixSignal.cpp: -------------------------------------------------------------------------------- 1 | /**@file Module for managing Linux signals and allowing multiple handlers per signal. */ 2 | /* 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "UnixSignal.h" 36 | #include "Logger.h" 37 | 38 | //UnixSignal gSigVec; 39 | 40 | static void _sigHandler(int sig) 41 | { 42 | signal(sig, SIG_IGN); 43 | if (sig <= 0 || sig >= UnixSignal::C_NSIG) 44 | { 45 | LOG(ERR) << "Signal Handler for signal " << sig << " (out of range)"; 46 | return; 47 | } 48 | // work around C++ issue with function pointers and class based function pointers 49 | gSigVec.Handler(sig); 50 | signal(sig, SIG_DFL); 51 | printf("Rethrowing signal %d\n", sig); 52 | kill(getpid(), sig); 53 | } 54 | 55 | void UnixSignal::Handler(int sig) 56 | { 57 | // Only write core files for the signals that need core 58 | switch(sig) 59 | { 60 | case SIGQUIT: case SIGILL: case SIGABRT: case SIGFPE: case SIGSEGV: 61 | case SIGBUS: case SIGSYS: case SIGTRAP: case SIGXCPU: case SIGXFSZ: 62 | { 63 | char buf[BUFSIZ]; 64 | if (mAddPid) 65 | snprintf(buf, sizeof(buf)-1, "%s.%d", mCoreFile.c_str(), getpid()); 66 | else 67 | snprintf(buf, sizeof(buf)-1, "%s", mCoreFile.c_str()); 68 | WriteCoreDump(buf); 69 | 70 | // and save the files if needed 71 | if (mSaveFiles) 72 | { 73 | char buf[BUFSIZ]; 74 | std::string s; 75 | std::string p; 76 | sprintf(buf, "%d", getpid()); 77 | p = buf; 78 | s = "rm -rf /tmp/staging." ; s += p; s += "/ ; "; 79 | s += "mkdir /tmp/staging." ; s += p; s += "/ ; "; 80 | s += "cp --parents /etc/issue /tmp/staging." ; s += p; s += "/ ; "; 81 | s += "cp --parents /proc/cpuinfo /proc/interrupts /proc/iomem /proc/ioports /proc/diskstats /proc/loadavg /proc/locks /proc/meminfo /proc/softirqs /proc/stat /proc/uptime /proc/version /proc/version_signature /proc/vmstat /tmp/staging." ; s += p; s += "/ ; "; 82 | 83 | s += "for i in cmdline cpuset environ io limits maps net/tcp net/udp net/tcp6 net/udp6 net/unix net/netstat sched schedstat smaps stat statm status ; "; 84 | s += "do cp --parents /proc/" ; s += p; s += "/$i /tmp/staging." ; s += p; s += "/ ; "; 85 | s += "cp --parents /proc/"; s += p; s += "/task/*/stat* /tmp/staging."; s += p; s += "/ ; "; 86 | s += "done ; "; 87 | s += "tar --create --verbose --file=- --directory=/proc/"; s += p; s += " fd | ( cd /tmp/staging."; s += p; s += "/proc/"; s += p; s += "/ ; tar xpvf - ) ; "; 88 | s += "tar --create --verbose --file=- --directory=/tmp/staging."; s += p; s += "/ . | gzip > "; s += mTarFile; s += " ; "; 89 | s += "rm -rf /tmp/staging." ; s += p; 90 | printf("Running '%s'\n", s.c_str()); 91 | system(s.c_str()); 92 | } 93 | } 94 | break; 95 | default: 96 | break; 97 | } 98 | 99 | printf("Processing signal vector for sig %d\n", sig); 100 | mLock[sig].lock(); 101 | for (std::list::iterator i = mListHandlers[sig].begin(); 102 | i != mListHandlers[sig].end(); i++) 103 | { 104 | (*i)(sig); 105 | } 106 | mLock[sig].unlock(); 107 | printf("Done processing signal vector for sig %d\n", sig); 108 | } 109 | 110 | UnixSignal::UnixSignal(void) 111 | { 112 | for (int i = 0; i < C_NSIG; i++) 113 | { 114 | mListHandlers[i].clear(); 115 | //signal(i, _sigHandler); 116 | } 117 | mAddPid = false; 118 | mCoreFile = "core"; 119 | } 120 | 121 | UnixSignal::~UnixSignal(void) 122 | { 123 | for (int i = 0; i < C_NSIG; i++) 124 | { 125 | mListHandlers[i].clear(); 126 | signal(i, SIG_DFL); 127 | } 128 | } 129 | 130 | void UnixSignal::Register(sighandler_t handler, int sig) // register the handler to the signal 131 | { 132 | if (sig <= 0 || sig >= C_NSIG) 133 | { 134 | LOG(ERR) << "Unable to register callback for UnixSignal " << sig << " (out of range)"; 135 | return; 136 | } 137 | mLock[sig].lock(); 138 | signal(sig, _sigHandler); // only catch signals that have been registered 139 | mListHandlers[sig].insert(mListHandlers[sig].end(), handler); 140 | mLock[sig].unlock(); 141 | } 142 | 143 | void UnixSignal::Dump(void) 144 | { 145 | for (int sig = 0; sig < C_NSIG; sig++) 146 | { 147 | mLock[sig].lock(); 148 | if (mListHandlers[sig].size() != 0) 149 | { 150 | printf("Signal vectors for signal %d: ", sig); 151 | for (std::list::iterator i = mListHandlers[sig].begin(); 152 | i != mListHandlers[sig].end(); i++) 153 | { 154 | printf("%s0x%p", i == mListHandlers[sig].begin() ? "" : ", ", *i); 155 | } 156 | printf("\n"); 157 | } 158 | mLock[sig].unlock(); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /InterthreadTest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | #include "Threads.h" 30 | #include "Interthread.h" 31 | #include 32 | #include "Configuration.h" 33 | ConfigurationTable gConfig; 34 | 35 | using namespace std; 36 | 37 | 38 | InterthreadQueue gQ; 39 | InterthreadMap gMap; 40 | 41 | void* qWriter(void*) 42 | { 43 | int *p; 44 | for (int i=0; i<20; i++) { 45 | p = new int; 46 | *p = i; 47 | COUT("queue write " << *p); 48 | gQ.write(p); 49 | if (random()%2) sleep(1); 50 | } 51 | p = new int; 52 | *p = -1; 53 | gQ.write(p); 54 | return NULL; 55 | } 56 | 57 | void* qReader(void*) 58 | { 59 | bool done = false; 60 | while (!done) { 61 | int *p = gQ.read(); 62 | COUT("queue read " << *p); 63 | if (*p<0) done=true; 64 | delete p; 65 | } 66 | return NULL; 67 | } 68 | 69 | 70 | void* mapWriter(void*) 71 | { 72 | int *p; 73 | for (int i=0; i<20; i++) { 74 | p = new int; 75 | *p = i; 76 | COUT("map write " << *p); 77 | gMap.write(i,p); 78 | if (random()%2) sleep(1); 79 | } 80 | return NULL; 81 | } 82 | 83 | void* mapReader(void*) 84 | { 85 | for (int i=0; i<20; i++) { 86 | int *p = gMap.read(i); 87 | COUT("map read " << *p); 88 | // InterthreadMap will delete the pointers 89 | // delete p; 90 | } 91 | return NULL; 92 | } 93 | 94 | static const uint32_t Hyperframe = 1024; 95 | 96 | static int32_t FNDelta(int32_t v1, int32_t v2) 97 | { 98 | static const int32_t halfModulus = Hyperframe/2; 99 | int32_t delta = v1-v2; 100 | if (delta>=halfModulus) delta -= Hyperframe; 101 | else if (delta<-halfModulus) delta += Hyperframe; 102 | return (int32_t) delta; 103 | } 104 | 105 | static int FNCompare(int32_t v1, int32_t v2) 106 | { 107 | int32_t delta = FNDelta(v1,v2); 108 | if (delta>0) return 1; 109 | if (delta<0) return -1; 110 | return 0; 111 | } 112 | 113 | struct TestTime { 114 | 115 | 116 | int mFN; ///< frame number in the hyperframe 117 | int mTN; ///< timeslot number 118 | 119 | public: 120 | 121 | TestTime(int wFN=0, int wTN=0) 122 | :mFN(wFN),mTN(wTN) 123 | { } 124 | 125 | bool operator<(const TestTime& other) const 126 | { 127 | if (mFN==other.mFN) return (mTN(const TestTime& other) const 132 | { 133 | if (mFN==other.mFN) return (mTN>other.mTN); 134 | return FNCompare(mFN,other.mFN)>0; 135 | } 136 | 137 | bool operator<=(const TestTime& other) const 138 | { 139 | if (mFN==other.mFN) return (mTN<=other.mTN); 140 | return FNCompare(mFN,other.mFN)<=0; 141 | } 142 | 143 | bool operator>=(const TestTime& other) const 144 | { 145 | if (mFN==other.mFN) return (mTN>=other.mTN); 146 | return FNCompare(mFN,other.mFN)>=0; 147 | } 148 | 149 | bool operator==(const TestTime& other) const 150 | { 151 | return (mFN == other.mFN) && (mTN==other.mTN); 152 | } 153 | 154 | }; 155 | 156 | 157 | // Welcome to wonderful C++. 158 | struct CompareAdapter { 159 | /** Compare the objects pointed to, not the pointers themselves. */ 160 | // (pat) This is used when a RachInfo is placed in a priority_queue. 161 | // Return true if rach1 should appear before rach2 in the priority_queue, 162 | // meaning that rach1 will be serviced before rach2. 163 | bool operator()(const TestTime *rach1, const TestTime *rach2) { 164 | return *rach1 > *rach2; 165 | } 166 | }; 167 | 168 | void priority_queue_test() 169 | { 170 | typedef InterthreadPriorityQueue,CompareAdapter> PQ_t; 171 | PQ_t pq; 172 | 173 | pq.write(new TestTime(2,0)); 174 | pq.write(new TestTime(1,0)); 175 | pq.write(new TestTime(3,0)); 176 | pq.write(new TestTime(2,3)); 177 | pq.write(new TestTime(2,2)); 178 | pq.write(new TestTime(2,1)); 179 | pq.write(new TestTime(0,0)); 180 | pq.write(new TestTime(1021,1)); 181 | pq.write(new TestTime(1023,1)); 182 | pq.write(new TestTime(1022,1)); 183 | pq.write(new TestTime(1024,1)); 184 | while (1) { 185 | TestTime *peek = pq.peek(); 186 | TestTime *ptime = pq.readNoBlock(); 187 | if (!ptime) { break; } // Done. 188 | assert(*peek == *ptime); 189 | printf("TestTime(%d,%d)\n",ptime->mFN,ptime->mTN); 190 | } 191 | } 192 | 193 | int main(int argc, char *argv[]) 194 | { 195 | priority_queue_test(); 196 | 197 | Thread qReaderThread; 198 | qReaderThread.start(qReader,NULL); 199 | Thread mapReaderThread; 200 | mapReaderThread.start(mapReader,NULL); 201 | 202 | Thread qWriterThread; 203 | qWriterThread.start(qWriter,NULL); 204 | Thread mapWriterThread; 205 | mapWriterThread.start(mapWriter,NULL); 206 | 207 | qReaderThread.join(); 208 | qWriterThread.join(); 209 | mapReaderThread.join(); 210 | mapWriterThread.join(); 211 | } 212 | 213 | 214 | // vim: ts=4 sw=4 215 | -------------------------------------------------------------------------------- /Sockets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008, 2010 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | 27 | #ifndef SOCKETS_H 28 | #define SOCKETS_H 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | 42 | 43 | 44 | #define MAX_UDP_LENGTH 1500 45 | 46 | /** A function to resolve IP host names. */ 47 | bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port); 48 | 49 | /** Resolve an address of the form ":". */ 50 | bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort); 51 | 52 | /** An exception to throw when a critical socket operation fails. */ 53 | struct SocketError { 54 | SocketError(); 55 | }; 56 | #define SOCKET_ERROR {throw SocketError(); } 57 | 58 | /** Abstract class for connectionless sockets. */ 59 | class DatagramSocket { 60 | 61 | protected: 62 | 63 | int mSocketFD; ///< underlying file descriptor 64 | char mDestination[256]; ///< address to which packets are sent 65 | char mSource[256]; ///< return address of most recent received packet 66 | 67 | public: 68 | 69 | /** An almost-does-nothing constructor. */ 70 | DatagramSocket(); 71 | 72 | virtual ~DatagramSocket(); 73 | 74 | /** Return the address structure size for this socket type. */ 75 | virtual size_t addressSize() const = 0; 76 | 77 | /** 78 | Send a binary packet. 79 | @param buffer The data bytes to send to mDestination. 80 | @param length Number of bytes to send, or strlen(buffer) if defaulted to -1. 81 | @return number of bytes written, or -1 on error. 82 | */ 83 | int write( const char * buffer, size_t length); 84 | 85 | /** 86 | Send a C-style string packet. 87 | @param buffer The data bytes to send to mDestination. 88 | @return number of bytes written, or -1 on error. 89 | */ 90 | int write( const char * buffer); 91 | 92 | /** 93 | Send a binary packet. 94 | @param buffer The data bytes to send to mSource. 95 | @param length Number of bytes to send, or strlen(buffer) if defaulted to -1. 96 | @return number of bytes written, or -1 on error. 97 | */ 98 | int writeBack(const char * buffer, size_t length); 99 | 100 | /** 101 | Send a C-style string packet. 102 | @param buffer The data bytes to send to mSource. 103 | @return number of bytes written, or -1 on error. 104 | */ 105 | int writeBack(const char * buffer); 106 | 107 | 108 | /** 109 | Receive a packet. 110 | @param buffer A char[MAX_UDP_LENGTH] procured by the caller. 111 | @return The number of bytes received or -1 on non-blocking pass. 112 | */ 113 | int read(char* buffer); 114 | 115 | /** 116 | Receive a packet with a timeout. 117 | @param buffer A char[MAX_UDP_LENGTH] procured by the caller. 118 | @param maximum wait time in milliseconds 119 | @return The number of bytes received or -1 on timeout. 120 | */ 121 | int read(char* buffer, unsigned timeout); 122 | 123 | 124 | /** Send a packet to a given destination, other than the default. */ 125 | int send(const struct sockaddr *dest, const char * buffer, size_t length); 126 | 127 | /** Send a C-style string to a given destination, other than the default. */ 128 | int send(const struct sockaddr *dest, const char * buffer); 129 | 130 | /** Make the socket non-blocking. */ 131 | void nonblocking(); 132 | 133 | /** Make the socket blocking (the default). */ 134 | void blocking(); 135 | 136 | /** Close the socket. */ 137 | void close(); 138 | 139 | }; 140 | 141 | 142 | 143 | /** UDP/IP User Datagram Socket */ 144 | class UDPSocket : public DatagramSocket { 145 | 146 | public: 147 | // (pat) If you want to set the local port using some sql option, you MUST NOT do it in a constructor 148 | // unless that constructor is called from OpenBTS.cpp, because there is a constructor race between 149 | // class ConfigurationTable (needed by the call to gConfig) and the class containing the UDPSocket and calling gConfig. 150 | // Alternatively, since we cannot add an empty constructor (because it is ambiguous with the following) 151 | // you must use a UDPSocket* and allocate it with 'new'. 152 | 153 | /** Open a USP socket with an OS-assigned port and no default destination. */ 154 | UDPSocket( unsigned short localPort=0); 155 | 156 | /** Given a full specification, open the socket and set the dest address. */ 157 | UDPSocket( unsigned short localPort, 158 | const char * remoteIP, unsigned short remotePort); 159 | 160 | /** Set the destination port. */ 161 | void destination( unsigned short wDestPort, const char * wDestIP ); 162 | 163 | /** Return the actual port number in use. */ 164 | unsigned short port() const; 165 | 166 | /** Open and bind the UDP socket to a local port. */ 167 | void open(unsigned short localPort=0); 168 | 169 | /** Give the return address of the most recently received packet. */ 170 | const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; } 171 | 172 | size_t addressSize() const { return sizeof(struct sockaddr_in); } 173 | 174 | }; 175 | 176 | 177 | /** Unix Domain Datagram Socket */ 178 | class UDDSocket : public DatagramSocket { 179 | 180 | public: 181 | 182 | UDDSocket(const char* localPath=NULL, const char* remotePath=NULL); 183 | 184 | void destination(const char* remotePath); 185 | 186 | void open(const char* localPath); 187 | 188 | /** Give the return address of the most recently received packet. */ 189 | const struct sockaddr_un* source() const { return (const struct sockaddr_un*)mSource; } 190 | 191 | size_t addressSize() const { return sizeof(struct sockaddr_un); } 192 | 193 | }; 194 | 195 | 196 | #endif 197 | 198 | 199 | 200 | // vim:ts=4:sw=4 201 | -------------------------------------------------------------------------------- /Reporting.cpp: -------------------------------------------------------------------------------- 1 | /**@file Module for performance-reporting mechanisms. */ 2 | /* 3 | * Copyright 2012, 2013, 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | #include "Reporting.h" 27 | #include "Logger.h" 28 | #include 29 | #include 30 | 31 | static const char* createReportingTable = { 32 | "CREATE TABLE IF NOT EXISTS REPORTING (" 33 | "NAME TEXT UNIQUE NOT NULL, " 34 | "VALUE INTEGER DEFAULT 0, " 35 | "CLEAREDTIME INTEGER NOT NULL, " 36 | "UPDATETIME INTEGER DEFAULT 0 " 37 | ")" 38 | }; 39 | 40 | 41 | ReportingTable::ReportingTable(const char* filename) 42 | { 43 | gLogEarly(LOG_INFO | mFacility, "opening reporting table from path %s", filename); 44 | // Connect to the database. 45 | int rc = sqlite3_open(filename,&mDB); 46 | if (rc) { 47 | gLogEarly(LOG_EMERG | mFacility, "cannot open reporting database at %s, error message: %s", filename, sqlite3_errmsg(mDB)); 48 | sqlite3_close(mDB); 49 | mDB = NULL; 50 | return; 51 | } 52 | // Create the table, if needed. 53 | if (!sqlite3_command(mDB,createReportingTable)) { 54 | gLogEarly(LOG_EMERG | mFacility, "cannot create reporting table in database at %s, error message: %s", filename, sqlite3_errmsg(mDB)); 55 | } 56 | // Set high-concurrency WAL mode. 57 | if (!sqlite3_command(mDB,enableWAL)) { 58 | gLogEarly(LOG_EMERG | mFacility, "Cannot enable WAL mode on database at %s, error message: %s", filename, sqlite3_errmsg(mDB)); 59 | } 60 | // Start the commit thread 61 | mBatchCommitter.start((void*(*)(void*))reportingBatchCommitter,NULL); 62 | } 63 | 64 | 65 | bool ReportingTable::create(const char* paramName) 66 | { 67 | // add this report name to the batch map 68 | mLock.lock(); 69 | if (mBatch.find(paramName) == mBatch.end()) { 70 | mBatch[paramName] = 0; 71 | } 72 | mLock.unlock(); 73 | 74 | // and to the database 75 | char cmd[200]; 76 | sprintf(cmd,"INSERT OR IGNORE INTO REPORTING (NAME,CLEAREDTIME) VALUES (\"%s\",%ld)", paramName, time(NULL)); 77 | if (!sqlite3_command(mDB,cmd)) { 78 | gLogEarly(LOG_CRIT|mFacility, "cannot create reporting parameter %s, error message: %s", paramName, sqlite3_errmsg(mDB)); 79 | return false; 80 | } 81 | return true; 82 | } 83 | 84 | 85 | 86 | bool ReportingTable::incr(const char* paramName) 87 | { 88 | mLock.lock(); 89 | mBatch[paramName]++; 90 | mLock.unlock(); 91 | 92 | return true; 93 | } 94 | 95 | 96 | 97 | bool ReportingTable::max(const char* paramName, unsigned newVal) 98 | { 99 | char cmd[200]; 100 | sprintf(cmd,"UPDATE REPORTING SET VALUE=MAX(VALUE,%u), UPDATETIME=%ld WHERE NAME=\"%s\"", newVal, time(NULL), paramName); 101 | if (!sqlite3_command(mDB,cmd)) { 102 | gLogEarly(LOG_CRIT|mFacility, "cannot maximize reporting parameter %s, error message: %s", paramName, sqlite3_errmsg(mDB)); 103 | return false; 104 | } 105 | return true; 106 | } 107 | 108 | 109 | bool ReportingTable::clear(const char* paramName) 110 | { 111 | char cmd[200]; 112 | sprintf(cmd,"UPDATE REPORTING SET VALUE=0, UPDATETIME=0, CLEAREDTIME=%ld WHERE NAME=\"%s\"", time(NULL), paramName); 113 | if (!sqlite3_command(mDB,cmd)) { 114 | gLogEarly(LOG_CRIT|mFacility, "cannot clear reporting parameter %s, error message: %s", paramName, sqlite3_errmsg(mDB)); 115 | return false; 116 | } 117 | return true; 118 | } 119 | 120 | 121 | 122 | bool ReportingTable::clear() 123 | { 124 | char cmd[200]; 125 | sprintf(cmd,"UPDATE REPORTING SET VALUE=0, UPDATETIME=0, CLEAREDTIME=%ld", time(NULL)); 126 | if (!sqlite3_command(mDB,cmd)) { 127 | gLogEarly(LOG_CRIT|mFacility, "cannot clear reporting table, error message: %s", sqlite3_errmsg(mDB)); 128 | return false; 129 | } 130 | return true; 131 | } 132 | 133 | 134 | bool ReportingTable::create(const char* baseName, unsigned minIndex, unsigned maxIndex) 135 | { 136 | size_t sz = strlen(baseName); 137 | for (unsigned i = minIndex; i<=maxIndex; i++) { 138 | char name[sz+10]; 139 | sprintf(name,"%s.%u",baseName,i); 140 | if (!create(name)) return false; 141 | } 142 | return true; 143 | } 144 | 145 | bool ReportingTable::incr(const char* baseName, unsigned index) 146 | { 147 | char name[strlen(baseName)+10]; 148 | sprintf(name,"%s.%u",baseName,index); 149 | return incr(name); 150 | } 151 | 152 | 153 | bool ReportingTable::max(const char* baseName, unsigned index, unsigned newVal) 154 | { 155 | char name[strlen(baseName)+10]; 156 | sprintf(name,"%s.%u",baseName,index); 157 | return max(name,newVal); 158 | } 159 | 160 | 161 | bool ReportingTable::clear(const char* baseName, unsigned index) 162 | { 163 | char name[strlen(baseName)+10]; 164 | sprintf(name,"%s.%u",baseName,index); 165 | return clear(name); 166 | } 167 | 168 | bool ReportingTable::commit() 169 | { 170 | ReportBatch oustanding; 171 | ReportBatch::iterator mp; 172 | unsigned oustandingCount = 0; 173 | 174 | // copy out to free up access to mBatch as quickly as possible 175 | mLock.lock(); 176 | mp = mBatch.begin(); 177 | while (mp != mBatch.end()) { 178 | if (mp->second > 0) { 179 | oustanding[mp->first] = mp->second; 180 | mBatch[mp->first] = 0; 181 | oustandingCount++; 182 | } 183 | mp++; 184 | } 185 | mLock.unlock(); 186 | 187 | // now actually write them into the db if needed 188 | if (oustandingCount > 0) { 189 | Timeval timer; 190 | char cmd[200]; 191 | 192 | // TODO : could wrap this in a BEGIN; COMMIT; pair to transactionize these X UPDATEs 193 | mp = oustanding.begin(); 194 | while (mp != oustanding.end()) { 195 | sprintf(cmd,"UPDATE REPORTING SET VALUE=VALUE+%u, UPDATETIME=%ld WHERE NAME=\"%s\"", mp->second, time(NULL), mp->first.c_str()); 196 | if (!sqlite3_command(mDB,cmd)) { 197 | LOG(CRIT) << "could not increment reporting parameter " << mp->first << ", error message: " << sqlite3_errmsg(mDB); 198 | } 199 | mp++; 200 | } 201 | 202 | LOG(INFO) << "wrote " << oustandingCount << " entries in " << timer.elapsed() << "ms"; 203 | } 204 | 205 | return true; 206 | } 207 | 208 | extern ReportingTable gReports; 209 | void* reportingBatchCommitter(void*) 210 | { 211 | gReports.mReportRunning = true; 212 | while (gReports.mReportRunning) { 213 | sleep(10); 214 | gReports.commit(); 215 | } 216 | 217 | return NULL; 218 | } 219 | -------------------------------------------------------------------------------- /Logger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2009, 2010 Free Software Foundation, Inc. 3 | * Copyright 2010 Kestrel Signal Processing, Inc. 4 | * Copyright 2014 Range Networks, Inc. 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | // (pat) Logging is via rsyslogd controlled by /etc/rsyslog.d/OpenBTS.conf 28 | 29 | // (pat) WARNING is stupidly defined in /usr/local/include/osipparser2/osip_const.h. 30 | // This must be outside the #ifndef LOGGER_H to fix it as long as Logger.h included after the above file. 31 | #ifdef WARNING 32 | #undef WARNING 33 | #endif 34 | 35 | #ifndef LOGGER_H 36 | #define LOGGER_H 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | // We cannot include Utils.h because it includes Logger.h, so just declare timestr() here. 48 | // If timestr decl is changed G++ will whine when Utils.h is included. 49 | namespace Utils { const std::string timestr(); }; 50 | 51 | #if !defined(gettid) 52 | # define gettid() syscall(SYS_gettid) 53 | #endif // !defined(gettid) 54 | 55 | extern pid_t gPid; 56 | #define _LOG(level) \ 57 | Log(LOG_##level).get() <=LOG_##wLevel) 64 | #define IS_LOG_LEVEL(wLevel) (gCheckGroupLogLevel(LOG_GROUP,LOG_##wLevel) || gGetLoggingLevel(__FILE__)>=LOG_##wLevel) 65 | #define IS_WATCH_LEVEL(wLevel) gCheckGroupWatchLevel(LOG_GROUP,LOG_##wLevel) 66 | #else 67 | #define IS_WATCH_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel) 68 | #define IS_LOG_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel) 69 | #endif 70 | 71 | #ifdef NDEBUG 72 | #define LOG(wLevel) \ 73 | if (LOG_##wLevel!=LOG_DEBUG && IS_LOG_LEVEL(wLevel)) _LOG(wLevel) 74 | #else 75 | #define LOG(wLevel) \ 76 | if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel) 77 | #endif 78 | 79 | // pat: And for your edification here are the 'levels' as defined in syslog.h: 80 | // LOG_EMERG 0 system is unusable 81 | // LOG_ALERT 1 action must be taken immediately 82 | // LOG_CRIT 2 critical conditions 83 | // LOG_ERR 3 error conditions 84 | // LOG_WARNING 4 warning conditions 85 | // LOG_NOTICE 5 normal, but significant, condition 86 | // LOG_INFO 6 informational message 87 | // LOG_DEBUG 7 debug-level message 88 | 89 | // (pat) added - print out a var and its name. 90 | // Use like this: int descriptive_name; LOG(INFO)<= (int) level; 189 | } 190 | static __inline__ bool gCheckGroupWatchLevel(LogGroup::Group group, unsigned level) { 191 | assert(group < LogGroup::_NumberOfLogGroups); 192 | //_LOG(DEBUG) << LOGVAR(group)<= (int) level; 194 | } 195 | 196 | 197 | 198 | std::list gGetLoggerAlarms(); ///< Get a copy of the recent alarm list. 199 | 200 | 201 | /**@ Global control and initialization of the logging system. */ 202 | //@{ 203 | 204 | 205 | /** Initialize the global logging system with filename test 10*/ 206 | void gLogInitWithFile(const char* name, const char* level, int facility, char* LogFilePath=NULL); 207 | 208 | /** Initialize the global logging system. */ 209 | void gLogInit(const char* name, const char* level=NULL, int facility=LOG_USER); 210 | /** Get the logging level associated with a given file. */ 211 | int gGetLoggingLevel(const char *filename=NULL); 212 | /** Allow early logging when still in constructors */ 213 | void gLogEarly(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); 214 | //@} 215 | 216 | // (pat) This is historical, some files include Logger.h and expect to get these too. These should be removed. 217 | #include "Threads.h" // must be after defines above, if these files are to be allowed to use LOG() 218 | #include "Utils.h" 219 | 220 | #endif 221 | 222 | // vim: ts=4 sw=4 223 | -------------------------------------------------------------------------------- /Sockets.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008, 2010, 2014 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "Defines.h" 36 | #include "Threads.h" 37 | #include "Sockets.h" 38 | #include "Logger.h" 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include 45 | 46 | 47 | 48 | SocketError::SocketError() { 49 | LOG(DEBUG) << "SocketError"; 50 | } 51 | 52 | 53 | 54 | bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort) 55 | { 56 | assert(address); 57 | assert(hostAndPort); 58 | char *copy = strdup(hostAndPort); 59 | char *colon = strchr(copy,':'); 60 | if (!colon) { 61 | LOG(WARNING) << "missing port number in:"<h_addrtype != AF_INET) { 106 | LOG(WARNING) << "gethostbyname() resolved " << host << " to something other then AF_INET"; 107 | return false; 108 | } 109 | address->sin_family = hp->h_addrtype; // Above guarantees it is AF_INET 110 | assert(sizeof(address->sin_addr) == hp->h_length); 111 | memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length); 112 | address->sin_port = htons(port); 113 | return true; 114 | } 115 | 116 | 117 | 118 | DatagramSocket::DatagramSocket() 119 | { 120 | memset(mDestination, 0, sizeof(mDestination)); 121 | } 122 | 123 | 124 | 125 | 126 | 127 | void DatagramSocket::nonblocking() 128 | { 129 | fcntl(mSocketFD,F_SETFL,O_NONBLOCK); 130 | } 131 | 132 | void DatagramSocket::blocking() 133 | { 134 | fcntl(mSocketFD,F_SETFL,0); 135 | } 136 | 137 | void DatagramSocket::close() 138 | { 139 | ::close(mSocketFD); 140 | } 141 | 142 | 143 | DatagramSocket::~DatagramSocket() 144 | { 145 | close(); 146 | } 147 | 148 | 149 | 150 | 151 | 152 | int DatagramSocket::write( const char * message, size_t length ) 153 | { 154 | //assert(length<=MAX_UDP_LENGTH); // (pat 8-2013) Removed on David's orders. 155 | int retVal = sendto(mSocketFD, message, length, 0, 156 | (struct sockaddr *)mDestination, addressSize()); 157 | if (retVal == -1 ) perror("DatagramSocket::write() failed"); 158 | return retVal; 159 | } 160 | 161 | int DatagramSocket::writeBack( const char * message, size_t length ) 162 | { 163 | //assert(length<=MAX_UDP_LENGTH); // (pat 8-2013) Removed on David's orders. 164 | int retVal = sendto(mSocketFD, message, length, 0, 165 | (struct sockaddr *)mSource, addressSize()); 166 | if (retVal == -1 ) perror("DatagramSocket::write() failed"); 167 | return retVal; 168 | } 169 | 170 | 171 | 172 | int DatagramSocket::write( const char * message) 173 | { 174 | size_t length=strlen(message)+1; 175 | return write(message,length); 176 | } 177 | 178 | int DatagramSocket::writeBack( const char * message) 179 | { 180 | size_t length=strlen(message)+1; 181 | return writeBack(message,length); 182 | } 183 | 184 | 185 | 186 | int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length ) 187 | { 188 | // (pat 8-2013) Dont assert! 189 | // assert(length<=MAX_UDP_LENGTH); 190 | // sendto is supposed to return an error if the packet is too long. 191 | int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize()); 192 | if (retVal == -1 ) perror("DatagramSocket::send() failed"); 193 | return retVal; 194 | } 195 | 196 | int DatagramSocket::send(const struct sockaddr* dest, const char * message) 197 | { 198 | size_t length=strlen(message)+1; 199 | return send(dest,message,length); 200 | } 201 | 202 | 203 | 204 | 205 | 206 | int DatagramSocket::read(char* buffer) 207 | { 208 | socklen_t temp_len = sizeof(mSource); 209 | int length = recvfrom(mSocketFD, (void*)buffer, MAX_UDP_LENGTH, 0, 210 | (struct sockaddr*)&mSource,&temp_len); 211 | if ((length==-1) && (errno!=EAGAIN)) { 212 | perror("DatagramSocket::read() failed"); 213 | devassert(0); 214 | throw SocketError(); 215 | } 216 | return length; 217 | } 218 | 219 | 220 | int DatagramSocket::read(char* buffer, unsigned timeout) 221 | { 222 | fd_set fds; 223 | FD_ZERO(&fds); 224 | FD_SET(mSocketFD,&fds); 225 | struct timeval tv; 226 | tv.tv_sec = timeout/1000; 227 | tv.tv_usec = (timeout%1000)*1000; 228 | int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv); 229 | if (sel<0) { 230 | perror("DatagramSocket::read() select() failed"); 231 | devassert(0); 232 | throw SocketError(); 233 | } 234 | if (sel==0) return -1; 235 | if (FD_ISSET(mSocketFD,&fds)) return read(buffer); 236 | return -1; 237 | } 238 | 239 | 240 | 241 | 242 | 243 | 244 | UDPSocket::UDPSocket(unsigned short wSrcPort) 245 | :DatagramSocket() 246 | { 247 | open(wSrcPort); 248 | } 249 | 250 | 251 | UDPSocket::UDPSocket(unsigned short wSrcPort, 252 | const char * wDestIP, unsigned short wDestPort ) 253 | :DatagramSocket() 254 | { 255 | open(wSrcPort); 256 | destination(wDestPort, wDestIP); 257 | } 258 | 259 | 260 | 261 | void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP ) 262 | { 263 | resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort ); 264 | } 265 | 266 | 267 | void UDPSocket::open(unsigned short localPort) 268 | { 269 | // create 270 | mSocketFD = socket(AF_INET,SOCK_DGRAM,0); 271 | if (mSocketFD<0) { 272 | perror("socket() failed"); 273 | devassert(0); 274 | throw SocketError(); 275 | } 276 | 277 | // pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes. 278 | int on = 1; 279 | setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 280 | 281 | 282 | // bind 283 | struct sockaddr_in address; 284 | size_t length = sizeof(address); 285 | bzero(&address,length); 286 | address.sin_family = AF_INET; 287 | address.sin_addr.s_addr = INADDR_ANY; 288 | address.sin_port = htons(localPort); 289 | if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) { 290 | char buf[100]; 291 | sprintf(buf,"bind(port %d) failed",localPort); 292 | perror(buf); 293 | devassert(0); 294 | throw SocketError(); 295 | } 296 | } 297 | 298 | 299 | 300 | unsigned short UDPSocket::port() const 301 | { 302 | struct sockaddr_in name; 303 | socklen_t nameSize = sizeof(name); 304 | int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize); 305 | if (retVal==-1) { 306 | devassert(0); 307 | throw SocketError(); 308 | } 309 | return ntohs(name.sin_port); 310 | } 311 | 312 | 313 | 314 | 315 | 316 | UDDSocket::UDDSocket(const char* localPath, const char* remotePath) 317 | :DatagramSocket() 318 | { 319 | if (localPath!=NULL) open(localPath); 320 | if (remotePath!=NULL) destination(remotePath); 321 | } 322 | 323 | 324 | 325 | void UDDSocket::open(const char* localPath) 326 | { 327 | // create 328 | mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0); 329 | if (mSocketFD<0) { 330 | perror("socket() failed"); 331 | devassert(0); 332 | throw SocketError(); 333 | } 334 | 335 | // bind 336 | struct sockaddr_un address; 337 | size_t length = sizeof(address); 338 | bzero(&address,length); 339 | address.sun_family = AF_UNIX; 340 | strcpy(address.sun_path,localPath); 341 | unlink(localPath); 342 | if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) { 343 | char buf[1100]; 344 | sprintf(buf,"bind(path %s) failed",localPath); 345 | perror(buf); 346 | devassert(0); 347 | throw SocketError(); 348 | } 349 | } 350 | 351 | 352 | 353 | void UDDSocket::destination(const char* remotePath) 354 | { 355 | struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination; 356 | strcpy(unAddr->sun_path,remotePath); 357 | } 358 | 359 | 360 | 361 | 362 | // vim:ts=4:sw=4 363 | -------------------------------------------------------------------------------- /Threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008, 2014 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | 30 | 31 | #include "Threads.h" 32 | #include "Timeval.h" 33 | #include "Logger.h" 34 | #include 35 | 36 | 37 | using namespace std; 38 | 39 | int gMutexLogLevel = LOG_INFO; // The mutexes cannot call gConfig or gGetLoggingLevel so we have to get the log level indirectly. 40 | 41 | #if !defined(gettid) 42 | # define gettid() syscall(SYS_gettid) 43 | #endif // !defined(gettid) 44 | 45 | #define LOCKLOG(level,fmt,...) \ 46 | if (gMutexLogLevel >= LOG_##level) syslog(LOG_##level,"%lu %s %s:%u:%s:lockid=%p " fmt,gettid(),Utils::timestr().c_str(),__FILE__,__LINE__,__FUNCTION__,this,##__VA_ARGS__); 47 | //if (gMutexLogLevel >= LOG_##level) syslog(LOG_##level,"%lu %s %s:%u:%s:lockid=%p " fmt,(unsigned long)pthread_self(),Utils::timestr().c_str(),__FILE__,__LINE__,__FUNCTION__,this,##__VA_ARGS__); 48 | //printf("%u %s %s:%u:%s:lockid=%u " fmt "\n",(unsigned)pthread_self(),Utils::timestr().c_str(),__FILE__,__LINE__,__FUNCTION__,(unsigned)this,##__VA_ARGS__); 49 | 50 | 51 | 52 | 53 | Mutex gStreamLock; ///< Global lock to control access to cout and cerr. 54 | 55 | void lockCout() 56 | { 57 | gStreamLock.lock(); 58 | Timeval entryTime; 59 | cout << entryTime << " " << pthread_self() << ": "; 60 | } 61 | 62 | 63 | void unlockCout() 64 | { 65 | cout << dec << endl << flush; 66 | gStreamLock.unlock(); 67 | } 68 | 69 | 70 | void lockCerr() 71 | { 72 | gStreamLock.lock(); 73 | Timeval entryTime; 74 | cerr << entryTime << " " << pthread_self() << ": "; 75 | } 76 | 77 | void unlockCerr() 78 | { 79 | cerr << dec << endl << flush; 80 | gStreamLock.unlock(); 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | Mutex::Mutex() : mLockCnt(0) //, mLockerFile(0), mLockerLine(0) 90 | { 91 | memset(mLockerFile,0,sizeof(mLockerFile)); 92 | // Must use getLoggingLevel, not gGetLoggingLevel, to avoid infinite recursion. 93 | bool res; 94 | res = pthread_mutexattr_init(&mAttribs); 95 | assert(!res); 96 | res = pthread_mutexattr_settype(&mAttribs,PTHREAD_MUTEX_RECURSIVE); 97 | assert(!res); 98 | res = pthread_mutex_init(&mMutex,&mAttribs); 99 | assert(!res); 100 | } 101 | 102 | 103 | Mutex::~Mutex() 104 | { 105 | pthread_mutex_destroy(&mMutex); 106 | bool res = pthread_mutexattr_destroy(&mAttribs); 107 | assert(!res); 108 | } 109 | 110 | bool Mutex::trylock(const char *file, unsigned line) 111 | { 112 | if (pthread_mutex_trylock(&mMutex)==0) { 113 | if (mLockCnt >= 0 && mLockCnt < maxLocks) { 114 | mLockerFile[mLockCnt] = file; mLockerLine[mLockCnt] = line; // Now our thread has it locked from here. 115 | } 116 | mLockCnt++; 117 | return true; 118 | } else { 119 | return false; 120 | } 121 | } 122 | 123 | // Returns true if the lock was acquired within the timeout, or false if it timed out. 124 | bool Mutex::timedlock(int msecs) // Wait this long in milli-seconds. 125 | { 126 | Timeval future(msecs); 127 | struct timespec timeout = future.timespec(); 128 | return ETIMEDOUT != pthread_mutex_timedlock(&mMutex, &timeout); 129 | } 130 | 131 | // There is a chance here that the mLockerFile&mLockerLine 132 | // could change while we are printing it if multiple other threads are contending for the lock 133 | // and swapping the lock around while we are in here. 134 | string Mutex::mutext() const 135 | { 136 | string result; 137 | result.reserve(100); 138 | //result += format("lockid=%u lockcnt=%d",(unsigned)this,mLockCnt); 139 | result += format("lockcnt=%d",mLockCnt); 140 | for (int i = 0; i < mLockCnt && i < maxLocks; i++) { 141 | if (mLockerFile[i]) { 142 | result += format(" %s:%u",mLockerFile[i],mLockerLine[i]); 143 | } else { 144 | result += " ?"; 145 | } 146 | } 147 | return result; 148 | } 149 | 150 | // Pat removed 10-1-2014. 151 | //void Mutex::lock() { 152 | // if (lockerFile()) LOCKLOG(DEBUG,"lock unchecked"); 153 | // _lock(); 154 | // mLockCnt++; 155 | //} 156 | 157 | // WARNING: The LOG facility calls lock, so to avoid infinite recursion do not call LOG if file == NULL, 158 | // and the file argument should never be used from the Logger facility. 159 | void Mutex::lock(const char *file, unsigned line) 160 | { 161 | // (pat 10-25-13) Deadlock reporting is now the default behavior so we can detect and report deadlocks at customer sites. 162 | if (file) { 163 | LOCKLOG(DEBUG,"start at %s %u",file,line); 164 | // If we wait more than a second, print an error message. 165 | if (!timedlock(1000)) { 166 | string backtrace = rn_backtrace(); 167 | LOCKLOG(ERR, "Blocked more than one second at %s %u by %s %s",file,line,mutext().c_str(),backtrace.c_str()); 168 | printf("WARNING: %s Blocked more than one second at %s %u by %s %s\n",timestr(4).c_str(),file,line,mutext().c_str(),backtrace.c_str()); 169 | _lock(); // If timedlock failed we are probably now entering deadlock. 170 | } 171 | } else { 172 | //LOCKLOG(DEBUG,"unchecked lock"); 173 | _lock(); 174 | } 175 | if (mLockCnt >= 0 && mLockCnt < maxLocks) { 176 | mLockerFile[mLockCnt] = file; mLockerLine[mLockCnt] = line; // Now our thread has it locked from here. 177 | } 178 | mLockCnt++; 179 | if (file) { LOCKLOG(DEBUG,"lock by %s",mutext().c_str()); } 180 | //else { LOCKLOG(DEBUG,"lock no file"); } 181 | } 182 | 183 | void Mutex::unlock() 184 | { 185 | if (lockerFile()) { LOCKLOG(DEBUG,"unlock at %s",mutext().c_str()); } 186 | //else { LOCKLOG(DEBUG,"unlock unchecked"); } 187 | mLockCnt--; 188 | pthread_mutex_unlock(&mMutex); 189 | } 190 | 191 | RWLock::RWLock() 192 | { 193 | bool res; 194 | res = pthread_rwlockattr_init(&mAttribs); 195 | assert(!res); 196 | res = pthread_rwlock_init(&mRWLock,&mAttribs); 197 | assert(!res); 198 | } 199 | 200 | 201 | RWLock::~RWLock() 202 | { 203 | pthread_rwlock_destroy(&mRWLock); 204 | bool res = pthread_rwlockattr_destroy(&mAttribs); 205 | assert(!res); 206 | } 207 | 208 | void ScopedLockMultiple::_init(int wOwner, Mutex& wA, Mutex&wB, Mutex&wC) { 209 | ownA[0] = wOwner & 1; ownA[1] = wOwner & 2; ownA[2] = wOwner & 4; 210 | mA[0] = &wA; mA[1] = &wB; mA[2] = &wC; 211 | _saveState(); 212 | } 213 | void ScopedLockMultiple::_lock(int which) { 214 | if (state[which]) return; 215 | mA[which]->lock(_file,_line); 216 | state[which] = true; 217 | } 218 | bool ScopedLockMultiple::_trylock(int which) { 219 | if (state[which]) return true; 220 | state[which] = mA[which]->trylock(_file,_line); 221 | return state[which]; 222 | } 223 | void ScopedLockMultiple::_unlock(int which) { 224 | if (state[which]) mA[which]->unlock(); 225 | state[which] = false; 226 | } 227 | void ScopedLockMultiple::_saveState() { 228 | // The caller may enter with mutex locked by the calling thread if the owner bit is set. 229 | for (int i = 0; i <= 2; i++) { 230 | // Test is deceptive because currently the owner bit is an assertion that owner has the bit locked. 231 | // If we dont require that, then how would we know whether the lock was held by the current thread, or by some other thread? 232 | // We would need to add some per-thread storage, and store it in the Mutex during Mutex::lock() or Mutex::trylock(). 233 | state[i] = ownA[i]; // (ownA[i] && mA[i]->lockcnt()); 234 | if (ownA[i]) { if (mA[i]->lockcnt() != 1) printf("mA[%d].lockcnt=%d\n",i,mA[i]->lockcnt()); assert(mA[i]->lockcnt() == 1); } 235 | } 236 | } 237 | void ScopedLockMultiple::_restoreState() { 238 | // Leave state of each lock the way we found it. 239 | for (int i = 0; i <= 2; i++) { 240 | // This is a little redundant because the _lock and _unlock now test state. 241 | if (!ownA[i] && state[i]) _unlock(i); 242 | else if (ownA[i] && ! state[i]) _lock(i); 243 | } 244 | } 245 | void ScopedLockMultiple::_lockAll() { 246 | // Do not return until we have locked all three mutexes. 247 | for (int n=0; true; n++) { 248 | // Attempt to lock in order 0,1,2. 249 | _lock(0); // Wait on 0, unless it was locked by us on entry. 250 | if (_trylock(1) && _trylock(2)) return; // Then try to acquire 1 and 2 251 | _unlock(1); // If failure, release all. 252 | _unlock(0); 253 | // Attempt to lock in order 1,0,2. 254 | _lock(1); 255 | if (_trylock(0) && _trylock(2)) return; 256 | _unlock(0); 257 | _unlock(1); 258 | // Attempt to lock in order 2,1,0. 259 | _lock(2); 260 | if (_trylock(0) && _trylock(1)) return; 261 | _unlock(0); 262 | _unlock(2); 263 | LOCKLOG(DEBUG,"Multiple lock attempt %d",n); // Seeing this message is a hint we are having contention issues. 264 | } 265 | } 266 | 267 | 268 | /** Block for the signal up to the cancellation timeout in msecs. */ 269 | // (pat 8-2013) Our code had places (InterthreadQueue) that passed in negative timeouts which create deadlock. 270 | // To prevent that, use signed, not unsigned timeout. 271 | void Signal::wait(Mutex& wMutex, long timeout) const 272 | { 273 | if (timeout <= 0) { return; } // (pat) Timeout passed already 274 | Timeval then(timeout); 275 | struct timespec waitTime = then.timespec(); 276 | pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime); 277 | } 278 | 279 | struct wrapArgs 280 | { 281 | void *(*task)(void *); 282 | void *arg; 283 | }; 284 | 285 | static void * 286 | thread_main(void *arg) 287 | { 288 | struct wrapArgs *p = (struct wrapArgs *)arg; 289 | void *(*task)(void *) = p->task; 290 | void *param = p->arg; 291 | delete p; 292 | return (*task)(param); 293 | } 294 | 295 | void Thread::start(void *(*task)(void*), void *arg) 296 | { 297 | assert(mThread==((pthread_t)0)); 298 | bool res; 299 | // (pat) Moved initialization to constructor to avoid crash in destructor. 300 | //res = pthread_attr_init(&mAttrib); 301 | //assert(!res); 302 | res = pthread_attr_setstacksize(&mAttrib, mStackSize); 303 | assert(!res); 304 | struct wrapArgs *p = new wrapArgs; 305 | p->task = task; 306 | p->arg = arg; 307 | res = pthread_create(&mThread, &mAttrib, &thread_main, p); 308 | // (pat) Note: the error is returned and is not placed in errno. 309 | if (res) { LOG(ALERT) << "pthread_create failed, error:" <. 23 | 24 | */ 25 | 26 | 27 | #ifndef THREADS_H 28 | #define THREADS_H 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | class Mutex; 37 | 38 | 39 | /**@name Multithreaded access for standard streams. */ 40 | //@{ 41 | 42 | extern int gMutexLogLevel; // The mutexes cannot call gConfig or gGetLoggingLevel so we have to get the log level indirectly. 43 | 44 | /**@name Functions for gStreamLock. */ 45 | //@{ 46 | extern Mutex gStreamLock; ///< global lock for cout and cerr 47 | void lockCerr(); ///< call prior to writing cerr 48 | void unlockCerr(); ///< call after writing cerr 49 | void lockCout(); ///< call prior to writing cout 50 | void unlockCout(); ///< call after writing cout 51 | //@} 52 | 53 | /**@name Macros for standard messages. */ 54 | //@{ 55 | #define COUT(text) { lockCout(); std::cout << text; unlockCout(); } 56 | #define CERR(text) { lockCerr(); std::cerr << __FILE__ << ":" << __LINE__ << ": " << text; unlockCerr(); } 57 | #ifdef NDEBUG 58 | #define DCOUT(text) {} 59 | #define OBJDCOUT(text) {} 60 | #else 61 | #define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); } 62 | #define OBJDCOUT(text) { DCOUT(this << " " << text); } 63 | #endif 64 | //@} 65 | //@} 66 | 67 | 68 | 69 | /**@defgroup C++ wrappers for pthread mechanisms. */ 70 | //@{ 71 | 72 | /** A class for recursive mutexes based on pthread_mutex. */ 73 | // If at all possible, do not call lock/unlock from this class directly; use a ScopedLock instead. 74 | class Mutex { 75 | 76 | private: 77 | 78 | pthread_mutex_t mMutex; 79 | pthread_mutexattr_t mAttribs; 80 | int mLockCnt; 81 | int mMutexLogLevel; // We cant use LOG inside the Mutex because LOG itself uses mutexes, so get the LOG level at mutex creation time 82 | // and use it for this mutex from then on. 83 | 84 | static const int maxLocks = 5; // Just the maximum number of recursive locks we report during debugging, not the max possible. 85 | const char *mLockerFile[maxLocks]; 86 | unsigned mLockerLine[maxLocks]; 87 | const char *lockerFile() { int i = mLockCnt-1; return (i >= 0 && i < maxLocks) ? mLockerFile[i] : NULL; } 88 | //unused: bool anyDebugging() { for (int i = 0; i < maxLocks; i++) { if (mLockerFile[i]) return true; return false; } } 89 | 90 | // pthread_mutex_trylock returns 0 and trylock returns true if the lock was acquired. 91 | public: 92 | bool trylock(const char *file=0, unsigned line=0); 93 | 94 | Mutex(); 95 | 96 | ~Mutex(); 97 | 98 | void _lock() { pthread_mutex_lock(&mMutex); } 99 | 100 | // (pat) Like the above but report blocking; to see report you must set both Log.Level to DEBUG for both Threads.cpp and the file. 101 | void lock(const char *file=0, unsigned line=0); 102 | 103 | std::string mutext() const; 104 | 105 | // Returns true if the lock was acquired, or false if it timed out. 106 | bool timedlock(int msecs); 107 | 108 | void unlock(); 109 | 110 | // (pat) I use this to assert that the Mutex is locked on entry to some method that requres it, but only in debug mode. 111 | int lockcnt() { return mLockCnt; } 112 | 113 | friend class Signal; 114 | 115 | }; 116 | 117 | /** A class for reader/writer based on pthread_rwlock. */ 118 | class RWLock { 119 | 120 | private: 121 | 122 | pthread_rwlock_t mRWLock; 123 | pthread_rwlockattr_t mAttribs; 124 | 125 | public: 126 | 127 | RWLock(); 128 | 129 | ~RWLock(); 130 | 131 | const char * wlock() { pthread_rwlock_wrlock(&mRWLock); return ""; } 132 | const char * rlock() { pthread_rwlock_rdlock(&mRWLock); return ""; } 133 | 134 | bool trywlock() { return pthread_rwlock_trywrlock(&mRWLock)==0; } 135 | bool tryrlock() { return pthread_rwlock_tryrdlock(&mRWLock)==0; } 136 | 137 | const char * unlock() { pthread_rwlock_unlock(&mRWLock); return ""; } 138 | 139 | }; 140 | 141 | 142 | #if 0 143 | // (pat) NOT FINISHED OR TESTED. A pointer that releases a specified mutex when it goes out of scope. 144 | template 145 | class ScopedPointer { 146 | Mutex &mControllingMutex; // A pointer to the mutex for the object being protected. 147 | PointsTo *mPtr; 148 | 149 | public: 150 | ScopedPointer(Mutex& wMutex) :mControllingMutex(wMutex) { mControllingMutex.lock(); } 151 | // Requisite Copy Constructor: The mutex is already locked, but we need to lock it again because the 152 | // other ScopedPointer is about to go out of scope and will call unlock. 153 | ScopedPointer(ScopedPointer &other) :mControllingMutex(other.mControllingMutex) { mControllingMutex.lock(); } 154 | ~ScopedPointer() { mControllingMutex.unlock(); } 155 | 156 | // You are allowed to assign and derference the underlying pointer - it still holds the Mutex locked. 157 | PointsTo *operator->() const { return mPtr; } 158 | PointsTo * operator=(PointsTo *other) { mPtr = other; } 159 | PointsTo& operator*() { return *mPtr; } 160 | }; 161 | #endif 162 | 163 | // Class to acquire a Mutex lock and release it automatically when this goes out of scope. 164 | // ScopedLock should be used preferentially to Mutex::lock() and Mutex::unlock() in case a try-catch throw passes through 165 | // the containing procedure while the lock is held; ScopedLock releases the lock in that case. 166 | // "We dont use try-catch" you say? Yes we do - C++ string and many standard containers use throw to handle unexpected arguments. 167 | class ScopedLock { 168 | Mutex& mMutex; 169 | 170 | public: 171 | ScopedLock(Mutex& wMutex) :mMutex(wMutex) { mMutex.lock(); } 172 | // Like the above but report blocking; to see report you must set both Log.Level to DEBUG for both Threads.cpp and the file. 173 | ScopedLock(Mutex& wMutex,const char *file, unsigned line):mMutex(wMutex) { mMutex.lock(file,line); } 174 | ~ScopedLock() { mMutex.unlock(); } 175 | }; 176 | 177 | // Lock multiple mutexes simultaneously. 178 | class ScopedLockMultiple { 179 | Mutex garbage; // Someplace to point mC if only two mutexes are specified. 180 | Mutex *mA[3]; 181 | bool ownA[3]; // If set, expect mA to be locked by this thread on entry. 182 | bool state[3]; // Current state, true if our thread has locked the associated Mutex; doesnt say if Mutex is locked by other threads. 183 | const char *_file; unsigned _line; 184 | 185 | void _lock(int which); 186 | bool _trylock(int which); 187 | void _unlock(int which); 188 | void _saveState(); 189 | void _restoreState(); 190 | void _lockAll(); 191 | void _init(int wOwner, Mutex& wA, Mutex&wB, Mutex&wCa); 192 | 193 | public: 194 | 195 | // Do not return until all three mutexes are locked. 196 | // On entry, the caller may optionally already have locked mutexes, as specified by the wOwner flag bits. 197 | // If owner&1, caller owns wA, if owner&2 caller owns wB, if owner&4 caller owns wC. 198 | // There wouldnt be much point of this class if the caller already owned all three mutexes. 199 | // Note that the mutexes may be temporarily surrendered during this call as the methodology to avoid deadlock, 200 | // but in that case all will be re-acquired before this returns. 201 | 202 | ScopedLockMultiple(int wOwner, Mutex&wA, Mutex&wB, Mutex&wC) : _file(NULL), _line(0) { 203 | _init(wOwner,wA,wB,wC); 204 | _lockAll(); 205 | } 206 | // Like the above but report blocking; to see report you must set both Log.Level to DEBUG for both Threads.cpp and the file. 207 | // Use like this: ScopedLockMultiple lock(bits,mutexa,mutexb,__FILE__,__LINE__); 208 | ScopedLockMultiple(int wOwner, Mutex&wA, Mutex&wB, Mutex&wC, const char *wFile, int wLine) : _file(wFile), _line(wLine) { 209 | _init(wOwner,wA,wB,wC); 210 | _lockAll(); 211 | } 212 | 213 | // Like the above but for two mutexes intead of three. 214 | ScopedLockMultiple(int wOwner, Mutex& wA, Mutex&wB) : _file(NULL), _line(0) { 215 | _init(wOwner,wA,wB,garbage); 216 | _lockAll(); 217 | } 218 | ScopedLockMultiple(int wOwner, Mutex&wA, Mutex&wB, const char *wFile, int wLine) : _file(wFile), _line(wLine) { 219 | _init(wOwner,wA,wB,garbage); 220 | _lockAll(); 221 | } 222 | ~ScopedLockMultiple() { _restoreState(); } 223 | }; 224 | 225 | 226 | 227 | 228 | /** A C++ interthread signal based on pthread condition variables. */ 229 | class Signal { 230 | 231 | private: 232 | 233 | mutable pthread_cond_t mSignal; 234 | 235 | public: 236 | 237 | Signal() { int s = pthread_cond_init(&mSignal,NULL); assert(!s); } 238 | 239 | ~Signal() { pthread_cond_destroy(&mSignal); } 240 | 241 | /** 242 | Block for the signal up to the cancellation timeout. 243 | Under Linux, spurious returns are possible. 244 | */ 245 | void wait(Mutex& wMutex, long timeout) const; 246 | 247 | /** 248 | Block for the signal. 249 | Under Linux, spurious returns are possible. 250 | */ 251 | void wait(Mutex& wMutex) const 252 | { pthread_cond_wait(&mSignal,&wMutex.mMutex); } 253 | 254 | void signal() { pthread_cond_signal(&mSignal); } 255 | 256 | void broadcast() { pthread_cond_broadcast(&mSignal); } 257 | 258 | }; 259 | 260 | 261 | 262 | #define START_THREAD(thread,function,argument) \ 263 | thread.start((void *(*)(void*))function, (void*)argument); 264 | 265 | /** A C++ wrapper for pthread threads. */ 266 | class Thread { 267 | 268 | private: 269 | 270 | pthread_t mThread; 271 | pthread_attr_t mAttrib; 272 | // FIXME -- Can this be reduced now? 273 | size_t mStackSize; 274 | 275 | 276 | public: 277 | // (pat) This is the type of the function argument to pthread_create. 278 | typedef void *(*Task_t)(void*); 279 | 280 | /** Create a thread in a non-running state. */ 281 | Thread(size_t wStackSize = (65536*4)):mThread((pthread_t)0) { 282 | pthread_attr_init(&mAttrib); // (pat) moved this here. 283 | mStackSize=wStackSize; 284 | } 285 | 286 | /** 287 | Destroy the Thread. 288 | It should be stopped and joined. 289 | */ 290 | // (pat) If the Thread is destroyed without being started, then mAttrib is undefined. Oops. 291 | ~Thread() { pthread_attr_destroy(&mAttrib); } 292 | 293 | 294 | /** Start the thread on a task. */ 295 | void start(Task_t task, void *arg); 296 | void start2(Task_t task, void *arg, int stacksize); 297 | 298 | /** Join a thread that will stop on its own. */ 299 | void join() { int s = pthread_join(mThread,NULL); assert(!s); mThread = 0; } 300 | 301 | }; 302 | 303 | 304 | 305 | 306 | #endif 307 | // vim: ts=4 sw=4 308 | -------------------------------------------------------------------------------- /BitVector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008, 2009, 2014 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * 6 | * This software is distributed under the terms of the GNU Affero Public License. 7 | * See the COPYING file in the main directory for details. 8 | * 9 | * This use of this software may be subject to additional restrictions. 10 | * See the LEGAL file in the main directory for details. 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU Affero General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU Affero General Public License for more details. 21 | 22 | You should have received a copy of the GNU Affero General Public License 23 | along with this program. If not, see . 24 | 25 | */ 26 | 27 | 28 | 29 | 30 | #include "BitVector.h" 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | using namespace std; 38 | 39 | 40 | 41 | BitVector::BitVector(const char *valString) 42 | { 43 | // 1-30-2013 pat: I dont know what this was intended to do, but it did not create a normalized BitVector, 44 | // and it could even fail if the accum overlows 8 bits. 45 | //uint32_t accum = 0; 46 | //for (size_t i=0; i=0; i--) { 79 | accum = (accum<<1) | ((*dp--) & 0x01); 80 | } 81 | return accum; 82 | } 83 | 84 | 85 | 86 | 87 | uint64_t BitVector::readField(size_t& readIndex, unsigned length) const 88 | { 89 | const uint64_t retVal = peekField(readIndex,length); 90 | readIndex += length; 91 | return retVal; 92 | } 93 | 94 | 95 | uint64_t BitVector::readFieldReversed(size_t& readIndex, unsigned length) const 96 | { 97 | 98 | const uint64_t retVal = peekFieldReversed(readIndex,length); 99 | readIndex += length; 100 | return retVal; 101 | 102 | } 103 | 104 | 105 | 106 | 107 | void BitVector::fillField(size_t writeIndex, uint64_t value, unsigned length) 108 | { 109 | if (length != 0) { 110 | char *dpBase = mStart + writeIndex; 111 | char *dp = dpBase + length - 1; 112 | assert(dp < mEnd); 113 | while (dp>=dpBase) { 114 | *dp-- = value & 0x01; 115 | value >>= 1; 116 | } 117 | } 118 | } 119 | 120 | 121 | void BitVector::fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length) 122 | { 123 | if (length != 0) { 124 | char *dp = mStart + writeIndex; 125 | char *dpEnd = dp + length - 1; 126 | assert(dpEnd < mEnd); 127 | while (dp<=dpEnd) { 128 | *dp++ = value & 0x01; 129 | value >>= 1; 130 | } 131 | } 132 | } 133 | 134 | 135 | 136 | 137 | void BitVector::writeField(size_t& writeIndex, uint64_t value, unsigned length) 138 | { 139 | if (length != 0) { 140 | fillField(writeIndex,value,length); 141 | writeIndex += length; 142 | } 143 | } 144 | 145 | 146 | void BitVector::writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length) 147 | { 148 | if (length != 0) { 149 | fillFieldReversed(writeIndex,value,length); 150 | writeIndex += length; 151 | } 152 | } 153 | 154 | 155 | void BitVector::invert() 156 | { 157 | for (size_t i=0; i=8); 168 | 169 | char tmp0 = mStart[0]; 170 | mStart[0] = mStart[7]; 171 | mStart[7] = tmp0; 172 | 173 | char tmp1 = mStart[1]; 174 | mStart[1] = mStart[6]; 175 | mStart[6] = tmp1; 176 | 177 | char tmp2 = mStart[2]; 178 | mStart[2] = mStart[5]; 179 | mStart[5] = tmp2; 180 | 181 | char tmp3 = mStart[3]; 182 | mStart[3] = mStart[4]; 183 | mStart[4] = tmp3; 184 | } 185 | 186 | 187 | 188 | void BitVector::LSB8MSB() 189 | { 190 | if (size()<8) return; 191 | size_t size8 = 8*(size()/8); 192 | size_t iTop = size8 - 8; 193 | for (size_t i=0; i<=iTop; i+=8) segment(i,8).reverse8(); 194 | } 195 | 196 | 197 | 198 | uint64_t BitVector::syndrome(Generator& gen) const 199 | { 200 | gen.clear(); 201 | const char *dp = mStart; 202 | while (dp0.5F) newSig[i]=1; 298 | else newSig[i] = 0; 299 | } 300 | return newSig; 301 | } 302 | 303 | 304 | 305 | // (pat) Added 6-22-2012 306 | float SoftVector::getEnergy(float *plow) const 307 | { 308 | const SoftVector &vec = *this; 309 | int len = vec.size(); 310 | float avg = 0; float low = 1; 311 | for (int i = 0; i < len; i++) { 312 | float bit = vec[i]; 313 | float energy = 2*((bit < 0.5) ? (0.5-bit) : (bit-0.5)); 314 | if (energy < low) low = energy; 315 | avg += energy/len; 316 | } 317 | if (plow) { *plow = low; } 318 | return avg; 319 | } 320 | 321 | // (pat) Added 1-2014. Compute SNR of a soft vector. Very similar to above. 322 | // Since we dont really know what the expected signal values are, we will assume that the signal is 0 or 1 323 | // and return the SNR on that basis. 324 | // SNR is power(signal) / power(noise) where power can be calculated as (RMS(signal) / RMS(noise))**2 of the values. 325 | // Since RMS is square-rooted, ie RMS = sqrt(1/n * (x1**2 + x2**2 ...)), we just add up the squares. 326 | // To compute RMS of the signal we will remove any constant offset, so the signal values are either 0.5 or -0.5, 327 | // so the RMS of the signal is just 0.5**2 * len; all we need to compute is the noise component. 328 | float SoftVector::getSNR() const 329 | { 330 | float sumSquaresNoise = 0; 331 | const SoftVector &vec = *this; 332 | int len = vec.size(); 333 | if (len == 0) { return 0.0; } 334 | for (int i = 0; i < len; i++) { 335 | float bit = vec[i]; 336 | if (bit < 0.5) { 337 | // Assume signal is 0. 338 | sumSquaresNoise += (bit - 0.0) * (bit - 0.0); 339 | } else { 340 | // Assume signal is 1. 341 | sumSquaresNoise += (bit - 1.0) * (bit - 1.0); 342 | } 343 | } 344 | float sumSquaresSignal = 0.5 * 0.5 * len; 345 | // I really want log10 of this to convert to dB, but log is expensive, and Harvind seems to like absolute SNR. 346 | // Clamp max to 999; it shouldnt get up there but be sure. This also avoids divide by zero. 347 | if (sumSquaresNoise * 1000 < sumSquaresSignal) return 999; 348 | return sumSquaresSignal / sumSquaresNoise; 349 | } 350 | 351 | 352 | 353 | ostream& operator<<(ostream& os, const SoftVector& sv) 354 | { 355 | for (size_t i=0; i0.75) os << "1"; 358 | else os << "-"; 359 | } 360 | return os; 361 | } 362 | 363 | 364 | 365 | void BitVector::pack(unsigned char* targ) const 366 | { 367 | // Assumes MSB-first packing. 368 | unsigned bytes = size()/8; 369 | for (unsigned i=0; ipack(result.c_str()) but technically c_str() is read-only. 383 | unsigned bytes = size()/8; 384 | for (unsigned i=0; i> (8-rem),rem); 406 | } 407 | 408 | void BitVector::hex(ostream& os) const 409 | { 410 | os << std::hex; 411 | unsigned digits = size()/4; 412 | size_t wp=0; 413 | for (unsigned i=0; i0) { 441 | if (sscanf(src+digits, "%1x", &val) < 1) { 442 | return false; 443 | } 444 | fillField(whole,val,rem); 445 | } 446 | return true; 447 | } 448 | 449 | bool BitVector::operator==(const BitVector &other) const 450 | { 451 | unsigned l = size(); 452 | return l == other.size() && 0==memcmp(begin(),other.begin(),l); 453 | } 454 | 455 | void BitVector::copyPunctured(BitVector &dst, const unsigned *puncture, const size_t plth) 456 | { 457 | assert(size() - plth == dst.size()); 458 | char *srcp = mStart; 459 | char *dstp = dst.mStart; 460 | const unsigned *pend = puncture + plth; 461 | while (srcp < mEnd) { 462 | if (puncture < pend) { 463 | int n = (*puncture++) - (srcp - mStart); 464 | assert(n >= 0); 465 | for (int i = 0; i < n; i++) { 466 | assert(srcp < mEnd && dstp < dst.mEnd); 467 | *dstp++ = *srcp++; 468 | } 469 | srcp++; 470 | } else { 471 | while (srcp < mEnd) { 472 | assert(dstp < dst.mEnd); 473 | *dstp++ = *srcp++; 474 | } 475 | } 476 | } 477 | assert(dstp == dst.mEnd && puncture == pend); 478 | } 479 | 480 | void SoftVector::copyUnPunctured(SoftVector &dst, const unsigned *puncture, const size_t plth) 481 | { 482 | assert(size() + plth == dst.size()); 483 | float *srcp = mStart; 484 | float *dstp = dst.mStart; 485 | const unsigned *pend = puncture + plth; 486 | while (dstp < dst.mEnd) { 487 | if (puncture < pend) { 488 | int n = (*puncture++) - (dstp - dst.mStart); 489 | assert(n >= 0); 490 | for (int i = 0; i < n; i++) { 491 | assert(srcp < mEnd && dstp < dst.mEnd); 492 | *dstp++ = *srcp++; 493 | } 494 | *dstp++ = 0.5; 495 | } else { 496 | while (srcp < mEnd) { 497 | assert(dstp < dst.mEnd); 498 | *dstp++ = *srcp++; 499 | } 500 | } 501 | } 502 | assert(dstp == dst.mEnd && puncture == pend); 503 | } 504 | 505 | // vim: ts=4 sw=4 506 | -------------------------------------------------------------------------------- /BitVector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008, 2009, 2014 Free Software Foundation, Inc. 3 | * Copyright 2014 Range Networks, Inc. 4 | * 5 | * This software is distributed under the terms of the GNU Affero Public License. 6 | * See the COPYING file in the main directory for details. 7 | * 8 | * This use of this software may be subject to additional restrictions. 9 | * See the LEGAL file in the main directory for details. 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU Affero General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU Affero General Public License for more details. 20 | 21 | You should have received a copy of the GNU Affero General Public License 22 | along with this program. If not, see . 23 | 24 | */ 25 | 26 | 27 | #ifndef BITVECTORS_H 28 | #define BITVECTORS_H 29 | 30 | #include "Vector.h" 31 | #include 32 | #include 33 | 34 | 35 | class BitVector; 36 | class SoftVector; 37 | 38 | 39 | 40 | 41 | /** Shift-register (LFSR) generator. */ 42 | class Generator { 43 | 44 | private: 45 | 46 | uint64_t mCoeff; ///< polynomial coefficients. LSB is zero exponent. 47 | uint64_t mState; ///< shift register state. LSB is most recent. 48 | uint64_t mMask; ///< mask for reading state 49 | unsigned mLen; ///< number of bits used in shift register 50 | unsigned mLen_1; ///< mLen - 1 51 | 52 | public: 53 | 54 | Generator(uint64_t wCoeff, unsigned wLen) 55 | :mCoeff(wCoeff),mState(0), 56 | mMask((1ULL<>(mLen_1)) & 0x01; 75 | mState = (mState<<1) ^ (inBit & 0x01); 76 | if (fb) mState ^= mCoeff; 77 | } 78 | 79 | /** 80 | Update the generator state by one cycle. 81 | This is in the .h for inlining. 82 | */ 83 | void encoderShift(unsigned inBit) 84 | { 85 | const unsigned fb = ((mState>>(mLen_1)) ^ inBit) & 0x01; 86 | mState <<= 1; 87 | if (fb) mState ^= mCoeff; 88 | } 89 | 90 | 91 | }; 92 | 93 | 94 | 95 | 96 | /** Parity (CRC-type) generator and checker based on a Generator. */ 97 | class Parity : public Generator { 98 | 99 | protected: 100 | 101 | unsigned mCodewordSize; 102 | 103 | public: 104 | 105 | Parity(uint64_t wCoefficients, unsigned wParitySize, unsigned wCodewordSize) 106 | :Generator(wCoefficients, wParitySize), 107 | mCodewordSize(wCodewordSize) 108 | { } 109 | 110 | /** Compute the parity word and write it into the target segment. */ 111 | void writeParityWord(const BitVector& data, BitVector& parityWordTarget, bool invert=true); 112 | 113 | /** Compute the syndrome of a received sequence. */ 114 | uint64_t syndrome(const BitVector& receivedCodeword); 115 | }; 116 | 117 | 118 | // (pat) Nov 2013. I rationalized the behavior of BitVector and added assertions to core dump code 119 | // that relied on the bad aspects of the original behavior. See comments at VectorBase. 120 | class BitVector : public VectorBase 121 | { 122 | public: 123 | /**@name Constructors. */ 124 | //@{ 125 | 126 | /**@name Casts of Vector constructors. */ 127 | BitVector(VectorDataType wData, char* wStart, char* wEnd) : VectorBase(wData, wStart, wEnd) {} 128 | 129 | // The one and only copy-constructor. 130 | BitVector(const BitVector&other) : VectorBase() { 131 | VECTORDEBUG("BitVector(%p)",(void*)&other); 132 | if (other.getData()) { 133 | this->clone(other); 134 | } else { 135 | this->makeAlias(other); 136 | } 137 | } 138 | 139 | // (pat) Removed default value for len and added 'explicit'. Please do not remove 'explicit'; 140 | // it prevents auto-conversion of int to BitVector in constructors. 141 | // Previous code was often ambiguous, especially for L3Frame and descendent constructors, leading to latent bugs. 142 | explicit BitVector(size_t len) { this->vInit(len); } 143 | BitVector() { this->vInit(0); } 144 | 145 | /** Build a BitVector by concatenation. */ 146 | BitVector(const BitVector& other1, const BitVector& other2) : VectorBase() 147 | { 148 | assert(this->getData() == 0); 149 | this->vConcat(other1,other2); 150 | } 151 | 152 | /** Construct from a string of "0" and "1". */ 153 | // (pat) Characters that are not '0' or '1' map to '0'. 154 | BitVector(const char* valString); 155 | //@} 156 | 157 | /**@name Casts and overrides of Vector operators. */ 158 | //@{ 159 | // (pat) Please DO NOT add a const anywhere in this method. Use cloneSegment instead. 160 | BitVector segment(size_t start, size_t span) 161 | { 162 | char* wStart = this->begin() + start; 163 | char* wEnd = wStart + span; 164 | assert(wEnd<=this->end()); 165 | #if BITVECTOR_REFCNTS 166 | return BitVector(mData,wStart,wEnd); 167 | #else 168 | return BitVector(NULL,wStart,wEnd); 169 | #endif 170 | } 171 | 172 | // (pat) Historically the BitVector segment method had const and non-const versions with different behavior. 173 | // I changed the name of the const version to cloneSegment and replaced all uses throughout OpenBTS. 174 | const BitVector cloneSegment(size_t start, size_t span) const 175 | { 176 | BitVector seg = const_cast(this)->segment(start,span); 177 | // (pat) We are depending on the Return Value Optimization not to invoke the copy-constructor on the result, 178 | // which would result in its immediate destruction while we are still using it. 179 | BitVector result; 180 | result.clone(seg); 181 | return result; 182 | } 183 | 184 | BitVector alias() const { 185 | return const_cast(this)->segment(0,size()); 186 | } 187 | 188 | BitVector head(size_t span) { return segment(0,span); } 189 | BitVector tail(size_t start) { return segment(start,size()-start); } 190 | 191 | // (pat) Please do NOT put the const version of head and tail back in, because historically they were messed up. 192 | // Use cloneSegment instead. 193 | //const BitVector head(size_t span) const { return segment(0,span); } 194 | //const BitVector tail(size_t start) const { return segment(start,size()-start); } 195 | //@} 196 | 197 | 198 | void zero() { fill(0); } 199 | 200 | /**@name FEC operations. */ 201 | //@{ 202 | /** Calculate the syndrome of the vector with the given Generator. */ 203 | uint64_t syndrome(Generator& gen) const; 204 | /** Calculate the parity word for the vector with the given Generator. */ 205 | uint64_t parity(Generator& gen) const; 206 | //@} 207 | 208 | 209 | /** Invert 0<->1. */ 210 | void invert(); 211 | 212 | /**@name Byte-wise operations. */ 213 | //@{ 214 | /** Reverse an 8-bit vector. */ 215 | void reverse8(); 216 | /** Reverse groups of 8 within the vector (byte reversal). */ 217 | void LSB8MSB(); 218 | //@} 219 | 220 | /**@name Serialization and deserialization. */ 221 | //@{ 222 | uint64_t peekField(size_t readIndex, unsigned length) const; 223 | uint64_t peekFieldReversed(size_t readIndex, unsigned length) const; 224 | uint64_t readField(size_t& readIndex, unsigned length) const; 225 | uint64_t readFieldReversed(size_t& readIndex, unsigned length) const; 226 | void fillField(size_t writeIndex, uint64_t value, unsigned length); 227 | void fillFieldReversed(size_t writeIndex, uint64_t value, unsigned length); 228 | void writeField(size_t& writeIndex, uint64_t value, unsigned length); 229 | void writeFieldReversed(size_t& writeIndex, uint64_t value, unsigned length); 230 | void write0(size_t& writeIndex) { writeField(writeIndex,0,1); } 231 | void write1(size_t& writeIndex) { writeField(writeIndex,1,1); } 232 | 233 | //@} 234 | 235 | /** Sum of bits. */ 236 | unsigned sum() const; 237 | 238 | /** Reorder bits, dest[i] = this[map[i]]. */ 239 | void map(const unsigned *map, size_t mapSize, BitVector& dest) const; 240 | 241 | /** Reorder bits, dest[map[i]] = this[i]. */ 242 | void unmap(const unsigned *map, size_t mapSize, BitVector& dest) const; 243 | 244 | /** Pack into a char array. */ 245 | void pack(unsigned char*) const; 246 | // Same as pack but return a string. 247 | std::string packToString() const; 248 | 249 | /** Unpack from a char array. */ 250 | void unpack(const unsigned char*); 251 | 252 | /** Make a hexdump string. */ 253 | void hex(std::ostream&) const; 254 | std::string hexstr() const; 255 | 256 | /** Unpack from a hexdump string. 257 | * @returns true on success, false on error. */ 258 | bool unhex(const char*); 259 | 260 | // For this method, 'other' should have been run through the copy-constructor already 261 | // (unless it was newly created, ie foo.dup(L2Frame(...)), in which case we are screwed anyway) 262 | // so the call to makeAlias is redundant. 263 | // This only works if other is already an alias. 264 | void dup(BitVector other) { assert(!this->getData()); makeAlias(other); assert(this->mStart == other.mStart); } 265 | void dup(BitVector &other) { makeAlias(other); assert(this->mStart == other.mStart); } 266 | 267 | #if 0 268 | void operator=(const BitVector& other) { 269 | printf("BitVector::operator=\n"); 270 | assert(0); 271 | //this->dup(other); 272 | } 273 | #endif 274 | 275 | bool operator==(const BitVector &other) const; 276 | 277 | /** Copy to dst, not including those indexed in puncture. */ 278 | void copyPunctured(BitVector &dst, const unsigned *puncture, const size_t plth); 279 | 280 | /** Index a single bit. */ 281 | // (pat) Cant have too many ways to do this, I guess. 282 | bool bit(size_t index) const 283 | { 284 | // We put this code in .h for fast inlining. 285 | const char *dp = this->begin()+index; 286 | assert(dpend()); 287 | return (*dp) & 0x01; 288 | } 289 | 290 | char& operator[](size_t index) 291 | { 292 | assert(this->mStart+indexmEnd); 293 | return this->mStart[index]; 294 | } 295 | 296 | const char& operator[](size_t index) const 297 | { 298 | assert(this->mStart+indexmEnd); 299 | return this->mStart[index]; 300 | } 301 | 302 | /** Set a bit */ 303 | void settfb(size_t index, int value) 304 | { 305 | char *dp = this->mStart+index; 306 | assert(dpmEnd); 307 | *dp = value; 308 | } 309 | 310 | typedef char* iterator; 311 | typedef const char* const_iterator; 312 | }; 313 | 314 | // (pat) BitVector2 was an intermediate step in fixing BitVector but is no longer needed. 315 | #define BitVector2 BitVector 316 | 317 | 318 | std::ostream& operator<<(std::ostream&, const BitVector&); 319 | 320 | 321 | 322 | 323 | 324 | 325 | /** 326 | The SoftVector class is used to represent a soft-decision signal. 327 | Values 0..1 represent probabilities that a bit is "true". 328 | */ 329 | class SoftVector: public Vector { 330 | 331 | public: 332 | 333 | /** Build a SoftVector of a given length. */ 334 | SoftVector(size_t wSize=0):Vector(wSize) {} 335 | 336 | /** Construct a SoftVector from a C string of "0", "1", and "X". */ 337 | SoftVector(const char* valString); 338 | 339 | /** Construct a SoftVector from a BitVector. */ 340 | SoftVector(const BitVector& source); 341 | 342 | /** 343 | Wrap a SoftVector around a block of floats. 344 | The block will be delete[]ed upon desctuction. 345 | */ 346 | SoftVector(float *wData, unsigned length) 347 | :Vector(wData,length) 348 | {} 349 | 350 | SoftVector(float* wData, float* wStart, float* wEnd) 351 | :Vector(wData,wStart,wEnd) 352 | { } 353 | 354 | /** 355 | Casting from a Vector. 356 | Note that this is NOT pass-by-reference. 357 | */ 358 | SoftVector(Vector source) 359 | :Vector(source) 360 | {} 361 | 362 | 363 | /**@name Casts and overrides of Vector operators. */ 364 | //@{ 365 | SoftVector segment(size_t start, size_t span) 366 | { 367 | float* wStart = mStart + start; 368 | float* wEnd = wStart + span; 369 | assert(wEnd<=mEnd); 370 | return SoftVector(NULL,wStart,wEnd); 371 | } 372 | 373 | SoftVector alias() 374 | { return segment(0,size()); } 375 | 376 | const SoftVector segment(size_t start, size_t span) const 377 | { return (SoftVector)(Vector::segment(start,span)); } 378 | 379 | SoftVector head(size_t span) { return segment(0,span); } 380 | const SoftVector head(size_t span) const { return segment(0,span); } 381 | SoftVector tail(size_t start) { return segment(start,size()-start); } 382 | const SoftVector tail(size_t start) const { return segment(start,size()-start); } 383 | //@} 384 | 385 | // (pat) How good is the SoftVector in the sense of the bits being solid? 386 | // Result of 1 is perfect and 0 means all the bits were 0.5 387 | // If plow is non-NULL, also return the lowest energy bit. 388 | float getEnergy(float *low=0) const; 389 | float getSNR() const; 390 | 391 | /** Fill with "unknown" values. */ 392 | void unknown() { fill(0.5F); } 393 | 394 | /** Return a hard bit value from a given index by slicing. */ 395 | bool bit(size_t index) const 396 | { 397 | const float *dp = mStart+index; 398 | assert(dp0.5F; 400 | } 401 | 402 | /** Slice the whole signal into bits. */ 403 | BitVector sliced() const; 404 | 405 | /** Copy to dst, adding in 0.5 for those indexed in puncture. */ 406 | void copyUnPunctured(SoftVector &dst, const unsigned *puncture, const size_t plth); 407 | 408 | /** Return a soft bit. */ 409 | float softbit(size_t index) const 410 | { 411 | const float *dp = mStart+index; 412 | assert(dp 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include // for sqrtf 25 | #include 26 | #include "Logger.h" 27 | 28 | 29 | namespace Utils { 30 | using namespace std; 31 | 32 | extern double timef(); // high resolution time 33 | // We dont use a default arg here timestr(unsigned fieldwidth=12) because g++ complains about duplicate decl in Logger.h 34 | extern const std::string timestr(); // A timestamp to print in messages. 35 | extern const std::string timestr(unsigned fieldwidth, bool addDate = false); // A timestamp to print in messages. 36 | extern void sleepf(double howlong); // high resolution sleep 37 | extern int gcd(int x, int y); 38 | 39 | string format(const char *fmt, ...) __attribute__((format (printf,1,2))); 40 | 41 | // format1 used to prevent C++ confusion over what function to call here. 42 | string format1(const char *fmt, ...) __attribute__((format (printf,1,2))); 43 | // We have to enumerate the cross product of argument types here. This is fixed in C++11. 44 | inline string format(const char *fmt, string s1) { 45 | return format1(fmt,s1.c_str()); 46 | } 47 | inline string format(const char *fmt, string s1, string s2) { 48 | return format1(fmt,s1.c_str(),s2.c_str()); 49 | } 50 | inline string format(const char *fmt, string s1, string s2, string s3) { 51 | return format1(fmt,s1.c_str(),s2.c_str(),s3.c_str()); 52 | } 53 | inline string format(const char *fmt, string s1, string s2, string s3, string s4) { 54 | return format1(fmt,s1.c_str(),s2.c_str(),s3.c_str(),s4.c_str()); 55 | } 56 | inline string format(const char *fmt, string s1, int i1) { 57 | return format1(fmt,s1.c_str(),i1); 58 | } 59 | inline string format(const char *fmt, int i1, string s1) { 60 | return format1(fmt,i1,s1.c_str()); 61 | } 62 | inline string format(const char *fmt, string s1, string s2, int i1) { 63 | return format1(fmt,s1.c_str(),s2.c_str(),i1); 64 | } 65 | inline string format(const char *fmt, string s1, string s2, int i1, int i2) { 66 | return format1(fmt,s1.c_str(),s2.c_str(),i1,i2); 67 | } 68 | 69 | int myscanf(const char *str, const char *fmt, string *s1); 70 | int myscanf(const char *str, const char *fmt, string *s1, string *s2); 71 | int myscanf(const char *str, const char *fmt, string *s1, string *s2, string *s3); 72 | int myscanf(const char *str, const char *fmt, string *s1, string *s2, string *s3, string *s4); 73 | 74 | int cstrSplit(char *in, char **pargv,int maxargc, const char *splitchars=NULL); 75 | char *cstrGetArg(const char *in, int nth, unsigned *length); 76 | 77 | // For classes with a text() function, provide a function to return a String, 78 | // and also a standard << stream function that takes a pointer to the object. 79 | // We dont provide the function that takes a reference to the object 80 | // because it is too highly overloaded and generally doesnt work. 81 | class Text2Str { 82 | public: 83 | virtual void text(std::ostream &os) const = 0; 84 | std::string str() const; 85 | }; 86 | std::ostream& operator<<(std::ostream& os, const Text2Str *val); 87 | 88 | #if 0 89 | // Generic Activity Timer. Lots of controls to make everybody happy. 90 | class ATimer { 91 | double mStart; 92 | //bool mActive; 93 | double mLimitTime; 94 | public: 95 | ATimer() : mStart(0), mLimitTime(0) { } 96 | ATimer(double wLimitTime) : mStart(0), mLimitTime(wLimitTime) { } 97 | void start() { mStart=timef(); } 98 | void stop() { mStart=0; } 99 | bool active() { return !!mStart; } 100 | double elapsed() { return timef() - mStart; } 101 | bool expired() { return elapsed() > mLimitTime; } 102 | }; 103 | #endif 104 | 105 | 106 | struct BitSet { 107 | unsigned mBits; 108 | void setBit(unsigned whichbit) { mBits |= 1< struct Statistic { 119 | Type mCurrent, mMin, mMax; // min,max optional initialization so you can print before adding any values. 120 | unsigned mCnt; 121 | double mSum; 122 | //double mSum2; // sum of squares. 123 | // (Type) cast needed in case Type is an enum, stupid language. 124 | Statistic() : mCurrent((Type)0), mMin((Type)0), mMax((Type)0), mCnt(0), mSum(0) /*,mSum2(0)*/ {} 125 | // Set the current value and add a statisical point. 126 | void addPoint(Type val) { 127 | mCurrent = val; 128 | if (mCnt == 0 || val < mMin) {mMin = val;} 129 | if (mCnt == 0 || val > mMax) {mMax = val;} 130 | mCnt++; 131 | mSum += val; 132 | //mSum2 += val * val; 133 | } 134 | Type getCurrent() const { // Return current value. 135 | return mCnt ? mCurrent : 0; 136 | } 137 | double getAvg() const { // Return average. 138 | return mCnt==0 ? 0 : mSum/mCnt; 139 | }; 140 | //float getSD() const { // Return standard deviation. Use low precision square root function. 141 | // return mCnt==0 ? 0 : sqrtf(mCnt * mSum2 - mSum*mSum) / mCnt; 142 | //} 143 | 144 | void text(std::ostream &os) const { // Print everything in parens. 145 | os << "("< &stat); 169 | std::ostream& operator<<(std::ostream& os, const Statistic &stat); 170 | std::ostream& operator<<(std::ostream& os, const Statistic &stat); 171 | std::ostream& operator<<(std::ostream& os, const Statistic &stat); 172 | 173 | 174 | // Yes, they botched and left this out: 175 | std::ostream& operator<<(std::ostream& os, std::ostringstream& ss); 176 | 177 | std::ostream &osprintf(std::ostream &os, const char *fmt, ...) __attribute__((format (printf,2,3))); 178 | 179 | std::string replaceAll(const std::string input, const std::string search, const std::string replace); 180 | 181 | vector& stringSplit(vector &result,const char *input); 182 | typedef vector > prettyTable_t; 183 | void printPrettyTable(prettyTable_t &tab, ostream&os, bool tabSeparated = false); 184 | 185 | // The need for this is eliminated in C++11. 186 | string stringcat(string a, string b); 187 | string stringcat(string a, string b, string c); 188 | string stringcat(string a, string b, string c, string d); 189 | string stringcat(string a, string b, string c, string d, string e); 190 | string stringcat(string a, string b, string c, string d, string e, string f); 191 | string stringcat(string a, string b, string c, string d, string e, string f, string g); 192 | 193 | extern void stringToUint(string strRAND, uint64_t *hRAND, uint64_t *lRAND); 194 | extern string uintToString(uint64_t h, uint64_t l); 195 | extern string uintToString(uint32_t x); 196 | 197 | //template class RefCntPointer; 198 | // The class is created with a RefCnt of 0. The caller may assign the constructed result to a pointer 199 | // of type RefCntPointer. If so, then when the last RefCntPointer is freed, this struct is too. 200 | class RefCntBase { 201 | template friend class RefCntPointer; 202 | mutable Mutex mRefMutex; 203 | mutable short mRefCnt; // signed, not unsigned! 204 | int setRefCnt(int val) { return mRefCnt = val; } 205 | // The semantics of reference counting mean you cannot copy an object that has reference counts; 206 | // they are only manipulated by pointers. This constructor is private, which makes C++ whine if you do this. 207 | // Actually, you could copy it, if the refcnt in the new object were 0 and the pointer was assigned to a RefCntPointer. 208 | RefCntBase(RefCntBase &) { assert(0); } 209 | RefCntBase(const RefCntBase &) { assert(0); } 210 | RefCntBase operator=(RefCntBase &) {assert(0); mRefCnt = 0; return *this; } 211 | // These are not 'const' but wonderful C++ requires us to declare them const so we can use a const pointer as the RefCntPointer target, 212 | // then add 'mutable' to everything. What a botched up language. 213 | int decRefCnt() const; // Only RefCntPointer is permitted to use incRefCnt and decRefCnt. 214 | void incRefCnt() const; 215 | public: 216 | virtual ~RefCntBase(); 217 | RefCntBase() : mRefCnt(0) {} 218 | int getRefCnt() const { return mRefCnt; } 219 | }; 220 | 221 | // This is basically the same as a C++11 shared_ptr, but we cannot use C++ 11 yet. 222 | // The basic idea is that once you put an object into a RefCntPointer, then destruction of that 223 | // object is controlled by and assured by RefCntPointer using reference counts; when the last 224 | // RefCntPointer referring to the object is destroyed, the object is too. 225 | // You can use RefCntPointer similarly to an object* for most data-access purposes. 226 | // The auto-destruction should be optional - there should be a version that just maintains reference counts for you. 227 | // Semantics: 228 | // SomeDescendentOfRefCntBase foo; 229 | // RefCntPointer ptrToFoo; 230 | // ptrToFoo = &foo; // increment the reference count of foo. 231 | // ... ptrToFoo->... // Normal code using ptrToFoo as a (SomeDescendentOfRefCntBase*) 232 | // ptrToFoo = 0; // release pointer and decrement reference count of foo. 233 | // ptrToFoo.free(); // A better way to release it. 234 | template // Type must be a descendent of RefCntBase. 235 | class RefCntPointer { 236 | Type *rcPointer; 237 | void rcInc() { if (rcPointer) rcPointer->incRefCnt(); } 238 | void rcDec() { 239 | if (rcPointer) if (rcPointer->decRefCnt() <= 0) { rcPointer = NULL; }; 240 | } 241 | public: 242 | RefCntPointer() : rcPointer(NULL) { } 243 | RefCntPointer(const RefCntPointer &other) { rcPointer = other.rcPointer; rcInc(); } 244 | RefCntPointer(RefCntPointer &other) { rcPointer = other.rcPointer; rcInc(); } 245 | RefCntPointer(Type*other) { rcPointer = other; rcInc(); } 246 | // (pat) Making this virtual ~RefCntPointer makes ~MMContext crash, dont know why. 247 | // (pat) Update: lets try making it virtual again; it should work, but no one derives off RefCntPointer so I dont know why it crashes.. 248 | ~RefCntPointer() { 249 | if (rcPointer) { LOG(DEBUG) <<" rcPointer="<<((void*)rcPointer) <<" refcnt="<<(rcPointer?rcPointer->getRefCnt():0); } 250 | rcDec(); 251 | rcPointer = NULL; // should be redundant 252 | } 253 | Type* self() const { return rcPointer; } 254 | // The operator=(Type*) is called if the argument is NULL, so we dont need int. 255 | //Type* operator=(int value) { assert(value == 0); rcDec(); rcPointer = 0; return rcPointer; } 256 | // We increment before decrement if possible so that a = a; does not crash. 257 | RefCntPointer& operator=(RefCntPointer other) { other.rcInc(); rcDec(); rcPointer = other.rcPointer; return *this; } 258 | // The old is the previous value of this pointer. We do not decrement the refcnt in the other that we are taking charge of. 259 | RefCntPointer& operator=(Type* other) { Type *old = rcPointer; rcPointer = other; rcInc(); if (old) {old->decRefCnt();} return *this; } 260 | bool operator==(const RefCntPointer &other) const { return rcPointer == other.rcPointer; } 261 | bool operator==(const Type* other) const { return rcPointer == other; } 262 | bool operator!=(const RefCntPointer &other) const { return rcPointer != other.rcPointer; } 263 | bool operator!=(const Type* other) const { return rcPointer != other; } 264 | Type* operator->() const { return rcPointer; } 265 | Type& operator*() const { return *rcPointer; } 266 | // This auto-conversion causes gcc warning messages, which are of no import, but to avoid them I now use self() everywhere instead. 267 | //operator Type*() const { return rcPointer; } 268 | // free is a synonym for *this = NULL; but it is a better comment in the code what is happening. RefCntBase is only freed if this was the last pointer to it. 269 | void free() { 270 | int refcnt = rcPointer ? rcPointer->getRefCnt() : 0; 271 | rcDec(); 272 | if (refcnt > 1) { LOG(DEBUG)<<"RefCntPointer "<<(void*)rcPointer<<" refcnt before="< alarmsList; 50 | void addAlarm(const string&); 51 | //@} 52 | 53 | // (pat 3-2014) Note that the logger is used by multiple programs. 54 | pid_t gPid = 0; 55 | 56 | 57 | // (pat) If Log messages are printed before the classes in this module are inited 58 | // (which happens when static classes have constructors that do work) 59 | // the OpenBTS just crashes. 60 | // Prevent that by setting sLoggerInited to true when this module is inited. 61 | static bool sLoggerInited = 0; 62 | static struct CheckLoggerInitStatus { 63 | CheckLoggerInitStatus() { sLoggerInited = 1; } 64 | } sCheckloggerInitStatus; 65 | 66 | 67 | 68 | /** Names of the logging levels. */ 69 | const char *levelNames[] = { 70 | "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG" 71 | }; 72 | int numLevels = 8; 73 | bool gLogToConsole = 0; 74 | FILE *gLogToFile = NULL; 75 | Mutex gLogToLock; 76 | LogGroup gLogGroup; 77 | 78 | 79 | int levelStringToInt(const string& name) 80 | { 81 | // Reverse search, since the numerically larger levels are more common. 82 | for (int i=numLevels-1; i>=0; i--) { 83 | if (name == levelNames[i]) return i; 84 | } 85 | 86 | // Common substitutions. 87 | if (name=="INFORMATION") return 6; 88 | if (name=="WARN") return 4; 89 | if (name=="ERROR") return 3; 90 | if (name=="CRITICAL") return 2; 91 | if (name=="EMERGENCY") return 0; 92 | 93 | // Unknown level. 94 | return -1; 95 | } 96 | 97 | /** Given a string, return the corresponding level name. */ 98 | static int lookupLevel2(const string& key, const string &keyVal) 99 | { 100 | int level = levelStringToInt(keyVal); 101 | 102 | if (level == -1) { 103 | string defaultLevel = gConfig.mSchema["Log.Level"].getDefaultValue(); 104 | level = levelStringToInt(defaultLevel); 105 | _LOG(CRIT) << "undefined logging level (" << key << " = \"" << keyVal << "\") defaulting to \"" << defaultLevel << ".\" Valid levels are: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO or DEBUG"; 106 | gConfig.set(key, defaultLevel); 107 | } 108 | 109 | return level; 110 | } 111 | 112 | static int lookupLevel(const string& key) 113 | { 114 | string val = gConfig.getStr(key); 115 | return lookupLevel2(key,val); 116 | } 117 | 118 | 119 | int getLoggingLevel(const char* filename) 120 | { 121 | // Default level? 122 | if (!filename) return lookupLevel("Log.Level"); 123 | 124 | // This can afford to be inefficient since it is not called that often. 125 | string keyName; 126 | keyName.reserve(100); 127 | keyName.append("Log.Level."); 128 | keyName.append(filename); 129 | if (gConfig.defines(keyName)) { 130 | string keyVal = gConfig.getStr(keyName); 131 | // (pat 4-2014) The CLI 'unconfig' command does not unset the value, it just gives an empty value, 132 | // so check for that and treat it as an unset value, ie, do nothing. 133 | if (keyVal.size()) { 134 | return lookupLevel2(keyName,keyVal); 135 | } 136 | } 137 | return lookupLevel("Log.Level"); 138 | } 139 | 140 | 141 | int gGetLoggingLevel(const char* filename) 142 | { 143 | // This is called a lot and needs to be efficient. 144 | 145 | static Mutex sLogCacheLock; 146 | static map sLogCache; 147 | static unsigned sCacheCount; 148 | static const unsigned sCacheRefreshCount = 1000; 149 | 150 | if (filename==NULL) return gGetLoggingLevel(""); 151 | 152 | HashString hs(filename); 153 | uint64_t key = hs.hash(); 154 | 155 | sLogCacheLock.lock(); 156 | // Time for a cache flush? 157 | if (sCacheCount>sCacheRefreshCount) { 158 | sLogCache.clear(); 159 | sCacheCount=0; 160 | } 161 | // Is it cached already? 162 | map::const_iterator where = sLogCache.find(key); 163 | sCacheCount++; 164 | if (where!=sLogCache.end()) { 165 | int retVal = where->second; 166 | sLogCacheLock.unlock(); 167 | return retVal; 168 | } 169 | // Look it up in the config table and cache it. 170 | // FIXME: Figure out why unlock and lock below fix the config table deadlock. 171 | // (pat) Probably because getLoggingLevel may call LOG recursively via lookupLevel(). 172 | sLogCacheLock.unlock(); 173 | int level = getLoggingLevel(filename); 174 | sLogCacheLock.lock(); 175 | sLogCache.insert(pair(key,level)); 176 | sLogCacheLock.unlock(); 177 | return level; 178 | } 179 | 180 | 181 | 182 | 183 | 184 | // copies the alarm list and returns it. list supposed to be small. 185 | list gGetLoggerAlarms() 186 | { 187 | alarmsLock.lock(); 188 | list ret; 189 | // excuse the "complexity", but to use std::copy with a list you need 190 | // an insert_iterator - copy technically overwrites, doesn't insert. 191 | insert_iterator< list > ii(ret, ret.begin()); 192 | copy(alarmsList.begin(), alarmsList.end(), ii); 193 | alarmsLock.unlock(); 194 | return ret; 195 | } 196 | 197 | /** Add an alarm to the alarm list. */ 198 | void addAlarm(const string& s) 199 | { 200 | alarmsLock.lock(); 201 | alarmsList.push_back(s); 202 | unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max"); 203 | while (alarmsList.size() > maxAlarms) alarmsList.pop_front(); 204 | alarmsLock.unlock(); 205 | } 206 | 207 | 208 | Log::~Log() 209 | { 210 | if (mDummyInit) return; 211 | // Anything at or above LOG_CRIT is an "alarm". 212 | // Save alarms in the local list and echo them to stderr. 213 | if (mPriority <= LOG_CRIT) { 214 | if (sLoggerInited) addAlarm(mStream.str().c_str()); 215 | cerr << mStream.str() << endl; 216 | } 217 | // Current logging level was already checked by the macro. 218 | // So just log. 219 | syslog(mPriority, "%s", mStream.str().c_str()); 220 | // pat added for easy debugging. 221 | if (gLogToConsole||gLogToFile) { 222 | int mlen = mStream.str().size(); 223 | int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n'); 224 | gLogToLock.lock(); 225 | if (gLogToConsole) { 226 | // The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers, 227 | // so just use std::cout. 228 | std::cerr << mStream.str(); 229 | if (neednl) std::cerr<<"\n"; 230 | } 231 | if (gLogToFile) { 232 | fputs(mStream.str().c_str(),gLogToFile); 233 | if (neednl) {fputc('\n',gLogToFile);} 234 | fflush(gLogToFile); 235 | } 236 | gLogToLock.unlock(); 237 | } 238 | } 239 | 240 | 241 | // (pat) This is the log initialization function. 242 | // It is invoked by this line in OpenBTS.cpp, and similar lines in other programs like the TransceiverRAD1: 243 | // Log dummy("openbts",gConfig.getStr("Log.Level").c_str(),LOG_LOCAL7); 244 | // The LOCAL7 corresponds to the "local7" line in the file /etc/rsyslog.d/OpenBTS.log. 245 | Log::Log(const char* name, const char* level, int facility) 246 | { 247 | // (pat) This 'constructor' has nothing to do with the regular use of the Log class, so we have 248 | // to set this special flag to prevent the destructor from generating a syslog message. 249 | // This is really goofy, but there is a reason - this is the way whoever wrote this got the Logger initialized early during 250 | // static class initialization since OpenBTS has so many static classes whose constructors do work (a really bad idea) 251 | // and may generate log messages. 252 | mDummyInit = true; 253 | gLogInit(name, level, facility); 254 | } 255 | 256 | 257 | ostringstream& Log::get() 258 | { 259 | assert(mPriority 0) { 274 | gLogToFile = fopen(LogFilePath,"w"); // New log file each time we start. 275 | if (gLogToFile) { 276 | string when = Timeval::isoTime(time(NULL),true); 277 | fprintf(gLogToFile,"Starting at %s\n",when.c_str()); 278 | fflush(gLogToFile); 279 | std::cerr << name <<" logging to file: " << LogFilePath << "\n"; 280 | } 281 | } 282 | 283 | // Open the log connection. 284 | openlog(name,0,facility); 285 | 286 | // We cant call this from the Mutex itself because the Logger uses Mutex. 287 | gMutexLogLevel = gGetLoggingLevel("Mutex.cpp"); 288 | } 289 | 290 | 291 | 292 | void gLogInit(const char* name, const char* level, int facility) 293 | { 294 | // Set the level if one has been specified. 295 | if (level) { 296 | gConfig.set("Log.Level",level); 297 | } 298 | gPid = getpid(); 299 | 300 | // Pat added, tired of the syslog facility. 301 | // Both the transceiver and OpenBTS use this same Logger class, but only RMSC/OpenBTS/OpenNodeB may use this log file: 302 | string str = gConfig.getStr("Log.File"); 303 | if (gLogToFile==0 && str.length() && (0==strncmp(gCmdName,"Open",4) || 0==strncmp(gCmdName,"RMSC",4) || 0==strncmp(gCmdName,"RangeFinderGW",13))) { 304 | const char *fn = str.c_str(); 305 | if (fn && *fn && strlen(fn)>3) { // strlen because a garbage char is getting in sometimes. 306 | gLogToFile = fopen(fn,"w"); // New log file each time we start. 307 | if (gLogToFile) { 308 | string when = Timeval::isoTime(time(NULL),true); 309 | fprintf(gLogToFile,"Starting at %s\n",when.c_str()); 310 | fflush(gLogToFile); 311 | std::cerr << name <<" logging to file: " << fn << "\n"; 312 | } 313 | } 314 | } 315 | 316 | // Open the log connection. 317 | openlog(name,0,facility); 318 | 319 | // We cant call this from the Mutex itself because the Logger uses Mutex. 320 | gMutexLogLevel = gGetLoggingLevel("Mutex.cpp"); 321 | } 322 | 323 | 324 | void gLogEarly(int level, const char *fmt, ...) 325 | { 326 | va_list args; 327 | 328 | va_start(args, fmt); 329 | vsyslog(level | LOG_USER, fmt, args); 330 | va_end(args); 331 | } 332 | 333 | // Return _NumberOfLogGroups if invalid. 334 | LogGroup::Group LogGroup::groupNameToIndex(const char *groupName) const 335 | { 336 | for (unsigned g = (Group)0; g < _NumberOfLogGroups; g++) { 337 | if (0 == strcasecmp(mGroupNames[g],groupName)) { return (Group) g; } // happiness 338 | } 339 | return _NumberOfLogGroups; // failed 340 | } 341 | 342 | LogGroup::LogGroup() { LogGroupInit(); } 343 | 344 | // These must match LogGroup::Group. 345 | const char *LogGroup::mGroupNames[] = { "Control", "SIP", "GSM", "GPRS", "Layer2", "SMS", NULL }; 346 | 347 | void LogGroup::LogGroupInit() 348 | { 349 | // Error check some more. 350 | assert(0==strcmp(mGroupNames[Control],"Control")); 351 | assert(0==strcmp(mGroupNames[SIP],"SIP")); 352 | assert(0==strcmp(mGroupNames[GSM],"GSM")); 353 | assert(0==strcmp(mGroupNames[GPRS],"GPRS")); 354 | assert(0==strcmp(mGroupNames[Layer2],"Layer2")); 355 | 356 | // Error check mGroupNames is the correct length; 357 | unsigned g; 358 | for (g = 0; mGroupNames[g]; g++) { continue; } 359 | assert(g == _NumberOfLogGroups); // If you get this, go fix mGroupNames to match enum LogGroup::Group. 360 | 361 | for (unsigned g = 0; g < _NumberOfLogGroups; g++) { 362 | mDebugLevel[g] = 0; 363 | mWatchLevel[g] = 0; 364 | } 365 | 366 | #if 0 367 | if (mGroupNameToIndex.size()) { return; } // inited previously. 368 | mGroupNameToIndex[string("Control")] = Control; 369 | mGroupNameToIndex[string("SIP")] = SIP; 370 | mGroupNameToIndex[string("GSM")] = GSM; 371 | mGroupNameToIndex[string("GPRS")] = GPRS; 372 | mGroupNameToIndex[string("Layer2")] = Layer2; 373 | #endif 374 | } 375 | 376 | 377 | static const char*getNonEmptyStrIfDefined(string param) 378 | { 379 | if (! gConfig.defines(param)) { return NULL; } 380 | string result = gConfig.getStr(param); 381 | // (pat) The "unconfig" command does not remove the value, it just gives it an empty value, so check for that. 382 | return result.size() ? result.c_str() : NULL; 383 | } 384 | 385 | // Set all the Log.Group debug levels based on database settings 386 | void LogGroup::setAll() 387 | { 388 | LOG(DEBUG); 389 | string groupprefix = string("Log.Group."); 390 | string watchprefix = string("Log.Watch."); 391 | for (unsigned g = 0; g < _NumberOfLogGroups; g++) { 392 | { 393 | string param = groupprefix + mGroupNames[g]; 394 | int level = 0; 395 | if (const char*levelName = getNonEmptyStrIfDefined(param)) { 396 | level = lookupLevel2(param,levelName); 397 | } 398 | mDebugLevel[g] = level; 399 | } 400 | 401 | { 402 | string watchparam = watchprefix + mGroupNames[g]; 403 | int watchlevel = 0; 404 | if (const char*levelName = getNonEmptyStrIfDefined(watchparam)) { 405 | watchlevel = lookupLevel2(watchparam,levelName); 406 | } 407 | mWatchLevel[g] = watchlevel; 408 | } 409 | } 410 | } 411 | 412 | // vim: ts=4 sw=4 413 | --------------------------------------------------------------------------------