nrtb-core team mailing list archive
-
nrtb-core team
-
Mailing list archive
-
Message #00493
[Merge] lp:~fpstovall/nrtb/bk2thefuture into lp:nrtb
Rick Stovall has proposed merging lp:~fpstovall/nrtb/bk2thefuture into lp:nrtb.
Requested reviews:
NRTB Core (nrtb-core): code merge
For more details, see:
https://code.launchpad.net/~fpstovall/nrtb/bk2thefuture/+merge/179547
This branch moves our development focus back to C++ (C++11). In preparing for this, the following has been accomplished:
* The D code has been moved to the "obsolete" directory.
* The needed C++ common libs have been restored from the obsolete directory.
* Threading now uses the C++11 model; the old thread class has been removed.
* The work_queue template has been replaced by cleaner thread safe queues.
* The tcp_server_socket factory has been redesigned to use a producer/consumer model.
* There is a new logger class which is simple and fast.
* All the common code has been reviewed, formatted neatly, and updated to C++11 standards.
The upshot of all this is that we are closer to a working alpha phase release now than at any time in the last couple of years. I intend to allow this to rest until Sunday, at which time I will promoted it to main branch if there are no objections.
--
https://code.launchpad.net/~fpstovall/nrtb/bk2thefuture/+merge/179547
Your team NRTB Core is requested to review the proposed merge of lp:~fpstovall/nrtb/bk2thefuture into lp:nrtb.
=== renamed directory 'obsolete/Cpp' => 'cpp'
=== modified file 'cpp/common/Makefile'
--- obsolete/Cpp/common/Makefile 2011-12-14 19:24:03 +0000
+++ cpp/common/Makefile 2013-08-09 21:47:12 +0000
@@ -16,7 +16,7 @@
#
#***********************************************
-lib: ./lib/nrtb_common.a ./lib/nrtb_communication.a
+lib: ./lib/nrtb_common.a
./lib/nrtb_common.a:
@echo "============= building common libs ==============="
@@ -24,9 +24,6 @@
@ar -r ./lib/nrtb_common.a ./obj/*.o
@echo "============= common libs complete ==============="
-./lib/nrtb_communication.a:
- @cd comm_handlers; make lib
-
modules:
@echo "============= building common modules ==============="
@make doit
@@ -36,14 +33,13 @@
@echo "============= cleaning common libs ==============="
@make action=clean doit
@rm -fv ./obj/* ./lib/* ./include/*
- @cd comm_handlers; make clean
@echo "========== common lib cleanup complete ==========="
doit:
@cd common_rl; make ${action}
@cd point; make ${action}
@cd timer; make ${action}
- @cd threads; make ${action}
+ @cd abs_queue; make ${action}
@cd circular_queue; make ${action}
@cd linear_queue; make ${action}
@cd sockets; make ${action}
@@ -51,6 +47,9 @@
@cd singleton; make ${action}
@cd logger; make ${action}
@cd confreader; make ${action}
- @cd GPB; make ${action}
- @cd transceiver; make ${action}
+
+# --- the following are obsolete and may be removed later.
+# @cd threads; make ${action}
+# @cd GPB; make ${action}
+# @cd transceiver; make ${action}
=== added directory 'cpp/common/abs_queue'
=== added file 'cpp/common/abs_queue/Makefile'
--- cpp/common/abs_queue/Makefile 1970-01-01 00:00:00 +0000
+++ cpp/common/abs_queue/Makefile 2013-08-09 21:47:12 +0000
@@ -0,0 +1,33 @@
+#***********************************************
+#This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+# NRTB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# NRTB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
+lib: abs_queue_test
+ @./abs_queue_test
+ @cp -v abs_queue.h ../include
+ @echo build complete
+
+abs_queue_test: abs_queue.h abs_queue_test.cpp
+ @rm -f abs_queue_test
+ g++ -c abs_queue_test.cpp -I../include ${switches}
+ g++ -o abs_queue_test abs_queue_test.o -lpthread ${switches}
+
+clean:
+ @rm -rvf *.o abs_queue_test ../include/abs_queue.h *.log ../obj/abs_queue.o
+ @echo all objects and executables have been erased.
=== added file 'cpp/common/abs_queue/abs_queue.h'
--- cpp/common/abs_queue/abs_queue.h 1970-01-01 00:00:00 +0000
+++ cpp/common/abs_queue/abs_queue.h 2013-08-09 21:47:12 +0000
@@ -0,0 +1,187 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+
+#ifndef nrtb_abs_queue_h
+#define nrtb_abs_queue_h
+
+#include <common.h>
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+
+namespace nrtb
+{
+
+/********************************************************
+ * The abs_queue template is designed for use with
+ * the classic producer/consumer thread management model.
+ * The producer uses abs_queue::push() to put items
+ * in the queue as they become available, and the consumer
+ * thread calls abs_queue::park() when it is ready
+ * for the next item to work.
+ *
+ * This queue will expand as needed. Constrast this with
+ * the circular_queue, which is of a fixed size and will
+ * drop older data when full
+ *
+ * Common uses would be for buffering outgoing or incomming
+ * messages from a communications channel, providing a feed
+ * queue for parallel threads to make full use of multi-core
+ * processors, or any case where one or more threads are
+ * passing data to another set of threads.
+********************************************************/
+template <class T, class queue_t>
+class abs_queue
+{
+public:
+ class queue_not_ready: public nrtb::base_exception {};
+
+ /// Total number of items placed in queue.
+ std::atomic<int> in_count {0};
+ /// Total number of items read from queue.
+ std::atomic<int> out_count {0};
+
+ /*********************************************
+ * creates the queue with the specified
+ * number of elements.
+ *********************************************/
+ abs_queue();
+
+ /*********************************************
+ * releases all items in the queue
+ *********************************************/
+ ~abs_queue();
+
+ /*********************************************
+ * Puts an item in the queue.
+ *********************************************/
+ void push(T item);
+
+ /*********************************************
+ * Pops the next item off the queue, blocking
+ * if needed until an item becomes available.
+ *********************************************/
+ T pop();
+
+ /*********************************************
+ * puts the queue in shutdown mode.
+ *********************************************/
+ void shutdown();
+
+ // returns the number of items in the queue
+ int size();
+ // resizes the buffer, may cause data loss
+ void resize(int newsize);
+ // clears the buffer, data will be discarded.
+ void clear();
+
+protected:
+
+ queue_t buffer;
+ std::mutex mylock;
+ std::condition_variable signal;
+ bool ready {true};
+};
+
+template <class T, class queue_t>
+abs_queue<T,queue_t>::abs_queue()
+{
+};
+
+template <class T, class queue_t>
+abs_queue<T,queue_t>::~abs_queue()
+{
+ shutdown();
+};
+
+template <class T, class queue_t>
+void abs_queue<T,queue_t>::push(T item)
+{
+ if (ready)
+ {
+ in_count++;
+ {
+ std::unique_lock<std::mutex> lock(mylock);
+ buffer.push(item);
+ }
+ signal.notify_one();
+ }
+ else
+ {
+ queue_not_ready e;
+ throw e;
+ }
+};
+
+template <class T, class queue_t>
+T abs_queue<T,queue_t>::pop()
+{
+ std::unique_lock<std::mutex> lock(mylock);
+ while (buffer.empty() && ready)
+ signal.wait(lock);
+ if (ready)
+ {
+ T returnme = buffer.front();
+ buffer.pop();
+ out_count++;
+ return returnme;
+ }
+ else
+ {
+ queue_not_ready e;
+ throw e;
+ };
+};
+
+template <class T, class queue_t>
+void abs_queue<T,queue_t>::shutdown()
+{
+ try
+ {
+ std::unique_lock<std::mutex> lock(mylock);
+ ready = false;
+ while (buffer.size()) { buffer.pop(); }
+ signal.notify_all();
+ }
+ catch (...) {}
+}
+
+template <class T, class queue_t>
+int abs_queue<T,queue_t>::size()
+{
+ std::unique_lock<std::mutex> lock(mylock);
+ return buffer.size();
+};
+
+template <class T, class queue_t>
+void abs_queue<T,queue_t>::resize(int newsize)
+{
+ std::unique_lock<std::mutex> lock(mylock);
+ buffer.set_capacity(newsize);
+};
+
+template <class T, class queue_t>
+void abs_queue<T,queue_t>::clear()
+{
+ std::unique_lock<std::mutex> lock(mylock);
+ while (buffer.size()) buffer.pop();
+};
+
+} // namespace nrtb
+
+#endif //nrtb_abs_queue_h//
=== added file 'cpp/common/abs_queue/abs_queue_test.cpp'
--- cpp/common/abs_queue/abs_queue_test.cpp 1970-01-01 00:00:00 +0000
+++ cpp/common/abs_queue/abs_queue_test.cpp 2013-08-09 21:47:12 +0000
@@ -0,0 +1,120 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+
+#include <unistd.h> // included for usleep()
+#include <string>
+#include <iostream>
+#include "abs_queue.h"
+#include <memory>
+#include <atomic>
+#include <future>
+#include <queue>
+
+using namespace nrtb;
+using namespace std;
+
+typedef abs_queue<int,std::queue<int>> test_queue;
+typedef shared_ptr<test_queue> queue_p;
+
+int consumer_task(string name, queue_p input)
+{
+ bool ready {true};
+ int count {0};
+ try
+ {
+ while (ready)
+ {
+ int num = input->pop();
+ count++;
+ usleep(1);
+ }
+ }
+ catch (...)
+ {
+ // exit if we get any exception.
+ ready = false;
+ };
+ return count;
+};
+
+int main()
+{
+ cout << "***** abs_queue unit test ******" << endl;
+ /************************************************
+ * Load queue and then cook it down...
+ ***********************************************/
+ // make and load a queue
+ queue_p q1(new test_queue());
+ for (int i=0; i<100; i++)
+ {
+ q1->push(i);
+ };
+ // the queue should be loaded with 0-99
+ // attach a thread and process it.
+ auto t1 = async(launch::async,consumer_task,"task 1",q1);
+ while (q1->size()) usleep(100);
+ cout << "cp 1 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
+ /************************************************
+ * now that the preload is exhasted, shove items
+ * in one at a time to make sure each is picked
+ * up correctly.
+ ***********************************************/
+ for (int i=200; i<225; i++)
+ {
+ q1->push(i);
+ usleep(100);
+ };
+ cout << "cp 2 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
+ /************************************************
+ * Last check; attach a second thread to the queue
+ * and make sure both are servicing it.
+ ***********************************************/
+ auto t2 = async(launch::async,consumer_task,"task 2",q1);
+ for (int i=300; i<325; i++)
+ {
+ q1->push(i);
+ };
+ while (q1->size()) usleep(100);
+ // shut it all down
+ q1->shutdown();
+ // important numbers
+ int t1_count = t1.get();
+ int t2_count = t2.get();
+ int q1_in = q1->in_count;
+ int q1_out = q1->out_count;
+ // release the queues.
+ q1.reset();
+ // do some reporting.
+ cout << "cp 3 "
+ << q1_in << ":" << q1_out
+ << " t1=" << t1_count
+ << " t2=" << t2_count
+ << endl;
+ bool passed = (q1_in == q1_out)
+ and (q1_out == (t1_count + t2_count));
+ cout << "***** abs_queue TEST "
+ << (passed ? "PASSED" : "FAILED")
+ << " ******" << endl;
+ // inverted logic needed because 0 is good for
+ // return codes.
+ return !passed;
+};
\ No newline at end of file
=== modified file 'cpp/common/circular_queue/Makefile'
--- obsolete/Cpp/common/circular_queue/Makefile 2012-04-06 12:10:36 +0000
+++ cpp/common/circular_queue/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,8 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
lib: circular_queue_test
@./circular_queue_test
@cp -v circular_queue.h ../include
@@ -23,8 +25,8 @@
circular_queue_test: circular_queue.h circular_queue_test.cpp
@rm -f circular_queue_test
- g++ -c circular_queue_test.cpp -I../include -std=gnu++0x
- g++ -o circular_queue_test circular_queue_test.o ../obj/common.o ../obj/base_thread.o -lpthread -std=gnu++0x
+ g++ -c circular_queue_test.cpp -I../include ${switches}
+ g++ -o circular_queue_test circular_queue_test.o -lpthread ${switches}
clean:
@rm -rvf *.o circular_queue_test ../include/circular_queue.h *.log ../obj/circular_queue.o
=== modified file 'cpp/common/circular_queue/circular_queue.h'
--- obsolete/Cpp/common/circular_queue/circular_queue.h 2011-10-06 20:09:07 +0000
+++ cpp/common/circular_queue/circular_queue.h 2013-08-09 21:47:12 +0000
@@ -20,18 +20,31 @@
#define nrtb_circular_queue_h
#include <iostream>
-#include <base_thread.h>
#include <boost/circular_buffer.hpp>
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+#include <common.h>
+#include <abs_queue.h>
namespace nrtb
{
+
+// specialize boost::circular_buffer to act like a queue.
+template <class T>
+class base_cq : public boost::circular_buffer<T>
+{
+public:
+ void push(T elem) { this->push_back(elem); };
+ void pop() { this->pop_front(); };
+};
/********************************************************
* The circular_queue template is designed for use with
* the classic producer/consumer thread management model.
* The producer uses circular_queue::push() to put items
* in the queue as they become available, and the consumer
- * thread calls circular_queue::park() when it is ready
+ * thread calls circular_queue::pop() when it is ready
* for the next item to work.
*
* Common uses would be for buffering outgoing or incomming
@@ -41,132 +54,14 @@
* passing data to another set of threads.
********************************************************/
template <class T>
-class circular_queue
-{
-public:
- class queue_not_ready: public base_exception {};
-
- /*********************************************
- * creates the queue with the specified
- * number of elements. All memory is allocated
- * at construction to minimize delays at runtime.
- *********************************************/
- circular_queue(int size);
-
- /*********************************************
- * releases all items in the queue
- *********************************************/
- virtual ~circular_queue();
-
- /*********************************************
- * Puts an item in the queue.
- *********************************************/
- void push(T item);
-
- /*********************************************
- * Pops the next item off the queue, blocking
- * if needed until an item becomes available.
- *********************************************/
- T pop();
-
- /*********************************************
- * puts the queue in shutdown mode.
- *********************************************/
- void shutdown();
-
- // returns the number of items in the queue
- int size();
- // resizes the buffer, may cause data loss
- void resize(int newsize);
- // clears the buffer, data will be discarded.
- void clear();
-
-protected:
-
- boost::circular_buffer<T> buffer;
- cond_variable buffer_lock;
- bool ready;
-};
-
-template <class T>
-circular_queue<T>::circular_queue(int size)
-{
- buffer.set_capacity(size);
- ready = true;
-};
-
-// TODO: needed ... a queue stop method.
-
-template <class T>
-circular_queue<T>::~circular_queue()
-{
-};
-
-template <class T>
-void circular_queue<T>::push(T item)
-{
- if (ready)
- {
- scope_lock lock(buffer_lock);
- buffer.push_back(item);
- buffer_lock.signal();
- }
- else
- {
- queue_not_ready e;
- throw e;
- }
-};
-
-template <class T>
-T circular_queue<T>::pop()
-{
- scope_lock lock(buffer_lock);
- while (buffer.empty() && ready)
- buffer_lock.wait();
- if (!ready)
- {
- queue_not_ready e;
- throw e;
- };
- T returnme = buffer.front();
- buffer.pop_front();
- return returnme;
-};
-
-template <class T>
-void circular_queue<T>::shutdown()
-{
- try
- {
- scope_lock lock(buffer_lock);
- ready = false;
- buffer_lock.broadcast_signal();
- buffer.clear();
- }
- catch (...) {}
-}
-
-
-template <class T>
-int circular_queue<T>::size()
-{
- scope_lock lock(buffer_lock);
- return buffer.size();
-};
-
-template <class T>
-void circular_queue<T>::resize(int newsize)
-{
- scope_lock lock(buffer_lock);
- buffer.set_capacity(newsize);
-};
-
-template <class T>
-void circular_queue<T>::clear()
-{
- scope_lock lock(buffer_lock);
- buffer.clear();
+class circular_queue : public abs_queue<T, base_cq<T>>
+{
+public:
+ // convienence constructor because a 0 size circular_queue is useless.
+ circular_queue(int size=10) : abs_queue<T, base_cq<T>>()
+ {
+ this->resize(size);
+ };
};
} // namespace nrtb
=== modified file 'cpp/common/circular_queue/circular_queue_test.cpp'
--- obsolete/Cpp/common/circular_queue/circular_queue_test.cpp 2011-10-06 20:09:07 +0000
+++ cpp/common/circular_queue/circular_queue_test.cpp 2013-08-09 21:47:12 +0000
@@ -18,78 +18,41 @@
#include <string>
#include <iostream>
+#include <unistd.h>
#include "circular_queue.h"
-#include <boost/shared_ptr.hpp>
+#include <memory>
+#include <future>
using namespace nrtb;
using namespace std;
typedef circular_queue<int> test_queue;
-typedef boost::shared_ptr<test_queue> queue_p;
+typedef std::shared_ptr<test_queue> queue_p;
-class consumer_task: public thread
+int consumer_task(string name, queue_p input)
{
-public:
-
- consumer_task(string n, queue_p buffer)
- {
- name = n;
- input = buffer;
- count = 0;
- };
-
- ~consumer_task()
- {
- cout << ">> in " << name << "::~consumer_task()" << endl;
- try
- {
- this->thread::~thread();
- input.reset();
- }
- catch (...) {};
- cout << "<< leaving " << name << "::~consumer_task()" << endl;
- };
-
- int get_count() { return count; };
-
- void run()
- {
- try
- {
- while (true)
- {
- int num = input->pop();
- {
- static mutex console;
- scope_lock lock(console);
- cout << name << " picked up " << num
- << endl;
- };
- count++;
- lastnum = num;
- yield();
- }
- }
- catch (...) {};
- };
-
-protected:
- // link to the feed queue
- queue_p input;
- // a name to report
- string name;
- // number of items processed
- int count;
- // last number caught
- int lastnum;
+ bool ready {true};
+ int count {0};
+ try
+ {
+ while (ready)
+ {
+ int num = input->pop();
+ count++;
+ usleep(1);
+ }
+ }
+ catch (...)
+ {
+ // exit on any exception
+ ready = false;
+ };
+ return count;
};
-typedef boost::shared_ptr<consumer_task> task_p;
-
-
int main()
{
- int er_count = 0;
+ cout << "***** circular_queue unit test *****" << endl;
/************************************************
* Load queue and then cook it down...
***********************************************/
@@ -101,10 +64,11 @@
};
// the queue should be loaded with 50-99
// attach a thread and process it.
- task_p p1(new consumer_task("task 1",q1));
- p1->start();
+ auto t1 = async(launch::async,consumer_task,"task 1",q1);
while (q1->size()) usleep(100);
- cout << "cp 1 " << p1->get_count() << endl;
+ cout << "cp 1 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
/************************************************
* now that the preload is exhasted, shove items
* in one at a time to make sure each is picked
@@ -112,40 +76,42 @@
***********************************************/
for (int i=200; i<225; i++)
{
- q1->push(i);
- usleep(100);
+ q1->push(i);
+ usleep(100);
};
- cout << "cp 2 " << p1->get_count() << endl;
+ cout << "cp 2 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
/************************************************
* Last check; attach a second thread to the queue
* and make sure both are servicing it.
***********************************************/
- task_p p2(new consumer_task("task 2",q1));
- p2->start();
+ auto t2 = async(launch::async,consumer_task,"task 2",q1);
for (int i=300; i<325; i++)
{
- q1->push(i);
+ q1->push(i);
};
while (q1->size()) usleep(100);
// shut it all down
q1->shutdown();
- p1->join();
- p2->join();
// important numbers
- int tot_items = p1->get_count() + p2->get_count();
- int p1_items = p1->get_count() - 75;
- int p2_items = p2->get_count();
+ int q1_in = q1->in_count;
+ int q1_out = q1->out_count;
+ int t1_items = t1.get();
+ int t2_items = t2.get();
// release she threads and queues.
- p1.reset();
- p2.reset();
q1.reset();
// do some reporting.
cout << "cp 3 "
- << tot_items
- << " [75 + (" << p1_items
- << " + " << p2_items
- << ")]" << endl;
- bool passed = (tot_items == 100);
+ << q1_in << ":" << q1_out
+ << " t1=" << t1_items
+ << " t2=" << t2_items
+ << endl;
+ bool passed = (q1_in - 50 == q1_out)
+ and (q1_out == (t1_items + t2_items));
+ cout << "***** circular_queue TEST "
+ << (passed ? "PASSED" : "FAILED")
+ << " ******" << endl;
// inverted logic needed because 0 is good for
// return codes.
return !passed;
=== modified file 'cpp/common/common_rl/Makefile'
--- obsolete/Cpp/common/common_rl/Makefile 2012-04-06 12:16:10 +0000
+++ cpp/common/common_rl/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,9 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
+
lib: common_rl_test
@./common_rl_test
@cp -v common.h ../include
@@ -24,12 +27,12 @@
common.o: common.h common.cpp Makefile
@rm -f common.o
- g++ -c -O3 common.cpp -std=gnu++0x
+ g++ -c -O3 common.cpp ${switches}
common_rl_test: common.o common_rl_test.cpp
@rm -f common_rl_test
- g++ -c common_rl_test.cpp -std=gnu++0x
- g++ -o common_rl_test common_rl_test.o common.o -std=gnu++0x
+ g++ -c common_rl_test.cpp ${switches}
+ g++ -o common_rl_test common_rl_test.o common.o ${switches}
clean:
@rm -rvf *.o ../include/common.h ../obj/common.o common_rl_test
=== modified file 'cpp/common/common_rl/common.cpp'
--- obsolete/Cpp/common/common_rl/common.cpp 2010-12-25 22:44:22 +0000
+++ cpp/common/common_rl/common.cpp 2013-08-09 21:47:12 +0000
@@ -19,7 +19,6 @@
#include <stdlib.h>
#include <iostream>
#include <math.h>
-#include <time.h>
#include "common.h"
using namespace std;
@@ -27,247 +26,224 @@
namespace nrtb
{
-base_exception::base_exception()
-{
- ctime = time(NULL);
-};
-
-base_exception::base_exception(const string & text)
-{
- ctime = time(NULL);
- _text = text;
-};
-
-void base_exception::store(const string & s)
-{
- _text = s;
-};
-
-string base_exception::comment()
-{
- return _text;
-};
-
-unsigned long int base_exception::creation_time()
-{
- return ctime;
-};
-
const string __ricks_handy_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string __ricks_handy_lower = "abcdefghijklmnopqrstuvwxyz";
-string changecase(const string &s,const string &upper, const string &lower)
+string changecase(const string &s,const string &upper,
+ const string &lower)
{
- try
- {
- string returnme = "";
- for (int i = 0; i < s.size(); i++)
- {
- unsigned long int loc = lower.find(s[i]);
- if (loc == string::npos)
- {
- returnme += s[i];
- }
- else
- {
- returnme += upper[loc];
- };
- };
- return returnme;
- }
- catch (...)
- {
- throw translate_exception();
- };
+ try
+ {
+ string returnme = "";
+ for (int i = 0; i < s.size(); i++)
+ {
+ unsigned long int loc = lower.find(s[i]);
+ if (loc == string::npos)
+ {
+ returnme += s[i];
+ }
+ else
+ {
+ returnme += upper[loc];
+ };
+ };
+ return returnme;
+ }
+ catch (...)
+ {
+ throw translate_exception();
+ };
};
string upcase(const string &s)
{
- return changecase(s,__ricks_handy_upper,__ricks_handy_lower);
+ return changecase(s,__ricks_handy_upper,__ricks_handy_lower);
};
string downcase(const string &s)
{
- return changecase(s,__ricks_handy_lower,__ricks_handy_upper);
+ return changecase(s,__ricks_handy_lower,__ricks_handy_upper);
};
const string __ricks_handy_hexits = "0123456789ABCDEF";
-string gsub(const string & target, const string & findme, const string & putme)
+string gsub(const string & target, const string & findme,
+ const string & putme)
{
- // error checking
- if (findme.empty() || target.empty())
- {
- throw gsub_exception();
- };
- string returnme = "";
- unsigned long int okay_through = 0;
- unsigned long int step = findme.length();
- unsigned long int where = target.find(findme,okay_through);
- while (where != string::npos)
- {
- returnme += target.substr(okay_through,where-okay_through) + putme;
- okay_through = where + step;
- where = target.find(findme,okay_through);
- };
- returnme += target.substr(okay_through);
- return returnme;
+ // error checking
+ if (findme.empty() || target.empty())
+ {
+ throw gsub_exception();
+ };
+ string returnme = "";
+ unsigned long int okay_through = 0;
+ unsigned long int step = findme.length();
+ unsigned long int where = target.find(findme,okay_through);
+ while (where != string::npos)
+ {
+ returnme += target.substr(okay_through,where-okay_through) + putme;
+ okay_through = where + step;
+ where = target.find(findme,okay_through);
+ };
+ returnme += target.substr(okay_through);
+ return returnme;
};
strlist split(const string & source, const char token)
{
- strlist returnme;
- returnme.clear();
- if (source.size() > 0)
- {
- unsigned long int loc;
- unsigned long int processed = 0;
- try
- {
- loc = source.find(token,processed);
- while (loc != string::npos)
- {
- returnme.push_back(source.substr(processed,loc-processed));
- processed = loc + 1;
- loc = source.find(token,processed);
- }
- returnme.push_back(source.substr(processed));
- }
- catch (...)
- {
- throw split_exception();
- };
- };
- return returnme;
+ strlist returnme;
+ returnme.clear();
+ if (source.size() > 0)
+ {
+ unsigned long int loc;
+ unsigned long int processed = 0;
+ try
+ {
+ loc = source.find(token,processed);
+ while (loc != string::npos)
+ {
+ returnme.push_back(source.substr(processed,loc-processed));
+ processed = loc + 1;
+ loc = source.find(token,processed);
+ }
+ returnme.push_back(source.substr(processed));
+ }
+ catch (...)
+ {
+ throw split_exception();
+ };
+ };
+ return returnme;
};
string trim(std::string s)
{
- const string ws = "\t\n ";
- unsigned long int where = s.find_first_not_of(ws);
- if (where != string::npos)
- {
- s.erase(0,where);
- };
- where = s.find_last_not_of(ws);
- if (where != string::npos)
- {
- s.erase(where+1);
- };
- return s;
+ const string ws = "\t\n ";
+ unsigned long int where = s.find_first_not_of(ws);
+ if (where != string::npos)
+ {
+ s.erase(0,where);
+ };
+ where = s.find_last_not_of(ws);
+ if (where != string::npos)
+ {
+ s.erase(where+1);
+ };
+ return s;
};
string mconvert(const string &s)
{
- /* This function is designed to escape strings destined for
- * use in SQL queries and the like. Specifically, the following
- * is done to the string passed in:
- * 1. "\" is replaced with "\\"
- * 2. "'" is replaced with "\'"
- * 3. """ (double quote) is replaced with "\""
- * 4. 0x00 is replaced with "\"+0x00.
- */
- string returnme = "";
- if (s.length() > 0)
- {
- returnme = gsub(s,"\\","\\\\");
- returnme = gsub(returnme,"'", "\\'");
- returnme = gsub(returnme,"\"","\\\"");
- // special handling is required to make strings including
- // 0x00; this is the kludge I found to work at 2200 tonight.
- string findme = " "; findme[0] = 0;
- returnme = gsub(returnme,findme,"\\0");
- };
- return returnme;
+ /* This function is designed to escape strings destined for
+ * use in SQL queries and the like. Specifically, the following
+ * is done to the string passed in:
+ * 1. "\" is replaced with "\\"
+ * 2. "'" is replaced with "\'"
+ * 3. """ (double quote) is replaced with "\""
+ * 4. 0x00 is replaced with "\"+0x00.
+ */
+ string returnme = "";
+ if (s.length() > 0)
+ {
+ returnme = gsub(s,"\\","\\\\");
+ returnme = gsub(returnme,"'", "\\'");
+ returnme = gsub(returnme,"\"","\\\"");
+ // special handling is required to make strings including
+ // 0x00; this is the kludge I found to work at 2200 tonight.
+ string findme = " "; findme[0] = 0;
+ returnme = gsub(returnme,findme,"\\0");
+ };
+ return returnme;
};
string dateflip(string date, const string & sep)
{
- string out;
- try
- {
- strlist temp = split(date,'-');
- out = temp[1]+ sep + temp[2] + sep + temp[0];
- }
- catch (...)
- {
- throw dateflip_exception();
- };
- return out;
+ string out;
+ try
+ {
+ strlist temp = split(date,'-');
+ out = temp[1]+ sep + temp[2] + sep + temp[0];
+ }
+ catch (...)
+ {
+ throw dateflip_exception();
+ };
+ return out;
}; // string dateflip
string http_hextochar(string s)
{
- try
- {
- s = upcase(s);
- unsigned char v = (16 * __ricks_handy_hexits.find(s[0]))
- + __ricks_handy_hexits.find(s[1]);
- return s = v;
- }
- catch (...)
- {
- throw hextrans_exception();
- };
+ try
+ {
+ s = upcase(s);
+ unsigned char v = (16 * __ricks_handy_hexits.find(s[0]))
+ + __ricks_handy_hexits.find(s[1]);
+ return s = v;
+ }
+ catch (...)
+ {
+ throw hextrans_exception();
+ };
}; // string hextochar
string http_chartohex(const string &s)
{
- string out;
- try
- {
- for (long int i=0; i < s.length() ; i++ ) {
- unsigned char v = s[i];
- div_t hexval = div(v,16);
- out += __ricks_handy_hexits[hexval.quot];
- out += __ricks_handy_hexits[hexval.rem];
- }; /* endfor */
- }
- catch (...)
- {
- throw hextrans_exception();
- };
- return out;
+ string out;
+ try
+ {
+ for (long int i=0; i < s.length() ; i++ ) {
+ unsigned char v = s[i];
+ div_t hexval = div(v,16);
+ out += __ricks_handy_hexits[hexval.quot];
+ out += __ricks_handy_hexits[hexval.rem];
+ }; /* endfor */
+ }
+ catch (...)
+ {
+ throw hextrans_exception();
+ };
+ return out;
};// string chartohex()
string http_enhex(const string & s)
{
- string out;
- try
- {
- for (long int i=0; i < s.length() ; i++ ) {
- unsigned char v = s[i];
- div_t hexval = div(v,16);
- out += "%";
- out += __ricks_handy_hexits[hexval.quot];
- out += __ricks_handy_hexits[hexval.rem];
- }; /* endfor */
- }
- catch (...)
- {
- throw hextrans_exception();
- };
- return out;
+ string out;
+ try
+ {
+ for (long int i=0; i < s.length() ; i++ )
+ {
+ unsigned char v = s[i];
+ div_t hexval = div(v,16);
+ out += "%";
+ out += __ricks_handy_hexits[hexval.quot];
+ out += __ricks_handy_hexits[hexval.rem];
+ }; /* endfor */
+ }
+ catch (...)
+ {
+ throw hextrans_exception();
+ };
+ return out;
}; // string enhex()
string http_unhex(string s)
{
- try
- {
- while (s.find('%') != string::npos)
- {
- int where = s.find('%');
- string hexchar = s.substr(where+1,2);
- s.erase(where,3);
- s.insert(where,http_hextochar(hexchar));
- }; /* endwhile */
- }
- catch (...)
- {
- throw hextrans_exception();
- };
- return s;
+ try
+ {
+ while (s.find('%') != string::npos)
+ {
+ int where = s.find('%');
+ string hexchar = s.substr(where+1,2);
+ s.erase(where,3);
+ s.insert(where,http_hextochar(hexchar));
+ }; /* endwhile */
+ }
+ catch (...)
+ {
+ throw hextrans_exception();
+ };
+ return s;
};// string unhex()
=== modified file 'cpp/common/common_rl/common.h'
--- obsolete/Cpp/common/common_rl/common.h 2010-12-25 22:44:22 +0000
+++ cpp/common/common_rl/common.h 2013-08-09 21:47:12 +0000
@@ -20,10 +20,10 @@
#ifndef __ga_common_h
#define __ga_common_h 1
-//#include <stream.h>
#include <string>
#include <map>
#include <vector>
+#include <chrono>
namespace nrtb
{
@@ -39,40 +39,36 @@
** get the time the exception was created and any text the thrower may have
** provided.
**/
- class base_exception: public std::exception
- {
- protected:
- unsigned long int ctime;
- std::string _text;
- public:
- /** Default constructor.
- **
- ** Creates an nrtb_exception recording it's creation time but without
- ** a comment string.
- **/
- base_exception();
- /** Constructs with a comment string.
- **
- ** Creates an nrtb_exception recording it's creation time and storing the
- ** provided string "text" for recall later via the comment method.
- **
- ** This version takes an ISO standard C++ string.
- **/
- base_exception(const std::string & text);
- /// NOP virtual distructor for safe inheritance
- virtual ~base_exception() throw() {};
- /** Stores a comment string.
- **/
- void store(const std::string & s);
- /** Returns the value stored at exception creation.
- **/
- std::string comment();
- /** Returns the unix time the exception was created.
- **/
- unsigned long int creation_time();
+class base_exception: public std::exception
+{
+protected:
+ typedef std::chrono::high_resolution_clock myclock;
+ typedef std::chrono::high_resolution_clock::time_point mark;
+ typedef std::chrono::microseconds ms;
+ mark created {myclock::now()};
+ std::string _text;
+
+public:
+ /// NOP virtual distructor for safe inheritance
+ virtual ~base_exception() throw() {};
+ /** Stores a comment string.
+ **/
+ void store(const std::string & s) { _text = s; };
+ /** Returns the value stored at exception creation.
+ **/
+ std::string comment() { return _text; };
+ /** Returns the time the exception was created.
+ **/
+ mark creation_time() { return created; };
+ /** Returns the age of the exception
+ **/
+ ms age_in_ms()
+ {
+ return std::chrono::duration_cast<ms>(myclock::now() - created);
+ };
};
-// Thrown by gsub() in cases of unexpected error.
+// Thrown by gsub() in cases of unexpectaed error.
class gsub_exception: public nrtb::base_exception {};
// Thrown by split() in cases of unexpected error.
class split_exception: public nrtb::base_exception {};
=== modified file 'cpp/common/common_rl/common_rl_test.cpp'
--- obsolete/Cpp/common/common_rl/common_rl_test.cpp 2011-07-21 22:14:53 +0000
+++ cpp/common/common_rl/common_rl_test.cpp 2013-08-09 21:47:12 +0000
@@ -18,6 +18,7 @@
#include "common.h"
#include <iostream>
+#include <unistd.h>
using namespace std;
@@ -96,6 +97,23 @@
"nrtb::http_unhex()",
nrtb::http_unhex("%4D%69%58%65%44%63%41%73%45") == tstr);
+ try
+ {
+ nrtb::base_exception e;
+ e.store("Test code");
+ usleep(100);
+ throw e;
+ }
+ catch (nrtb::base_exception & e)
+ {
+ returnme += report_test(
+ "nrtb::base_exception::comment()",
+ e.comment() == "Test code");
+ returnme += report_test(
+ "nrtb::base_exception::age_in_ms()",
+ e.age_in_ms().count() > 100 );
+ };
+
cout << "=== nrtb::common_rl unit test complete ===" << endl;
return returnme;
};
\ No newline at end of file
=== modified file 'cpp/common/confreader/Makefile'
--- obsolete/Cpp/common/confreader/Makefile 2012-04-06 12:19:37 +0000
+++ cpp/common/confreader/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,8 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
lib: conftest
@rm -f conf_test.log
@./conftest test=1 test2-2 test2=71.837486 test3="jack danials" --doit
@@ -26,12 +28,12 @@
confreader.o: confreader.h confreader.cpp Makefile
@rm -f confreader.o
- g++ -c confreader.cpp -I../include -std=gnu++0x
+ g++ -c confreader.cpp -I../include ${switches}
conftest: confreader.o conftest.cpp
@rm -f conftest
- g++ -c conftest.cpp -I../include -std=gnu++0x
- g++ -o conftest conftest.o confreader.o ../obj/common.o ../obj/log_setup.o ../obj/base_thread.o -lpthread -lPocoFoundation -lPocoUtil -std=gnu++0x
+ g++ -c conftest.cpp -I../include ${switches}
+ g++ -o conftest conftest.o confreader.o ../obj/common.o ../obj/logger.o -lpthread ${switches}
clean:
@rm -rvf *.o conftest ../include/confreader.h ../obj/confreader.o conf_test.log
=== modified file 'cpp/common/confreader/confreader.cpp'
--- obsolete/Cpp/common/confreader/confreader.cpp 2011-08-13 15:06:08 +0000
+++ cpp/common/confreader/confreader.cpp 2013-08-09 21:47:12 +0000
@@ -21,206 +21,198 @@
#include "confreader.h"
#include <fstream>
#include <iostream>
-#include <common.h>
-#include "Poco/Logger.h"
using namespace std;
using namespace nrtb;
-const std::string logname = "conf_reader";
-
namespace nrtb
{
conf_reader::conf_reader()
{
- Poco::Logger& logger = Poco::Logger::get(logname);
- logger.information("conf_reader instanciated.");
+ // nop constructor
};
-conf_reader::~conf_reader() {};
+conf_reader::~conf_reader()
+{
+ // nop destructor
+};
unsigned int conf_reader::read(const std::string & _filename, bool _clear)
{
- Poco::Logger& logger = Poco::Logger::get(logname);
- logger.information("Reading from \"" + _filename + "\".");
- if (_filename != "") { filename = _filename; };
- if (filename != "")
- {
- try
- {
- ifstream cfile(filename.c_str());
- if (!cfile) throw base_exception();
- if (_clear) values.clear();
- // read the file line by line, ignoring comments.
- char inbuff[16*1024];
- while (cfile)
- {
- cfile.getline(inbuff, 16*1024);
- string in = inbuff;
- // truncate at the start of a comment.
- unsigned long int where = in.find("#");
- while (where != string::npos)
- {
- if (in[where-1] == '\\')
- {
- // comment char was escaped.. ignore.
- where = in.find("#",where+1);
- }
- else
- {
- // truncate the string at this point.
- in.erase(where);
- where = string::npos;
- };
- };
- // see if we can parse what's left.
- in = trim(in);
- unsigned long int split_point = in.find_first_of("\t ");
- if (split_point != string::npos)
- {
- // okay.. get the fields.
- pair arg;
- arg.first = gsub(trim(in.substr(0,split_point)),"\\#","#");
- arg.second = gsub(trim(in.substr(split_point)),"\\#","#");
- // is this an include directive?
- if (arg.first == "*INCLUDE")
- {
- read(arg.second,false);
- }
- else if (arg.first != "")
- {
- values.insert(arg);
- };
- };
- };
- }
- catch (...)
- {
- logger.warning("Problems reading configuration file \""
- + filename + "\"; data may be incomplete.");
- }
- };
- return values.size();
+ if (_filename != "") { filename = _filename; };
+ if (filename != "")
+ {
+ try
+ {
+ ifstream cfile(filename.c_str());
+ if (!cfile) throw base_exception();
+ if (_clear) values.clear();
+ // read the file line by line, ignoring comments.
+ char inbuff[16*1024];
+ while (cfile)
+ {
+ cfile.getline(inbuff, 16*1024);
+ string in = inbuff;
+ // truncate at the start of a comment.
+ unsigned long int where = in.find("#");
+ while (where != string::npos)
+ {
+ if (in[where-1] == '\\')
+ {
+ // comment char was escaped.. ignore.
+ where = in.find("#",where+1);
+ }
+ else
+ {
+ // truncate the string at this point.
+ in.erase(where);
+ where = string::npos;
+ };
+ };
+ // see if we can parse what's left.
+ in = trim(in);
+ unsigned long int split_point = in.find_first_of("\t ");
+ if (split_point != string::npos)
+ {
+ // okay.. get the fields.
+ pair arg;
+ arg.first = gsub(trim(in.substr(0,split_point)),"\\#","#");
+ arg.second = gsub(trim(in.substr(split_point)),"\\#","#");
+ // is this an include directive?
+ if (arg.first == "*INCLUDE")
+ {
+ read(arg.second,false);
+ }
+ else if (arg.first != "")
+ {
+ values.insert(arg);
+ };
+ };
+ };
+ }
+ catch (...)
+ {
+ cerr << "WARNING:Problems reading configuration file \""
+ << filename << "\"; data may be incomplete.";
+ }
+ };
+ return values.size();
};
unsigned int conf_reader::read(int argc, char * argv[],
const string & _filename)
{
- Poco::Logger& logger = Poco::Logger::get(logname);
- logger.information("Reading from command line.");
- clear();
- filename = _filename;
- value_list_type cvars;
- // read values from the command line first.
- for (int i = 0; i < argc; i++)
- {
- string instring = argv[i];
- if (i == 0)
- {
- instring = "__exec_name="+instring;
- };
- strlist t = split(instring,'=');
- if (t.size() > 0)
- {
- // build the new insert pair;
- pair newval;
- newval.first = t[0];
- // assemble the value
- // (allows for including "=" in the argument)
- for (unsigned int l = 1; l < t.size(); l++)
- {
- newval.second += t[l];
- if (l < (t.size() -1) )
- {
- newval.second += "=";
- };
- };
- // store this in the list
- trim(newval.first);
- trim(newval.second);
- cvars.insert(newval);
- // is this a config file name?
- if (newval.first == "configfile")
- {
- filename = newval.second;
- };
- };
- }; // read the command line arguments.
- // read the file args if any.
- read(filename,false);
- // override the first instance of any value found in configs
- // or insert as appropriate.
- iterator c = cvars.begin();
- iterator e = cvars.end();
- while (c != e)
- {
- iterator here = values.find(c->first);
- if (here != values.end())
- {
- here->second = c->second;
- }
- else
- {
- values.insert(*c);
- };
- c++;
+ clear();
+ filename = _filename;
+ value_list_type cvars;
+ // read values from the command line first.
+ for (int i = 0; i < argc; i++)
+ {
+ string instring = argv[i];
+ if (i == 0)
+ {
+ instring = "__exec_name="+instring;
+ };
+ strlist t = split(instring,'=');
+ if (t.size() > 0)
+ {
+ // build the new insert pair;
+ pair newval;
+ newval.first = t[0];
+ // assemble the value
+ // (allows for including "=" in the argument)
+ for (unsigned int l = 1; l < t.size(); l++)
+ {
+ newval.second += t[l];
+ if (l < (t.size() -1) )
+ {
+ newval.second += "=";
};
- std::stringstream message;
- message << "Read " << values.size() << " parameters.";
- logger.information(message.str());
- return values.size();
+ };
+ // store this in the list
+ trim(newval.first);
+ trim(newval.second);
+ cvars.insert(newval);
+ // is this a config file name?
+ if (newval.first == "configfile")
+ {
+ filename = newval.second;
+ };
+ };
+ }; // read the command line arguments.
+ // read the file args if any.
+ read(filename,false);
+ // override the first instance of any value found in configs
+ // or insert as appropriate.
+ iterator c = cvars.begin();
+ iterator e = cvars.end();
+ while (c != e)
+ {
+ iterator here = values.find(c->first);
+ if (here != values.end())
+ {
+ here->second = c->second;
+ }
+ else
+ {
+ values.insert(*c);
+ };
+ c++;
+ };
+ cout << "Read " << values.size() << " parameters.";
+ return values.size();
};
void conf_reader::clear()
{
- values.clear();
+ values.clear();
};
conf_reader::iterator conf_reader::begin()
{
- return values.begin();
+ return values.begin();
};
conf_reader::iterator conf_reader::end()
{
- return values.end();
+ return values.end();
};
bool conf_reader::empty()
{
- return values.empty();
+ return values.empty();
};
unsigned int conf_reader::size()
{
- return values.size();
+ return values.size();
};
strlist conf_reader::all(const std::string & key)
{
- strlist returnme;
- iterator current = values.find(key);
- iterator e = values.end();
- while ((current != e) && (current->first == key))
- {
- returnme.push_back(current->second);
- current++;
- };
- return returnme;
+ strlist returnme;
+ iterator current = values.find(key);
+ iterator e = values.end();
+ while ((current != e) && (current->first == key))
+ {
+ returnme.push_back(current->second);
+ current++;
+ };
+ return returnme;
};
string conf_reader::operator [] (const std::string & key)
{
- iterator res = values.find(key);
- string returnme = "";
- if (res != values.end()) returnme = res->second;
- return returnme;
+ iterator res = values.find(key);
+ string returnme = "";
+ if (res != values.end()) returnme = res->second;
+ return returnme;
};
bool conf_reader::exists(const std::string & key)
{
- return (values.find(key) != values.end());
+ return (values.find(key) != values.end());
};
} // namespace nrtb
=== modified file 'cpp/common/confreader/confreader.h'
--- obsolete/Cpp/common/confreader/confreader.h 2011-08-13 15:06:08 +0000
+++ cpp/common/confreader/confreader.h 2013-08-09 21:47:12 +0000
@@ -16,8 +16,8 @@
**********************************************/
-#ifndef ricklib_confreader_h
-#define ricklib_confreader_h
+#ifndef nrtb_confreader_h
+#define nrtb_confreader_h
#include <string.h>
#include <map>
@@ -25,13 +25,13 @@
#include <string>
#include <fstream>
#include <boost/lexical_cast.hpp>
+#include <common.h>
+#include <logger.h>
#include <singleton.h>
-namespace nrtb
+namespace nrtb
{
-typedef std::vector<std::string> strlist;
-
/** Reads command line and configuration file information.
**
** For this NRTB implementation, this class is implemented as
@@ -47,241 +47,242 @@
**/
class conf_reader
{
- private:
- typedef std::multimap<std::string,std::string> value_list_type;
- value_list_type values;
- std::string filename;
- protected:
- /** Reads and parses a configuration file.
- **
- ** Returns the number of values stored.
- **
- ** The optional parameter _clear when true clears the currently
- ** stored list of values. if false the new values read will be added
- ** to the existing list.
- **
- ** If the file named can not be processed completely, a warning
- ** message is published to cerr.
- **
- ** Configuration files are defined as follows.
- **
- ** 1. Files are read line by line. No value can cross a newline
- ** (and at least in this version) or include one. The good
- ** news is that you are allowed up to 16k for each line.
- **
- ** 2. values are specifed in name/value pairs, one per line, with
- ** the name first, followed by whitespace, followed by the
- ** value. Values may include whitespace. All leading and trailing
- ** whitespace is removed from both the name and the value.
- **
- ** 3. Comments start with a \# symbol; all text following a \# is
- ** ignored. If you need to use \# in a name or value, escape
- ** it with a backslash instead.
- **
- ** 4. Duplicate names are allowed.
- **
- ** 5. Names without values will be stored with "" as the value.
- **
- ** 6. A configuration file may include another configuration file
- ** automatically by the use of the "*INCLUDE" reserved name.
- ** When this name is found, it's value is used as the name of
- ** the new file to be read.
- **/
- unsigned int read(const std::string & _filename = "", bool _clear=true);
- public:
- /// conf_reader iterator, points to a conf_reader::pair
- typedef value_list_type::iterator iterator;
- /// conf_reader::pair is a std::pair<string,string>
- typedef std::pair<std::string,std::string> pair;
- /** No argument constructor; actually calls read() without a filename.
- **/
- conf_reader();
- /** NOP virtual destructor to allow safe inheritance.
- **/
- virtual ~conf_reader();
- /** Reads and parses the command line and the provided file.
- **
- ** Returns the number of values stored. argc and argv are, of
- ** course the same names you used as arguments to main(). Therefore
- ** you can easily read all command line and configuration file
- ** values like this:
- **
- ** int main(int argc, char* argv[])
- **
- ** {
- **
- ** conf_reader config;
- **
- ** config.read(argc,argv,"my_conf_file");
- **
- ** ...
- **
- ** }
- **
- ** See read(filename,_clear) for a discription of how configuration
- ** files are structured and parsed. This method unconditionally
- ** clears the existing value list before starting. For command line
- ** arguments the following rules are true.
- **
- ** 1. The executable name (argv[0]) is stored as a value with the
- ** name "__exec_name".
- **
- ** 2. Command line arguments of the form "name=value" are parsed
- ** stored as named values.
- **
- ** 3. All other command line arguments are stored as names with
- ** value = "".
- **
- ** 4. A command line argument of form "configfile=filename" will
- ** override the filename supplied as an argument to this method.
- **
- ** 5. In the case of duplicate command line arguments, the last one
- ** specified wins.
- **
- ** 6. In the case of names in the configuration file duplicating
- ** names from the command line, the values from the command line
- ** dominate. If there were multiple values for a given name
- ** specified in the file, only the first one (the one returned by
- ** the "[]" operator or get<>() method) is overridden.
- **/
- unsigned int read(int argc, char* argv[],
- const std::string & _filename);
- /// clears the name/value list.
- void clear();
- /// returns an iterator to the first item in the list.
- iterator begin();
- /// returns an iterator one past the end of the list.
- iterator end();
- /// True if there are no values, false otherwise.
- bool empty();
- /// Returns the number of values stored.
- unsigned int size();
- /** Returns the string value matching the supplied name.
- **
- ** NOTE: the use of get<T>(key) or get<T>(key,default) is preferred.
- ** This method is public to allow for specialized handling in the
- ** rare cases where it may be required.
- **
- ** If there are no matching names, "" is returned. Be aware that
- ** "" is a valid value, so you can not use this to verify that
- ** a given name was defined. Use exists() for that.
- **/
- std::string operator [] (const std::string & key);
- /** Returns all values associated with the supplied name.
- **
- ** NOTE: the use of getall<T>(key) is preferred. This method is
- ** public to allow specialized handling in rare case where it
- ** may be required.
- **
- ** If there are no values defined the strlist will be empty.
- **/
- strlist all(const std::string & key);
- /// True if the name exists, false otherwise.
- bool exists(const std::string & key);
- /** Use this to get all matching values.
- **
- ** Usage:
- **
- ** vector<type> mylist = conf_reader_object.getall<type>(key);
- **
- ** type can be any standard type (string, int, double, etc.) or any
- ** type for which the ">>" stream operator is defined. All values
- ** with matching names that can map to the requested type will be
- ** returned. Any that do not map will not be returned.
- **/
- template < class T >
- typename std::vector<T> getall(const std::string & key);
- /** Use this to get the matching value.
- **
- ** Useage:
- **
- ** type myvar = get<type>(key);
- **
- ** type can be any standard type (string, int, double, etc.) or any
- ** type for which the ">>" stream operator is defined. The return
- ** value is initialized to all zeros if no matching name is found or
- ** if the first value with that name does not map to the requested
- ** type. For the numeric types that results in zero being returned,
- ** but be aware that more complex object may be in non-sensible
- ** states if they were not found or could not map. Use exists() to
- ** verify the existance of a given name if needed.
- **/
- template < class T >
- T get(const std::string & key);
- /** Returns the value for the requested key, or the supplied default.
- **
- ** Works exactly like get<>() with the exception that if the key
- ** is not found in the list, the user supplied default value is
- ** returned instead of 0 or an empty string. If the value exists but
- ** can not map to the requested type, 0 or an empty string is
- ** returned for the standard types.
- **/
- template <class T>
- T get(const std::string & key, const T & def);
+private:
+ typedef std::multimap<std::string,std::string> value_list_type;
+ value_list_type values;
+public:
+ /// conf_reader iterator, points to a conf_reader::pair
+ typedef value_list_type::iterator iterator;
+ /// conf_reader::pair is a std::pair<string,string>
+ typedef std::pair<std::string,std::string> pair;
+ /** No argument constructor; actually calls read() without a filename.
+ **/
+ conf_reader();
+ /** NOP virtual destructor to allow safe inheritance.
+ **/
+ virtual ~conf_reader();
+ /** Reads and parses the command line and the provided file.
+ **
+ ** Returns the number of values stored. argc and argv are, of
+ ** course the same names you used as arguments to main(). Therefore
+ ** you can easily read all command line and configuration file
+ ** values like this:
+ **
+ ** int main(int argc, char* argv[])
+ **
+ ** {
+ **
+ ** conf_reader config;
+ **
+ ** config.read(argc,argv,"my_conf_file");
+ **
+ ** ...
+ **
+ ** }
+ **
+ ** See read(filename,_clear) for a discription of how configuration
+ ** files are structured and parsed. This method unconditionally
+ ** clears the existing value list before starting. For command line
+ ** arguments the following rules are true.
+ **
+ ** 1. The executable name (argv[0]) is stored as a value with the
+ ** name "__exec_name".
+ **
+ ** 2. Command line arguments of the form "name=value" are parsed
+ ** stored as named values.
+ **
+ ** 3. All other command line arguments are stored as names with
+ ** value = "".
+ **
+ ** 4. A command line argument of form "configfile=filename" will
+ ** override the filename supplied as an argument to this method.
+ **
+ ** 5. In the case of duplicate command line arguments, the last one
+ ** specified wins.
+ **
+ ** 6. In the case of names in the configuration file duplicating
+ ** names from the command line, the values from the command line
+ ** dominate. If there were multiple values for a given name
+ ** specified in the file, only the first one (the one returned by
+ ** the "[]" operator or get<>() method) is overridden.
+ **/
+ unsigned int read(int argc, char* argv[],
+ const std::string & _filename);
+ /// clears the name/value list.
+ void clear();
+ /// returns an iterator to the first item in the list.
+ iterator begin();
+ /// returns an iterator one past the end of the list.
+ iterator end();
+ /// True if there are no values, false otherwise.
+ bool empty();
+ /// Returns the number of values stored.
+ unsigned int size();
+ /** Returns the string value matching the supplied name.
+ **
+ ** NOTE: the use of get<T>(key) or get<T>(key,default) is preferred.
+ ** This method is public to allow for specialized handling in the
+ ** rare cases where it may be required.
+ **
+ ** If there are no matching names, "" is returned. Be aware that
+ ** "" is a valid value, so you can not use this to verify that
+ ** a given name was defined. Use exists() for that.
+ **/
+ std::string operator [] (const std::string & key);
+ /** Returns all values associated with the supplied name.
+ **
+ ** NOTE: the use of getall<T>(key) is preferred. This method is
+ ** public to allow specialized handling in rare case where it
+ ** may be required.
+ **
+ ** If there are no values defined the strlist will be empty.
+ **/
+ strlist all(const std::string & key);
+ /// True if the name exists, false otherwise.
+ bool exists(const std::string & key);
+ /** Use this to get all matching values.
+ **
+ ** Usage:
+ **
+ ** vector<type> mylist = conf_reader_object.getall<type>(key);
+ **
+ ** type can be any standard type (string, int, double, etc.) or any
+ ** type for which the ">>" stream operator is defined. All values
+ ** with matching names that can map to the requested type will be
+ ** returned. Any that do not map will not be returned.
+ **/
+ template < class T >
+ typename std::vector<T> getall(const std::string & key);
+ /** Use this to get the matching value.
+ **
+ ** Useage:
+ **
+ ** type myvar = get<type>(key);
+ **
+ ** type can be any standard type (string, int, double, etc.) or any
+ ** type for which the ">>" stream operator is defined. The return
+ ** value is initialized to all zeros if no matching name is found or
+ ** if the first value with that name does not map to the requested
+ ** type. For the numeric types that results in zero being returned,
+ ** but be aware that more complex object may be in non-sensible
+ ** states if they were not found or could not map. Use exists() to
+ ** verify the existance of a given name if needed.
+ **/
+ template < class T >
+ T get(const std::string & key);
+ /** Returns the value for the requested key, or the supplied default.
+ **
+ ** Works exactly like get<>() with the exception that if the key
+ ** is not found in the list, the user supplied default value is
+ ** returned instead of 0 or an empty string. If the value exists but
+ ** can not map to the requested type, 0 or an empty string is
+ ** returned for the standard types.
+ **/
+ template <class T>
+ T get(const std::string & key, const T & def);
+private:
+ std::string filename;
+protected:
+ /** Reads and parses a configuration file.
+ **
+ ** Returns the number of values stored.
+ **
+ ** The optional parameter _clear when true clears the currently
+ ** stored list of values. if false the new values read will be added
+ ** to the existing list.
+ **
+ ** If the file named can not be processed completely, a warning
+ ** message is published to cerr.
+ **
+ ** Configuration files are defined as follows.
+ **
+ ** 1. Files are read line by line. No value can cross a newline
+ ** (and at least in this version) or include one. The good
+ ** news is that you are allowed up to 16k for each line.
+ **
+ ** 2. values are specifed in name/value pairs, one per line, with
+ ** the name first, followed by whitespace, followed by the
+ ** value. Values may include whitespace. All leading and trailing
+ ** whitespace is removed from both the name and the value.
+ **
+ ** 3. Comments start with a \# symbol; all text following a \# is
+ ** ignored. If you need to use \# in a name or value, escape
+ ** it with a backslash instead.
+ **
+ ** 4. Duplicate names are allowed.
+ **
+ ** 5. Names without values will be stored with "" as the value.
+ **
+ ** 6. A configuration file may include another configuration file
+ ** automatically by the use of the "*INCLUDE" reserved name.
+ ** When this name is found, it's value is used as the name of
+ ** the new file to be read.
+ **/
+ unsigned int read(const std::string & _filename = "", bool _clear=true);
};
typedef singleton<conf_reader> global_conf_reader;
template < class T >
- typename std::vector<T> conf_reader::getall(const std::string & key)
-{
- strlist tvals = all(key);
- std::vector<T> returnme;
- if (typeid(T) == typeid(std::string))
- {
- // T is a std::string.. we can do this quickly.
- strlist * wl = (strlist *) &returnme;
- *wl = tvals;
- }
- else
- {
- // T is non-string.. will require more playing around.
- unsigned int limit = tvals.size();
- for (unsigned int i = 0; i < limit; i++)
- {
- try
- {
- returnme.push_back(boost::lexical_cast<T>(tvals[i]));
- }
- catch (...) {};
- };
- };
- return returnme;
-};
-
-template < class T >
- T conf_reader::get(const std::string & key)
-{
- conf_reader & me = *this;
- std::string tval = me[key];
- T returnme;
- // initialize the return value to nulls
- // Needed for the numeric types, but bad for strings.
- if (typeid(T) != typeid(std::string))
- {
- // null out the working area (death for strings!)
- memset(&returnme,0,sizeof(T));
- };
- // This does appear to work for all the standard types.
- if (tval != "")
- {
- try
- {
- returnme = boost::lexical_cast<T>(tval);
- }
- catch (...) {};
- };
- return returnme;
-};
-
-template < class T >
- T conf_reader::get(const std::string & key, const T & def)
-{
- if (exists(key)) { return get<T>(key); }
- else { return def; };
+ typename std::vector<T> conf_reader::getall(const std::string & key)
+{
+ strlist tvals = all(key);
+ std::vector<T> returnme;
+ if (typeid(T) == typeid(std::string))
+ {
+ // T is a std::string.. we can do this quickly.
+ strlist * wl = (strlist *) &returnme;
+ *wl = tvals;
+ }
+ else
+ {
+ // T is non-string.. will require more playing around.
+ unsigned int limit = tvals.size();
+ for (unsigned int i = 0; i < limit; i++)
+ {
+ try
+ {
+ returnme.push_back(boost::lexical_cast<T>(tvals[i]));
+ }
+ catch (...) {};
+ };
+ };
+ return returnme;
+};
+
+template < class T >
+ T conf_reader::get(const std::string & key)
+{
+ conf_reader & me = *this;
+ std::string tval = me[key];
+ T returnme;
+ // initialize the return value to nulls
+ // Needed for the numeric types, but bad for strings.
+ if (typeid(T) != typeid(std::string))
+ {
+ // null out the working area (death for strings!)
+ memset(&returnme,0,sizeof(T));
+ };
+ // This does appear to work for all the standard types.
+ if (tval != "")
+ {
+ try
+ {
+ returnme = boost::lexical_cast<T>(tval);
+ }
+ catch (...) {};
+ };
+ return returnme;
+};
+
+template < class T >
+ T conf_reader::get(const std::string & key, const T & def)
+{
+ if (exists(key)) { return get<T>(key); }
+ else { return def; };
};
}; // namespace nrtb
-#endif // ricklib_confreader_h
+#endif // nrtb_confreader_h
=== modified file 'cpp/common/confreader/conftest.cpp'
--- obsolete/Cpp/common/confreader/conftest.cpp 2011-08-13 15:06:08 +0000
+++ cpp/common/confreader/conftest.cpp 2013-08-09 21:47:12 +0000
@@ -19,54 +19,56 @@
/* confreader test program */
#include "confreader.h"
-#include <log_setup.h>
#include <iostream>
-#include "Poco/Logger.h"
-#include "Poco/SimpleFileChannel.h"
-//#include "Poco/AutoPtr.h"
using namespace nrtb;
using namespace std;
+log_queue lq;
+log_file_writer writer(lq, "conf_test.log");
+
int main(int argc, char* argv[])
{
bool set_if_failed = false;
- setup_global_logging("conf_test.log");
- Poco::Logger & log = Poco::Logger::get("conftest");
- log.information("=-=-=-=-=-= conftest Init =-=-=-=-=-=-=");
- global_conf_reader & config = global_conf_reader::get_instance();
+ log_recorder log("config_test",lq);
+ log.info("=-=-=-=-=-= conftest Init =-=-=-=-=-=-=");
+ conf_reader & config = global_conf_reader::get_reference();
+
try
{
- log.information("Starting read");
- config.read(argc,argv,"test.config");
+ log.info("Starting read");
+ config.read(argc,argv,"test.config");
}
catch (...)
{
- set_if_failed = true;
- cerr << "Failed reading the configuration." << endl;
+ set_if_failed = true;
+ cerr << "Failed reading the configuration." << endl;
+ log.severe("Failed reading the configuration.");
};
if (config.size() != 12)
{
- set_if_failed = true;
- cerr << "Did not find 12 parameters." << endl;
+ set_if_failed = true;
+ cerr << "Did not find 12 parameters." << endl;
+ log.severe("Did not find 12 parameters.");
};
// iterator test
try
{
- conf_reader::iterator c = config.begin();
- conf_reader::iterator e = config.end();
- while (c != e)
- {
- cout << "\t\"" << c->first << "\"=\"" << c->second
- << "\"" << endl;
- c++;
- };
+ conf_reader::iterator c = config.begin();
+ conf_reader::iterator e = config.end();
+ while (c != e)
+ {
+ cout << "\t\"" << c->first << "\"=\"" << c->second
+ << "\"" << endl;
+ c++;
+ };
}
catch (...)
{
- set_if_failed = true;
- cerr << "Iterator test failed." << endl;
- };
+ set_if_failed = true;
+ cerr << "Iterator test failed." << endl;
+ log.severe("Iterator test failed.");
+};
// template test.
int test = config.get<int>("test",-1);
int test2 = config.get<int>("test2",-1);
@@ -74,56 +76,60 @@
double test4 = config.get<double>("test",-1);
double test5 = config.get<double>("test2",-1);
cout << "(int) test = " << test
- << "\n(int) test2 = " << test2
- << "\n(string) test3 = \"" << test3 << "\""
- << "\n(double) test = " << test4
- << "\n(double) test2 = " << test5
- << endl;
+ << "\n(int) test2 = " << test2
+ << "\n(string) test3 = \"" << test3 << "\""
+ << "\n(double) test = " << test4
+ << "\n(double) test2 = " << test5
+ << endl;
if (
- (test != 1) or (test2 != 0)
- or (test3 != "jack danials")
- or (test4 != 1.0) or (test5 != 71.837486)
+ (test != 1) or (test2 != 0)
+ or (test3 != "jack danials")
+ or (test4 != 1.0) or (test5 != 71.837486)
)
{
- set_if_failed = true;
- cerr << "** Template test failed." << endl;
+ set_if_failed = true;
+ cerr << "** Template test failed." << endl;
+ log.severe("** Template test failed.");
};
// exists test.
cout << "?var \"--doit\" exists? "
- << (config.exists("--doit") ? "Yes" : "No")
- << endl;
+ << (config.exists("--doit") ? "Yes" : "No")
+ << endl;
if (!config.exists("--doit"))
{
- set_if_failed = true;
- cerr << "exists() test failed." << endl;
+ set_if_failed = true;
+ cerr << "exists() test failed." << endl;
+ log.severe("exists() test failed.");
};
vector<int> intlist = config.getall<int>("test");
cout << "valid int \"test\" values:" << endl;
for (unsigned int i=0; i < intlist.size(); i++)
{
- cout << "\t" << i << ": " << intlist[i] << endl;
+ cout << "\t" << i << ": " << intlist[i] << endl;
};
if (intlist.size() != 2)
{
- set_if_failed = true;
- cerr << "getall<int>() did not find 2 parameters." << endl;
+ set_if_failed = true;
+ cerr << "getall<int>() did not find 2 parameters." << endl;
+ log.severe("getall<int>() did not find 2 parameters.");
};
strlist strings = config.getall<string>("test");
cout << "valid string \"test\" values:" << endl;
for (unsigned int i=0; i < strings.size(); i++)
{
- cout << "\t" << i << ": " << strings[i] << endl;
+ cout << "\t" << i << ": " << strings[i] << endl;
};
if (strings.size() != 3)
{
- set_if_failed = true;
- cerr << "getall<string>() did not find 3 parameters." << endl;
+ set_if_failed = true;
+ cerr << "getall<string>() did not find 3 parameters." << endl;
+ log.severe("getall<string>() did not find 3 parameters.");
};
if (set_if_failed)
{
- cerr << "** ntrb::conf_reader UNIT TEST FAILED. **" << endl;
- log.fatal("UNIT TEST FAILED");
+ cerr << "** ntrb::conf_reader UNIT TEST FAILED. **" << endl;
+ log.critical("UNIT TEST FAILED");
};
- log.information("Run Complete");
+ log.info("Run Complete");
return set_if_failed;
};
=== modified file 'cpp/common/linear_queue/Makefile'
--- obsolete/Cpp/common/linear_queue/Makefile 2012-04-06 17:18:50 +0000
+++ cpp/common/linear_queue/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,8 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
lib: linear_queue_test
@./linear_queue_test
@cp -v linear_queue.h ../include
@@ -23,8 +25,8 @@
linear_queue_test: linear_queue.h linear_queue_test.cpp
@rm -f linear_queue_test
- g++ -c linear_queue_test.cpp -I../include -std=gnu++0x
- g++ -o linear_queue_test linear_queue_test.o ../obj/common.o ../obj/base_thread.o -lpthread -std=gnu++0x
+ g++ -c linear_queue_test.cpp -I../include ${switches}
+ g++ -o linear_queue_test linear_queue_test.o -lpthread ${switches}
clean:
@rm -rvf *.o linear_queue_test ../include/linear_queue.h *.log ../obj/linear_queue.o
=== modified file 'cpp/common/linear_queue/linear_queue.h'
--- obsolete/Cpp/common/linear_queue/linear_queue.h 2011-10-07 00:01:15 +0000
+++ cpp/common/linear_queue/linear_queue.h 2013-08-09 21:47:12 +0000
@@ -19,9 +19,11 @@
#ifndef nrtb_linear_queue_h
#define nrtb_linear_queue_h
-#include <iostream>
-#include <base_thread.h>
-#include <list>
+#include <atomic>
+#include <mutex>
+#include <condition_variable>
+#include <queue>
+#include <abs_queue.h>
namespace nrtb
{
@@ -45,120 +47,7 @@
* passing data to another set of threads.
********************************************************/
template <class T>
-class linear_queue
-{
-public:
- class queue_not_ready: public base_exception {};
-
- /*********************************************
- * creates the queue with the specified
- * number of elements.
- *********************************************/
- linear_queue();
-
- /*********************************************
- * releases all items in the queue
- *********************************************/
- virtual ~linear_queue();
-
- /*********************************************
- * Puts an item in the queue.
- *********************************************/
- void push(T item);
-
- /*********************************************
- * Pops the next item off the queue, blocking
- * if needed until an item becomes available.
- *********************************************/
- T pop();
-
- /*********************************************
- * puts the queue in shutdown mode.
- *********************************************/
- void shutdown();
-
- // returns the number of items in the queue
- int size();
- // clears the buffer, data will be discarded.
- void clear();
-
-protected:
-
- std::list<T> buffer;
- cond_variable buffer_lock;
- bool ready;
-};
-
-template <class T>
-linear_queue<T>::linear_queue()
-{
- ready = true;
-};
-
-template <class T>
-linear_queue<T>::~linear_queue()
-{
-};
-
-template <class T>
-void linear_queue<T>::push(T item)
-{
- if (ready)
- {
- scope_lock lock(buffer_lock);
- buffer.push_back(item);
- buffer_lock.signal();
- }
- else
- {
- queue_not_ready e;
- throw e;
- }
-};
-
-template <class T>
-T linear_queue<T>::pop()
-{
- scope_lock lock(buffer_lock);
- while (buffer.empty() && ready)
- buffer_lock.wait();
- if (!ready)
- {
- queue_not_ready e;
- throw e;
- };
- T returnme = buffer.front();
- buffer.pop_front();
- return returnme;
-};
-
-template <class T>
-void linear_queue<T>::shutdown()
-{
- try
- {
- scope_lock lock(buffer_lock);
- ready = false;
- buffer_lock.broadcast_signal();
- buffer.clear();
- }
- catch (...) {}
-}
-
-
-template <class T>
-int linear_queue<T>::size()
-{
- scope_lock lock(buffer_lock);
- return buffer.size();
-};
-
-template <class T>
-void linear_queue<T>::clear()
-{
- scope_lock lock(buffer_lock);
- buffer.clear();
-};
+class linear_queue : public abs_queue<T,std::queue<T>> {};
} // namespace nrtb
=== modified file 'cpp/common/linear_queue/linear_queue_test.cpp'
--- obsolete/Cpp/common/linear_queue/linear_queue_test.cpp 2011-10-07 00:01:15 +0000
+++ cpp/common/linear_queue/linear_queue_test.cpp 2013-08-09 21:47:12 +0000
@@ -15,81 +15,45 @@
along with NRTB. If not, see <http://www.gnu.org/licenses/>.
**********************************************/
-
+
+#include <unistd.h> // included for usleep()
#include <string>
#include <iostream>
#include "linear_queue.h"
-#include <boost/shared_ptr.hpp>
+#include <memory>
+#include <atomic>
+#include <future>
using namespace nrtb;
using namespace std;
typedef linear_queue<int> test_queue;
-typedef boost::shared_ptr<test_queue> queue_p;
+typedef shared_ptr<test_queue> queue_p;
-class consumer_task: public thread
+int consumer_task(string name, queue_p input)
{
-public:
-
- consumer_task(string n, queue_p buffer)
- {
- name = n;
- input = buffer;
- count = 0;
- };
-
- ~consumer_task()
- {
- cout << ">> in " << name << "::~consumer_task()" << endl;
- try
- {
- this->thread::~thread();
- input.reset();
- }
- catch (...) {};
- cout << "<< leaving " << name << "::~consumer_task()" << endl;
- };
-
- int get_count() { return count; };
-
- void run()
- {
- try
- {
- while (true)
- {
- int num = input->pop();
- {
- static mutex console;
- scope_lock lock(console);
- cout << name << " picked up " << num
- << endl;
- };
- count++;
- lastnum = num;
- yield();
- }
- }
- catch (...) {};
- };
-
-protected:
- // link to the feed queue
- queue_p input;
- // a name to report
- string name;
- // number of items processed
- int count;
- // last number caught
- int lastnum;
+ bool ready {true};
+ int count {0};
+ try
+ {
+ while (ready)
+ {
+ int num = input->pop();
+ count++;
+ usleep(1);
+ }
+ }
+ catch (...)
+ {
+ // exit if we get any exception.
+ ready = false;
+ };
+ return count;
};
-typedef boost::shared_ptr<consumer_task> task_p;
-
-
int main()
{
- int er_count = 0;
+ cout << "***** linear_queue unit test ******" << endl;
/************************************************
* Load queue and then cook it down...
***********************************************/
@@ -97,14 +61,15 @@
queue_p q1(new test_queue());
for (int i=0; i<100; i++)
{
- q1->push(i);
+ q1->push(i);
};
- // the queue should be loaded with 50-99
+ // the queue should be loaded with 0-99
// attach a thread and process it.
- task_p p1(new consumer_task("task 1",q1));
- p1->start();
+ auto t1 = async(launch::async,consumer_task,"task 1",q1);
while (q1->size()) usleep(100);
- cout << "cp 1 " << p1->get_count() << endl;
+ cout << "cp 1 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
/************************************************
* now that the preload is exhasted, shove items
* in one at a time to make sure each is picked
@@ -112,40 +77,42 @@
***********************************************/
for (int i=200; i<225; i++)
{
- q1->push(i);
- usleep(100);
+ q1->push(i);
+ usleep(100);
};
- cout << "cp 2 " << p1->get_count() << endl;
+ cout << "cp 2 "
+ << q1->in_count << ":"
+ << q1->out_count << endl;
/************************************************
* Last check; attach a second thread to the queue
* and make sure both are servicing it.
***********************************************/
- task_p p2(new consumer_task("task 2",q1));
- p2->start();
+ auto t2 = async(launch::async,consumer_task,"task 2",q1);
for (int i=300; i<325; i++)
{
- q1->push(i);
+ q1->push(i);
};
while (q1->size()) usleep(100);
// shut it all down
q1->shutdown();
- p1->join();
- p2->join();
// important numbers
- int tot_items = p1->get_count() + p2->get_count();
- int p1_items = p1->get_count() - 125;
- int p2_items = p2->get_count();
- // release she threads and queues.
- p1.reset();
- p2.reset();
+ int t1_count = t1.get();
+ int t2_count = t2.get();
+ int q1_in = q1->in_count;
+ int q1_out = q1->out_count;
+ // release the queues.
q1.reset();
// do some reporting.
cout << "cp 3 "
- << tot_items
- << " [125 + (" << p1_items
- << " + " << p2_items
- << ")]" << endl;
- bool passed = (tot_items == 150);
+ << q1_in << ":" << q1_out
+ << " t1=" << t1_count
+ << " t2=" << t2_count
+ << endl;
+ bool passed = (q1_in == q1_out)
+ and (q1_out == (t1_count + t2_count));
+ cout << "***** linear_queue TEST "
+ << (passed ? "PASSED" : "FAILED")
+ << " ******" << endl;
// inverted logic needed because 0 is good for
// return codes.
return !passed;
=== modified file 'cpp/common/logger/Makefile'
--- obsolete/Cpp/common/logger/Makefile 2012-04-06 17:42:05 +0000
+++ cpp/common/logger/Makefile 2013-08-09 21:47:12 +0000
@@ -1,5 +1,5 @@
#***********************************************
-#This file is part of the NRTB project (https://launchpad.net/nrtb).
+# This file is part of the NRTB project (https://launchpad.net/nrtb).
#
# NRTB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,27 +16,25 @@
#
#***********************************************
-lib: log_test
- @echo "Testing..."
- @rm -f test_output.log
- @./log_test
- @grep "Program run complete." test_output.log
- @cp -fv log_setup.h ../include
- @cp -fv log_setup.o ../obj
-
-
-log_setup.o: log_setup.h log_setup.cpp Makefile
- @rm -f log_setup.o
- g++ -c log_setup.cpp -I ../include -std=gnu++0x
-
-log_test: log_setup.o log_test.cpp Makefile
- @rm -vf log_test
- g++ -c log_test.cpp -I../include -std=gnu++0x
- g++ -o log_test log_setup.o log_test.o -lPocoFoundation -std=gnu++0x
-# g++ -g common_test.cpp -idirafter . -o common_test
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
+lib: logger_test
+ @./logger_test
+ @cp -v logger.h ../include/
+ @cp -v logger.o ../obj/
+ @echo build complete
+
+logger_test: logger.o logger_test.cpp
+ @rm -f logger_test
+ g++ -c -O3 logger_test.cpp -I ../include ${switches}
+ g++ -o logger_test logger_test.o logger.o -lpthread ${switches}
+
+
+logger.o: logger.cpp logger.h Makefile
+ @rm -f logger.o
+ g++ -c -O3 logger.cpp -I ../include ${switches}
clean:
- @rm -vf *.o log_test ../include/log_setup.h ../obj/log_setup.o test_output.log
-
-
+ @rm -vf *.o ../include/logger.h logger_test
+ @echo all objects and executables have been erased.
=== added file 'cpp/common/logger/logger.cpp'
--- cpp/common/logger/logger.cpp 1970-01-01 00:00:00 +0000
+++ cpp/common/logger/logger.cpp 2013-08-09 21:47:12 +0000
@@ -0,0 +1,141 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+
+// see base_socket.h for documentation
+
+#include "logger.h"
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+#include <ctime>
+#include <unistd.h>
+
+namespace nrtb
+{
+
+std::string sev2text(log_sev s)
+{
+ std::string returnme;
+ switch (s)
+ {
+ case log_sev::critical : returnme = "CRITICAL"; break;
+ case log_sev::severe : returnme = "SEVERE"; break;
+ case log_sev::warning : returnme = "WARNING"; break;
+ case log_sev::info : returnme = "INFO"; break;
+ case log_sev::trace : returnme = "TRACE"; break;
+ default: returnme = "Undefined";
+ };
+ return returnme;
+};
+
+log_record::log_record(log_sev s, std::string c, std::string m)
+{
+ created = std::time(NULL);
+ severity = s;
+ component = c;
+ message = m;
+};
+
+void log_recorder::operator()(log_sev sev, std::string msg)
+{
+ log_record tr(sev, component, msg);
+ my_queue.push(tr);
+};
+
+void log_recorder::critical(std::string msg)
+{
+ (*this)(log_sev::critical,msg);
+};
+
+void log_recorder::severe(std::string msg)
+{
+ (*this)(log_sev::severe, msg);
+};
+
+void log_recorder::warning(std::string msg)
+{
+ (*this)(log_sev::warning, msg);
+};
+
+void log_recorder::info(std::string msg)
+{
+ (*this)(log_sev::info, msg);
+};
+
+void log_recorder::trace(std::string msg)
+{
+ (*this)(log_sev::trace, msg);
+};
+
+log_file_writer::log_file_writer(log_queue& queue, std::string filename)
+ : myqueue(queue)
+{
+ // start the writer
+ writer_process =
+ std::thread(log_file_writer::writer_thread,
+ std::ref(queue),filename);
+};
+
+void log_file_writer::close()
+{
+ // Hang around long enough to drain the queue.
+ while (myqueue.size())
+ usleep(100);
+ // Shutdown the queue, terminate the worker thread.
+ myqueue.shutdown();
+};
+
+log_file_writer::~log_file_writer()
+{
+ close();
+ // Wait for the worker to close down.
+ if (writer_process.joinable())
+ writer_process.join();
+};
+
+void log_file_writer::writer_thread(log_queue& q, std::string fname)
+{
+ bool done {false};
+ std::ofstream output;
+ output.open(fname);
+ while (!done)
+ {
+ try
+ {
+ log_record record = q.pop();
+ std::tm tm = *std::localtime(&record.created);
+ std::stringstream s;
+ s << tm.tm_year + 1900
+ << "-" << tm.tm_mon + 1
+ << "-" << tm.tm_mday
+ << ":" << tm.tm_hour
+ << ":" << tm.tm_min
+ << ":" << tm.tm_sec
+ << "\t" << sev2text(record.severity)
+ << "\t" << record.component
+ << "\t" << record.message;
+ output << s.str()
+ << std::endl;
+ }
+ catch (...) { done = true; };
+ };
+ output.close();
+};
+
+} // namqespace nrtb
+
=== added file 'cpp/common/logger/logger.h'
--- cpp/common/logger/logger.h 1970-01-01 00:00:00 +0000
+++ cpp/common/logger/logger.h 2013-08-09 21:47:12 +0000
@@ -0,0 +1,76 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+
+#ifndef logger_header
+#define logger_header
+
+#include <string>
+#include <chrono>
+#include <thread>
+#include <ctime>
+#include <linear_queue.h>
+
+namespace nrtb
+{
+
+enum class log_sev {critical,severe,warning,info,trace};
+
+std::string sev2text(log_sev s);
+
+struct log_record
+{
+ log_record(log_sev s, std::string c, std::string m);
+ std::time_t created;
+ log_sev severity;
+ std::string component;
+ std::string message;
+};
+
+typedef linear_queue<log_record> log_queue;
+
+class log_recorder
+{
+public:
+ log_recorder(std::string comp, log_queue & queue):
+ component(comp), my_queue(queue) {};
+ void operator () (log_sev sev, std::string msg);
+ void critical(std::string msg);
+ void severe(std::string msg);
+ void warning(std::string msg);
+ void info(std::string msg);
+ void trace(std::string msg);
+private:
+ log_queue & my_queue;
+ std::string component;
+};
+
+class log_file_writer
+{
+public:
+ log_file_writer(log_queue & queue, std::string filename);
+ ~log_file_writer();
+ void close();
+private:
+ log_queue & myqueue;
+ std::thread writer_process;
+ static void writer_thread(log_queue & q, std::string fname);
+};
+
+} // namepace nrtb
+
+#endif // logger_header
=== added file 'cpp/common/logger/logger_test.cpp'
--- cpp/common/logger/logger_test.cpp 1970-01-01 00:00:00 +0000
+++ cpp/common/logger/logger_test.cpp 2013-08-09 21:47:12 +0000
@@ -0,0 +1,105 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+
+#include "logger.h"
+#include <sstream>
+#include <iostream>
+#include <boost/concept_check.hpp>
+
+using namespace nrtb;
+using namespace std;
+
+int ecount {0};
+
+string stext_test(string a, log_sev b)
+{
+ stringstream s;
+ s << a << " " << (a == sev2text(b) ? "passed" : "failed");
+ if (a != sev2text(b)) ecount++;
+ return s.str();
+};
+
+int main()
+{
+ cout << "=========== logger unit test ============="
+ << endl;
+
+ log_queue test_logger;
+ log_recorder log("Unit_Test",test_logger);
+ log_file_writer writer(test_logger,"test_log.log");
+
+ log.trace("Starting");
+ for(auto i= 0; i<10; i++)
+ {
+ stringstream s;
+ s << "Log entry " << i;
+ log(log_sev::info,s.str());
+ };
+
+ log.trace("sev2test() testing");
+ log.info(stext_test("CRITICAL",log_sev::critical));
+ log.info(stext_test("SEVERE",log_sev::severe));
+ log.info(stext_test("WARNING",log_sev::warning));
+ log.info(stext_test("INFO",log_sev::info));
+ log.info(stext_test("TRACE",log_sev::trace));
+
+ log.trace("Shutting down");
+ writer.close();
+
+ bool good = (test_logger.in_count == test_logger.out_count);
+ good = good and (ecount == 0);
+
+ // test status billboard
+ cout << test_logger.in_count
+ << " : " << test_logger.out_count
+ << " : " << ecount
+ << endl;
+ if (!good)
+ cout << "Errors reported.. check log file." << endl;
+ cout << "=========== tcp_socket and server test complete ============="
+ << endl;
+
+ return !good; // return code has reversed values.
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
=== modified file 'cpp/common/point/Makefile'
--- obsolete/Cpp/common/point/Makefile 2012-04-06 17:42:40 +0000
+++ cpp/common/point/Makefile 2013-08-09 21:47:12 +0000
@@ -16,17 +16,16 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
lib: common_test Makefile
@echo "(2,3.5,7)" | ./common_test
@cp -v triad.h ../include
@echo nrtb::triad build complete
-../include/common.h:
- @cd ../common_rl; make lib
-
-common_test: common_test.cpp triad.h Makefile ../include/common.h
+common_test: common_test.cpp triad.h Makefile
@rm -vf common_test
- g++ -O3 common_test.cpp -I ../include ../obj/common.o -o common_test -std=gnu++0x
+ g++ -O3 common_test.cpp -I ../include ../obj/common.o -o common_test ${switches}
clean:
@rm -vf *.o common_test ../include/triad.h
=== modified file 'cpp/common/point/common_test.cpp'
--- obsolete/Cpp/common/point/common_test.cpp 2011-07-27 02:27:23 +0000
+++ cpp/common/point/common_test.cpp 2013-08-09 21:47:12 +0000
@@ -32,8 +32,8 @@
cout << "\t" << prompt << " = " << val << endl;
if (val != right)
{
- ec++;
- cerr << "\t\tTest Failed: Answer should be " << val << endl;
+ ec++;
+ cerr << "\t\tTest Failed: Answer should be " << val << endl;
}
return ec;
};
@@ -43,75 +43,75 @@
cout << "\t" << prompt << " = " << val << endl;
if (val != right)
{
- ec++;
- cerr << "\t\tTest Failed: Answer should be " << val << endl;
+ ec++;
+ cerr << "\t\tTest Failed: Answer should be " << val << endl;
}
return ec;
};
int main()
{
- ld_triad a(1,2,3);
- ld_triad b(3,2,1);
- int returnme = 0;
+ ld_triad a(1,2,3);
+ ld_triad b(3,2,1);
+ int returnme = 0;
- cout << setprecision(10);
- cout << "=== nrtb::triad Unit Test ===" << endl;
- cout << "\ta = " << a << "; b = " << b << endl;
- // basic operations tests
- returnme = test_triad("a + b",a + b,ld_triad(4,4,4),returnme);
- returnme = test_triad("a - b",a - b,ld_triad(-2,0,2),returnme);
- returnme = test_triad("a * b",a * b,ld_triad(3,4,3),returnme);
- returnme = test_triad("a / b",a / b,ld_triad(1.0d/(long double) 3.0,1,3),returnme);
- returnme = test_triad("a += b; a",a += b,ld_triad(4,4,4),returnme);
- returnme = test_triad("a -= b; a",a -= b,ld_triad(1,2,3),returnme);
- returnme = test_triad("a *= b; a",a *= b,ld_triad(3,4,3),returnme);
- returnme = test_triad("a /= b; a",a /= b,ld_triad(1,2,3),returnme);
- // power test
- returnme = test_triad("a.pow(b)",a.pow(b),ld_triad(1,4,3),returnme);
- // range test
- ld_triad t = b - a;
- t *= t;
- long double r = sqrt(t.x + t.y + t.z);
- returnme = test_ld("a.range(b)",a.range(b),r,returnme);
- // magnatude test
- returnme = test_ld("a.magnatude()",a.magnatude(),a.range(0),returnme);
- // boolean tests
- returnme = test_ld("a == a",a == a,1,returnme);
- returnme = test_ld("a == b",a == b,0,returnme);
- returnme = test_ld("a != b",a != b,1,returnme);
- returnme = test_ld("a != a",a != a,0,returnme);
- // point/scalar operations
- returnme = test_triad("a + 2",a + 2,ld_triad(3,4,5),returnme);
- returnme = test_triad("a - 2",a - 2,ld_triad(-1,0,1),returnme);
- returnme = test_triad("a * 2",a * 2,ld_triad(2,4,6),returnme);
- returnme = test_triad("a / 2",a / 2,ld_triad(0.5,1,1.5),returnme);
- returnme = test_triad("a += 2",a += 2,ld_triad(3,4,5),returnme);
- returnme = test_triad("a -= 2",a -= 2,ld_triad(1,2,3),returnme);
- returnme = test_triad("a *= 2",a *= 2,ld_triad(2,4,6),returnme);
- returnme = test_triad("a /= 2",a /= 2,ld_triad(1,2,3),returnme);
- returnme = test_triad("a.pow(2)",a.pow(2),ld_triad(1,4,9),returnme);
- // normalization test
- cout << "\ta.normalize() = " << a.normalize() << endl;
- returnme = test_ld("a.normalize().magnatude()",a.normalize().magnatude(),1.0,returnme);
- // dot and vector product tests.
- returnme = test_ld("a.dot_product(b)",a.dot_product(b),10,returnme);
- returnme = test_triad("a.vector_product(b)",a.vector_product(b),
- ld_triad(-4,8,-4),returnme);
- // string i/o tests, assumes "2,3.5,7) is input.
- cout << "\tInput a new value for b \"(2,3.5,7)\": " << flush;
- cin >> b; cout << endl;
- returnme = test_triad("b",b,ld_triad(2,3.5,7),returnme);
- returnme = test_triad("b.from_str(b.to_str(10))",
- b.from_str(b.to_str(10)),ld_triad(2,3.5,7),returnme);
- // report errors, if any
- if (returnme)
- {
- cerr << "There were " << returnme
- << " error(s) found." << endl;
- }
- cout << "=== nrtb::triad Unit Test Complete ===" << endl;
- // return the error count as the exit code
- return returnme;
+ cout << setprecision(10);
+ cout << "=== nrtb::triad Unit Test ===" << endl;
+ cout << "\ta = " << a << "; b = " << b << endl;
+ // basic operations tests
+ returnme = test_triad("a + b",a + b,ld_triad(4,4,4),returnme);
+ returnme = test_triad("a - b",a - b,ld_triad(-2,0,2),returnme);
+ returnme = test_triad("a * b",a * b,ld_triad(3,4,3),returnme);
+ returnme = test_triad("a / b",a / b,ld_triad(1.0d/(long double) 3.0,1,3),returnme);
+ returnme = test_triad("a += b; a",a += b,ld_triad(4,4,4),returnme);
+ returnme = test_triad("a -= b; a",a -= b,ld_triad(1,2,3),returnme);
+ returnme = test_triad("a *= b; a",a *= b,ld_triad(3,4,3),returnme);
+ returnme = test_triad("a /= b; a",a /= b,ld_triad(1,2,3),returnme);
+ // power test
+ returnme = test_triad("a.pow(b)",a.pow(b),ld_triad(1,4,3),returnme);
+ // range test
+ ld_triad t = b - a;
+ t *= t;
+ long double r = sqrt(t.x + t.y + t.z);
+ returnme = test_ld("a.range(b)",a.range(b),r,returnme);
+ // magnatude test
+ returnme = test_ld("a.magnatude()",a.magnatude(),a.range(0),returnme);
+ // boolean tests
+ returnme = test_ld("a == a",a == a,1,returnme);
+ returnme = test_ld("a == b",a == b,0,returnme);
+ returnme = test_ld("a != b",a != b,1,returnme);
+ returnme = test_ld("a != a",a != a,0,returnme);
+ // point/scalar operations
+ returnme = test_triad("a + 2",a + 2,ld_triad(3,4,5),returnme);
+ returnme = test_triad("a - 2",a - 2,ld_triad(-1,0,1),returnme);
+ returnme = test_triad("a * 2",a * 2,ld_triad(2,4,6),returnme);
+ returnme = test_triad("a / 2",a / 2,ld_triad(0.5,1,1.5),returnme);
+ returnme = test_triad("a += 2",a += 2,ld_triad(3,4,5),returnme);
+ returnme = test_triad("a -= 2",a -= 2,ld_triad(1,2,3),returnme);
+ returnme = test_triad("a *= 2",a *= 2,ld_triad(2,4,6),returnme);
+ returnme = test_triad("a /= 2",a /= 2,ld_triad(1,2,3),returnme);
+ returnme = test_triad("a.pow(2)",a.pow(2),ld_triad(1,4,9),returnme);
+ // normalization test
+ cout << "\ta.normalize() = " << a.normalize() << endl;
+ returnme = test_ld("a.normalize().magnatude()",a.normalize().magnatude(),1.0,returnme);
+ // dot and vector product tests.
+ returnme = test_ld("a.dot_product(b)",a.dot_product(b),10,returnme);
+ returnme = test_triad("a.vector_product(b)",a.vector_product(b),
+ ld_triad(-4,8,-4),returnme);
+ // string i/o tests, assumes "2,3.5,7) is input.
+ cout << "\tInput a new value for b \"(2,3.5,7)\": " << flush;
+ cin >> b; cout << endl;
+ returnme = test_triad("b",b,ld_triad(2,3.5,7),returnme);
+ returnme = test_triad("b.from_str(b.to_str(10))",
+ b.from_str(b.to_str(10)),ld_triad(2,3.5,7),returnme);
+ // report errors, if any
+ if (returnme)
+ {
+ cerr << "There were " << returnme
+ << " error(s) found." << endl;
+ }
+ cout << "=== nrtb::triad Unit Test Complete ===" << endl;
+ // return the error count as the exit code
+ return returnme;
};
=== modified file 'cpp/common/point/triad.h'
--- obsolete/Cpp/common/point/triad.h 2011-07-27 02:27:23 +0000
+++ cpp/common/point/triad.h 2013-08-09 21:47:12 +0000
@@ -43,265 +43,265 @@
template <class T>
struct triad
{
- /// X coordinate
- T x;
- /// Y coordinate
- T y;
- /// Z coordinate
- T z;
+ /// X coordinate
+ T x;
+ /// Y coordinate
+ T y;
+ /// Z coordinate
+ T z;
- /** Constructor.
- **
- ** An easy way to create a point at the origin would be
- ** "triad<T> a;".
- **/
- triad(T _x=0, T _y=0, T _z=0);
- triad<T> operator + (const triad<T> & a);
- triad<T> operator - (const triad<T> & a);
- triad<T> operator * (const triad<T> & a);
- triad<T> operator / (const triad<T> & a);
- triad<T> operator += (const triad<T> & a);
- triad<T> operator -= (const triad<T> & a);
- triad<T> operator *= (const triad<T> & a);
- triad<T> operator /= (const triad<T> & a);
- /// returns (pow(x,a.x),pow(y,a.y),pow(z,a.z)).
- triad<T> pow(const triad<T> & a);
- triad<T> operator + (const T & a);
- triad<T> operator - (const T & a);
- triad<T> operator * (const T & a);
- triad<T> operator / (const T & a);
- triad<T> operator += (const T & a);
- triad<T> operator -= (const T & a);
- triad<T> operator *= (const T & a);
- triad<T> operator /= (const T & a);
- /// returns (pow(x,a),pow(y,a),pow(z,a)).
- triad<T> pow(const T & a);
- /** Returns a normalized version of the triad.
- **
- ** Normalization in this case refers to an operation resulting in a
- ** traid where the magnatude of the vector is 1.0 while maintaining the
- ** same angular component. For example, given triad<float> a = (1,2,3),
- ** a.normalize() = (0.267,0.534,0.802). Of course, the original triad
- ** is not modified.
- **
- ** Normalized triads are very useful when calcuating force or
- ** accelleration vectors, for example.
- **/
- triad<T> normalize();
- /// Returns the distance between *this and the supplied argument.
- T range(const triad<T> & a);
- /// Returns the magnatude of the vector.
- T magnatude();
- /// Returns the dot (scalar) product of two triads
- T dot_product(const triad<T> & a);
- /// Returns the vector product of two triads
- triad<T> vector_product(const triad<T> & a);
- bool operator == (const triad<T> & a);
- bool operator != (const triad<T> & a);
- /// Loads from a std::string.
- triad<T> from_str(const std::string & a);
- /// Returns a std::string representation.
- std::string to_str(int precision=6);
+ /** Constructor.
+ **
+ ** An easy way to create a point at the origin would be
+ ** "triad<T> a;".
+ **/
+ triad(T _x=0, T _y=0, T _z=0);
+ triad<T> operator + (const triad<T> & a);
+ triad<T> operator - (const triad<T> & a);
+ triad<T> operator * (const triad<T> & a);
+ triad<T> operator / (const triad<T> & a);
+ triad<T> operator += (const triad<T> & a);
+ triad<T> operator -= (const triad<T> & a);
+ triad<T> operator *= (const triad<T> & a);
+ triad<T> operator /= (const triad<T> & a);
+ /// returns (pow(x,a.x),pow(y,a.y),pow(z,a.z)).
+ triad<T> pow(const triad<T> & a);
+ triad<T> operator + (const T & a);
+ triad<T> operator - (const T & a);
+ triad<T> operator * (const T & a);
+ triad<T> operator / (const T & a);
+ triad<T> operator += (const T & a);
+ triad<T> operator -= (const T & a);
+ triad<T> operator *= (const T & a);
+ triad<T> operator /= (const T & a);
+ /// returns (pow(x,a),pow(y,a),pow(z,a)).
+ triad<T> pow(const T & a);
+ /** Returns a normalized version of the triad.
+ **
+ ** Normalization in this case refers to an operation resulting in a
+ ** traid where the magnatude of the vector is 1.0 while maintaining the
+ ** same angular component. For example, given triad<float> a = (1,2,3),
+ ** a.normalize() = (0.267,0.534,0.802). Of course, the original triad
+ ** is not modified.
+ **
+ ** Normalized triads are very useful when calcuating force or
+ ** accelleration vectors, for example.
+ **/
+ triad<T> normalize();
+ /// Returns the distance between *this and the supplied argument.
+ T range(const triad<T> & a);
+ /// Returns the magnatude of the vector.
+ T magnatude();
+ /// Returns the dot (scalar) product of two triads
+ T dot_product(const triad<T> & a);
+ /// Returns the vector product of two triads
+ triad<T> vector_product(const triad<T> & a);
+ bool operator == (const triad<T> & a);
+ bool operator != (const triad<T> & a);
+ /// Loads from a std::string.
+ triad<T> from_str(const std::string & a);
+ /// Returns a std::string representation.
+ std::string to_str(int precision=6);
};
template <class T>
triad<T>::triad(T _x, T _y, T _z)
{
- x = _x;
- y = _y;
- z = _z;
+ x = _x;
+ y = _y;
+ z = _z;
};
template <class T>
triad<T> triad<T>::operator + (const triad<T> & a)
{
- triad<T> returnme;
- returnme.x = x + a.x;
- returnme.y = y + a.y;
- returnme.z = z + a.z;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x + a.x;
+ returnme.y = y + a.y;
+ returnme.z = z + a.z;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator - (const triad<T> & a)
{
- triad<T> returnme;
- returnme.x = x - a.x;
- returnme.y = y - a.y;
- returnme.z = z - a.z;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x - a.x;
+ returnme.y = y - a.y;
+ returnme.z = z - a.z;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator * (const triad<T> & a)
{
- triad<T> returnme;
- returnme.x = x * a.x;
- returnme.y = y * a.y;
- returnme.z = z * a.z;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x * a.x;
+ returnme.y = y * a.y;
+ returnme.z = z * a.z;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator / (const triad<T> & a)
{
- triad<T> returnme;
- returnme.x = x / a.x;
- returnme.y = y / a.y;
- returnme.z = z / a.z;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x / a.x;
+ returnme.y = y / a.y;
+ returnme.z = z / a.z;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator += (const triad<T> & a)
{
- x += a.x;
- y += a.y;
- z += a.z;
- return *this;
+ x += a.x;
+ y += a.y;
+ z += a.z;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator -= (const triad<T> & a)
{
- x -= a.x;
- y -= a.y;
- z -= a.z;
- return *this;
+ x -= a.x;
+ y -= a.y;
+ z -= a.z;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator *= (const triad<T> & a)
{
- x *= a.x;
- y *= a.y;
- z *= a.z;
- return *this;
+ x *= a.x;
+ y *= a.y;
+ z *= a.z;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator /= (const triad<T> & a)
{
- x /= a.x;
- y /= a.y;
- z /= a.z;
- return *this;
+ x /= a.x;
+ y /= a.y;
+ z /= a.z;
+ return *this;
};
template <class T>
triad<T> triad<T>::pow(const triad<T> & a)
{
- triad<T> returnme;
- returnme.x = ::pow(x,a.x);
- returnme.y = ::pow(y,a.y);
- returnme.z = ::pow(z,a.z);
- return returnme;
+ triad<T> returnme;
+ returnme.x = ::pow(x,a.x);
+ returnme.y = ::pow(y,a.y);
+ returnme.z = ::pow(z,a.z);
+ return returnme;
};
template <class T>
triad<T> triad<T>::normalize()
{
- return (*this / this->magnatude());
+ return (*this / this->magnatude());
};
template <class T>
triad<T> triad<T>::operator + (const T & a)
{
- triad<T> returnme;
- returnme.x = x + a;
- returnme.y = y + a;
- returnme.z = z + a;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x + a;
+ returnme.y = y + a;
+ returnme.z = z + a;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator - (const T & a)
{
- triad<T> returnme;
- returnme.x = x - a;
- returnme.y = y - a;
- returnme.z = z - a;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x - a;
+ returnme.y = y - a;
+ returnme.z = z - a;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator * (const T & a)
{
- triad<T> returnme;
- returnme.x = x * a;
- returnme.y = y * a;
- returnme.z = z * a;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x * a;
+ returnme.y = y * a;
+ returnme.z = z * a;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator / (const T & a)
{
- triad<T> returnme;
- returnme.x = x / a;
- returnme.y = y / a;
- returnme.z = z / a;
- return returnme;
+ triad<T> returnme;
+ returnme.x = x / a;
+ returnme.y = y / a;
+ returnme.z = z / a;
+ return returnme;
};
template <class T>
triad<T> triad<T>::operator += (const T & a)
{
- x += a;
- y += a;
- z += a;
- return *this;
+ x += a;
+ y += a;
+ z += a;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator -= (const T & a)
{
- x -= a;
- y -= a;
- z -= a;
- return *this;
+ x -= a;
+ y -= a;
+ z -= a;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator *= (const T & a)
{
- x *= a;
- y *= a;
- z *= a;
- return *this;
+ x *= a;
+ y *= a;
+ z *= a;
+ return *this;
};
template <class T>
triad<T> triad<T>::operator /= (const T & a)
{
- x /= a;
- y /= a;
- z /= a;
- return *this;
+ x /= a;
+ y /= a;
+ z /= a;
+ return *this;
};
template <class T>
triad<T> triad<T>::pow(const T & a)
{
- triad<T> returnme;
- returnme.x = ::pow(x,a);
- returnme.y = ::pow(y,a);
- returnme.z = ::pow(z,a);
- return returnme;
+ triad<T> returnme;
+ returnme.x = ::pow(x,a);
+ returnme.y = ::pow(y,a);
+ returnme.z = ::pow(z,a);
+ return returnme;
};
template <class T>
T triad<T>::range(const triad<T> & a)
{
- triad<T> offset = *this - a;
- offset *= offset;
- return sqrt(offset.x + offset.y + offset.z);
+ triad<T> offset = *this - a;
+ offset *= offset;
+ return sqrt(offset.x + offset.y + offset.z);
};
template <class T>
T triad<T>::magnatude()
{
- return sqrt((x*x) + (y*y) + (z*z));
+ return sqrt((x*x) + (y*y) + (z*z));
};
template <class T>
@@ -327,39 +327,39 @@
template <class T>
bool triad<T>::operator == (const triad<T> & a)
{
- return ((x == a.x) && (y == a.y) && (z == a.z));
+ return ((x == a.x) && (y == a.y) && (z == a.z));
};
template <class T>
bool triad<T>::operator != (const triad<T> & a)
{
- return (! (*this == a));
+ return (! (*this == a));
};
template <class T>
triad<T> triad<T>::from_str(const std::string & a)
{
- std::istringstream t(a.c_str());
- t >> *this;
- return *this;
+ std::istringstream t(a.c_str());
+ t >> *this;
+ return *this;
};
template <class T>
std::string triad<T>::to_str(int precision)
{
- std::stringstream a;
- a << std::setprecision(precision) << *this;
- std::string returnme;
- a >> returnme;
- return returnme;
+ std::stringstream a;
+ a << std::setprecision(precision) << *this;
+ std::string returnme;
+ a >> returnme;
+ return returnme;
};
/// Writes the triad<T> in the format "(x,y,z)" to the output stream.
template <class T>
std::ostream & operator << (std::ostream &f, const triad<T> & a)
{
- f << "(" << a.x << "," << a.y << "," << a.z << ")";
- return f;
+ f << "(" << a.x << "," << a.y << "," << a.z << ")";
+ return f;
};
/** Reads the triad<T> from an input stream.
@@ -372,22 +372,22 @@
template <class T>
std::istream & operator >> (std::istream &f, triad<T> & a)
{
- std::string element;
- f >> element;
- strlist t = split(element,',');
- if (t.size() != 3)
- {
- a = 0;
- }
- else
- {
- std::stringstream transmorgrafier;
- transmorgrafier << std::setprecision(30);
- if (t[0][0] == '(') { t[0].erase(0,1); };
- for(int i=0; i < 3; i++) { transmorgrafier << t[i] << " "; };
- transmorgrafier >> a.x >> a.y >> a.z;
- };
- return f;
+ std::string element;
+ f >> element;
+ strlist t = split(element,',');
+ if (t.size() != 3)
+ {
+ a = 0;
+ }
+ else
+ {
+ std::stringstream transmorgrafier;
+ transmorgrafier << std::setprecision(30);
+ if (t[0][0] == '(') { t[0].erase(0,1); };
+ for(int i=0; i < 3; i++) { transmorgrafier << t[i] << " "; };
+ transmorgrafier >> a.x >> a.y >> a.z;
+ };
+ return f;
};
} // namespace nrtb
=== modified file 'cpp/common/serializer/Makefile'
--- obsolete/Cpp/common/serializer/Makefile 2012-04-06 17:44:53 +0000
+++ cpp/common/serializer/Makefile 2013-08-09 21:47:12 +0000
@@ -28,8 +28,8 @@
serializer_test: serializer.o serializer_test.cpp
@rm -f serializer_test
- g++ -c serializer_test.cpp -I../include -std=gnu++0x
- g++ -o serializer_test serializer_test.o serializer.o ../obj/base_thread.o -lpthread ../obj/common.o -std=gnu++0x
+ g++ -c serializer_test.cpp -I../include -std=gnu++11
+ g++ -o serializer_test serializer_test.o serializer.o -lpthread -std=gnu++11
clean:
@rm -rvf *.o serializer_test ../include/serializer.h ../obj/serializer.o
=== modified file 'cpp/common/serializer/serializer.cpp'
--- obsolete/Cpp/common/serializer/serializer.cpp 2011-07-30 15:32:43 +0000
+++ cpp/common/serializer/serializer.cpp 2013-08-09 21:47:12 +0000
@@ -17,7 +17,6 @@
**********************************************/
#include "serializer.h"
-#include <base_thread.h>
using namespace nrtb;
@@ -38,6 +37,5 @@
unsigned long long serializer::operator()()
{
- nrtb::scope_lock mylock(lock);
return counter++;
}
=== modified file 'cpp/common/serializer/serializer.h'
--- obsolete/Cpp/common/serializer/serializer.h 2011-09-15 01:21:11 +0000
+++ cpp/common/serializer/serializer.h 2013-08-09 21:47:12 +0000
@@ -18,7 +18,8 @@
#ifndef nrtb_serializer_h
#define nrtb_serializer_h
-#include <base_thread.h>
+
+#include <atomic>
namespace nrtb
{
@@ -41,8 +42,7 @@
// functor method, returns the next value in the sequence.
unsigned long long operator ()();
private:
- nrtb::mutex lock;
- unsigned long long int counter;
+ std::atomic<unsigned long long> counter;
};
}
=== modified file 'cpp/common/singleton/Makefile'
--- obsolete/Cpp/common/singleton/Makefile 2012-04-06 17:46:15 +0000
+++ cpp/common/singleton/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,7 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
lib: singleton_test
@./singleton_test
@@ -24,8 +25,8 @@
singleton_test: singleton_test.cpp Makefile
@rm -f singleton_test
- g++ -c singleton_test.cpp -I ../include -std=gnu++0x
- g++ -o singleton_test singleton_test.o ../obj/base_thread.o ../obj/common.o ../obj/serializer.o -lpthread -std=gnu++0x
+ g++ -c singleton_test.cpp -I ../include ${switches}
+ g++ -o singleton_test singleton_test.o ../obj/serializer.o -lpthread ${switches}
clean:
@rm -rvf *.o singleton_test ../include/singleton.h
=== modified file 'cpp/common/singleton/singleton.h'
--- obsolete/Cpp/common/singleton/singleton.h 2011-08-13 13:13:25 +0000
+++ cpp/common/singleton/singleton.h 2013-08-09 21:47:12 +0000
@@ -25,7 +25,9 @@
#ifndef nrtb_singleton_h
#define nrtb_singleton_h
-#include <base_thread.h>
+#include <mutex>
+#include <memory>
+#include <atomic>
namespace nrtb
{
@@ -55,68 +57,70 @@
template <class T, int mytag=0>
class singleton: public T
{
- private:
- static mutex __mylock;
- static singleton * __me;
- protected:
- singleton() : T() {};
- virtual ~singleton() {};
- singleton(const singleton &) {};
- public:
- /** Used to access the object.
- **
- ** Returns a reference to the instanciated singleton object. If
- ** the object has not been accessed before, the object will be
- ** instanciated automatically.
- **
- ** As is usual for the method that provides access to a singleton,
- ** this method is static, allowing it to be called via the class
- ** name as shown. Remember you can only assign the return value to
- ** a reference:
- **
- ** mytype & a = mytype::get_instance();
- **
- ** Attempts to make a copy of the instance should throw a compiler
- ** error.
- **
- ** This method is thread safe, but that does not imply that the
- ** class returned is thread-safe overall; that would depend on the
- ** implementation of the class used to instaciate the template.
- **/
- static singleton & get_instance()
- {
- // First test avoids expensive mutex cycle
- // if the object is already allocated.
- if (!__me)
- {
- scope_lock lock(__mylock);
- // second test required in case multiple threads
- // get past the first check.
- if (!__me)
- {
- __me = new singleton;
- };
- };
- return *__me;
- };
+private:
+ static std::mutex __mylock;
+ static singleton<T,mytag> * __me ;
+protected:
+ singleton() : T() {};
+ virtual ~singleton() {};
+ singleton(const singleton &) = delete;
+public:
+ /** Used to access the object.
+ **
+ ** Returns a reference to the instanciated singleton object. If
+ ** the object has not been accessed before, the object will be
+ ** instanciated automatically.
+ **
+ ** As is usual for the method that provides access to a singleton,
+ ** this method is static, allowing it to be called via the class
+ ** name as shown. Remember you can only assign the return value to
+ ** a reference:
+ **
+ ** mytype & a = mytype::get_instance();
+ **
+ ** Attempts to make a copy of the instance should throw a compiler
+ ** error.
+ **
+ ** This method is thread safe, but that does not imply that the
+ ** class returned is thread-safe overall; that would depend on the
+ ** implementation of the class used to instaciate the template.
+ **/
+ static singleton & get_reference()
+ {
+ // First test avoids expensive mutex cycle
+ // if the object is already allocated.
+ if (!__me)
+ {
+ std::unique_lock<std::mutex> lock(__mylock);
+ // second test required in case multiple threads
+ // get past the first check.
+ if (!__me)
+ {
+ __me = new singleton;
+ };
+ };
+ return *__me;
+ };
- /** Destructs and deallocates the singleton object.
- **
- ** After a call to this method, the singleton object will
- ** be destructed and deallocated from memory. However, it
- ** will be automatically reconstruted and allocated if
- ** get_instance() called at any time afterword.
- **/
- void delete_me()
- {
- scope_lock lock(__mylock);
- if (__me) delete __me;
- __me = 0;
- };
+ /** Destructs and deallocates the singleton object.
+ **
+ ** After a call to this method, the singleton object will
+ ** be destructed and deallocated from memory. However, it
+ ** will be automatically reconstruted and allocated if
+ ** get_instance() called at any time afterword.
+ **/
+ void delete_me()
+ {
+ std::unique_lock<std::mutex> lock(__mylock);
+ if (__me) delete __me;
+ __me = 0;
+ };
};
-template <class T, int mytag> mutex singleton<T,mytag>::__mylock;
-template <class T, int mytag> singleton<T,mytag> * singleton<T,mytag>::__me = 0;
+template <class T, int mytag>
+ std::mutex singleton<T,mytag>::__mylock;
+template <class T, int mytag>
+ singleton<T,mytag> * singleton<T,mytag>::__me;
} // namespace nrtb;
=== modified file 'cpp/common/singleton/singleton_test.cpp'
--- obsolete/Cpp/common/singleton/singleton_test.cpp 2011-08-13 14:19:56 +0000
+++ cpp/common/singleton/singleton_test.cpp 2013-08-09 21:47:12 +0000
@@ -32,24 +32,25 @@
cout << "============== singleton unit test ================"
<< endl;
- int er_count = 0;
+ int er_count {0};
- sequence_type & a = sequence_type::get_instance();
+ sequence_type & a = sequence_type::get_reference();
for (int i=0; i<10; i++)
{
- cout << a();
+ cout << a();
};
- sequence_type & b = sequence_type::get_instance();
+ sequence_type & b = sequence_type::get_reference();
if ( b() != 10)
{
- er_count++;
+ er_count++;
};
- cout << "\n=========== singleton test " << (er_count ? "failed" : "passed")
- << " =============" << endl;
+ cout << "\n=========== singleton test "
+ << (er_count ? "failed" : "passed")
+ << " =============" << endl;
return er_count;
};
=== modified file 'cpp/common/sockets/Makefile'
--- obsolete/Cpp/common/sockets/Makefile 2012-03-31 21:56:49 +0000
+++ cpp/common/sockets/Makefile 2013-08-09 21:47:12 +0000
@@ -16,6 +16,8 @@
#
#***********************************************
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
lib: socket_test
@./socket_test
@cp -v base_socket.h ../include/
@@ -24,13 +26,13 @@
socket_test: base_socket.o socket_test.cpp
@rm -f socket_test
- g++ -c -O3 socket_test.cpp -I ../include -std=gnu++0x
- g++ -o socket_test socket_test.o base_socket.o ../obj/hires_timer.o ../obj/common.o ../obj/base_thread.o -lpthread -std=gnu++0x
+ g++ -c -O3 socket_test.cpp -I ../include ${switches}
+ g++ -o socket_test socket_test.o base_socket.o ../obj/common.o -lpthread ${switches}
base_socket.o: base_socket.cpp base_socket.h Makefile
@rm -f base_socket.o
- g++ -c -O3 base_socket.cpp -I ../include -std=gnu++0x
+ g++ -c -O3 base_socket.cpp -I ../include ${switches}
clean:
@rm -vf *.o ../include/base_socket.h socket_test
=== modified file 'cpp/common/sockets/base_socket.cpp'
--- obsolete/Cpp/common/sockets/base_socket.cpp 2012-04-07 14:16:46 +0000
+++ cpp/common/sockets/base_socket.cpp 2013-08-09 21:47:12 +0000
@@ -19,11 +19,13 @@
// see base_socket.h for documentation
#include "base_socket.h"
+#include <boost/lexical_cast.hpp>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netdb.h>
-#include <boost/lexical_cast.hpp>
+#include <vector>
+#include <regex>
// testing
#include <iostream>
@@ -34,554 +36,527 @@
namespace nrtb
{
-// added for Solaris 2.6
-#ifdef no_inet_aton
-int inet_aton(const char * addr, in_addr * inp)
-{
- // this workaround defines inet_aton in term in_addr. Drawbacks are
- // that there is no useful error checking.
- inp->s_addr = inet_addr(addr);
- return (inp->s_addr != 0);
-};
-#endif // no_inet_aton
-
-// added for solaris 2.6
-#ifdef no_socklen_t
-typedef int socklen_t;
-#endif // no_sock_len_t
-
int tcp_socket::transmit(const string & data)
{
- return send(mysock,data.c_str(),data.length(),MSG_DONTWAIT);
+ return send(mysock,data.c_str(),data.length(),MSG_DONTWAIT);
};
int tcp_socket::receive(std::string & data, int limit)
{
- errno = 0;
- data = "";
- // make more room in the input buffer if needed.
- int bufsize = limit + 1;
- if (bufsize > inbuff.size()) inbuff.resize(bufsize);
- // get the data to inbuff
- int returnme = recv(mysock,(void *) &(inbuff[0]),limit,0);
- // did we get anything?
- if (returnme > 0)
- {
- // yes.. store for the caller.
- data.resize(returnme,0);
- for (int i=0; i<returnme; i++)
- {
- data[i] = inbuff[i];
- };
- }
- // ... or was there an error?
- else if (errno)
- {
- // flag it for the caller.
- returnme = -1;
- };
- return returnme;
+ errno = 0;
+ data = "";
+ // make more room in the input buffer if needed.
+ int bufsize = limit + 1;
+ if (bufsize > inbuff.size()) inbuff.resize(bufsize);
+ // get the data to inbuff
+ int returnme = recv(mysock,(void *) &(inbuff[0]),limit,0);
+ // did we get anything?
+ if (returnme > 0)
+ {
+ // yes.. store for the caller.
+ data.resize(returnme,0);
+ for (int i=0; i<returnme; i++)
+ {
+ data[i] = inbuff[i];
+ };
+ }
+ // ... or was there an error?
+ else if (errno)
+ {
+ // flag it for the caller.
+ returnme = -1;
+ };
+ return returnme;
};
tcp_socket::tcp_socket(bool autoclose)
{
- close_on_destruct = autoclose;
- mysock = socket(AF_INET,SOCK_STREAM,0);
- _status = sock_init;
- _last_error = 0;
+ close_on_destruct = autoclose;
+ mysock = socket(AF_INET,SOCK_STREAM,0);
+ _status = state::sock_init;
+ _last_error = 0;
};
tcp_socket::tcp_socket(int existing_socket, bool autoclose)
{
- close_on_destruct = autoclose;
- mysock = existing_socket;
- _status = sock_connect;
- _last_error = 0;
+ close_on_destruct = autoclose;
+ mysock = existing_socket;
+ _status = state::sock_connect;
+ _last_error = 0;
};
tcp_socket::~tcp_socket()
{
- if (close_on_destruct)
- {
- try {shutdown(mysock,SHUT_RDWR); } catch (...) {};
- try {::close(mysock); } catch (...) {};
- _status = sock_undef;
- };
+ if (close_on_destruct)
+ {
+ try {shutdown(mysock,SHUT_RDWR); } catch (...) {};
+ try {::close(mysock); } catch (...) {};
+ _status = state::sock_undef;
+ };
};
void tcp_socket::reset()
{
- // close the old socket if we can.
- try { close(); } catch (tcp_socket::general_exception) {};
- // get a new one.
- mysock = socket(AF_INET,SOCK_STREAM,0);
- // set up the default conditions;
- _status = sock_init;
- _last_error = 0;
+ // close the old socket if we can.
+ try { close(); } catch (tcp_socket::general_exception) {}
+ // get a new one.
+ mysock = socket(AF_INET,SOCK_STREAM,0);
+ // set up the default conditions;
+ _status = state::sock_init;
+ _last_error = 0;
};
sockaddr_in tcp_socket::str_to_sockaddr(const string & address)
{
- sockaddr_in in_address;
- // init our address structure.
- memset(&in_address,0,sizeof(in_address));
- //in_address.sin_len = 16;
- in_address.sin_family = AF_INET;
- // seperate the IP and port addresses.
- const int IP = 0;
- const int PORT = 1;
- strlist addr;
- addr = split(address,':');
- if (addr.size() != 2)
- {
- throw bad_address_exception();
- };
- if (addr[IP] != "*")
- {
- // first attempt name resolution
- hostent * name = gethostbyname(addr[IP].c_str());
- if ((name != 0) && (name->h_length > 0))
- {
- in_address.sin_addr = *( (in_addr *) (name->h_addr_list[0]));
- }
- else if (!inet_aton(addr[IP].c_str(),&in_address.sin_addr))
- {
- throw bad_address_exception();
- };
- };
- if (addr[PORT] != "*")
- {
- // get the good port;
- uint16_t port = lexical_cast<uint16_t>(addr[PORT]);
- in_address.sin_port = htons(port);
- };
- return in_address;
+ sockaddr_in in_address;
+ // init our address structure.
+ memset(&in_address,0,sizeof(in_address));
+ //in_address.sin_len = 16;
+ in_address.sin_family = AF_INET;
+ // seperate the IP and port addresses.
+ const int IP = 0;
+ const int PORT = 1;
+ strlist addr;
+ addr = split(address,':');
+ if (addr.size() != 2)
+ {
+ throw bad_address_exception();
+ };
+ if (addr[IP] != "*")
+ {
+ // first attempt name resolution
+ hostent * name = gethostbyname(addr[IP].c_str());
+ if ((name != 0) && (name->h_length > 0))
+ {
+ in_address.sin_addr = *( (in_addr *) (name->h_addr_list[0]));
+ }
+ else if (!inet_aton(addr[IP].c_str(),&in_address.sin_addr))
+ {
+ throw bad_address_exception();
+ };
+ };
+ if (addr[PORT] != "*")
+ {
+ // get the good port;
+ uint16_t port = lexical_cast<uint16_t>(addr[PORT]);
+ in_address.sin_port = htons(port);
+ };
+ return in_address;
};
string tcp_socket::sockaddr_to_str(const sockaddr_in & address)
{
- // get the IP address.
- string returnme = inet_ntoa(address.sin_addr);
- // adjust for wild card if appropriate.
- if (returnme == "0.0.0.0") { returnme = "*"; };
- // get the port address
- returnme += ":";
- uint16_t myport = ntohs(address.sin_port);
- if (myport > 0 )
- {
- returnme += lexical_cast<string>(myport);
- }
- else
- {
- returnme += "*";
- };
- return returnme;
+ // get the IP address.
+ string returnme = inet_ntoa(address.sin_addr);
+ // adjust for wild card if appropriate.
+ if (returnme == "0.0.0.0") { returnme = "*"; };
+ // get the port address
+ returnme += ":";
+ uint16_t myport = ntohs(address.sin_port);
+ if (myport > 0 )
+ {
+ returnme += lexical_cast<string>(myport);
+ }
+ else
+ {
+ returnme += "*";
+ };
+ return returnme;
};
void tcp_socket::bind(const string & address)
{
- if (address != "*:*")
- {
- sockaddr_in in_address = str_to_sockaddr(address);
- socklen_t socklen = sizeof(in_address);
- // try bind.
- if (::bind(mysock, (sockaddr*) &in_address, socklen))
- {
- // failed in some way.
- _last_error = errno;
- cant_bind_exception e;
- e.store(address);
- throw e;
- };
- }; // nop if "*:*" is passed in.
+ if (address != "*:*")
+ {
+ sockaddr_in in_address = str_to_sockaddr(address);
+ socklen_t socklen = sizeof(in_address);
+ // try bind.
+ if (::bind(mysock, (sockaddr*) &in_address, socklen))
+ {
+ // failed in some way.
+ _last_error = errno;
+ cant_bind_exception e;
+ e.store(address);
+ throw e;
+ };
+ }; // nop if "*:*" is passed in.
};
void tcp_socket::connect(const string & address, int timeout)
{
- sockaddr_in in_address = str_to_sockaddr(address);
- if (::connect(mysock, ( sockaddr *) &in_address, sizeof(in_address)))
- {
- _last_error = errno;
- bad_connect_exception e;
- e.store(address);
- throw e;
- }
- else
- {
- _status = sock_connect;
- };
+ sockaddr_in in_address = str_to_sockaddr(address);
+ if (::connect(mysock, ( sockaddr *) &in_address, sizeof(in_address)))
+ {
+ _last_error = errno;
+ bad_connect_exception e;
+ e.store(address);
+ throw e;
+ }
+ else
+ {
+ _status = state::sock_connect;
+ };
};
void tcp_socket::close()
{
- if (::close(mysock))
- {
- _last_error = errno;
- throw close_exception();
- }
- else
- {
- _status = sock_close;
- };
+ if (::close(mysock))
+ {
+ _last_error = errno;
+ throw close_exception();
+ }
+ else
+ {
+ _status = state::sock_close;
+ };
};
int tcp_socket::put(string s, int timeout)
{
- // set up for the testing loop.
- time_t endtime = time(NULL);
- int orig_len = s.length();
- endtime += timeout;
- // Try to send.
- bool done = false;
- while (!done)
- {
- // make an attempt.
- int results = transmit(s);
- // remove the chars already sent from the buffer and set done
- // if appropriate.
- if (results > 0)
- {
- s.erase(0,results);
- done = (s.length() == 0) ? true : false;
- };
- // decide what do do about any possible error results.
- if (results == -1)
- {
- switch (errno)
- {
- case EBADF :
- case ENOTSOCK:
- {
- done = true;
- _last_error = errno;
- _status = sock_close;
- not_open_exception e;
- e.store(s);
- throw e;
- break;
- };
- case ENOBUFS :
- case ENOMEM :
- {
- done = true;
- _last_error = errno;
- buffer_full_exception e;
- e.store(s);
- throw e;
- break;
- };
- case EINTR:
- case EAGAIN :
-// case EWOULDBLOCK :
- {
- usleep(50);
- break;
- };
- default :
- {
- done = true;
- _last_error = errno;
- general_exception e;
- e.store(s);
- throw e;
- break;
- };
- }; // switch (errno)
- }; // until error,
- if ((timeout > 0) && ((time(NULL) >= endtime)))
- {
- done = true;
- };
- }; // continue sending until success or error or timeout.
- // check for timeout.
- int sent = orig_len - s.length();
- if (sent != orig_len)
- {
- timeout_exception e;
- e.store(s);
- throw e;
- };
- return sent;
+ // set up for the testing loop.
+ time_t endtime = time(NULL);
+ int orig_len = s.length();
+ endtime += timeout;
+ // Try to send.
+ bool done = false;
+ while (!done)
+ {
+ // make an attempt.
+ int results = transmit(s);
+ // remove the chars already sent from the buffer and set done
+ // if appropriate.
+ if (results > 0)
+ {
+ s.erase(0,results);
+ done = (s.length() == 0) ? true : false;
+ };
+ // decide what do do about any possible error results.
+ if (results == -1)
+ {
+ switch (errno)
+ {
+ case EBADF :
+ case ENOTSOCK:
+ {
+ done = true;
+ _last_error = errno;
+ _status = state::sock_close;
+ not_open_exception e;
+ e.store(s);
+ throw e;
+ break;
+ };
+ case ENOBUFS :
+ case ENOMEM :
+ {
+ done = true;
+ _last_error = errno;
+ buffer_full_exception e;
+ e.store(s);
+ throw e;
+ break;
+ };
+ case EINTR:
+ case EAGAIN :
+ {
+ usleep(50);
+ break;
+ };
+ default :
+ {
+ done = true;
+ _last_error = errno;
+ general_exception e;
+ e.store(s);
+ throw e;
+ break;
+ };
+ }; // switch (errno)
+ }; // until error,
+ if ((timeout > 0) && ((time(NULL) >= endtime)))
+ {
+ done = true;
+ };
+ }; // continue sending until success or error or timeout.
+ // check for timeout.
+ int sent = orig_len - s.length();
+ if (sent != orig_len)
+ {
+ timeout_exception e;
+ e.store(s);
+ throw e;
+ };
+ return sent;
};
string tcp_socket::get(int maxlen, int timeout)
{
-/*
-micro_timer run_time;
-run_time.start();
-std::cerr << "ENTER get(" << maxlen << "," << timeout << ")" << std::endl;
-*/
- string returnme = "";
- returnme.reserve(maxlen);
- string in_buffer;
- // set out timeout marker.
- time_t endtime = time(NULL);
- endtime += timeout;
- timeval wait;
- // input loop
- bool done = false;
- while (!done)
- {
- time_t waittime = endtime - time(NULL);
- wait.tv_sec = (waittime > 0) ? waittime : 0;
- wait.tv_usec = 10;
- // set max timeout.
- // the assert is used because some platforms may not properly support
- // the SO_RCVTIMEO socket option.
- setsockopt(mysock,SOL_SOCKET,SO_RCVTIMEO,&wait,sizeof(wait));
- // is there any data waiting?
- int results = receive(in_buffer,maxlen-returnme.size());
- // was there an error?
- switch (results)
- {
- case 0:
- {
- if (returnme == "")
- {
- throw not_open_exception();
- }
- else
- {
- done = true;
- }
- break;
- }
- case -1 :
- {
- switch (errno)
- {
- case EBADF :
- case ENOTCONN :
- case ENOTSOCK :
- {
- done = true;
- _last_error = errno;
- _status = sock_close;
- if (returnme == "")
- {
- not_open_exception e;
- e.store(returnme);
- throw e;
- };
- break;
- }
- case EAGAIN : // shouldn't happen, but .....
- case EINTR : // this too....
- {
- if (timeout == 0)
- {
- done = true;
- };
- usleep(50);
- break;
- }
- default :
- {
- done = true;
- _last_error = errno;
- if (returnme == "")
- {
- general_exception e;
- e.store(returnme);
- throw e;
- };
- break;
- }
- }; // there was an error.
- break;
- }
- default:
- {
- returnme += in_buffer;
- break;
- }
- };
- // check boundry conditions;
- // -- maxlen only effective if maxlen > 0.
- if ((maxlen > 0) && (returnme.length() >= maxlen)) { done = true; };
- // -- timeout only effective if timeout > 0.
- if ((timeout > 0) && (time(NULL) > endtime)) { done = true; };
- if (timeout == 0) { done = true; };
-/*
-std::cerr << "\tstatus: " << returnme.size()
-<< ", done = " << done
-<< " (" << run_time.interval() << ")"
-<< std::endl;
-*/
- }; // input loop.
- // did we time out?
- if ((timeout > 0) && (time(NULL) > endtime))
- {
- timeout_exception e;
- e.store(returnme);
- throw e;
- };
- // done!
- return returnme;
+ string returnme = "";
+ returnme.reserve(maxlen);
+ string in_buffer;
+ // set out timeout marker.
+ time_t endtime = time(NULL);
+ endtime += timeout;
+ timeval wait;
+ // input loop
+ bool done = false;
+ while (!done)
+ {
+ time_t waittime = endtime - time(NULL);
+ wait.tv_sec = (waittime > 0) ? waittime : 0;
+ wait.tv_usec = 10;
+ // set max timeout.
+ // the assert is used because some platforms may not properly support
+ // the SO_RCVTIMEO socket option.
+ setsockopt(mysock,SOL_SOCKET,SO_RCVTIMEO,&wait,sizeof(wait));
+ // is there any data waiting?
+ int results = receive(in_buffer,maxlen-returnme.size());
+ // was there an error?
+ switch (results)
+ {
+ case 0:
+ {
+ if (returnme == "")
+ {
+ throw not_open_exception();
+ }
+ else
+ {
+ done = true;
+ }
+ break;
+ }
+ case -1 :
+ {
+ switch (errno)
+ {
+ case EBADF :
+ case ENOTCONN :
+ case ENOTSOCK :
+ {
+ done = true;
+ _last_error = errno;
+ _status = state::sock_close;
+ if (returnme == "")
+ {
+ not_open_exception e;
+ e.store(returnme);
+ throw e;
+ };
+ break;
+ }
+ case EAGAIN : // shouldn't happen, but .....
+ case EINTR : // this too....
+ {
+ if (timeout == 0)
+ {
+ done = true;
+ };
+ usleep(50);
+ break;
+ }
+ default :
+ {
+ done = true;
+ _last_error = errno;
+ if (returnme == "")
+ {
+ general_exception e;
+ e.store(returnme);
+ throw e;
+ };
+ break;
+ }
+ }; // there was an error.
+ break;
+ }
+ default:
+ {
+ returnme += in_buffer;
+ break;
+ }
+ };
+ // check boundry conditions;
+ // -- maxlen only effective if maxlen > 0.
+ if ((maxlen > 0) && (returnme.length() >= maxlen)) { done = true; };
+ // -- timeout only effective if timeout > 0.
+ if ((timeout > 0) && (time(NULL) > endtime)) { done = true; };
+ if (timeout == 0) { done = true; };
+ }; // input loop.
+ // did we time out?
+ if ((timeout > 0) && (time(NULL) > endtime))
+ {
+ timeout_exception e;
+ e.store(returnme);
+ throw e;
+ };
+ // done!
+ return returnme;
};
-
string tcp_socket::getln(string eol, int maxlen, int timeout)
{
- // args check.
- if (eol == "")
- {
- throw bad_args_exception();
- return eol;
- };
- // setup.
- string returnme = "";
- returnme.reserve(maxlen);
- int targetlen = eol.length();
- int searchlen = targetlen - 1;
- time_t endtime = time(NULL);
- endtime += timeout;
- bool done = false;
- bool success = false;
- // first, get at least as many characters as are in the eol string.
- try
- {
- int wait_time = timeout;
- if (timeout < 0) { wait_time = 0; };
- returnme = get(targetlen,wait_time);
- }
- catch (timeout_exception e)
- {
- // if get timed out we may be done.
- if (timeout >= 0) { done = true; };
- returnme = e.comment();
- };
- // We only need to continue if we have not gotten our token yet.
- if ((!done) && (returnme.length() >= targetlen))
- {
-// success = returnme.substr(returnme.length()-targetlen,targetlen) == eol;
- success = returnme.find(eol,returnme.length()-targetlen) != string::npos;
- };
- while (!done && !success)
- {
- // still more to get, if we have time.
- int timeleft = endtime - time(NULL);
- timeleft = (timeleft > 0) ? timeleft : 0;
- // can we increase our get length?
- int getlen = 1;
- if (searchlen > 1)
- {
- // see if a token start is near.
- if (returnme.find(eol[0],returnme.length()-searchlen) == string::npos)
- {
- // great!.. get just less than one token's worth.
- getlen = searchlen;
- }
- };
- // okay.. let's get the next chunk
- try
- {
- returnme += get(getlen,timeleft);
- }
- catch (timeout_exception e)
- {
- if (timeout >= 0) { done = true; };
- };
- // check boundary conditions.
- // -- did we get it?
- if (returnme.length() >= targetlen)
- {
-// success = returnme.substr(returnme.length()-targetlen,targetlen) == eol;
- success = returnme.find(eol,returnme.length()-targetlen) != string::npos;
- };
- // -- maxlen only effective if maxlen > 0.
- if ((maxlen > 0) && (returnme.length() >= maxlen)) { done = true; };
- };
- // did we error out?
- if (!success)
- {
- // what type of error was it?
- if ((maxlen > 0) && (returnme.length() >= maxlen))
- {
- overrun_exception e;
- e.store(returnme);
- throw e;
- }
- else
- {
- timeout_exception e;
- e.store(returnme);
- throw e;
- };
- };
- return returnme;
+ // args check.
+ if (eol == "")
+ {
+ throw bad_args_exception();
+ return eol;
+ };
+ // setup.
+ string returnme = "";
+ returnme.reserve(maxlen);
+ int targetlen = eol.length();
+ int searchlen = targetlen - 1;
+ time_t endtime = time(NULL);
+ endtime += timeout;
+ bool done = false;
+ bool success = false;
+ // first, get at least as many characters as are in the eol string.
+ try
+ {
+ int wait_time = timeout;
+ if (timeout < 0) { wait_time = 0; };
+ returnme = get(targetlen,wait_time);
+ }
+ catch (timeout_exception e)
+ {
+ // if get timed out we may be done.
+ if (timeout >= 0) { done = true; };
+ returnme = e.comment();
+ };
+ // We only need to continue if we have not gotten our token yet.
+ if ((!done) && (returnme.length() >= targetlen))
+ {
+ success = returnme.find(eol,returnme.length()-targetlen) != string::npos;
+ };
+ while (!done && !success)
+ {
+ // still more to get, if we have time.
+ int timeleft = endtime - time(NULL);
+ timeleft = (timeleft > 0) ? timeleft : 0;
+ // can we increase our get length?
+ int getlen = 1;
+ if (searchlen > 1)
+ {
+ // see if a token start is near.
+ if (returnme.find(eol[0],returnme.length()-searchlen) == string::npos)
+ {
+ // great!.. get just less than one token's worth.
+ getlen = searchlen;
+ }
+ };
+ // okay.. let's get the next chunk
+ try
+ {
+ returnme += get(getlen,timeleft);
+ }
+ catch (timeout_exception e)
+ {
+ if (timeout >= 0) { done = true; };
+ };
+ // check boundary conditions.
+ // -- did we get it?
+ if (returnme.length() >= targetlen)
+ {
+ success = returnme.find(eol,returnme.length()-targetlen) != string::npos;
+ };
+ // -- maxlen only effective if maxlen > 0.
+ if ((maxlen > 0) && (returnme.length() >= maxlen)) { done = true; };
+ };
+ // did we error out?
+ if (!success)
+ {
+ // what type of error was it?
+ if ((maxlen > 0) && (returnme.length() >= maxlen))
+ {
+ overrun_exception e;
+ e.store(returnme);
+ throw e;
+ }
+ else
+ {
+ timeout_exception e;
+ e.store(returnme);
+ throw e;
+ };
+ };
+ return returnme;
};
string tcp_socket::get_local_address()
{
- sockaddr_in myaddr;
- socklen_t len = sizeof(myaddr);
- int results = getsockname(mysock,(sockaddr *) &myaddr,&len);
- // check that getsockname was okay.
- if (results == -1)
- {
- // some type of error occurred.
- switch (errno)
- {
- case ENOBUFS :
- {
- throw buffer_full_exception();
- break;
- };
- default :
- {
- throw general_exception();
- break;
- };
- }; // switch errno
- }
- return sockaddr_to_str(myaddr);
+ sockaddr_in myaddr;
+ socklen_t len = sizeof(myaddr);
+ int results = getsockname(mysock,(sockaddr *) &myaddr,&len);
+ // check that getsockname was okay.
+ if (results == -1)
+ {
+ // some type of error occurred.
+ switch (errno)
+ {
+ case ENOBUFS :
+ {
+ throw buffer_full_exception();
+ break;
+ };
+ default :
+ {
+ throw general_exception();
+ break;
+ };
+ }; // switch errno
+ }
+ return sockaddr_to_str(myaddr);
};
string tcp_socket::get_remote_address()
{
- sockaddr_in myaddr;
- socklen_t len = sizeof(myaddr);
- int results = getpeername(mysock,(sockaddr *) &myaddr,&len);
- // check that getsockname was okay.
- if (results == -1)
- {
- // some type of error occurred.
- switch (errno)
- {
- case ENOTCONN :
- {
- _status = sock_close;
- throw not_open_exception();
- break;
- };
- case ENOBUFS :
- {
- throw buffer_full_exception();
- break;
- };
- default :
- {
- throw general_exception();
- break;
- };
- }; // switch errno
- }
- return sockaddr_to_str(myaddr);
+ sockaddr_in myaddr;
+ socklen_t len = sizeof(myaddr);
+ int results = getpeername(mysock,(sockaddr *) &myaddr,&len);
+ // check that getsockname was okay.
+ if (results == -1)
+ {
+ // some type of error occurred.
+ switch (errno)
+ {
+ case ENOTCONN :
+ {
+ _status = state::sock_close;
+ throw not_open_exception();
+ break;
+ };
+ case ENOBUFS :
+ {
+ throw buffer_full_exception();
+ break;
+ };
+ default :
+ {
+ throw general_exception();
+ break;
+ };
+ }; // switch errno
+ }
+ return sockaddr_to_str(myaddr);
};
tcp_server_socket_factory::tcp_server_socket_factory(
- const string & address, const unsigned short int & backlog = 5)
+ const string & address,
+ const unsigned short int backlog,
+ const int queue_size)
{
- // does not attempt to set up the connection initially.
- _address = address;
- _backlog = backlog;
- _last_thread_fault = 0;
+ // does not attempt to set up the connection initially.
+ _address = address;
+ _backlog = backlog;
+ pending.resize(queue_size);
};
tcp_server_socket_factory::~tcp_server_socket_factory()
{
+ // Shutdown the queue and notify the workers.
+ try { pending.shutdown(); } catch (...) {};
// make sure we've stopped doing anything.
try { stop_listen(); } catch (...) {};
};
@@ -589,10 +564,15 @@
void tcp_server_socket_factory::start_listen()
{
// take no action if the listen thread is already running.
- if (!is_running())
+ if (in_run_method or work_thread.joinable())
+ {
+ throw already_running_exception();
+ }
+ else
{
// start it up!
- start();
+ work_thread =
+ std::thread(tcp_server_socket_factory::run, this);
int countdown = 99;
while (!listening() and countdown)
{
@@ -605,10 +585,6 @@
e.store(_address);
throw e;
};
- }
- else
- {
- throw already_running_exception();
};
};
@@ -617,20 +593,22 @@
// take action only if the listen thread is running.
if (listening())
{
- // stop the listener thread
- stop();
- join();
listen_sock.reset();
};
+ if (work_thread.joinable()) work_thread.join();
+ // just in case.
+ pending.shutdown();
+ _last_thread_fault = 0;
+ in_run_method == false;
};
bool tcp_server_socket_factory::listening()
{
- bool running = is_running();
+ bool running = in_run_method and work_thread.joinable();
if (listen_sock)
{
- running = running
- and listen_sock->status() == tcp_socket::sock_connect;
+ running = running and listen_sock->status() ==
+ tcp_socket::state::sock_connect;
}
else
{
@@ -646,124 +624,113 @@
unsigned short int tcp_server_socket_factory::backlog()
{
- return _backlog;
+ return _backlog;
};
-void tcp_server_socket_factory::run()
+void tcp_server_socket_factory::run(
+ tcp_server_socket_factory * server )
{
- // set up the listening socket.
- int sock;
- _last_thread_fault = 0;
- bool go = false;
+ server->in_run_method = true;
try
{
- sock = socket(AF_INET,SOCK_STREAM,0);
- sockaddr_in myaddr;
- myaddr = tcp_socket::str_to_sockaddr(_address);
- int a = bind(sock,(sockaddr *) &myaddr,sizeof(myaddr));
- int b = listen(sock,_backlog);
- if (a || b)
+ // set up the listening socket.
+ int sock;
+ server->_last_thread_fault = 0;
+ bool go = false;
+ try
{
- go = false;
- if (a) _last_thread_fault += 1;
- if (b) _last_thread_fault += 2;
+ sock = socket(AF_INET,SOCK_STREAM,0);
+ sockaddr_in myaddr;
+ myaddr = tcp_socket::str_to_sockaddr(server->_address);
+ int a = bind(sock,(sockaddr *) &myaddr,sizeof(myaddr));
+ int b = listen(sock,server->_backlog);
+ if (a || b)
+ {
+ go = false;
+ if (a) server->_last_thread_fault += 1;
+ if (b) server->_last_thread_fault += 2;
+ }
+ else
+ {
+ go = true;
+ };
}
- else
- {
- go = true;
- };
- }
- catch (...)
- {
- _last_thread_fault = 100;
- };
- // if not in a good state, terminate the thread.
- if (!go)
- {
- _last_thread_fault =+ 200;
- exit(0);
- };
- // make sure the listener is closed when we exit.
- // also prevides an external hook to socket.
- listen_sock.reset(new tcp_socket(sock));
- // processing loop
- while
- (
- go
- and listen_sock
- and (listen_sock->status() == tcp_socket::sock_connect)
- )
- {
- // accept a new connection
- bool good_connect = true;
- int new_conn = accept(sock,NULL,NULL);
- // is the listener still open?
- if
+ catch (...)
+ {
+ server->_last_thread_fault = 100;
+ };
+ // if not in a good state, terminate the thread.
+ if (!go)
+ {
+ server->_last_thread_fault =+ 200;
+ exit(0);
+ };
+ // make sure the listener is closed when we exit.
+ // also prevides an external hook to socket.
+ server->listen_sock.reset(new tcp_socket(sock));
+ // processing loop
+ while
(
- (!listen_sock)
- and (listen_sock->status() != tcp_socket::sock_connect)
+ go
+ and server->listen_sock
+ and (server->listen_sock->status()
+ == tcp_socket::state::sock_connect)
)
{
- // the listner socket is not available.. get out of here.
- listen_sock.reset();
- _last_thread_fault = 300;
- exit(0);
- };
- // validate the accept return value.
- if (new_conn == -1)
- {
- // accept returned an error.
- switch (errno)
- {
- case EPROTO :
- case EHOSTDOWN :
- case EHOSTUNREACH :
- case EAGAIN :
- case ECONNABORTED :
- {
- // abandon this connection
- good_connect = false;
- break;
- };
- default :
- {
- // for any other error, we're going to shutdown the
- // this listener thread.
- go = false;
- good_connect = false;
- _last_thread_fault = errno;
- break;
- };
- }; // switch (errno)
- }; // error thrown by accept.
- if (good_connect)
- {
- connect_sock.reset(new tcp_socket(new_conn));
- set_cancel_anytime();
- // call the connection handler.
- try
- {
- go = on_accept();
- }
- catch (...)
- {
- go = false;
- _last_thread_fault = 501;
- };
- set_deferred_cancel();
- // safety check.
- if (connect_sock)
- {
- std::cerr << "WARNING: on_accept() did not take ownership of "
- << "connect_sock.\n"
- << " This can lead to leaks and should be fixed."
- << std::endl;
- connect_sock.reset();
- _last_thread_fault = 500;
- go = false;
- };
- };
- }; // while go;
+ // accept a new connection
+ bool good_connect = true;
+ int new_conn = accept(sock,NULL,NULL);
+ // is the listener still open?
+ if
+ (
+ (!server->listen_sock)
+ or (server->listen_sock->status()
+ != tcp_socket::state::sock_connect)
+ )
+ {
+ // the listner socket is not available.. get out of here.
+ server->listen_sock.reset();
+ server->_last_thread_fault = 300;
+ good_connect = false;
+ go = false;
+ break;
+ };
+ // validate the accept return value.
+ if (new_conn == -1)
+ {
+ // accept returned an error.
+ switch (errno)
+ {
+ case EPROTO :
+ case EHOSTDOWN :
+ case EHOSTUNREACH :
+ case EAGAIN :
+ case ECONNABORTED :
+ {
+ // abandon this connection
+ good_connect = false;
+ break;
+ };
+ default :
+ {
+ // for any other error, we're going to shutdown the
+ // this listener thread.
+ go = false;
+ good_connect = false;
+ server->_last_thread_fault = errno;
+ break;
+ };
+ }; // switch (errno)
+ }; // error thrown by accept.
+ if (good_connect)
+ {
+ tcp_socket_p storeme(new tcp_socket(new_conn));
+ server->pending.push(storeme);
+ };
+ }; // while go;
+ }
+ catch (...) {};
+ server->in_run_method = false;
};
} // namespace nrtb
=== modified file 'cpp/common/sockets/base_socket.h'
--- obsolete/Cpp/common/sockets/base_socket.h 2012-04-07 13:33:10 +0000
+++ cpp/common/sockets/base_socket.h 2013-08-09 21:47:12 +0000
@@ -19,8 +19,11 @@
#ifndef base_socket_header
#define base_socket_header
-#include <base_thread.h>
#include <memory>
+#include <atomic>
+#include <thread>
+#include <common.h>
+#include <circular_queue.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -39,539 +42,480 @@
**/
class tcp_socket
{
- public:
-
- typedef enum {sock_undef,sock_init,sock_connect,sock_close} state;
-
- protected:
-
- int mysock;
- bool close_on_destruct;
- state _status;
- int _last_error;
- std::vector<unsigned char> inbuff;
-
- virtual int transmit(const std::string & data);
- virtual int receive(std::string & data,int limit);
-
- public:
-
- /// Use to catch all socket exceptions.
- class general_exception: public base_exception {};
- /// Thrown by send or get* if the socket is not open for use.
- class not_open_exception: public general_exception {};
- /// Thrown by get* if more than maxlen chars are receieved.
- class overrun_exception: public general_exception {};
- /// Thrown if a timeout occured during an operation.
- class timeout_exception: public general_exception {};
- /// Thrown if the socket could not connect to the target.
- class bad_connect_exception: public general_exception {};
- /// Thrown if the address argument is not interpretable.
- class bad_address_exception: public general_exception {};
- /// Thrown by bind() if the address/port is not bindable.
- class cant_bind_exception: public general_exception {};
- /// Thrown by close() if an error is reported.
- class close_exception: public general_exception {};
- /// Thrown by send if the message is too large.
- class msg_too_large_exception: public general_exception {};
- /// Thrown by send if buffer overflows.
- class buffer_full_exception: public general_exception {};
- /// Thrown if the socket lib complains of bad args.
- class bad_args_exception: public general_exception {};
-
- /** Constructs a tcp_socket.
- **
- ** Prepares this socket for use. If autoclose=true the socket will be
- ** closed when the object is distructed, otherwise it will be left in
- ** whatever state it happened to be in at the time.
- **
- ** BTW, I _don't_ recommend you leave the socket open. If the tcp_socket
- ** was instanciated via this constructor, there will not be any other
- ** references to the socket save the one held privately, so a socket left
- ** open will be there forever. This will almost certainly warrent an
- ** unpleasent visit by one or more SAs of the box(es) hosting your
- ** application over time.
- **
- ** autoclose=true; it's the only way to be sure. ;)
- **/
- tcp_socket(bool autoclose=true);
-
- /** Constructs from an already existing socket.
- **
- ** Constructs the tcp_socket from an already existing socket. This
- ** constructor is specifically for use with the traditional listen()
- ** sockets function, and probably should not be used in other contexts.
- **
- ** If autoclose is true the socket will be closed on destruction of the
- ** object, otherwise the socket will be left in whatever state it happened
- ** to be in at the time. As a general rule I suspect you'll want leave
- ** autoclose defaulted to true.
- **
- ** In most cases where you would use listen(), take a look at the
- ** tcp_server_socket_factory class; it'll probably do everything you need
- ** with a minimum of programming overhead.
- **
- ** BTW, I _don't_ recommend you leave the socket open. If the socket variable
- ** used for instanciation was discarded, there will not be any other
- ** references to the socket save the one held privately, so a socket left
- ** open will be there forever. This will almost certainly warrent an
- ** unpleasent visit by one or more SAs of the box(es) hosting your
- ** application over time.
- **
- ** autoclose=true; it's the only way to be sure. ;)
- **/
- tcp_socket(int existing_socket, bool autoclose=true);
-
- /** Destructs a tcp_socket.
- **
- ** If autoclose was set to true, the socket will be closed if it is open
- ** at the time of destruction. If no, the socket will be left in whatever
- ** state it happened to be in at the time.
- **/
- virtual ~tcp_socket();
-
- /** Resets the socket after a hard error.
- **
- ** In cases where the socket was invlidated by the operating system
- ** (typically cases where a SIGPIPE was raised by the TCP/IP stack),
- ** use this function to discard the old socket id and aquire a new one.
- ** Understand that this will make the tcp_socket useful again, but you
- ** will have to reconnect before any traffic can be sent.
- **/
- virtual void reset();
-
- /** Creates a sockaddr_in from a formatted string.
- **
- ** address is an "IP:port" formatted string; i.e. 129.168.1.1:80.
- ** "*" may use used to substatute for the IP, port or both.
- **
- ** Returns a properly formatted sockaddr_in struct for use with connect,
- ** bind, etc. Throws a bad_address_exception if the address argument is
- ** mal-formed.
- **/
- static sockaddr_in str_to_sockaddr(const std::string & address);
-
- /** Creates a string from a sockaddr_in.
- **
- ** The returned string is of the same format accepted as arguments to the
- ** to the bind() and connect() methods.
- **
- ** May throw a bad_address_exception if the sock_addr_in is not
- ** properly formatted.
- **/
- static std::string sockaddr_to_str(const sockaddr_in & address);
-
- /** binds the tcp_socket to a local address/port.
- **
- ** You do _not_ need to use this method if you are setting up a tcp_socket
- ** for client use. If you don't call bind an ephemeral port and the host's
- ** IP number will be assigned, as is normal and preferred for client sockets.
- **
- ** In very rare cases where you have a multi-homed host and a real
- ** requirement to specify which IP this connection uses as local, you can
- ** use this method to select the port and address the client will use.
- **
- ** address: string of the format IP:port; example "255.255.255.255:91".
- ** If you wish to accept input on any active IP address in this host,
- ** use "*" for the IP address, as in "*:80". If you want to fix the address
- ** but leave the port up to the host, use "*" for the port, as in
- ** "10.101.78.33:*". Obviously, using "*:*" as the address gives the
- ** same results as not calling this method at all.
- **
- ** If the address argument is mal-formed a bad_address_exception will be
- ** thrown and no changes will be made to the tcp_socket.
- **
- ** If the address is not bindable (already in use is a common cause) a
- ** cant_bind_exception will be thrown.
- **/
- void bind(const std::string & address);
-
- /** Opens the connection.
- **
- ** address: string of the format IP:port; example "255.255.255.255:91".
- ** If the address is mal-formed a bad_address_exception will be thrown.
- **
- ** If timeout is specified and >0, the system will not wait more than
- ** timeout seconds before throwing a timeout_exception.
- **
- ** If the connection is not set up properly, a bad_connection_exception
- ** will be thrown.
- **/
- void connect(const std::string & address, int timeout=0);
-
- /** Closes an open connection.
- **
- ** If a problem is reported a close_exception will be thrown. Possible
- ** causes include the socket not being open, unsent data pending in the
- ** tcp stack, etc.
- **/
- virtual void close();
-
- /** Returns the current status.
- **
- ** Possibles states are tcp_socket::undef, tcp_socket::init,
- ** tcp_socket::connect, and tcp_socket::close.
- **/
- state status() { return _status; };
-
- /** Returns the last socket error recieved.
- **
- ** Will contain zero if no errors have occured on the socket since
- ** the tcp_socket was instanciated, or the errno returned on the most recent
- ** error otherwise.
- **
- ** Check the man pages for bind(), connect(), close(), socket(), send(),
- ** and recv() for possible values. They are defined in error.h.
- **/
- int last_error() { return _last_error; };
-
- /** Sends the string to the target host.
- **
- ** If timeout is specified and >0, a timeout_exception will be thrown
- ** if the send does not succeed within timeout seconds.
- **
- ** If socket is not connected or closes during sending a
- ** not_open_exception will be thrown.
- **
- ** If an exception is thrown, the characters that were not
- ** sent will be available via the exception's comment() method (as
- ** a string, of course).
- **/
- int put(std::string s, int timeout=10);
-
- /** gets a string of characters from the socket.
- **
- ** This method allows the reception of a string of characters
- ** limited by length and time. Use this method when you are expecting a
- ** stream if data that you either know the length of or where there is
- ** no specific ending character. If the expected traffic is organized
- ** into messages or lines ending with a specific character or string,
- ** use the getln() method instead.
- **
- ** Examples:
- **
- ** get() or get(1) will return a string containing a single
- ** character or throw a timeout in 10 seconds if one is not
- ** recieved.
- **
- ** get(100,30) will return when 100 characters have been recieved or
- ** throw a timeout in 30 seconds.
- **
- ** get(100,-1) will return after 100 characters have been recieved, and will
- ** _never_ time out. I strongly recommend that at the very least use timeout
- ** values >= 0 to this method to prevent program long term program stalls.
- **
- ** If maxlen==0, this method will return immediately with whatever characters
- ** happen to be in the socket's input buffer at the time.
- **
- ** If maxlen>0 and timeout<0, this method will block until maxlen characters
- ** have been recieved and then return. NOTE: this method could block
- ** forever if the sending host does not send maxlen characters and timeout
- ** is < 0.
- **
- ** If maxlen>0 and timeout>0 this method will return upon recieving
- ** maxlen characters or throw a timeout_exception after timeout seconds
- ** have expired in the worse case.
- **
- ** In all cases the method returns a string containing the characters
- ** recieved, if any.
- **
- ** If the timeout expires before the required number of characters are
- ** recieved a timeout_exception will be thrown.
- **
- ** If the socket is not connected or closes while being read a
- ** not_open_exception will be thrown.
- **
- ** If an exception is thrown, any characters already recieved
- ** will be available via the exception's comment() method.
- **/
- std::string get(int maxlen=1, int timeout=10);
-
- /** gets a string of characters from the socket.
- **
- ** This method is for the reception of messages (or lines) that have a
- ** specific ending string. As such it considers the recept of maxlen
- ** characters or a timeout without the designated eol string to be
- ** a problem and will throw an exception in those cases. This behavor
- ** differs from that of the get() method, which simply returns when it
- ** has received its limit.
- **
- ** If there is no specific eol or eom string in your expected data
- ** stream use the get() method instead.
- **
- ** Examples:
- **
- ** getln() will return all characters recieved up to and including the
- ** first carrage return or throw a timeout if a carrage return is not
- ** recieved after 10 seconds.
- **
- ** getln("</alert>") will return all characters recieved up to and
- ** including "</alert>" or throw a timeout if "</alert>" is not recieved
- ** within 10 seconds.
- **
- ** getln(":",30) will return all characters recieved up to and including
- ** ":" if ":" is recieved by the 30th character. If 30 characters are recieved
- ** before ":", an overrun_exception would be thrown. A timeout would be
- ** thrown if ":" is not recieved within 10 seconds.
- **
- ** getln(":",30,20) would react exactly like getln(":",30) except the timeout
- ** period would be 20 seconds instead of the default 10.
- **
- ** getln(":",30,-1) will react exactly like getln(":",30) except that no
- ** timeout will ever be thrown. In this case, the method may block
- ** forever if no ":" is received and it never receives 30 characters.
- ** I strongly recommend that at the very least that timeout be a
- ** value >= 0 to this method to prevent program long term program stalls.
- **
- ** If maxlen==0 and timeout<0, this method will block until the eol
- ** string is recieved from the host or maxlen characters
- ** have been recieved. and then return. NOTE: this method could block
- ** forever if the sending host does not send maxlen characters or the
- ** eol string and timeout is < 0;
- **
- ** If maxlen>0 and timeout>0 this method will return upon recieving the
- ** eol string, when maxlen characters have be recieved or when
- ** timeout seconds have expired.
- **
- ** In all cases the method returns a string containing the characters
- ** recieved, if any, including the eol string.
- **
- ** If the timeout expires before eol is recieved or maxlen characters are
- ** recieved a timeout_exception will be thrown.
- **
- ** If maxlen characters are recieved before the eol string is recieved
- ** an overrun_exception will be thown.
- **
- ** If the socket is not connected or closes while being read a
- ** not_open_exception will be thrown.
- **
- ** If an exception is thrown, any characters already recieved
- ** will be available via the exception's comment() method.
- **/
- std::string getln(std::string eol="\r", int maxlen=0, int timeout=10);
-
- /** Returns the local address.
- **
- ** Returns the address in the same form that it needs to be in for the
- ** bind and connect addess arguments.
- **
- ** May throw a buffer_full_exception if there are not enough resources,
- ** or a general_exception if some other problem occurs.
- **/
- std::string get_local_address();
-
- /** Returns the remote address.
- **
- ** Returns the address in the same form that it needs to be in for the
- ** bind and connect addess arguments.
- **
- ** May throw a buffer_full_exception if there are not enough resources,
- ** a not_open_exception if the socket has not been connected to a remote
- ** host, or a general_exception if some other problem occurs.
- **/
- std::string get_remote_address();
+public:
+
+ enum class state {sock_undef,sock_init,sock_connect,sock_close};
+
+protected:
+
+ int mysock {0};
+ bool close_on_destruct {true};
+ state _status {state::sock_undef};
+ int _last_error {0};
+ std::vector<unsigned char> inbuff;
+
+ virtual int transmit(const std::string & data);
+ virtual int receive(std::string & data,int limit);
+
+public:
+
+ /// Use to catch all socket exceptions.
+ class general_exception: public base_exception {};
+ /// Thrown by send or get* if the socket is not open for use.
+ class not_open_exception: public general_exception {};
+ /// Thrown by get* if more than maxlen chars are receieved.
+ class overrun_exception: public general_exception {};
+ /// Thrown if a timeout occured during an operation.
+ class timeout_exception: public general_exception {};
+ /// Thrown if the socket could not connect to the target.
+ class bad_connect_exception: public general_exception {};
+ /// Thrown if the address argument is not interpretable.
+ class bad_address_exception: public general_exception {};
+ /// Thrown by bind() if the address/port is not bindable.
+ class cant_bind_exception: public general_exception {};
+ /// Thrown by close() if an error is reported.
+ class close_exception: public general_exception {};
+ /// Thrown by send if the message is too large.
+ class msg_too_large_exception: public general_exception {};
+ /// Thrown by send if buffer overflows.
+ class buffer_full_exception: public general_exception {};
+ /// Thrown if the socket lib complains of bad args.
+ class bad_args_exception: public general_exception {};
+
+ /** Constructs a tcp_socket.
+ **
+ ** Prepares this socket for use. If autoclose=true the socket will be
+ ** closed when the object is distructed, otherwise it will be left in
+ ** whatever state it happened to be in at the time.
+ **
+ ** BTW, I _don't_ recommend you leave the socket open. If the tcp_socket
+ ** was instanciated via this constructor, there will not be any other
+ ** references to the socket save the one held privately, so a socket left
+ ** open will be there forever. This will almost certainly warrent an
+ ** unpleasent visit by one or more SAs of the box(es) hosting your
+ ** application over time.
+ **
+ ** autoclose=true; it's the only way to be sure. ;)
+ **/
+ tcp_socket(bool autoclose=true);
+
+ /** Constructs from an already existing socket.
+ **
+ ** Constructs the tcp_socket from an already existing socket. This
+ ** constructor is specifically for use with the traditional listen()
+ ** sockets function, and probably should not be used in other contexts.
+ **
+ ** If autoclose is true the socket will be closed on destruction of the
+ ** object, otherwise the socket will be left in whatever state it happened
+ ** to be in at the time. As a general rule I suspect you'll want leave
+ ** autoclose defaulted to true.
+ **
+ ** In most cases where you would use listen(), take a look at the
+ ** tcp_server_socket_factory class; it'll probably do everything you need
+ ** with a minimum of programming overhead.
+ **
+ ** BTW, I _don't_ recommend you leave the socket open. If the socket variable
+ ** used for instanciation was discarded, there will not be any other
+ ** references to the socket save the one held privately, so a socket left
+ ** open will be there forever. This will almost certainly warrent an
+ ** unpleasent visit by one or more SAs of the box(es) hosting your
+ ** application over time.
+ **
+ ** autoclose=true; it's the only way to be sure. ;)
+ **/
+ tcp_socket(int existing_socket, bool autoclose=true);
+
+ /** Destructs a tcp_socket.
+ **
+ ** If autoclose was set to true, the socket will be closed if it is open
+ ** at the time of destruction. If no, the socket will be left in whatever
+ ** state it happened to be in at the time.
+ **/
+ virtual ~tcp_socket();
+
+ /** Resets the socket after a hard error.
+ **
+ ** In cases where the socket was invlidated by the operating system
+ ** (typically cases where a SIGPIPE was raised by the TCP/IP stack),
+ ** use this function to discard the old socket id and aquire a new one.
+ ** Understand that this will make the tcp_socket useful again, but you
+ ** will have to reconnect before any traffic can be sent.
+ **/
+ virtual void reset();
+
+ /** Creates a sockaddr_in from a formatted string.
+ **
+ ** address is an "IP:port" formatted string; i.e. 129.168.1.1:80.
+ ** "*" may use used to substatute for the IP, port or both.
+ **
+ ** Returns a properly formatted sockaddr_in struct for use with connect,
+ ** bind, etc. Throws a bad_address_exception if the address argument is
+ ** mal-formed.
+ **/
+ static sockaddr_in str_to_sockaddr(const std::string & address);
+
+ /** Creates a string from a sockaddr_in.
+ **
+ ** The returned string is of the same format accepted as arguments to the
+ ** to the bind() and connect() methods.
+ **
+ ** May throw a bad_address_exception if the sock_addr_in is not
+ ** properly formatted.
+ **/
+ static std::string sockaddr_to_str(const sockaddr_in & address);
+
+ /** binds the tcp_socket to a local address/port.
+ **
+ ** You do _not_ need to use this method if you are setting up a tcp_socket
+ ** for client use. If you don't call bind an ephemeral port and the host's
+ ** IP number will be assigned, as is normal and preferred for client sockets.
+ **
+ ** In very rare cases where you have a multi-homed host and a real
+ ** requirement to specify which IP this connection uses as local, you can
+ ** use this method to select the port and address the client will use.
+ **
+ ** address: string of the format IP:port; example "255.255.255.255:91".
+ ** If you wish to accept input on any active IP address in this host,
+ ** use "*" for the IP address, as in "*:80". If you want to fix the address
+ ** but leave the port up to the host, use "*" for the port, as in
+ ** "10.101.78.33:*". Obviously, using "*:*" as the address gives the
+ ** same results as not calling this method at all.
+ **
+ ** If the address argument is mal-formed a bad_address_exception will be
+ ** thrown and no changes will be made to the tcp_socket.
+ **
+ ** If the address is not bindable (already in use is a common cause) a
+ ** cant_bind_exception will be thrown.
+ **/
+ void bind(const std::string & address);
+
+ /** Opens the connection.
+ **
+ ** address: string of the format IP:port; example "255.255.255.255:91".
+ ** If the address is mal-formed a bad_address_exception will be thrown.
+ **
+ ** If timeout is specified and >0, the system will not wait more than
+ ** timeout seconds before throwing a timeout_exception.
+ **
+ ** If the connection is not set up properly, a bad_connection_exception
+ ** will be thrown.
+ **/
+ void connect(const std::string & address, int timeout=0);
+
+ /** Closes an open connection.
+ **
+ ** If a problem is reported a close_exception will be thrown. Possible
+ ** causes include the socket not being open, unsent data pending in the
+ ** tcp stack, etc.
+ **/
+ virtual void close();
+
+ /** Returns the current status.
+ **
+ ** Possibles states are tcp_socket::undef, tcp_socket::init,
+ ** tcp_socket::connect, and tcp_socket::close.
+ **/
+ state status() { return _status; };
+
+ /** Returns the last socket error recieved.
+ **
+ ** Will contain zero if no errors have occured on the socket since
+ ** the tcp_socket was instanciated, or the errno returned on the most recent
+ ** error otherwise.
+ **
+ ** Check the man pages for bind(), connect(), close(), socket(), send(),
+ ** and recv() for possible values. They are defined in error.h.
+ **/
+ int last_error() { return _last_error; };
+
+ /** Sends the string to the target host.
+ **
+ ** If timeout is specified and >0, a timeout_exception will be thrown
+ ** if the send does not succeed within timeout seconds.
+ **
+ ** If socket is not connected or closes during sending a
+ ** not_open_exception will be thrown.
+ **
+ ** If an exception is thrown, the characters that were not
+ ** sent will be available via the exception's comment() method (as
+ ** a string, of course).
+ **/
+ int put(std::string s, int timeout=10);
+
+ /** gets a string of characters from the socket.
+ **
+ ** This method allows the reception of a string of characters
+ ** limited by length and time. Use this method when you are expecting a
+ ** stream if data that you either know the length of or where there is
+ ** no specific ending character. If the expected traffic is organized
+ ** into messages or lines ending with a specific character or string,
+ ** use the getln() method instead.
+ **
+ ** Examples:
+ **
+ ** get() or get(1) will return a string containing a single
+ ** character or throw a timeout in 10 seconds if one is not
+ ** recieved.
+ **
+ ** get(100,30) will return when 100 characters have been recieved or
+ ** throw a timeout in 30 seconds.
+ **
+ ** get(100,-1) will return after 100 characters have been recieved, and will
+ ** _never_ time out. I strongly recommend that at the very least use timeout
+ ** values >= 0 to this method to prevent program long term program stalls.
+ **
+ ** If maxlen==0, this method will return immediately with whatever characters
+ ** happen to be in the socket's input buffer at the time.
+ **
+ ** If maxlen>0 and timeout<0, this method will block until maxlen characters
+ ** have been recieved and then return. NOTE: this method could block
+ ** forever if the sending host does not send maxlen characters and timeout
+ ** is < 0.
+ **
+ ** If maxlen>0 and timeout>0 this method will return upon recieving
+ ** maxlen characters or throw a timeout_exception after timeout seconds
+ ** have expired in the worse case.
+ **
+ ** In all cases the method returns a string containing the characters
+ ** recieved, if any.
+ **
+ ** If the timeout expires before the required number of characters are
+ ** recieved a timeout_exception will be thrown.
+ **
+ ** If the socket is not connected or closes while being read a
+ ** not_open_exception will be thrown.
+ **
+ ** If an exception is thrown, any characters already recieved
+ ** will be available via the exception's comment() method.
+ **/
+ std::string get(int maxlen=1, int timeout=10);
+
+ /** gets a string of characters from the socket.
+ **
+ ** This method is for the reception of messages (or lines) that have a
+ ** specific ending string. As such it considers the recept of maxlen
+ ** characters or a timeout without the designated eol string to be
+ ** a problem and will throw an exception in those cases. This behavor
+ ** differs from that of the get() method, which simply returns when it
+ ** has received its limit.
+ **
+ ** If there is no specific eol or eom string in your expected data
+ ** stream use the get() method instead.
+ **
+ ** Examples:
+ **
+ ** getln() will return all characters recieved up to and including the
+ ** first carrage return or throw a timeout if a carrage return is not
+ ** recieved after 10 seconds.
+ **
+ ** getln("</alert>") will return all characters recieved up to and
+ ** including "</alert>" or throw a timeout if "</alert>" is not recieved
+ ** within 10 seconds.
+ **
+ ** getln(":",30) will return all characters recieved up to and including
+ ** ":" if ":" is recieved by the 30th character. If 30 characters are recieved
+ ** before ":", an overrun_exception would be thrown. A timeout would be
+ ** thrown if ":" is not recieved within 10 seconds.
+ **
+ ** getln(":",30,20) would react exactly like getln(":",30) except the timeout
+ ** period would be 20 seconds instead of the default 10.
+ **
+ ** getln(":",30,-1) will react exactly like getln(":",30) except that no
+ ** timeout will ever be thrown. In this case, the method may block
+ ** forever if no ":" is received and it never receives 30 characters.
+ ** I strongly recommend that at the very least that timeout be a
+ ** value >= 0 to this method to prevent program long term program stalls.
+ **
+ ** If maxlen==0 and timeout<0, this method will block until the eol
+ ** string is recieved from the host or maxlen characters
+ ** have been recieved. and then return. NOTE: this method could block
+ ** forever if the sending host does not send maxlen characters or the
+ ** eol string and timeout is < 0;
+ **
+ ** If maxlen>0 and timeout>0 this method will return upon recieving the
+ ** eol string, when maxlen characters have be recieved or when
+ ** timeout seconds have expired.
+ **
+ ** In all cases the method returns a string containing the characters
+ ** recieved, if any, including the eol string.
+ **
+ ** If the timeout expires before eol is recieved or maxlen characters are
+ ** recieved a timeout_exception will be thrown.
+ **
+ ** If maxlen characters are recieved before the eol string is recieved
+ ** an overrun_exception will be thown.
+ **
+ ** If the socket is not connected or closes while being read a
+ ** not_open_exception will be thrown.
+ **
+ ** If an exception is thrown, any characters already recieved
+ ** will be available via the exception's comment() method.
+ **/
+ std::string getln(std::string eol="\r", int maxlen=0, int timeout=10);
+
+ /** Returns the local address.
+ **
+ ** Returns the address in the same form that it needs to be in for the
+ ** bind and connect addess arguments.
+ **
+ ** May throw a buffer_full_exception if there are not enough resources,
+ ** or a general_exception if some other problem occurs.
+ **/
+ std::string get_local_address();
+
+ /** Returns the remote address.
+ **
+ ** Returns the address in the same form that it needs to be in for the
+ ** bind and connect addess arguments.
+ **
+ ** May throw a buffer_full_exception if there are not enough resources,
+ ** a not_open_exception if the socket has not been connected to a remote
+ ** host, or a general_exception if some other problem occurs.
+ **/
+ std::string get_remote_address();
};
/// smart pointer for use with tcp_sockets
-typedef std::unique_ptr<nrtb::tcp_socket> tcp_socket_p;
+typedef std::shared_ptr<nrtb::tcp_socket> tcp_socket_p;
-/** Abstract "listener" TCP/IP socket for servers.
- **
- ** Simplifies the use of TCP/IP sockets for applications providing services.
- ** base_sock implements a free running thread that listens for connections on
- ** the address and port specified and on connection calls the abstract method
- ** on_accept(). Upon return from on_accept the class returns to listening for
- ** the next connection.
- **
- ** Normal useage: This is an abstract class, so you must make a descendent
- ** class that at a minimum overrides on_accept() to provide connection handling.
- ** That aside, a typical sequence for a descendent of this class would be:
- **
- ** (1) construct the object providing the address, port and backlog;
- **
- ** (2) when the application is ready to accept traffic it calls the
- ** start_listen() method to start the listening on the socket;
- **
- ** (3) as each connection is accepted, a new connect_sock* is contructed and
- ** then on_accept() is called;
- **
- ** (4) on_accept() processes the connection, using connect_sock* to receive and
- ** send data. In most cases, on_accept will only place the new tcp_socket in
- ** a queue for other threads to process so that on_accept() can return quickly;
- **
- ** (5) when on_accept() returns we start listening for the next connection.
- **
- ** (6) When the application wishes to stop accepting connections, it calls
- ** the stop_listen() method, which will return when as soon any current calls
- ** to on_accept() complete.
- **
- ** --NOTE--- This class is a tcp_socket_p factory in that a new one
- ** is created for each request received. As the tcp_socket_p is a
- ** smart pointer, the allocated socket will be closed and deallocated
- ** when the last reference to the socket goes out of scope automatically.
- **
- ** Descendent classes must override on_accept() to provide the necessary
- ** connection handling. See the documentation on on_accept for more details.
+/** "listener" TCP/IP socket socket factory for servers.
+ **
+ ** Upon construction this class establishes a listening socket
+ ** on the specified address and port. Each incomming connection
+ ** is automatically accepted and its socket put on queue for other
+ ** tasks to process.
**/
-class tcp_server_socket_factory: private thread
+class tcp_server_socket_factory
{
-
- private:
-
- int _last_thread_fault;
- // Provides the listener thread.
- void run();
- // pointer to the listener socket
- typedef std::shared_ptr<tcp_socket> lsock_p;
- lsock_p listen_sock;
-
- protected:
-
- /// the address:port the listening socket will connect to.
- std::string _address;
- unsigned short int _backlog;
-
- /** Pointer to the socket for the current connection. This is
- ** only safe to use/manipulate after entry of the method on_accept();
- ** at any other time this pointer may be altered without notice.
- **
- ** At entry to on_accept() this will point to a valid tcp_socket_p
- ** smart pointer. As with all smart pointers, the object it
- ** points to will be deleted automatically when the last
- ** reference to it goes out of scope.
- **/
- tcp_socket_p connect_sock;
-
- /** Abstract method to process connections. An on_accept() call is
- ** made on every connection accepted immediately after constructing a
- ** new base_sock socket for it (pointed to by connect_sock).
- **
- ** It is expected that a useful on_accept() method must either place
- ** the connection information (presumably including conect_sock*) on
- ** a queue for the application to process later, or process the connection
- ** itself. It is desireable for on_accept() to return quickly to minimize
- ** connection latency, so for most applications you'll want to queue
- ** the connection for processing by another thread.
- **
- ** on_accept() should return true to contine processing, or false
- ** to force a shutdown of the listener.
- **
- ** WARNING: While this class attempts to respect the integrity of any code
- ** placed in on_accept(), you must be aware that it may be cancelled
- ** quite rudely if any given call to on_accept() takes more than 30
- ** seconds to process. on_accept() is run with the cancel_anytime attribute
- ** set, and this can not be changed from within the method. Therefore,
- ** take care that on_accept() either runs within 30 seconds or at the
- ** very least that it does not hold any resource (mutex, etc.) locks
- ** by the time it's run over 20 seconds or so. Failure to follow these
- ** guidelines could result in program deadlocks should on_accept be
- ** cancelled while holding a resource lock.
- **/
- virtual bool on_accept() = 0;
-
- public:
-
- /// Use to catch all server_socket_factory exceptions.
- class general_exception: public base_exception {};
- /// Thrown if we can not allocate a new connect_sock* as needed.
- class mem_exhasted_exception: public general_exception {};
- /// Thrown by start_listen() if the IP/port could not be bound.
- class bind_failure_exception: public general_exception {};
- /** Thrown by stop_listen() if on_accept takes more than 30 seconds
- ** to return.
- **/
- class on_accept_bound_exception: public general_exception {};
- /// Thrown by by the listen thread in case of unexpected error.
- class listen_terminated_exception: public general_exception {};
-
- /** Construct a tcp_server_socket_factory.
- **
- ** address: std::string of the format IP:port; example "255.255.255.255:91".
- ** if you wish to accept input on any active IP address in this host,
- ** use "*" for the IP address, as in "*:80". The port number is
- ** required.
- **
- ** backlog: The number of backlog connections (connections pending accept)
- ** allowed for this socket. The limit is operating system dependent. If
- ** the supplied value is 0 or less, the default value for the operating
- ** system will be used.
- **/
- tcp_server_socket_factory(const std::string & address,
- const unsigned short int & backlog);
-
- /** Destructs a server_sock.
- **
- ** If the server_sock is currently listening the listener thread is
- ** shut down and the socket released immediately, rudely if necessary.
- **
- ** It's preferable to call stop_listen() before desconstruction to allow
- ** graceful termination of the listener thread and teardown of the port.
- **/
- virtual ~tcp_server_socket_factory();
-
- /** Initiate listening for inbound connections.
- **
- ** This opens the port and spawns the listener thread, then returns
- ** immediately. An exception will be thrown if a problem occurs.
- **
- ** If the listener thread is already running this method returns
- ** immediately without taking any action.
- **
- ** Call this method when your application is ready to start recieving
- ** connections. Once started, the server_sock will call on_accept()
- ** for each connection recieved until stop_listen() is called.
- **/
- void start_listen();
-
- /** Stop listening for inbound connections.
- **
- ** This shuts down the listener thread and tears down the TCP/IP port
- ** before returning. An exception will be thrown if a problem occurs.
- **
- ** If a connection is being actively processed (defined as thread
- ** execution being post accept() and prior to the return of on_accept()),
- ** the return will be delayed until on_accept() is complete, though
- ** the listening socket will be torn down immediately. If on_accept()
- ** fails to return within 30 seconds, the listener thread will be
- ** rudely murdered and an on_accept_bound_exception will be thrown. In the
- ** worse case it may be that the listener thread will not die for some time,
- ** though it should be cleanly cancelable at most any time.
- **
- ** If the listener thread is not running this method returns immediately
- ** without taking any actions.
- **
- ** Call this method when your application wishes to stop recieving input,
- ** even if you are going to restart reception later.
- **/
- void stop_listen();
-
- /** Monitors listening status.
- **
- ** At it's simplist, this method returns true if the socket is listening
- ** for new connections, and false if if it not. Additionally, this
- ** method will throw a listen_terminated_exception if the listener thread
- ** died unexpectedly. Therefore, calling this method periodically is an
- ** easy way to monitor the health of the listener thread.
- **/
- bool listening();
-
- /** Returns the last listen thread fault code.
- **
- ** Will be 0 if the listener has never faulted. If -1, an untrapped
- ** exception was caught (likely thrown by on_accept()); if -2 the thread
- ** did not manage to initialize the listening socket successfully, and
- ** if > 0 then it'll be the error code of the socket error caught that
- ** forced the thread shutdown.
- **
- ** check this if you catch a listen_terminated_exception to find out
- ** what really happened.
- **/
- int last_fault();
-
- /** Returns the max number of backlog connections.
- **/
- unsigned short int backlog();
-
+public:
+
+ /// Use to catch all server_socket_factory exceptions.
+ class general_exception: public base_exception {};
+ /// Thrown if start_listen is called while already listening
+ class already_running_exception: public general_exception {};
+ /// Thrown if we can not allocate a new connect_sock* as needed.
+ class mem_exhasted_exception: public general_exception {};
+ /// Thrown by start_listen() if the IP/port could not be bound.
+ class bind_failure_exception: public general_exception {};
+ /// Thrown by by the listen thread in case of unexpected error.
+ class listen_terminated_exception: public general_exception {};
+ /// handlers should catch this and shutdown gracefully.
+ typedef circular_queue<tcp_socket_p>::queue_not_ready queue_not_ready;
+
+ /** Construct a tcp_server_socket_factory and puts it online.
+ **
+ ** address: std::string of the format IP:port; example "255.255.255.255:91".
+ ** if you wish to accept input on any active IP address in this host,
+ ** use "*" for the IP address, as in "*:80". The port number is
+ ** required.
+ **
+ ** backlog: The number of backlog connections (connections pending accept)
+ ** allowed for this socket. The limit is operating system dependent. If
+ ** the supplied value is 0 or less, the default value for the operating
+ ** system will be used.
+ **
+ ** queue_size: Optional; the size of the queue for connections
+ ** waiting to be serviced. Defaults to 10. If queue_size is
+ ** exceeded, oldest connections will be discarded.
+ **/
+ tcp_server_socket_factory(const std::string & address,
+ const unsigned short int backlog = 5,
+ const int queue_size=10);
+
+ /** Destructs a server_sock.
+ **
+ ** If the server_sock is currently listening the listener thread is
+ ** shut down and the socket released immediately, rudely if necessary.
+ **
+ ** It's preferable to call stop_listen() before desconstruction to allow
+ ** graceful termination of the listener thread and teardown of the port.
+ **/
+ virtual ~tcp_server_socket_factory();
+
+ /// Consumers call this to get a connected socket.
+ tcp_socket_p get_sock() { return pending.pop(); };
+
+ /// returns the number of connections received.
+ int accepted() { return pending.in_count; };
+ /// returns the number of connections consumed.
+ int processed() { return pending.out_count; };
+ /// returns the number of connections waiting to be consumed.
+ int available() { return pending.size(); };
+ /// returns the number of connections dropped due to overflow.
+ int discarded()
+ {
+ return pending.in_count -
+ pending.out_count - pending.size();
+ };
+
+ /** Stop listening for inbound connections.
+ **
+ ** This shuts down the listener thread and tears down the TCP/IP port
+ ** before returning. An exception will be thrown if a problem occurs.
+ **
+ ** If a connection is being actively processed (defined as thread
+ ** execution being post accept() and prior to the return of on_accept()),
+ ** the return will be delayed until on_accept() is complete, though
+ ** the listening socket will be torn down immediately. If on_accept()
+ ** fails to return within 30 seconds, the listener thread will be
+ ** rudely murdered and an on_accept_bound_exception will be thrown. In the
+ ** worse case it may be that the listener thread will not die for some time,
+ ** though it should be cleanly cancelable at most any time.
+ **
+ ** If the listener thread is not running this method returns immediately
+ ** without taking any actions.
+ **
+ ** Call this method when your application wishes to stop recieving input,
+ ** even if you are going to restart reception later.
+ **/
+ void stop_listen();
+
+ /** Starts a stopped listener
+ **/
+ void start_listen();
+
+ /** Monitors listening status.
+ **
+ ** At it's simplist, this method returns true if the socket is listening
+ ** for new connections, and false if if it not. Additionally, this
+ ** method will throw a listen_terminated_exception if the listener thread
+ ** died unexpectedly. Therefore, calling this method periodically is an
+ ** easy way to monitor the health of the listener thread.
+ **/
+ bool listening();
+
+ /** Returns the last listen thread fault code.
+ **
+ ** Will be 0 if the listener has never faulted. If -1, an untrapped
+ ** exception was caught (likely thrown by on_accept()); if -2 the thread
+ ** did not manage to initialize the listening socket successfully, and
+ ** if > 0 then it'll be the error code of the socket error caught that
+ ** forced the thread shutdown.
+ **
+ ** check this if you catch a listen_terminated_exception to find out
+ ** what really happened.
+ **/
+ int last_fault();
+
+ /** Returns the max number of backlog connections.
+ **/
+ unsigned short int backlog();
+
+private:
+
+ // the address:port the listening socket will connect to.
+ std::string _address;
+ unsigned short int _backlog;
+ // stuff for the listener thread
+ std::thread work_thread;
+ std::shared_ptr<tcp_socket> listen_sock {nullptr};
+ std::atomic< int > _last_thread_fault {0};
+ std::atomic< bool > in_run_method {false};
+ // The accepted inbound connection queue
+ nrtb::circular_queue<tcp_socket_p> pending;
+ // Provides the listener thread.
+ static void run(tcp_server_socket_factory * server);
+
};
} // namepace nrtb
=== modified file 'cpp/common/sockets/socket_test.cpp'
--- obsolete/Cpp/common/sockets/socket_test.cpp 2012-04-07 14:16:46 +0000
+++ cpp/common/sockets/socket_test.cpp 2013-08-09 21:47:12 +0000
@@ -19,57 +19,44 @@
#include <iostream>
#include <sstream>
#include <string>
+#include <future>
+#include <typeinfo>
+#include <common.h>
#include <boost/random.hpp>
#include "base_socket.h"
using namespace nrtb;
using namespace std;
-class myserver: public tcp_server_socket_factory
+int request_processor(tcp_server_socket_factory & server)
{
-public:
- int hits;
- int errors;
-
- // constructor
- myserver(const string & a, const unsigned short int & b)
- : tcp_server_socket_factory(a,b)
- {
- // Don't need to lock here because we know the
- // listener thread is not running.
- hits = 0;
- errors = 0;
- };
-
-protected:
-
- // on_accept() is called on each connection.
- bool on_accept()
+ int hits {0};
+ bool done {false};
+ while (!done)
{
try
{
- tcp_socket_p sock = std::move(connect_sock);
+ auto sock = server.get_sock();
// just return what we've recieved.
string msg = sock->getln();
sock->put(msg);
// Update our hit count.
hits++;
}
- catch (base_exception & e)
+ catch (tcp_server_socket_factory::queue_not_ready)
{
- errors++;
- cerr << "server Caught " << e.what() << endl;
+ done = true;
}
- catch (...)
+ catch (exception & e)
{
- errors++;
- cerr << "Unexpected error in on_accept()" << endl;
+ cout << "ReqProc recieved "
+ << typeid(e).name()
+ << endl;
+ done = true;
};
- if (hits > 99)
- return false;
- else
- return true;
- };
+ };
+ cout << "Request processor shut down." << endl;
+ return hits;
};
string transceiver(const string address, const string sendme)
@@ -88,7 +75,11 @@
int main()
{
- int er_count = 0;
+ cout << "=========== tcp_socket and server test ============="
+ << endl;
+
+ int er_count {0};
+ int hits {0};
//set up our port and address
boost::mt19937 rng;
rng.seed(time(0));
@@ -98,14 +89,17 @@
address = s.str();
cout << "Using " << address << endl;
- myserver test_server(address,5);
+ tcp_server_socket_factory test_server(address);
try
{
// start the receiver/server
test_server.start_listen();
cout << "test_server ready." << endl;
-
+ auto rp_out =
+ async(launch::async,request_processor,std::ref(test_server));
+ cout << "Request processor attached." << endl;
+
// Send test messages
for (int i = 0; i < 100; i++)
{
@@ -117,60 +111,22 @@
{
er_count++;
};
- cout << returned.substr(0,returned.size()-1) << ": "
- << ((returned == checkme) ? "Passed" : "Failed")
+ };
+ test_server.stop_listen();
+ hits = rp_out.get();
+ }
+ catch (tcp_server_socket_factory::general_exception & e)
+ {
+ cout << "Server exception "
+ << typeid(e).name() << " was caught."
+ << "\n\tComment: " << e.comment()
<< endl;
- };
- }
- catch (myserver::bind_failure_exception)
- {
- cout << "Could not bind port" << endl;
- }
- catch (myserver::mem_exhasted_exception)
- {
- cout << "myserver reports out of memory." << endl;
- }
- catch (myserver::listen_terminated_exception)
- {
- cout << "Listener terminated unexpectedly." << endl;
- }
- catch (myserver::on_accept_bound_exception)
- {
- cout << "myserver::on_accept() seems bound." << endl;
- }
- catch (tcp_socket::bad_connect_exception & e)
- {
- cout << "A bad_connect_exception was thrown.\n"
- << " comment: " << e.comment() << endl;
- cout << " test_server.last_fault() = "
- << test_server.last_fault() << endl;
- }
- catch (tcp_socket::not_open_exception & e)
- {
- cout << "A tcp not open exception was caught.\n"
- << e.comment() << endl;
- }
- catch (tcp_socket::close_exception & e)
- {
- cout << "A close_exception was caught.\n"
- << e.comment() << endl;
- }
- catch (tcp_socket::overrun_exception & e)
- {
- cout << "An overrun_exception was caught.\n"
- << e.comment() << endl;
- }
- catch (tcp_socket::buffer_full_exception & e)
- {
- cout << "A buffer_full_exception was caught.\n"
- << e.comment() << endl;
}
catch (tcp_socket::general_exception & e)
{
- cout << "A tcp_socket exception was caught.\n"
- << " comment: " << e.comment() << endl;
- cout << " test_server.last_fault() = "
- << test_server.last_fault() << endl;
+ cout << "Socket exception "
+ << typeid(e).name() << " was caught.\n"
+ << "\tComment: " << e.comment() << endl;
}
catch (exception & e)
{
@@ -178,15 +134,25 @@
<< " exception was caught." << endl;
};
+ // test server status billboard
+ cout << "Test Server Results:"
+ << "\n\tAccepted: " << test_server.accepted()
+ << "\n\tProcessed: " << test_server.processed()
+ << "\n\tAvailable: " << test_server.available()
+ << "\n\tDiscarded: " << test_server.discarded()
+ << "\n\tLast Fault: " << test_server.last_fault()
+ << endl;
// final check.
- if (test_server.hits != 100)
+ if (hits != test_server.accepted()
+ or hits != test_server.processed()
+ or test_server.discarded() != 0 )
{
er_count++;
cout << "Server does not report the proper number of hits.\n"
- << "\tExpected 100, got " << test_server.hits
+ << "\tExpected 100, got " << hits
<< endl;
};
- cout << "=========== tcp_socket test complete ============="
+ cout << "=========== tcp_socket and server test complete ============="
<< endl;
return er_count;
=== added directory 'cpp/common/timer'
=== added file 'cpp/common/timer/Makefile'
--- cpp/common/timer/Makefile 1970-01-01 00:00:00 +0000
+++ cpp/common/timer/Makefile 2013-08-09 21:47:12 +0000
@@ -0,0 +1,38 @@
+#***********************************************
+#This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+# NRTB is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# NRTB is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+switches=-std=gnu++11 -D _GLIBCXX_USE_SCHED_YIELD -D _GLIBCXX_USE_NANOSLEEP
+
+lib: timer_test
+ @./timer_test
+ @cp -v hires_timer.h ../include
+ @cp -v hires_timer.o ../obj
+ @echo build complete
+
+hires_timer.o: hires_timer.h hires_timer.cpp Makefile
+ @rm -f hires_timer.o
+ g++ -c -O3 hires_timer.cpp ${switches}
+
+timer_test: hires_timer.o timer_test.cpp
+ @rm -f timer_test
+ g++ -c timer_test.cpp ${switches}
+ g++ -o timer_test timer_test.o hires_timer.o ${switches}
+
+clean:
+ @rm -rvf *.o timer_test ../include/hires_timer.h ../obj/hires_timer.o
+ @echo all objects and executables have been erased.
=== added file 'cpp/common/timer/hires_timer.cpp'
--- cpp/common/timer/hires_timer.cpp 1970-01-01 00:00:00 +0000
+++ cpp/common/timer/hires_timer.cpp 2013-08-09 21:47:12 +0000
@@ -0,0 +1,174 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+/* see ricklib_timers.h for whatever documentation you can find */
+#include "hires_timer.h"
+#include <math.h>
+#include <sstream>
+
+namespace nrtb
+{
+
+hirez_timer::hirez_timer(const double init)
+{
+ reset();
+ start(init);
+};
+
+hirez_timer::hirez_timer(const timeval & init)
+{
+ reset();
+ start(init);
+};
+
+void hirez_timer::reset()
+{
+ running = false;
+ starttime = 0;
+ elapsed = 0;
+};
+
+void hirez_timer::start(const double init)
+{
+ if (!running)
+ {
+ timeval startt;
+ gettimeofday(&startt,0);
+ starttime = tv_to_ll(startt);
+ if (init > 0)
+ {
+ starttime -= double_to_ll(init);
+ };
+ };
+ running = true;
+};
+
+void hirez_timer::start(const timeval & init)
+{
+ starttime = tv_to_ll(init);
+ running = true;
+};
+
+double hirez_timer::stop()
+{
+ stop_timer();
+ return ll_to_double(elapsed);
+};
+
+unsigned long long hirez_timer::stop_as_usec()
+{
+ stop_timer();
+ return elapsed;
+};
+
+double hirez_timer::interval()
+{
+ return ll_to_double(interval_time());
+};
+
+unsigned long long hirez_timer::interval_as_usec()
+{
+ return interval_time();
+};
+
+tm hirez_timer::interval_as_tm()
+{
+ time_t temp = (interval_time()+500000)/1000000;
+ return *gmtime(&temp);
+};
+
+double hirez_timer::ll_to_double(const unsigned long long int ll)
+{
+ return ll / (double) 1e6;
+};
+
+timeval hirez_timer::ll_to_tv(const unsigned long long int ll)
+{
+ timeval t;
+ t.tv_sec = ll / (unsigned long long int) 1e6;
+ t.tv_usec = ll % (unsigned long long int) 1e6;
+ return t;
+};
+
+unsigned long long int hirez_timer::tv_to_ll(const timeval & tv)
+{
+ return ((unsigned long long) tv.tv_sec * (unsigned long long) 1e6)
+ + (unsigned long long) tv.tv_usec;
+};
+
+unsigned long long int hirez_timer::double_to_ll(const double d)
+{
+ return (unsigned long long int) floor(d * 1e6);
+};
+
+void hirez_timer::stop_timer()
+{
+ if (running)
+ {
+ timeval endtime;
+ gettimeofday(&endtime,0);
+ elapsed += (tv_to_ll(endtime) - starttime);
+ };
+ running = false;
+};
+
+unsigned long long int hirez_timer::interval_time()
+{
+ if (running)
+ {
+ timeval endtime;
+ gettimeofday(&endtime,0);
+ return elapsed + (tv_to_ll(endtime) - starttime);
+ }
+ else
+ {
+ return elapsed;
+ };
+};
+
+std::string hirez_timer::interval_as_HMS(const bool days)
+{
+ // local working vars.
+ std::stringstream output;
+ double t1;
+ long int t2;
+ t1 = interval();
+ // Days (only if needed)
+ if (days)
+ {
+ t2 = long(t1) / 86400l;
+ if (t2 > 0)
+ {
+ output << t2 << "d, ";
+ t1 -= t2 * 86400l;
+ };
+ };
+ // hours
+ t2 = long(t1) / 3600;
+ output << t2;
+ t1 -= t2 * 3600;
+ // minutes
+ t2 = long(t1) / 60;
+ output << ((t2 < 10) ? ":0" : ":") << t2;
+ t1 -= t2 * 60;
+ // seconds
+ output << ((t1 < 10) ? ":0" : ":") << t1;
+ return output.str();
+};
+
+} // namespace ricklib;
+
=== added file 'cpp/common/timer/hires_timer.h'
--- cpp/common/timer/hires_timer.h 1970-01-01 00:00:00 +0000
+++ cpp/common/timer/hires_timer.h 2013-08-09 21:47:12 +0000
@@ -0,0 +1,131 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+#ifndef nrtb_timer_h
+#define nrtb_timer_h
+
+#include <sys/time.h>
+#include <time.h>
+#include <string>
+
+namespace nrtb
+{
+
+/** Provides a timer with microsecond (1e-6 second) resolution.
+ **
+ ** Actual resolution on x86 machines is probably closer to 1e-4 or
+ ** -5, but it's still pretty good.
+ **
+ ** Usage notes: instanciating this class will start the timer
+ ** automagically.
+ **/
+class hirez_timer
+{
+ public:
+ /** initializes the timer and starts it.
+ **
+ ** Sets the the timer's elapsed time to init number of seconds and
+ ** then starts the timer.
+ **/
+ hirez_timer(const double init = 0);
+ /** initalizes the timer and starts it.
+ **
+ ** The timer's elapsed time is set to match the value provided in
+ ** init, and the timer is started.
+ **/
+ hirez_timer(const timeval & init);
+
+ /** Clears the timer.
+ **
+ ** If the timer is running, this stops it as well.
+ **/
+ void reset();
+ /** Starts the timer.
+ **
+ ** Starts the timer, and optionally sets the elapsed time at
+ ** startup to the value provided in init.
+ **/
+ void start(const double init = 0);
+ /** Starts the timer.
+ **
+ ** Sets the elapsed time equal to the value provided in init
+ ** and then starts the timer.
+ **/
+ void start(const timeval & init);
+ /** Stops the timer.
+ **
+ ** Unconditionally stops the timer, preserving the current
+ ** values. It may be restarted using the start() method,
+ ** acummulating from where is stopped.
+ **
+ ** Returns the elapsed time in seconds.
+ **/
+ double stop();
+ /** Stops the timer.
+ ** Unconditionally stops the timer, preserving the current
+ ** values. It may be restarted using the start() method,
+ ** acummulating from where is stopped.
+ **
+ ** The return value is the elapsed time in microseconds
+ ** (1e-6 seconds).
+ **/
+ unsigned long long stop_as_usec();
+ /** Returns the current elapsed time.
+ **
+ ** Returns the number of elapsed seconds on the timer. No change
+ ** is made to the timer's status.
+ **/
+ double interval();
+ /** Returns the current elapsed time.
+ **
+ ** Returns the elapsed time in microseconds (1e-6 seconds). No
+ ** change is made to the timer's status.
+ **/
+ unsigned long long interval_as_usec();
+ /** Returns the elapsed time in a tm struct.
+ **
+ ** See "man gmtime" for the structure of the tm struct. In short
+ ** though, this method provides the current timer value in a
+ ** structure where it's broken down into hours, minutes, seconds and
+ ** the like. No change is made to the timer's status.
+ **/
+ tm interval_as_tm();
+ /** Returns the elapsed time in H:MM:SS format
+ **
+ ** Returns the elapsed time in a std::string. The formate is
+ ** H:MM:SS.sssss. No change is made to the timer's status.
+ ** If the optional days parameter is set to true, the number
+ ** of days will be displayed and hours will be < 24, otherwise
+ ** no days are shown and hours will grow as needed (default).
+ **/
+ std::string interval_as_HMS(const bool days = false);
+ private:
+ unsigned long long int starttime;
+ unsigned long long int elapsed;
+ bool running;
+
+ inline double ll_to_double(const unsigned long long int ll);
+ inline timeval ll_to_tv(const unsigned long long int ll);
+ inline unsigned long long int double_to_ll(const double d);
+ inline unsigned long long int tv_to_ll(const timeval & tv);
+ inline void stop_timer();
+ inline unsigned long long int interval_time();
+};
+
+}; // namespace nrtb
+
+#endif // nrtb_timer_h
=== added file 'cpp/common/timer/timer_test.cpp'
--- cpp/common/timer/timer_test.cpp 1970-01-01 00:00:00 +0000
+++ cpp/common/timer/timer_test.cpp 2013-08-09 21:47:12 +0000
@@ -0,0 +1,72 @@
+/***********************************************
+ This file is part of the NRTB project (https://*launchpad.net/nrtb).
+
+ NRTB is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ NRTB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NRTB. If not, see <http://www.gnu.org/licenses/>.
+
+ **********************************************/
+/* hirez_timer test program */
+
+#include <iostream>
+#include <unistd.h>
+#include "hires_timer.h"
+
+using namespace nrtb;
+using namespace std;
+
+int main()
+{
+ hirez_timer overall;
+ hirez_timer interval;
+ int returnme = 0;
+ try
+ {
+ overall.start();
+ interval.start();
+ cout << "sleep 0.1 second" << endl;
+ usleep(1e5);
+ cout << overall.interval() << " | " << interval.stop() << " (stop)" << endl;
+ cout << "sleep 0.3 seconds" << endl;
+ usleep(3e5);
+ cout << overall.interval() << " | " << interval.stop() << " (start)" << endl;
+ interval.start();
+ cout << "sleep 0.2 seconds" << endl;
+ usleep(2e5);
+ cout << overall.interval() << " | " << interval.stop() << " (reset)" << endl;
+ interval.reset();
+ interval.start();
+ cout << "sleep 0.5 seconds" << endl;
+ usleep(5e5);
+ cout << overall.interval() << " | " << interval.stop() << endl;
+ // test the advanced formationg function
+ interval.start(109472.34);
+ interval.stop();
+ cout << "Extended interval_as_HMS() test: \""
+ << interval.interval_as_HMS(true)
+ << "\" or \"" << interval.interval_as_HMS() << "\"" << endl;
+ cout << "Total run time: " << overall.stop() << " seconds." << endl;
+ if ((overall.interval() < 1.1) or (overall.interval() > 1.105))
+ {
+ cerr << "Measured runtime "
+ << overall.interval()
+ << " is outside of expected limits, failed test" << endl;
+ returnme = 1;
+ };
+ }
+ catch (...)
+ {
+ returnme = 1;
+ };
+ return returnme;
+};
+
=== removed file 'obsolete/Cpp/common/logger/log_setup.cpp'
--- obsolete/Cpp/common/logger/log_setup.cpp 2010-12-27 04:21:16 +0000
+++ obsolete/Cpp/common/logger/log_setup.cpp 1970-01-01 00:00:00 +0000
@@ -1,43 +0,0 @@
-/***********************************************
- This file is part of the NRTB project (https://*launchpad.net/nrtb).
-
- NRTB is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- NRTB is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with NRTB. If not, see <http://www.gnu.org/licenses/>.
-
- **********************************************/
-
-#include "log_setup.h"
-
-#include "Poco/SimpleFileChannel.h"
-#include "Poco/FormattingChannel.h"
-#include "Poco/PatternFormatter.h"
-#include "Poco/Logger.h"
-#include "Poco/AutoPtr.h"
-
-using Poco::SimpleFileChannel;
-using Poco::FormattingChannel;
-using Poco::PatternFormatter;
-using Poco::Logger;
-using Poco::AutoPtr;
-
-void nrtb::setup_global_logging(const std::string & logfilename)
-{
- AutoPtr<SimpleFileChannel> pFile(new SimpleFileChannel);
- pFile->setProperty("path", logfilename);
- pFile->setProperty("rotation", "250 K");
- AutoPtr<PatternFormatter> pPF(new PatternFormatter);
- pPF->setProperty("pattern", "%Y-%m-%d %H:%M:%S [%s:%p] %t");
- AutoPtr<FormattingChannel> pFC(new FormattingChannel(pPF, pFile));
- Logger::root().setChannel(pFC);
- Logger::root().notice("Logging system initialized");
-}
\ No newline at end of file
=== removed file 'obsolete/Cpp/common/logger/log_setup.h'
--- obsolete/Cpp/common/logger/log_setup.h 2010-12-27 03:55:39 +0000
+++ obsolete/Cpp/common/logger/log_setup.h 1970-01-01 00:00:00 +0000
@@ -1,30 +0,0 @@
-/***********************************************
- This file is part of the NRTB project (https://*launchpad.net/nrtb).
-
- NRTB is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- NRTB is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with NRTB. If not, see <http://www.gnu.org/licenses/>.
-
- **********************************************/
-
-#ifndef logger_setup_h
-#define logger_setup_h
-
-#include <string>
-
-namespace nrtb
-{
-
- void setup_global_logging(const std::string & logfilename);
-}
-
-#endif //logger_setup_h
\ No newline at end of file
=== removed file 'obsolete/Cpp/common/logger/log_test.cpp'
--- obsolete/Cpp/common/logger/log_test.cpp 2010-12-31 12:21:51 +0000
+++ obsolete/Cpp/common/logger/log_test.cpp 1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
-/***********************************************
- This file is part of the NRTB project (https://*launchpad.net/nrtb).
-
- NRTB is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- NRTB is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with NRTB. If not, see <http://www.gnu.org/licenses/>.
-
- **********************************************/
-
-#include "log_setup.h"
-
-#include <string>
-#include <iostream>
-#include <Poco/Logger.h>
-#include "Poco/LogStream.h"
-
-using namespace std;
-
-int main()
-{
- bool set_if_failed = false;
- try
- {
- nrtb::setup_global_logging("test_output.log");
- Poco::Logger & logger = Poco::Logger::get("log_test");
- logger.notice("Logging should be set up now.");
- Poco::LogStream log(logger);
- log << "This message used the stream interface" << endl;
- logger.notice("Program run complete.");
- }
- catch (...)
- {
- set_if_failed = true;
- cout << "** UNIT TEST FAILED **" << endl;
- };
- return set_if_failed;
-}
=== renamed directory 'D_lang' => 'obsolete/D_lang'
=== added directory 'obsolete/cpp'
=== renamed directory 'obsolete/Cpp/common/GPB' => 'obsolete/cpp/GPB'
=== renamed directory 'obsolete/Cpp/common/comm_handlers' => 'obsolete/cpp/comm_handlers'
=== renamed directory 'obsolete/Cpp/common/threads' => 'obsolete/cpp/threads'
=== renamed directory 'obsolete/Cpp/common/timer' => 'obsolete/cpp/timer'
=== renamed directory 'obsolete/Cpp/common/transceiver' => 'obsolete/cpp/transceiver'
Follow ups