在 C 與 Bluez

int get_l2cap_connection () {

首先,我們需要的所有變數,將在適當的位置進行解釋。

    int ssock = 0;
    int csock = 0;
    int reuse_addr = 1;
    struct sockaddr_l2 src_addr;
    struct bt_security bt_sec;
    int result = 0;

首先,我們需要建立一個套接字,我們可以接受來自的連線。socket 系列是 PF_BLUETOOTH,socket 型別是 SOCK_SEQPACKET(我們想要一個類似 TCP 的套接字,而不是 raw),協議是藍芽協議 L2CAP(BTPROTO_L2CAP)。

    ssock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);

我們想確保它是成功的:

    if (ssock < 0) {
        perror("Opening L2CAP socket failed");
        return -1;
    }

我們現在必須使用萬用字元地址填充源地址結構,因此任何具有任何地址的藍芽裝置都可以連線到我們。萬用字元地址在 bluetooth.h 中定義為 BDADDR_ANY。要將其複製到地址結構中,我們可以使用 bacpy 函式。我們還必須設定地址系列,地址型別和通道 ID。

    memset(&src_addr, 0, sizeof(src_addr));
    bacpy(&src_addr.l2_bdaddr, BDADDR_ANY);
    src_addr.l2_family = AF_BLUETOOTH;
    src_addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
    src_addr.l2_cid = htobs(CID_ATT);

設定 SO_REUSEADDR 選項將允許我們在必要時再次快速呼叫 bind(這可以省略):

    setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));

接下來,我們必須使用剛剛定義的源地址結構繫結套接字。我們再次檢查返回值以確保它有效。

    result = bind(ssock, (struct sockaddr*) &src_addr, sizeof(src_addr));
    if (result < 0) {
        perror("Binding L2CAP socket failed");
        return -1;
    }

接下來是設定安全級別。請注意,此步驟是可選的,但將安全級別設定為 MEDIUM 將允許自動與裝置配對(核心處理實際配對)。

    memset(&bt_sec, 0, sizeof(bt_sec));
    bt_sec.level = BT_SECURITY_MEDIUM;
    result = setsockopt(ssock, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, sizeof(bt_sec));
    if (result != 0) {
        perrorno("Setting L2CAP security level failed");
        return -1;
    }

現在我們可以告訴核心我們的 ssock 是一個被動套接字,它將接受一個連線。第二個引數是積壓。如果你想了解更多資訊,listen 的聯機幫助頁面包含你需要的所有資訊。

    result = listen(ssock, 10);
    if (result < 0) {
        perror("Listening on L2CAP socket failed");
        return -1;
    }

現在我們可以等待傳入的連線。一旦 accept 返回,peer_addr 結構將包含所連線裝置的地址。csock 將是我們可以讀取/寫入的套接字的檔案描述符,以便與連線的裝置進行通訊。

    memset(peer_addr, 0, sizeof(*peer_addr));
    socklen_t addrlen = sizeof(*peer_addr);
    csock = accept(ssock, (struct sockaddr*)peer_addr, &addrlen);
    if (csock < 0) {
        perror("Accepting connection on L2CAP socket failed");
        return -1;
    }

我們可以列印連線裝置的地址(當然是可選的)。我們可以使用 batostr 函式將藍芽地址轉換為字串。

    printf("Accepted connection from %s", batostr(&peer_addr->l2_bdaddr));

如果我們不想要任何其他裝置連線,我們應該關閉伺服器套接字。在與裝置通訊完成後,使用 csock 執行相同的操作。

    close(ssock);
    return csock;
}