File: 200_udp.t

package info (click to toggle)
libio-multiplex-perl 1.16-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 136 kB
  • sloc: perl: 568; makefile: 2
file content (173 lines) | stat: -rw-r--r-- 3,930 bytes parent folder | download | duplicates (4)
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
162
163
164
165
166
167
168
169
170
171
172
173
# Test using UDP with two IO::Multiplex
# servers communicating with each other.
# Assume no UDP packet loss on loopback.

# This script tests the following:
# 1) Sending packets using a connected UDP socket.
#    (connect() and send() syscalls)
# 2) Sending packets using unconnected UDP socket.
#    (sendto() syscall)
# 3) Receiving UDP packets.
#    (bind() and recv() syscalls)
# 4) The tied handle interface to send UDP data.
#    print $fh $UDP_data;
# 5) The mux_input interface for incoming UDP data.
#    (simple $$data scalar consumption)

use strict;
use Test;
use IO::Socket;
use IO::Multiplex;
use POSIX qw(ENOTCONN EDESTADDRREQ);

if($^O eq 'MSWin32')
{   no warnings;
    *ENOTCONN = sub() {10057};
}

$| = 1;
plan tests => 15;

# Create a recv()ing socket.
ok my $sock1 = new IO::Socket::INET
  LocalAddr => "127.0.0.1",
  Proto => "udp",
  or die $!;

my $magic_port = $sock1->sockport;

# Create connect()ed socket for send()ing.
ok my $sock2 = new IO::Socket::INET
  PeerAddr => "127.0.0.1",
  PeerPort => $magic_port,
  Proto => "udp",
  or die $!;

# Create a generic unconnected socket for sendto()ing.
ok my $sock3 = new IO::Socket::INET
  Proto => "udp"
  or die $!;

my $msg1 = "uno";
my $msg2 = "dos";
my $msg3 = "tres";
my $msg4 = "cuatro";
my $msg5 = "cinco";
my $msg6 = "seis";

my $pid = fork();
# Catch runaway processes just in case...
alarm(10);
$SIG{ALRM} = sub {
  die "[$$] Got bored";
};

if (!defined $pid) {
  ok 0;
  die "fork: $!";
}

if ($pid) {
  # Parent process
  # This will be the Pitcher IO::Multiplex server.
  my $plexer = new IO::Multiplex;

  $plexer->add($sock2);
  $plexer->add($sock3);
  $plexer->set_callback_object("Pitcher");
  # Set timer to do mux_timeout in 2 seconds
  $plexer->set_timeout($sock2, 2);
  $plexer->loop;
  ok 1;
  exit;
} else {
  # Child process
  # This will be the Catcher IO::Multiplex server.
  # (No talking allowed.)
  my $plexer = new IO::Multiplex;

  $plexer->add($sock1);
  $plexer->set_callback_object("Catcher");

  $plexer->loop;
  exit;
}

sub Pitcher::mux_timeout {
  my $self    = shift;
  my $mux     = shift;
  my $fh      = shift;
  if (fileno $fh == fileno $sock2) {
    ok 1;
    # Connected UDP socket should know where to send it
    print $fh $msg1;
    ok !$!;
  } elsif (fileno $fh == fileno $sock3) {
    ok 1;
    # Unconnected UDP socket should fail
    # when trying to send() a packet.
    $! = 0;
    print $fh $msg2;
    ok ($! == ENOTCONN || $! == EDESTADDRREQ)
      or warn "DEBUG: bang = [$!](".($!+0).")";

    # Grab the real peer destination.
    ok my $saddr = $mux->{_fhs}{$sock2}{udp_peer};

    # Unconnected UDP socket will sendto() just fine
    # but only with an explicit destination.
    ok send($fh, $msg3, 0, $saddr);
    ok !$!;
  } else {
    die "$$: Not my fh?";
  }
}

sub Pitcher::mux_input {
  my $package = shift;
  my $mux     = shift;
  my $fh      = shift;
  my $data    = shift;
  if (fileno $fh == fileno $sock2) {
    ok ($$data eq $msg2);
    $mux->set_timeout($sock3, 3);
  } elsif (fileno $fh == fileno $sock3) {
    if ($$data eq $msg4) {
      ok 1;
      # Even though this was the unconnected socket,
      # it should remember where the last packer came from.
      print $fh $msg5;
      ok !$!;
    } elsif ($$data eq $msg6) {
      # Yippy, caught the final packet
      ok 1;
      # All done
      $mux->endloop;
    } else {
      die "sock3 caught weird [$$data]";
    }
  } else {
    die "$$: Pitcher found something weird [$$data]";
  }
  $$data = "";
}

# Just bounce it back with one up
sub Catcher::mux_input {
  my $package = shift;
  my $mux     = shift;
  my $fh      = shift;
  my $data    = shift;
  if ($$data eq $msg1) {
    print $fh $msg2;
  } elsif ($$data eq $msg3) {
    print $fh $msg4;
  } elsif ($$data eq $msg5) {
    print $fh $msg6;
    # I'm done.
    $mux->endloop;
  } else {
    die "$$: Caught something weird [$$data]";
  }
  $$data = "";
}