commit 7913a62707d9c62aefce153607d6be1610c12bb4
parent 53b59e98e0fca52a7bc550043d3cbfc229969a43
Author: kyle <kyle@getaddrinfo.net>
Date: Sat, 13 Feb 2016 20:56:42 -0700
sl: add comments
Diffstat:
M | server/sl | | | 40 | ++++++++++++++++++++++++++++++++++------ |
1 file changed, 34 insertions(+), 6 deletions(-)
diff --git a/server/sl b/server/sl
@@ -12,6 +12,7 @@ use JSON::XS;
use Scalar::Util qw(looks_like_number);
use Try::Tiny;
+# Our own modules
use logger;
use database;
@@ -32,6 +33,13 @@ $log->print_bare("using database '$db_file'\n");
my $db = database->new($db_file);
$db->create_tables();
+# Create master listening socket, by default on port 5437. All connection
+# requests are served from this socket. Don't make this an SSL listening socket
+# as the IO::Socket::SSL man page warns about potential blocks that can happen
+# during an SSL handshake (which would be bad).
+#
+# So create the socket as plain TCP, accept plain TCP and then start SSL on the
+# client socket.
my $server_socket = new IO::Socket::INET (
LocalPort => $args{p} || '5437',
Proto => 'tcp',
@@ -43,7 +51,10 @@ die "Could not create socket: $!\n" unless($server_socket);
my ($addr, $port) = ($server_socket->sockhost(), $server_socket->sockport());
$log->print_bare("accepting connections on $addr:$port (pid = '$$')\n");
+# Children who have died will do not have to be waited on with this
$SIG{CHLD} = 'IGNORE';
+
+# Accept new plain TCP connections and handle them in separate processes
while (my $client_socket = $server_socket->accept()) {
# Create a child process to handle this client
@@ -57,13 +68,13 @@ while (my $client_socket = $server_socket->accept()) {
}
close $server_socket;
- # In child: stir the random pool after fork() just in case
+ # Stir the random pool after fork() just in case
arc4random_stir();
$log->set_peer_host_port($client_socket);
$log->print("new connection (pid = '$$')\n");
- # Upgrade connection to SSL
+ # Upgrade plain TCP connection to SSL
my $ret = IO::Socket::SSL->start_SSL($client_socket,
SSL_server => 1,
SSL_cert_file => 'ssl/cert_chain.pem',
@@ -83,13 +94,16 @@ while (my $client_socket = $server_socket->accept()) {
while (1) {
# Database errors and socket connect errors both modify this
- # value, make sure it's reset
+ # value. Make sure it's reset
undef $@;
+ # Wait for an entire message to be received
my ($ver, $msg_type, $request) = recv_msg($client_socket);
$db->{dbh}->begin_work;
+ # Every message type except 'device_add' needs to include
+ # 'device_id' in the request. Check that here.
my $device = undef;
if ($msg_type != $msg_num{device_add}) {
(my $err, $device) = get_device($db, $request);
@@ -101,6 +115,9 @@ while (my $client_socket = $server_socket->accept()) {
}
}
+ # Call appropriate message handler. Each handler returns both
+ # data that should be sent back over the main socket and
+ # notification data that gets sent over vendor specific API.
my ($response, $notify) = $msg_func[$msg_type]->($db, $request, $device);
$db->{dbh}->commit;
@@ -117,7 +134,7 @@ while (my $client_socket = $server_socket->accept()) {
next;
}
- # Reply to client
+ # Respond to client over the main socket
send_msg($client_socket, $ver, $msg_type, $response);
# Some messages don't send notifications
@@ -126,11 +143,11 @@ while (my $client_socket = $server_socket->accept()) {
# Don't send notifications when there was en error
next if ($response->{status} eq 'err');
- # Encode the notification message to find its size
+ # Encode the notification message and find its size
my $msg = encode_json($notify);
my $msg_len = length($msg);
- # Try to send to various messaging daemons
+ # Send to notification daemons
send_unix("../apnd.socket", $msg, $msg_len) unless ($args{t});
send_unix("../gcmd.socket", $msg, $msg_len) unless ($args{t});
send_unix("../testd.socket", $msg, $msg_len) if ($args{t});
@@ -140,6 +157,8 @@ while (my $client_socket = $server_socket->accept()) {
sub send_unix {
my ($socket_path, $msg, $msg_len) = @_;
+ # Every time this function is called we create a new connection to the
+ # socket, send our data and then disconnect
my $socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM(),
Peer => $socket_path
@@ -149,12 +168,16 @@ sub send_unix {
return;
}
+ # This is the same function we use for TCP data sending
send_all($socket, $msg, $msg_len);
+
+ close($socket);
}
sub recv_msg {
my ($sock) = @_;
+ # First read the fixed size 6 byte header
my $header = read_all($sock, 6);
my ($version, $msg_type, $payload_size) = unpack("nnn", $header);
@@ -169,10 +192,15 @@ sub recv_msg {
}
$log->set_msg($msg_str[$msg_type]);
+ # Server requests are limited to 4KB size, a 0 byte payload will not be
+ # valid JSON so reject that here
if ($payload_size > 4096 || $payload_size == 0) {
$log->print("error: $payload_size byte payload invalid\n");
exit 0;
}
+
+ # Now that we know the size of the message we can try and read the
+ # entire thing exactly
my $payload = read_all($sock, $payload_size);
try {