summaryrefslogtreecommitdiff
path: root/core/obex/obexserver.cpp
Unidiff
Diffstat (limited to 'core/obex/obexserver.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/obex/obexserver.cpp514
1 files changed, 514 insertions, 0 deletions
diff --git a/core/obex/obexserver.cpp b/core/obex/obexserver.cpp
new file mode 100644
index 0000000..95196de
--- a/dev/null
+++ b/core/obex/obexserver.cpp
@@ -0,0 +1,514 @@
1/*
2               =. This file is part of the OPIE Project
3             .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de>
4           .>+-=
5 _;:,     .>    :=|. This library is free software; you can
6.> <,   >  .   <= redistribute it and/or modify it under
7:=1 )Y*s>-.--   : the terms of the GNU Library General Public
8.="- .-=="i,     .._ License as published by the Free Software
9 - .   .-<_>     .<> Foundation; version 2 of the License.
10     ._= =}       :
11    .%+i>       _;_.
12    .i_,=:_.      -<s. This library is distributed in the hope that
13     +  .  -:.       = it will be useful, but WITHOUT ANY WARRANTY;
14    : ..    .:,     . . . without even the implied warranty of
15    =_        +     =;=| MERCHANTABILITY or FITNESS FOR A
16  _.=:.       :    :=>: PARTICULAR PURPOSE. See the GNU
17..}^=.=       =       ; Library General Public License for more
18++=   -.     .     .: details.
19 :     =  ...= . :.=-
20 -.   .:....=;==+<; You should have received a copy of the GNU
21  -_. . .   )=.  = Library General Public License along with
22   --        :-= this library; see the file COPYING.LIB.
23 If not, write to the Free Software Foundation,
24 Inc., 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA.
26
27*/
28/*
29 * The OBEX server class implementation
30 * Based on OBEX server from GPE (thanks, guys)
31 */
32
33#include "obexserver.h"
34#include <unistd.h>
35#include <opie2/odebug.h>
36#include <sys/types.h>
37#include <sys/wait.h>
38#include <errno.h>
39#include <stdlib.h>
40#include <stdio.h>
41#include <fcntl.h>
42#include <qapplication.h>
43#include <opie2/oprocctrl.h>
44#include <qstring.h>
45#include <qfile.h>
46
47using namespace Opie::Core;
48using namespace Opie::Core::Internal;
49using namespace OpieObex;
50
51ObexServer::ObexServer() :
52 OProcess(tr("ObexServer"), 0, "ObexServer")
53{
54 m_obex = NULL;
55}
56
57ObexServer::~ObexServer()
58{
59 stop();
60}
61
62/**
63 * Function handles the file received
64 * @param name the file name
65 * @param data the file data
66 * @param data_len the data length
67 * @return 0 on success -1 on error
68 */
69static int file_received(uint8_t* name, const uint8_t* data, size_t data_len)
70{
71 QString path("/tmp/");
72 path += (char*)name;
73 QFile out(path);
74 int err = 0;
75
76 if (!out.open(IO_Raw | IO_ReadWrite | IO_Truncate)) {
77 printf("File %s open error %d\n", (const char*)path, errno);
78 err = -1;
79 goto out;
80 }
81 if (out.writeBlock((const char*)data, data_len) < 0) {
82 printf("File %s write error %d\n", (const char*)path, errno);
83 err = -1;
84 goto out;
85 }
86out:
87 out.close();
88 if (err == 0) {
89 printf("Wrote %s (%d bytes)\n", (const char*)path, data_len);
90 fflush(stdout);
91 }
92 return err;
93}
94
95/**
96 * Function handles the situation when the PUT request has been done
97 * @param handle OBEX connection handle
98 * @param object OBEX object itself
99 */
100static int put_done(obex_t* handle, obex_object_t* object)
101{
102 obex_headerdata_t hv; //Received file header
103 uint8_t hi; //Type of the request
104 uint32_t hlen; //File (file name) length
105 int err = 0;
106
107 const uint8_t *body = NULL;
108 int body_len = 0;
109 uint8_t* name = NULL;
110
111 while (OBEX_ObjectGetNextHeader (handle, object, &hi, &hv, &hlen)) {
112 switch(hi) {
113 case OBEX_HDR_BODY:
114 body = hv.bs;
115 body_len = hlen;
116 break;
117
118 case OBEX_HDR_NAME:
119 name = new uint8_t[(hlen / 2) + 1];
120 OBEX_UnicodeToChar(name, hv.bs, hlen);
121 break;
122
123 default:
124 break;
125 }
126 }
127
128 if (body)
129 err = file_received(name, body, body_len);
130
131 if (name)
132 delete[] name;
133 return err;
134}
135
136/**
137 * Function handles OBEX request
138 * @param handle OBEX connection handle
139 * @param object OBEX object itself
140 * @param mode
141 * @param event event code
142 * @param cmd OBEX command itself
143 */
144static void handle_request (obex_t* handle, obex_object_t* object,
145 int event, int cmd)
146{
147 (void)event;
148 switch(cmd){
149 case OBEX_CMD_SETPATH:
150 OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
151 break;
152 case OBEX_CMD_PUT:
153 if (put_done (handle, object) < 0)
154 OBEX_ObjectSetRsp (object, OBEX_RSP_INTERNAL_SERVER_ERROR,
155 OBEX_RSP_INTERNAL_SERVER_ERROR);
156 else
157 OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
158 break;
159 case OBEX_CMD_CONNECT:
160 OBEX_ObjectSetRsp (object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
161 break;
162 case OBEX_CMD_DISCONNECT:
163 OBEX_ObjectSetRsp (object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
164 break;
165 default:
166 printf("Denied %02x request\n", cmd);
167 fflush(stdout);
168 OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED,
169 OBEX_RSP_NOT_IMPLEMENTED);
170 break;
171 }
172}
173
174
175/**
176 * Function handles OBEX event when a client is connected to the server
177 * @param handle OBEX connection handle
178 * @param object OBEX object itself
179 * @param mode
180 * @param event event code
181 * @param obex_cmd OBEX command itself
182 * @param obex_rsp OBEX responce
183 */
184static void obex_conn_event (obex_t *handle, obex_object_t *object,
185 int mode, int event, int obex_cmd, int obex_rsp)
186{
187 (void)mode;
188 (void)obex_rsp;
189
190 switch(event) {
191 case OBEX_EV_REQHINT:
192 switch(obex_cmd) {
193 case OBEX_CMD_PUT:
194 case OBEX_CMD_CONNECT:
195 case OBEX_CMD_DISCONNECT:
196 OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
197 break;
198 default:
199 OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED,
200 OBEX_RSP_NOT_IMPLEMENTED);
201 break;
202 }
203 break;
204
205 case OBEX_EV_REQ:
206 /* Comes when a server-request has been received. */
207 handle_request (handle, object, event, obex_cmd);
208 break;
209
210 case OBEX_EV_LINKERR:
211 break;
212 }
213}
214
215/**
216 * Function handles OBEX event
217 * @param handle OBEX connection handle
218 * @param object OBEX object itself
219 * @param mode
220 * @param event event code
221 * @param obex_cmd OBEX command itself
222 * @param obex_rsp OBEX responce
223 */
224static void obex_event (obex_t* handle, obex_object_t* object, int mode,
225 int event, int obex_cmd, int obex_rsp)
226{
227
228 obex_t *obex; //OBEX connection handle
229
230 switch (event) {
231 case OBEX_EV_ACCEPTHINT:
232 obex = OBEX_ServerAccept (handle, obex_conn_event, NULL);
233 break;
234
235 default:
236 obex_conn_event(handle, object, mode, event, obex_cmd, obex_rsp);
237 }
238}
239
240/**
241 * Function registers OBEX push service on a specified channel
242 * Based on The same function from GPE.
243 * @param session SDP session
244 * @param chan channel to listen
245 * @name name to show
246 */
247sdp_session_t* ObexServer::addOpushSvc(uint8_t chan, const char* name)
248{
249 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
250 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
251 sdp_profile_desc_t profile[1];
252 sdp_list_t *aproto, *proto[3];
253 sdp_record_t record;
254 sdp_data_t *channel;
255 uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
256 //uint8_t formats[] = { 0xff };
257 void *dtds[sizeof(formats)], *values[sizeof(formats)];
258 unsigned int i;
259 uint8_t dtd = SDP_UINT8;
260 sdp_data_t *sflist;
261 int err = 0;
262 sdp_session_t* lsession = 0;
263
264 memset((void *)&record, 0, sizeof(sdp_record_t));
265 record.handle = 0xffffffff;
266 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
267 root = sdp_list_append(0, &root_uuid);
268 sdp_set_browse_groups(&record, root);
269
270 sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
271 svclass_id = sdp_list_append(0, &opush_uuid);
272 sdp_set_service_classes(&record, svclass_id);
273
274 sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
275 profile[0].version = 0x0100;
276 pfseq = sdp_list_append(0, profile);
277 sdp_set_profile_descs(&record, pfseq);
278
279 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
280 proto[0] = sdp_list_append(0, &l2cap_uuid);
281 apseq = sdp_list_append(0, proto[0]);
282
283 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
284 proto[1] = sdp_list_append(0, &rfcomm_uuid);
285 channel = sdp_data_alloc(SDP_UINT8, &chan);
286 proto[1] = sdp_list_append(proto[1], channel);
287 apseq = sdp_list_append(apseq, proto[1]);
288
289 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
290 proto[2] = sdp_list_append(0, &obex_uuid);
291 apseq = sdp_list_append(apseq, proto[2]);
292
293 aproto = sdp_list_append(0, apseq);
294 sdp_set_access_protos(&record, aproto);
295
296 for (i = 0; i < sizeof(formats); i++)
297 {
298 dtds[i] = &dtd;
299 values[i] = &formats[i];
300 }
301 sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
302 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
303
304 sdp_set_info_attr(&record, name, 0, 0);
305
306 // connect to the local SDP server, register the service record, and
307 // disconnect
308 lsession = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
309 if (lsession == NULL)
310 goto errout;
311 err = sdp_record_register(lsession, &record, 0);
312 if (err) {
313 sdp_close(lsession);
314 lsession = NULL;
315 }
316errout:
317 sdp_data_free(channel);
318 sdp_list_free(proto[0], 0);
319 sdp_list_free(proto[1], 0);
320 sdp_list_free(proto[2], 0);
321 sdp_list_free(apseq, 0);
322 sdp_list_free(aproto, 0);
323
324 return lsession;
325}
326
327int ObexServer::initObex(void)
328{
329 int channel = 10; //Channel on which we do listen
330 if (m_obex)
331 return 0;
332 m_obex = ::OBEX_Init(OBEX_TRANS_BLUETOOTH, obex_event, 0);
333 if (!m_obex) {
334 printf("OBEX initialization error %d\n", errno);
335 return -1;
336 }
337 ::BtOBEX_ServerRegister(m_obex, NULL, channel);
338 m_session = addOpushSvc(channel, "OBEX push service");
339 if (!m_session) {
340 printf("OBEX registration error %d\n", errno);
341 ::OBEX_Cleanup(m_obex);
342 m_obex = NULL;
343 return -1;
344 }
345 return 0;
346}
347
348bool ObexServer::start(RunMode runmode, Communication comm)
349{
350 if ( runs )
351 {
352 return false; // cannot start a process that is already running
353 // or if no executable has been assigned
354 }
355 run_mode = runmode;
356 status = 0;
357
358 if ( !setupCommunication( comm ) )
359 qWarning( "Could not setup Communication!" );
360
361 // We do this in the parent because if we do it in the child process
362 // gdb gets confused when the application runs from gdb.
363 uid_t uid = getuid();
364 gid_t gid = getgid();
365#ifdef HAVE_INITGROUPS
366
367 struct passwd *pw = getpwuid( uid );
368#endif
369
370 int fd[ 2 ];
371 if ( 0 > pipe( fd ) )
372 {
373 fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue
374 }
375
376 runs = true;
377
378 QApplication::flushX();
379
380 // WABA: Note that we use fork() and not vfork() because
381 // vfork() has unclear semantics and is not standardized.
382 pid_ = fork();
383
384 if ( 0 == pid_ )
385 {
386 if ( fd[ 0 ] )
387 close( fd[ 0 ] );
388 if ( !runPrivileged() )
389 {
390 setgid( gid );
391#if defined( HAVE_INITGROUPS)
392
393 if ( pw )
394 initgroups( pw->pw_name, pw->pw_gid );
395#endif
396
397 setuid( uid );
398 }
399 // The child process
400 if ( !commSetupDoneC() )
401 qWarning( "Could not finish comm setup in child!" );
402
403 setupEnvironment();
404
405 // Matthias
406 if ( run_mode == DontCare )
407 setpgid( 0, 0 );
408 // restore default SIGPIPE handler (Harri)
409 struct sigaction act;
410 sigemptyset( &( act.sa_mask ) );
411 sigaddset( &( act.sa_mask ), SIGPIPE );
412 act.sa_handler = SIG_DFL;
413 act.sa_flags = 0;
414 sigaction( SIGPIPE, &act, 0L );
415
416 // We set the close on exec flag.
417 // Closing of fd[1] indicates that the execvp succeeded!
418 if ( fd[ 1 ] )
419 fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC );
420
421 if (initObex() == 0) {
422 do {
423 int result; //Connection result
424 if ( fd[ 1 ] ) {
425 ::close(fd[1]);
426 fd[1] = 0;
427 }
428 if ((result = OBEX_HandleInput(m_obex, 60)) < 0) {
429 if (errno != ECONNRESET) {
430 printf("OBEX_HandleInput error %d\n", errno);
431 fflush(stdout);
432 _exit(-1);
433 }
434 else
435 _exit(0);
436 }
437 } while(1);
438 }
439 char resultByte = 1;
440 if ( fd[ 1 ] )
441 write( fd[ 1 ], &resultByte, 1 );
442 _exit( -1 );
443 }
444 else if ( -1 == pid_ )
445 {
446 // forking failed
447
448 runs = false;
449 return false;
450 }
451 else
452 {
453 if ( fd[ 1 ] )
454 close( fd[ 1 ] );
455 // the parent continues here
456
457 // Discard any data for stdin that might still be there
458 input_data = 0;
459
460 // Check whether client could be started.
461 if ( fd[ 0 ] )
462 for ( ;; )
463 {
464 char resultByte;
465 int n = ::read( fd[ 0 ], &resultByte, 1 );
466 if ( n == 1 )
467 {
468 // Error
469 runs = false;
470 close( fd[ 0 ] );
471 pid_ = 0;
472 return false;
473 }
474 if ( n == -1 )
475 {
476 if ( ( errno == ECHILD ) || ( errno == EINTR ) )
477 continue; // Ignore
478 }
479 break; // success
480 }
481 if ( fd[ 0 ] )
482 close( fd[ 0 ] );
483
484 if ( !commSetupDoneP() ) // finish communication socket setup for the parent
485 qWarning( "Could not finish comm setup in parent!" );
486
487 if ( run_mode == Block )
488 {
489 commClose();
490
491 // The SIGCHLD handler of the process controller will catch
492 // the exit and set the status
493 while ( runs )
494 {
495 OProcessController::theOProcessController->
496 slotDoHousekeeping( 0 );
497 }
498 runs = FALSE;
499 emit processExited( this );
500 }
501 }
502 return true;
503}
504
505/*
506 * Stop forwarding process
507 */
508int ObexServer::stop()
509{
510 kill(SIGTERM);
511 return 0;
512}
513
514//eof