📄 btsrv.c
字号:
btdev_cache_unlock(); hci_close(fd); return err;}int event_link_key_notification(struct Link_Key_Notification_Event *evt, int devnum){ btdev_struct *btdev; if (!managekey) return 0; btdev_cache_reload(); btdev = btdev_cache_add(&evt->bda); if (btdev == NULL) return -1; btdev->key_type = evt->Key_Type; memcpy(btdev->link_key, evt->Link_Key, 16); btdev->flags |= BTDEV_KEY; btdev_cache_save(); return 0;}int event_handler(int fd){ uint8_t buf[HCI_MAX_EVENT_SIZE]; int err, devnum; HCI_Event_Packet_Header *hdr = (void*)buf; err = hci_recv_event_any(fd, &devnum, buf, sizeof(buf)); if (err < 0) return err; DBPRT("got event: %#x, from: %d", hdr->EventCode, devnum); switch (hdr->EventCode) { case HCI_E_LINK_KEY_REQUEST: event_link_key_request((void*)hdr, devnum); break; case HCI_E_LINK_KEY_NOTIFICATION: event_link_key_notification((void*)hdr, devnum); break; case HCI_E_PIN_CODE_REQUEST: event_pin_code_request((void*)hdr, devnum); break; default: break; } return 0;}int message_handler(int fd){ uint8_t buf[HCI_MAX_MSG_SIZE]; struct hci_msg_hdr *msg = (void*)(buf+1); int err; err = recv(fd, buf, sizeof(buf), 0); if (err < 0) return err; DBPRT("got message: %x", msg->opcode); if (msg->opcode == HCICTL_STATE_CHANGE) { struct hci_state_change *cmd = (void*)msg; if (cmd->event == HCIDEV_UP) { updevnums++; BTINFO("device %d is up, count: %d\n", cmd->devnum, updevnums); err = btsrv_devconf(cmd->devnum); if (err) { BTERROR("Unable to configure device: %d", cmd->devnum); return err; } start_services(); } else if (cmd->event == HCIDEV_DOWN) { updevnums--; BTINFO("device %d is down, count: %d\n", cmd->devnum, updevnums); if (updevnums < 1) { // no active devices.. stop services stop_services(); } } } return 0;}int handle_connections(void){ int i, err = 0; int fd_cnt; fd_set fds_read; int max_fd; for(;;) { FD_ZERO(&fds_read); max_fd = -1; /* set service fd */ for (i = 0; i < svcnums; i++) { if (services[i].running && services[i].srv_fd != -1) { FD_SET(services[i].srv_fd, &fds_read); if (max_fd < services[i].srv_fd) max_fd = services[i].srv_fd; } } /* set event fd */ FD_SET(efd, &fds_read); if (max_fd < efd) max_fd = efd; FD_SET(mfd, &fds_read); if (max_fd < mfd) max_fd = mfd; /* poll data */ fd_cnt = select(max_fd + 1, &fds_read, NULL, NULL, NULL); if (fd_cnt < 0) { if (errno != EINTR) { BTERROR("Select error: %s", strerror(errno)); err = -1; } goto exit; } else if (fd_cnt == 0) { //should not happen } if (FD_ISSET(efd, &fds_read)) { event_handler(efd); } if (FD_ISSET(mfd, &fds_read)) { message_handler(mfd); } for (i = 0; fd_cnt && (i < svcnums); i++) { if (services[i].running && services[i].srv_fd != -1 && FD_ISSET(services[i].srv_fd, &fds_read)) { int newsock; struct sockaddr_affix caddr; socklen_t calen = sizeof(caddr); int pid = 0; newsock = accept(services[i].srv_fd, (struct sockaddr*)&caddr, &calen); if (newsock == -1) { BTERROR("Accept error"); continue; } BTINFO("Connection from %s\nchannel %d (%s Profile)", bda2str(&caddr.bda), caddr.port, services[i].name); if (services[i].cmd[0] != '\0') { pid = fork(); if (pid == 0) { // child int res, j; for (j = 0; j < svcnums; j++) close(services[j].srv_fd); res = execute_cmd(services[i].cmd, newsock, caddr.port, &caddr.bda, services[i].flags); /* In case of error.. */ exit(res); } } if (pid < 0) { BTERROR("Fork error"); } close(newsock); fd_cnt--; } } }exit: return err;}/* * read HCI events and kernel messages */int start_event_handler(void){ uint64_t mask = 0; efd = hci_open_event(); if (efd < 0) { BTERROR("Unable to open hci(NULL)"); return efd; } mfd = hci_open_mgr(); if (mfd < 0) { BTERROR("Unable to open mgr"); close(efd); return mfd; } if (managepin) { hci_set_mode(mfd, AFFIX_MODE_PIN); mask |= PIN_CODE_REQUEST_MASK; } if (managekey) { hci_set_mode(mfd, AFFIX_MODE_KEY); mask |= LINK_KEY_NOTIFICATION_MASK | LINK_KEY_REQUEST_MASK; } if (mask) hci_event_mask(efd, mask); return 0;}void stop_event_handler(void){ close(mfd); close(efd);}int btsrv_setdev(int fd, struct btdevice *dev){ int err; err = HCI_WriteSecurityMode(fd, dev->security); if (err < 0) { BTERROR("hci_set_secmode() failed\n"); return err; } err = hci_set_role(fd, dev->role); if (err < 0) { BTERROR("hci_set_role() failed\n"); return err; } err = hci_set_pkttype(fd, dev->pkt_type); if (err < 0) { BTERROR("hci_set_pkttype() failed\n"); return err; } err = HCI_WriteClassOfDevice(fd, dev->cod); if (err) { BTERROR("WriteScanEnable error\n"); return err; } if (dev->btname) { err = HCI_ChangeLocalName(fd, dev->btname); if (err) { BTERROR("WriteScanEnable error\n"); return err; } } err = HCI_WriteScanEnable(fd, dev->scan); if (err) { BTERROR("WriteScanEnable error\n"); return err; } return 0;}int btsrv_devconf(int devnum){ int err = 0, i, fd; struct btdevice *dev; struct hci_dev_attr da; if (!initdev) return 0; err = hci_get_attr_id(devnum, &da); if (err) return err; fd = hci_open(da.name); if (fd < 0) { BTERROR("hci_open_id() failed: %s\n", da.name); return fd; } for (i = 0; i < devnums; i++) { dev = &devices[i]; if ((i == 0 && dev->name[0] == '*') || (strcasecmp(dev->name, da.name) == 0)) { err = btsrv_setdev(fd, dev); if (err) break; } } close(fd); return err;}int btsrv_devinit(void){ int i, err, num; struct hci_dev_attr da; int devs[HCI_MAX_DEVS]; num = hci_get_devs(devs); if (num < 0) { BTERROR("Unable to get device info\n"); return num; } for (i = 0; i < num; i++) { err = hci_get_attr_id(devs[i], &da); if (err < 0) { BTERROR("hci_get_attr() failed: %d\n", devs[i]); continue; } if (!(da.flags & HCI_FLAGS_UP)) continue; updevnums++; err = btsrv_devconf(da.devnum); if (err) return err; } return 0;}int btsrv_startup(void){ if (start_event_handler() < 0) { BTERROR("Cannot start event handler"); return -1; } /* initialize devices */ if (btsrv_devinit()) { BTERROR("Unable to initialize devices\n"); return -1; } if (start_services() < 0) { BTERROR("Cannot start services"); return -1; } return 0;}int btsrv_cleanup(void){ int i; struct btdevice *dev; BTINFO("Terminating .."); stop_event_handler(); stop_services(); free(config_file); config_file = NULL; free(config_expr); config_expr = NULL; for (i = 0; i < svcnums; i++) { if (services[i].name) free(services[i].name); if (services[i].prov) free(services[i].prov); if (services[i].desc) free(services[i].prov); } for (i = 0; i < devnums; i++) { dev = &devices[i]; if (dev->btname) free(dev->btname); } memset(services, 0, sizeof(services)); memset(services, 0, sizeof(devices)); return 0;}void get_cmd_opts(int argc, char **argv){ int c, lind = 0; struct option opts[] = { {"help", 0, 0, 'h'}, {"daemon", 0, 0, 'd'}, {"config", 1, 0, 'C'}, {"debug", 0, 0, 'v'}, {"initdev", 0, 0, 'i'}, {"noinitdev", 0, 0, 'I'}, {"startsvc", 0, 0, 's'}, {"nostartsvc", 0, 0, 'S'}, {"managepin", 0, 0, 'p'}, {"nomanagepin", 0, 0, 'P'}, {"managekey", 0, 0, 'k'}, {"nomanagekey", 0, 0, 'K'}, {"expression", 0, 0, 'e'}, {0, 0, 0, 0} }; optind = 0; for (;;) { c = getopt_long(argc, argv, "hdpskvC:e:", opts, &lind); if (c == -1) break; switch (c) { case 'h': printusage(); exit(0); break; case 'd': gobackground = 1; break; case 'C': config_file = strdup(optarg); break; case 'v': verboseflag = 1; break; case 'p': managepin = 1; break; case 'P': managepin = 0; break; case 'k': managekey = 1; break; case 'K': managekey = 0; break; case 'i': initdev = 1; break; case 'I': initdev = 0; break; case 's': startsvc = 1; break; case 'S': startsvc = 0; break; case 'e': config_expr = strdup(optarg); break; case '?': fprintf(stderr, "Unknown option: %c\n", optopt); exit(1); break; } }}void signal_handler(int sig){ BTINFO("Sig handler : %d", sig); if (sig != SIGHUP) exit(0); restart = 1;}void do_exit(void){ btsrv_cleanup();}int main(int argc, char **argv){ int err; if (affix_init(argc, argv, LOG_DAEMON)) { BTERROR("Affix initialization failed\n"); return 1; } BTINFO("%s started [%s].", argv[0], affix_version); restart: // read first to get config_file get_cmd_opts(argc, argv); if (config_expr) { // use command line configuration if (btsrv_read_config_buf(config_expr, &svcnums, &devnums)) { BTERROR("Invalid config expr: %s", config_expr); return -1; } startsvc = 1; // default action for this } else { if (!config_file) config_file = strdup(DEF_CONFIG_FILE); // read config_file if (btsrv_read_config(config_file, &svcnums, &devnums)) { BTERROR("Invalid config file: %s", config_file); return -1; } } // read again to overwride config file setting by command line get_cmd_opts(argc, argv); /* test X access */ if (managepin) { err = system("/etc/affix/btsrv-gui try 2>/dev/null"); if (err) { BTERROR("Unable to launch to /etc/affix/btsrv-gui\n" "-> maybe unable to connect to X-server or python-gtk problems\n" "-> Disable options requiring btsrv-gui (e.g. give --nomanagepin)\n"); return 1; } } if (startsvc && svcnums < 1) BTINFO("No services found in %s", config_file); if (btsrv_startup() < 0) { return -1; } if (!restart) { if (gobackground) affix_background(); atexit(do_exit); // exit handler signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGABRT, signal_handler); signal(SIGQUIT, signal_handler); } signal(SIGCHLD, SIG_IGN); restart = 0; if (handle_connections() < 0) { BTERROR("Unable to listen to incoming connections"); } signal(SIGCHLD, SIG_DFL); if (restart) { BTINFO("restarting..."); btsrv_cleanup(); // cleanup first goto restart; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -