./ct_report/coverage/ejabberd_zlib.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : ejabberd_zlib.erl
3 %%% Author : Alexey Shchepin <alexey@process-one.net>
4 %%% Purpose : Interface to zlib
5 %%% Created : 19 Jan 2006 by Alexey Shchepin <alexey@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25
26 -module(ejabberd_zlib).
27 -author('alexey@process-one.net').
28 -xep([{xep, 138}, {version, "2.0"}]).
29 -export([enable_zlib/3, disable_zlib/1,
30 send/2,
31 recv_data/2,
32 setopts/2,
33 sockname/1, peername/1,
34 get_sockmod/1,
35 controlling_process/2,
36 close/1]).
37
38 -ignore_xref([close/1, controlling_process/2, disable_zlib/1, peername/1, send/2,
39 setopts/2, sockname/1]).
40
41 -define(DEFLATE, 1).
42 -define(INFLATE, 2).
43
44 -record(zlibsock, {sockmod, socket, zlibport, inflate_size_limit = 0}).
45 -type zlibsock() :: #zlibsock{}.
46
47 -spec enable_zlib(ejabberd:sockmod(), zlibsock(), integer()) -> {ok, zlibsock()}.
48 enable_zlib(SockMod, Socket, InflateSizeLimit) ->
49 10 case erl_ddll:load_driver(ejabberd:get_so_path(), ejabberd_zlib_drv) of
50 10 ok -> ok;
51
:-(
{error, already_loaded} -> ok;
52 {error, OtherError} ->
53
:-(
erlang:error({cannot_load_ejabberd_zlib_drv, erl_ddll:format_error(OtherError)})
54 end,
55 10 Port = open_port({spawn_driver, "ejabberd_zlib_drv"}, [binary]),
56 10 {ok, #zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port,
57 inflate_size_limit = InflateSizeLimit}}.
58
59 -spec disable_zlib(zlibsock()) -> {ejabberd:sockmod(), inet:socket()}.
60 disable_zlib(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
61
:-(
port_close(Port),
62
:-(
{SockMod, Socket}.
63
64 -spec recv_data(zlibsock(), Packet :: string()|binary()) -> {ok, _} | {error, _}.
65 recv_data(#zlibsock{sockmod = SockMod, socket = Socket} = ZlibSock, Packet) ->
66 39 case SockMod of
67 gen_tcp ->
68
:-(
recv_data2(ZlibSock, Packet);
69 _ ->
70 39 case SockMod:recv_data(Socket, Packet) of
71 {ok, Packet2} ->
72 39 recv_data2(ZlibSock, Packet2);
73 Error ->
74
:-(
Error
75 end
76 end.
77
78 recv_data2(ZlibSock, Packet) ->
79 39 case catch recv_data1(ZlibSock, Packet) of
80 {'EXIT', Reason} ->
81
:-(
{error, Reason};
82 Res ->
83 39 Res
84 end.
85
86 -spec recv_data1(zlibsock(), iolist()) -> {'error', atom()} | {'ok', binary()}.
87 recv_data1(#zlibsock{zlibport = Port, inflate_size_limit = SizeLimit} = _ZlibSock, Packet) ->
88 39 case port_control(Port, SizeLimit bsl 2 + ?INFLATE, Packet) of
89 <<0, In/binary>> ->
90 39 {ok, In};
91 <<1, Error/binary>> ->
92
:-(
{error, erlang:binary_to_existing_atom(Error, utf8)}
93 end.
94
95 -spec send(zlibsock(), iolist()) -> ok | {error, atom()}.
96 send(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port},
97 Packet) ->
98 34 case port_control(Port, ?DEFLATE, Packet) of
99 <<0, Out/binary>> ->
100 34 mongoose_metrics:update(global, [data, xmpp, sent, compressed_size], size(Out)),
101 34 SockMod:send(Socket, Out);
102 <<1, Error/binary>> ->
103
:-(
{error, erlang:binary_to_existing_atom(Error, utf8)};
104 _ ->
105
:-(
{error, deflate_error}
106 end.
107
108
109 setopts(#zlibsock{sockmod = SockMod, socket = Socket}, Opts) ->
110 39 case SockMod of
111 gen_tcp ->
112
:-(
inet:setopts(Socket, Opts);
113 _ ->
114 39 SockMod:setopts(Socket, Opts)
115 end.
116
117 sockname(#zlibsock{sockmod = SockMod, socket = Socket}) ->
118
:-(
case SockMod of
119 gen_tcp ->
120
:-(
inet:sockname(Socket);
121 _ ->
122
:-(
SockMod:sockname(Socket)
123 end.
124
125 get_sockmod(#zlibsock{sockmod = SockMod}) ->
126 8 SockMod.
127
128 peername(#zlibsock{sockmod = SockMod, socket = Socket}) ->
129 39 case SockMod of
130 gen_tcp ->
131
:-(
inet:peername(Socket);
132 _ ->
133 39 SockMod:peername(Socket)
134 end.
135
136 controlling_process(#zlibsock{sockmod = SockMod, socket = Socket}, Pid) ->
137
:-(
SockMod:controlling_process(Socket, Pid).
138
139 close(#zlibsock{sockmod = SockMod, socket = Socket, zlibport = Port}) ->
140 10 SockMod:close(Socket),
141 10 port_close(Port).
Line Hits Source