Net-Clacks

 view release on metacpan or  search on metacpan

lib/Net/Clacks/Server.pm  view on Meta::CPAN

                    $self->_safeCloseSocket($msocket);
                    return;
                }
            }

            $msocket->blocking(0);
            #binmode($msocket, ':bytes');
            my %tmp = (
                buffer  => '',
                charbuffer => [],
                listening => {},
                socket => $msocket,
                lastping => $now,
                mirror => 0,
                outbuffer => "CLACKS PageCamel $VERSION in interclacks client mode\r\n" .  # Tell the server we are using PageCamel Interclacks...
                             "OVERHEAD A " . $self->{authtoken} . "\r\n" .              # ...send Auth token
                             "OVERHEAD I 1\r\n",                                        # ...and turn interclacks master mode ON on remote side
                clientinfo => 'Interclacks link',
                client_timeoffset => 0,
                interclacks => 1,
                interclacksclient => 1,
                lastinterclacksping => $now,
                lastmessage => $now,
                authtimeout => $now + $self->{config}->{authtimeout},
                authok => 0,
                failtime => 0,
                writefailtime => 0,  # streak-start time for stalled writes; 0 = no streak in progress
                outmessages => [],
                inmessages => [],
                messagedelay => 0,
                inmessagedelay => 0,
                outmessagedelay => 0,
                permissions => {
                    read => 1,
                    write => 1,
                    manage => 1,
                    interclacks => 1,
                },
            );

            if(defined($self->{config}->{master}->{ip})) {
                $tmp{host} = $self->{config}->{master}->{ip}->[0];
                $tmp{port} = $self->{config}->{master}->{port};
            }
            $self->{clients}->{$mcid} = \%tmp;
            $msocket->_setClientID($mcid);
            $self->{selector}->add($msocket);

            $self->{workCount}++;
        }
    }
    return;
}

sub _addNewClients($self) {
    my $now = $self->_getTime();
    foreach my $tcpsocket (@{$self->{tcpsockets}}) {
        # Drain the listen queue rather than accepting one connection per iteration.
        # The listener is non-blocking, so accept() returns undef once the queue is empty.
        # This prevents a burst of connects from being rejected at the kernel level when
        # the backlog fills up while the main loop is busy elsewhere.
        my $acceptedThisCycle = 0;
        while(1) {
            # Hard cap to keep one rogue burst from monopolising the loop and starving
            # existing clients. Any remaining pending connects will be picked up in the
            # next runOnce() iteration.
            last if($acceptedThisCycle >= 64);

            my $clientsocket = $tcpsocket->accept;
            if(!defined($clientsocket)) {
                # EAGAIN/EWOULDBLOCK (no more pending) or a transient error like
                # ECONNABORTED (peer RST between the kernel queueing the connection
                # and our accept). Either way, stop draining this listener.
                last;
            }
            $acceptedThisCycle++;

            $clientsocket->blocking(0);

            # Build a guaranteed-unique CID. The previous "$now:$rand(1_000_000)" scheme
            # had a 50% birthday collision chance after ~1180 connects in the same
            # second, and TCP CIDs based on $peerhost:$peerport collide whenever the
            # kernel reuses an ephemeral port. A process-monotonic serial fixes both.
            my $serial = $self->_nextClientSerial();
            my ($cid, $chost, $cport);
            if(ref $tcpsocket eq 'IO::Socket::UNIX') {
                $chost = 'unixdomainsocket';
                $cport = $now . ':' . $serial;
            } else {
                ($chost, $cport) = ($clientsocket->peerhost, $clientsocket->peerport);
                # Append the serial so a reused ephemeral port can never alias an
                # existing or recently-disconnected client.
                $cport .= ':' . $serial;
            }
            $cid = "$chost:$cport";
            print "Got a new client $cid!\n";
            foreach my $debugcid (keys %{$self->{clients}}) {
                if($self->{clients}->{$debugcid}->{mirror}) {
                    $self->{clients}->{$debugcid}->{outbuffer} .= "DEBUG CONNECTED=" . $cid . "\r\n";
                }
            }

            if(ref $clientsocket ne 'IO::Socket::UNIX') {
                # ONLY USE SSL WHEN RUNNING OVER THE NETWORK
                # There is simply no point in running it over a local socket.
                my $encrypted = IO::Socket::SSL->start_SSL($clientsocket,
                                                           SSL_server => 1,
                                                           SSL_cert_file => $self->{config}->{ssl}->{cert},
                                                           SSL_key_file => $self->{config}->{ssl}->{key},
                                                           SSL_cipher_list => 'ALL:!ADH:!RC4:+HIGH:+MEDIUM:!LOW:!SSLv2:!SSLv3!EXPORT',
                                                           SSL_create_ctx_callback => sub {
                                                                my $ctx = shift;

                                                                # Enable workarounds for broken clients
                                                                Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL); ## no critic (Subroutines::ProhibitAmpersandSigils)

                                                                # Disable session resumption completely
                                                                Net::SSLeay::CTX_set_session_cache_mode($ctx, $SSL_SESS_CACHE_OFF);

                                                                # Disable session tickets
                                                                Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_NO_TICKET); ## no critic (Subroutines::ProhibitAmpersandSigils)

lib/Net/Clacks/Server.pm  view on Meta::CPAN

sub _handleMessageDirect($self, $cid, $inmsg) {
    if($inmsg =~ /^NOTIFY\ (.*)/) {
        return true unless($self->_requirePermission($cid, 'write'));
        my %tmp = (
            sender => $cid,
            type => 'NOTIFY',
            name => $1,
        );
        push @{$self->{outbox}}, \%tmp;
    } elsif($inmsg =~ /^SET\ (.+?)\=(.*)/) {
        return true unless($self->_requirePermission($cid, 'write'));
        my %tmp = (
            sender => $cid,
            type => 'SET',
            name => $1,
            value => $2,
        );
        push @{$self->{outbox}}, \%tmp;
    } else {
        # "not handled in this sub"
        return false;
    }

    return true;
}

1;
__END__

=head1 NAME

Net::Clacks::Server - server for CLACKS interprocess messaging

=head1 SYNOPSIS

  use Net::Clacks::Server;



=head1 DESCRIPTION

This implements the server for the CLACKS interprocess messaging protocol. It supports Interclacks mode,
for a master/client server architecture.

=head2 new

Create a new instance.

=head2 init

DEPRECATED: Initialize server instance (required before running). This is now a dummy function that will show a deprecation warning and return.
Initialization is now done automatically when calling run().

=head2 run

Run the server instance in it's own event loop. Only returns when server is shutdown.

=head2 runOnce

Run through the event loop once. This allows you to use your own programs event loop, and call runOnce a couple of times per second. It is a good idea to call runShutdown() to cleanly
disconnect clients before exiting your program. runOnce() returns a "work count" number, on which you *may* decide on how busy the server is and when to call runOnce() next.

=head2 runShutdown

Shuts down all connections. This is called automatically if you use run(), but not if you use runOnce()

=head1 IMPORTANT NOTE

Please make sure and read the documentations for L<Net::Clacks> as it contains important information
pertaining to upgrades and general changes!

=head1 AUTHOR

Rene Schickbauer, E<lt>cavac@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008-2024 Rene Schickbauer

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.

=cut



( run in 1.789 second using v1.01-cache-2.11-cpan-6aa56a78535 )