capricorn 2.0.8 → 2.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
- data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
- data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
- data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
- data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
- data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
- data/erlang/lib/ejson/Makefile +24 -0
- data/erlang/lib/ejson/ebin/ejson.app +9 -0
- data/erlang/lib/ejson/include/ejson.hrl +40 -0
- data/erlang/lib/ejson/rebar.config +3 -0
- data/erlang/lib/ejson/src/ejson.erl +22 -0
- data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
- data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
- data/erlang/lib/ejson/test/arrays.escript +47 -0
- data/erlang/lib/ejson/test/compound.escript +56 -0
- data/erlang/lib/ejson/test/literals.escript +30 -0
- data/erlang/lib/ejson/test/numbers.escript +70 -0
- data/erlang/lib/ejson/test/objects.escript +51 -0
- data/erlang/lib/ejson/test/strings.escript +49 -0
- data/erlang/lib/ejson/test/timing.escript +43 -0
- data/erlang/lib/ejson/test/timing.json +382 -0
- data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
- data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
- data/erlang/lib/misultin/LICENSE.txt +41 -0
- data/erlang/lib/misultin/Makefile +26 -0
- data/erlang/lib/misultin/README.txt +120 -0
- data/erlang/lib/misultin/ebin/misultin.app +9 -0
- data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
- data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
- data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
- data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
- data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
- data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
- data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
- data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
- data/erlang/lib/misultin/include/misultin.hrl +95 -0
- data/erlang/lib/misultin/make.bat +55 -0
- data/erlang/lib/misultin/priv/README.txt +12 -0
- data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
- data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
- data/erlang/lib/misultin/rebar.config +3 -0
- data/erlang/lib/misultin/src/misultin.app.src +9 -0
- data/erlang/lib/misultin/src/misultin.erl +338 -0
- data/erlang/lib/misultin/src/misultin_http.erl +488 -0
- data/erlang/lib/misultin/src/misultin_req.erl +280 -0
- data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
- data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
- data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
- data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
- data/erlang/rebar.config +2 -0
- data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
- data/erlang/rel/reltool.config +5 -0
- data/lib/capricorn/recipes/apache-debian.rb +1 -1
- data/lib/capricorn/recipes/centos-plesk.rb +1 -1
- data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
- data/lib/capricorn/recipes/macports.rb +1 -1
- data/lib/capricorn/version.rb +1 -1
- metadata +51 -4
@@ -0,0 +1,95 @@
|
|
1
|
+
% ==========================================================================================================
|
2
|
+
% MISULTIN - Include file
|
3
|
+
%
|
4
|
+
% Copyright (C) 2009, Sean Hinde, Roberto Ostinelli <roberto@ostinelli.net>
|
5
|
+
% All rights reserved.
|
6
|
+
%
|
7
|
+
% BSD License
|
8
|
+
%
|
9
|
+
% Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
10
|
+
% that the following conditions are met:
|
11
|
+
%
|
12
|
+
% * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
13
|
+
% following disclaimer.
|
14
|
+
% * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
15
|
+
% the following disclaimer in the documentation and/or other materials provided with the distribution.
|
16
|
+
% * Neither the name of the authors nor the names of its contributors may be used to endorse or promote
|
17
|
+
% products derived from this software without specific prior written permission.
|
18
|
+
%
|
19
|
+
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
20
|
+
% WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
21
|
+
% PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
22
|
+
% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
23
|
+
% TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24
|
+
% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
26
|
+
% POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
% ==========================================================================================================
|
28
|
+
|
29
|
+
% define debug
|
30
|
+
-ifdef(log_debug).
|
31
|
+
-define(LOG_DEBUG(Str, Args), erlang:apply(error_logger, info_msg, [lists:concat(["[DEBUG] pid: ", pid_to_list(self()), "~n module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
32
|
+
-define(LOG_INFO(Str, Args), erlang:apply(error_logger, info_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
33
|
+
-define(LOG_WARNING(Str, Args), erlang:apply(error_logger, warning_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
34
|
+
-define(LOG_ERROR(Str, Args), erlang:apply(error_logger, error_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
35
|
+
-else.
|
36
|
+
-ifdef(log_info).
|
37
|
+
-define(LOG_DEBUG(Str, Args), ok).
|
38
|
+
-define(LOG_INFO(Str, Args), erlang:apply(error_logger, info_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
39
|
+
-define(LOG_WARNING(Str, Args), erlang:apply(error_logger, warning_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
40
|
+
-define(LOG_ERROR(Str, Args), erlang:apply(error_logger, error_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
41
|
+
-else.
|
42
|
+
-ifdef(log_warning).
|
43
|
+
-define(LOG_DEBUG(Str, Args), ok).
|
44
|
+
-define(LOG_INFO(Str, Args), ok).
|
45
|
+
-define(LOG_WARNING(Str, Args), erlang:apply(error_logger, warning_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
46
|
+
-define(LOG_ERROR(Str, Args), erlang:apply(error_logger, error_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
47
|
+
-else.
|
48
|
+
-define(LOG_DEBUG(Str, Args), ok).
|
49
|
+
-define(LOG_INFO(Str, Args), ok).
|
50
|
+
-define(LOG_WARNING(Str, Args), ok).
|
51
|
+
-define(LOG_ERROR(Str, Args), erlang:apply(error_logger, error_msg, [lists:concat([" module: ", ?MODULE, "~n line: ", ?LINE, "~n", Str, "~n"]), Args])).
|
52
|
+
-endif.
|
53
|
+
-endif.
|
54
|
+
-endif.
|
55
|
+
|
56
|
+
% misultin server Options
|
57
|
+
-record(custom_opts, {
|
58
|
+
compress, % send compressed output if supported by browser
|
59
|
+
stream_support, % stream support option
|
60
|
+
loop, % the fun handling requests
|
61
|
+
ws_loop, % the loop handling websockets
|
62
|
+
ws_autoexit % true | false
|
63
|
+
}).
|
64
|
+
|
65
|
+
% Request
|
66
|
+
-record(req, {
|
67
|
+
socket, % the socket handling the request
|
68
|
+
socket_mode, % http | ssl
|
69
|
+
peer_addr, % peer IP | undefined
|
70
|
+
peer_port, % peer port | undefined
|
71
|
+
peer_cert, % undefined | the DER encoded peer certificate that can be decoded with public_key:pkix_decode_cert/2
|
72
|
+
connection = keep_alive, % keep_alive | close
|
73
|
+
content_length, % Integer
|
74
|
+
vsn, % {Maj,Min}
|
75
|
+
method, % 'GET'|'POST'
|
76
|
+
uri, % Truncated URI /index.html
|
77
|
+
args = "", % Part of URI after ?
|
78
|
+
headers, % [{Tag, Val}]
|
79
|
+
body = <<>> % Content Body
|
80
|
+
}).
|
81
|
+
|
82
|
+
% Websocket Request
|
83
|
+
-record(ws, {
|
84
|
+
socket, % the socket handling the request
|
85
|
+
socket_mode, % http | ssl
|
86
|
+
ws_autoexit, % websocket process is automatically killed: true | false
|
87
|
+
peer_addr, % peer IP | undefined
|
88
|
+
peer_port, % peer port | undefined
|
89
|
+
peer_cert, % undefined | the DER encoded peer certificate that can be decoded with public_key:pkix_decode_cert/2
|
90
|
+
vsn, % {Maj,Min} | {'draft-hixie', Ver}
|
91
|
+
origin, % the originator
|
92
|
+
host, % the host
|
93
|
+
path, % the websocket GET request path
|
94
|
+
headers % [{Tag, Val}]
|
95
|
+
}).
|
@@ -0,0 +1,55 @@
|
|
1
|
+
@echo off
|
2
|
+
REM ==========================================================================================================
|
3
|
+
REM MISULTIN - compile
|
4
|
+
REM
|
5
|
+
REM >-|-|-<°>
|
6
|
+
REM
|
7
|
+
REM Copyright (C) 2009, Roberto Ostinelli <roberto@ostinelli.net>
|
8
|
+
REM All rights reserved.
|
9
|
+
REM
|
10
|
+
REM BSD License
|
11
|
+
REM
|
12
|
+
REM Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
13
|
+
REM that the following conditions are met:
|
14
|
+
REM
|
15
|
+
REM * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
16
|
+
REM following disclaimer.
|
17
|
+
REM * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
18
|
+
REM the following disclaimer in the documentation and/or other materials provided with the distribution.
|
19
|
+
REM * Neither the name of the authors nor the names of its contributors may be used to endorse or promote
|
20
|
+
REM products derived from this software without specific prior written permission.
|
21
|
+
REM
|
22
|
+
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
23
|
+
REM WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
24
|
+
REM PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
25
|
+
REM ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
26
|
+
REM TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
27
|
+
REM HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
28
|
+
REM NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
+
REM POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
REM ==========================================================================================================
|
31
|
+
|
32
|
+
:BEGIN
|
33
|
+
IF "%1"=="debug" GOTO SETDEBUG
|
34
|
+
IF "%1"=="example" GOTO EXAMPLES
|
35
|
+
IF "%1"=="clean" GOTO CLEAN
|
36
|
+
GOTO COMPILE
|
37
|
+
|
38
|
+
:SETDEBUG
|
39
|
+
SET command=-D log_debug
|
40
|
+
GOTO COMPILE
|
41
|
+
|
42
|
+
:EXAMPLES
|
43
|
+
mkdir ebin
|
44
|
+
FOR %%f in (examples\*.erl) DO erlc -W %command% -o ebin "%%f"
|
45
|
+
|
46
|
+
:COMPILE
|
47
|
+
mkdir ebin
|
48
|
+
FOR %%f in (src\*.erl) DO erlc -W %command% -o ebin "%%f"
|
49
|
+
copy src\misultin.app.src ebin\misultin.app /Y
|
50
|
+
GOTO END
|
51
|
+
|
52
|
+
:CLEAN
|
53
|
+
FOR %%f in (ebin\*) DO del "%%f"
|
54
|
+
|
55
|
+
:END
|
@@ -0,0 +1,12 @@
|
|
1
|
+
==========================================================================================================
|
2
|
+
DISCLAIMER
|
3
|
+
==========================================================================================================
|
4
|
+
|
5
|
+
Please note that the included certificate 'test_certificate.pem' and private key 'test_privkey.pem' are
|
6
|
+
publicly available via the Misultin repositories, and should NOT be used for any secure application. These
|
7
|
+
have been provided here for your testing comfort only.
|
8
|
+
|
9
|
+
You may consider getting your copy of OpenSSL <http://www.openssl.org> and generate your own certificate
|
10
|
+
and private key by issuing a command similar to:
|
11
|
+
|
12
|
+
openssl req -new -x509 -newkey rsa:1024 -days 365 -keyout test_privkey.pem -out test_certificate.pem
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDhzCCAvCgAwIBAgIJAPFFl046vv7vMA0GCSqGSIb3DQEBBQUAMIGKMQswCQYD
|
3
|
+
VQQGEwJJVDENMAsGA1UECBMEQ29tbzENMAsGA1UEBxMEQ29tbzERMA8GA1UEChMI
|
4
|
+
TWlzdWx0aW4xETAPBgNVBAsTCE1pc3VsdGluMREwDwYDVQQDEwhNaXN1bHRpbjEk
|
5
|
+
MCIGCSqGSIb3DQEJARYVcm9iZXJ0b0Bvc3RpbmVsbGkubmV0MB4XDTEwMDQyMDE3
|
6
|
+
NDczOFoXDTIwMDQxNzE3NDczOFowgYoxCzAJBgNVBAYTAklUMQ0wCwYDVQQIEwRD
|
7
|
+
b21vMQ0wCwYDVQQHEwRDb21vMREwDwYDVQQKEwhNaXN1bHRpbjERMA8GA1UECxMI
|
8
|
+
TWlzdWx0aW4xETAPBgNVBAMTCE1pc3VsdGluMSQwIgYJKoZIhvcNAQkBFhVyb2Jl
|
9
|
+
cnRvQG9zdGluZWxsaS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM8A
|
10
|
+
BT4OzNCcgrfVnzmEp8VdyR+O0ubsSBunX8J/BTKbWgZVrrGrY9fO8AkVmD1VFm8n
|
11
|
+
w/yLlz/Ow24j40UCY82Y9gMDgADa3BqcDPn1lPdGpOHhaMXMRFKnrVOfwMPE0wfx
|
12
|
+
kpr9/I5rAPAnkX1WtvOWMK0V5yGsuIMBd2S4VzmrAgMBAAGjgfIwge8wHQYDVR0O
|
13
|
+
BBYEFItpRD/8fT21N/pLeSWKexZHWP/3MIG/BgNVHSMEgbcwgbSAFItpRD/8fT21
|
14
|
+
N/pLeSWKexZHWP/3oYGQpIGNMIGKMQswCQYDVQQGEwJJVDENMAsGA1UECBMEQ29t
|
15
|
+
bzENMAsGA1UEBxMEQ29tbzERMA8GA1UEChMITWlzdWx0aW4xETAPBgNVBAsTCE1p
|
16
|
+
c3VsdGluMREwDwYDVQQDEwhNaXN1bHRpbjEkMCIGCSqGSIb3DQEJARYVcm9iZXJ0
|
17
|
+
b0Bvc3RpbmVsbGkubmV0ggkA8UWXTjq+/u8wDAYDVR0TBAUwAwEB/zANBgkqhkiG
|
18
|
+
9w0BAQUFAAOBgQA5ePVuJo6LcHegSKfD1GlTu2Ffkom547e9PYmKBaDyuNhCfP4F
|
19
|
+
YB4GMi1SZeCsaYzJpEOCY9JEJD8hJO7xPnyKnwc3FhT7KfYHWO7FNZdmdMxE99mi
|
20
|
+
lolCiDfglJkQCPihtxK5TKBDK+lzMub+1Xmc3VOvIuonzjh+VkSz1rCciQ==
|
21
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,18 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
Proc-Type: 4,ENCRYPTED
|
3
|
+
DEK-Info: DES-EDE3-CBC,E6F891BC96EC9B16
|
4
|
+
|
5
|
+
kBpeVQGiACcY96k5ix5H+/Htt6XIGB2cyUhBMZlgBPQSAttU9B94YV+nXZmIVi8f
|
6
|
+
r0cBDqGZ7uv+YjQom1HWw/NilWJr5x67VOhBGvg3kb2wYe3aMeGrmqRpPqNi6K2U
|
7
|
+
t9QuragXj7tyFu8+sYnW0SeI7GN9aghF2S9bVKasOFDBHGDg1igb7PzBsctrQh1Q
|
8
|
+
Hhkl2/Ql3+j18yUNZ2vCZgvGE2UfX5TJ79irpUCFiSgbf31EU7WCePZfSuNZfJB7
|
9
|
+
hjQM5q/vfEmgqVCdVR1W8wFxdalPJOA819gKwpKBBgpfWPn2Gvyw/yAhm3FPLasG
|
10
|
+
OgrY9PgsAcfozXgCOJP6NEP8IHzvb7kWoTussgBCd8P2Vv+YTp8WkBQDtpAlQExf
|
11
|
+
03sKUE9+pDXnzLnq4Pore6xBlzcZ4hu35WUo854UApRT/OQB5+Kmth9pqax43bbp
|
12
|
+
9Lfg6Zg9NXDuGHbRdK3U48uXLa7lDi5TMJ3LHuJ+DxZq4WNCTbMA3YZTFnjGiD/N
|
13
|
+
NvTy54oQThjn67N7BQe3PeWI2ryGEWJAXShnc0ZTaxQaQn+18zVAe2tQOFUPhbbA
|
14
|
+
Bq7zx49gea1tlJC1DHLktmw72v0g5W3HZ2fP1m+9socH9n4iORGEpicwuMgf9Tlb
|
15
|
+
T0mFP3hL0y1wEdBoohF6Euk1Y33P44tbXsYn6bP2/mVmWphVA3wWOocMYw/UgSxM
|
16
|
+
pzpC+z6y19dhqYNJyywgsMv6GQdrovW1DF2udmjx1Mv7qbwdJlH0GyLdyBL8aZFb
|
17
|
+
WBXI2PjWWtZS/F1U7QsELzV3mM1U8n+K5hZuBPtvLzohpq2W59tPkg==
|
18
|
+
-----END RSA PRIVATE KEY-----
|
@@ -0,0 +1,9 @@
|
|
1
|
+
{application, misultin,
|
2
|
+
[
|
3
|
+
{description, "Lightweight HTTP(s) and Websockets Server Library"},
|
4
|
+
{vsn, "0.6.1"},
|
5
|
+
{modules, [misultin, misultin_req, misultin_socket, misultin_http, misultin_utility, misultin_websocket, misultin_ws]},
|
6
|
+
{registered, [misultin]},
|
7
|
+
{env, []},
|
8
|
+
{applications, [kernel, stdlib]}
|
9
|
+
]}.
|
@@ -0,0 +1,338 @@
|
|
1
|
+
% ==========================================================================================================
|
2
|
+
% MISULTIN - Main
|
3
|
+
%
|
4
|
+
% >-|-|-(°>
|
5
|
+
%
|
6
|
+
% Copyright (C) 2010, Roberto Ostinelli <roberto@ostinelli.net>, Sean Hinde.
|
7
|
+
% All rights reserved.
|
8
|
+
%
|
9
|
+
% Code portions from Sean Hinde have been originally taken under BSD license from Trapexit at the address:
|
10
|
+
% <http://www.trapexit.org/A_fast_web_server_demonstrating_some_undocumented_Erlang_features>
|
11
|
+
%
|
12
|
+
% BSD License
|
13
|
+
%
|
14
|
+
% Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
15
|
+
% that the following conditions are met:
|
16
|
+
%
|
17
|
+
% * Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
18
|
+
% following disclaimer.
|
19
|
+
% * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
|
20
|
+
% the following disclaimer in the documentation and/or other materials provided with the distribution.
|
21
|
+
% * Neither the name of the authors nor the names of its contributors may be used to endorse or promote
|
22
|
+
% products derived from this software without specific prior written permission.
|
23
|
+
%
|
24
|
+
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
25
|
+
% WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
26
|
+
% PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
27
|
+
% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
28
|
+
% TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
29
|
+
% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
30
|
+
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
31
|
+
% POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
% ==========================================================================================================
|
33
|
+
-module(misultin).
|
34
|
+
-behaviour(gen_server).
|
35
|
+
-vsn("0.6.1").
|
36
|
+
|
37
|
+
% gen_server callbacks
|
38
|
+
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
|
39
|
+
|
40
|
+
% API
|
41
|
+
-export([start_link/1, stop/0, persistent_socket_pid_add/1, persistent_socket_pid_remove/1]).
|
42
|
+
|
43
|
+
% macros
|
44
|
+
-define(SERVER, ?MODULE).
|
45
|
+
|
46
|
+
% records
|
47
|
+
-record(state, {
|
48
|
+
% tcp
|
49
|
+
listen_socket,
|
50
|
+
socket_mode,
|
51
|
+
port,
|
52
|
+
options,
|
53
|
+
acceptor,
|
54
|
+
recv_timeout,
|
55
|
+
persistent_sock_references = [],
|
56
|
+
% misultin
|
57
|
+
custom_opts
|
58
|
+
}).
|
59
|
+
|
60
|
+
% includes
|
61
|
+
-include("../include/misultin.hrl").
|
62
|
+
|
63
|
+
|
64
|
+
% ============================ \/ API ======================================================================
|
65
|
+
|
66
|
+
% Function: {ok,Pid} | ignore | {error, Error}
|
67
|
+
% Description: Starts the server.
|
68
|
+
start_link(Options) when is_list(Options) ->
|
69
|
+
gen_server:start_link({local, ?SERVER}, ?MODULE, [Options], []).
|
70
|
+
|
71
|
+
% Function: -> ok
|
72
|
+
% Description: Manually stops the server.
|
73
|
+
stop() ->
|
74
|
+
gen_server:cast(?SERVER, stop).
|
75
|
+
|
76
|
+
% Function -> ok
|
77
|
+
% Description: Adds a new persistent socket pid reference to status
|
78
|
+
persistent_socket_pid_add(WsPid) ->
|
79
|
+
gen_server:cast(?SERVER, {add_ws_pid, WsPid}).
|
80
|
+
|
81
|
+
% Function -> ok
|
82
|
+
% Description: Remove a persistent socket pid reference from status
|
83
|
+
persistent_socket_pid_remove(WsPid) ->
|
84
|
+
gen_server:cast(?SERVER, {remove_ws_pid, WsPid}).
|
85
|
+
|
86
|
+
% ============================ /\ API ======================================================================
|
87
|
+
|
88
|
+
|
89
|
+
% ============================ \/ GEN_SERVER CALLBACKS =====================================================
|
90
|
+
|
91
|
+
% ----------------------------------------------------------------------------------------------------------
|
92
|
+
% Function: -> {ok, State} | {ok, State, Timeout} | ignore | {stop, Reason}
|
93
|
+
% Description: Initiates the server.
|
94
|
+
% ----------------------------------------------------------------------------------------------------------
|
95
|
+
init([Options]) ->
|
96
|
+
process_flag(trap_exit, true),
|
97
|
+
?LOG_INFO("starting with Pid: ~p", [self()]),
|
98
|
+
% test and get options
|
99
|
+
OptionProps = [
|
100
|
+
% socket
|
101
|
+
{ip, {0, 0, 0, 0}, fun check_and_convert_string_to_ip/1, invalid_ip},
|
102
|
+
{port, 80, fun is_integer/1, port_not_integer},
|
103
|
+
{backlog, 128, fun is_integer/1, backlog_not_integer},
|
104
|
+
{recv_timeout, 30*1000, fun is_integer/1, recv_timeout_not_integer},
|
105
|
+
{ssl, false, fun check_ssl_options/1, invalid_ssl_options},
|
106
|
+
% misultin
|
107
|
+
{compress, false, fun is_boolean/1, invalid_compress_option},
|
108
|
+
{stream_support, true, fun is_boolean/1, invalid_stream_support_option},
|
109
|
+
{loop, {error, undefined_loop}, fun is_function/1, loop_not_function},
|
110
|
+
{ws_loop, none, fun is_function/1, ws_loop_not_function},
|
111
|
+
{ws_autoexit, true, fun is_boolean/1, invalid_ws_autoexit_option}
|
112
|
+
],
|
113
|
+
OptionsVerified = lists:foldl(fun(OptionName, Acc) -> [get_option(OptionName, Options)|Acc] end, [], OptionProps),
|
114
|
+
case proplists:get_value(error, OptionsVerified) of
|
115
|
+
undefined ->
|
116
|
+
% ok, no error found in options
|
117
|
+
% tcp options
|
118
|
+
Ip = proplists:get_value(ip, OptionsVerified),
|
119
|
+
Port = proplists:get_value(port, OptionsVerified),
|
120
|
+
Backlog = proplists:get_value(backlog, OptionsVerified),
|
121
|
+
RecvTimeout = proplists:get_value(recv_timeout, OptionsVerified),
|
122
|
+
SslOptions0 = proplists:get_value(ssl, OptionsVerified),
|
123
|
+
% misultin options
|
124
|
+
Compress = proplists:get_value(compress, OptionsVerified),
|
125
|
+
StreamSupport = proplists:get_value(stream_support, OptionsVerified),
|
126
|
+
Loop = proplists:get_value(loop, OptionsVerified),
|
127
|
+
WsLoop = proplists:get_value(ws_loop, OptionsVerified),
|
128
|
+
WsAutoExit = proplists:get_value(ws_autoexit, OptionsVerified),
|
129
|
+
% ipv6 support
|
130
|
+
?LOG_DEBUG("ip address is: ~p", [Ip]),
|
131
|
+
% set additional options according to socket mode if necessary
|
132
|
+
Continue = case SslOptions0 of
|
133
|
+
false ->
|
134
|
+
% without SSL
|
135
|
+
SocketMode = http,
|
136
|
+
InetOpt = case Ip of
|
137
|
+
{_, _, _, _} ->
|
138
|
+
% IPv4
|
139
|
+
inet;
|
140
|
+
{_, _, _, _, _, _, _, _} ->
|
141
|
+
% IPv6
|
142
|
+
inet6
|
143
|
+
end,
|
144
|
+
AdditionalOptions = [InetOpt],
|
145
|
+
true;
|
146
|
+
_ ->
|
147
|
+
% with SSL
|
148
|
+
SocketMode = ssl,
|
149
|
+
% the only current way to use {active, once} in Ssl is to start the crypto module
|
150
|
+
% and set {ssl_imp, new} as SSL option, see
|
151
|
+
% <http://www.erlang.org/cgi-bin/ezmlm-cgi?4:mss:50633:201004:fpopocbfkpppecdembbe>
|
152
|
+
AdditionalOptions = [{ssl_imp, new}|SslOptions0],
|
153
|
+
% start Ssl and crypto applications if necessary, and get outcomes
|
154
|
+
AppStartResults = lists:keyfind(error, 1, [start_application(ssl), start_application(crypto)]),
|
155
|
+
case AppStartResults of
|
156
|
+
false ->
|
157
|
+
% all applications started succesfully
|
158
|
+
true;
|
159
|
+
_ ->
|
160
|
+
% error starting application
|
161
|
+
{error, AppStartResults}
|
162
|
+
end
|
163
|
+
end,
|
164
|
+
% proceed?
|
165
|
+
case Continue of
|
166
|
+
true ->
|
167
|
+
% set options
|
168
|
+
OptionsTcp = [binary, {packet, raw}, {ip, Ip}, {reuseaddr, true}, {active, false}, {backlog, Backlog}|AdditionalOptions],
|
169
|
+
% build custom_opts
|
170
|
+
CustomOpts = #custom_opts{compress = Compress, stream_support = StreamSupport, loop = Loop, ws_loop = WsLoop, ws_autoexit = WsAutoExit},
|
171
|
+
% create listening socket and acceptor
|
172
|
+
case create_listener_and_acceptor(Port, OptionsTcp, RecvTimeout, SocketMode, CustomOpts) of
|
173
|
+
{ok, ListenSocket, AcceptorPid} ->
|
174
|
+
?LOG_DEBUG("listening socket and acceptor succesfully started",[]),
|
175
|
+
{ok, #state{listen_socket = ListenSocket, socket_mode = SocketMode, port = Port, options = OptionsTcp, acceptor = AcceptorPid, recv_timeout = RecvTimeout, custom_opts = CustomOpts}};
|
176
|
+
{error, Reason} ->
|
177
|
+
?LOG_ERROR("error starting listener socket: ~p", [Reason]),
|
178
|
+
{stop, Reason}
|
179
|
+
end;
|
180
|
+
Error ->
|
181
|
+
{stop, Error}
|
182
|
+
end;
|
183
|
+
Reason ->
|
184
|
+
% error found in options
|
185
|
+
{stop, Reason}
|
186
|
+
end.
|
187
|
+
|
188
|
+
% ----------------------------------------------------------------------------------------------------------
|
189
|
+
% Function: handle_call(Request, From, State) -> {reply, Reply, State} | {reply, Reply, State, Timeout} |
|
190
|
+
% {noreply, State} | {noreply, State, Timeout} |
|
191
|
+
% {stop, Reason, Reply, State} | {stop, Reason, State}
|
192
|
+
% Description: Handling call messages.
|
193
|
+
% ----------------------------------------------------------------------------------------------------------
|
194
|
+
|
195
|
+
% handle_call generic fallback
|
196
|
+
handle_call(_Request, _From, State) ->
|
197
|
+
{reply, undefined, State}.
|
198
|
+
|
199
|
+
% ----------------------------------------------------------------------------------------------------------
|
200
|
+
% Function: handle_cast(Msg, State) -> {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State}
|
201
|
+
% Description: Handling cast messages.
|
202
|
+
% ----------------------------------------------------------------------------------------------------------
|
203
|
+
|
204
|
+
% manual shutdown
|
205
|
+
handle_cast(stop, State) ->
|
206
|
+
?LOG_INFO("manual shutdown..", []),
|
207
|
+
{stop, normal, State};
|
208
|
+
|
209
|
+
% add persistent socket reference to server
|
210
|
+
handle_cast({add_ws_pid, PsPid}, #state{persistent_sock_references = PersistentSockReferences} = State) ->
|
211
|
+
{noreply, State#state{persistent_sock_references = [PsPid|PersistentSockReferences]}};
|
212
|
+
|
213
|
+
% remove persistent socket reference from server
|
214
|
+
handle_cast({remove_ws_pid, PsPid}, #state{persistent_sock_references = PersistentSockReferences} = State) ->
|
215
|
+
{noreply, State#state{persistent_sock_references = lists:delete(PsPid, PersistentSockReferences)}};
|
216
|
+
|
217
|
+
% handle_cast generic fallback (ignore)
|
218
|
+
handle_cast(_Msg, State) ->
|
219
|
+
?LOG_WARNING("received unknown cast message: ~p", [_Msg]),
|
220
|
+
{noreply, State}.
|
221
|
+
|
222
|
+
% ----------------------------------------------------------------------------------------------------------
|
223
|
+
% Function: handle_info(Info, State) -> {noreply, State} | {noreply, State, Timeout} | {stop, Reason, State}
|
224
|
+
% Description: Handling all non call/cast messages.
|
225
|
+
% ----------------------------------------------------------------------------------------------------------
|
226
|
+
|
227
|
+
% Acceptor died
|
228
|
+
% -> shutdown in progress, ignore
|
229
|
+
handle_info({'EXIT', Pid, {error, {{accept_failed, {shutdown, _}}}}}, #state{acceptor = Pid} = State) -> {noreply, State};
|
230
|
+
% -> respawn listening socket and acceptor
|
231
|
+
handle_info({'EXIT', Pid, _Reason}, #state{listen_socket = ListenSocket, socket_mode = SocketMode, port = Port, acceptor = Pid, recv_timeout = RecvTimeout, custom_opts = CustomOpts} = State) ->
|
232
|
+
?LOG_WARNING("acceptor has died with reason: ~p, respawning", [_Reason]),
|
233
|
+
AcceptorPid = misultin_socket:start_link(ListenSocket, Port, RecvTimeout, SocketMode, CustomOpts),
|
234
|
+
{noreply, State#state{acceptor = AcceptorPid}};
|
235
|
+
|
236
|
+
% handle_info generic fallback (ignore)
|
237
|
+
handle_info(_Info, State) ->
|
238
|
+
?LOG_WARNING("received unknown info message: ~p", [_Info]),
|
239
|
+
{noreply, State}.
|
240
|
+
|
241
|
+
% ----------------------------------------------------------------------------------------------------------
|
242
|
+
% Function: terminate(Reason, State) -> void()
|
243
|
+
% Description: This function is called by a gen_server when it is about to terminate. When it returns,
|
244
|
+
% the gen_server terminates with Reason. The return value is ignored.
|
245
|
+
% ----------------------------------------------------------------------------------------------------------
|
246
|
+
terminate(_Reason, #state{listen_socket = ListenSocket, socket_mode = SocketMode, acceptor = AcceptorPid, persistent_sock_references = PersistentSockReferences}) ->
|
247
|
+
?LOG_INFO("shutting down server with Pid ~p", [self()]),
|
248
|
+
% kill acceptor
|
249
|
+
exit(AcceptorPid, kill),
|
250
|
+
% send a shutdown message to all persistent sockets, if any
|
251
|
+
?LOG_DEBUG("sending shutdown message to persistent sockets, if any", []),
|
252
|
+
lists:foreach(fun(PsPid) -> catch PsPid ! shutdown end, PersistentSockReferences),
|
253
|
+
% stop tcp socket
|
254
|
+
misultin_socket:close(ListenSocket, SocketMode),
|
255
|
+
terminated.
|
256
|
+
|
257
|
+
% ----------------------------------------------------------------------------------------------------------
|
258
|
+
% Function: code_change(OldVsn, State, Extra) -> {ok, NewState}
|
259
|
+
% Description: Convert process state when code is changed.
|
260
|
+
% ----------------------------------------------------------------------------------------------------------
|
261
|
+
code_change(_OldVsn, State, _Extra) ->
|
262
|
+
{ok, State}.
|
263
|
+
|
264
|
+
% ============================ /\ GEN_SERVER CALLBACKS =====================================================
|
265
|
+
|
266
|
+
|
267
|
+
% ============================ \/ INTERNAL FUNCTIONS =======================================================
|
268
|
+
|
269
|
+
% Function: -> false | IpTuple
|
270
|
+
% Description: Checks and converts a string Ip to inet repr.
|
271
|
+
check_and_convert_string_to_ip(Ip) ->
|
272
|
+
case inet_parse:address(Ip) of
|
273
|
+
{error, _Reason} ->
|
274
|
+
false;
|
275
|
+
{ok, IpTuple} ->
|
276
|
+
IpTuple
|
277
|
+
end.
|
278
|
+
|
279
|
+
% Function: -> true | false
|
280
|
+
% Description: Checks if all necessary Ssl Options have been specified
|
281
|
+
check_ssl_options(SslOptions) ->
|
282
|
+
Opts = [verify, fail_if_no_peer_cert, verify_fun, depth, certfile, keyfile, password, cacertfile, ciphers, reuse_sessions, reuse_session],
|
283
|
+
F = fun({Name, _Value}) ->
|
284
|
+
?LOG_DEBUG("testing ~p", [Name]),
|
285
|
+
case lists:member(Name, Opts) of
|
286
|
+
false -> ?LOG_DEBUG("NOT found ~p", [Name]),false;
|
287
|
+
_ -> ?LOG_DEBUG("found ~p", [Name]),true
|
288
|
+
end
|
289
|
+
end,
|
290
|
+
lists:all(F, SslOptions).
|
291
|
+
|
292
|
+
% Description: Validate and get misultin options.
|
293
|
+
get_option({OptionName, DefaultValue, CheckAndConvertFun, FailTypeError}, Options) ->
|
294
|
+
case proplists:get_value(OptionName, Options) of
|
295
|
+
undefined ->
|
296
|
+
case DefaultValue of
|
297
|
+
{error, Reason} ->
|
298
|
+
{error, Reason};
|
299
|
+
Value ->
|
300
|
+
{OptionName, Value}
|
301
|
+
end;
|
302
|
+
Value ->
|
303
|
+
case CheckAndConvertFun(Value) of
|
304
|
+
false ->
|
305
|
+
{error, {FailTypeError, Value}};
|
306
|
+
true ->
|
307
|
+
{OptionName, Value};
|
308
|
+
OutValue ->
|
309
|
+
{OptionName, OutValue}
|
310
|
+
end
|
311
|
+
end.
|
312
|
+
|
313
|
+
% Function: -> ok | {error, Reason}
|
314
|
+
% Description: Start an application.
|
315
|
+
start_application(Application) ->
|
316
|
+
case lists:keyfind(Application, 1, application:which_applications()) of
|
317
|
+
false ->
|
318
|
+
application:start(Application);
|
319
|
+
_ ->
|
320
|
+
ok
|
321
|
+
end.
|
322
|
+
|
323
|
+
% Function: -> {ok, ListenSocket, AcceptorPid} | {error, Error}
|
324
|
+
% Description: Create listening socket
|
325
|
+
create_listener_and_acceptor(Port, Options, RecvTimeout, SocketMode, CustomOpts) ->
|
326
|
+
?LOG_DEBUG("starting listening ~p socket with options ~p on port ~p", [SocketMode, Options, Port]),
|
327
|
+
case misultin_socket:listen(Port, Options, SocketMode) of
|
328
|
+
{ok, ListenSocket} ->
|
329
|
+
?LOG_DEBUG("starting acceptor",[]),
|
330
|
+
% create acceptor
|
331
|
+
AcceptorPid = misultin_socket:start_link(ListenSocket, Port, RecvTimeout, SocketMode, CustomOpts),
|
332
|
+
{ok, ListenSocket, AcceptorPid};
|
333
|
+
{error, Reason} ->
|
334
|
+
% error
|
335
|
+
{error, Reason}
|
336
|
+
end.
|
337
|
+
|
338
|
+
% ============================ /\ INTERNAL FUNCTIONS =======================================================
|