File: samplechat.pl

package info (click to toggle)
libnet-server-perl 2.006-1%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 896 kB
  • sloc: perl: 5,413; makefile: 2
file content (161 lines) | stat: -rwxr-xr-x 4,746 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/perl -w

=head1 NAME

samplechat.pl - Show a basic Net::Server::Multiplex sample

=head SERVER SYNOPIS

    # To run this in background daemon mode, listening on port 2000, do:

    samplechat.pl --setsid=1 --log_file=/tmp/samplechat.log --pid_file=/tmp/samplechat.pid --port=2000

    # To turn off the daemon, do:

    kill `cat /tmp/samplechat.pid`;

=head CLIENT SYNOPIS

    # from a terminal type

    telnet localhost 2000

    # you will then be in a echo server.

=head DESCRIPTION

This example demonstrates some of the features of Net::Server::Multiplex

=cut

package SampleChatServer;

use strict;
use base qw(Net::Server::Multiplex);

__PACKAGE__->run();
exit;

###----------------------------------------------------------------###

# Demonstrate a Net::Server style hook
sub allow_deny_hook {
    my $self = shift;
    my $prop = $self->{server};
    my $sock = $prop->{client};

    return 1 if $prop->{peeraddr} =~ /^127\./;
    return 0;
}


# Another Net::Server style hook
sub request_denied_hook {
    print "Go away!\n";
    print STDERR "DEBUG: Client denied!\n";
}


# IO::Multiplex style callback hook
sub mux_connection {
    my $self = shift;
    my $mux  = shift;
    my $fh   = shift;
    my $peer = $self->{peeraddr};
    # Net::Server stores a connection counter in the {requests} field.
    $self->{id} = $self->{net_server}->{server}->{requests};
    # Keep some values that I might need while the {server}
    # property hash still contains the current client info
    # and stash them in my own object hash.
    $self->{peerport} = $self->{net_server}->{server}->{peerport};
    # Net::Server directs STDERR to the log_file
    print STDERR "DEBUG: Client [$peer] (id $self->{id}) just connected...\n";
    # Notify everyone that the client arrived
    $self->broadcast($mux,"JOIN: (#$self->{id}) from $peer\r\n");
    # STDOUT is tie'd to the correct IO::Multiplex handle
    print "Welcome, you are number $self->{id} to connect.\r\n";
    # Try out the timeout feature of IO::Multiplex
    $mux->set_timeout($fh, undef);
    $mux->set_timeout($fh, 20);
    # This is my state and will be unique to this connection
    $self->{state} = "junior";
}


# If this callback is ever hooked, then the mux_connection callback
# is guaranteed to have already been run once (if defined).
sub mux_input {
    my $self = shift;
    my $mux  = shift;
    my $fh   = shift;
    my $in_ref = shift;  # Scalar reference to the input
    my $peer = $self->{peeraddr};
    my $id   = $self->{id};

    print STDERR "DEBUG: input from [$peer] ready for consuming.\n";
    # Process each line in the input, leaving partial lines
    # in the input buffer
    while ($$in_ref =~ s/^(.*?)\r?\n//) {
        next unless $1;
        my $message = "[$id - $peer] $1\r\n";
        $self->broadcast($mux, $message);
        print " - sent ".(length $message)." byte message\r\n";
    }
    if ($self->{state} eq "senior") {
        $mux->set_timeout($fh, undef);
        $mux->set_timeout($fh, 40);
    }
}


# It is possible that this callback will be called even
# if mux_connection or mux_input were never called.  This
# occurs when allow_deny or allow_deny_hook fails to
# authorize the client.  The callback object will be the
# default listen object instead of a client unique object.
# However, both object should contain the $self->{net_server}
# key pointing to the original Net::Server object.
sub mux_close {
    my $self = shift;
    my $mux  = shift;
    my $fh   = shift;
    my $peer = $self->{peeraddr};
    # If mux_connection has actually been run
    if (exists $self->{id}) {
        $self->broadcast($mux,"LEFT: (#$self->{id}) from $peer\r\n");
        print STDERR "DEBUG: Client [$peer] (id $self->{id}) closed connection!\n";
    }
}


# This callback will happen when the mux->set_timeout expires.
sub mux_timeout {
    my $self = shift;
    my $mux  = shift;
    my $fh   = shift;
    print STDERR "DEBUG: HEARTBEAT!\n";
    if ($self->{state} eq "junior") {
        print "Whoa, you must have a lot of patience.  You have been upgraded.\r\n";
        $self->{state} = "senior";
    } elsif ($self->{state} eq "senior") {
        print "If you don't want to talk then you should leave. *BYE*\r\n";
        close(STDOUT);
    }
    $mux->set_timeout($fh, undef);
    $mux->set_timeout($fh, 40);
}


# Routine to send a message to all clients in a mux.
sub broadcast {
    my $self = shift;
    my $mux  = shift;
    my $msg  = shift;
    foreach my $fh ($mux->handles) {
        # NOTE: All the client unique objects can be found at
        # $mux->{_fhs}->{$fh}->{object}
        # In this example, the {id} would be
        #   $mux->{_fhs}->{$fh}->{object}->{id}
        print $fh $msg;
    }
}