📄 btsrv.c
字号:
/* Affix - Bluetooth Protocol Stack for Linux Copyright (C) 2001,2002 Nokia Corporation Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com> Original Author: Imre Deak <ext-imre.deak@nokia.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//* $Id: btsrv.c,v 1.13 2004/02/13 17:16:03 kassatki Exp $ User space daemon for making local services accessable to remote devices Fixes: Imre Deak <ext-imre.deak@nokia.com> Dmitry Kasatkin <dmitry.kasatkin@nokia.com>*/#include <affix/config.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/errno.h>#include <fcntl.h>#include <unistd.h>#include <syslog.h>#include <signal.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <getopt.h>#include <string.h>#include <sys/mman.h>/* bluetooth stuff */#include <affix/bluetooth.h>#include <affix/btcore.h>#include "btsrv.h"#define DEF_CONFIG_FILE "/etc/affix/btsrv.conf"service_t services[MAX_SERVICE_NUM];device_t devices[MAX_DEVICE_NUM];btdev_list btdevs; // device cachechar *config_file = NULL;char *config_expr = NULL;int initdev = 0;int startsvc = 0;int managepin = 0;int managekey = 0;/* local */int svcnums;int devnums;int efd, mfd;char confdir[80];int _daemon = 0;service_info_t profiles[] = { { "SerialPort", SDP_UUID_SERIAL_PORT, 0x0000, SDP_UUID_SERIAL_PORT, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "DialupNetworking", SDP_UUID_DUN, SDP_UUID_GENERIC_NETWORKING, SDP_UUID_DUN, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "LANAccess", SDP_UUID_LAN, SDP_UUID_GENERIC_NETWORKING, SDP_UUID_LAN, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "OBEXFiletransfer", SDP_UUID_OBEX_FTP, 0x0000, SDP_UUID_OBEX_FTP, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "OBEXObjectPush", SDP_UUID_OBEX_PUSH, 0x0000, SDP_UUID_OBEX_PUSH, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "PANPanu", SDP_UUID_PANU, 0x0000, SDP_UUID_PANU, BTPROTO_L2CAP, sdpreg_pan }, { "PANGn", SDP_UUID_GN, 0x0000, SDP_UUID_GN, BTPROTO_L2CAP, sdpreg_pan }, { "PANNap", SDP_UUID_NAP, 0x0000, SDP_UUID_NAP, BTPROTO_L2CAP, sdpreg_pan }, { "FAX", SDP_UUID_FAX, SDP_UUID_GENERIC_TELEPHONY, SDP_UUID_FAX, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "HandsFree", SDP_UUID_HANDSFREE, SDP_UUID_GENERIC_AUDIO, SDP_UUID_HANDSFREE, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "HandsFreeAG", SDP_UUID_HANDSFREE_AG, SDP_UUID_GENERIC_AUDIO, SDP_UUID_HANDSFREE, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "Headset", SDP_UUID_HEADSET, SDP_UUID_GENERIC_AUDIO, SDP_UUID_HEADSET, BTPROTO_RFCOMM, sdpreg_rfcomm }, { "HeadsetAG", SDP_UUID_HEADSET_AG, SDP_UUID_GENERIC_AUDIO, SDP_UUID_HEADSET, BTPROTO_RFCOMM, sdpreg_rfcomm }, {NULL,}};int btsrv_devconf(int fd);void printusage(void){ printf("usage: btsrv " "[-d] " "[-v] " "[--config config_file | -C config_file] " "[--expression config_expr | -e config_expr] " "[--initdev | -i] " "[--noinitdev] " "[--startsvc | -s] " "[--nostartsvc] " "[--managepin | -p] " "[--nomanagepin] " "[--managekey | -k]" "[--nomanagekey] " "\n" );}int start_service(service_t *svc){ struct sockaddr_affix saddr; int err, fd; socklen_t len = sizeof(saddr); svc->srv_fd = -1; if (!(svc->flags & SRV_FLAG_SOCKET)) goto skip_socket; if (svc->info->proto == BTPROTO_RFCOMM) { fd = socket(PF_AFFIX, SOCK_STREAM, BTPROTO_RFCOMM); if (fd < 0) { BTERROR("Unable to create RFCOMM socket"); return -1; } if (svc->flags & SRV_FLAG_RFCOMM_TTY) { err = rfcomm_set_type(fd, RFCOMM_TYPE_BTY); if (err < 0) { BTERROR("Unable to set RFCOMM interface type to tty"); return -1; } } } else { fd = socket(PF_AFFIX, SOCK_SEQPACKET, BTPROTO_L2CAP); if (fd < 0) { BTERROR("Unable to create L2CAP socket"); return -1; } } if (fcntl(fd, F_SETFL, O_NONBLOCK) != 0) { BTERROR("Unable to set non blocking mode for RFCOMM socket"); return -1; } saddr.family = AF_AFFIX; saddr.devnum = HCIDEV_ANY; saddr.port = svc->port; /* if 0 - dynamically allocated */ saddr.bda = BDADDR_ANY; err = bind(fd, (struct sockaddr*)&saddr, sizeof(saddr)); if (err < 0) { BTERROR("Unable to bind address"); return -1; } setsockopt(fd, SOL_AFFIX, BTSO_SECURITY, &svc->security, sizeof(int)); err = getsockname(fd, (struct sockaddr*)&saddr, &len); if (err < 0) { BTERROR("Unable to get address info"); return -1; } BTINFO("Bound service %s to port %d", svc->name, saddr.port); err = listen(fd, 5); if (err < 0) { BTERROR("Unable to listen for connection requests"); return -1; } svc->srv_fd = fd; svc->port = saddr.port;skip_socket:#if defined(CONFIG_AFFIX_SDP) if (sdpreg_register(svc) < 0 ) return -1;#endif svc->running = 1; return 0;}void stop_service(service_t *svc){ if (!svc->running) return;#if defined(CONFIG_AFFIX_SDP) sdpreg_unregister(svc);#endif if (svc->srv_fd != -1) close(svc->srv_fd);}int start_all_services(void){ int i, j; if (!startsvc) return 0; for (i = 0; i < svcnums; i++) if (services[i].active && start_service(&services[i]) < 0) goto fail; return 0;fail: for (j = 0; j < i; j++) stop_service(&services[i]); return -1;}void stop_all_services(void){ int i; for (i = 0; i < svcnums; i++) stop_service(&services[i]);}char *btsrv_format_cmd(const char *cmd, int conid, int line, BD_ADDR *bda, int port){ char *formatted_cmd; int i, j, res; formatted_cmd = (char *)malloc(MAX_CMD_LEN + 1); if (formatted_cmd == NULL) return NULL; i = j = 0; while (cmd[i]) { switch (cmd[i]) { case '%': switch(cmd[i + 1]) { case 'a': res = snprintf(&formatted_cmd[j], MAX_CMD_LEN - j, "%s", bda2str(bda)); break; case 'l': res = snprintf(&formatted_cmd[j], MAX_CMD_LEN - j, "%d", line); break; case 'i': res = snprintf(&formatted_cmd[j], MAX_CMD_LEN - j, "%d", conid); break; case 'c': res = snprintf(&formatted_cmd[j], MAX_CMD_LEN - j, "%d", port); break; case '%': formatted_cmd[j] = '%'; res = j < MAX_CMD_LEN ? 1 : -1; break; default: res = -1; } i++; /* skip % sign */ break; default: formatted_cmd[j] = cmd[i]; res = j < MAX_CMD_LEN ? 1 : -1; } if (res == -1) { free(formatted_cmd); return NULL; } j += res; i++; } formatted_cmd[j] = '\0'; return formatted_cmd;}int execute_cmd(char *cmd, int sock_fd, int port, BD_ADDR *bd_addr, int flags){ char *formatted_cmd; int line; int fd = -1; int conid; conid = sock_fd; if (flags & SRV_FLAG_RFCOMM_TTY) { char dev[10]; line = rfcomm_open_tty(sock_fd, RFCOMM_BTY_ANY); close(sock_fd); if (line < 0) { BTERROR("Unable to bind a socket to virtual port device"); return -1; } sprintf(dev, "/dev/bty%d", line); BTINFO("Socket bound to virtual port device %s", dev); if (flags & SRV_FLAG_STD) { fd = open(dev, O_RDWR); if (fd < 0) { BTERROR("Unable to open port device %s", dev); return -1; } } } else { fd = sock_fd; line = -1; } if (flags & SRV_FLAG_STD) { BTINFO("Socket multiplexed to stdin/stdout"); if (fd != 0){ close(0); if (dup2(fd, 0) < 0) { BTERROR("Unable to duplicate socket descriptor to stdin\n"); return -1; } } if (fd != 1) { close(1); if (dup2(fd, 1) < 0) { BTERROR("Unable to duplicate socket descriptor to stdout\n"); return -1; } } if (fd != 0 && fd != 1) close(fd); close(2); if (open("/dev/null", O_RDWR) != 2) { BTERROR("Cannot open /dev/null to stderr"); return -1; } } formatted_cmd = btsrv_format_cmd(cmd, conid, line, bd_addr, port); if (formatted_cmd) { BTINFO("Execute %s", formatted_cmd); /* the following does not return normally */ execl("/bin/sh", "sh", "-c", formatted_cmd, NULL); BTERROR("Exec error"); return -1; } BTERROR("Parse error in the command line"); return -1;}/* * Event processing block */int event_pin_code_request(struct PIN_Code_Request_Event *evt, int devnum){ int fd, err, flags; FILE *fp; char pin[32], cmdline[100]; char name[248]; if (!managepin) return 0; err = hci_get_flags_id(devnum, &flags); if (err) return 0; fd = hci_open_id(devnum); if (fd < 0) return fd;#if 0 { /* get device name first */ INQUIRY_ITEM dev; dev.bda = evt->bda; dev.PS_Repetition_Mode = 0x00; dev.PS_Mode = 0x00; dev.Clock_Offset = 0x00; err = HCI_RemoteNameRequest(fd, &dev, name); if (err) { close(fd); BTERROR("Name request failed"); return err; } }#else name[0] = '\0';#endif if (!(flags & HCI_SECURITY_PAIRABLE)) goto err; sprintf(cmdline, "/etc/affix/btsrv-gui pin %s \"%s\"", bda2str(&evt->bda), name); DBPRT("cmdline: [%s]", cmdline); fp = popen(cmdline, "r"); if (!fp) { BTERROR("popen() failed"); goto err; } err = fscanf(fp, "%s", pin); if (err == EOF) { BTERROR("fscanf() failed"); pclose(fp); goto err; } DBPRT("Got PIN code from pipe: %s, len: %d", pin, strlen(pin)); pclose(fp); err = HCI_PINCodeRequestReply(fd, &evt->bda, strlen(pin), pin); if (err) { BTERROR("unable to set pin code: %d", err); } close(fd); return 0;err: err = HCI_PINCodeRequestNegativeReply(fd, &evt->bda); close(fd); return 0;}int event_link_key_request(struct Link_Key_Request_Event *evt, int devnum){ int fd, err, ok = 0; btdev_struct *btdev; fd = hci_open_id(devnum); if (fd < 0) return fd; btdev_cache_reload(&btdevs); btdev = btdev_cache_lookup(&btdevs, &evt->bda); if (btdev && (btdev->flags & BTDEV_KEY)) ok = 1; if (ok) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -