libsyncml 0.5.4

- Main Page
- Modules
- Data Structures
- Files

- File List

obex_server.c
1 /*
2 * libsyncml - A syncml protocol implementation
3 * Copyright (C) 2005 Armin Bauer <armin.bauer@opensync.org>
4 * Copyright (C) 2008-2009 Michael Bell <michael.bell@opensync.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include <libsyncml/syncml.h>
23 #include <libsyncml/syncml_internals.h>
24 #include <libsyncml/sml_error_internals.h>
25
26 #include <libsyncml/sml_transport_internals.h>
27
28 #include "obex_internals.h"
29 #include "obex_server_internals.h"
30
31 #ifndef WIN32
32 #include <fcntl.h>
33 #include <sys/poll.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <termios.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #endif
41
42 static gboolean _dispatch_obex(gpointer data)
43 {
44 SmlLinkObexServerEnv *linkenv = data;
45
46 int result = OBEX_HandleInput(linkenv->handle, 0);
47 if (result < 0) {
48 SmlError *error = NULL;
49 smlErrorSet(&error, SML_ERROR_GENERIC,
50 "The handling of the obex input failed (%i).",
51 result);
52 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, error);
53 smlTrace(TRACE_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
54 smlErrorDeref(&error);
55 return FALSE;
56 }
57
58 if (linkenv->disconnect) {
59 smlTrace(TRACE_INTERNAL, "%s: disconnecting link", __func__);
60 OBEX_TransportDisconnect(linkenv->handle);
61 // close(linkenv->fd);
62 linkenv->destroy = TRUE;
63 }
64
65
66 if (linkenv->destroy) {
67 smlTrace(TRACE_INTERNAL, "%s: Destroying link %p %p", __func__, linkenv, linkenv->link);
68
69 /* preserve the link and the transport for the disconnect event */
70 SmlTransport *tsp = linkenv->env->tsp;
71 SmlLink *link_ = linkenv->link;
72 smlLinkRef(link_);
73
74 /* the environment must be cleaned up before the event is sent */
75 smlLinkDeref(linkenv->link);
76 g_source_unref(linkenv->source);
77 OBEX_Cleanup(linkenv->handle);
78 if (tsp->context)
79 g_main_context_unref(tsp->context);
80 smlSafeFree((gpointer *)&linkenv);
81 link_->link_data = NULL;
82
83 /* send the event */
84 smlTransportReceiveEvent(tsp, link_, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
85 smlLinkDeref(link_);
86
87 return FALSE;
88 }
89 return TRUE;
90 }
91
92 static void _smlTransportObexServerLinkEvent(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp)
93 {
94 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %i, %i, %i)", __func__, handle, object, mode, event, obex_cmd, obex_rsp);
95 SmlLinkObexServerEnv *linkenv = OBEX_GetUserData(handle);
96 SmlError *error = NULL;
97 obex_headerdata_t header;
98 uint8_t headertype = 0;
99 uint32_t len = 0;
100 uint32_t conid = 0;
101 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
102
103 if (linkenv->disconnect) {
104 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
105 smlTrace(TRACE_EXIT, "%s: This link was disconnected", __func__);
106 return;
107 }
108
109 switch (event) {
110 case OBEX_EV_PROGRESS:
111 smlTrace(TRACE_INTERNAL, "%s: Progress", __func__);
112 break;
113 case OBEX_EV_REQDONE:
114 smlTrace(TRACE_INTERNAL, "%s: Done", __func__);
115 if (obex_cmd == OBEX_CMD_DISCONNECT) {
116 linkenv->destroy = TRUE;
117 }
118 break;
119 case OBEX_EV_REQHINT:
120 smlTrace(TRACE_INTERNAL, "%s: Hint", __func__);
121 /* Comes BEFORE the lib parses anything. */
122 switch (obex_cmd) {
123 case OBEX_CMD_GET:
124 /* At this point we received a get request. If we dont have any data
125 * to send yet, we iterate the main context until the data arrived. */
126 while (!linkenv->send_data && !linkenv->disconnect && !linkenv->error) {
127 if (!g_main_context_pending(linkenv->env->tsp->context)) {
128 usleep(100);
129 continue;
130 }
131 smlTrace(TRACE_INTERNAL, "%s: Dispatching command queue since we dont have data to send", __func__);
132 g_main_context_iteration(linkenv->env->tsp->context, TRUE);
133 }
134
135 /* We received a disconnect event so we reply with an error */
136 if (linkenv->disconnect) {
137 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
138 smlTrace(TRACE_INTERNAL, "%s: Get was aborted", __func__);
139 break;
140 }
141 case OBEX_CMD_PUT:
142 case OBEX_CMD_CONNECT:
143 case OBEX_CMD_DISCONNECT:
144 OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
145 break;
146 default:
147 OBEX_ObjectSetRsp(object, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED);
148 break;
149 }
150 break;
151 case OBEX_EV_REQ:
152 switch (obex_cmd) {
153 case OBEX_CMD_SETPATH:
154 smlTrace(TRACE_INTERNAL, "%s: Got SETPATH command", __func__);
155 OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
156 break;
157 case OBEX_CMD_PUT:;
158 smlTrace(TRACE_INTERNAL, "%s: Got PUT command", __func__);
159 uint32_t length = 0;
160 char *body = NULL;
161
162 while (OBEX_ObjectGetNextHeader(handle, object, &headertype, &header, &len)) {
163 smlTrace(TRACE_INTERNAL, "%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
164 switch (headertype) {
165 case OBEX_HDR_CONNECTION:
166 smlTrace(TRACE_INTERNAL, "%s: Found connection number: %d", __func__, header.bq4);
167 conid = header.bq4;
168 break;
169 case OBEX_HDR_TYPE:;
170 char *mimetypestr = g_strndup((char *)header.bs, len);
171 /*char *mimetypestr = g_malloc0(len);// / 2 + 1);
172 if (OBEX_UnicodeToChar((unsigned char *)mimetypestr, header.bs, len / 2 + 1) == -1) {
173 smlSafeCFree(&mimetypestr);
174 smlErrorSet(&error, SML_ERROR_GENERIC, "unable to convert from unicode");
175 goto error;
176 }*/
177
178 smlTrace(TRACE_INTERNAL, "%s: Found type: %s", __func__, VA_STRING(mimetypestr));
179
180 if (!strcmp(mimetypestr, SML_ELEMENT_WBXML)) {
181 mimetype = SML_MIMETYPE_WBXML;
182 } else if (!strcmp(mimetypestr, SML_ELEMENT_XML)) {
183 mimetype = SML_MIMETYPE_XML;
184 } else if (!strcmp(mimetypestr, SML_ELEMENT_SAN)) {
185 mimetype = SML_MIMETYPE_SAN;
186 } else {
187 smlSafeCFree(&mimetypestr);
188 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mime type");
189 goto error;
190 }
191
192 smlSafeCFree(&mimetypestr);
193 break;
194 case OBEX_HDR_LENGTH:
195 smlTrace(TRACE_INTERNAL, "%s: Found length: %d", __func__, header.bq4);
196 length = header.bq4;
197 break;
198 case OBEX_HDR_BODY:
199 if (!length) {
200 smlErrorSet(&error, SML_ERROR_GENERIC, "Length must come before the body");
201 goto error;
202 }
203
204 /* We need one byte more than the response length
205 * because the data can be a native XML message.
206 * If the data is a native XML message then it is
207 * sometimes directly used as string.
208 *
209 * The string is automatically NULL terminated
210 * because smlTryMalloc0 fills the new memory with NULLs.
211 */
212 body = smlTryMalloc0(length + 1, &error);
213 if (!body)
214 goto error;
215
216 memcpy(body, header.bs, length);
217 break;
218 default:
219 smlTrace(TRACE_INTERNAL, "%s: Unknown header", __func__);
220 }
221 }
222
223 if (!conid) {
224 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing connection id");
225 goto error;
226 }
227
228 if (conid != linkenv->conid) {
229 smlErrorSet(&error, SML_ERROR_GENERIC, "Wrong connection id");
230 goto error;
231 }
232
233 if (mimetype == SML_MIMETYPE_UNKNOWN) {
234 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing mime type");
235 goto error;
236 }
237
238 if (!length) {
239 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing length");
240 goto error;
241 }
242
243 if (!body) {
244 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing body");
245 goto error;
246 }
247
248 SmlTransportData *tspdata = smlTransportDataNew(body, length, mimetype, TRUE, &error);
249 if (!tspdata)
250 goto error;
251
252 if (smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_DATA, tspdata, NULL))
253 OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
254 else
255 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
256
257 smlTransportDataDeref(tspdata);
258 break;
259 case OBEX_CMD_GET:;
260 smlTrace(TRACE_INTERNAL, "%s: Got GET command", __func__);
261
262 while (OBEX_ObjectGetNextHeader(handle, object, &headertype, &header, &len)) {
263 smlTrace(TRACE_INTERNAL, "%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
264 switch (headertype) {
265 case OBEX_HDR_CONNECTION:
266 smlTrace(TRACE_INTERNAL, "%s: Found connection number: %d", __func__, header.bq4);
267 conid = header.bq4;
268 break;
269 case OBEX_HDR_TYPE:;
270 char *mimetypestr = g_strndup((char *)header.bs, len);
271 /*char *mimetypestr = g_malloc0(len / 2 + 1);
272 if (OBEX_UnicodeToChar((unsigned char *)mimetypestr, header.bs, len / 2 + 1) == -1) {
273 smlSafeCFree(&mimetypestr);
274 smlErrorSet(&error, SML_ERROR_GENERIC, "unable to convert from unicode");
275 goto error;
276 }*/
277
278 smlTrace(TRACE_INTERNAL, "%s: Found type: %s", __func__, VA_STRING(mimetypestr));
279
280 if (!strcmp(mimetypestr, SML_ELEMENT_WBXML)) {
281 mimetype = SML_MIMETYPE_WBXML;
282 } else if (!strcmp(mimetypestr, SML_ELEMENT_XML)) {
283 mimetype = SML_MIMETYPE_XML;
284 } else if (!strcmp(mimetypestr, SML_ELEMENT_SAN)) {
285 mimetype = SML_MIMETYPE_SAN;
286 } else {
287 smlSafeCFree(&mimetypestr);
288 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mime type");
289 goto error;
290 }
291
292 smlSafeCFree(&mimetypestr);
293 break;
294 default:
295 smlTrace(TRACE_INTERNAL, "%s: Unknown header", __func__);
296 }
297 }
298
299 if (!conid) {
300 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing connection id");
301 goto error;
302 }
303
304 if (conid != linkenv->conid) {
305 smlErrorSet(&error, SML_ERROR_GENERIC, "Wrong connection id");
306 goto error;
307 }
308
309 if (mimetype == SML_MIMETYPE_UNKNOWN) {
310 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing mime type");
311 goto error;
312 }
313
314 if (linkenv->error) {
315 if (smlErrorGetClass(&(linkenv->error)) <= SML_ERRORCLASS_RETRY)
316 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
317 else
318 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
319
320 smlErrorDeref(&(linkenv->error));
321 linkenv->error = NULL;
322 smlTrace(TRACE_INTERNAL, "%s: Sent error in response to get", __func__);
323 break;
324 }
325
326 if (!linkenv->send_data) {
327 smlErrorSet(&error, SML_ERROR_GENERIC, "No data to send");
328 goto error;
329 }
330
331 if (mimetype != linkenv->send_data->type) {
332 smlErrorSet(&error, SML_ERROR_GENERIC,
333 "Wrong mimetype %d requested. %d was expected.",
334 mimetype, linkenv->send_data->type);
335 goto error;
336 }
337
338 /* Now the data and size */
339 header.bq4 = (uint32_t)linkenv->send_data->size;
340 OBEX_ObjectAddHeader(handle, object, OBEX_HDR_LENGTH, header, sizeof(uint32_t), 0);
341
342 header.bs = (unsigned char *)linkenv->send_data->data;
343 OBEX_ObjectAddHeader(handle, object, OBEX_HDR_BODY, header, linkenv->send_data->size, 0);
344
345 smlTransportDataDeref(linkenv->send_data);
346 linkenv->send_data = NULL;
347
348 OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
349 break;
350 case OBEX_CMD_CONNECT:;
351 smlTrace(TRACE_INTERNAL, "%s: Got CONNECT command", __func__);
352 char *target = NULL;
353
354 while (OBEX_ObjectGetNextHeader(handle, object, &headertype, &header, &len)) {
355 smlTrace(TRACE_INTERNAL, "%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
356 switch (headertype) {
357 case OBEX_HDR_TARGET:
358 target = g_strndup((char *)header.bs, len);
359 smlTrace(TRACE_INTERNAL, "%s: Found target: %s", __func__, VA_STRING(target));
360 break;
361 default:
362 smlTrace(TRACE_INTERNAL, "%s: Unknown header", __func__);
363 }
364 }
365
366 if (!target || strcmp(target, "SYNCML-SYNC")) {
367 smlSafeCFree(&target);
368 smlErrorSet(&error, SML_ERROR_GENERIC, "Missing target");
369 goto error;
370 }
371 smlSafeCFree(&target);
372
373 header.bq4 = linkenv->conid;
374 OBEX_ObjectAddHeader(handle, object, OBEX_HDR_CONNECTION, header, sizeof(linkenv->conid), OBEX_FL_FIT_ONE_PACKET);
375
376 header.bs = (unsigned char *)"SYNCML-SYNC";
377 OBEX_ObjectAddHeader(handle, object, OBEX_HDR_WHO, header, strlen((char *)header.bs), OBEX_FL_FIT_ONE_PACKET);
378
379
380 linkenv->link = smlLinkNew(linkenv->env->tsp, linkenv, &error);
381 if (!linkenv->link)
382 goto error;
383
384 if (smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL))
385 OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
386 else {
387 OBEX_ObjectSetRsp(object, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
388 linkenv->disconnect = TRUE;
389 }
390 break;
391 case OBEX_CMD_DISCONNECT:
392 smlTrace(TRACE_INTERNAL, "%s: Got DISCONNECT command", __func__);
393 OBEX_ObjectSetRsp(object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
394 break;
395 default:
396 smlTrace(TRACE_INTERNAL, "%s: Denied %02x request", __func__, obex_cmd);
397 OBEX_ObjectSetRsp(object, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED);
398 break;
399 }
400
401 break;
402 case OBEX_EV_LINKERR:
403 smlTrace(TRACE_INTERNAL, "%s: Link broken (this does not have to be an error)!", __func__);
404 break;
405 default:
406 smlTrace(TRACE_INTERNAL, "%s: Unknown event!", __func__);
407 break;
408 }
409
410 smlTrace(TRACE_EXIT, "%s", __func__);
411 return;
412
413 error:
414 OBEX_ObjectSetRsp(object, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST);
415 smlErrorRef(&error);
416 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, error);
417 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
418 smlErrorDeref(&error);
419 }
420
421 static void _smlTransportObexServerMainEvent(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp)
422 {
423 smlTrace(TRACE_ENTRY, "%s(%p, %p, %i, %i, %i, %i)",
424 __func__, handle, object, mode, event, obex_cmd, obex_rsp);
425 SmlTransportObexServerEnv *env = OBEX_GetUserData(handle);
426 SmlError *error = NULL;
427 SmlLinkObexServerEnv *linkenv = NULL;
428
429 switch (event) {
430 case OBEX_EV_ACCEPTHINT:
431 /* This event means that there is a new connection. */
432
433 /* Create the env that handles this link */
434 linkenv = smlTryMalloc0(sizeof(SmlLinkObexServerEnv), &error);
435 if (!linkenv)
436 goto error;
437 linkenv->env = env;
438
439 linkenv->handle = OBEX_ServerAccept(env->handle, _smlTransportObexServerLinkEvent, linkenv);
440 if (!linkenv->handle) {
441 smlErrorSet(&error, SML_ERROR_GENERIC,
442 "OBEX_ServerAccept failed.");
443 smlSafeFree((gpointer *)&linkenv);
444 goto error;
445 }
446 smlTrace(TRACE_INTERNAL, "%s: New obex_t * handle %p", __func__, linkenv->handle);
447
448 /* Now we create a source that watches the new obex connection */
449 linkenv->source = g_idle_source_new();
450 g_source_set_callback(linkenv->source, _dispatch_obex, linkenv, NULL);
451 g_source_attach(linkenv->source, env->tsp->context);
452 if (env->tsp->context)
453 g_main_context_ref(env->tsp->context);
454
455 /* We first have to add the connection id which we generate for this transport */
456 env->lastConId++;
457 linkenv->conid = env->lastConId;
458
459 // the user data was already ste accept
460 // OBEX_SetUserData(linkenv->handle, linkenv);
461
462 break;
463 default:
464 smlErrorSet(&error, SML_ERROR_GENERIC,
465 "Unknown OBEX event %d.", event);
466 goto error;
467 break;
468 }
469
470 smlTrace(TRACE_EXIT, "%s", __func__);
471 return;
472
473 error:
474 OBEX_ObjectSetRsp(object, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST);
475 smlErrorRef(&error);
476 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
477 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(&error));
478 smlErrorDeref(&error);
479 }
480
481 /* These function supervise the file descriptor where we are listening for incoming
482 * connections */
483 static gboolean _fd_prepare(GSource *source, gint *timeout_)
484 {
485 smlTrace(TRACE_INTERNAL, "%s(%p, %p)", __func__, source, timeout_);
486 /* There is no need to dispatch this too fast since
487 * it does not influence the transmission of data, only
488 * the connection */
489 *timeout_ = 50;
490 return FALSE;
491 }
492
493 static gboolean _fd_check(GSource *source)
494 {
495 SmlTransportObexServerEnv *env = *((SmlTransportObexServerEnv **)(source + 1));
496
497 fd_set rfds;
498 FD_ZERO(&rfds);
499 int fd = OBEX_GetFD(env->handle);
500 FD_SET(fd, &rfds);
501
502 struct timeval tv;
503 tv.tv_sec = 0;
504 tv.tv_usec = 1;
505
506 int retval = select(fd + 1, &rfds, NULL, NULL, &tv);
507
508 if (retval == -1)
509 smlTrace(TRACE_ERROR, "%s: Unable to select()", __func__);
510 else if (retval)
511 return TRUE;
512
513 return FALSE;
514 }
515
516 static gboolean _fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
517 {
518 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, source, callback, user_data);
519 SmlTransportObexServerEnv *env = user_data;
520 SmlError *error = NULL;
521
522 /* this is a non-locking function */
523 int result = OBEX_HandleInput(env->handle, 0);
524 if (result < 0) {
525 smlErrorSet(&error, SML_ERROR_GENERIC,
526 "OBEX_HandleInput on main handle returned %d.",
527 result);
528 goto error;
529 }
530 if (result == 0) {
531 smlErrorSet(&error, SML_ERROR_GENERIC,
532 "OBEX_HandleInput on main handle get a timeout.");
533 goto error;
534 }
535
536 smlTrace(TRACE_EXIT, "%s", __func__);
537 return TRUE;
538 error:
539 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
540 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
541 return FALSE;
542 }
543
544 static SmlBool smlTransportObexServerSetConfigOption(
545 SmlTransport *tsp,
546 const char *name,
547 const char *value,
548 SmlError **error)
549 {
550 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
551 CHECK_ERROR_REF
552 smlAssert(tsp);
553 smlAssert(tsp->transport_data);
554 SmlTransportObexServerEnv *env = tsp->transport_data;
555
556 if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
557 env->port = atoi(value);
558 smlTrace(TRACE_INTERNAL, "%s: Port %i detected", __func__, env->port);
559 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS)) {
560 #ifdef ENABLE_BLUETOOTH
561 int code = str2ba(value, env->bdaddr);
562 if (code != 0) {
563 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
564 "Bluetooth MAC cannot be interpreted (%d).", code);
565 goto error;
566 }
567 smlTrace(TRACE_INTERNAL, "%s: Bluetooth MAC %s detected",
568 __func__, VA_STRING(value));
569 #else
570 smlErrorSet(error, SML_ERROR_GENERIC, "Bluetooth not enabled");
571 goto error;
572 #endif
573 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL)) {
574 env->port = atoi(value);
575 smlTrace(TRACE_INTERNAL, "%s: Bluetooth channel %i detected",
576 __func__, env->port);
577 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_IRDA_SERVICE)) {
578 env->irda_service = g_strdup(value);
579 smlTrace(TRACE_INTERNAL, "%s: IRDA service %s detected",
580 __func__, VA_STRING(env->irda_service));
581 } else {
582 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
583 "Unknown parameter %s found.", name);
584 goto error;
585 }
586
587 smlTrace(TRACE_EXIT, "%s - TRUE", __func__);
588 return TRUE;
589 error:
590 smlTrace(TRACE_EXIT, "%s - %s", __func__, smlErrorPrint(error));
591 return FALSE;
592 }
593
594 static SmlBool smlTransportObexServerSetConnectionType(
595 SmlTransport *tsp,
596 SmlTransportConnectionType type,
597 SmlError **error)
598 {
599 smlTrace(TRACE_ENTRY, "%s(%p, %i, %p)", __func__, tsp, type, error);
600 CHECK_ERROR_REF
601 smlAssert(tsp);
602 smlAssert(tsp->transport_data);
603 SmlTransportObexServerEnv *env = tsp->transport_data;
604
605 env->type = type;
606
607 smlTrace(TRACE_EXIT, "%s", __func__);
608 return TRUE;
609 }
610
611 static SmlBool smlTransportObexServerInit(SmlTransport *tsp, SmlError **error)
612 {
613 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
614 CHECK_ERROR_REF
615 smlAssert(tsp);
616 smlAssert(tsp->transport_data);
617 SmlTransportObexServerEnv *env = tsp->transport_data;
618 smlAssert(env->handle == NULL);
619
620 switch (env->type) {
621 #ifdef ENABLE_OPENOBEX_TCP
622 case SML_TRANSPORT_CONNECTION_TYPE_NET:;
623 /* init object */
624 env->handle = OBEX_Init(OBEX_TRANS_INET,
625 _smlTransportObexServerMainEvent,
626 OBEX_FL_KEEPSERVER);
627 if (!env->handle) {
628 smlErrorSet(error, SML_ERROR_GENERIC,
629 "Unable to create OBEX IRDA transport.");
630 goto error;
631 }
632 OBEX_SetUserData(env->handle, env);
633 /* prepare IP address etc. */
634 if (!env->port)
635 g_warning("Using default INET port.");
636 size_t size = sizeof(struct sockaddr_in);
637 struct sockaddr_in *addr = smlTryMalloc0(size, error);
638 if (!addr)
639 goto error;
640 addr->sin_family = PF_INET;
641 addr->sin_port = htons(env->port);
642 addr->sin_addr.s_addr = INADDR_ANY;
643 /* register server */
644 if (GET_OBEX_RESULT(TcpOBEX_ServerRegister(env->handle, (struct sockaddr *) addr, size)) < 0)
645 {
646 smlErrorSet(error, SML_ERROR_GENERIC,
647 "Unable to register INET OBEX server. %s (%i).",
648 strerror(errno), errno);
649 smlSafeFree((gpointer *)&addr);
650 goto error;
651 }
652 smlSafeFree((gpointer *)&addr);
653 break;
654 #endif /* ENABLE_OPENOBEX_TCP */
655 case SML_TRANSPORT_CONNECTION_TYPE_SERIAL:
656 /* init object */
657 env->handle = OBEX_Init(OBEX_TRANS_IRDA,
658 _smlTransportObexServerMainEvent,
659 OBEX_FL_KEEPSERVER);
660 if (!env->handle) {
661 smlErrorSet(error, SML_ERROR_GENERIC,
662 "Unable to create OBEX IRDA transport.");
663 goto error;
664 }
665 OBEX_SetUserData(env->handle, env);
666 /* register server */
667 if (GET_OBEX_RESULT(IrOBEX_ServerRegister(env->handle, env->irda_service)))
668 {
669 smlErrorSet(error, SML_ERROR_GENERIC,
670 "Unable to register IRDA OBEX server. %s (%i).",
671 strerror(errno), errno);
672 goto error;
673 }
674 break;
675 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
676 #ifdef ENABLE_BLUETOOTH
677 /* init object */
678 env->handle = OBEX_Init(OBEX_TRANS_BLUETOOTH,
679 _smlTransportObexServerMainEvent,
680 OBEX_FL_KEEPSERVER);
681 if (!env->handle) {
682 smlErrorSet(error, SML_ERROR_GENERIC,
683 "Unable to create OBEX Bluetooth transport.");
684 goto error;
685 }
686 OBEX_SetUserData(env->handle, env);
687 /* register server */
688 if (GET_OBEX_RESULT(BtOBEX_ServerRegister(env->handle, env->bdaddr, env->port)) < 0)
689 {
690 smlErrorSet(error, SML_ERROR_GENERIC,
691 "Unable to register Bluetooth OBEX server. %s (%i).",
692 strerror(errno), errno);
693 goto error;
694 }
695 #else
696 smlErrorSet(error, SML_ERROR_GENERIC, "Bluetooth not enabled");
697 goto error;
698 #endif
699 break;
700 default:
701 smlErrorSet(error, SML_ERROR_GENERIC, "Unknown obex type");
702 goto error;
703 }
704 smlTrace(TRACE_INTERNAL, "%s: server registered successfully", __func__);
705
706 /* Now we create a source that watches for incoming connection requests */
707 env->functions = smlTryMalloc0(sizeof(GSourceFuncs), error);
708 if (!env->functions)
709 goto error;
710 env->functions->prepare = _fd_prepare;
711 env->functions->check = _fd_check;
712 env->functions->dispatch = _fd_dispatch;
713 env->functions->finalize = NULL;
714
715 env->source = g_source_new(env->functions, sizeof(GSource) + sizeof(SmlTransportObexServerEnv *));
716 SmlTransportObexServerEnv **envptr = (SmlTransportObexServerEnv **)(env->source + 1);
717 *envptr = env;
718 g_source_set_callback(env->source, NULL, env, NULL);
719 g_source_attach(env->source, tsp->context);
720 if (tsp->context)
721 g_main_context_ref(tsp->context);
722
723 smlTrace(TRACE_EXIT, "%s: %p", __func__, env);
724 return TRUE;
725
726 error:
727 if (env->handle) {
728 OBEX_Cleanup(env->handle);
729 env->handle = NULL;
730 }
731 if (env)
732 smlSafeFree((gpointer *)&env);
733 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
734 return FALSE;
735 }
736
737 static SmlBool smlTransportObexServerFinalize(void *data, SmlError **error)
738 {
739 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, error);
740 CHECK_ERROR_REF
741 smlAssert(data);
742 SmlTransportObexServerEnv *env = data;
743
744 smlAssert(env->tsp);
745
746 if (env->handle)
747 OBEX_Cleanup(env->handle);
748
749 /* detach source */
750 if (env->source) {
751 g_source_destroy(env->source);
752 g_source_unref(env->source);
753 }
754
755 /* free context */
756 if (env->tsp->context)
757 g_main_context_unref(env->tsp->context);
758
759 /* free functions */
760 if (env->functions)
761 smlSafeFree((gpointer *)&(env->functions));
762
763
764 if (env->irda_service)
765 smlSafeCFree(&(env->irda_service));
766
767 smlSafeFree((gpointer *)&env);
768
769 smlTrace(TRACE_EXIT, "%s", __func__);
770 return TRUE;
771 }
772
773 static void smlTransportObexServerSend(void *userdata, void *linkdata, SmlTransportData *data, SmlError *error)
774 {
775 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, userdata, linkdata, data, error);
776 smlAssert(data || error);
777 smlAssert(userdata);
778 // Unused: SmlTransportObexServerEnv *env = userdata;
779 SmlLinkObexServerEnv *linkenv = linkdata;
780 smlAssert(linkenv);
781 SmlError *local_error = NULL;
782
783 if (linkdata == NULL) {
784 /* send is called before connect succeeded or
785 * the user of the library ignored the link
786 */
787 smlErrorSet(&local_error, SML_ERROR_GENERIC,
788 "The OBEX server tries to send before a connection with a client was established or the link was ignored.");
789 goto error;
790 }
791
792 if (error) {
793 smlAssert(!data);
794 linkenv->error = error;
795
796 smlTrace(TRACE_EXIT, "%s: Error set", __func__);
797 return;
798 }
799
800 if (linkenv->send_data) {
801 smlErrorSet(&local_error, SML_ERROR_GENERIC, "We already have waiting data");
802 goto error;
803 }
804
805 linkenv->send_data = data;
806 smlTransportDataRef(linkenv->send_data);
807
808 smlTrace(TRACE_EXIT, "%s", __func__);
809 return;
810
811 error:
812 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&local_error));
813 smlTransportReceiveEvent(linkenv->env->tsp, linkenv->link, SML_TRANSPORT_EVENT_ERROR, NULL, local_error);
814 smlErrorDeref(&local_error);
815 return;
816 }
817
818 static void smlTransportObexServerDisconnect(void *data, void *linkdata)
819 {
820 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, linkdata);
821 smlAssert(data);
822
823 /* The OBEX client usually performs the disconnect.
824 * If the server disconnects first then the client
825 * interprets this as an error. So if we want to
826 * abort a connection then this is the correct way.
827 */
828 if (linkdata) {
829 SmlLinkObexServerEnv *linkenv = linkdata;
830 linkenv->disconnect = TRUE;
831 smlTrace(TRACE_ERROR, "%s - explicit disconnect by OBEX server", __func__);
832 }
833
834 smlTrace(TRACE_EXIT, "%s", __func__);
835 return;
836 }
837
838 SmlBool smlTransportObexServerNew(SmlTransport *tsp, SmlError **error)
839 {
840 CHECK_ERROR_REF
841 smlAssert(tsp);
842
843 tsp->functions.set_config_option = smlTransportObexServerSetConfigOption;
844 tsp->functions.set_connection_type = smlTransportObexServerSetConnectionType;
845 tsp->functions.initialize = smlTransportObexServerInit;
846 tsp->functions.finalize = smlTransportObexServerFinalize;
847 tsp->functions.send = smlTransportObexServerSend;
848 tsp->functions.disconnect = smlTransportObexServerDisconnect;
849
850 SmlTransportObexServerEnv *env = smlTryMalloc0(sizeof(SmlTransportObexServerEnv), error);
851 if (!env)
852 return FALSE;
853 tsp->transport_data = env;
854 env->tsp = tsp;
855 env->lastConId = 0;
856 env->port = 0;
857
858 return TRUE;
859 }
860