0%

ios15 修复websocket ssl连接失败的问题

玩家反馈,ios15无法登录游戏,android和ios其他版本没有问题

分析发现,ios15将原本是一条数据内容分成三份发送

1
2
3
4
5
6
7
8
## 本来这应该是一条数据的
## FIN - Payload len
websocket:request:53 [mfa:proc_lib:init_p/5] parse_frames:{ssl,hybi,<<130,131>>,{ssl,{sslsocket,{gen_tcp,#Port<0.17851>,tls_connection,<0.533.0>},<0.6628.124>}}}
## Masking-key
websocket:request:53 [mfa:proc_lib:init_p/5] parse_frames:{ssl,hybi,<<153,193,1,85>>,{ssl,{sslsocket,{gen_tcp,#Port<0.17851>,tls_connection,<0.533.0>},<0.6628.124>}}}
## Payload Data
websocket:request:53 [mfa:proc_lib:init_p/5] parse_frames:{ssl,hybi,<<190,209,15>>,{ssl,{sslsocket,{gen_tcp,#Port<0.17851>,tls_connection,<0.533.0>},<0.6628.124>}}}

对应的协议格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/63) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+

对于使用mochiweb的websocket只要增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
parse_hybi_frames(_, <<>>, Acc) ->
lists:reverse(Acc);

......此处省略N行

%% 数据不完整,继续收
parse_hybi_frames(Socket, PartFrame, Acc) ->
%% io:format("3 ~p ~n",[{_Fin,_Rsv,_Opcode,_Mask,_PayloadLen,_MaskKey}]),
ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, 0}, {active, once}])),
receive
{tcp_closed, _} ->
mochiweb_socket:close(Socket),
exit(normal);
{ssl_closed, _} ->
mochiweb_socket:close(Socket),
exit(normal);
{tcp_error, _, _} ->
mochiweb_socket:close(Socket),
exit(normal);
{Proto, _, Continuation} when Proto =:= tcp orelse Proto =:= ssl ->
parse_hybi_frames(Socket, <<PartFrame/binary, Continuation/binary>>,
Acc);
_ ->
mochiweb_socket:close(Socket),
exit(normal)
after
5000 ->
mochiweb_socket:close(Socket),
exit(normal)
end.

其他语言也差不多的逻辑,数据不全就继续等待数据了

参考文档

  1. https://datatracker.ietf.org/doc/html/draft-ietf-hybi-thewebsocketprotocol-10