├── 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 |
--------------------------------------------------------------------------------