Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mtproto_proxy
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
mtproto_proxy
Commits
977109d0
Unverified
Commit
977109d0
authored
May 09, 2019
by
Сергей Прохоров
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add special helpers for live config_change
parent
f1070dfe
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
186 additions
and
14 deletions
+186
-14
mtp_config.erl
src/mtp_config.erl
+17
-5
mtp_dc_pool.erl
src/mtp_dc_pool.erl
+11
-2
mtp_down_conn.erl
src/mtp_down_conn.erl
+20
-3
mtproto_proxy_app.erl
src/mtproto_proxy_app.erl
+81
-2
single_dc_SUITE.erl
test/single_dc_SUITE.erl
+57
-2
No files found.
src/mtp_config.erl
View file @
977109d0
...
...
@@ -20,7 +20,8 @@
get_netloc
/
1
,
get_netloc_safe
/
1
,
get_secret
/
0
,
status
/
0
]).
status
/
0
,
update
/
0
]).
%% gen_server callbacks
-
export
([
init
/
1
,
handle_call
/
3
,
handle_cast
/
2
,
handle_info
/
2
,
...
...
@@ -103,16 +104,21 @@ get_secret() ->
[{_,
Key
}]
=
ets
:
lookup
(
?
TAB
,
key
),
Key
.
-
spec
status
()
->
[
mtp_dc_pool
:
status
()].
status
()
->
[{
?
IDS_KEY
,
L
}]
=
ets
:
lookup
(
?
TAB
,
?
IDS_KEY
),
lists
:
map
(
fun
(
DcId
)
->
{
ok
,
Pid
}
=
get_downstream_pool
(
DcId
),
DcPoolStatus
=
mtp_dc_pool
:
status
(
Pid
),
DcPoolStatus
#
{
dc_id
=>
DcId
}
mtp_dc_pool
:
status
(
Pid
)
end
,
L
).
-
spec
update
()
->
ok
.
update
()
->
gen_server
:
cast
(
?
MODULE
,
update
).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
...
...
@@ -133,8 +139,14 @@ init([]) ->
handle_call
(_
Request
,
_
From
,
State
)
->
Reply
=
ok
,
{
reply
,
Reply
,
State
}.
handle_cast
(_
Request
,
State
)
->
{
noreply
,
State
}.
handle_cast
(
update
,
#state
{
timer
=
Timer
}
=
State
)
->
update
(
State
,
soft
),
lager
:
info
(
"Config updated"
),
Timer1
=
gen_timeout
:
bump
(
gen_timeout
:
reset
(
Timer
)),
{
noreply
,
State
#state
{
timer
=
Timer1
}}.
handle_info
(
timeout
,
#state
{
timer
=
Timer
}
=
State
)
->
case
gen_timeout
:
is_expired
(
Timer
)
of
true
->
...
...
src/mtp_dc_pool.erl
View file @
977109d0
...
...
@@ -26,6 +26,7 @@
%% gen_server callbacks
-
export
([
init
/
1
,
handle_call
/
3
,
handle_cast
/
2
,
handle_info
/
2
,
terminate
/
2
,
code_change
/
3
]).
-
export_type
([
status
/
0
]).
-
define
(
SERVER
,
?
MODULE
).
-
define
(
APP
,
mtproto_proxy
).
...
...
@@ -34,6 +35,11 @@
-
type
upstream
()
::
mtp_handler
:
handle
().
-
type
downstream
()
::
mtp_down_conn
:
handle
().
-
type
ds_store
()
::
psq
:
psq
().
-
type
status
()
::
#
{
n_downstreams
:
=
non_neg_integer
(),
n_upstreams
:
=
non_neg_integer
(),
min
:
=
non_neg_integer
(),
max
:
=
non_neg_integer
(),
dc_id
:
=
mtp_config
:
dc_id
()}.
-
record
(
state
,
{
dc_id
::
mtp_config
:
dc_id
(),
...
...
@@ -76,6 +82,7 @@ add_connection(Pool) ->
ack_connected
(
Pool
,
Downstream
)
->
gen_server
:
cast
(
Pool
,
{
connected
,
Downstream
}).
-
spec
status
(
pid
())
->
status
().
status
(
Pool
)
->
gen_server
:
call
(
Pool
,
status
).
...
...
@@ -97,7 +104,8 @@ handle_call(add_connection, _From, State) ->
State1
=
connect
(
State
),
{
reply
,
ok
,
State1
};
handle_call
(
status
,
_
From
,
#state
{
downstreams
=
Ds
,
upstreams
=
Us
}
=
State
)
->
upstreams
=
Us
,
dc_id
=
DcId
}
=
State
)
->
{
NDowns
,
NUps
,
Min
,
Max
}
=
ds_fold
(
fun
(_
Pid
,
N
,
{
NDowns
,
NUps
,
Min
,
Max
})
->
...
...
@@ -106,7 +114,8 @@ handle_call(status, _From, #state{downstreams = Ds,
{
reply
,
#
{
n_downstreams
=>
NDowns
,
n_upstreams
=>
NUps
,
min
=>
Min
,
max
=>
Max
},
State
}.
max
=>
Max
,
dc_id
=>
DcId
},
State
}.
handle_cast
({
return
,
Upstream
},
State
)
->
{
noreply
,
handle_return
(
Upstream
,
State
)};
...
...
src/mtp_down_conn.erl
View file @
977109d0
...
...
@@ -16,7 +16,8 @@
upstream_closed
/
2
,
shutdown
/
1
,
send
/
2
,
ack
/
3
]).
ack
/
3
,
set_config
/
3
]).
-
ifdef
(
TEST
).
-
export
([
get_middle_key
/
1
]).
-
endif
.
...
...
@@ -93,6 +94,10 @@ send(Conn, Data) ->
ack
(
Conn
,
Count
,
Size
)
->
gen_server
:
cast
(
Conn
,
{
ack
,
self
(),
Count
,
Size
}).
-
spec
set_config
(
handle
(),
atom
(),
any
())
->
{
ok
,
OldValue
::
any
()}
|
ignored
.
set_config
(
Conn
,
Option
,
Value
)
->
gen_server
:
call
(
Conn
,
{
set_config
,
Option
,
Value
}).
init
([
Pool
,
DcId
])
->
self
()
!
do_connect
,
{
ok
,
#state
{
pool
=
Pool
,
...
...
@@ -100,7 +105,20 @@ init([Pool, DcId]) ->
handle_call
({
send
,
Data
},
{
Upstream
,
_},
State
)
->
{
Res
,
State1
}
=
handle_send
(
Data
,
Upstream
,
State
),
{
reply
,
Res
,
State1
}.
{
reply
,
Res
,
State1
};
handle_call
({
set_config
,
Name
,
Value
},
_
From
,
State
)
->
Result
=
case
Name
of
downstream_socket_buffer_size
when
is_integer
(
Value
),
Value
>=
512
->
{
ok
,
[{
buffer
,
OldSize
}]}
=
inet
:
getopts
(
State
#state.sock
,
[
buffer
]),
ok
=
inet
:
setopts
(
State
#state.sock
,
[{
buffer
,
Value
}]),
{
ok
,
OldSize
};
_
->
lager
:
warning
(
"set_config
~p
=
~p
ignored"
,
[
Name
,
Value
]),
ignored
end
,
{
reply
,
Result
,
State
}.
handle_cast
({
ack
,
Upstream
,
Count
,
Size
},
State
)
->
{
noreply
,
handle_ack
(
Upstream
,
Count
,
Size
,
State
)};
...
...
@@ -112,7 +130,6 @@ handle_cast({upstream_closed, Upstream}, State) ->
handle_cast
(
shutdown
,
State
)
->
{
stop
,
shutdown
,
State
}.
handle_info
({
tcp
,
Sock
,
Data
},
#state
{
sock
=
Sock
,
dc_id
=
DcId
}
=
S
)
->
mtp_metric
:
count_inc
([
?
APP
,
received
,
downstream
,
bytes
],
byte_size
(
Data
),
#
{
labels
=>
[
DcId
]}),
mtp_metric
:
histogram_observe
([
?
APP
,
tracker_packet_size
,
bytes
],
byte_size
(
Data
),
#
{
labels
=>
[
downstream
]}),
...
...
src/mtproto_proxy_app.erl
View file @
977109d0
...
...
@@ -8,9 +8,16 @@
-
behaviour
(
application
).
%% Application callbacks
-
export
([
start
/
2
,
prep_stop
/
1
,
stop
/
1
,
start_proxy
/
1
]).
-
export
([
start
/
2
,
prep_stop
/
1
,
stop
/
1
,
config_change
/
3
]).
-
export
([
mtp_listeners
/
0
,
running_ports
/
0
,
start_proxy
/
1
]).
-
define
(
APP
,
mtproto_proxy
).
-
type
proxy_port
()
::
#
{
name
:
=
any
(),
port
:
=
inet
:
port_number
(),
secret
:
=
binary
(),
tag
:
=
binary
(),
listen_ip
=>
inet
:
ip4_addr
()}.
%%====================================================================
%% API
%%====================================================================
...
...
@@ -22,17 +29,54 @@ start(_StartType, _StartArgs) ->
[
start_proxy
(
Where
)
||
Where
<-
application
:
get_env
(
?
APP
,
ports
,
[])],
Res
.
%%--------------------------------------------------------------------
prep_stop
(
State
)
->
[
stop_proxy
(
Where
)
||
Where
<-
application
:
get_env
(
?
APP
,
ports
,
[])],
State
.
stop
(_
State
)
->
ok
.
config_change
(
Changed
,
New
,
Removed
)
->
%% app's env is already updated when this callback is called
ok
=
lists
:
foreach
(
fun
(
K
)
->
config_changed
(
removed
,
K
,
[])
end
,
Removed
),
ok
=
lists
:
foreach
(
fun
({
K
,
V
})
->
config_changed
(
changed
,
K
,
V
)
end
,
Changed
),
ok
=
lists
:
foreach
(
fun
({
K
,
V
})
->
config_changed
(
new
,
K
,
V
)
end
,
New
).
%%--------------------------------------------------------------------
%% @doc List of ranch listeners running mtproto_proxy
-
spec
mtp_listeners
()
->
[
tuple
()].
mtp_listeners
()
->
lists
:
filter
(
fun
({_
Name
,
Opts
})
->
proplists
:
get_value
(
protocol
,
Opts
)
==
mtp_handler
end
,
ranch
:
info
()).
%% @doc Currently running listeners in a form of proxy_port()
-
spec
running_ports
()
->
[
proxy_port
()].
running_ports
()
->
lists
:
map
(
fun
({
Name
,
Opts
})
->
#
{
protocol_options
:
=
ProtoOpts
,
ip
:
=
Ip
,
port
:
=
Port
}
=
maps
:
from_list
(
Opts
),
[
Name
,
Secret
,
AdTag
]
=
ProtoOpts
,
#
{
name
=>
Name
,
listen_ip
=>
inet
:
ntoa
(
Ip
),
port
=>
Port
,
secret
=>
Secret
,
tag
=>
AdTag
}
end
,
mtp_listeners
()).
%%====================================================================
%% Internal functions
%%====================================================================
-
spec
start_proxy
(
proxy_port
())
->
{
ok
,
pid
()}.
start_proxy
(
#
{
name
:
=
Name
,
port
:
=
Port
,
secret
:
=
Secret
,
tag
:
=
Tag
}
=
P
)
->
ListenIpStr
=
maps
:
get
(
listen_ip
,
P
,
...
...
@@ -59,6 +103,41 @@ start_proxy(#{name := Name, port := Port, secret := Secret, tag := Tag} = P) ->
stop_proxy
(
#
{
name
:
=
Name
})
->
ranch
:
stop_listener
(
Name
).
config_changed
(_,
ip_lookup_services
,
_)
->
mtp_config
:
update
();
config_changed
(_,
proxy_secret_url
,
_)
->
mtp_config
:
update
();
config_changed
(_,
proxy_config_url
,
_)
->
mtp_config
:
update
();
config_changed
(
Action
,
max_connections
,
N
)
when
Action
==
new
;
Action
==
changed
->
(
is_integer
(
N
)
and
(
N
>=
0
))
orelse
error
({
"max_connections should be non_neg_integer"
,
N
}),
lists
:
foreach
(
fun
({
Name
,
_})
->
ranch
:
set_max_connections
(
Name
,
N
)
end
,
mtp_listeners
());
config_changed
(
Action
,
downstream_socket_buffer_size
,
N
)
when
Action
==
new
;
Action
==
changed
->
[{
ok
,
_}
=
mtp_down_conn
:
set_config
(
Pid
,
downstream_socket_buffer_size
,
N
)
||
{_,
Pid
,
worker
,
[
mtp_down_conn
]}
<-
supervisor
:
which_children
(
mtp_down_conn_sup
)],
ok
;
%% Since upstream connections are mostly short-lived, live-update doesn't make much difference
%% config_changed(Action, upstream_socket_buffer_size, N) when Action == new; Action == changed ->
config_changed
(
Action
,
ports
,
Ports
)
when
Action
==
new
;
Action
==
changed
->
%% TODO: update secret or ad_tag without disconnect
RanchPorts
=
ordsets
:
from_list
(
running_ports
()),
DefaultListenIp
=
#
{
listen_ip
=>
application
:
get_env
(
?
APP
,
listen_ip
,
"0.0.0.0"
)},
NewPorts
=
ordsets
:
from_list
([
maps
:
merge
(
DefaultListenIp
,
Port
)
||
Port
<-
Ports
]),
ToStop
=
ordsets
:
subtract
(
RanchPorts
,
NewPorts
),
ToStart
=
ordsets
:
subtract
(
NewPorts
,
RanchPorts
),
lists
:
foreach
(
fun
stop_proxy
/
1
,
ToStop
),
[{
ok
,
_}
=
mtproto_proxy_app
:
start_proxy
(
Conf
)
||
Conf
<-
ToStart
],
ok
;
config_changed
(
Action
,
K
,
V
)
->
%% Most of the other config options are applied automatically without extra work
lager
:
info
(
"Config
~p
~p
to
~p
ignored"
,
[
K
,
Action
,
V
]),
ok
.
-
ifdef
(
TEST
).
report
(
Fmt
,
Args
)
->
lager
:
debug
(
Fmt
,
Args
).
...
...
test/single_dc_SUITE.erl
View file @
977109d0
...
...
@@ -11,7 +11,8 @@
echo_abridged_many_packets_case
/
1
,
packet_too_large_case
/
1
,
downstream_size_backpressure_case
/
1
,
downstream_qlen_backpressure_case
/
1
downstream_qlen_backpressure_case
/
1
,
config_change_case
/
1
]).
-
export
([
set_env
/
2
,
...
...
@@ -248,11 +249,65 @@ downstream_qlen_backpressure_case(Cfg) when is_list(Cfg) ->
%% ct:pal("Metric: ~p", [sys:get_state(mtp_test_metric)]),
ok
.
gen_rpc_replies
(
#
{
packet
:
=
Packet
,
n
:
=
N
},
ConnId
,
St
)
->
Rpcs
=
[{
proxy_ans
,
ConnId
,
Packet
}
||
_
<-
lists
:
seq
(
1
,
N
)],
{
return
,
{
rpc_multi
,
Rpcs
,
St
#
{
ConnId
=>
1
}}}.
%% @doc test mtproto_proxy_app:config_change/3
config_change_case
({
pre
,
Cfg
})
->
setup_single
(
?
FUNCTION_NAME
,
10000
+
?
LINE
,
#
{},
Cfg
);
config_change_case
({
post
,
Cfg
})
->
stop_single
(
Cfg
);
config_change_case
(
Cfg
)
when
is_list
(
Cfg
)
->
%% test "max_connections"
MaxConnsBefore
=
[{
Listener
,
proplists
:
get_value
(
max_connections
,
Opts
)}
||
{
Listener
,
Opts
}
<-
mtproto_proxy_app
:
mtp_listeners
()],
NewMaxConns
=
10
,
ok
=
mtproto_proxy_app
:
config_change
([{
max_connections
,
NewMaxConns
}],
[],
[]),
MaxConnsAfter
=
[{
Listener
,
proplists
:
get_value
(
max_connections
,
Opts
)}
||
{
Listener
,
Opts
}
<-
mtproto_proxy_app
:
mtp_listeners
()],
?
assertNotEqual
(
MaxConnsBefore
,
MaxConnsAfter
),
?
assert
(
lists
:
all
(
fun
({_
Listener
,
MaxConns
})
->
MaxConns
==
NewMaxConns
end
,
MaxConnsAfter
),
MaxConnsAfter
),
%% test downstream_socket_buffer_size
GetBufferSizes
=
fun
()
->
lists
:
map
(
fun
({_,
Pid
,
worker
,
[
mtp_down_conn
]})
->
%% This is hacky and may brake in future erlang releases
{
links
,
Links
}
=
process_info
(
Pid
,
links
),
[
Port
]
=
[
L
||
L
<-
Links
,
is_port
(
L
)],
{
ok
,
[{
buffer
,
BufSize
}]}
=
inet
:
getopts
(
Port
,
[
buffer
]),
{
Pid
,
BufSize
}
end
,
supervisor
:
which_children
(
mtp_down_conn_sup
))
end
,
BufSizesBefore
=
GetBufferSizes
(),
NewBufSize
=
512
,
ok
=
mtproto_proxy_app
:
config_change
([{
downstream_socket_buffer_size
,
NewBufSize
}],
[],
[]),
BufSizesAfter
=
GetBufferSizes
(),
?
assertNotEqual
(
BufSizesBefore
,
BufSizesAfter
),
?
assert
(
lists
:
all
(
fun
({_
Conn
,
BufSize
})
->
BufSize
==
NewBufSize
end
,
BufSizesAfter
),
BufSizesAfter
),
%% test ports
PortsBefore
=
mtproto_proxy_app
:
running_ports
(),
?
assertMatch
([
#
{
name
:
=
_,
listen_ip
:
=
_,
port
:
=
_,
secret
:
=
_,
tag
:
=
_}],
PortsBefore
),
ok
=
mtproto_proxy_app
:
config_change
([{
ports
,
[]}],
[],
[]),
?
assertEqual
([],
mtproto_proxy_app
:
running_ports
()),
ok
=
mtproto_proxy_app
:
config_change
([{
ports
,
PortsBefore
}],
[],
[]),
?
assertEqual
(
PortsBefore
,
mtproto_proxy_app
:
running_ports
()),
ok
.
%% TODO: send a lot, not read, and then close - assert connection IDs are cleaned up
%% Helpers
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment