]> granicus.if.org Git - ejabberd/commitdiff
Don't ignore Length parameter in tls:recv
authorPaweł Chmielowski <pchmielowski@process-one.net>
Fri, 6 Apr 2012 09:53:21 +0000 (11:53 +0200)
committerPaweł Chmielowski <pchmielowski@process-one.net>
Fri, 6 Apr 2012 09:53:21 +0000 (11:53 +0200)
src/tls/tls.erl
src/tls/tls_drv.c

index 010d5b5223c4aa5f36fff6afcfd56a071d6b3761..84a0d4737eacbcdf595e202a167363ed169e3dab 100644 (file)
@@ -32,7 +32,7 @@
 -export([start/0, start_link/0,
         tcp_to_tls/2, tls_to_tcp/1,
         send/2,
-        recv/2, recv/3, recv_data/2,
+        recv/2, recv/3,
         setopts/2,
         sockname/1, peername/1,
         controlling_process/2,
@@ -160,29 +160,34 @@ tls_to_tcp(#tlssock{tcpsock = TCPSocket, tlsport = Port}) ->
 
 recv(Socket, Length) ->
     recv(Socket, Length, infinity).
-recv(#tlssock{tcpsock = TCPSocket} = TLSSock,
-     _Length, Timeout) ->
-    %% The Length argument cannot be used for gen_tcp:recv/3, because the
-    %% compressed size does not equal the desired uncompressed one.
-    case gen_tcp:recv(TCPSocket, 0, Timeout) of
-       {ok, Packet} ->
-           recv_data(TLSSock, Packet);
-       {error, _Reason} = Error ->
-           Error
+recv(#tlssock{tcpsock = TCPSocket, tlsport = Port} = TLSSock,
+     Length, Timeout) ->
+    case port_control(Port, ?GET_DECRYPTED_INPUT, <<Length:32>>) of
+        <<0>> ->
+            case gen_tcp:recv(TCPSocket, 0, Timeout) of
+                {ok, Packet} ->
+                    recv_data(TLSSock, Packet, Length);
+                {error, _Reason} = Error ->
+                    Error
+            end;
+        <<0, In/binary>> ->
+            {ok, In};
+        <<1, Error/binary>> ->
+            {error, binary_to_list(Error)}
     end.
 
-recv_data(TLSSock, Packet) ->
-    case catch recv_data1(TLSSock, Packet) of
+recv_data(TLSSock, Packet, Length) ->
+    case catch recv_data1(TLSSock, Packet, Length) of
        {'EXIT', Reason} ->
            {error, Reason};
        Res ->
            Res
     end.
 
-recv_data1(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet) ->
+recv_data1(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet, Length) ->
     case port_control(Port, ?SET_ENCRYPTED_INPUT, Packet) of
        <<0>> ->
-           case port_control(Port, ?GET_DECRYPTED_INPUT, []) of
+           case port_control(Port, ?GET_DECRYPTED_INPUT, <<Length:32>>) of
                <<0, In/binary>> ->
                    case port_control(Port, ?GET_ENCRYPTED_OUTPUT, []) of
                        <<0, Out/binary>> ->
index e680cde65039a854b5166285119843ea456a2a7e..d0774684cc7160800912903fb6bbb572fe07137e 100644 (file)
@@ -432,13 +432,22 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle,
                          "SSL_do_handshake failed");
         }
         if (SSL_is_init_finished(d->ssl)) {
+           size_t req_size = 0;
+           if (len == 4)
+           {
+              req_size =
+                 (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+           }
            size = BUF_SIZE + 1;
            rlen = 1;
            b = driver_alloc_binary(size);
            b->orig_bytes[0] = 0;
 
-           while ((res = SSL_read(d->ssl,
-                                  b->orig_bytes + rlen, BUF_SIZE)) > 0)
+           while ((req_size == 0 || rlen < req_size + 1) &&
+                  (res = SSL_read(d->ssl,
+                                  b->orig_bytes + rlen,
+                                  (req_size == 0 || req_size + 1 >= size) ?
+                                  size - rlen : req_size + 1 - rlen)) > 0)
            {
               //printf("%d bytes of decrypted data read from state machine\r\n",res);
               rlen += res;