📄 bthandler.c
字号:
char* argv[9]; char ttyname[BTS_TTY_NAME_LEN]; char bdaddrstr[BT_BDADDR_LEN]; struct stat s; if (!con) return BT_ERR_ARGUMENT; switch (con->state) { case BT_STATE_UNINITIALIZED: break; case BT_STATE_INITIALIZED: /* clean-up after pppd finished, sometimes it takes ages to bring it down */ if (con->profile == BT_PROFILE_DUN) if (con->ppp.pid > 0) if (waitpid(con->ppp.pid, &res, WNOHANG)) con->ppp.pid = -1; break; case BT_STATE_START_LISTENING: /* put socket into the listening mode */ if (!BTTimerExpired(&con->listenretrytr) && !BTTimerExpired(&con->listentotaltr)) break; res = BTSocketListen(con->sock, (con->profile == BT_PROFILE_HF) ? BT_CHANNEL_HF : ( (con->profile == BT_PROFILE_HS) ? BT_CHANNEL_HS : con->sock->chan ) ); if (res != BT_ERR_NONE) { if (BTTimerExpired(&con->listentotaltr)) { DEBUG_LOG1("cannot start listening, error=%s", ERROR2STR(res)); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } else { BTSetTimer(&con->listenretrytr, BT_TO_LISTEN_RETRY); } } else { UPDATE_STATE(con->state, BT_STATE_LISTENING); } break; case BT_STATE_LISTENING: /* try to accept a new connection */ res = BTSocketAccept(con->sock, BT_TO_NONE); switch (res) { case BT_ERR_TIMEOUT: break; case BT_ERR_NONE: UPDATE_STATE(con->state, BT_STATE_CONNECTED); break; default: DEBUG_LOG1("cannot accept, error=%s", ERROR2STR(res)); BTSocketStopListen(con->sock); BTSetTimer(&con->listenretrytr, BT_TO_LISTEN_RETRY); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); break; } break; case BT_STATE_START_CONNECTING: /* put the socket into connecting mode */ if (!BTTimerExpired(&con->connectretrytr) && !BTTimerExpired(&con->connecttotaltr)) break; /* wait till ACL link is down (the hack needed by some phones) */ if (!(con->flags & BT_FLAG_MULTICHANNEL)) { if (BTSocketGetAddress(con->sock, bdaddrstr) == BT_ERR_NONE) { if (BTIsAclLinkActive(bdaddrstr)) { DEBUG_LOG("ACL link is up, waiting..."); BTSetTimer(&con->aclremovetr, BT_TO_REMOVEACL); UPDATE_STATE(con->state, BT_STATE_REMOVE_CONNECTION); break; } } } res = BTSocketConnect(con->sock, BT_TO_NONE); switch (res) { case BT_ERR_NONE: UPDATE_STATE(con->state, BT_STATE_CONNECTED); break; case BT_ERR_TIMEOUT: UPDATE_STATE(con->state, BT_STATE_CONNECTING); break; default: DEBUG_LOG1("cannot start connecting, error=%s", ERROR2STR(res)); if (con->flags & BT_FLAG_DONOTRECONNECT) { if (con->flags & BT_FLAG_LISTEN) { DEBUG_LOG("reconnect disabled, listening"); INIT_LISTEN_TIMER(con, BT_TO_LISTEN_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); } else { DEBUG_LOG("reconnect disabled, initialized"); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } } if (BTTimerExpired(&con->connecttotaltr)) { if (con->flags & BT_FLAG_AUTORECONNECT) { DEBUG_LOG("autoreconnect enabled, reconnecting"); INIT_CONNECT_TIMER(con, BT_TO_CONNECT_TOTAL); } else if (con->flags & BT_FLAG_LISTEN) { DEBUG_LOG("number of retries exceeded, listening"); INIT_LISTEN_TIMER(con, BT_TO_LISTEN_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); } else { DEBUG_LOG("number of retries exceeded, initialized"); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } } else { int modelid = BTGetFileInt(BT_FILENAME_MODELID); if (!con->reconnecting && modelid != GOTYPE_VALENCIA500 && modelid != GOTYPE_VALENCIA700) { DEBUG_LOG("reconnecting using short timeout"); BTSetTimer(&con->connectretrytr, BT_TO_CONNECT_RETRY_1); } else { DEBUG_LOG("reconnecting using normal timeout"); BTSetTimer(&con->connectretrytr, BT_TO_CONNECT_RETRY); } } break; } break; case BT_STATE_REMOVE_CONNECTION: /* wait till ACL link is down (the hack needed by some phones) */ if (BTSocketGetAddress(con->sock, bdaddrstr) == BT_ERR_NONE) { if (BTIsAclLinkActive(bdaddrstr) == BT_TRUE) { if (!BTTimerExpired(&con->aclremovetr)) break; DEBUG_LOG("destroying ACL link."); BTDestroyAclLink(bdaddrstr); } else { DEBUG_LOG("ACL link is down."); } } BTSetTimer(&con->connectretrytr, 0); UPDATE_STATE(con->state, BT_STATE_START_CONNECTING); break; case BT_STATE_CONNECTING: /* check if connection is ready, no global timeout here - user may need to enter a PIN code for example */ res = BTSocketIsConnected(con->sock, BT_TO_NONE); switch (res) { case BT_ERR_TIMEOUT: break; case BT_ERR_NONE: UPDATE_STATE(con->state, BT_STATE_CONNECTED); break; default: DEBUG_LOG1("connecting failed, error=%s", ERROR2STR(res)); BTSocketClose(con->sock); if (con->flags & BT_FLAG_DONOTRECONNECT) { if (con->flags & BT_FLAG_LISTEN) { DEBUG_LOG("reconnect disabled, listening"); INIT_LISTEN_TIMER(con, BT_TO_LISTEN_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); } else { DEBUG_LOG("reconnect disabled, initialized"); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } } if (BTTimerExpired(&con->connecttotaltr)) { if (con->flags & BT_FLAG_AUTORECONNECT) { DEBUG_LOG("autoreconnect enabled, reconnecting"); INIT_CONNECT_TIMER(con, BT_TO_CONNECT_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_CONNECTING); } else if (con->flags & BT_FLAG_LISTEN) { DEBUG_LOG("number of retries exceeded, listening"); INIT_LISTEN_TIMER(con, BT_TO_LISTEN_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); } else { DEBUG_LOG("number of retries exceeded, initialized"); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } } else { int modelid = BTGetFileInt(BT_FILENAME_MODELID); if (!con->reconnecting && modelid != GOTYPE_VALENCIA500 && modelid != GOTYPE_VALENCIA700) { DEBUG_LOG("reconnecting using short timeout"); BTSetTimer(&con->connectretrytr, BT_TO_CONNECT_RETRY_1); } else { DEBUG_LOG("reconnecting using normal timeout"); BTSetTimer(&con->connectretrytr, BT_TO_CONNECT_RETRY); } UPDATE_STATE(con->state, BT_STATE_START_CONNECTING); } break; } break; case BT_STATE_CONNECTED: if (!con->sendbuf) break; res = BTSocketSend(con->sock, con->sendbuf, con->sendbuflen, &sent, BT_TO_NONE); if (res == BT_ERR_TIMEOUT) break; if (res != BT_ERR_NONE) { DEBUG_LOG("sending buffer: connection is lost"); BTSocketClose(con->sock); if (BTTimerExpired(&con->connecttotaltr)) { free(con->sendbuf); con->sendbuf = NULL; con->sendbuflen = 0; if (con->flags & BT_FLAG_AUTORECONNECT) { DEBUG_LOG("autoreconnect enabled, reconnecting"); con->reconnecting = 1; INIT_CONNECT_TIMER(con, BT_TO_CONNECT_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_CONNECTING); } else if (con->flags & BT_FLAG_LISTEN) { DEBUG_LOG("number of retries exceeded, listening"); INIT_LISTEN_TIMER(con, BT_TO_LISTEN_TOTAL); UPDATE_STATE(con->state, BT_STATE_START_LISTENING); } else { DEBUG_LOG("number of retries exceeded, initialized"); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } } else { BTSetTimer(&con->connectretrytr, 0); UPDATE_STATE(con->state, BT_STATE_START_CONNECTING); } break; } if (sent < con->sendbuflen) { DEBUG_LOG("send buffer partially sent"); memcpy(con->sendbuf, con->sendbuf + sent, con->sendbuflen - sent); con->sendbuflen -= sent; } else { DEBUG_LOG("send buffer purged"); free(con->sendbuf); con->sendbuf = NULL; con->sendbuflen = 0; } break; case BT_STATE_APP_START: switch(con->ppp.state){ case BT_PPP_STATE_INIT: pid = BTGetFileInt(BT_PPP_PIDFILE); if (pid > 0) { DEBUG_LOG1("removing previous instance of %s", BT_PPP_NAME); kill(pid, SIGTERM); BTSetTimer(&con->ppp.removetr, BT_TO_APPREMOVE); UPDATE_STATE(con->ppp.state, BT_PPP_STATE_REMOVE); break; } if (!(con->flags & BT_FLAG_MULTICHANNEL)) { if (BTSocketGetAddress(con->sock, bdaddrstr) == BT_ERR_NONE) { if (BTIsAclLinkActive(bdaddrstr)) { DEBUG_LOG("ACL link is up, waiting."); BTSetTimer(&con->aclremovetr, BT_TO_REMOVEACL); UPDATE_STATE(con->state, BT_STATE_APP_REMOVE_CONNECTION); break; } } } UPDATE_STATE(con->ppp.state, BT_PPP_STATE_CREATETTY); //fall trough case BT_PPP_STATE_CREATETTY: if (BTSocketCreateTTY(con->sock) != BT_ERR_NONE) { UPDATE_STATE(con->state, BT_STATE_INITIALIZED); break; } BTSetTimer(&con->ppp.ttytr, BT_TO_TTYCREATE); UPDATE_STATE(con->ppp.state, BT_PPP_STATE_CHECKTTY); //fall though case BT_PPP_STATE_CHECKTTY: if (BTSocketIsTTYReady(con->sock, &res) != BT_ERR_NONE) { BTSocketReleaseTTY(con->sock); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); break; } if (res == BT_FALSE && !BTTimerExpired(&con->ppp.ttytr)) break; if (res == BT_FALSE) { BTSocketReleaseTTY(con->sock); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); break; } UPDATE_STATE(con->ppp.state, BT_PPP_STATE_START); BTSetTimer(&con->ppp.startretrytr, 0); BTSetTimer(&con->ppp.starttotaltr, BT_TO_PPPSTARTTOTAL); //fall through case BT_PPP_STATE_START: /* put the socket into connecting mode */ if (!BTTimerExpired(&con->ppp.startretrytr)) break; i = 0; argv[i++] = BT_PPP_NAME; if (BTSocketGetTTYName(con->sock, ttyname) != BT_ERR_NONE) { DEBUG_LOG("failed to get TTY name"); BTSocketReleaseTTY(con->sock); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); break; } //PLEASECHECK (Victor): work around, removing the PPP lock file unlink("/var/lock/LCK..rfcomm0"); argv[i++] = ttyname; argv[i++] = BT_PPP_BAUDRATE; if (strlen(con->ppp.param)) { argv[i++] = "call"; argv[i++] = con->ppp.param; } argv[i++] = "linkname"; argv[i++] = BT_PPP_LINKNAME; argv[i++] = NULL; con->ppp.pid = vfork(); if (!con->ppp.pid) { if (execvp(BT_PPP_NAME, argv) < 0) { DEBUG_LOG2("%s failed to start: %s", BT_PPP_NAME, strerror(errno)); exit(1); } } else if (con->ppp.pid > 0) { DEBUG_LOG2("%s started with pid=%d", BT_PPP_NAME, con->ppp.pid); BTSetTimer(&con->ppp.readytr, BT_TO_PPPREADY); UPDATE_STATE(con->ppp.state, BT_PPP_STATE_CHECKREADY); } else { DEBUG_LOG1("failed to start %s", BT_PPP_NAME); BTSocketReleaseTTY(con->sock); UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } break; case BT_PPP_STATE_CHECKREADY: if (BTTimerExpired(&con->ppp.readytr) || waitpid(con->ppp.pid, &res, WNOHANG)) { if (!BTTimerExpired(&con->ppp.readytr)) { if (WIFEXITED(res)) { DEBUG_LOG1("terminated normally, exit status = %d", WEXITSTATUS(res)); if (WEXITSTATUS(res) == 7 && !BTTimerExpired(&con->ppp.starttotaltr)) { DEBUG_LOG("retrying ppp startup: busy device"); BTSetTimer(&con->ppp.startretrytr, BT_TO_PPPSTARTRETRY); UPDATE_STATE(con->ppp.state, BT_PPP_STATE_START); break; } } DEBUG_LOG1("%s failed after start", BT_PPP_NAME); } else { DEBUG_LOG1("%s timeout expired", BT_PPP_NAME); } BTSocketReleaseTTY(con->sock); pid = BTGetFileInt(BT_PPP_PIDFILE); if (pid > 0) { DEBUG_LOG1("terminating %d", pid); kill(pid, SIGTERM); } BTSetTimer(&con->ppp.removetr, BT_TO_APPREMOVE); UPDATE_STATE(con->state, BT_STATE_APP_CLOSING); } else if (stat(BT_PPP_UPFILE, &s) >= 0 ) { BTSocketReleaseTTY(con->sock); UPDATE_STATE(con->state, BT_STATE_APP_READY); } break; case BT_PPP_STATE_REMOVE: pid = BTGetFileInt(BT_PPP_PIDFILE); if (pid > 0) { if (!waitpid(pid, &res, WNOHANG) && !BTTimerExpired(&con->ppp.removetr)) break; pid = BTGetFileInt(BT_PPP_PIDFILE); if (pid > 0) { DEBUG_LOG1("sending KILL to %s", BT_PPP_NAME); kill(pid, SIGKILL); waitpid(pid, &res, WNOHANG); } } UPDATE_STATE(con->ppp.state, BT_PPP_STATE_INIT); break; default: break; } break; case BT_STATE_APP_REMOVE_CONNECTION: if (BTSocketGetAddress(con->sock, bdaddrstr) == BT_ERR_NONE) { if (BTIsAclLinkActive(bdaddrstr) == BT_TRUE) { if (!BTTimerExpired(&con->aclremovetr)) break; DEBUG_LOG("destroying ACL link."); BTDestroyAclLink(bdaddrstr); } else { DEBUG_LOG("ACL link is down."); } } UPDATE_STATE(con->state, BT_STATE_APP_START); break; case BT_STATE_APP_READY: if (waitpid(con->ppp.pid, &res, WNOHANG)) UPDATE_STATE(con->state, BT_STATE_INITIALIZED); break; case BT_STATE_APP_CLOSING: if (BTTimerExpired(&con->ppp.removetr) || waitpid(con->ppp.pid, &res, WNOHANG)) { if (!BTTimerExpired(&con->ppp.removetr)) con->ppp.pid = -1; UPDATE_STATE(con->state, BT_STATE_INITIALIZED); } break; case BT_STATE_CLOSING: switch(con->ppp.state){ case BT_PPP_STATE_CLOSING: if (BTTimerExpired(&con->ppp.removetr) || waitpid(con->ppp.pid, &res, WNOHANG)) { if (!BTTimerExpired(&con->ppp.removetr)) con->ppp.pid = -1; UPDATE_STATE(con->state, BT_STATE_UNINITIALIZED); } break; case BT_PPP_STATE_UNINITIALIZED: default: UPDATE_STATE(con->state, BT_STATE_UNINITIALIZED); break; } break; default: break; } return BT_ERR_NONE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -