#13795: Initial commit for sflphone-android
includes: libexpat libyaml libdbus-c++ commoncpp ccrtp
libdbus (from android-4.0.4 sources)
TODO:
- git ignores "/jni/sflphone", sflphone repo should be cloned.
- sflphone-android only needs daemon directory. Ideally it should be possible
to clone it without cloning the whole sflphone project.
into sfl-android (commit 6a0fa7a "#13961: Fix cipher handling" has been used here)
- add pjsip-android project as a git submodule
- sflphone-android needs pjsip android project. Ideally daemon git repository
should not embed pjsip. Instead pjsip should be clone from official repositories.
Considering this, structure should have three distincts git repos:
sflphone-android/.git
sflphone-android/jni/ccrtp-1.8.0-android
sflphone-android/jni/commoncpp2-1.8.1-android
sflphone-android/jni/dbus
sflphone-android/jni/libdbus-c++-0.9.0-android
sflphone-android/jni/libexpat
sflphone-android/jni/libyaml
sflphone-android/jni/sflphone-daemon/.git
sflphone-android/jni/sflphone-daemon/src/audio
sflphone-android/jni/sflphone-daemon/src/config
sflphone-android/jni/sflphone-daemon/src/dbus
sflphone-android/jni/sflphone-daemon/src/history
sflphone-android/jni/sflphone-daemon/src/hooks
sflphone-android/jni/sflphone-daemon/src/iax
sflphone-android/jni/sflphone-daemon/src/sip
sflphone-android/jni/sflphone-daemon/src/video
sflphone-android/jni/pjsip-android/.git
Signed-off-by: Emeric Vigier <emeric.vigier@savoirfairelinux.com>
diff --git a/jni/commoncpp2-1.8.1-android/demo/tcpservice.cpp b/jni/commoncpp2-1.8.1-android/demo/tcpservice.cpp
new file mode 100644
index 0000000..8e16a04
--- /dev/null
+++ b/jni/commoncpp2-1.8.1-android/demo/tcpservice.cpp
@@ -0,0 +1,413 @@
+//
+// tcpservice.cpp
+//
+// Copyright 2000 - Gianni Mariani <gianni@mariani.ws>
+//
+// An example of a simple chatty server using CommonC++.
+//
+// This simple application basically operates as a
+// very simple chat system. From a telnet session
+// on localhost:3999 , any messages typed from a telnet
+// client are written to all participating sessions.
+//
+// This is free software licensed under the terms of the GNU
+// Public License
+//
+// This example:
+//
+// This demostrates a simple threaded server, actually,
+// the sessions are not all threaded though they could be
+// if that's what you wanted. Basically it demonstrates the
+// use of SocketService, SocketPorts and Threads.
+//
+// For those familiar with Unix network programming, SocketService
+// basically encapsulates all the work to communicate with
+// the select() or poll() system calls. SocketPorts are
+// basically encapsulations of sessions or open file descriptors.
+//
+// Anyhow, this example is a very simple echo server but
+// it echos to all connected clients. So it's a poor man's
+// IRC ! You connect via telnet to localhost port 3999 and
+// it will echo to all other connected clients what you type in !
+//
+
+#include <cc++/socketport.h>
+
+#include <iostream>
+
+// For starters, we need a thread safe list, we'll make one
+// out of the STL list<> template -
+// http://www.sgi.com/Technology/STL/index.html
+//
+// Thread safe list class
+//
+#include <list>
+
+#ifdef CCXX_NAMESPACES
+using namespace std;
+using namespace ost;
+#endif
+
+class ts_list_item;
+typedef list<ts_list_item *> ts_list;
+
+// a list head - containing a list and a Mutex.
+// It would be really nice to teach stl to do this.
+
+class ts_list_head {
+public:
+
+ // No point inheriting, I'd have to implement
+ // alot of code. We'll hold off on that exercise.
+
+ // Using the CommonC++ Mutex class.
+ Mutex linkmutex;
+ // And the STL template.
+ ts_list list_o_items;
+
+ // Not nessasary, but nice to be explicit.
+ ts_list_head()
+ : linkmutex(), list_o_items() {
+ }
+
+ // This thing knows how to remove and insert items.
+ void RemoveListItem( ts_list_item * li );
+ void InsertListItem( ts_list_item * li );
+
+ // And it knows how to notify that it became empty
+ // or an element was deleted and it was the last one.
+ virtual void ListDepleted() {
+ }
+
+ virtual ~ts_list_head() {
+ }
+};
+
+
+// This item knows how to remove itself from the
+// list it belongs to.
+class ts_list_item {
+public:
+ ts_list::iterator linkpoint;
+ ts_list_head * listhead;
+
+ virtual ~ts_list_item() {
+ listhead->RemoveListItem( this );
+ }
+
+ ts_list_item( ts_list_head * head ) {
+ listhead = head;
+ head->InsertListItem( this );
+ }
+};
+
+void ts_list_head::RemoveListItem( ts_list_item * li )
+{
+ bool is_empty;
+ linkmutex.enterMutex();
+ list_o_items.erase( li->linkpoint );
+ is_empty = list_o_items.empty();
+ linkmutex.leaveMutex();
+
+ // There is a slim possibility that at this time
+ // we recieve a connection.
+ if ( is_empty ) {
+ ListDepleted();
+ }
+}
+
+void ts_list_head::InsertListItem( ts_list_item * li )
+{
+ linkmutex.enterMutex();
+ list_o_items.push_front( li );
+ li->linkpoint = list_o_items.begin();
+ linkmutex.leaveMutex();
+}
+
+// ChatterSession operates on the individual connections
+// from clients as are managed by the SocketService
+// contained in CCExec. ChatterThread simply waits in
+// a loop to create these, listening forever.
+//
+// Even though the SocketService contains a list of
+// clients it serves, it may actually serve more than
+// one type of session so we create our own list by
+// inheriting the ts_list_item.
+//
+
+class ChatterSession :
+ public virtual SocketPort,
+ public virtual ts_list_item {
+public:
+
+ enum { size_o_buf = 2048 };
+
+ // Nothing special to do here, it's all handled
+ // by SocketPort and ts_list_item
+
+ virtual ~ChatterSession() {
+ cerr << "ChatterSession deleted !\n";
+ }
+
+ // When you create a ChatterSession it waits to accept a
+ // connection. This is done by it's own
+ ChatterSession(
+ TCPSocket & server,
+ SocketService * svc,
+ ts_list_head * head
+ ) :
+ SocketPort( NULL, server ),
+ ts_list_item( head ) {
+ cerr << "ChatterSession Created\n";
+
+ tpport_t port;
+ InetHostAddress ia = getPeer( & port );
+
+ cerr << "connecting from " << ia.getHostname() <<
+ ":" << port << endl;
+
+ // Set up non-blocking reads
+ setCompletion( false );
+
+ // Set yerself to time out in 10 seconds
+ setTimer( 100000 );
+ attach(svc);
+ }
+
+ //
+ // This is called by the SocketService thread when it the
+ // object has expired.
+ //
+
+ virtual void expired() {
+ // Get outa here - this guy is a LOOSER - type or terminate
+ cerr << "ChatterSession Expired\n";
+ delete this;
+ }
+
+ //
+ // This is called by the SocketService thread when it detects
+ // that there is somthing to read on this connection.
+ //
+
+ virtual void pending() {
+ // Implement the echo
+
+ cerr << "Pending called\n";
+
+ // reset the timer
+ setTimer( 100000 );
+ try {
+ int len;
+ unsigned int total = 0;
+ char buf[ size_o_buf ];
+
+ while ( (len = receive(buf, sizeof(buf) )) > 0 ) {
+ total += len;
+ cerr << "Read '";
+ cerr.write( buf, len );
+ cerr << "'\n";
+
+ // Send it to all the sessions.
+ // We probably don't really want to lock the
+ // entire list for the entire time.
+ // The best way to do this would be to place the
+ // message somewhere and use the service function.
+ // But what are examples for ?
+
+ bool sent = false;
+ listhead->linkmutex.enterMutex();
+ for (
+ ts_list::iterator iter = listhead->list_o_items.begin();
+ iter != listhead->list_o_items.end();
+ iter ++
+ ) {
+ ChatterSession * sess =
+ dynamic_cast< ChatterSession * >( * iter );
+ if ( sess != this ) {
+ sess->send( buf, len );
+ sent = true;
+ }
+ }
+ listhead->linkmutex.leaveMutex();
+
+ if ( ! sent ) {
+ send(
+ ( void * ) "No one else listening\n",
+ sizeof( "No one else listening\n" ) - 1
+ );
+
+ send( buf, len );
+ }
+ }
+ if (total == 0) {
+ cerr << "Broken connection!\n" << endl;
+ delete this;
+ }
+ }
+ catch ( ... ) {
+ // somthing wrong happened here !
+ cerr << "Socket port write sent an exception !\n";
+ }
+
+ }
+
+ virtual void disconnect() {
+ // Called by the SocketService thread when the client
+ // hangs up.
+ cerr << "ChatterSession disconnected!\n";
+
+ delete this;
+ }
+
+};
+
+class ChatterThread;
+
+//
+// This is the main application object containing all the
+// state for the application. It uses a SocketService object
+// (and thread) to do all the work, however, that object could
+// theoretically be use by more than one main application.
+//
+// It creates a ChatterThread to sit and wait for connections
+// from clients.
+
+class CCExec : public virtual ts_list_head {
+public:
+
+ SocketService * service;
+ ChatterThread * my_Chatter;
+ Semaphore mainsem[1];
+
+ CCExec():my_Chatter(NULL) {
+ service = new SocketService( 0 );
+ }
+
+ virtual void ListDepleted();
+
+ // These methods defined later.
+ virtual ~CCExec();
+ int RunApp( char * hn = (char *)"localhost" );
+
+};
+
+//
+// ChatterThread simply creates ChatterSession all the time until
+// it has an error. I suspect you could create as many of these
+// as the OS could take.
+//
+
+class ChatterThread : public virtual TCPSocket, public virtual Thread {
+public:
+
+ CCExec * exec;
+
+ void run () {
+ while ( 1 ) {
+ try {
+ // new does all the work to accept a new connection
+ // attach itself to the SocketService AND include
+ // itself in the CCExec list of sessions.
+ new ChatterSession(
+ * ( TCPSocket * ) this,
+ exec->service,
+ exec
+ );
+ }
+ catch ( ... ) {
+ // Bummer - there was an error.
+ cerr << "ChatterSession create failed\n";
+ exit();
+ }
+ }
+ }
+
+ ChatterThread(
+ InetHostAddress & machine,
+ int port,
+ CCExec * inexec
+
+ ) : TCPSocket( machine, port ),
+ Thread(),
+ exec( inexec ) {
+ start();
+ }
+
+
+};
+
+//
+// Bug here, this should go ahead and shut down all sessions
+// for application. An exercise left to the reader.
+
+CCExec::~CCExec()
+{
+ // MUST delete my_Chatter first or it may end up using
+ // a deleted service.
+ if ( my_Chatter ) delete my_Chatter;
+
+ // Delete whatever is left.
+ delete service;
+}
+
+//
+// Run App would normally read some config file or take some
+// parameters about which port to connect to and then
+// do that !
+int CCExec::RunApp( char * hn )
+{
+ // which port ?
+
+ InetHostAddress machine( hn );
+
+ if ( machine.isInetAddress() == false ) {
+ cerr << "machine is not address" << endl;
+ }
+
+ cerr << "machine is " << machine.getHostname() << endl;
+
+ // Start accepting connections - this will bind to the
+ // port as well.
+ try {
+ my_Chatter = new ChatterThread(
+ machine,
+ 3999,
+ this
+ );
+ }
+ catch ( ... ) {
+ cerr << "Failed to bind\n";
+ return false;
+ }
+
+ return true;
+}
+
+// When there is no one else connected - terminate !
+void CCExec::ListDepleted()
+{
+ mainsem->post();
+}
+
+
+int main( int argc, char ** argv )
+{
+ CCExec * server;
+
+ server = new CCExec();
+
+ // take the first command line option as a hostname
+ // to listen to.
+ if ( argc > 1 ) {
+ server->RunApp( argv[ 1 ] );
+ } else {
+ server->RunApp();
+ }
+
+ server->mainsem->wait();
+
+ delete server;
+
+ return 0;
+}