我正在使用libwebsockets库(纯C)来编写应用程序(C ++ 11),即在ARMv7设备上运行。我正在使用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;
}
为简洁起见,我删除了一些代码和注释。好吧,我被困在这里。找不到可能破坏整个事情的东西。有没有人对正在发生的事情有任何想法?可能是那双新鲜的眼睛可以帮助我。
感谢。
答案 0 :(得分:4)
看起来有点像ARM版本,你的pkt
缓冲区可能不够大或者你的堆栈不够大。
令我担心的一件事是这个巨大的buff被声明并且没有被使用。它是否真的没有被使用,或者为了清楚起见,您删除了一些代码是否需要它?我必须说,当我看到这种事情并调查它时,它被用来防止因溢出缓冲区而导致某种形式的未定义行为。
这段代码充斥着未经检查的sprintfs,它只是假设输出缓冲区对于数据而言足够大,并且几乎就像你看到的奇怪错误的滋生地。
答案 1 :(得分:2)
我刚刚完成了一个长时间的调试会话,问题完全相同(ARMv6上的libwebsockets连接请求损坏),这样可以节省其他人2天的调试时间(包括学习如何使用GDB)。
三个字:未对齐的内存访问
超过三个字:错误地,我的makefile没有将正确的编译器标志传递给gcc(特别是-mno-unaligned-access),ARMv6(或ARM11以下的任何东西)只会损坏1-3个内存字节。未对齐的写地址。
编辑:显然我误读了文档,ARMv6(及以上版本)应该没有对齐访问,但我的不是,所以YMMV ......