| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
=pod |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Net::OSCAR::Connection -- individual Net::OSCAR service connection |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 VERSION |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
version 1.928 |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=cut |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
package Net::OSCAR::Connection; |
|
14
|
|
|
|
|
|
|
BEGIN { |
|
15
|
4
|
|
|
4
|
|
133
|
$Net::OSCAR::Connection::VERSION = '1.928'; |
|
16
|
|
|
|
|
|
|
} |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
$REVISION = '$Revision$'; |
|
19
|
|
|
|
|
|
|
|
|
20
|
4
|
|
|
4
|
|
24
|
use strict; |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
122
|
|
|
21
|
4
|
|
|
4
|
|
21
|
use Carp; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
359
|
|
|
22
|
4
|
|
|
4
|
|
23
|
use Socket; |
|
|
4
|
|
|
|
|
13
|
|
|
|
4
|
|
|
|
|
2704
|
|
|
23
|
4
|
|
|
4
|
|
3776
|
use Symbol; |
|
|
4
|
|
|
|
|
4262
|
|
|
|
4
|
|
|
|
|
298
|
|
|
24
|
4
|
|
|
4
|
|
27
|
use Digest::MD5; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
132
|
|
|
25
|
4
|
|
|
4
|
|
21
|
use Fcntl; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
19231
|
|
|
26
|
4
|
|
|
4
|
|
3631
|
use POSIX qw(:errno_h); |
|
|
4
|
|
|
|
|
32968
|
|
|
|
4
|
|
|
|
|
31
|
|
|
27
|
4
|
|
|
4
|
|
16833
|
use Scalar::Util qw(weaken); |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
211
|
|
|
28
|
4
|
|
|
4
|
|
23
|
use List::Util qw(max); |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
375
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
4
|
|
|
4
|
|
26
|
use Net::OSCAR::Common qw(:all); |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
1376
|
|
|
31
|
4
|
|
|
4
|
|
28
|
use Net::OSCAR::Constants; |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
502
|
|
|
32
|
4
|
|
|
4
|
|
23
|
use Net::OSCAR::Utility; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
436
|
|
|
33
|
4
|
|
|
4
|
|
20
|
use Net::OSCAR::TLV; |
|
|
4
|
|
|
|
|
16
|
|
|
|
4
|
|
|
|
|
182
|
|
|
34
|
4
|
|
|
4
|
|
4481
|
use Net::OSCAR::Callbacks; |
|
|
4
|
|
|
|
|
12
|
|
|
|
4
|
|
|
|
|
137
|
|
|
35
|
4
|
|
|
4
|
|
36
|
use Net::OSCAR::XML; |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
23774
|
|
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
if($^O eq "MSWin32") { |
|
38
|
|
|
|
|
|
|
eval '*F_GETFL = sub {0};'; |
|
39
|
|
|
|
|
|
|
eval '*F_SETFL = sub {0};'; |
|
40
|
|
|
|
|
|
|
eval '*O_NONBLOCK = sub {0}; '; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub new($@) { |
|
44
|
0
|
|
|
0
|
0
|
|
my($class, %data) = @_; |
|
45
|
0
|
|
0
|
|
|
|
$class = ref($class) || $class || "Net::OSCAR::Connection"; |
|
46
|
0
|
|
|
|
|
|
my $self = { %data }; |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Avoid circular references |
|
49
|
0
|
|
|
|
|
|
weaken($self->{session}); |
|
50
|
|
|
|
|
|
|
|
|
51
|
0
|
|
|
|
|
|
bless $self, $class; |
|
52
|
0
|
|
|
|
|
|
$self->{seqno} = 0; |
|
53
|
0
|
|
|
|
|
|
$self->{icq_seqno} = 0; |
|
54
|
0
|
|
|
|
|
|
$self->{outbuff} = ""; |
|
55
|
0
|
|
0
|
|
|
|
$self->{state} ||= "write"; |
|
56
|
0
|
0
|
|
|
|
|
$self->{paused} = 0 unless $self->{paused}; |
|
57
|
0
|
|
|
|
|
|
$self->{families} = {}; |
|
58
|
0
|
|
|
|
|
|
$self->{buffsize} = 65535; |
|
59
|
0
|
|
|
|
|
|
$self->{buffer} = \""; |
|
60
|
|
|
|
|
|
|
|
|
61
|
0
|
0
|
|
|
|
|
$self->connect($self->{peer}) if exists($self->{peer}); |
|
62
|
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
return $self; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub pause($) { |
|
67
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
68
|
0
|
|
0
|
|
|
|
$self->{pause_queue} ||= []; |
|
69
|
0
|
|
|
|
|
|
$self->{paused} = 1; |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub unpause($) { |
|
73
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
74
|
0
|
0
|
|
|
|
|
return unless $self->{paused}; |
|
75
|
0
|
|
|
|
|
|
$self->{paused} = 0; |
|
76
|
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_WARN, "Flushing pause queue"); |
|
78
|
0
|
|
|
|
|
|
foreach my $item(@{$self->{pause_queue}}) { |
|
|
0
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$self->log_printf(OSCAR_DBG_WARN, "Flushing SNAC 0x%04X/0x%04X", $item->{family}, $item->{subtype}); |
|
80
|
0
|
|
|
|
|
|
$self->snac_put(%$item); |
|
81
|
|
|
|
|
|
|
} |
|
82
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_WARN, "Pause queue flushed"); |
|
83
|
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
delete $self->{pause_queue}; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub proto_send($%) { |
|
88
|
0
|
|
|
0
|
0
|
|
my($self, %data) = @_; |
|
89
|
0
|
|
0
|
|
|
|
$data{protodata} ||= {}; |
|
90
|
|
|
|
|
|
|
|
|
91
|
0
|
|
|
|
|
|
my %snac = protobit_to_snac($data{protobit}); # or croak "Couldn't find protobit $data{protobit}"; |
|
92
|
0
|
0
|
|
|
|
|
confess "BAD SELF!" unless ref($self); |
|
93
|
0
|
0
|
|
|
|
|
confess "BAD DATA!" unless ref($data{protodata}); |
|
94
|
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
|
$snac{data} = protoparse($self->{session}, $data{protobit})->pack(%{$data{protodata}}); |
|
|
0
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
foreach (qw(reqdata reqid flags1 flags2)) { |
|
97
|
0
|
0
|
|
|
|
|
$snac{$_} = $data{$_} if exists($data{$_}); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
0
|
|
|
|
|
if(exists($snac{family})) { |
|
101
|
0
|
0
|
0
|
|
|
|
if($snac{family} == -1 and exists($data{family})) { |
|
102
|
0
|
|
|
|
|
|
$snac{family} = $data{family}; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
0
|
0
|
0
|
|
|
|
if($self->{paused} and !$data{nopause}) { |
|
106
|
0
|
|
|
|
|
|
$self->log_printf(OSCAR_DBG_WARN, "Adding SNAC 0x%04X/0x%04X to pause queue", $snac{family}, $snac{subtype}); |
|
107
|
0
|
|
|
|
|
|
push @{$self->{pause_queue}}, \%snac; |
|
|
0
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
} else { |
|
109
|
0
|
|
|
|
|
|
$self->log_printf(OSCAR_DBG_DEBUG, "Put SNAC 0x%04X/0x%04X: %s", $snac{family}, $snac{subtype}, $data{protobit}); |
|
110
|
0
|
|
|
|
|
|
$self->snac_put(%snac); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
} else { |
|
113
|
0
|
|
0
|
|
|
|
$snac{channel} ||= 0+FLAP_CHAN_SNAC; |
|
114
|
0
|
|
|
|
|
|
$self->log_printf(OSCAR_DBG_DEBUG, "Putting raw FLAP: %s", $data{protobit}); |
|
115
|
0
|
|
|
|
|
|
$self->flap_put($snac{data}, $snac{channel}); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub fileno($) { |
|
122
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
123
|
0
|
0
|
|
|
|
|
return undef unless $self->{socket}; |
|
124
|
0
|
|
|
|
|
|
return fileno $self->{socket}; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub flap_encode($$;$) { |
|
128
|
0
|
|
|
0
|
0
|
|
my ($self, $msg, $channel) = @_; |
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
|
0
|
|
|
|
$channel ||= FLAP_CHAN_SNAC; |
|
131
|
0
|
|
|
|
|
|
return protoparse($self->{session}, "flap")->pack( |
|
132
|
|
|
|
|
|
|
channel => $channel, |
|
133
|
|
|
|
|
|
|
seqno => ++$self->{seqno}, |
|
134
|
|
|
|
|
|
|
msg => $msg |
|
135
|
|
|
|
|
|
|
); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub write($$) { |
|
139
|
0
|
|
|
0
|
0
|
|
my($self, $data) = @_; |
|
140
|
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
my $had_outbuff = 1 if $self->{outbuff}; |
|
142
|
0
|
|
|
|
|
|
$self->{outbuff} .= $data; |
|
143
|
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
my $nchars = syswrite($self->{socket}, $self->{outbuff}, length($self->{outbuff})); |
|
145
|
0
|
0
|
|
|
|
|
if(!defined($nchars)) { |
|
146
|
0
|
0
|
|
|
|
|
return "" if $! == EAGAIN; |
|
147
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Couldn't write to socket: $!"); |
|
148
|
0
|
|
|
|
|
|
$self->{sockerr} = 1; |
|
149
|
0
|
|
|
|
|
|
$self->disconnect(); |
|
150
|
0
|
|
|
|
|
|
return undef; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
|
my $wrote = substr($self->{outbuff}, 0, $nchars, ""); |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
0
|
|
|
|
|
if($self->{outbuff}) { |
|
|
|
0
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Couldn't do complete write - had to buffer ", length($self->{outbuff}), " bytes."); |
|
157
|
0
|
|
|
|
|
|
$self->{state} = "readwrite"; |
|
158
|
0
|
|
|
|
|
|
$self->{session}->callback_connection_changed($self, "readwrite"); |
|
159
|
0
|
|
|
|
|
|
return 0; |
|
160
|
|
|
|
|
|
|
} elsif($had_outbuff) { |
|
161
|
0
|
|
|
|
|
|
$self->{state} = "read"; |
|
162
|
0
|
|
|
|
|
|
$self->{session}->callback_connection_changed($self, "read"); |
|
163
|
0
|
|
|
|
|
|
return 1; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
0
|
|
|
0
|
|
|
$self->log_print_cond(OSCAR_DBG_PACKETS, sub { "Put '", hexdump($wrote), "'" }); |
|
|
0
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
return 1; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub flap_put($;$$) { |
|
171
|
0
|
|
|
0
|
0
|
|
my($self, $msg, $channel) = @_; |
|
172
|
0
|
|
|
|
|
|
my $had_outbuff = 0; |
|
173
|
|
|
|
|
|
|
|
|
174
|
0
|
|
0
|
|
|
|
$channel ||= FLAP_CHAN_SNAC; |
|
175
|
|
|
|
|
|
|
|
|
176
|
0
|
0
|
0
|
|
|
|
return unless $self->{socket} and CORE::fileno($self->{socket}) and getpeername($self->{socket}); # and !$self->{socket}->error; |
|
|
|
|
0
|
|
|
|
|
|
177
|
|
|
|
|
|
|
|
|
178
|
0
|
0
|
|
|
|
|
$msg = $self->flap_encode($msg, $channel) if $msg; |
|
179
|
0
|
|
|
|
|
|
$self->write($msg); |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# We need to do non-buffered reading so that stdio's buffers don't screw up select, poll, etc. |
|
183
|
|
|
|
|
|
|
# Thus, for efficiency, we do our own buffering. |
|
184
|
|
|
|
|
|
|
# To prevent a single OSCAR conneciton from monopolizing processing time, for instance if it has |
|
185
|
|
|
|
|
|
|
# a flood of incoming data wide enough that we never run out of stuff to read, we'll only fill |
|
186
|
|
|
|
|
|
|
# the buffer once per call to process_one. |
|
187
|
|
|
|
|
|
|
# |
|
188
|
|
|
|
|
|
|
# no_reread value of 2 indicates that we should only read if we have to |
|
189
|
|
|
|
|
|
|
sub read($$;$) { |
|
190
|
0
|
|
|
0
|
0
|
|
my($self, $len, $no_reread) = @_; |
|
191
|
0
|
|
0
|
|
|
|
$no_reread ||= 0; |
|
192
|
|
|
|
|
|
|
|
|
193
|
0
|
|
0
|
|
|
|
$self->{buffsize} ||= $len; |
|
194
|
0
|
|
|
|
|
|
my $buffsize = $self->{buffsize}; |
|
195
|
0
|
0
|
|
|
|
|
$buffsize = $len if $len > $buffsize; |
|
196
|
0
|
|
|
|
|
|
my $readlen; |
|
197
|
0
|
0
|
|
|
|
|
if($no_reread == 2) { |
|
198
|
0
|
|
|
|
|
|
$readlen = $len - length(${$self->{buffer}}); |
|
|
0
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
} else { |
|
200
|
0
|
|
|
|
|
|
$readlen = $buffsize - length(${$self->{buffer}}); |
|
|
0
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
0
|
0
|
|
|
|
if($readlen > 0 and $no_reread != 1) { |
|
204
|
0
|
|
|
|
|
|
my $buffer = ""; |
|
205
|
0
|
|
|
|
|
|
my $nchars = sysread($self->{socket}, $buffer, $buffsize - length(${$self->{buffer}})); |
|
|
0
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
|
if(${$self->{buffer}}) { |
|
|
0
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
${$self->{buffer}} .= $buffer; |
|
|
0
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
} else { |
|
209
|
0
|
|
|
|
|
|
$self->{buffer} = \$buffer; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
0
|
0
|
0
|
|
|
|
if(!${$self->{buffer}} and !defined($nchars)) { |
|
|
0
|
0
|
0
|
|
|
|
|
|
213
|
0
|
0
|
|
|
|
|
return "" if $! == EAGAIN; |
|
214
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Couldn't read from socket: $!"); |
|
215
|
0
|
|
|
|
|
|
$self->{sockerr} = 1; |
|
216
|
0
|
|
|
|
|
|
$self->disconnect(); |
|
217
|
0
|
|
|
|
|
|
return undef; |
|
218
|
|
|
|
|
|
|
} elsif(!${$self->{buffer}} and $nchars == 0) { # EOF |
|
219
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Got EOF on socket"); |
|
220
|
0
|
|
|
|
|
|
$self->{sockerr} = 1; |
|
221
|
0
|
|
|
|
|
|
$self->disconnect(); |
|
222
|
0
|
|
|
|
|
|
return undef; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
0
|
0
|
|
|
|
|
if(length(${$self->{buffer}}) < $len) { |
|
|
0
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
return ""; |
|
228
|
|
|
|
|
|
|
} else { |
|
229
|
0
|
|
|
|
|
|
my $ret; |
|
230
|
0
|
|
|
|
|
|
delete $self->{buffsize}; |
|
231
|
0
|
0
|
|
|
|
|
if(length(${$self->{buffer}}) == $len) { |
|
|
0
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
|
$ret = $self->{buffer}; |
|
233
|
0
|
|
|
|
|
|
$self->{buffer} = \""; |
|
234
|
|
|
|
|
|
|
} else { |
|
235
|
0
|
|
|
|
|
|
$ret = \substr(${$self->{buffer}}, 0, $len, ""); |
|
|
0
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
} |
|
237
|
0
|
|
|
0
|
|
|
$self->log_print_cond(OSCAR_DBG_PACKETS, sub { "Got '", hexdump($$ret), "'" }); |
|
|
0
|
|
|
|
|
|
|
|
238
|
0
|
|
|
|
|
|
return $$ret; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
sub flap_get($;$) { |
|
243
|
0
|
|
|
0
|
0
|
|
my ($self, $no_reread) = @_; |
|
244
|
0
|
|
|
|
|
|
my $socket = $self->{socket}; |
|
245
|
0
|
|
|
|
|
|
my ($buffer, $channel, $len); |
|
246
|
0
|
|
|
|
|
|
my $nchars; |
|
247
|
|
|
|
|
|
|
|
|
248
|
0
|
0
|
|
|
|
|
if(!$self->{buff_gotflap}) { |
|
249
|
0
|
|
|
|
|
|
my $header = $self->read(6, $no_reread); |
|
250
|
0
|
0
|
|
|
|
|
if(!defined($header)) { |
|
|
|
0
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
return undef; |
|
252
|
|
|
|
|
|
|
} elsif($header eq "") { |
|
253
|
0
|
|
|
|
|
|
return ""; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
$self->{buff_gotflap} = 1; |
|
257
|
0
|
|
|
|
|
|
(undef, $self->{channel}, undef, $self->{flap_size}) = |
|
258
|
|
|
|
|
|
|
unpack("CCnn", $header); |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
0
|
0
|
|
|
|
|
if($self->{flap_size} > 0) { |
|
262
|
0
|
|
0
|
|
|
|
my $data = $self->read($self->{flap_size}, $no_reread || 2); |
|
263
|
0
|
0
|
|
|
|
|
if(!defined($data)) { |
|
|
|
0
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
return undef; |
|
265
|
|
|
|
|
|
|
} elsif($data eq "") { |
|
266
|
0
|
|
|
|
|
|
return ""; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
|
|
0
|
|
|
$self->log_print_cond(OSCAR_DBG_PACKETS, sub { "Got ", hexdump($data) }); |
|
|
0
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
delete $self->{buff_gotflap}; |
|
271
|
0
|
|
|
|
|
|
return $data; |
|
272
|
|
|
|
|
|
|
} else { |
|
273
|
0
|
|
|
|
|
|
delete $self->{buff_gotflap}; |
|
274
|
0
|
|
|
|
|
|
return ""; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub snac_encode($%) { |
|
279
|
0
|
|
|
0
|
0
|
|
my($self, %snac) = @_; |
|
280
|
|
|
|
|
|
|
|
|
281
|
0
|
|
0
|
|
|
|
$snac{family} ||= 0; |
|
282
|
0
|
|
0
|
|
|
|
$snac{subtype} ||= 0; |
|
283
|
0
|
|
0
|
|
|
|
$snac{flags1} ||= 0; |
|
284
|
0
|
|
0
|
|
|
|
$snac{flags2} ||= 0; |
|
285
|
0
|
|
0
|
|
|
|
$snac{data} ||= ""; |
|
286
|
0
|
|
0
|
|
|
|
$snac{reqdata} ||= ""; |
|
287
|
0
|
|
0
|
|
|
|
$snac{reqid} ||= ($snac{subtype}<<16) | (unpack("n", randchars(2)))[0]; |
|
288
|
0
|
0
|
|
|
|
|
$self->{reqdata}->[$snac{family}]->{pack("N", $snac{reqid})} = $snac{reqdata} if $snac{reqdata}; |
|
289
|
|
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
|
my $snac = protoparse($self->{session}, "snac")->pack(%snac); |
|
291
|
0
|
|
|
|
|
|
return $snac; |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub snac_put($%) { |
|
295
|
0
|
|
|
0
|
0
|
|
my($self, %snac) = @_; |
|
296
|
|
|
|
|
|
|
|
|
297
|
0
|
0
|
0
|
|
|
|
if($snac{family} and !$self->{families}->{$snac{family}}) { |
|
298
|
0
|
|
|
|
|
|
$self->log_printf(OSCAR_DBG_WARN, "Tried to send unsupported SNAC 0x%04X/0x%04X", $snac{family}, $snac{subtype}); |
|
299
|
|
|
|
|
|
|
|
|
300
|
0
|
|
|
|
|
|
my $newconn = $self->{session}->connection_for_family($snac{family}); |
|
301
|
0
|
0
|
|
|
|
|
if($newconn) { |
|
302
|
0
|
|
|
|
|
|
return $newconn->snac_put(%snac); |
|
303
|
|
|
|
|
|
|
} else { |
|
304
|
0
|
|
|
|
|
|
$self->{session}->crapout($self, "Couldn't find supported connection for SNAC 0x%04X/0x%04X", $snac{family}, $snac{subtype}); |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
} else { |
|
307
|
0
|
|
0
|
|
|
|
$snac{channel} ||= 0+FLAP_CHAN_SNAC; |
|
308
|
0
|
0
|
0
|
|
|
|
confess "No family/subtype" unless exists($snac{family}) and exists($snac{subtype}); |
|
309
|
|
|
|
|
|
|
|
|
310
|
0
|
0
|
0
|
|
|
|
if($self->{session}->{rate_manage_mode} != OSCAR_RATE_MANAGE_NONE and $self->{rate_limits}) { |
|
311
|
0
|
|
|
|
|
|
my $key = $self->{rate_limits}->{classmap}->{pack("nn", $snac{family}, $snac{subtype})}; |
|
312
|
0
|
0
|
|
|
|
|
if($key) { |
|
313
|
0
|
|
|
|
|
|
my $rinfo = $self->{rate_limits}->{$key}; |
|
314
|
0
|
0
|
|
|
|
|
if($rinfo) { |
|
315
|
0
|
|
|
|
|
|
$rinfo->{current_state} = max( |
|
316
|
|
|
|
|
|
|
$rinfo->{max}, |
|
317
|
|
|
|
|
|
|
$self->{session}->_compute_rate($rinfo) |
|
318
|
|
|
|
|
|
|
); |
|
319
|
0
|
|
|
|
|
|
$rinfo->{last_time} = millitime() - $rinfo->{time_offset}; |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
} |
|
323
|
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
$self->flap_put($self->snac_encode(%snac), $snac{channel}); |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub snac_get($;$) { |
|
329
|
0
|
|
|
0
|
0
|
|
my($self, $no_reread) = @_; |
|
330
|
0
|
0
|
|
|
|
|
my $snac = $self->flap_get($no_reread) or return 0; |
|
331
|
0
|
|
|
|
|
|
return $self->snac_decode($snac); |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub snac_decode($$) { |
|
335
|
0
|
|
|
0
|
0
|
|
my($self, $snac) = @_; |
|
336
|
0
|
|
|
|
|
|
my(%data) = protoparse($self->{session}, "snac")->unpack($snac); |
|
337
|
|
|
|
|
|
|
|
|
338
|
0
|
0
|
|
|
|
|
if($data{flags1} & 0x80) { |
|
339
|
0
|
|
|
|
|
|
my($minihdr_len) = unpack("n", $data{data}); |
|
340
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "Got miniheader of length $minihdr_len"); |
|
341
|
0
|
|
|
|
|
|
substr($data{data}, 0, 2+$minihdr_len) = ""; |
|
342
|
|
|
|
|
|
|
} |
|
343
|
|
|
|
|
|
|
|
|
344
|
0
|
|
|
|
|
|
return \%data; |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub snac_dump($$) { |
|
348
|
0
|
|
|
0
|
0
|
|
my($self, $snac) = @_; |
|
349
|
0
|
|
|
|
|
|
return "family=".$snac->{family}." subtype=".$snac->{subtype}; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub disconnect($) { |
|
353
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
|
354
|
|
|
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
$self->{session}->delconn($self); |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub set_blocking($$) { |
|
359
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
360
|
0
|
|
|
|
|
|
my $blocking = shift; |
|
361
|
0
|
|
|
|
|
|
my $flags = 0; |
|
362
|
|
|
|
|
|
|
|
|
363
|
0
|
0
|
|
|
|
|
if($^O ne "MSWin32") { |
|
364
|
0
|
|
|
|
|
|
fcntl($self->{socket}, F_GETFL, $flags); |
|
365
|
0
|
0
|
|
|
|
|
if($blocking) { |
|
366
|
0
|
|
|
|
|
|
$flags &= ~O_NONBLOCK; |
|
367
|
|
|
|
|
|
|
} else { |
|
368
|
0
|
|
|
|
|
|
$flags |= O_NONBLOCK; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
0
|
|
|
|
|
|
fcntl($self->{socket}, F_SETFL, $flags); |
|
371
|
|
|
|
|
|
|
} else { |
|
372
|
|
|
|
|
|
|
# Cribbed from http://nntp.x.perl.org/group/perl.perl5.porters/42198 |
|
373
|
0
|
0
|
|
|
|
|
ioctl($self->{socket}, |
|
374
|
|
|
|
|
|
|
0x80000000 | (4 << 16) | (ord('f') << 8) | 126, |
|
375
|
|
|
|
|
|
|
$blocking |
|
376
|
|
|
|
|
|
|
) or warn "Couldn't set Win32 blocking: $!\n"; |
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
|
return $self->{socket}; |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub connect($$) { |
|
384
|
0
|
|
|
0
|
0
|
|
my($self, $host) = @_; |
|
385
|
0
|
|
|
|
|
|
my $temp; |
|
386
|
|
|
|
|
|
|
my $port; |
|
387
|
|
|
|
|
|
|
|
|
388
|
0
|
0
|
|
|
|
|
return $self->{session}->crapout($self, "Empty host!") unless $host; |
|
389
|
0
|
|
|
|
|
|
$host =~ s/:(.+)//; |
|
390
|
0
|
0
|
|
|
|
|
if(!$1) { |
|
391
|
0
|
0
|
|
|
|
|
if(exists($self->{session})) { |
|
392
|
0
|
|
|
|
|
|
$port = $self->{session}->{port}; |
|
393
|
|
|
|
|
|
|
} else { |
|
394
|
0
|
|
|
|
|
|
return $self->{session}->crapout($self, "No port!"); |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
} else { |
|
397
|
0
|
|
|
|
|
|
$port = $1; |
|
398
|
0
|
0
|
|
|
|
|
if($port =~ /^[^0-9]/) { |
|
399
|
0
|
|
|
|
|
|
$port = $self->{session}->{port}; |
|
400
|
|
|
|
|
|
|
} |
|
401
|
|
|
|
|
|
|
} |
|
402
|
0
|
|
|
|
|
|
$self->{host} = $host; |
|
403
|
0
|
|
|
|
|
|
$self->{port} = $port; |
|
404
|
|
|
|
|
|
|
|
|
405
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Connecting to $host:$port."); |
|
406
|
0
|
0
|
|
|
|
|
if(defined($self->{session}->{proxy_type})) { |
|
407
|
0
|
0
|
0
|
|
|
|
if($self->{session}->{proxy_type} eq "SOCKS4" or $self->{session}->{proxy_type} eq "SOCKS5") { |
|
|
|
0
|
0
|
|
|
|
|
|
408
|
0
|
0
|
|
|
|
|
require Net::SOCKS or die "SOCKS proxying not available - couldn't load Net::SOCKS: $!\n"; |
|
409
|
|
|
|
|
|
|
|
|
410
|
0
|
|
|
|
|
|
my $socksver; |
|
411
|
0
|
0
|
|
|
|
|
if($self->{session}->{proxy_type} eq "SOCKS4") { |
|
412
|
0
|
|
|
|
|
|
$socksver = 4; |
|
413
|
|
|
|
|
|
|
} else { |
|
414
|
0
|
|
|
|
|
|
$socksver = 5; |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
|
|
417
|
0
|
|
0
|
|
|
|
my %socksargs = ( |
|
418
|
|
|
|
|
|
|
socks_addr => $self->{session}->{proxy_host}, |
|
419
|
|
|
|
|
|
|
socks_port => $self->{session}->{proxy_port} || 1080, |
|
420
|
|
|
|
|
|
|
protocol_version => $socksver |
|
421
|
|
|
|
|
|
|
); |
|
422
|
0
|
0
|
|
|
|
|
$socksargs{user_id} = $self->{session}->{proxy_username} if exists($self->{session}->{proxy_username}); |
|
423
|
0
|
0
|
|
|
|
|
$socksargs{user_password} = $self->{session}->{proxy_password} if exists($self->{session}->{proxy_password}); |
|
424
|
0
|
0
|
|
|
|
|
$self->{socks} = new Net::SOCKS(%socksargs) or return $self->{session}->crapout($self, "Couldn't connect to SOCKS proxy: $@"); |
|
425
|
|
|
|
|
|
|
|
|
426
|
0
|
0
|
|
|
|
|
$self->{socket} = $self->{socks}->connect(peer_addr => $host, peer_port => $port) or return $self->{session}->crapout({}, "Couldn't establish connection via SOCKS: $@\n"); |
|
427
|
|
|
|
|
|
|
|
|
428
|
0
|
|
|
|
|
|
$self->{ready} = 0; |
|
429
|
0
|
|
|
|
|
|
$self->{connected} = 1; |
|
430
|
0
|
|
|
|
|
|
$self->set_blocking(0); |
|
431
|
|
|
|
|
|
|
} elsif($self->{session}->{proxy_type} eq "HTTP" or $self->{session}->{proxy_type} eq "HTTPS") { |
|
432
|
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
|
require MIME::Base64; |
|
434
|
|
|
|
|
|
|
|
|
435
|
0
|
|
|
|
|
|
my $authen = $self->{session}->{proxy_username}; |
|
436
|
0
|
0
|
|
|
|
|
$authen .= ":$self->{session}->{proxy_password}" if $self->{session}->{proxy_password}; |
|
437
|
0
|
0
|
|
|
|
|
$authen = encode_base64 $authen if $authen; |
|
438
|
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
my $request = "CONNECT $host:$port HTTP/1.1\r\n"; |
|
440
|
0
|
0
|
|
|
|
|
$request .= "Proxy-Authorization: Basic $authen\r\n" if $authen; |
|
441
|
0
|
|
|
|
|
|
$request .= "User-Agent: Net::OSCAR\r\n"; |
|
442
|
0
|
|
|
|
|
|
$request .= "\r\n"; |
|
443
|
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
|
$self->{socket} = gensym; |
|
445
|
0
|
|
|
|
|
|
socket($self->{socket}, PF_INET, SOCK_STREAM, getprotobyname('tcp')); |
|
446
|
0
|
0
|
|
|
|
|
if($self->{session}->{local_ip}) { |
|
447
|
0
|
0
|
|
|
|
|
bind($self->{socket}, sockaddr_in(0, inet_aton($self->{session}->{local_ip}))) or croak "Couldn't bind to desired IP: $!\n"; |
|
448
|
|
|
|
|
|
|
} |
|
449
|
0
|
|
|
|
|
|
$self->set_blocking(0); |
|
450
|
|
|
|
|
|
|
|
|
451
|
0
|
0
|
|
|
|
|
my $addr = inet_aton($self->{session}{proxy_host}) or return $self->{session}->crapout($self, "Couldn't resolve $self->{session}{proxy_host}."); |
|
452
|
0
|
0
|
|
|
|
|
if(!connect($self->{socket}, sockaddr_in($self->{session}{proxy_port}, $addr))) { |
|
453
|
0
|
0
|
|
|
|
|
return $self->{session}->crapout($self, "Couldn't connect to $self->{session}{proxy_host}:$self->{session}{proxy_port}: $!") |
|
454
|
|
|
|
|
|
|
unless $! == EINPROGRESS; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# TODO: I don't know what happens if authentication or connection fails |
|
458
|
|
|
|
|
|
|
# |
|
459
|
0
|
|
|
|
|
|
my $buffer; |
|
460
|
0
|
|
|
|
|
|
syswrite ($self->{socket}, $request); |
|
461
|
0
|
0
|
|
|
|
|
sysread ($self->{socket}, $buffer, 1024) |
|
462
|
|
|
|
|
|
|
or return $self->{session}->crapout($self, "Couldn't read from $self->{session}{proxy_host}:$self->{session}{proxy_port}: $!"); |
|
463
|
|
|
|
|
|
|
|
|
464
|
0
|
0
|
|
|
|
|
return $self->{session}->crapout($self, "Couldn't connect to proxy: $self->{session}{proxy_host}:$self->{session}{proxy_port}: $!") |
|
465
|
|
|
|
|
|
|
unless $buffer =~ /connection\s+established/i; |
|
466
|
|
|
|
|
|
|
|
|
467
|
0
|
|
|
|
|
|
$self->set_blocking(0); |
|
468
|
0
|
|
|
|
|
|
$self->{ready} = 0; |
|
469
|
0
|
|
|
|
|
|
$self->{connected} = 1; |
|
470
|
|
|
|
|
|
|
} else { |
|
471
|
0
|
|
|
|
|
|
die "Unknown proxy_type $self->{session}->{proxy_type} - valid types are SOCKS4, SOCKS5, HTTP, and HTTPS\n"; |
|
472
|
|
|
|
|
|
|
} |
|
473
|
|
|
|
|
|
|
} else { |
|
474
|
0
|
|
|
|
|
|
$self->{socket} = gensym; |
|
475
|
0
|
|
|
|
|
|
socket($self->{socket}, PF_INET, SOCK_STREAM, getprotobyname('tcp')); |
|
476
|
0
|
0
|
|
|
|
|
if($self->{session}->{local_ip}) { |
|
477
|
0
|
0
|
|
|
|
|
bind($self->{socket}, sockaddr_in(0, inet_aton($self->{session}->{local_ip}))) or croak "Couldn't bind to desired IP: $!\n"; |
|
478
|
|
|
|
|
|
|
} |
|
479
|
0
|
|
|
|
|
|
$self->set_blocking(0); |
|
480
|
|
|
|
|
|
|
|
|
481
|
0
|
0
|
|
|
|
|
my $addr = inet_aton($host) or return $self->{session}->crapout($self, "Couldn't resolve $host."); |
|
482
|
0
|
0
|
|
|
|
|
if(!connect($self->{socket}, sockaddr_in($port, $addr))) { |
|
483
|
0
|
0
|
|
|
|
|
return 1 if $! == EINPROGRESS; |
|
484
|
0
|
|
|
|
|
|
return $self->{session}->crapout($self, "Couldn't connect to $host:$port: $!"); |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
|
|
487
|
0
|
|
|
|
|
|
$self->{ready} = 0; |
|
488
|
0
|
|
|
|
|
|
$self->{connected} = 0; |
|
489
|
|
|
|
|
|
|
} |
|
490
|
|
|
|
|
|
|
|
|
491
|
0
|
0
|
|
|
|
|
binmode($self->{socket}) or return $self->{session}->crapout($self, "Couldn't set binmode: $!"); |
|
492
|
0
|
|
|
|
|
|
return 1; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
sub listen($$) { |
|
496
|
0
|
|
|
0
|
0
|
|
my($self, $port) = @_; |
|
497
|
0
|
|
|
|
|
|
my $temp; |
|
498
|
|
|
|
|
|
|
|
|
499
|
0
|
|
0
|
|
|
|
$self->{host} = $self->{local_addr} || "0.0.0.0"; |
|
500
|
0
|
|
|
|
|
|
$self->{port} = $port; |
|
501
|
|
|
|
|
|
|
|
|
502
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Listening."); |
|
503
|
0
|
0
|
|
|
|
|
if(defined($self->{session}->{proxy_type})) { |
|
504
|
0
|
|
|
|
|
|
die "Proxying not support for listening sockets.\n"; |
|
505
|
|
|
|
|
|
|
} else { |
|
506
|
0
|
|
|
|
|
|
$self->{socket} = gensym; |
|
507
|
0
|
|
|
|
|
|
socket($self->{socket}, PF_INET, SOCK_STREAM, getprotobyname('tcp')); |
|
508
|
|
|
|
|
|
|
|
|
509
|
0
|
0
|
|
|
|
|
setsockopt($self->{socket}, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or return $self->{session}->crapout($self, "Couldn't set listen socket options: $!"); |
|
510
|
|
|
|
|
|
|
|
|
511
|
0
|
|
0
|
|
|
|
my $sockaddr = sockaddr_in($self->{session}->{local_port} || $port || 0, inet_aton($self->{session}->{local_ip} || 0)); |
|
|
|
|
0
|
|
|
|
|
|
512
|
0
|
0
|
|
|
|
|
bind($self->{socket}, $sockaddr) or return $self->{session}->crapout("Couldn't bind to desired IP: $!"); |
|
513
|
0
|
|
|
|
|
|
$self->set_blocking(0); |
|
514
|
0
|
0
|
|
|
|
|
listen($self->{socket}, SOMAXCONN) or return $self->{session}->crapout("Couldn't listen: $!"); |
|
515
|
|
|
|
|
|
|
|
|
516
|
0
|
|
|
|
|
|
$self->{state} = "read"; |
|
517
|
0
|
|
|
|
|
|
$self->{rv}->{ft_state} = "listening"; |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
0
|
0
|
|
|
|
|
binmode($self->{socket}) or return $self->{session}->crapout("Couldn't set binmode: $!"); |
|
521
|
0
|
|
|
|
|
|
return 1; |
|
522
|
|
|
|
|
|
|
} |
|
523
|
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
|
|
526
|
0
|
|
|
0
|
0
|
|
sub get_filehandle($) { shift->{socket}; } |
|
527
|
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
# $read/$write tell us if select indicated readiness to read and/or write |
|
529
|
|
|
|
|
|
|
# Ditto for $error |
|
530
|
|
|
|
|
|
|
sub process_one($;$$$) { |
|
531
|
0
|
|
|
0
|
0
|
|
my($self, $read, $write, $error) = @_; |
|
532
|
0
|
|
|
|
|
|
my $snac; |
|
533
|
|
|
|
|
|
|
|
|
534
|
0
|
0
|
|
|
|
|
if($error) { |
|
535
|
0
|
|
|
|
|
|
$self->{sockerr} = 1; |
|
536
|
0
|
|
|
|
|
|
return $self->disconnect(); |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
0
|
0
|
0
|
|
|
|
if($write && $self->{outbuff}) { |
|
540
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "Flushing output buffer."); |
|
541
|
0
|
|
|
|
|
|
$self->flap_put(); |
|
542
|
|
|
|
|
|
|
} |
|
543
|
|
|
|
|
|
|
|
|
544
|
0
|
0
|
0
|
|
|
|
if($write && !$self->{connected}) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
545
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Connected."); |
|
546
|
0
|
|
|
|
|
|
$self->{connected} = 1; |
|
547
|
0
|
|
|
|
|
|
$self->{state} = "read"; |
|
548
|
0
|
|
|
|
|
|
$self->{session}->callback_connection_changed($self, "read"); |
|
549
|
0
|
|
|
|
|
|
return 1; |
|
550
|
|
|
|
|
|
|
} elsif($read && !$self->{ready}) { |
|
551
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "Getting connack."); |
|
552
|
0
|
|
|
|
|
|
my $flap = $self->flap_get(); |
|
553
|
0
|
0
|
|
|
|
|
if(!defined($flap)) { |
|
554
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Couldn't connect."); |
|
555
|
0
|
|
|
|
|
|
return 0; |
|
556
|
|
|
|
|
|
|
} else { |
|
557
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "Got connack."); |
|
558
|
|
|
|
|
|
|
} |
|
559
|
|
|
|
|
|
|
|
|
560
|
0
|
0
|
|
|
|
|
return $self->{session}->crapout($self, "Got bad connack from server") unless $self->{channel} == FLAP_CHAN_NEWCONN; |
|
561
|
|
|
|
|
|
|
|
|
562
|
0
|
0
|
|
|
|
|
if($self->{conntype} == CONNTYPE_LOGIN) { |
|
563
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "Got connack. Sending connack."); |
|
564
|
0
|
0
|
|
|
|
|
$self->flap_put(pack("N", 1), FLAP_CHAN_NEWCONN) unless $self->{session}->{svcdata}->{hashlogin}; |
|
565
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_SIGNON, "Connected to login server."); |
|
566
|
0
|
|
|
|
|
|
$self->{ready} = 1; |
|
567
|
0
|
|
|
|
|
|
$self->{families} = {23 => 1}; |
|
568
|
|
|
|
|
|
|
|
|
569
|
0
|
0
|
|
|
|
|
if(!$self->{session}->{svcdata}->{hashlogin}) { |
|
570
|
0
|
|
|
|
|
|
$self->proto_send(protobit => "initial_signon_request", |
|
571
|
|
|
|
|
|
|
protodata => {screenname => $self->{session}->{screenname}}, |
|
572
|
|
|
|
|
|
|
nopause => 1 |
|
573
|
|
|
|
|
|
|
); |
|
574
|
|
|
|
|
|
|
} else { |
|
575
|
0
|
|
|
|
|
|
$self->proto_send(protobit => "ICQ_signon_request", |
|
576
|
|
|
|
|
|
|
protodata => {signon_tlv($self->{session}, delete($self->{auth}))}, |
|
577
|
|
|
|
|
|
|
nopause => 1 |
|
578
|
|
|
|
|
|
|
); |
|
579
|
|
|
|
|
|
|
} |
|
580
|
|
|
|
|
|
|
} else { |
|
581
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_NOTICE, "Sending BOS-Signon."); |
|
582
|
0
|
|
|
|
|
|
$self->proto_send(protobit => "BOS_signon", |
|
583
|
|
|
|
|
|
|
reqid => 0x01000000 | (unpack("n", substr($self->{auth}, 0, 2)))[0], |
|
584
|
|
|
|
|
|
|
protodata => {cookie => substr(delete($self->{auth}), 2)}, |
|
585
|
|
|
|
|
|
|
nopause => 1 |
|
586
|
|
|
|
|
|
|
); |
|
587
|
|
|
|
|
|
|
} |
|
588
|
0
|
|
|
|
|
|
$self->log_print(OSCAR_DBG_DEBUG, "SNAC time."); |
|
589
|
0
|
|
|
|
|
|
$self->{ready} = 1; |
|
590
|
|
|
|
|
|
|
} elsif($read) { |
|
591
|
0
|
|
|
|
|
|
my $no_reread = 0; |
|
592
|
0
|
|
|
|
|
|
while(1) { |
|
593
|
0
|
0
|
|
|
|
|
if(!$self->{session}->{svcdata}->{hashlogin}) { |
|
594
|
0
|
0
|
|
|
|
|
$snac = $self->snac_get($no_reread) or return 0; |
|
595
|
0
|
|
|
|
|
|
Net::OSCAR::Callbacks::process_snac($self, $snac); |
|
596
|
|
|
|
|
|
|
} else { |
|
597
|
0
|
0
|
|
|
|
|
my $data = $self->flap_get($no_reread) or return 0; |
|
598
|
0
|
|
|
|
|
|
$snac = {data => $data, reqid => 0, family => 0x17, subtype => 0x3}; |
|
599
|
0
|
0
|
|
|
|
|
if($self->{channel} == FLAP_CHAN_CLOSE) { |
|
600
|
0
|
|
|
|
|
|
$self->{conntype} = CONNTYPE_LOGIN; |
|
601
|
0
|
|
|
|
|
|
$self->{family} = 0x17; |
|
602
|
0
|
|
|
|
|
|
$self->{subtype} = 0x3; |
|
603
|
0
|
|
|
|
|
|
$self->{data} = $data; |
|
604
|
0
|
|
|
|
|
|
$self->{reqid} = 0; |
|
605
|
0
|
|
|
|
|
|
$self->{reqdata}->[0x17]->{pack("N", 0)} = ""; |
|
606
|
0
|
|
|
|
|
|
Net::OSCAR::Callbacks::process_snac($self, $snac); |
|
607
|
|
|
|
|
|
|
} else { |
|
608
|
0
|
|
|
|
|
|
my $snac = $self->snac_decode($data); |
|
609
|
0
|
0
|
|
|
|
|
if($snac) { |
|
610
|
0
|
|
|
|
|
|
Net::OSCAR::Callbacks::process_snac($self, $snac); |
|
611
|
|
|
|
|
|
|
} else { |
|
612
|
0
|
|
|
|
|
|
return 0; |
|
613
|
|
|
|
|
|
|
} |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
} |
|
616
|
|
|
|
|
|
|
} continue { |
|
617
|
0
|
|
|
|
|
|
$no_reread = 1; |
|
618
|
|
|
|
|
|
|
} |
|
619
|
|
|
|
|
|
|
} |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub ready($) { |
|
623
|
0
|
|
|
0
|
0
|
|
my($self) = shift; |
|
624
|
|
|
|
|
|
|
|
|
625
|
0
|
0
|
|
|
|
|
return if $self->{sentready}++; |
|
626
|
0
|
|
|
|
|
|
send_versions($self, 1); |
|
627
|
0
|
|
|
|
|
|
$self->unpause(); |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
0
|
|
|
0
|
0
|
|
sub session($) { return shift->{session}; } |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
sub peer_ip($) { |
|
633
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
|
634
|
|
|
|
|
|
|
|
|
635
|
0
|
|
|
|
|
|
my $sockaddr = getpeername($self->{socket}); |
|
636
|
0
|
|
|
|
|
|
my($port, $iaddr) = sockaddr_in($sockaddr); |
|
637
|
0
|
|
|
|
|
|
return inet_ntoa($iaddr); |
|
638
|
|
|
|
|
|
|
} |
|
639
|
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
sub local_ip($) { |
|
641
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
|
642
|
|
|
|
|
|
|
|
|
643
|
0
|
|
|
|
|
|
my $sockaddr = getsockname($self->{socket}); |
|
644
|
0
|
|
|
|
|
|
my($port, $iaddr) = sockaddr_in($sockaddr); |
|
645
|
0
|
|
|
|
|
|
return inet_ntoa($iaddr); |
|
646
|
|
|
|
|
|
|
} |
|
647
|
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
1; |