libsyncml  0.5.4
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 
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 
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
SmlErrorClass smlErrorGetClass(SmlError **error)
Gets the error class.
Definition: sml_error.c:382
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
Definition: sml_support.c:120
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
Definition: sml_support.c:335
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
Represent an error.