summaryrefslogtreecommitdiff
path: root/noncore/net/opietooth/lib/forwarder.cc
Side-by-side diff
Diffstat (limited to 'noncore/net/opietooth/lib/forwarder.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/net/opietooth/lib/forwarder.cc203
1 files changed, 203 insertions, 0 deletions
diff --git a/noncore/net/opietooth/lib/forwarder.cc b/noncore/net/opietooth/lib/forwarder.cc
new file mode 100644
index 0000000..c38f5b8
--- a/dev/null
+++ b/noncore/net/opietooth/lib/forwarder.cc
@@ -0,0 +1,203 @@
+/* $Id$
+ * Bluetooth serial forwarder class implementation
+ *
+ * (c) Copyright 2006 GPL
+ *
+ * This software is provided under the GNU public license, incorporated
+ * herein by reference. The software is provided without warranty or
+ * support.
+ */
+#include "bt-serial.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <qapplication.h>
+#include <opie2/oprocctrl.h>
+#include "forwarder.h"
+using namespace OpieTooth;
+using namespace Opie::Core;
+using namespace Opie::Core::Internal;
+
+SerialForwarder::SerialForwarder(QString& devName, int dspeed) :
+ OProcess(), device(devName), speed(dspeed)
+{
+ status = false;
+}
+
+SerialForwarder::~SerialForwarder()
+{
+ stop();
+}
+
+
+bool SerialForwarder::start(RunMode runmode, Communication comm)
+{
+ int htmp; //temporary device
+ int result; //call result
+
+ if ( runs )
+ {
+ return false; // cannot start a process that is already running
+ // or if no executable has been assigned
+ }
+ //First, check if serial device is usable
+ htmp = ::openSerial(device);
+ if (htmp < 0)
+ return false;
+ close(htmp);
+
+ run_mode = runmode;
+ status = 0;
+
+ if(::bt_serialStart() < 0)
+ return false;
+
+ if ( !setupCommunication( comm ) )
+ qWarning( "Could not setup Communication!" );
+
+ // We do this in the parent because if we do it in the child process
+ // gdb gets confused when the application runs from gdb.
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+#ifdef HAVE_INITGROUPS
+
+ struct passwd *pw = getpwuid( uid );
+#endif
+
+ int fd[ 2 ];
+ if ( 0 > pipe( fd ) )
+ {
+ fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue
+ }
+
+ runs = true;
+
+ QApplication::flushX();
+
+ // WABA: Note that we use fork() and not vfork() because
+ // vfork() has unclear semantics and is not standardized.
+ pid_ = fork();
+
+ if ( 0 == pid_ )
+ {
+ if ( fd[ 0 ] )
+ close( fd[ 0 ] );
+ if ( !runPrivileged() )
+ {
+ setgid( gid );
+#if defined( HAVE_INITGROUPS)
+
+ if ( pw )
+ initgroups( pw->pw_name, pw->pw_gid );
+#endif
+
+ setuid( uid );
+ }
+ // The child process
+ if ( !commSetupDoneC() )
+ qWarning( "Could not finish comm setup in child!" );
+
+ setupEnvironment();
+
+ // Matthias
+ if ( run_mode == DontCare )
+ setpgid( 0, 0 );
+ // restore default SIGPIPE handler (Harri)
+ struct sigaction act;
+ sigemptyset( &( act.sa_mask ) );
+ sigaddset( &( act.sa_mask ), SIGPIPE );
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigaction( SIGPIPE, &act, 0L );
+
+ // We set the close on exec flag.
+ // Closing of fd[1] indicates that the execvp succeeded!
+ if ( fd[ 1 ] )
+ fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC );
+ do {
+ BTSerialConn conn; //Connection handler
+ if ( fd[ 1 ] ) {
+ ::close(fd[1]);
+ fd[1] = 0;
+ }
+ result = ::bt_serialForward(&conn, device);
+ } while(result == 0);
+
+ char resultByte = 1;
+ if ( fd[ 1 ] )
+ write( fd[ 1 ], &resultByte, 1 );
+ _exit( -1 );
+ }
+ else if ( -1 == pid_ )
+ {
+ // forking failed
+
+ runs = false;
+ return false;
+ }
+ else
+ {
+ if ( fd[ 1 ] )
+ close( fd[ 1 ] );
+ // the parent continues here
+
+ // Discard any data for stdin that might still be there
+ input_data = 0;
+
+ // Check whether client could be started.
+ if ( fd[ 0 ] )
+ for ( ;; )
+ {
+ char resultByte;
+ int n = ::read( fd[ 0 ], &resultByte, 1 );
+ if ( n == 1 )
+ {
+ // Error
+ runs = false;
+ close( fd[ 0 ] );
+ pid_ = 0;
+ return false;
+ }
+ if ( n == -1 )
+ {
+ if ( ( errno == ECHILD ) || ( errno == EINTR ) )
+ continue; // Ignore
+ }
+ break; // success
+ }
+ if ( fd[ 0 ] )
+ close( fd[ 0 ] );
+
+ if ( !commSetupDoneP() ) // finish communication socket setup for the parent
+ qWarning( "Could not finish comm setup in parent!" );
+
+ if ( run_mode == Block )
+ {
+ commClose();
+
+ // The SIGCHLD handler of the process controller will catch
+ // the exit and set the status
+ while ( runs )
+ {
+ OProcessController::theOProcessController->
+ slotDoHousekeeping( 0 );
+ }
+ runs = FALSE;
+ emit processExited( this );
+ }
+ }
+ return true;
+}
+
+/*
+ * Stop forwarding process
+ */
+int SerialForwarder::stop()
+{
+ kill(SIGTERM);
+ ::bt_serialStop();
+ return 0;
+}
+//eof