aboutsummaryrefslogtreecommitdiff
path: root/src/mod_proxy65
diff options
context:
space:
mode:
authorJérôme Sautret <jerome.sautret@process-one.net>2007-06-27 10:01:39 +0000
committerJérôme Sautret <jerome.sautret@process-one.net>2007-06-27 10:01:39 +0000
commit9cd3a6db0742d7923a545bdc043fba5c0393ba33 (patch)
treeddbeeb737332340ff1c01dbf7dcc617b72e4d8a5 /src/mod_proxy65
parent* src/mod_muc/mod_muc_room.erl: Include <body/> in MUC invitations (diff)
Unsafe working version of http file transfer
SVN Revision: 798
Diffstat (limited to 'src/mod_proxy65')
-rw-r--r--src/mod_proxy65/Makefile.in6
-rw-r--r--src/mod_proxy65/TODO17
-rw-r--r--src/mod_proxy65/mod_proxy65.erl8
-rw-r--r--src/mod_proxy65/mod_proxy65.hrl33
-rw-r--r--src/mod_proxy65/mod_proxy65_http.erl156
-rw-r--r--src/mod_proxy65/mod_proxy65_lib.erl4
-rw-r--r--src/mod_proxy65/mod_proxy65_service.erl81
-rw-r--r--src/mod_proxy65/mod_proxy65_sm.erl34
-rw-r--r--src/mod_proxy65/mod_proxy65_stream.erl2
9 files changed, 300 insertions, 41 deletions
diff --git a/src/mod_proxy65/Makefile.in b/src/mod_proxy65/Makefile.in
index bb70ac5cb..0cd3e0639 100644
--- a/src/mod_proxy65/Makefile.in
+++ b/src/mod_proxy65/Makefile.in
@@ -1,12 +1,12 @@
# $Id$
-CC = @CC@
+CC = @CC@
CFLAGS = @CFLAGS@ @ERLANG_CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ @ERLANG_LIBS@
-SUBDIRS =
+SUBDIRS =
OUTDIR = ..
EFLAGS = -I .. -pz ..
@@ -20,6 +20,7 @@ OBJS = \
$(OUTDIR)/mod_proxy65_service.beam \
$(OUTDIR)/mod_proxy65_sm.beam \
$(OUTDIR)/mod_proxy65_stream.beam \
+ $(OUTDIR)/mod_proxy65_http.beam \
$(OUTDIR)/mod_proxy65_lib.beam
all: $(OBJS)
@@ -35,4 +36,3 @@ distclean: clean
TAGS:
etags *.erl
-
diff --git a/src/mod_proxy65/TODO b/src/mod_proxy65/TODO
new file mode 100644
index 000000000..7414ff8ca
--- /dev/null
+++ b/src/mod_proxy65/TODO
@@ -0,0 +1,17 @@
+
+
+HTTP transfer
+-------------
+
+* stream POST to GET in real time, whithout storing the file
+* handle acl
+* get base URL from ejabberd_http config
+* add parameters:
+ - store directory
+ - URL of upload
+* virtual host handling
+* check security stuffs:
+ - limit file size at upload time
+ - acl
+* transfer socks5 -> HTTP
+* transfer HTTP -> socks5 \ No newline at end of file
diff --git a/src/mod_proxy65/mod_proxy65.erl b/src/mod_proxy65/mod_proxy65.erl
index 65719241e..dfa5b89cb 100644
--- a/src/mod_proxy65/mod_proxy65.erl
+++ b/src/mod_proxy65/mod_proxy65.erl
@@ -50,8 +50,14 @@ init([Host, Opts]) ->
[gen_mod:get_module_proc(Host, ejabberd_mod_proxy65_sup),
mod_proxy65_stream]},
transient, infinity, supervisor, [ejabberd_tmp_sup]},
+ HttpStreamSupervisor =
+ {ejabberd_mod_proxy65_http_sup,
+ {ejabberd_tmp_sup, start_link,
+ [gen_mod:get_module_proc(Host, ejabberd_mod_proxy65_http_sup),
+ mod_proxy65_http]},
+ transient, infinity, supervisor, [ejabberd_tmp_sup]},
StreamManager =
{mod_proxy65_sm, {mod_proxy65_sm, start_link, [Host, Opts]},
transient, 5000, worker, [mod_proxy65_sm]},
{ok, {{one_for_one, 10, 1},
- [StreamManager, StreamSupervisor, Service]}}.
+ [StreamManager, StreamSupervisor, HttpStreamSupervisor, Service]}}.
diff --git a/src/mod_proxy65/mod_proxy65.hrl b/src/mod_proxy65/mod_proxy65.hrl
index eeab6804d..a26c04c4a 100644
--- a/src/mod_proxy65/mod_proxy65.hrl
+++ b/src/mod_proxy65/mod_proxy65.hrl
@@ -27,20 +27,37 @@
%% RFC 1928 replies
-define(SUCCESS, 0).
--define(ERR_GENERAL_FAILURE, 1).
--define(ERR_NOT_ALLOWED, 2).
--define(ERR_NETWORK_UNREACHABLE, 3).
--define(ERR_HOST_UNREACHABLE, 4).
--define(ERR_CONNECTION_REFUSED, 5).
--define(ERR_TTL_EXPIRED, 6).
--define(ERR_COMMAND_NOT_SUPPORTED, 7).
--define(ERR_ADDRESS_TYPE_NOT_SUPPORTED, 8).
+-define(SOCKS5_ERR_GENERAL_FAILURE, 1).
+-define(SOCKS5_ERR_NOT_ALLOWED, 2).
+-define(SOCKS5_ERR_NETWORK_UNREACHABLE, 3).
+-define(SOCKS5_ERR_HOST_UNREACHABLE, 4).
+-define(SOCKS5_ERR_CONNECTION_REFUSED, 5).
+-define(SOCKS5_ERR_TTL_EXPIRED, 6).
+-define(SOCKS5_ERR_COMMAND_NOT_SUPPORTED, 7).
+-define(SOCKS5_ERR_ADDRESS_TYPE_NOT_SUPPORTED, 8).
%% RFC 1928 defined timeout.
-define(SOCKS5_REPLY_TIMEOUT, 10000).
+-record(bytestream, {
+ sha1, %% SHA1 key
+ target, %% Target Pid
+ initiator, %% Initiator Pid
+ active = false, %% Activity flag
+ jid_i, %% Initiator's JID
+ jid_t, %% Target's JID (for http file transfert)
+ file, %% store status of file (for http file transfert)
+ myhost %% proxy's jid
+ }).
+
-record(s5_request, {
rsv = 0,
cmd,
sha1
}).
+
+% For http transfer
+-define(NS_HTTP_BYTESTREAMS, "http://oneteam.im/bs-proxy").
+-define(DEFAULT_HTTP_BASE_PATH, "/proxy").
+-define(DEFAULT_HTTP_UPLOAD_PATH, "/upload").
+-define(DEFAULT_STORE_PATH, "/tmp").
diff --git a/src/mod_proxy65/mod_proxy65_http.erl b/src/mod_proxy65/mod_proxy65_http.erl
new file mode 100644
index 000000000..f3d6abbea
--- /dev/null
+++ b/src/mod_proxy65/mod_proxy65_http.erl
@@ -0,0 +1,156 @@
+%%%----------------------------------------------------------------------
+%%% File : mod_proxy65_http
+%%% Author : Jérôme Sautret <jerome.sautret@process-one.net>
+%%% Purpose : HTTP bytestreams proxy for oneteam file transfert
+%%% Created : 28 may 2007
+%%% Id : $Id: mod_last.erl 370 2005-06-20 03:18:13Z alexey $
+%%%----------------------------------------------------------------------
+
+-module(mod_proxy65_http).
+-author('jerome.sautret@process-one.net').
+
+-behaviour(gen_mod).
+
+%% gen_mod callbacks.
+-export([
+ start/2,
+ stop/1
+ ]).
+%% mod_proxy65 api
+-export([
+ activate/2
+ ]).
+%% ejabberd_http callback.
+-export([
+ process/2
+ ]).
+
+-include("mod_proxy65.hrl").
+-include("../ejabberd.hrl").
+-include("../jlib.hrl").
+-include("../web/ejabberd_http.hrl").
+
+%%%----------------------------------------------------------------------
+%%% gen_mod Callbacks
+%%%----------------------------------------------------------------------
+
+start(_Host, _Opts) ->
+ ok.
+
+stop(_Host) ->
+ ok.
+
+activate({_IPid, _IJid}, {_TPid, _TJid}) ->
+ ok.
+
+%%%----------------------------------------------------------------------
+%%% ejabberd_http Callbacks
+%%%----------------------------------------------------------------------
+
+% Receive File
+% XXX TODO: limit file size
+process(["upload"], #request{method='POST',
+ content_type = "multipart/form-data;"++_Boundary = ContentType,
+ data=Data} = _Request) ->
+ io:format("POST~n", []),
+ DataParts = ejabberd_http:parse_data(Data, ContentType),
+ {SHA1, {Filename, FileContentType, FileContent}} = parse_upload_data(DataParts),
+ case mnesia:dirty_read(bytestream, SHA1) of
+ [#bytestream{jid_t = TargetJID, file = BaseURL, myhost = MyHost}] when is_list(BaseURL) ->
+ Path = store_file(Filename, FileContent),
+ F = fun() ->
+ mnesia:write(#bytestream{sha1 = SHA1,
+ file = {path, Path},
+ target = FileContentType})
+ end,
+ mnesia:transaction(F),
+ URL = BaseURL ++ "/" ++ filename:join(Path),
+ send_activated(TargetJID, MyHost, SHA1, URL),
+ Result = "ok",
+ ejabberd_web:make_xhtml([{xmlcdata, Result}]);
+ _Other ->
+ ?ERROR_MSG("Upload ~p not activated~n", [SHA1]),
+ ejabberd_web:error(bad_request)
+ end;
+
+process([_UID, _Filename] = Path, #request{method='GET'} = _Request) ->
+ io:format("GET~n~p~n", [Path]),
+ case mnesia:dirty_index_read(bytestream, {path, Path}, #bytestream.file) of
+ [#bytestream{sha1=SHA1, target=ContentType}|_Tail] ->
+ mnesia:dirty_delete({bytestream, SHA1}),
+ serve_file(Path, ContentType);
+ _ ->
+ ?ERROR_MSG("Bad request, GET ~p~n", [Path]),
+ ejabberd_web:error(bad_request)
+ end.
+
+
+% store the data transfered in a file and return the URL of the file
+store_file(Filename, FileContent) ->
+ HASH = sha:sha(FileContent),
+ % TODO store dir from a parameter
+ Path = ?DEFAULT_STORE_PATH ++ "/" ++ HASH ++ "/",
+ io:format("Path ~p~n", [Path]),
+ ok = filelib:ensure_dir(Path),
+ FilePath = Path ++ "/" ++ Filename,
+ %io:format("FilePath ~p~n~p", [FilePath, FileContent]),
+ ok = file:write_file(FilePath, list_to_binary(FileContent)),
+ [HASH, Filename].
+
+% send the <activated> connexion to the target.
+send_activated(TargetJID, MyJID, SHA1, URL) ->
+ IQ = #iq{type=set,
+ sub_el=[{xmlelement, "activated",
+ [{"xmlns", ?NS_HTTP_BYTESTREAMS}, {"sidhash", SHA1}, {"url", URL}], []}]},
+ ejabberd_router:route(jlib:string_to_jid(MyJID), TargetJID, jlib:iq_to_xml(IQ)).
+
+
+parse_upload_data(Data) ->
+ parse_upload_data(Data, {undefined, undefined, undefined}).
+parse_upload_data([], Result) ->
+ Result;
+parse_upload_data([#http_data{content_disposition="form-data",
+ content_type=ContentType, args=Args, data=Data} | Tail],
+ Result) ->
+ Result2 = case lists:keysearch("name", 1, Args) of
+ {value, {"name", "SIDHASH"}} ->
+ {remove_cr(Data), element(2, Result)};
+ {value, {"name", "FILE"}} ->
+ case lists:keysearch("filename", 1, Args) of
+ {value, {"filename", Filename}} ->
+ {element(1, Result), {Filename, ContentType, remove_cr(Data)}}
+ end;
+ _ ->
+ Result
+ end,
+ parse_upload_data(Tail, Result2).
+
+
+% remove last trailling carriage return
+remove_cr(String) ->
+ lists:reverse(remove_leading_cr(lists:reverse(String))).
+% remove fisrt leading inversed carriage return
+remove_leading_cr([$\n, $\r|String]) ->
+ String;
+remove_leading_cr(String) ->
+ String.
+
+
+serve_file(Path, ContentType) ->
+ FileName = filename:join([?DEFAULT_STORE_PATH | Path]),
+ case file:read_file(FileName) of
+ {ok, FileContents} ->
+ ?DEBUG("Delivering content.", []),
+ {200,
+ [{"Server", "ejabberd"},
+ {"Content-type", ContentType},
+ {"Content-disposition", "attachment; filename="++filename:basename(FileName)}],
+ FileContents};
+ {error, Error} ->
+ ?DEBUG("Delivering error: ~p", [Error]),
+ case Error of
+ eacces -> {403, [], "Forbidden"};
+ enoent -> {404, [], "Not found"};
+ _Else -> {500, [], atom_to_list(Error)}
+ end
+ end.
diff --git a/src/mod_proxy65/mod_proxy65_lib.erl b/src/mod_proxy65/mod_proxy65_lib.erl
index 09ee6b981..02d4ecbe8 100644
--- a/src/mod_proxy65/mod_proxy65_lib.erl
+++ b/src/mod_proxy65/mod_proxy65_lib.erl
@@ -53,7 +53,7 @@ make_init_reply(Method) ->
[?VERSION_5, Method].
make_auth_reply(true) -> [1, ?SUCCESS];
-make_auth_reply(false) -> [1, ?ERR_NOT_ALLOWED].
+make_auth_reply(false) -> [1, ?SOCKS5_ERR_NOT_ALLOWED].
%% WARNING: According to SOCKS5 RFC, this reply is _incorrect_, but
%% Psi writes junk to the beginning of the file on correct reply.
@@ -63,7 +63,7 @@ make_reply() ->
[?VERSION_5, ?SUCCESS, 0, 0, 0, 0].
make_error_reply(Request) ->
- make_error_reply(Request, ?ERR_NOT_ALLOWED).
+ make_error_reply(Request, ?SOCKS5_ERR_NOT_ALLOWED).
make_error_reply(#s5_request{rsv = RSV, sha1 = SHA1}, Reason) ->
[?VERSION_5, Reason, RSV, ?ATYP_DOMAINNAME, length(SHA1), SHA1, 0,0].
diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl
index f9f3bf12d..c590f22f7 100644
--- a/src/mod_proxy65/mod_proxy65_service.erl
+++ b/src/mod_proxy65/mod_proxy65_service.erl
@@ -23,6 +23,7 @@
%% API.
-export([start_link/2]).
+-include("mod_proxy65.hrl").
-include("../ejabberd.hrl").
-include("../jlib.hrl").
@@ -34,6 +35,8 @@
name,
stream_addr,
port,
+ http_port,
+ http_base_path,
acl
}).
@@ -84,12 +87,14 @@ handle_info(_Info, State) ->
%%%------------------------
%% disco#info request
-process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ, #state{name=Name}) ->
+process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO} = IQ, #state{name=Name, http_port=HTTP_Port}) ->
+ io:format("~p~n", [IQ]),
IQ#iq{type = result, sub_el =
- [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], iq_disco_info(Lang, Name)}]};
+ [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], iq_disco_info(Name, HTTP_Port)}]};
%% disco#items request
process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) ->
+ io:format("~p~n", [IQ]),
IQ#iq{type = result, sub_el =
[{xmlelement, "query", [{"xmlns", ?NS_DISCO_ITEMS}], []}]};
@@ -101,6 +106,7 @@ process_iq(_, #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, _) ->
%% bytestreams info request
process_iq(JID, #iq{type = get, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ,
#state{acl = ACL, stream_addr = StreamAddr, serverhost = ServerHost}) ->
+ io:format("~p~n", [IQ]),
case acl:match_rule(ServerHost, ACL, JID) of
allow ->
StreamHostEl = [{xmlelement, "streamhost", StreamAddr, []}],
@@ -110,9 +116,39 @@ process_iq(JID, #iq{type = get, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ,
IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]}
end;
+
+%% bytestream target fake connection (for later http connection)
+process_iq(TargetJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_HTTP_BYTESTREAMS} = IQ,
+ #state{acl = _ACL, myhost = MyHost,
+ http_port=HTTP_Port, http_base_path=HTTP_Base_Path}) ->
+ % XXX TODO: acl
+ SID = xml:get_tag_attr_s("sid", SubEl),
+ case catch jlib:string_to_jid(xml:get_tag_attr_s("jid", SubEl)) of
+ InitiatorJID when is_record(InitiatorJID, jid), SID /= "",
+ length(SID) =< 128, TargetJID /= InitiatorJID ->
+ Target = jlib:jid_to_string(jlib:jid_tolower(TargetJID)),
+ Initiator = jlib:jid_to_string(jlib:jid_tolower(InitiatorJID)),
+ SHA1 = sha:sha(SID ++ Initiator ++ Target),
+ URL = "http://" ++ MyHost ++ ":"++HTTP_Port++ HTTP_Base_Path,
+ case catch mod_proxy65_sm:register_stream(SHA1, TargetJID, URL, MyHost, self()) of
+ {atomic, ok} ->
+ IQ#iq{type = result, sub_el =
+ [{xmlelement, "connected",
+ [{"xmlns", ?NS_HTTP_BYTESTREAMS}, {"jid", MyHost}], []}]};
+ _Reason ->
+ ?ERROR_MSG("process IQ set ~p:~n~p~n", [?NS_HTTP_BYTESTREAMS, _Reason]),
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
+ end;
+ _Reason ->
+ ?ERROR_MSG("process IQ set ~p:~n~p~n", [?NS_HTTP_BYTESTREAMS, _Reason]),
+ IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
+ end;
+
+
%% bytestream activation request
process_iq(InitiatorJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ,
- #state{acl = ACL, serverhost = ServerHost}) ->
+ #state{acl = ACL, serverhost = ServerHost, myhost = MyHost,
+ http_port=HTTP_Port, http_base_path=HTTP_Base_Path}) ->
case acl:match_rule(ServerHost, ACL, InitiatorJID) of
allow ->
ActivateEl = xml:get_path_s(SubEl, [{elem, "activate"}]),
@@ -123,9 +159,21 @@ process_iq(InitiatorJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS
Target = jlib:jid_to_string(jlib:jid_tolower(TargetJID)),
Initiator = jlib:jid_to_string(jlib:jid_tolower(InitiatorJID)),
SHA1 = sha:sha(SID ++ Initiator ++ Target),
- case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, TargetJID, ServerHost) of
+ {Module, Activated} =
+ case xml:get_path_s(SubEl, [{elem, "x"}]) of
+ {xmlelement, "x", [{"xmlns", ?NS_HTTP_BYTESTREAMS}], _} ->
+ {mod_proxy65_http,
+ [{xmlelement, "activated",
+ [{"xmlns", ?NS_HTTP_BYTESTREAMS},
+ {"url", "http://" ++ MyHost ++ ":"++HTTP_Port++
+ HTTP_Base_Path ++ ?DEFAULT_HTTP_UPLOAD_PATH}], []}]};
+ _ ->
+ {mod_proxy65_sm, []}
+ end,
+ case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, TargetJID,
+ ServerHost, Module) of
ok ->
- IQ#iq{type = result, sub_el = []};
+ IQ#iq{type = result, sub_el = Activated};
false ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]};
limit ->
@@ -135,7 +183,8 @@ process_iq(InitiatorJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS
_ ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]}
end;
- _ ->
+ _Reason ->
+ ?ERROR_MSG("process IQ set ~p:~n~p~n", [?NS_BYTESTREAMS, _Reason]),
IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]}
end;
deny ->
@@ -155,15 +204,21 @@ process_iq(_, _, _) ->
%%%-------------------------
-define(FEATURE(Feat), {xmlelement,"feature",[{"var", Feat}],[]}).
-iq_disco_info(Lang, Name) ->
+iq_disco_info(Name, HTTP_Port) ->
+ HTTP_Bytestreams = case HTTP_Port of
+ "0" ->
+ [];
+ _ ->
+ [?FEATURE(?NS_HTTP_BYTESTREAMS)]
+ end,
[{xmlelement, "identity",
[{"category", "proxy"},
{"type", "bytestreams"},
- {"name", translate:translate(Lang, Name)}], []},
+ {"name", Name}], []},
?FEATURE(?NS_DISCO_INFO),
?FEATURE(?NS_DISCO_ITEMS),
?FEATURE(?NS_VCARD),
- ?FEATURE(?NS_BYTESTREAMS)].
+ ?FEATURE(?NS_BYTESTREAMS)] ++ HTTP_Bytestreams.
iq_vcard(Lang) ->
[{xmlelement, "FN", [],
@@ -177,6 +232,8 @@ iq_vcard(Lang) ->
parse_options(ServerHost, Opts) ->
MyHost = gen_mod:get_opt(host, Opts, "proxy." ++ ServerHost),
Port = gen_mod:get_opt(port, Opts, 7777),
+ HTTP_Port = integer_to_list(gen_mod:get_opt(http_port, Opts, 0)),
+ HTTP_Base_Path = gen_mod:get_opt(http_base_path, Opts, ?DEFAULT_HTTP_BASE_PATH),
ACL = gen_mod:get_opt(access, Opts, all),
Name = gen_mod:get_opt(name, Opts, "SOCKS5 Bytestreams"),
IP = case gen_mod:get_opt(ip, Opts, none) of
@@ -189,7 +246,9 @@ parse_options(ServerHost, Opts) ->
serverhost = ServerHost,
name = Name,
port = Port,
- stream_addr = StreamAddr,
+ http_port = HTTP_Port,
+ http_base_path = HTTP_Base_Path,
+ stream_addr = StreamAddr,
acl = ACL}}.
%% Return the IP of the proxy host, or if not found, the ip of the xmpp domain
@@ -201,4 +260,4 @@ get_proxy_or_domainip(ServerHost, MyHost) ->
{ok, Addr} -> Addr;
{error, _} -> {127,0,0,1}
end
- end. \ No newline at end of file
+ end.
diff --git a/src/mod_proxy65/mod_proxy65_sm.erl b/src/mod_proxy65/mod_proxy65_sm.erl
index 7ddfd2c89..32e89fac4 100644
--- a/src/mod_proxy65/mod_proxy65_sm.erl
+++ b/src/mod_proxy65/mod_proxy65_sm.erl
@@ -24,18 +24,14 @@
-export([
start_link/2,
register_stream/1,
+ register_stream/5,
unregister_stream/1,
- activate_stream/4
+ activate_stream/5
]).
+-include("mod_proxy65.hrl").
+
-record(state, {max_connections}).
--record(bytestream, {
- sha1, %% SHA1 key
- target, %% Target Pid
- initiator, %% Initiator Pid
- active = false, %% Activity flag
- jid_i %% Initiator's JID
- }).
-define(PROCNAME, ejabberd_mod_proxy65_sm).
@@ -55,6 +51,7 @@ start_link(Host, Opts) ->
init([Opts]) ->
mnesia:create_table(bytestream, [{ram_copies, [node()]},
{attributes, record_info(fields, bytestream)}]),
+ mnesia:add_table_index(bytestream, file),
mnesia:add_table_copy(bytestream, node(), ram_copies),
MaxConnections = gen_mod:get_opt(max_connections, Opts, infinity),
{ok, #state{max_connections=MaxConnections}}.
@@ -67,7 +64,7 @@ handle_call({activate, SHA1, IJid}, _From, State) ->
F = fun() ->
case mnesia:read(bytestream, SHA1, write) of
[#bytestream{target = TPid, initiator = IPid} = ByteStream]
- when is_pid(TPid), is_pid(IPid) ->
+ when is_pid(TPid), is_pid(IPid) ->
ActiveFlag = ByteStream#bytestream.active,
if
ActiveFlag == false ->
@@ -109,13 +106,20 @@ handle_call(_Request, _From, State) ->
%%% transaction abort
%%% SHA1 = string()
%%%---------------------------------------------------
-register_stream(SHA1) when is_list(SHA1) ->
+register_stream(SHA1) ->
+ register_stream(SHA1, undefined, undefined, undefined, undefined).
+register_stream(SHA1, JID, URL, MyHost, InitiatorPID) when is_list(SHA1) ->
+ % PIDs are not used for http, we set it for compatibilty with plain socks5
StreamPid = self(),
F = fun() ->
case mnesia:read(bytestream, SHA1, write) of
[] ->
mnesia:write(#bytestream{sha1 = SHA1,
- target = StreamPid});
+ target = StreamPid,
+ initiator = InitiatorPID,
+ jid_t = JID,
+ file = URL,
+ myhost = MyHost});
[#bytestream{target = Pid,
initiator = undefined} = ByteStream]
when is_pid(Pid), Pid /= StreamPid ->
@@ -145,14 +149,14 @@ unregister_stream(SHA1) when is_list(SHA1) ->
%%% IJid = TJid = jid()
%%% Host = string()
%%%--------------------------------------------------------
-activate_stream(SHA1, IJid, TJid, Host) when is_list(SHA1) ->
+activate_stream(SHA1, IJid, TJid, Host, Module) when is_list(SHA1) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
case catch gen_server:call(Proc, {activate, SHA1, IJid}) of
{atomic, {ok, IPid, TPid}} ->
- mod_proxy65_stream:activate({IPid, IJid}, {TPid, TJid});
+ Module:activate({IPid, IJid}, {TPid, TJid});
{atomic, {limit, IPid, TPid}} ->
- mod_proxy65_stream:stop(IPid),
- mod_proxy65_stream:stop(TPid),
+ Module:stop(IPid),
+ Module:stop(TPid),
limit;
{atomic, conflict} ->
conflict;
diff --git a/src/mod_proxy65/mod_proxy65_stream.erl b/src/mod_proxy65/mod_proxy65_stream.erl
index 1a1503384..88ad1eb29 100644
--- a/src/mod_proxy65/mod_proxy65_stream.erl
+++ b/src/mod_proxy65/mod_proxy65_stream.erl
@@ -163,7 +163,7 @@ wait_for_request(Packet, #state{socket=Socket} = StateData) ->
{stop, normal, StateData}
end;
#s5_request{cmd=udp} ->
- Err = mod_proxy65_lib:make_error_reply(Request, ?ERR_COMMAND_NOT_SUPPORTED),
+ Err = mod_proxy65_lib:make_error_reply(Request, ?SOCKS5_ERR_COMMAND_NOT_SUPPORTED),
gen_tcp:send(Socket, Err),
{stop, normal, StateData};
_ ->