aboutsummaryrefslogtreecommitdiff
path: root/lib/Arctica
diff options
context:
space:
mode:
authorGZNGET FOSS Team <opensource@gznianguan.com>2016-09-06 15:46:45 +0200
committerMike Gabriel <mike.gabriel@das-netzwerkteam.de>2016-09-06 15:46:45 +0200
commit6a14d487a699eaa6048b97fd9c75b14cb61d3e3e (patch)
tree0152395b0c09a9a63be4c1d1e00658663a59b43d /lib/Arctica
downloadperl-Arctica-Core-JABus-Socket-6a14d487a699eaa6048b97fd9c75b14cb61d3e3e.tar.gz
perl-Arctica-Core-JABus-Socket-6a14d487a699eaa6048b97fd9c75b14cb61d3e3e.tar.bz2
perl-Arctica-Core-JABus-Socket-6a14d487a699eaa6048b97fd9c75b14cb61d3e3e.zip
initial Arctica JABus implementation
Diffstat (limited to 'lib/Arctica')
-rw-r--r--lib/Arctica/Core/JABus/Socket.pm686
-rw-r--r--lib/Arctica/Core/JABus/Socket/RandomPortTCP.pm92
-rw-r--r--lib/Arctica/Core/JABus/Socket/Version.pm65
3 files changed, 843 insertions, 0 deletions
diff --git a/lib/Arctica/Core/JABus/Socket.pm b/lib/Arctica/Core/JABus/Socket.pm
new file mode 100644
index 0000000..f87c838
--- /dev/null
+++ b/lib/Arctica/Core/JABus/Socket.pm
@@ -0,0 +1,686 @@
+################################################################################
+# _____ _
+# |_ _| |_ ___
+# | | | ' \/ -_)
+# |_| |_||_\___|
+# _ _ ____ _ _
+# / \ _ __ ___| |_(_) ___ __ _ | _ \ _ __ ___ (_) ___ ___| |_
+# / _ \ | '__/ __| __| |/ __/ _` | | |_) | '__/ _ \| |/ _ \/ __| __|
+# / ___ \| | | (__| |_| | (_| (_| | | __/| | | (_) | | __/ (__| |_
+# /_/ \_\_| \___|\__|_|\___\__,_| |_| |_| \___// |\___|\___|\__|
+# |__/
+# The Arctica Modular Remote Computing Framework
+#
+################################################################################
+#
+# Copyright (C) 2015-2016 The Arctica Project
+# http://http://arctica-project.org/
+#
+# This code is dual licensed: strictly GPL-2 or AGPL-3+
+#
+# GPL-2
+# -----
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+#
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# AGPL-3+
+# -------
+# This programm is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This programm is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Copyright (C) 2015-2016 Guangzhou Nianguan Electronics Technology Co.Ltd.
+# <opensource@gznianguan.com>
+# Copyright (C) 2015-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+#
+################################################################################
+package Arctica::Core::JABus::Socket;
+use strict;
+use Exporter qw(import);
+#use Glib 'TRUE', 'FALSE';
+use Data::Dumper;
+use JSON;# Should we use the OO style apporach?
+use Arctica::Core::eventInit qw( genARandom BugOUT );
+use IO::Socket::UNIX qw( SOCK_STREAM SOMAXCONN );
+# Be very selective about what (if any) gets exported by default:
+our @EXPORT = qw(genARandom);
+# And be mindfull of what we lett the caller request here too:
+our @EXPORT_OK = qw( BugOUT bugOutCfg );
+
+my $arctica_core_object;
+
+# * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE *
+# MISSING A BUNCH OF HOOKS, SANITATION AND PROPPER AUTHENTICATION FOR ALL REMOTE
+# AND LOCAL TCP SOCKETS. (relatively simpel apporach will be attached soon)
+# PS! DON'T FORGET STRICT FILE PREMS FOR SOCKETS ETC....
+# ANTICIPATING SUNSET WEEK 34....
+# * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE *
+# DIE on obvious developer mistakes.... WARN on stuff that could potentially
+# happen dynamically during runtime.
+
+################################################################################
+# Are we even using this at all....?!?!
+# Maybe later? For now we're just leeping it here as a reminder...
+#
+# EVERY CONF VALUE THAT IS READ ONLY (RO) only need only have two pieces
+# Of information "ro => 1," and "value => 'what ever'".
+# Any value that may be set by the application developer need to have a
+# sanitation routine attached to it, be it one a standart Arctica one,
+# or a custom private one. It the module/lib in question is the only use
+# case for a particular rule. Duplicate the standard sanitation function and
+# clear out the standard rules and attach a "priv_saneconf" at the bottom of
+# the code section of this file. If your "nonstandard" sanitation rule fits on
+# a line or so... you may use an anonymus sub.
+# the 'critical' value determin if a sanitation failure should result in death
+# or simple failure to set the unsanitized value.
+my %_conf_template = (
+ dval1 => {
+ ro => 0,
+ sanitation => sub {return $_[0];},
+ critical => 0,
+ value => 'something default'
+ },
+);
+#
+################################################################################
+
+sub new {
+ BugOUT(9,"JABus Socket new->ENTER");
+ my $class_name = $_[0];# Be EXPLICIT!! DON'T SHIFT OR "@_";
+ $arctica_core_object = $_[1];
+ my $the_tmpdir = $arctica_core_object->{'a_dirs'}{'tmp_adir'};
+ my $dev_conf = $_[2];
+ my $socket_destination = lc($dev_conf->{'destination'});
+ my $S_or_C;
+ my $socket_type = lc($dev_conf->{'type'});
+ if ($dev_conf->{'is_server'} eq 1) {
+ $S_or_C = "Server";
+ } elsif ($dev_conf->{'is_client'} eq 1) {
+ $S_or_C = "Client";
+ } elsif (($dev_conf->{'is_server'} eq 1) and ($dev_conf->{'is_client'} eq 1)) {
+ die("same socket object can't be both server and client!");
+ } else {
+ die("socket 'is_client' or 'is_server' must be set!");
+ }
+ unless (($socket_destination eq 'local') or ($socket_destination eq 'remote')) {
+ die("socket destination can only be 'local' or 'remote'!");
+ }
+ BugOUT(2,"Creating new socket object");
+ my %conf = %_conf_template;
+ my $self = {
+ type => $socket_type,
+ destination => $socket_destination,
+ conf => \%conf,# Change THIS LATER TO Make COPY of %conf?
+ isArctica => 1, # Declare that this is a Arctica "something"
+ aobject_name => "JABus_Socket_$S_or_C",
+ };
+ if ($dev_conf->{'hooks'}) {
+ $self->{'hooks'} = $dev_conf->{'hooks'};
+ }
+ $self->{'declare_id'} = $arctica_core_object->{'AExecDeclaration'};
+ if ($dev_conf->{'handle_in_solo'} and $dev_conf->{'handle_in_dispatc'}) {
+ die("JABus::Server: solo and dispatch at the same time? Not ok!");
+ } elsif ($dev_conf->{'handle_in_solo'}) {
+ $self->{'handle_in_solo'} = $dev_conf->{'handle_in_solo'};
+ } elsif ($dev_conf->{'handle_in_dispatch'}) {
+ $self->{'handle_in_dispatch'} = $dev_conf->{'handle_in_dispatch'};
+ }
+
+ unless ($self->{'handle_in_dispatch'} or $self->{'handle_in_solo'}) {
+ die("You need to define something for handle_in_dispatch or handle_in_solo");
+ }
+
+ if ($S_or_C eq "Server") {
+ $self->{'_socket_id'} = genARandom('id');
+ BugOUT(1,"Server SocketID: $self->{'_socket_id'}");
+ } elsif ($S_or_C eq "Client") {
+ if ($dev_conf->{'connect_to'}) {# ADD SANITATION HERE!!!!
+ $self->{'_socket_id'} = $dev_conf->{'connect_to'};
+ BugOUT(1,"Client SocketID: $self->{'_socket_id'}");
+ }
+ }
+
+ bless($self, $class_name);
+ if ($S_or_C eq "Server") {
+ BugOUT(1,"Initiating Server...");
+ # TCP STUFF GOES HERE ON NEXT REWRITE!
+ # ONLY USED FOR CLIENT OS WITHOUT UNIX SOCKET SUPPORT.
+ if ($socket_type eq "unix") {
+ my $tmp_soc_dir;
+ if ($socket_destination eq "local") {
+ $tmp_soc_dir = "$the_tmpdir/soc/local";
+ } elsif ($socket_destination eq "remote") {
+ $tmp_soc_dir = "$the_tmpdir/soc/remote/out";
+ } else {
+ die("There must be a hole in the fabric of time and space!");
+ }
+ unless (-d $tmp_soc_dir) {
+ die("JABus::Socket expects tmp dirs to be present.");
+ }
+
+ $self->{'s_or_c'} = "Server";
+ $self->{'the_socket_path'} = "$tmp_soc_dir/$self->{'_socket_id'}.sock";
+ $self->{'the_socket'} = IO::Socket::UNIX->new(
+ Local => $self->{'the_socket_path'},# do something "smart" here!
+ Type => SOCK_STREAM,
+ Reuse => 1,
+ Timeout => 5,
+ Listen => SOMAXCONN);
+ if (defined $self->{'the_socket'}) {
+ # Hand it over to a watcher...
+ $self->{'the_fileno'} = fileno($self->{'the_socket'});
+ $self->{'watcher'} = Glib::IO->add_watch(
+ $self->{'the_fileno'}, 'in',
+ sub {\$self->_server_accept_conn();},
+ $self->{'the_socket'});
+ BugOUT(1,"Initiation complete!");
+ } else {
+ die("Unable to initiate socket: $self->{'_socket_id'} ($tmp_soc_dir)");# DO SOMETHING ELSE HERE!
+ }
+ }
+ } elsif ($S_or_C eq "Client") {
+ BugOUT(1,"Initiating Client..");
+ # TCP STUFF GOES HERE ON NEXT REWRITE!
+ # ONLY USED FOR CLIENT OS WITHOUT UNIX SOCKET SUPPORT.
+ if ($socket_type eq "unix") {
+ my $tmp_soc_dir;
+ if ($socket_destination eq "local") {
+ $tmp_soc_dir = "$the_tmpdir/soc/local";
+ } elsif ($socket_destination eq "remote") {
+ $tmp_soc_dir = "$the_tmpdir/soc/remote/in";
+ } else {
+ die("There must be a hole in the fabric of time and space!");
+ }
+ unless (-d $tmp_soc_dir) {
+ die("JABus::Socket expects tmp dirs to be present. ($tmp_soc_dir)");
+ }
+
+ $self->{'s_or_c'} = "Client";
+ $self->{'the_socket_path'} = "$tmp_soc_dir/$self->{'_socket_id'}.sock";
+ $self->{'the_socket'} = IO::Socket::UNIX->new(
+ Peer => $self->{'the_socket_path'},
+ Type => SOCK_STREAM,
+ Timeout => 5 );
+ if (defined $self->{'the_socket'}) {
+ $self->{'the_socket'}->autoflush(1);
+ # Hand it over to a watcher...
+ $self->{'the_fileno'} = fileno($self->{'the_socket'});# do we ever really use this?
+ $self->{'watcher'} = Glib::IO->add_watch (
+ $self->{'the_fileno'},
+ ['in', 'hup', 'err'],
+ sub {\$self->_client_handle_conn($_[1])},
+ $self->{'the_socket'});
+
+ # REMOVE THE FOLLOWING LINE... INSERT AUTH STUFFS HERE
+ if ($self->{'handle_in_solo'}) {
+ $self->_client_send({
+ 'JAB' => 'auth',
+ 'declare_id' => $self->{'declare_id'},
+ 'handler_type' => 'solo',
+ 'auth_key' => 0,
+ });
+ } elsif ($self->{'handle_in_dispatch'}) {
+ my %to_send;
+ foreach my $hidp_key (keys $self->{'handle_in_dispatch'}) {#do some filtering here?!
+# print "\t\tKEY:\t$hidp_key\n";
+ $to_send{$hidp_key} = 1;
+ }
+ $self->_client_send({
+ 'JAB' => 'auth',
+ 'declare_id' => $self->{'declare_id'},
+ 'handler_type' => 'dispatch',
+ 'dispatch_list' => \%to_send,
+ 'auth_key' => 0,
+ });
+ } else {
+ die("THIS SHOULD NEVER HAPPEN");
+ }
+
+
+ BugOUT(1,"Initiation complete!");
+ } else {
+ die("Unable to initiate socket: $self->{'_socket_id'} ($tmp_soc_dir)");# DO SOMETHING ELSE HERE!
+ }
+ }
+ }
+
+ $arctica_core_object->{'aobj'}{'JABus'}{$S_or_C}{$self->{'_socket_id'}}
+ = \$self;
+
+ BugOUT(9,"JABus Socket new->DONE");
+
+ return $self;
+}
+
+#sub send {
+# BugOUT(9,"JABus::Socket Server send()->ENTER");
+# my $self = $_[0];
+# my $client_id = $_[1];
+# my $data_to_send = $_[2];
+# my $json_data = encode_json($data_to_send);
+# if ($self->{'clients'}{$client_id}{'io_obj'}) {
+# my $bytes_written
+# = syswrite($self->{'clients'}{$client_id}{'io_obj'},
+# $json_data)
+# or warn("Error while trying to send to client ($!)");
+# $self->{'clients'}{$client_id}{'bytes_written'}+=$bytes_written;
+# $self->{'total_bytes_written'} += $bytes_written;
+# BugOUT(8,"JABus::Socket Server Send->JAB Sent...");
+# }
+# BugOUT(9,"JABus::Socket Server send()->DONE");
+#}
+
+sub server_send {
+ BugOUT(9,"JABus::Socket server_send()->ENTER");
+ my $self = $_[0];
+ my $client_id = $_[1];
+ if ($self->{'clients'}{$client_id}{'status'}{'auth'} eq 1) {
+ if ($self->{'clients'}{$client_id}{'handler_type'} eq 'solo') {
+ my $data_to_send = $_[2];
+ $self->_server_send($client_id,{
+ 'data' => $data_to_send,
+ 'JAB' => 'data'
+ });
+ } elsif ($self->{'clients'}{$client_id}{'handler_type'} eq 'dispatch') {
+ my $dispatch_to = lc($_[2]);
+# my $dispatch_data = $_[3];
+ if ($dispatch_to =~ /^([a-z0-9\_]{2,32})$/) {
+ $dispatch_to = $1;
+ if ($self->{'clients'}{$client_id}{'dispatch_list'}{$dispatch_to} eq 1) {
+ $self->_server_send($client_id,{
+ 'disp_to' => $dispatch_to,
+ 'data' => $_[3],
+ 'JAB' => 'data'
+ });
+ } else {
+ die("JABus::Socket server_send() '$dispatch_to' is valid dispatch alias");
+ }
+ } else {
+ die("JABus::Socket server_send() DISPATCH TO WHERE?!!?!");
+ }
+ } else {
+ die("THIS SHOULD NEVER HAPPEN!?!");
+ }
+ }
+ BugOUT(9,"JABus::Socket server_send()->DONE");
+}
+
+sub _server_send {
+ BugOUT(9,"JABus::Socket _server_send()->ENTER");
+ my $self = $_[0];
+ my $client_id = $_[1];
+
+ my $json_data;
+ eval {
+ $json_data = encode_json($_[2]);
+ } or warn("JABus::Socket _server_send() encode_json crapped it self!");
+
+ if ($self->{'clients'}{$client_id}{'io_obj'} and $json_data) {
+ my $bytes_written
+ = syswrite($self->{'clients'}{$client_id}{'io_obj'},
+ "$json_data\n")
+ or warn("Error while trying to send to client ($!)");
+
+ $self->{'clients'}{$client_id}{'bytes_written'}+=$bytes_written;
+ $self->{'total_bytes_written'} += $bytes_written;
+ BugOUT(8,"JABus::Socket Server Send->JAB Sent...");
+ }
+
+ BugOUT(9,"JABus::Socket _server_send()->DONE");
+}
+
+sub _server_accept_conn {
+ BugOUT(9,"JABus::Socket Server _accept_conn()->ENTER");
+ my $self = $_[0];
+
+ my $new_client_id = genARandom('id');
+ $self->{'clients'}{$new_client_id}{'io_obj'}
+ = $self->{'the_socket'}->accept()
+ or BugOUT(1,"Can't accept connection @_");
+ $self->{'clients'}{$new_client_id}{'auth'} = 0;
+ $self->{'clients'}{$new_client_id}{'io_obj'}->autoflush(1);
+ $self->{'clients'}{$new_client_id}{'watcher'} = Glib::IO->add_watch (
+ fileno( $self->{'clients'}{$new_client_id}{'io_obj'} ),
+ ['in', 'hup', 'err'],
+ sub {\$self->_server_handle_conn($new_client_id,$_[1])},
+ $self->{'clients'}{$new_client_id}{'io_obj'} );
+
+ BugOUT(9,"JABus::Socket Server _accept_conn()->DONE");
+ return 1;
+}
+
+sub _server_handle_conn {
+ BugOUT(9,"JABus Server _handle_conn()->ENTER");
+ my $self = $_[0];
+ my $client_id = $_[1];
+ my $client_conn_cond = $_[2];
+
+ if ($client_conn_cond >= 'hup' or $client_conn_cond >= 'err') {
+ BugOUT(9,"JABus Server _handle_conn()->ERRHUP!");
+ $self->_server_terminate_client_conn($client_id);
+ BugOUT(9,"JABus Server _handle_conn()->DONE!");
+ return 0;
+
+ } elsif ( $client_conn_cond >= 'in' ) {
+ if ($self->{'clients'}{$client_id}{'io_obj'}) {
+ my $bytes_read = sysread($self->{'clients'}{$client_id}{'io_obj'},my $in_data,16384);
+#print "IND:\n$in_data\n\n";
+ $self->{'total_bytes_read'} += $bytes_read;
+ $self->{'clients'}{$client_id}{'bytes_read'}
+ += $bytes_read;
+
+foreach my $in_data_line (split(/\n/,$in_data)) {
+ $in_data_line =~ s/^\s*//g;
+ $in_data_line =~ s/\s*$//g;
+ if ($in_data_line =~ /JAB/) {
+
+ my $jData;
+ eval {
+ $jData = decode_json($in_data_line);
+ } or warn("JABus Server _handle_conn()->DONE (Got some garbage instead of JSON!)");
+
+
+ if ($jData) {
+ if ($self->{'clients'}{$client_id}{'status'}{'auth'} eq 1) {
+ if ($self->{'handle_in_solo'}) {
+ BugOUT(9,"JABus::Socket _server_handle_conn()->Got JSON for solo!");
+
+ $self->{'handle_in_solo'}->($jData->{'data'},
+ sub {\$self->server_send($client_id,$_[0],$_[1]);});
+
+ } elsif ($self->{'handle_in_dispatch'}) {
+ BugOUT(9,"JABus::Socket _server_handle_conn()->Got JSON for dispatch ($jData->{'disp_to'})!");
+# print "DISPATCHDATA:\n",Dumper($jData);
+ if ($self->{'handle_in_dispatch'}{$jData->{'disp_to'}}) {
+ $self->{'handle_in_dispatch'}{$jData->{'disp_to'}}($jData->{'data'}, sub {\$self->server_send($client_id,$_[0],$_[1]);});
+ } else {
+ die("Didn't we send over a list of valid options? WTF?");
+ }
+ }
+ } else {
+ my $server_handler_type;
+ if ($self->{'handle_in_solo'}) {
+ $server_handler_type = "solo";
+ } elsif ($self->{'handle_in_dispatch'}) {
+ $server_handler_type = "dispatch";
+ } else {
+ die("THIS SHOULD NEVER HAPPEN");
+ }
+ BugOUT(9,"JABus Server _handle_conn()-> PRE AUTH JSON...");
+# Client and server are no longer required to be same input handler type....
+# if (($jData->{'handler_type'} eq "solo") and $self->{'handle_in_solo'}) {
+# # MAY WANT TO DO SOMETHING HERE!?} elsif (($jData->{'handler_type'} eq "dispatch") and $self->{'handle_in_dispatch'}) {
+# # MAY WANT TO DO SOMETHING HERE!?} else {
+# warn("JABus Server _handle_conn()-> Client handler type is $jData->{'handler_type'}... but we are not...!");
+# $self->_server_terminate_client_conn($client_id);
+# return 0;
+# }
+
+ if (($self->{'type'} eq "unix") and ($self->{'destination'} eq "local")) {
+ # Accepting connections should probably move to a sub func
+ $self->{'clients'}{$client_id}{'status'}{'auth'} = 1;
+ $self->{'clients'}{$client_id}{'declared_id'} = $jData->{'declare_id'};
+
+ $self->{'clients'}{$client_id}{'handler_type'} = $jData->{'handler_type'};
+ if ($jData->{'handler_type'} eq "dispatch") {
+# print "DUMPYO:\n",Dumper($jData->{'dispatch_list'}),"\n\n";
+ $self->{'clients'}{$client_id}{'dispatch_list'} = $jData->{'dispatch_list'};
+ # add sanitation of incomming list
+ }
+
+ $self->_server_send($client_id,{
+ 'auth' => 1,
+ 'JAB' => 'auth',
+ 'server_declare_id' => $self->{'declare_id'},
+ 'server_handler_type' => $server_handler_type,
+ });
+ } else {
+ if (lenght($self->{'auth_key'}) > 30) {
+
+ } else {
+ $self->_server_terminate_client_conn($client_id);
+ return 0;
+ }
+ }
+
+
+ }
+ } else {
+ if ($self->{'clients'}{$client_id}{'status'}{'auth'} eq 1) {
+ warn("JABus Server _handle_conn()-> Got the GARBAGE after ok auth.... ?!");
+ } else {
+ BugOUT(9,"JABus Server _handle_conn()->Probably something else tickeling our sockets...");
+ $self->_server_terminate_client_conn($client_id);
+ BugOUT(8,"OR IS IT!?");
+ return 0;
+ }
+ }
+
+}}
+ return 1;
+ } else {
+ warn("JABus Server _handle_conn()->DONE (client_fh problem?!)");
+ $self->_server_terminate_client_conn($client_id);
+ return 0;
+ }
+ } else {
+ warn("JABus Server _handle_conn()->DONE (Weird exception?!)");
+ $self->_server_terminate_client_conn($client_id);
+ return 0;
+ }
+}
+
+sub _server_terminate_client_conn {
+ # also serves as a general cleanup of failed or partialy initiated connections
+ my $self = $_[0];
+ my $client_id = $_[1];
+ if ($self->{'clients'}{$client_id}) {
+ if ($self->{'clients'}{$client_id}{'watcher'}) {
+ Glib::Source->remove($self->{'clients'}{$client_id}{'watcher'});
+ }
+ if ($self->{'clients'}{$client_id}{'io_obj'}) {
+ if ($self->{'clients'}{$client_id}{'status'}{'auth'} eq 1) {
+ # send clean termination message
+ }
+ $self->{'clients'}{$client_id}{'io_obj'}->close;
+ $self->{'clients'}{$client_id}{'io_obj'} = undef;
+ }
+ delete $self->{'clients'}{$client_id};
+ }
+
+ return 1;
+}
+
+sub _client_handle_conn {
+ BugOUT(9,"JABus::Socket _client_handle_conn()->ENTER");
+ my $self = $_[0];
+ my $connection_cond = $_[1];
+
+ if ($connection_cond >= 'hup' or $connection_cond >= 'err') {
+ BugOUT(9,"JABus::Socket _client_handle_conn()->ERRHUP!");
+ $self->_client_terminate_conn();
+ BugOUT(9,"JABus::Socket _client_handle_conn()->DONE!");
+ return 0;
+ } elsif ( $connection_cond >= 'in' ) {
+ if ($self->{'the_socket'}) {
+ my $bytes_read = sysread($self->{'the_socket'},my $in_data,16384);
+#print "IND:\n$in_data\n\n";
+ $self->{'bytes_read'} += $bytes_read;
+
+foreach my $in_data_line (split(/\n/,$in_data)) {
+ $in_data_line =~ s/^\s*//g;
+ $in_data_line =~ s/\s*$//g;
+ if ($in_data_line =~ /JAB/) {
+
+ my $jData;
+ eval {
+ $jData = decode_json($in_data_line);
+ } or warn("JABus _client_handle_conn()->DONE (Got some garbage instead of JSON!)");
+
+
+ if ($jData) {
+# print Dumper($jData);
+ if ($self->{'status'}{'auth'} eq 1) {
+ if ($self->{'handle_in_solo'}) {
+ BugOUT(9,"JABus::Socket _client_handle_conn()->Got JSON for solo!");
+ $self->{'handle_in_solo'}->($jData->{'data'}, sub {\$self->client_send($_[0],$_[1]);});
+ } elsif ($self->{'handle_in_dispatch'}) {
+ BugOUT(9,"JABus::Socket _client_handle_conn()->Got JSON for dispatch ($jData->{'disp_to'})!");
+# print "DISPATCHDATA:\n",Dumper($jData);
+ if ($self->{'handle_in_dispatch'}{$jData->{'disp_to'}}) {
+ $self->{'handle_in_dispatch'}{$jData->{'disp_to'}}($jData->{'data'}, sub {\$self->client_send($_[0],$_[1]);});
+ } else {
+ die("Didn't we send over a list of valid options? WTF?");
+ }
+ }
+ } else {
+ BugOUT(9,"JABus _client_handle_conn()-> PRE AUTH JSON...");
+ if ($jData->{'auth'} eq 1) {
+ BugOUT(9,"JABus _client_handle_conn()->AUTH OK! YAY!");
+ $self->{'status'}{'auth'} = 1;
+ $self->{'server_handler_type'} = $jData->{'server_handler_type'};
+ $self->{'server_declared_id'} = $jData->{'server_declare_id'};
+
+ if ($self->{'hooks'}{'on_ready'}) {
+ # ADD SOME HOOK STUFF HERE?!
+ $self->{'hooks'}{'on_ready'}($self->{'_socket_id'});# RETURN SOME OTHER VALUES?!
+ }
+ } else {
+ BugOUT(9,"JABus _client_handle_conn()-> AUTH NOT OK?!?! WTF?!");
+ $self->_client_terminate_conn();
+ }
+ }
+ }
+ #or warn("JABus::Socket _client_handle_conn()->DONE (Got some garbage instead of JSON!)");
+}}
+ return 1;
+ } else {
+ warn("JABus::Socket _client_handle_conn()->DONE (client_fh problem?!)");
+ $self->_client_terminate_conn();
+ return 0;
+ }
+ } else {
+ warn("JABus::Socket _client_handle_conn()->DONE (Weird exception?!)");
+ $self->_client_terminate_conn();
+ return 0;
+ }
+}
+
+sub _client_terminate_conn {
+ # also serves as a general cleanup of failed or partialy initiated connections
+ my $self = $_[0];
+ if ($self) {
+ if ($self->{'watcher'}) {
+ Glib::Source->remove($self->{'watcher'});
+ }
+ if ($self->{'the_socket'}) {
+ if ($self->{'status'}{'auth'} eq 1) {
+ # send clean termination message
+ }
+ $self->{'the_socket'}->close;
+ $self->{'the_socket'} = undef;
+ }
+ delete $arctica_core_object->{'aobj'}{'JABus'}{'Client'}{$self->{'_socket_id'}};
+ undef $self;
+ }
+
+ return 1;
+}
+
+sub client_send {
+ BugOUT(9,"JABus::Socket client_send()->ENTER");
+ my $self = $_[0];
+ if ($self->{'status'}{'auth'} eq 1) {
+ if ($self->{'server_handler_type'} eq 'solo') {
+ $self->_client_send({
+ 'data' => $_[1],
+ 'JAB' => 'data'
+ });
+ } elsif ($self->{'server_handler_type'} eq 'dispatch') {
+ my $dispatch_to = lc($_[1]);
+ if ($dispatch_to =~ /^([a-z0-9\_]{2,32})$/) {
+ $dispatch_to = $1;
+ $self->_client_send({
+ 'disp_to' => $dispatch_to,
+ 'data' => $_[2],
+ 'JAB' => 'data'
+ });
+ } else {
+ die("JABus::Socket client_send() DISPATCH TO WHERE?!!?!");
+ }
+ } else {
+ die("THIS SHOULD NEVER HAPPEN!?!");
+ }
+ }
+ BugOUT(9,"JABus::Socket client_send()->DONE");
+}
+
+
+
+sub _client_send {
+ BugOUT(9,"JABus::Socket _client_send()->ENTER");
+ my $self = $_[0];
+ my $data_to_send = $_[1];
+
+ my $json_data;
+ eval {
+ $json_data = encode_json($data_to_send);
+ } or warn("JABus::Socket _client_send() encode_json crapped it self!");
+
+ if ($self->{'the_socket'} and $json_data) {
+ my $bytes_written = syswrite($self->{'the_socket'}, "$json_data\n")
+ or warn("Error while trying to send to server ($!)");
+ $self->{'bytes_written'}+=$bytes_written;
+ BugOUT(8,"JABus::Socket _client_send()->JAB Sent...");
+ }
+
+ BugOUT(9,"JABus::Socket _client_send()->DONE");
+}
+
+
+sub DESTROY {
+ my $self = $_[0];
+ if (($self->{'s_or_c'} eq "Server") and (-e $self->{'the_socket_path'})) {
+ BugOUT(9,"JABus::Socket DESTROY socket file exists: $self->{'the_socket_path'}");
+ unlink($self->{'the_socket_path'}) or warn("JABus::Socket DESTROY unable to unlink socket file!");
+ }
+ warn("JABus::Socket Object $self->{'_socket_id'} ($self->{'s_or_c'}) DESTOYED");
+ return 0;
+}
+
+
+# REMOVE THIS GARBAGE?!?!?
+#sub server_drop_client {
+# return 1;
+#}
+#
+#sub close_socket {
+#
+# return 1;
+#}
+
+
+1;
diff --git a/lib/Arctica/Core/JABus/Socket/RandomPortTCP.pm b/lib/Arctica/Core/JABus/Socket/RandomPortTCP.pm
new file mode 100644
index 0000000..383c39f
--- /dev/null
+++ b/lib/Arctica/Core/JABus/Socket/RandomPortTCP.pm
@@ -0,0 +1,92 @@
+################################################################################
+# _____ _
+# |_ _| |_ ___
+# | | | ' \/ -_)
+# |_| |_||_\___|
+# _ _ ____ _ _
+# / \ _ __ ___| |_(_) ___ __ _ | _ \ _ __ ___ (_) ___ ___| |_
+# / _ \ | '__/ __| __| |/ __/ _` | | |_) | '__/ _ \| |/ _ \/ __| __|
+# / ___ \| | | (__| |_| | (_| (_| | | __/| | | (_) | | __/ (__| |_
+# /_/ \_\_| \___|\__|_|\___\__,_| |_| |_| \___// |\___|\___|\__|
+# |__/
+# The Arctica Modular Remote Computing Framework
+#
+################################################################################
+#
+# Copyright (C) 2015-2016 The Arctica Project
+# http://http://arctica-project.org/
+#
+# This code is dual licensed: strictly GPL-2 or AGPL-3+
+#
+# GPL-2
+# -----
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+#
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# AGPL-3+
+# -------
+# This programm is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This programm is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Copyright (C) 2015-2016 Guangzhou Nianguan Electronics Technology Co.Ltd.
+# <opensource@gznianguan.com>
+# Copyright (C) 2015-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+#
+################################################################################
+package Arctica::Core::JABus::Socket::RandomPortTCP;
+use strict;
+use Exporter qw(import);
+use IO::Socket::INET;
+# Be very selective about what (if any) gets exported by default:
+our @EXPORT = qw( getRandomPortTCP );
+# And be mindfull of what we lett the caller request here too:
+our @EXPORT_OK = qw( );
+
+sub getRandomPortTCP {
+ # Dirty little hack that gets you a random availalbe TCP port
+ # Its advisable to catch bind failure and request a new port
+ # in the unlikely event bind to port fails.
+ # Makes prediction based DoS harder and avoids a few other issues...
+ # Need to load these values from a config file in /etc/arctica/
+ my $portrange_min = 30000;
+ my $portrange_max = 50000;
+ my $attempt_max = 1000;
+ my $attempt_cnt = 0;
+ while ($attempt_cnt <= $attempt_max) {
+ my $random_port = int($portrange_min + rand($portrange_max - $portrange_min));
+ unless (IO::Socket::INET->new(
+ PeerAddr => 'localhost',
+ PeerPort => $random_port,
+ Proto => 'tcp')) {
+ return $random_port;
+ }
+ $attempt_cnt++;
+ }
+ return 0;
+}
+
+
diff --git a/lib/Arctica/Core/JABus/Socket/Version.pm b/lib/Arctica/Core/JABus/Socket/Version.pm
new file mode 100644
index 0000000..ac332f2
--- /dev/null
+++ b/lib/Arctica/Core/JABus/Socket/Version.pm
@@ -0,0 +1,65 @@
+################################################################################
+# _____ _
+# |_ _| |_ ___
+# | | | ' \/ -_)
+# |_| |_||_\___|
+# _ _ ____ _ _
+# / \ _ __ ___| |_(_) ___ __ _ | _ \ _ __ ___ (_) ___ ___| |_
+# / _ \ | '__/ __| __| |/ __/ _` | | |_) | '__/ _ \| |/ _ \/ __| __|
+# / ___ \| | | (__| |_| | (_| (_| | | __/| | | (_) | | __/ (__| |_
+# /_/ \_\_| \___|\__|_|\___\__,_| |_| |_| \___// |\___|\___|\__|
+# |__/
+# The Arctica Modular Remote Computing Framework
+#
+################################################################################
+#
+# Copyright (C) 2015-2016 The Arctica Project
+# http://http://arctica-project.org/
+#
+# This code is dual licensed: strictly GPL-2 or AGPL-3+
+#
+# GPL-2
+# -----
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+#
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# AGPL-3+
+# -------
+# This programm is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This programm is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# Copyright (C) 2015-2016 Guangzhou Nianguan Electronics Technology Co.Ltd.
+# <opensource@gznianguan.com>
+# Copyright (C) 2015-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
+#
+################################################################################
+package Arctica::Core::JABus::Socket::Version;
+use strict;
+
+use vars qw[$VERSION];
+
+$VERSION = '0.0.0.1';