Diffstat (limited to 'noncore/net/opietooth/lib/forwarder.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/net/opietooth/lib/forwarder.cc | 203 |
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 @@ | |||
1 | /* $Id$ | ||
2 | *Bluetooth serial forwarder class implementation | ||
3 | * | ||
4 | *(c) Copyright 2006 GPL | ||
5 | * | ||
6 | *This software is provided under the GNU public license, incorporated | ||
7 | *herein by reference. The software is provided without warranty or | ||
8 | *support. | ||
9 | */ | ||
10 | #include "bt-serial.h" | ||
11 | #include <sys/types.h> | ||
12 | #include <sys/wait.h> | ||
13 | #include <errno.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <qapplication.h> | ||
17 | #include <opie2/oprocctrl.h> | ||
18 | #include "forwarder.h" | ||
19 | using namespace OpieTooth; | ||
20 | using namespace Opie::Core; | ||
21 | using namespace Opie::Core::Internal; | ||
22 | |||
23 | SerialForwarder::SerialForwarder(QString& devName, int dspeed) : | ||
24 | OProcess(), device(devName), speed(dspeed) | ||
25 | { | ||
26 | status = false; | ||
27 | } | ||
28 | |||
29 | SerialForwarder::~SerialForwarder() | ||
30 | { | ||
31 | stop(); | ||
32 | } | ||
33 | |||
34 | |||
35 | bool SerialForwarder::start(RunMode runmode, Communication comm) | ||
36 | { | ||
37 | int htmp; //temporary device | ||
38 | int result; //call result | ||
39 | |||
40 | if ( runs ) | ||
41 | { | ||
42 | return false; // cannot start a process that is already running | ||
43 | // or if no executable has been assigned | ||
44 | } | ||
45 | //First, check if serial device is usable | ||
46 | htmp = ::openSerial(device); | ||
47 | if (htmp < 0) | ||
48 | return false; | ||
49 | close(htmp); | ||
50 | |||
51 | run_mode = runmode; | ||
52 | status = 0; | ||
53 | |||
54 | if(::bt_serialStart() < 0) | ||
55 | return false; | ||
56 | |||
57 | if ( !setupCommunication( comm ) ) | ||
58 | qWarning( "Could not setup Communication!" ); | ||
59 | |||
60 | // We do this in the parent because if we do it in the child process | ||
61 | // gdb gets confused when the application runs from gdb. | ||
62 | uid_t uid = getuid(); | ||
63 | gid_t gid = getgid(); | ||
64 | #ifdef HAVE_INITGROUPS | ||
65 | |||
66 | struct passwd *pw = getpwuid( uid ); | ||
67 | #endif | ||
68 | |||
69 | int fd[ 2 ]; | ||
70 | if ( 0 > pipe( fd ) ) | ||
71 | { | ||
72 | fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue | ||
73 | } | ||
74 | |||
75 | runs = true; | ||
76 | |||
77 | QApplication::flushX(); | ||
78 | |||
79 | // WABA: Note that we use fork() and not vfork() because | ||
80 | // vfork() has unclear semantics and is not standardized. | ||
81 | pid_ = fork(); | ||
82 | |||
83 | if ( 0 == pid_ ) | ||
84 | { | ||
85 | if ( fd[ 0 ] ) | ||
86 | close( fd[ 0 ] ); | ||
87 | if ( !runPrivileged() ) | ||
88 | { | ||
89 | setgid( gid ); | ||
90 | #if defined( HAVE_INITGROUPS) | ||
91 | |||
92 | if ( pw ) | ||
93 | initgroups( pw->pw_name, pw->pw_gid ); | ||
94 | #endif | ||
95 | |||
96 | setuid( uid ); | ||
97 | } | ||
98 | // The child process | ||
99 | if ( !commSetupDoneC() ) | ||
100 | qWarning( "Could not finish comm setup in child!" ); | ||
101 | |||
102 | setupEnvironment(); | ||
103 | |||
104 | // Matthias | ||
105 | if ( run_mode == DontCare ) | ||
106 | setpgid( 0, 0 ); | ||
107 | // restore default SIGPIPE handler (Harri) | ||
108 | struct sigaction act; | ||
109 | sigemptyset( &( act.sa_mask ) ); | ||
110 | sigaddset( &( act.sa_mask ), SIGPIPE ); | ||
111 | act.sa_handler = SIG_DFL; | ||
112 | act.sa_flags = 0; | ||
113 | sigaction( SIGPIPE, &act, 0L ); | ||
114 | |||
115 | // We set the close on exec flag. | ||
116 | // Closing of fd[1] indicates that the execvp succeeded! | ||
117 | if ( fd[ 1 ] ) | ||
118 | fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); | ||
119 | do { | ||
120 | BTSerialConn conn; //Connection handler | ||
121 | if ( fd[ 1 ] ) { | ||
122 | ::close(fd[1]); | ||
123 | fd[1] = 0; | ||
124 | } | ||
125 | result = ::bt_serialForward(&conn, device); | ||
126 | } while(result == 0); | ||
127 | |||
128 | char resultByte = 1; | ||
129 | if ( fd[ 1 ] ) | ||
130 | write( fd[ 1 ], &resultByte, 1 ); | ||
131 | _exit( -1 ); | ||
132 | } | ||
133 | else if ( -1 == pid_ ) | ||
134 | { | ||
135 | // forking failed | ||
136 | |||
137 | runs = false; | ||
138 | return false; | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | if ( fd[ 1 ] ) | ||
143 | close( fd[ 1 ] ); | ||
144 | // the parent continues here | ||
145 | |||
146 | // Discard any data for stdin that might still be there | ||
147 | input_data = 0; | ||
148 | |||
149 | // Check whether client could be started. | ||
150 | if ( fd[ 0 ] ) | ||
151 | for ( ;; ) | ||
152 | { | ||
153 | char resultByte; | ||
154 | int n = ::read( fd[ 0 ], &resultByte, 1 ); | ||
155 | if ( n == 1 ) | ||
156 | { | ||
157 | // Error | ||
158 | runs = false; | ||
159 | close( fd[ 0 ] ); | ||
160 | pid_ = 0; | ||
161 | return false; | ||
162 | } | ||
163 | if ( n == -1 ) | ||
164 | { | ||
165 | if ( ( errno == ECHILD ) || ( errno == EINTR ) ) | ||
166 | continue; // Ignore | ||
167 | } | ||
168 | break; // success | ||
169 | } | ||
170 | if ( fd[ 0 ] ) | ||
171 | close( fd[ 0 ] ); | ||
172 | |||
173 | if ( !commSetupDoneP() ) // finish communication socket setup for the parent | ||
174 | qWarning( "Could not finish comm setup in parent!" ); | ||
175 | |||
176 | if ( run_mode == Block ) | ||
177 | { | ||
178 | commClose(); | ||
179 | |||
180 | // The SIGCHLD handler of the process controller will catch | ||
181 | // the exit and set the status | ||
182 | while ( runs ) | ||
183 | { | ||
184 | OProcessController::theOProcessController-> | ||
185 | slotDoHousekeeping( 0 ); | ||
186 | } | ||
187 | runs = FALSE; | ||
188 | emit processExited( this ); | ||
189 | } | ||
190 | } | ||
191 | return true; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Stop forwarding process | ||
196 | */ | ||
197 | int SerialForwarder::stop() | ||
198 | { | ||
199 | kill(SIGTERM); | ||
200 | ::bt_serialStop(); | ||
201 | return 0; | ||
202 | } | ||
203 | //eof | ||