Gammu internals  1.38.0
bluez.c
Go to the documentation of this file.
1 /* Based on some work from Bluez (www.bluez.org)
2  * (C) 2000-2001 Qualcomm Incorporated
3  * (C) 2002-2003 Maxim Krasnyansky <[email protected]>
4  * (C) 2002-2004 Marcel Holtmann <[email protected]>
5  * GNU GPL version 2
6  */
7 /* based on some Marcel Holtmann work from Gnokii (www.gnokii.org)
8  * (C) 1999-2000 Hugh Blemings & Pavel Janik ml. (C) 2001-2004 Pawel Kot
9  * GNU GPL version 2 or later
10  */
11 /* Due to a problem in the source code management, the names of some of
12  * the authors have unfortunately been lost. We do not mean to belittle
13  * their efforts and hope they will contact us to see their names
14  * properly added to the Copyright notice above.
15  * Having published their contributions under the terms of the GNU
16  * General Public License (GPL) [version 2], the Copyright of these
17  * authors will remain respected by adhering to the license they chose
18  * to publish their code under.
19  */
20 
21 #include "../../gsmstate.h"
22 
23 #ifdef GSM_ENABLE_BLUETOOTHDEVICE
24 #ifdef BLUEZ_FOUND
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 #include <bluetooth/bluetooth.h>
35 #include <bluetooth/rfcomm.h>
36 #include <bluetooth/sdp.h>
37 #include <bluetooth/sdp_lib.h>
38 #include <bluetooth/hci_lib.h>
39 
40 #include "../../gsmcomon.h"
41 #include "../devfunc.h"
42 #include "bluetooth.h"
43 
44 GSM_Error bluetooth_connect(GSM_StateMachine *s, int port, char *device)
45 {
46  int tries;
47 
48  /* Some phones need time till they are accessible after SDP browsing */
49  for (tries = 0; tries < 5; tries++) {
50  GSM_Device_BlueToothData *d = &s->Device.Data.BlueTooth;
51  struct sockaddr_rc laddr, raddr;
52  bdaddr_t bdaddr;
53  int fd;
54 
55  if (tries) {
56  sleep (1);
57  }
58 
59  memset(&laddr, 0, sizeof(laddr));
60  memset(&raddr, 0, sizeof(raddr));
61 
62  smprintf(s, "Connecting to RF channel %i\n", port);
63 
64  fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
65  if (fd < 0) {
66  smprintf(s, "Can't create socket\n");
67  continue;
68  }
69 
70  bacpy(&laddr.rc_bdaddr, BDADDR_ANY);
71  laddr.rc_family = AF_BLUETOOTH;
72  laddr.rc_channel = 0;
73 
74  if (bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
75  smprintf(s, "Can't bind socket (%d, %s)\n", errno, strerror(errno));
76  close(fd);
77  continue;
78  }
79 
80  str2ba(device, &bdaddr);
81  bacpy(&raddr.rc_bdaddr, &bdaddr);
82  raddr.rc_family = AF_BLUETOOTH;
83  raddr.rc_channel = port;
84 
85  if (connect(fd, (struct sockaddr *)&raddr, sizeof(raddr)) < 0) {
86  smprintf(s, "Can't connect (%d, %s)\n", errno, strerror(errno));
87  close(fd);
88  continue;
89  }
90 
91  d->hPhone = fd;
92 
93  return ERR_NONE;
94  }
95  return ERR_DEVICEOPENERROR;
96 }
97 
98 #ifdef BLUETOOTH_RF_SEARCHING
99 
100 static GSM_Error bluetooth_checkdevice(GSM_StateMachine *s, bdaddr_t *bdaddr, uuid_t *group)
101 {
102  sdp_session_t *sess = 0;
103  sdp_record_t *rec;
104  sdp_list_t *attrid, *search, *seq, *next, *proto;
105  sdp_data_t *d;
106  bdaddr_t interface;
107  uint32_t range = 0x0000ffff;
108  char str[20];
109  int channel,dd;
110  char name[1000];
111  int score, bestscore = 0;
112  int found = -1;
113  int retries = 0;
114  uuid_t subgroup;
115 
116  if (s->ConnectionType == GCT_BLUEPHONET) {
117  smprintf(s, "Looking for suitable channel for PHONET\n");
118  } else if (s->ConnectionType == GCT_BLUEOBEX) {
119  smprintf(s, "Looking for suitable channel for OBEX\n");
120  } else if (s->ConnectionType == GCT_BLUEAT) {
121  smprintf(s, "Looking for suitable channel for AT\n");
122  }
123 
124  bacpy(&interface,BDADDR_ANY);
125 
126  ba2str(bdaddr, str);
127  smprintf(s,"Device %s", str);
128 
129  /* Try to read name */
130  dd = hci_open_dev(0);
131  if (dd < 0) return ERR_UNKNOWN;
132  memset(name, 0, sizeof(name));
133  if (hci_read_remote_name(dd, bdaddr, sizeof(name), name, 100000) >= 0) {
134  smprintf(s, " (\"%s\")", name);
135  }
136  close(dd);
137  smprintf(s,"\n");
138 
139  /*
140  * Need to sleep for some slow devices, otherwise we get
141  * "Operation already in progress" error.
142  */
143  while (!sess) {
144  /* Try to connect to device */
145  sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
146  if (sess) break;
147 
148  if (errno == EALREADY && retries < 5) {
149  smprintf(s, "Operation already in progress, retrying.\n");
150  sleep(1);
151  continue;
152  }
153  /* Failure */
154  break;
155  }
156 
157  /* Did we connect? */
158  if (!sess) {
159  smprintf(s, "Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
160  return ERR_TIMEOUT;
161  }
162 
163  /* List available channels */
164  attrid = sdp_list_append(0, &range);
165  search = sdp_list_append(0, group);
166  if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
167  smprintf(s, "Service Search failed: %s\n", strerror(errno));
168  sdp_close(sess);
169  return ERR_UNKNOWN;
170  }
171  sdp_list_free(attrid, 0);
172  sdp_list_free(search, 0);
173 
174  for (; seq; seq = next) {
175  rec = (sdp_record_t *) seq->data;
176 
177  /* Get channel info */
178  if (sdp_get_access_protos(rec, &proto) == 0) {
179  channel = sdp_get_proto_port(proto, RFCOMM_UUID);
180  sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
181  sdp_list_free(proto, 0);
182  } else {
183  goto next_seq;
184  }
185  smprintf(s, " Channel %i", channel);
186 
187  /* Get service name and check it */
188  d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
189  if (d) {
190  score = bluetooth_checkservicename(s, d->val.str);
191  smprintf(s," - \"%s\" (score=%d)\n", d->val.str, score);
192  if (score > bestscore) {
193  found = channel;
194  bestscore = score;
195  }
196  } else {
197  smprintf(s,"\n");
198  }
199 
200  /* Descent to subroups */
201  memset(&subgroup, 0, sizeof(subgroup));
202  if (sdp_get_group_id(rec, &subgroup) != -1) {
203  if (subgroup.value.uuid16 != group->value.uuid16) {
204  bluetooth_checkdevice(s, bdaddr, &subgroup);
205  }
206  }
207 
208 next_seq:
209  next = seq->next;
210  free(seq);
211  seq=NULL;
212  sdp_record_free(rec);
213  }
214  sdp_close(sess);
215 
216  if (found != -1) {
217  return bluetooth_connect(s, found, str);
218  }
219 
220  smprintf(s, "No suitable bluetooth channel found!\n");
221  return ERR_NOTSUPPORTED;
222 }
223 
225 {
226  inquiry_info ii[20];
227  uint8_t count = 0;
228  int i;
229  GSM_Error error = ERR_TIMEOUT;
230  struct hci_dev_info hci_info;
231  uuid_t group;
232 
233  memset(&group, 0, sizeof(group));
234  /* We're looking only for rfcomm channels */
235  sdp_uuid16_create(&group, RFCOMM_UUID);
236 
237  if (hci_devinfo(0, &hci_info) < 0) return ERR_DEVICENOTWORK;
238 
239  if (s->CurrentConfig->Device[0] == '/') {
240  smprintf(s, "Searching for devices\n");
241  if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
242  return ERR_UNKNOWN;
243  }
244  } else {
245  count = 1;
246  str2ba(s->CurrentConfig->Device,&ii[0].bdaddr);
247  }
248  for (i=0;i<count;i++) {
249  error = bluetooth_checkdevice(s,&ii[i].bdaddr,&group);
250  if (error == ERR_NONE) {
251  free(s->CurrentConfig->Device);
252  s->CurrentConfig->Device = (char *)malloc(18);
253  if (s->CurrentConfig->Device == NULL) {
254  return ERR_MOREMEMORY;
255  }
256  ba2str(&ii[0].bdaddr, s->CurrentConfig->Device);
257  return ERR_NONE;
258  }
259  }
260  return error;
261 }
262 
263 #endif
264 #endif
265 #endif
266 
267 /* How should editor hadle tabs in this file? Add editor commands here.
268  * vim: noexpandtab sw=8 ts=8 sts=8:
269  */
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
union GSM_Device::@0 Data
GSM_ConnectionType ConnectionType
Definition: gsmstate.h:1402
GSM_Error
Definition: gammu-error.h:23
GSM_Error bluetooth_connect(GSM_StateMachine *s, int port, char *device)
socket_type hPhone
Definition: bluetooth.h:7
GSM_Error bluetooth_findchannel(GSM_StateMachine *s)
GSM_Device Device
Definition: gsmstate.h:1429
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261