22 #include <libsyncml/syncml.h> 23 #include <libsyncml/syncml_internals.h> 25 #include <libsyncml/sml_error_internals.h> 26 #include <libsyncml/sml_transport_internals.h> 28 #include "obex_internals.h" 29 #include "obex_client_internals.h" 30 #include "obex_client_vendor_internals.h" 32 #ifdef ENABLE_BLUETOOTH_SDPLIB 34 #include <bluetooth/sdp.h> 35 #include <bluetooth/sdp_lib.h> 44 #include <sys/socket.h> 45 #include <netinet/in.h> 47 #include <sys/socket.h> 48 #include <arpa/inet.h> 49 #include <netinet/in.h> 52 #include <sys/types.h> 61 static SmlBool obex_cable_at(
69 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %p, %i, %i, %p)", __func__, userdata, VA_STRING(cmd), rspbuf, rspbuflen, timeout, error);
76 SmlBool statusOnly = FALSE;
79 char *answer_end = NULL;
82 char tmpbuf[100] = {0,};
87 if (!strncasecmp(
"ATZ", cmd, 3)) {
88 smlTrace(TRACE_INTERNAL,
"%s: detected standard ATZ command", __func__);
91 if (!strncasecmp(
"AT+CPROT=0", cmd, 10)) {
92 smlTrace(TRACE_INTERNAL,
"%s: detected standard AT+CPROT=0 command", __func__);
101 "The file descriptor for the cable AT command is not legal (%d).",
109 cmdlen = strlen(cmd);
110 if(write(fd, cmd, cmdlen) < cmdlen) {
112 "The command cannot be written (completely) to the file descriptor.");
125 if(select(fd+1, &ttyset, NULL, NULL, &tv)) {
126 actual = read(fd, &tmpbuf[total],
sizeof(tmpbuf) - total);
129 "read failed with return code %i.",
136 if(total ==
sizeof(tmpbuf)) {
138 "The size of the answer to the AT command %s was too large for the internal buffer.",
143 if( (answer = index(tmpbuf,
'\n')) &&
144 (answer_end = index(answer+1,
'\n'))
147 if (!strncasecmp(
"ERROR", answer+1, 5)) {
149 "The AT command %s failed.",
161 if ( (ok = index(answer_end+1,
'\n')) &&
162 (ok_end = index(ok+1,
'\n'))
172 "The read operation for the answer of the AT command was timed out.");
176 smlTrace(TRACE_INTERNAL,
"%s: answer: %s", __func__, VA_STRING(answer));
179 if((*answer_end ==
'\r') || (*answer_end ==
'\n'))
181 if((*answer_end ==
'\r') || (*answer_end ==
'\n'))
183 if((*answer ==
'\r') || (*answer ==
'\n'))
185 if((*answer ==
'\r') || (*answer ==
'\n'))
188 answer_size = (answer_end) - answer +1;
190 smlTrace(TRACE_INTERNAL,
"%s: answer size=%d", __func__, answer_size);
191 if( (answer_size) >= rspbuflen ) {
193 "The size of the answer to the AT command %s was too large.",
198 strncpy(rspbuf, answer, answer_size);
199 rspbuf[answer_size] = 0;
200 smlTrace(TRACE_EXIT,
"%s", __func__);
207 static int smlTransportObexClientCableDisconnect(obex_t *handle, gpointer ud) {
209 smlTrace(TRACE_INTERNAL,
"%s(%p, %p)", __func__, handle, ud);
212 if (userdata->fd >= 0) {
215 if(ioctl(userdata->fd, TCSBRKP, 0) < 0) {
216 #elif defined(TCSBRK) 217 if(ioctl(userdata->fd, TCSBRK, 0) < 0) {
219 if(tcsendbreak(userdata->fd, 0) < 0) {
221 smlTrace(TRACE_INTERNAL,
"%s: Unable to send break!", __func__);
224 tcsetattr(userdata->fd, TCSANOW, &userdata->oldtio);
231 SmlTransportObexVendorType smlTransportObexClientGetVendor(
const char *manufacturer)
233 smlTrace(TRACE_ENTRY,
"%s(%s)", __func__, VA_STRING(manufacturer));
234 smlAssert(manufacturer);
235 SmlTransportObexVendorType vendor = SML_OBEX_VENDOR_UNKNOWN;
237 char *big = g_ascii_strup(manufacturer, -1);
239 if (strstr(big,
"SAMSUNG") != NULL) {
240 smlTrace(TRACE_INTERNAL,
"%s - Samsung found.", __func__);
241 vendor = SML_OBEX_VENDOR_SAMSUNG;
246 smlTrace(TRACE_EXIT,
"%s - %d", __func__, vendor);
250 static int smlTransportObexClientCableConnect(obex_t *handle, gpointer ud)
252 smlTrace(TRACE_ENTRY,
"%s", __func__);
256 struct termios newtio;
258 rspbuf[
sizeof(rspbuf)-1] = 0;
260 userdata->fd = open(userdata->path, O_RDWR|O_NONBLOCK|O_NOCTTY);
261 if (userdata->fd < 0) {
263 "A valid file descriptor must be non-negative.");
267 tcgetattr(userdata->fd, &userdata->oldtio);
268 bzero(&newtio,
sizeof(
struct termios));
269 newtio.c_cflag = B115200 | CLOCAL | CS8 | CREAD | CRTSCTS;
270 newtio.c_cc[VMIN] = 1;
271 newtio.c_cc[VTIME] = 0;
272 newtio.c_iflag = IGNPAR;
274 tcflush(userdata->fd, TCIFLUSH);
275 tcsetattr(userdata->fd, TCSANOW, &newtio);
278 if (!obex_cable_at(userdata,
"ATZ\r", rspbuf,
sizeof(rspbuf) - 1, 1, &error))
281 if (strcasecmp(
"OK", rspbuf)) {
283 "The ATZ command was answered with %s.",
288 if (!userdata->at_command && !userdata->manufacturer)
291 if (!obex_cable_at(userdata,
"AT+CGMI\r", rspbuf,
sizeof(rspbuf), 1, &error)) {
292 smlTrace(TRACE_ERROR,
"%s: Comm-error sending AT+CGMI\\r", __func__);
295 userdata->manufacturer = g_strdup(rspbuf);
296 smlTrace(TRACE_ERROR,
"%s: manufacturer %s", __func__, VA_STRING(userdata->manufacturer));
298 if (!userdata->at_command && !userdata->model)
301 if (!obex_cable_at(userdata,
"AT+CGMM\r", rspbuf,
sizeof(rspbuf), 1, &error)) {
302 smlTrace(TRACE_ERROR,
"%s: Comm-error sending AT+CGMM\\r", __func__);
305 userdata->model = g_strdup(rspbuf);
306 smlTrace(TRACE_ERROR,
"%s: model %s", __func__, VA_STRING(userdata->model));
308 if (!userdata->at_command)
311 SmlTransportObexVendorType vendor = SML_OBEX_VENDOR_UNKNOWN;
312 if (userdata->manufacturer) {
313 smlTrace(TRACE_INTERNAL,
"%s: Try to find an appropriate AT command", __func__);
314 vendor = smlTransportObexClientGetVendor(userdata->manufacturer);
318 case SML_OBEX_VENDOR_SAMSUNG:
319 smlTrace(TRACE_INTERNAL,
"%s: Samsung detected", __func__);
320 if (!smlTransportObexVendorSamsungInit(userdata)) {
322 "The intialization for Samsung failed.");
327 smlTrace(TRACE_ERROR,
"%s: Ups, vendor defined but not handled.", __func__);
332 if (!userdata->at_command) {
334 smlTrace(TRACE_INTERNAL,
"%s: Setting up default AT command AT+CPROT=0\\r", __func__);
335 userdata->at_command = g_strdup(
"AT+CPROT=0\r");
339 if (!obex_cable_at(userdata, userdata->at_command, rspbuf,
sizeof(rspbuf) - 1, 1, &error))
342 if (strcasecmp(
"CONNECT", rspbuf)) {
344 "The command AT+CPROT=0 failed with answer %s.",
352 smlTransportObexClientCableDisconnect(handle, userdata);
354 smlErrorDeref(&error);
358 static int smlTransportObexClientCableWrite(obex_t *handle, gpointer ud, guint8 *buf,
int buflen) {
360 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p, %i)", __func__, handle, ud, buf, buflen);
365 while (ret >= 0 && written < buflen) {
366 ret = write(userdata->fd, buf + written, buflen - written);
371 smlTrace(TRACE_EXIT,
"%s: %i", __func__, written);
375 gint obex_cable_handleinput(obex_t *handle, gpointer ud, gint timeout) {
376 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %i)", __func__, handle, ud, timeout);
386 FD_SET(userdata->fd, &readfds);
391 smlTrace(TRACE_INTERNAL,
"%s - %i", __func__, __LINE__);
392 ret = select(userdata->fd + 1, &readfds, NULL, NULL, &to);
397 smlTrace(TRACE_INTERNAL,
"%s - %i", __func__, __LINE__);
398 if ((actual = read(userdata->fd, buf,
sizeof(buf))) <= 0)
401 smlTrace(TRACE_INTERNAL,
"%s - %i", __func__, __LINE__);
402 OBEX_CustomDataFeed(handle, (
unsigned char *) buf, actual);
405 smlTrace(TRACE_EXIT,
"%s(%p, %p, %i)", __func__, handle, ud, timeout);
410 smlTrace(TRACE_EXIT_ERROR,
"%s: %i", __func__, ret);
417 static void smlTransportObexClientEvent(obex_t *handle, obex_object_t *
object,
int mode,
int event,
int obex_cmd,
int obex_rsp)
419 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %i, %i, %i, %i)", __func__, handle,
object, mode, event, obex_cmd, obex_rsp);
424 case OBEX_EV_PROGRESS:
425 smlTrace(TRACE_INTERNAL,
"%s: Progress", __func__);
427 case OBEX_EV_REQDONE:
428 smlTrace(TRACE_INTERNAL,
"%s: Request Done", __func__);
431 if (obex_rsp != OBEX_RSP_SUCCESS) {
433 case OBEX_CMD_CONNECT:
434 smlErrorSet(&error, SML_ERROR_INTERNAL_MISCONFIGURATION,
435 "The OBEX client cannot connect to the configured device or resource (%s - 0x%x).",
436 OBEX_ResponseToString(obex_rsp),
442 OBEX_ResponseToString(obex_rsp),
451 case OBEX_CMD_CONNECT:;
452 uint8_t headertype = 0;
453 obex_headerdata_t header;
457 while (OBEX_ObjectGetNextHeader(env->obexhandle,
object, &headertype, &header, &len)) {
458 smlTrace(TRACE_INTERNAL,
"%s: Next header %i, %d, %p", __func__, headertype, header.bq4, header.bs);
459 switch (headertype) {
460 case OBEX_HDR_CONNECTION:
461 smlTrace(TRACE_INTERNAL,
"%s: Found connection number: %d", __func__, header.bq4);
462 env->connection_id = header.bq4;
465 who = g_strndup((
char *)header.bs, len);
466 smlTrace(TRACE_INTERNAL,
"%s: Found who: %s", __func__, VA_STRING(who));
469 smlTrace(TRACE_INTERNAL,
"%s: Unknown header", __func__);
473 if (!env->connection_id) {
474 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing connection id");
479 smlTrace(TRACE_INTERNAL,
"%s: Got who: %s", __func__, VA_STRING(who));
480 if (!who || strcmp(who,
"SYNCML-SYNC")) {
481 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing or wrong who response");
487 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
489 case OBEX_CMD_DISCONNECT:;
490 if (!env->isDisconnected)
493 env->isDisconnected = TRUE;
494 OBEX_TransportDisconnect(env->obexhandle);
495 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
499 smlTrace(TRACE_INTERNAL,
"%s: Got GET command done", __func__);
503 while (OBEX_ObjectGetNextHeader(handle,
object, &headertype, &header, &len)) {
504 smlTrace(TRACE_INTERNAL,
"%s: Next header %i, %d, %p, len %i", __func__, headertype, header.bq4, header.bs, len);
505 switch (headertype) {
506 case OBEX_HDR_LENGTH:
507 smlTrace(TRACE_INTERNAL,
"%s: Found length: %d", __func__, header.bq4);
512 smlTrace(TRACE_INTERNAL,
"%s: Length not given. Calculating it to: %i", __func__, len);
517 smlErrorSet(&error, SML_ERROR_GENERIC,
"Got zero length!");
533 memcpy(body, header.bs, length);
536 smlTrace(TRACE_INTERNAL,
"%s: Unknown header", __func__);
541 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing length");
546 smlErrorSet(&error, SML_ERROR_GENERIC,
"Missing body");
550 SmlTransportData *tspdata = smlTransportDataNew(body, length, env->mimetype, TRUE, &error);
554 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
555 smlTransportDataDeref(tspdata);
559 case OBEX_EV_LINKERR:
563 if (!env->isDisconnected)
566 env->isDisconnected = TRUE;
567 OBEX_TransportDisconnect(env->obexhandle);
568 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
573 "Link Error: %s - 0x%x",
574 OBEX_ResponseToString(obex_rsp), obex_rsp);
580 case OBEX_EV_STREAMEMPTY:
581 smlTrace(TRACE_INTERNAL,
"%s: Empty Stream", __func__);
585 smlTrace(TRACE_EXIT,
"%s", __func__);
589 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
591 smlErrorDeref(&error);
597 static SmlBool smlTransportObexClientSetConfigOption(
603 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
606 smlAssert(tsp->transport_data);
613 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
614 "The configuration option %s requires a value.", name);
618 if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL)) {
619 env->port = atoi(value);
620 smlTrace(TRACE_INTERNAL,
"%s: Bluetooth channel %i detected", __func__, env->port);
621 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS)) {
623 env->path = g_strdup(value);
624 smlTrace(TRACE_INTERNAL,
"%s: Bluetooth MAC %s detected", __func__, VA_STRING(env->path));
625 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
626 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH)
627 g_warning(
"Please use %s instead of %s.",
628 SML_TRANSPORT_CONFIG_BLUETOOTH_CHANNEL,
629 SML_TRANSPORT_CONFIG_PORT);
630 env->port = atoi(value);
631 smlTrace(TRACE_INTERNAL,
"%s: Port or Bluetooth channel %i detected",
632 __func__, env->port);
633 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_URL)) {
634 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH)
635 g_warning(
"Please use %s instead of %s.",
636 SML_TRANSPORT_CONFIG_BLUETOOTH_ADDRESS,
637 SML_TRANSPORT_CONFIG_URL);
638 env->path = g_strdup(value);
639 smlTrace(TRACE_INTERNAL,
"%s: URL or Bluetooth MAC %s detected",
640 __func__, VA_STRING(env->path));
641 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_IRDA_SERVICE)) {
642 if (env->irda_service)
643 smlSafeCFree(&(env->irda_service));
644 env->irda_service = g_strdup(value);
645 smlTrace(TRACE_INTERNAL,
"%s: IrDA service %s detected", __func__, VA_STRING(env->irda_service));
646 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_COMMAND)) {
648 smlSafeCFree(&(env->at_command));
649 env->at_command = g_strdup(value);
650 smlTrace(TRACE_INTERNAL,
"%s: AT command %s detected", __func__, VA_STRING(env->at_command));
651 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_MANUFACTURER)) {
652 if (env->manufacturer)
653 smlSafeCFree(&(env->manufacturer));
654 env->manufacturer = g_strdup(value);
655 smlTrace(TRACE_INTERNAL,
"%s: AT manufacturer %s detected", __func__, VA_STRING(env->manufacturer));
656 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_AT_MODEL)) {
658 smlSafeCFree(&(env->model));
659 env->model = g_strdup(value);
660 smlTrace(TRACE_INTERNAL,
"%s: AT model %s detected", __func__, VA_STRING(env->model));
661 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_DATASTORE)) {
663 SmlTransportObexDatastoreType datastore = SML_TRANSPORT_OBEX_DATASTORE_UNKNOWN;
664 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_EVENT, value))
665 datastore = SML_TRANSPORT_OBEX_DATASTORE_EVENT;
666 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_TODO, value))
667 datastore = SML_TRANSPORT_OBEX_DATASTORE_TODO;
668 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_CONTACT, value))
669 datastore = SML_TRANSPORT_OBEX_DATASTORE_CONTACT;
670 if (!strcasecmp(SML_TRANSPORT_CONFIG_DATASTORE_NOTE, value))
671 datastore = SML_TRANSPORT_OBEX_DATASTORE_NOTE;
673 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown datastore %s found.", value);
676 SmlTransportObexDatastoreType *type =
smlTryMalloc0(
sizeof(SmlTransportObexDatastoreType), error);
680 env->datastores = g_list_append(env->datastores, type);
681 smlTrace(TRACE_INTERNAL,
"%s: Datastore %i detected", __func__, datastore);
683 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown parameter %s found.", name);
687 smlTrace(TRACE_EXIT,
"%s", __func__);
695 static SmlBool smlTransportObexClientSetConnectionType(
697 SmlTransportConnectionType type,
700 smlTrace(TRACE_ENTRY,
"%s(%p, %i, %p)", __func__, tsp, type, error);
703 smlAssert(tsp->transport_data);
709 case SML_TRANSPORT_CONNECTION_TYPE_NET:
710 env->obexhandle = OBEX_Init(OBEX_TRANS_FD, smlTransportObexClientEvent, 0);
712 case SML_TRANSPORT_CONNECTION_TYPE_IRDA:
713 env->obexhandle = OBEX_Init(OBEX_TRANS_IRDA, smlTransportObexClientEvent, 0);
715 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
716 env->obexhandle = OBEX_Init(OBEX_TRANS_BLUETOOTH, smlTransportObexClientEvent, 0);
718 case SML_TRANSPORT_CONNECTION_TYPE_SERIAL:
719 env->obexhandle = OBEX_Init(OBEX_TRANS_CUSTOM, smlTransportObexClientEvent, 0);
721 case SML_TRANSPORT_CONNECTION_TYPE_USB:
722 env->obexhandle = OBEX_Init(OBEX_TRANS_USB, smlTransportObexClientEvent, 0);
725 smlErrorSet(error, SML_ERROR_GENERIC,
"Unknown obex type");
730 if (!env->obexhandle) {
731 smlErrorSet(error, SML_ERROR_GENERIC,
"Unable to open connection");
737 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_SERIAL) {
738 obex_ctrans_t cabletrans = {
739 smlTransportObexClientCableConnect,
740 smlTransportObexClientCableDisconnect,
742 smlTransportObexClientCableWrite,
743 obex_cable_handleinput,
745 OBEX_RegisterCTransport(env->obexhandle, &cabletrans);
749 smlTrace(TRACE_EXIT,
"%s", __func__);
755 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
758 smlAssert(tsp->transport_data);
761 OBEX_SetUserData(env->obexhandle, env);
764 case SML_TRANSPORT_CONNECTION_TYPE_NET:
767 "The hostname or address is missing.");
771 case SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH:
774 "The bluetooth address is missing.");
777 #ifndef ENABLE_BLUETOOTH_SDPLIB 780 "The bluetooth channel is missing.");
790 smlTrace(TRACE_EXIT,
"%s - TRUE", __func__);
793 OBEX_Cleanup(env->obexhandle);
795 smlSafeCFree(&(env->path));
797 smlSafeCFree(&(env->at_command));
798 if (env->manufacturer)
799 smlSafeCFree(&(env->manufacturer));
801 smlSafeCFree(&(env->model));
802 smlSafeFree((gpointer *)&env);
807 static SmlBool smlTransportObexClientFinalize(
void *data,
SmlError **error)
809 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, error);
815 if (env->path) smlSafeCFree(&(env->path));
817 OBEX_Cleanup(env->obexhandle);
819 if (env->irda_service)
820 smlSafeCFree(&(env->irda_service));
822 smlSafeCFree(&(env->at_command));
823 if (env->manufacturer)
824 smlSafeCFree(&(env->manufacturer));
826 smlSafeCFree(&(env->model));
827 while (env->datastores) {
828 SmlTransportObexDatastoreType *type = env->datastores->data;
829 env->datastores = g_list_remove(env->datastores, type);
830 smlSafeFree((gpointer *) &type);
833 smlSafeFree((gpointer *)&env);
835 smlTrace(TRACE_EXIT,
"%s", __func__);
839 static void smlTransportObexClientConnect(
void *data)
841 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
846 unsigned int obex_intf_cnt;
847 obex_interface_t *obex_intf;
848 env->isDisconnected = FALSE;
850 if (env->type == SML_TRANSPORT_CONNECTION_TYPE_NET) {
851 smlTrace(TRACE_INTERNAL,
"%s: connecting to inet address %s:%d",
852 __func__, VA_STRING(env->path), env->port);
853 struct sockaddr_in addr;
854 memset(&addr, 0,
sizeof(addr));
855 addr.sin_family = AF_INET;
856 addr.sin_port = htons(env->port);
858 struct hostent *hostinfo = gethostbyname (env->path);
860 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown host %s", env->path);
863 addr.sin_addr = *(
struct in_addr *) hostinfo->h_addr_list[0];
865 fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
867 smlErrorSet(&error, SML_ERROR_GENERIC,
"Cannot create socket: %s", strerror(errno));
871 smlTrace(TRACE_INTERNAL,
"%s: socket %i", __func__, fd);
873 char *addrstr = inet_ntoa(addr.sin_addr);
874 smlTrace(TRACE_INTERNAL,
"%s: peer addr = %d %s %i", __func__, hostinfo->h_addr_list[0], VA_STRING(addrstr), env->port);
876 if (connect(fd, (
struct sockaddr *)&addr,
sizeof(
struct sockaddr_in)) < 0) {
877 smlErrorSet(&error, SML_ERROR_GENERIC,
"Cannot connect socket: %s", strerror(errno));
880 smlTrace(TRACE_INTERNAL,
"%s: connect done", __func__);
882 }
else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_USB) {
883 smlTrace(TRACE_INTERNAL,
"%s: connecting to usb interface %i", __func__, env->port);
885 obex_intf_cnt = OBEX_EnumerateInterfaces(env->obexhandle);
886 smlTrace(TRACE_INTERNAL,
"%s: found %i interfaces", __func__, obex_intf_cnt);
888 if (obex_intf_cnt <= 0) {
889 smlErrorSet(&error, SML_ERROR_GENERIC,
"There are no valid USB interfaces.");
891 }
else if (env->port >= obex_intf_cnt) {
892 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to find the USB interface number %i", env->port);
895 if (GET_OBEX_RESULT(OBEX_InterfaceConnect(env->obexhandle, &obex_intf[env->port])) < 0) {
897 "The interface cannot be connected. %s (%i).",
898 strerror(errno), errno);
902 smlTrace(TRACE_INTERNAL,
"%s: usb connect done", __func__);
903 }
else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH) {
904 #ifdef ENABLE_BLUETOOTH 905 smlTrace(TRACE_INTERNAL,
"%s: connecting to bluetooth device %s channel %i", __func__, VA_STRING(env->path), env->port);
907 uint8_t channel = env->port;
909 str2ba(env->path, &bdaddr);
911 #ifdef ENABLE_BLUETOOTH_SDPLIB 915 sdp_session_t *sdp_session = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY);
917 smlErrorSet(&error, SML_ERROR_GENERIC,
"The Bluetooth connect to search for the channel failed.");
920 unsigned char syncml_client_uuid[] = {
921 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
922 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02};
924 uint32_t range = SDP_ATTR_PROTO_DESC_LIST;
925 sdp_uuid128_create(&uuid, syncml_client_uuid);
926 sdp_list_t *attribute = sdp_list_append(0, &range);
927 sdp_list_t *
class = sdp_list_append(0, &uuid);
930 if (sdp_service_search_attr_req(sdp_session,
class, SDP_ATTR_REQ_INDIVIDUAL, attribute, &list) < 0) {
931 sdp_close(sdp_session);
932 sdp_list_free(attribute, 0);
933 sdp_list_free(
class, 0);
936 &error, SML_ERROR_GENERIC,
937 "The service search on the Bluetooth device failed.");
940 sdp_list_free(attribute, 0);
941 sdp_list_free(
class, 0);
943 sdp_list_t *iterator;
944 for(iterator = list; iterator; iterator = iterator->next) {
945 sdp_record_t *item = (sdp_record_t *) iterator->data;
946 sdp_list_t *protos = NULL;
948 sdp_get_access_protos(item, &protos);
950 channel = sdp_get_proto_port(protos, RFCOMM_UUID);
952 sdp_record_free(item);
954 sdp_list_free(list, 0);
955 sdp_close(sdp_session);
958 "%s: SDP SyncML channel for %s: %d",
959 __func__, env->path, channel);
964 if (GET_OBEX_RESULT(BtOBEX_TransportConnect(env->obexhandle, BDADDR_ANY, &bdaddr, channel)) < 0) {
966 "The Bluetooth connect failed. %s (%i).",
967 strerror(errno), errno);
971 smlTrace(TRACE_INTERNAL,
"%s: bluetooth connect done", __func__);
973 smlErrorSet(&error, SML_ERROR_GENERIC,
"Bluetooth not enabled");
976 }
else if (env->type == SML_TRANSPORT_CONNECTION_TYPE_IRDA) {
977 smlTrace(TRACE_INTERNAL,
"%s: connecting to IrDA service %s", __func__, env->irda_service ? env->irda_service :
"OBEX");
979 if (GET_OBEX_RESULT(IrOBEX_TransportConnect(env->obexhandle, env->irda_service)) < 0) {
981 "The IrDA connect failed. %s (%i).",
982 strerror(errno), errno);
986 smlTrace(TRACE_INTERNAL,
"%s: IrDA connect done", __func__);
990 memset(&tio, 0,
sizeof(tio));
993 fd = open(env->path, O_RDWR | O_NOCTTY);
995 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to open %s: %s", env->path, strerror(errno));
1000 if (lockf(fd, F_TLOCK, 0)) {
1001 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to lock %s: %s", env->path, strerror(errno));
1005 if (tcgetattr(fd, &tio)) {
1006 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to get attr from %s", env->path);
1013 #if defined(sun) && defined(__SVR4) 1014 tio.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1015 tio.c_oflag &= ~OPOST;
1016 tio.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1017 tio.c_cflag &= ~(CSIZE|PARENB);
1023 cfsetispeed(&tio, B115200);
1024 cfsetospeed(&tio, B115200);
1026 if (tcsetattr(fd, TCSANOW, &tio)) {
1027 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to set attr from %s", env->path);
1030 tcflush(fd, TCIFLUSH);
1034 if (env->type != SML_TRANSPORT_CONNECTION_TYPE_USB
1035 && env->type != SML_TRANSPORT_CONNECTION_TYPE_BLUETOOTH
1036 && env->type != SML_TRANSPORT_CONNECTION_TYPE_IRDA) {
1038 if (GET_OBEX_RESULT(FdOBEX_TransportSetup(env->obexhandle, fd, fd, 4096)) < 0) {
1040 "The OBEX transport setup failed. %s (%i).",
1041 strerror(errno), errno);
1047 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_CONNECT);
1049 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to create new connect object");
1050 goto error_transport_close;
1054 obex_headerdata_t header;
1055 header.bs = (
unsigned char *)
"SYNCML-SYNC";
1056 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TARGET, header, strlen((
char *)header.bs), OBEX_FL_FIT_ONE_PACKET);
1060 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
1062 "The OBEX request failed. %s (%i).",
1063 strerror(errno), errno);
1064 goto error_free_obj;
1068 smlTrace(TRACE_EXIT,
"%s: Unable to send connect request. Bailing out", __func__);
1074 int result = OBEX_HandleInput(env->obexhandle, 20);
1077 "The connect request was not successful (%i).",
1080 }
else if (result == 0) {
1082 "The connect request was timed out.");
1087 smlTrace(TRACE_EXIT,
"%s", __func__);
1091 OBEX_ObjectDelete(env->obexhandle, obj);
1092 error_transport_close:
1093 OBEX_Cleanup(env->obexhandle);
1096 if (!lockf(fd, F_ULOCK, 0))
1097 smlTrace(TRACE_ERROR,
"%s: error_unlock failed.", __func__);
1102 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
1104 smlErrorDeref(&error);
1107 static void smlTransportObexClientDisconnect(
void *data,
void *linkdata)
1109 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, linkdata);
1114 if (env->isDisconnected) {
1120 "%s - disconnect called on already disconnected transport",
1122 g_warning(
"%s called on disconnected OBEX connection.", __func__);
1129 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_DISCONNECT);
1131 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to create new disconnect object");
1136 obex_headerdata_t header;
1137 header.bq4 = env->connection_id;
1138 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header,
sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
1142 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
1144 "The OBEX request cannot be sent. %s (%i).",
1145 strerror(errno), errno);
1146 goto error_free_obj;
1150 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to send disconnect request. Bailing out");
1162 smlTrace(TRACE_INTERNAL,
"%s: Disconnect loop %i", __func__, i);
1163 int result = OBEX_HandleInput(env->obexhandle, 1);
1167 "The disconnect request was not accepted (%i).",
1170 }
else if (result == 0 && !env->busy && !env->isDisconnected) {
1172 "The disconnect request was timed out.");
1177 smlTrace(TRACE_INTERNAL,
"%s: Did not receive a response to our disconnect", __func__);
1185 if (!env->isDisconnected)
1188 env->isDisconnected = TRUE;
1189 OBEX_TransportDisconnect(env->obexhandle);
1190 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
1193 smlTrace(TRACE_EXIT,
"%s", __func__);
1197 OBEX_ObjectDelete(env->obexhandle, obj);
1199 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
1201 smlErrorDeref(&error);
1206 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p, %p)", __func__, userdata, link_, data, error);
1207 smlAssert(error || data);
1208 smlAssert(userdata);
1216 env->mimetype = data->type;
1219 obex_object_t *obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_PUT);
1221 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to create new put object");
1226 obex_headerdata_t header;
1228 smlTrace(TRACE_INTERNAL,
"%s: Adding connection id %i", __func__, env->connection_id);
1231 header.bq4 = env->connection_id;
1232 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header,
sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
1234 const char *target = NULL;
1235 switch (data->type) {
1236 case SML_MIMETYPE_WBXML:
1237 target = SML_ELEMENT_WBXML;
1239 case SML_MIMETYPE_XML:
1240 target = SML_ELEMENT_XML;
1242 case SML_MIMETYPE_SAN:
1243 target = SML_ELEMENT_SAN;
1246 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mime type");
1247 goto error_free_obj;
1249 smlTrace(TRACE_INTERNAL,
"%s: Target %s", __func__, VA_STRING(target));
1263 header.bs = (
unsigned char *)target;
1264 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TYPE, header, strlen(target) + 1, 0);
1267 header.bq4 = (uint32_t)data->size;
1268 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_LENGTH, header,
sizeof(uint32_t), 0);
1270 header.bs = (
unsigned char *)data->data;
1271 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_BODY, header, data->size, 0);
1275 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
1277 "The OBEX request cannot be sent. %s (%i).",
1278 strerror(errno), errno);
1279 goto error_free_obj;
1284 int result = OBEX_HandleInput(env->obexhandle, 20);
1287 "The request was not successful (%d).",
1290 }
else if (result == 0 && !env->busy) {
1292 "The request was timed out.");
1298 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to send put request. Bailing out");
1302 smlTrace(TRACE_INTERNAL,
"%s: Done sending the put request", __func__);
1305 smlTrace(TRACE_EXIT,
"%s: No answer is needed", __func__);
1310 obj = OBEX_ObjectNew(env->obexhandle, OBEX_CMD_GET);
1312 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unable to create new get object");
1317 smlTrace(TRACE_INTERNAL,
"%s: Adding connection id %i", __func__, env->connection_id);
1320 header.bq4 = env->connection_id;
1321 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_CONNECTION, header,
sizeof(env->connection_id), OBEX_FL_FIT_ONE_PACKET);
1330 if (data->
type_get != SML_MIMETYPE_UNKNOWN)
1333 case SML_MIMETYPE_WBXML:
1334 target = SML_ELEMENT_WBXML;
1336 case SML_MIMETYPE_XML:
1337 target = SML_ELEMENT_XML;
1339 case SML_MIMETYPE_SAN:
1340 target = SML_ELEMENT_SAN;
1343 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mime type");
1344 goto error_free_obj;
1350 smlTrace(TRACE_INTERNAL,
"%s: Switch to new target: %s", __func__, VA_STRING(target));
1357 header.bs = (
unsigned char *)target;
1358 OBEX_ObjectAddHeader(env->obexhandle, obj, OBEX_HDR_TYPE, header, strlen(target) + 1, 0);
1362 if (GET_OBEX_RESULT(OBEX_Request(env->obexhandle, obj)) < 0) {
1364 "The OBEX request cannot be sent. %s (%i).",
1365 strerror(errno), errno);
1366 goto error_free_obj;
1370 smlTrace(TRACE_INTERNAL,
"%s: Wait for the answer ...", __func__);
1372 int result = OBEX_HandleInput(env->obexhandle, 20);
1375 "The answer was not received successfully (%i).",
1378 }
else if (result == 0 && !env->busy) {
1380 "The answer was timed out.");
1385 smlTrace(TRACE_EXIT,
"%s", __func__);
1389 OBEX_ObjectDelete(env->obexhandle, obj);
1391 smlTransportReceiveEvent(env->tsp, NULL, SML_TRANSPORT_EVENT_ERROR, NULL, error);
1401 tsp->functions.set_config_option = smlTransportObexClientSetConfigOption;
1402 tsp->functions.set_connection_type = smlTransportObexClientSetConnectionType;
1403 tsp->functions.initialize = smlTransportObexClientInit;
1404 tsp->functions.finalize = smlTransportObexClientFinalize;
1405 tsp->functions.connect = smlTransportObexClientConnect;
1406 tsp->functions.disconnect = smlTransportObexClientDisconnect;
1407 tsp->functions.send = smlTransportObexClientSend;
1412 tsp->transport_data = env;
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.