1

我正在使用libwebsockets库(纯 C)编写一个在 ARMv7 设备上运行的应用程序(C++11)。我正在使用 gcc 4.7.3(arm、gnueabi)和 openwrt 来构建工具链和应用程序。

因此,libwebsockets 库在连接到服务器期间会在 HTTP 请求中发送握手请求。它看起来像这样:

GET / HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
Host: 192.168.1.111
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: YDtqt/+y5Efpzo1YiCg5YQ==
Origin: /
Sec-WebSocket-Protocol: myproto
Sec-WebSocket-Extensions: deflate-fram
Sec-WebSocket-Version: 13

当我在 x86_64 linux(Fedora,gcc 4.8.1)下构建我的应用程序时,这部分工作得很好。但如果我为 ARM 构建应用程序然后运行它,HTTP 请求如下所示:

gPra ma: / HTTP/1.1
no-<ach
C chegCon rol
 no<cac�e
Host: 192.168.1.111
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: QKnxtiEc3IlvyOW254h6kg==
Origin: /
Sec-WebSocket-Protocol: myproto
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Version: 13

或者这个(每次都会改变):

GET / HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
tUpgoade2.168.1.111
we.soc

该应用程序的代码与 x86_64 linux 机器的代码完全相同,所以我猜问题出在库或工具链(编译器、glibc)中的某个地方。这是发出 HTTP 请求的库代码(来自client.c):

char *
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
    struct libwebsocket *wsi, char *pkt)
{
    char buf[128];
    char hash[20];
    char key_b64[40];
    char *p = pkt;
    int n;

    n = libwebsockets_get_random(context, hash, 16);
    if (n != 16) {
        lwsl_err("Unable to read from random dev %s\n",
                    SYSTEM_RANDOM_FILEPATH);
        libwebsocket_close_and_free_session(context, wsi,
                     LWS_CLOSE_STATUS_NOSTATUS);
        return NULL;
    }

    lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));

    p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
            lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));

    p += sprintf(p, "Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a");
    p += sprintf(p, "Host: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
    p += sprintf(p, "Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: ");
    strcpy(p, key_b64);
    p += strlen(key_b64);
    p += sprintf(p, "\x0d\x0a");
    if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
        p += sprintf(p, "Origin: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));

    if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
        p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));

    p += sprintf(p, "Sec-WebSocket-Extensions: ");
    p += sprintf(p, "\x0d\x0a");

    if (wsi->ietf_spec_revision)
        p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
                       wsi->ietf_spec_revision);

    // here my callback is called and I print out the header (see examples above) 
    context->protocols[0].callback(context, wsi,
        LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
        NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12);

    p += sprintf(p, "\x0d\x0a");
    return p;
}

为简洁起见,我删除了一些代码和注释。好吧,我被困在这里。找不到可以破坏整个事情的东西。有人对发生的事情有任何想法吗?可能是那双清新的眼睛能帮到我。

谢谢。

4

2 回答 2

4

它看起来有点像在 ARM 构建上,您的pkt缓冲区可能不够大,或者您的堆栈不够大。

不过,让我担心的一件事是这个巨大的 buff 被声明但未被使用。它真的没有使用,还是为了清楚起见,您删除的某些代码是否需要它?我不得不说,当我看到这种东西并对其进行调查时,它被用来防止由于缓冲区溢出而导致的某种形式的未定义行为。

这段代码到处都是未经检查的 sprintfs,它只是假设输出缓冲区足够大,可以容纳数据,并且几乎是您看到的奇怪错误的温床。

于 2013-07-31T09:58:34.660 回答
2

我刚刚完成了一个长时间的调试会话,遇到了完全相同的问题(ARMv6 上的 libwebsockets 的连接请求损坏),所以这可能会让其他人免于 2 天的调试(包括学习如何使用 GDB)。

三个字:未对齐的内存访问

超过三个字:错误地,我的makefile没有将正确的编译器标志传递给gcc(尤其是-mno-unaligned-access),而ARMv6(或低于ARM11的任何东西)只会损坏未对齐的写入地址之前的1-3个内存字节.

编辑:显然我误读了文档,ARMv6(及更高版本)应该可以接受非对齐访问,但我的不是,所以 YMMV ...

于 2014-08-16T01:57:12.103 回答