📄 obex_socket.c
字号:
/********************************************************************* * * Filename: obex_cable.c * Original author: Pontus Fuchs <pontus.fuchs@tactel.se> * * Copyright (c) 1999, 2000 Pontus Fuchs, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ********************************************************************//* $Id: obex_socket.c,v 1.6 2002/05/15 13:08:06 kds Exp $ OBEX serial port transport functions. Adapted for Affix, Fixes: Imre Deak <ext-imre.deak@nokia.com> Adapted for Bluez, Fixes marked [REV]: reverend@unrooted.net Modified for BT name resolution and code cleanup: Davide Libenzi <davidel@xmailserver.org>*/ #include <stdio.h>#include <sys/time.h>#include <sys/ioctl.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <termios.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/rfcomm.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <glib.h>#include <openobex/obex.h>/* * [REV] * * I've moved the necessary parts of these two includes directly into here. * The BTDEBUG and BTERROR macros and the cobex_context struct. * * #include <affix/btcore.h> * #include "obex_server.h" */#if defined(_DEBUG)#define BTDEBUG(fmt, args...) //printf(fmt, ##args);#else#define BTDEBUG(fmt, args...) (void) 0#endif#define BTERROR(fmt, args...) //fprintf(stderr, fmt, ##args);extern int* __eebt_getErrLocation(const pthread_t aThread);struct cobex_context { char *addr; int chan; const char *portname; int rfd, wfd; char inputbuf[4096]; struct termios oldtio, newtio;};static void cobex_cleanup(struct cobex_context *gt, gboolean force);static char *bt_sock_cachefile(char *cfname, int len);static int bt_sock_cachefile_lookup(FILE *file, const char *btname, bdaddr_t *btaddr);static int bt_sock_cache_lookup(const char *btname, bdaddr_t *btaddr);static int bt_sock_cache_add(FILE *file, const char *btname, bdaddr_t const *btaddr);static char *bt_sock_addr2str(bdaddr_t const *btaddr, char *straddr);static int bt_sock_str2addr(const char *straddr, bdaddr_t *btaddr);static int bt_sock_name2bth(const char *btname, bdaddr_t *btaddr);static char *bt_sock_cachefile(char *cfname, int len) { char const *env = getenv("HOME"); if (env) snprintf(cfname, len, "%s/.bt-namecache", env); else snprintf(cfname, len, ".bt-namecache"); return cfname;}static int bt_sock_cachefile_lookup(FILE *file, const char *btname, bdaddr_t *btaddr) { char *name, *addr; char buf[512]; rewind(file); while (fgets(buf, sizeof(buf) - 1, file) != NULL) { buf[strlen(buf) - 1] = 0; if ((name = strtok(buf, " \t\r\n")) == NULL || (addr = strtok(NULL, " \t\r\n")) == NULL || bt_sock_str2addr(addr, btaddr) < 0) continue; if (strcasecmp(name, btname) == 0) return 0; } return -1;}static int bt_sock_cache_lookup(const char *btname, bdaddr_t *btaddr) { int err; FILE *file; char cfname[256]; bt_sock_cachefile(cfname, sizeof(cfname) - 1); if ((file = fopen(cfname, "rt")) == NULL) return -1; err = bt_sock_cachefile_lookup(file, btname, btaddr); fclose(file); return err;}static int bt_sock_cache_add(FILE *file, const char *btname, bdaddr_t const *btaddr) { bdaddr_t laddr; char addr[128]; if (bt_sock_cachefile_lookup(file, btname, &laddr) < 0) { fseek(file, 0, SEEK_END); fprintf(file, "%s\t%s\n", btname, bt_sock_addr2str(btaddr, addr)); } return 0;}static char *bt_sock_addr2str(bdaddr_t const *btaddr, char *straddr) { int i; for (i = 0; i < 6; i++) { if (i) sprintf(straddr + 2 + (i - 1) * 3, ":%02X", btaddr->b[5 - i]); else sprintf(straddr, "%02X", btaddr->b[5]); } return straddr;}static int bt_sock_str2addr(const char *straddr, bdaddr_t *btaddr) { int i; unsigned int aaddr[6]; if (sscanf(straddr, "%02x:%02x:%02x:%02x:%02x:%02x", &aaddr[0], &aaddr[1], &aaddr[2], &aaddr[3], &aaddr[4], &aaddr[5]) != 6) return -1; for (i = 0; i < 6; i++) btaddr->b[5 - i] = (unsigned char) (aaddr[i] & 0xff); return 0;}static int bt_sock_name2bth(const char *btname, bdaddr_t *btaddr) { int i, niinf, dd, err = -1; inquiry_info *piinf = NULL; FILE *file; char cfname[256]; if (bt_sock_cache_lookup(btname, btaddr) == 0) return 0; bt_sock_cachefile(cfname, sizeof(cfname) - 1); if ((file = fopen(cfname, "r+t")) == NULL && (file = fopen(cfname, "w+t")) == NULL) return -1; fprintf(stderr, "Resolving name '%s' ...\n", btname); if ((niinf = hci_inquiry(0, 32, -1, NULL, &piinf, 0)) < 0) { fprintf(stderr, "hci_inquiry error\n"); fclose(file); return -1; } if ((dd = hci_open_dev(0)) < 0) { fprintf(stderr, "Unable to open HCI device\n"); free(piinf); fclose(file); return -1; } for (i = 0; i < niinf; i++) { char devname[128]; if (hci_remote_name(dd, &piinf[i].bdaddr, sizeof(devname) - 1, devname, 100000) >= 0) { if (strcasecmp(devname, btname) == 0) { *btaddr = piinf[i].bdaddr; err = 0; } bt_sock_cache_add(file, devname, &piinf[i].bdaddr); } } hci_close_dev(dd); free(piinf); fclose(file); return err;}int bt_sock_open(char const *qcaddr, int channel) { int sock; bdaddr_t btaddr; struct sockaddr_rc laddr, raddr; struct hci_dev_info di; char straddr[64]; if(hci_devinfo(0, &di) < 0) { //perror("hci_devinfo"); return -1; } if (bt_sock_str2addr(qcaddr, &btaddr) < 0 && bt_sock_name2bth(qcaddr, &btaddr) < 0) { fprintf(stderr, "Unable to resolve '%s'\n", qcaddr); return -1; } laddr.rc_family = AF_BLUETOOTH; laddr.rc_bdaddr = di.bdaddr; laddr.rc_channel = 0; raddr.rc_family = AF_BLUETOOTH; raddr.rc_bdaddr = btaddr; raddr.rc_channel = channel; if ((sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { //perror("socket"); return -1; } if (bind(sock, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) { //perror("bind"); close(sock); return -1; } //printf("Local device %s\n", bt_sock_addr2str(&di.bdaddr, straddr)); //printf("Remote device %s (%d)\n", qcaddr, channel); if(connect(sock, (struct sockaddr *) &raddr, sizeof(raddr)) < 0) { *(__eebt_getErrLocation(pthread_self())) = errno; //printf("THREAD: %d, errno: %d\n", pthread_self(), errno); //perror("connect1"); close(sock); return -1; } return sock;}#if 0static int open_connection(char const *qcaddr, int channel) { int sock, d; struct sockaddr_rc laddr, raddr; struct hci_dev_info di; if(hci_devinfo(0, &di) < 0) { //perror("hci_devinfo"); return -1; } //printf("Local device %s\n", batostr(&di.bdaddr)); laddr.rc_family = AF_BLUETOOTH; laddr.rc_bdaddr = di.bdaddr; laddr.rc_channel = 0; raddr.rc_family = AF_BLUETOOTH; str2ba(qcaddr, &raddr.rc_bdaddr); raddr.rc_channel = channel; if ((sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { //perror("socket"); return -1; } if (bind(sock, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) { //perror("bind"); close(sock); return -1; } //printf("Remote device %s (%d)\n", qcaddr, channel); if(connect(sock, (struct sockaddr *) &raddr, sizeof(raddr)) < 0) { *(__eebt_getErrLocation(pthread_self())) = errno; //perror("connect2"); close(sock); return -1; } return sock;}#endif//// Open serial port.//static gint cobex_init(struct cobex_context *gt){ if( gt->rfd == -1 ) { if (gt->addr != NULL) { if ((gt->rfd = bt_sock_open(gt->addr, gt->chan)) < 0) { //printf("*** 1\n"); return -1; } gt->wfd = gt->rfd; } else if (gt->portname != NULL) { if ((gt->rfd = open(gt->portname, O_RDWR | O_NONBLOCK | O_NOCTTY, 0)) < 0) { *(__eebt_getErrLocation(pthread_self())) = errno; //perror("Can' t open tty"); return -1; } gt->wfd = gt->rfd; tcgetattr(gt->rfd, >->oldtio); bzero(>->newtio, sizeof(struct termios)); gt->newtio.c_cflag = B115200 | CS8 | CREAD; // T.Koba for RFCOMM gt->newtio.c_iflag = IGNPAR; gt->newtio.c_oflag = 0; tcflush(gt->rfd, TCIFLUSH); tcsetattr(gt->rfd, TCSANOW, >->newtio); } else { gt->rfd = 0; gt->wfd = 1; } } return 1;}//// Close down. If force is TRUE. Try to break out of OBEX-mode.//static void cobex_cleanup(struct cobex_context *gt, gboolean force){ if (gt->portname != NULL) { if(force) { // Send a break to get out of OBEX-mode if (ioctl(gt->rfd, TCSBRKP, 0) < 0) { BTERROR("Unable to send break!"); } } close(gt->rfd); } gt->rfd = gt->wfd = -1;}//// Open up cable OBEX//struct cobex_context *cobex_open(const gchar *port){ struct cobex_context *gt; const char *chan; gt = g_new0(struct cobex_context, 1); if (gt == NULL) return NULL; gt->rfd = gt->wfd = -1; gt->portname = port; gt->addr = NULL; gt->chan = -1; if ((chan = strchr((const char *) port, '@')) != NULL) { gt->addr = strdup((const char *) port); gt->addr[chan - (const char *) port] = 0; gt->chan = atoi(chan + 1); } return gt;}struct cobex_context *cobex_setsocket(const int fd){ struct cobex_context *gt; gt = g_new0(struct cobex_context, 1); if (gt == NULL) return NULL; gt->rfd = gt->wfd = fd; gt->portname = NULL; return gt;}int cobex_getsocket(struct cobex_context *gt){ return gt->rfd;} //// Close down cable OBEX.//void cobex_close(struct cobex_context *gt){ if (gt->addr) g_free(gt->addr); g_free(gt);} //// Do transport connect or listen//gint cobex_connect(obex_t *handle, gpointer userdata){ struct cobex_context *gt; gt = userdata; if(gt->rfd >= 0) { BTDEBUG("fd already exist. Using it"); return 1; } if(cobex_init(gt) < 0) { return -1; } return 1;}//// Do transport disconnect//gint cobex_disconnect(obex_t *handle, gpointer userdata){ struct cobex_context *gt; gt = userdata; cobex_cleanup(gt, FALSE); return 1;}//// Called when data needs to be written//gint cobex_write(obex_t *handle, gpointer userdata, guint8 *buffer, gint length){ struct cobex_context *gt; gint actual = 0; gint pos = 0; gt = userdata; /* * [REV] * For some reason the init function wasn't getting called before this call * to write. Probably my own fault, something I ripped out must have in * the initial cobex_connect() callback from OpenOBEX. Fortunately for me * it works fine if I just call the init from the first write. The init * sets the wfd field so that this call gets skipped on all writes after * the first. */ if(gt->wfd < 0) { if(cobex_init(gt) < 0) { //printf("*** 0\n"); return( -1 ); } } while (actual < length) { int frag; frag = write(gt->wfd, &buffer[pos], length - pos); if (frag < 0) { if (errno == EAGAIN) { frag = 0; BTDEBUG("Temp. no resource avail."); } else { *(__eebt_getErrLocation(pthread_self())) = errno; BTERROR("Write error:%s", strerror(errno)); return frag; } } actual += frag; pos += frag; BTDEBUG("Wrote %d fragment", frag); } BTDEBUG("Wrote %d bytes (expected %d)", actual, length); return actual;}//// Called when more data is needed.//gint cobex_handle_input(obex_t *handle, gpointer userdata, gint timeout){ gint actual; struct cobex_context *gt; struct timeval time; fd_set fdset; gint ret; gint16 expectlen; gt = userdata; /* Return if no fd */ if(gt->rfd < 0) return -1; time.tv_sec = timeout; time.tv_usec = 0; FD_ZERO(&fdset); FD_SET(gt->rfd, &fdset); // for fragment read T.Koba actual = 0; expectlen = 0; do { gint len; fd_set fdset1 = fdset; ret = select(gt->rfd+1, &fdset1, NULL, NULL, &time); /* Check if this is a timeout (0) or error (-1) */ if (ret < 0) { BTERROR("Error (%d)", ret); return -1; } if (ret == 0) len = 0; else { len = read(gt->rfd, >->inputbuf[actual], sizeof(gt->inputbuf)-actual); if( len < 0 ){ if (errno == -EAGAIN) { BTDEBUG("Temp. no resource available."); len = 0; } else { BTDEBUG("read error (%d)", len); *(__eebt_getErrLocation(pthread_self())) = errno; return len; } } else if (len == 0) { BTDEBUG("Connection terminated."); return -1; } } actual += len; if( (expectlen == 0) && (actual >= 3) ) { expectlen = ntohs(*(guint16 const *) (gt->inputbuf + 1)); BTDEBUG("expect %d bytes", expectlen); if( expectlen > sizeof(gt->inputbuf) ) { BTDEBUG("cobex_context buffer size is too small!!!"); exit(1); } } } while( (actual < expectlen) || (expectlen == 0) ); BTDEBUG("Read %d bytes", actual); OBEX_CustomDataFeed(handle, gt->inputbuf, actual); return actual;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -