melo / bitflu
- Source
- Commits
- Network (0)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Tree:
d3057cc
bitflu / bitflu.pl
| 3b5c9a66 » | pab | 2007-08-25 | 1 | #!/usr/bin/perl -w | |
| 2 | # | ||||
| 1b40ad37 » | pab | 2008-04-20 | 3 | # This file is part of 'Bitflu' - (C) 2006-2008 Adrian Ulrich | |
| 3b5c9a66 » | pab | 2007-08-25 | 4 | # | |
| 5 | # Released under the terms of The "Artistic License 2.0". | ||||
| 6 | # http://www.perlfoundation.org/legal/licenses/artistic-2_0.txt | ||||
| 7 | # | ||||
| 8 | |||||
| 9 | use strict; | ||||
| 10 | use Data::Dumper; | ||||
| 752a0239 » | pab | 2007-11-25 | 11 | use Getopt::Long; | |
| 3b5c9a66 » | pab | 2007-08-25 | 12 | ||
| 30afc404 » | pab | 2007-12-18 | 13 | ||
| bb56c9de » | pab | 2007-09-08 | 14 | my $bitflu_run = undef; # Start as not_running and not_killed | |
| 752a0239 » | pab | 2007-11-25 | 15 | my $getopts = { help => undef, config => '.bitflu.config', version => undef }; | |
| bb56c9de » | pab | 2007-09-08 | 16 | $SIG{PIPE} = $SIG{CHLD} = 'IGNORE'; | |
| 17 | $SIG{INT} = $SIG{HUP} = $SIG{TERM} = \&HandleShutdown; | ||||
| 18 | |||||
| 84c866d7 » | pab | 2008-02-15 | 19 | GetOptions($getopts, "help|h", "version", "plugins", "config=s", "daemon") or exit 1; | |
| 20 | if($getopts->{help}) { die "Usage: $0 [--config=.bitflu.config --version --help --plugins --daemon]\n"; } | ||||
| 752a0239 » | pab | 2007-11-25 | 21 | ||
| 22 | |||||
| bb56c9de » | pab | 2007-09-08 | 23 | # -> Create bitflu object | |
| 752a0239 » | pab | 2007-11-25 | 24 | my $bitflu = Bitflu->new(configuration_file=>$getopts->{config}) or Carp::confess("Unable to create Bitflu Object"); | |
| 25 | if($getopts->{version}) { die $bitflu->_Command_Version->{MSG}->[0]->[1]."\n" } | ||||
| 26 | |||||
| 27 | my @loaded_plugins = $bitflu->LoadPlugins('Bitflu'); | ||||
| 28 | if($getopts->{plugins}) { | ||||
| 29 | print "# Loaded Plugins: (from ".$bitflu->Configuration->GetValue('plugindir').")\n"; | ||||
| 59365da4 » | pab | 2007-12-17 | 30 | foreach (@loaded_plugins) { printf("File %-35s provides: %s\n", $_->{file}, $_->{package}); } | |
| 752a0239 » | pab | 2007-11-25 | 31 | exit(0); | |
| 32 | } | ||||
| 84c866d7 » | pab | 2008-02-15 | 33 | elsif($getopts->{daemon}) { | |
| 34 | $bitflu->Daemonize(); | ||||
| 35 | } | ||||
| 752a0239 » | pab | 2007-11-25 | 36 | ||
| bb56c9de » | pab | 2007-09-08 | 37 | $bitflu->SysinitProcess(); | |
| 25c08197 » | pab | 2008-05-24 | 38 | $bitflu->SetupDirectories(); | |
| 3b5c9a66 » | pab | 2007-08-25 | 39 | $bitflu->InitPlugins(); | |
| e6b5ae79 » | pab | 2007-09-15 | 40 | $bitflu->PreloopInit(); | |
| 1f6a66db » | pab | 2007-09-09 | 41 | ||
| bb56c9de » | pab | 2007-09-08 | 42 | $bitflu_run = 1 if !defined($bitflu_run); # Enable mainloop and sighandler if we are still not_killed | |
| 3b5c9a66 » | pab | 2007-08-25 | 43 | ||
| 84c866d7 » | pab | 2008-02-15 | 44 | ||
| 45 | |||||
| bb56c9de » | pab | 2007-09-08 | 46 | while($bitflu_run == 1) { | |
| bfb43a2a » | pab | 2008-09-07 | 47 | my $NOW = $bitflu->Network->GetTime; | |
| 48 | foreach my $rx (@{$bitflu->{_Runners}}) { | ||||
| 49 | next if $rx->{runat} > $NOW; | ||||
| 50 | $rx->{runat} = $NOW + $rx->{target}->run(); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 51 | } | |
| c664d5a6 » | pab | 2007-12-19 | 52 | select(undef,undef,undef,$bitflu->Configuration->GetValue('sleeper')); | |
| 3b5c9a66 » | pab | 2007-08-25 | 53 | } | |
| 54 | |||||
| b5c4ffa6 » | pab | 2008-01-18 | 55 | $bitflu->Storage->terminate; | |
| 56 | |||||
| 752a0239 » | pab | 2007-11-25 | 57 | $bitflu->info("-> Shutdown completed after running for ".(int(time())-$bitflu->{_BootTime})." seconds"); | |
| bb56c9de » | pab | 2007-09-08 | 58 | exit(0); | |
| 3b5c9a66 » | pab | 2007-08-25 | 59 | ||
| 60 | |||||
| bb56c9de » | pab | 2007-09-08 | 61 | sub HandleShutdown { | |
| 62 | my($sig) = @_; | ||||
| 63 | if(defined($bitflu_run) && $bitflu_run == 1) { | ||||
| 64 | # $bitflu is running, so we can use ->info | ||||
| 65 | $bitflu->info("-> Starting shutdown... (signal $sig received)"); | ||||
| 66 | } | ||||
| 5dfdd76f » | pab | 2007-12-17 | 67 | else { | |
| 68 | print "-> Starting shutdown... (signal $sig received), please wait...\n"; | ||||
| 69 | } | ||||
| bb56c9de » | pab | 2007-09-08 | 70 | $bitflu_run = 0; # set it to not_running and killed | |
| 71 | } | ||||
| 72 | |||||
| 752a0239 » | pab | 2007-11-25 | 73 | ||
| 74 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 75 | package Bitflu; | |
| 76 | use strict; | ||||
| 77 | use Carp; | ||||
| 37de81bf » | pab | 2008-08-24 | 78 | use constant V_MAJOR => '0'; | |
| 06f6784e » | pab | 2008-10-12 | 79 | use constant V_MINOR => '61'; | |
| 37de81bf » | pab | 2008-08-24 | 80 | use constant V_STABLE => 0; | |
| 81 | use constant V_TYPE => ( V_STABLE ? 'stable' : 'devel' ); | ||||
| 82 | use constant VERSION => V_MAJOR.'.'.V_MINOR.'-'.V_TYPE; | ||||
| 3a9518d5 » | pab | 2008-10-22 | 83 | use constant APIVER => 20081022; | |
| 37de81bf » | pab | 2008-08-24 | 84 | use constant LOGBUFF => 0xFF; | |
| 3b5c9a66 » | pab | 2007-08-25 | 85 | ||
| 86 | ########################################################################## | ||||
| 87 | # Create a new Bitflu-'Dispatcher' object | ||||
| 88 | sub new { | ||||
| 89 | my($class, %args) = @_; | ||||
| 90 | my $self = {}; | ||||
| 91 | bless($self, $class); | ||||
| b36be24e » | pab | 2008-03-24 | 92 | $self->{_LogFH} = *STDOUT; # Must be set ASAP | |
| caedb01c » | pab | 2008-06-29 | 93 | $self->{_LogBuff} = []; # Empty at startup | |
| b36be24e » | pab | 2008-03-24 | 94 | $self->{Core}->{Tools} = Bitflu::Tools->new(super => $self); # Tools is also loaded ASAP because ::Configuration needs it | |
| 3b5c9a66 » | pab | 2007-08-25 | 95 | $self->{Core}->{Configuration} = Bitflu::Configuration->new(super=>$self, configuration_file => $args{configuration_file}); | |
| 96 | $self->{Core}->{Network} = Bitflu::Network->new(super => $self); | ||||
| 97 | $self->{Core}->{AdminDispatch} = Bitflu::Admin->new(super => $self); | ||||
| 98 | $self->{Core}->{QueueMgr} = Bitflu::QueueMgr->new(super => $self); | ||||
| 99 | $self->{_Runners} = (); | ||||
| 100 | $self->{_BootTime} = time(); | ||||
| 1f6a66db » | pab | 2007-09-09 | 101 | $self->{_Plugins} = (); | |
| 3b5c9a66 » | pab | 2007-08-25 | 102 | return $self; | |
| 103 | } | ||||
| 104 | |||||
| 105 | ########################################################################## | ||||
| 37de81bf » | pab | 2008-08-24 | 106 | # Return internal version | |
| 107 | sub GetVersion { | ||||
| 108 | my($self) = @_; | ||||
| 109 | return(V_MAJOR, V_MINOR, V_STABLE); | ||||
| 110 | } | ||||
| 111 | |||||
| 112 | ########################################################################## | ||||
| 113 | # Return internal version as string | ||||
| 114 | sub GetVersionString { | ||||
| 115 | my($self) = @_; | ||||
| 116 | return VERSION; | ||||
| 117 | } | ||||
| 118 | |||||
| 119 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 120 | # Call hardcoded configuration plugin | |
| 121 | sub Configuration { | ||||
| 122 | my($self) = @_; | ||||
| 123 | return $self->{Core}->{Configuration}; | ||||
| 124 | } | ||||
| 125 | |||||
| 126 | ########################################################################## | ||||
| 4697a0af » | pab | 2007-12-26 | 127 | # Call hardcoded tools plugin | |
| 128 | sub Tools { | ||||
| 33a74a49 » | pab | 2007-12-22 | 129 | my($self) = @_; | |
| 4697a0af » | pab | 2007-12-26 | 130 | return $self->{Core}->{Tools}; | |
| 33a74a49 » | pab | 2007-12-22 | 131 | } | |
| 132 | |||||
| 133 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 134 | # Call hardcoded Network IO plugin | |
| 135 | sub Network { | ||||
| 136 | my($self) = @_; | ||||
| 137 | return $self->{Core}->{Network}; | ||||
| 138 | } | ||||
| 139 | |||||
| 140 | ########################################################################## | ||||
| 141 | # Call hardcoded Admin plugin | ||||
| 142 | sub Admin { | ||||
| 143 | my($self) = @_; | ||||
| 144 | return $self->{Core}->{AdminDispatch}; | ||||
| 145 | } | ||||
| 146 | |||||
| 147 | ########################################################################## | ||||
| 148 | # Call hardcoded Queue plugin | ||||
| 149 | sub Queue { | ||||
| 150 | my($self) = @_; | ||||
| 151 | return $self->{Core}->{QueueMgr}; | ||||
| 152 | } | ||||
| 153 | |||||
| 154 | ########################################################################## | ||||
| 155 | # Call currently loaded storage plugin | ||||
| 156 | sub Storage { | ||||
| 157 | my($self) = @_; | ||||
| 158 | return $self->{Plugin}->{Storage}; | ||||
| 159 | } | ||||
| 160 | |||||
| 161 | ########################################################################## | ||||
| 162 | # Let bitflu run the given target | ||||
| 163 | sub AddRunner { | ||||
| 164 | my($self,$target) = @_; | ||||
| bfb43a2a » | pab | 2008-09-07 | 165 | push(@{$self->{_Runners}}, {target=>$target, runat=>0}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 166 | } | |
| 167 | |||||
| 168 | |||||
| 169 | ########################################################################## | ||||
| 170 | # Register the exclusive storage plugin | ||||
| 171 | sub AddStorage { | ||||
| 172 | my($self,$target) = @_; | ||||
| 173 | if(defined($self->{Plugin}->{Storage})) { $self->panic("Unable to register additional storage driver '$target' !"); } | ||||
| 174 | $self->{Plugin}->{Storage} = $target; | ||||
| 175 | $self->debug("AddStorage($target)"); | ||||
| 176 | return 1; | ||||
| 177 | } | ||||
| 178 | |||||
| 1f6a66db » | pab | 2007-09-09 | 179 | ||
| 180 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 181 | ########################################################################## | |
| 182 | # Loads all plugins from 'plugins' directory but does NOT init them | ||||
| 183 | sub LoadPlugins { | ||||
| 1f6a66db » | pab | 2007-09-09 | 184 | my($self,$xclass) = @_; | |
| 3b5c9a66 » | pab | 2007-08-25 | 185 | # | |
| 186 | unshift(@INC, $self->Configuration->GetValue('plugindir')); | ||||
| d2039c3b » | pab | 2008-01-02 | 187 | ||
| 1f6a66db » | pab | 2007-09-09 | 188 | my $pdirpath = $self->Configuration->GetValue('plugindir')."/$xclass"; | |
| 189 | my @plugins = (); | ||||
| d2039c3b » | pab | 2008-01-02 | 190 | my %exclude = (map { $_ => 1} split(/;/,$self->Configuration->GetValue('pluginexclude'))); | |
| 1f6a66db » | pab | 2007-09-09 | 191 | ||
| 59365da4 » | pab | 2007-12-17 | 192 | opendir(PLUGINS, $pdirpath) or $self->stop("Unable to read directory '$pdirpath' : $!"); | |
| 1f6a66db » | pab | 2007-09-09 | 193 | foreach my $dirent (sort readdir(PLUGINS)) { | |
| d2039c3b » | pab | 2008-01-02 | 194 | next unless my($pfile, $porder, $pmodname) = $dirent =~ /^((\d\d)_(.+)\.pm)$/i; | |
| 326b02a0 » | pab | 2008-05-31 | 195 | ||
| d2039c3b » | pab | 2008-01-02 | 196 | if($exclude{$pfile}) { | |
| 197 | $self->info("Skipping disabled plugin '$pfile -> $pmodname'"); | ||||
| 198 | } | ||||
| 326b02a0 » | pab | 2008-05-31 | 199 | elsif($porder eq '00' && $pmodname ne $self->Configuration->GetValue('storage')) { | |
| 200 | $self->debug("Skipping unconfigured storage plugin '$dirent'"); | ||||
| 201 | } | ||||
| d2039c3b » | pab | 2008-01-02 | 202 | else { | |
| 203 | push(@plugins, {file=>$pfile, order=>$porder, class=>$xclass, modname=>$pmodname, package=>$xclass."::".$3}); | ||||
| 204 | $self->debug("Found plugin $plugins[-1]->{package} in folder $pdirpath"); | ||||
| 205 | } | ||||
| 1f6a66db » | pab | 2007-09-09 | 206 | } | |
| 207 | close(PLUGINS); | ||||
| 208 | |||||
| 209 | $self->{_Plugins} = \@plugins; | ||||
| 210 | |||||
| 211 | foreach my $plugin (@{$self->{_Plugins}}) { | ||||
| fbf219f9 » | pab | 2007-09-16 | 212 | my $fname = $plugin->{class}."/".$plugin->{file}; | |
| 213 | $self->debug("Loading $fname"); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 214 | eval { require $fname; }; | |
| 215 | if($@) { | ||||
| 1f6a66db » | pab | 2007-09-09 | 216 | my $perr = $@; chomp($perr); | |
| 38c04065 » | pab | 2008-04-19 | 217 | $self->yell("Unable to load plugin '$fname', error was: '$perr'"); | |
| 59365da4 » | pab | 2007-12-17 | 218 | $self->stop(" -> Please fix or remove this broken plugin file from $pdirpath"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 219 | } | |
| ce8a1baa » | pab | 2008-02-16 | 220 | my $this_apiversion = $plugin->{package}->_BITFLU_APIVERSION; | |
| 221 | if($this_apiversion != APIVER) { | ||||
| 222 | $self->yell("Plugin '$fname' has an invalid API-Version ( (\$apivers = $this_apiversion) != (\$expected = ".APIVER.") )"); | ||||
| 223 | $self->yell("HINT: Maybe you forgot to replace the plugins at $pdirpath while upgrading bitflu?!..."); | ||||
| 224 | $self->stop("-> Exiting due to APIVER mismatch"); | ||||
| 225 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 226 | } | |
| 752a0239 » | pab | 2007-11-25 | 227 | return @plugins; | |
| 3b5c9a66 » | pab | 2007-08-25 | 228 | } | |
| 229 | |||||
| 230 | ########################################################################## | ||||
| 231 | # Startup all plugins | ||||
| 232 | sub InitPlugins { | ||||
| 233 | my($self) = @_; | ||||
| 234 | |||||
| 235 | my @TO_INIT = (); | ||||
| 1f6a66db » | pab | 2007-09-09 | 236 | foreach my $plugin (@{$self->{_Plugins}}) { | |
| fbf219f9 » | pab | 2007-09-16 | 237 | $self->debug("Registering '$plugin->{package}'"); | |
| 238 | my $this_plugin = $plugin->{package}->register($self) or $self->panic("Regsitering '$plugin' failed, aborting"); | ||||
| 239 | push(@TO_INIT, {name=>$plugin->{package}, ref=>$this_plugin}); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 240 | } | |
| 241 | foreach my $toinit (@TO_INIT) { | ||||
| 242 | $self->debug("Firing up '$toinit->{name}'"); | ||||
| 243 | $toinit->{ref}->init() or $self->panic("Unable to init plugin : $!"); | ||||
| 244 | } | ||||
| 245 | foreach my $coreplug (sort keys(%{$self->{Core}})) { | ||||
| 246 | $self->debug("Starting Core-Plugin '$coreplug'"); | ||||
| 247 | $self->{Core}->{$coreplug}->init() or $self->panic("Unable to init Core-Plugin : $!"); | ||||
| 248 | } | ||||
| 249 | } | ||||
| 250 | |||||
| bb56c9de » | pab | 2007-09-08 | 251 | ########################################################################## | |
| 25c08197 » | pab | 2008-05-24 | 252 | # Build some basic directory structure | |
| 253 | sub SetupDirectories { | ||||
| 254 | my($self) =@_; | ||||
| 255 | my $workdir = $self->Configuration->GetValue('workdir') or $self->panic("No workdir configured"); | ||||
| 256 | my $tmpdir = $self->Configuration->GetValue('tempdir') or $self->panic("No tempdir configured"); | ||||
| 257 | $tmpdir = $workdir."/".$tmpdir; | ||||
| 258 | foreach my $this_dir ($workdir, $tmpdir) { | ||||
| 259 | unless(-d $this_dir) { | ||||
| 260 | $self->debug("mkdir($this_dir)"); | ||||
| 261 | mkdir($this_dir) or $self->stop("Unable to create directory '$this_dir' : $!"); | ||||
| 262 | } | ||||
| 263 | } | ||||
| 264 | } | ||||
| 265 | |||||
| 266 | ########################################################################## | ||||
| bb56c9de » | pab | 2007-09-08 | 267 | # Change nice level, chroot and drop privileges | |
| 268 | sub SysinitProcess { | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 269 | my($self) = @_; | |
| 270 | |||||
| 271 | my $chroot = $self->Configuration->GetValue('chroot'); | ||||
| 1b3c39c3 » | pab | 2007-12-22 | 272 | my $uid = int($self->Configuration->GetValue('runas_uid') || 0); | |
| 273 | my $gid = int($self->Configuration->GetValue('runas_gid') || 0); | ||||
| 274 | my $renice = int($self->Configuration->GetValue('renice') || 0); | ||||
| 84c866d7 » | pab | 2008-02-15 | 275 | my $outlog = ($self->Configuration->GetValue('logfile') || ''); | |
| 276 | |||||
| 277 | |||||
| 278 | if(length($outlog) > 0) { | ||||
| 279 | open(LFH, ">>", $outlog) or $self->stop("Cannot write to logfile '$outlog' : $!"); | ||||
| 280 | $self->{_LogFH} = *LFH; | ||||
| 281 | $self->{_LogFH}->autoflush(1); | ||||
| 282 | $self->yell("Logging to '$outlog'"); | ||||
| 283 | } | ||||
| 284 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 285 | ||
| bb56c9de » | pab | 2007-09-08 | 286 | # Lock values because we cannot change them after we finished | |
| 287 | foreach my $lockme qw(runas_uid runas_gid chroot) { | ||||
| 288 | $self->Configuration->RuntimeLockValue($lockme); | ||||
| 289 | } | ||||
| 290 | |||||
| 291 | |||||
| 292 | # -> Set niceness (This is done before dropping root to get negative values working) | ||||
| 293 | if($renice) { | ||||
| 294 | $renice = ($renice > 19 ? 19 : ($renice < -20 ? -20 : $renice) ); # Stop funny stuff... | ||||
| 295 | $self->info("Setting my own niceness to $renice"); | ||||
| 296 | POSIX::nice($renice) or $self->warn("nice($renice) failed: $!"); | ||||
| 297 | } | ||||
| 298 | |||||
| 299 | # -> Chroot | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 300 | if(defined($chroot)) { | |
| 301 | $self->info("Chrooting into '$chroot'"); | ||||
| 302 | Carp::longmess("FULLY_LOADING_CARP"); | ||||
| 303 | chdir($chroot) or $self->panic("Cannot change into directory '$chroot' : $!"); | ||||
| 304 | chroot($chroot) or $self->panic("Cannot chroot into directory '$chroot' (are you root?) : $!"); | ||||
| 305 | chdir('/') or $self->panic("Unable to change into new chroot topdir: $!"); | ||||
| 306 | } | ||||
| 307 | |||||
| bb56c9de » | pab | 2007-09-08 | 308 | # -> Drop group privileges | |
| 3b5c9a66 » | pab | 2007-08-25 | 309 | if($gid) { | |
| 310 | $self->info("Changing gid to $gid"); | ||||
| 311 | $! = undef; | ||||
| 312 | $) = "$gid $gid"; | ||||
| 313 | $self->panic("Unable to set EGID: $!") if $!; | ||||
| 314 | $( = "$gid"; | ||||
| 315 | $self->panic("Unable to set GID: $!") if $!; | ||||
| 316 | } | ||||
| 317 | |||||
| bb56c9de » | pab | 2007-09-08 | 318 | # -> Drop user privileges | |
| 3b5c9a66 » | pab | 2007-08-25 | 319 | if($uid) { | |
| 320 | $self->info("Changing uid to $uid"); | ||||
| 321 | POSIX::setuid($uid) or $self->panic("Unable to change UID: $!"); | ||||
| 322 | } | ||||
| 323 | |||||
| bb56c9de » | pab | 2007-09-08 | 324 | # -> Check if we are still root. We shouldn't. | |
| 3b5c9a66 » | pab | 2007-08-25 | 325 | if($> == 0 or $) == 0) { | |
| 326 | $self->warn("Refusing to run with root privileges. Do not start $0 as root unless you are using"); | ||||
| 327 | $self->warn("the chroot option. In this case you must also specify the options runas_uid & runas_gid"); | ||||
| 59365da4 » | pab | 2007-12-17 | 328 | $self->stop("Bitflu refuses to run as root"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 329 | } | |
| 330 | |||||
| 331 | $self->info("$0 is running with pid $$ ; uid = ($>|$<) / gid = ($)|$()"); | ||||
| 332 | } | ||||
| 333 | |||||
| 334 | |||||
| e6b5ae79 » | pab | 2007-09-15 | 335 | ########################################################################## | |
| 336 | # This should get called after starting the mainloop | ||||
| 337 | # The subroutine does the same as a 'init' in a plugin | ||||
| 338 | sub PreloopInit { | ||||
| 339 | my($self) = @_; | ||||
| 340 | $self->Admin->RegisterCommand('die' , $self, '_Command_Shutdown' , 'Terminates bitflu'); | ||||
| 341 | $self->Admin->RegisterCommand('version' , $self, '_Command_Version' , 'Displays bitflu version string'); | ||||
| 342 | $self->Admin->RegisterCommand('date' , $self, '_Command_Date' , 'Displays current time and date'); | ||||
| 343 | } | ||||
| 1f6a66db » | pab | 2007-09-09 | 344 | ||
| 84c866d7 » | pab | 2008-02-15 | 345 | sub Daemonize { | |
| 346 | my($self) = @_; | ||||
| 347 | $self->info("Backgrounding"); | ||||
| 348 | my $child = fork(); | ||||
| 349 | |||||
| 350 | if(!defined($child)) { | ||||
| 351 | die "Unable to fork: $!\n"; | ||||
| 352 | } | ||||
| 353 | elsif($child != 0) { | ||||
| 354 | $self->yell("Bitflu is running with pid $child"); | ||||
| 355 | exit(0); | ||||
| 356 | } | ||||
| 357 | } | ||||
| 1f6a66db » | pab | 2007-09-09 | 358 | ||
| e6b5ae79 » | pab | 2007-09-15 | 359 | ########################################################################## | |
| 360 | # bye! | ||||
| 361 | sub _Command_Shutdown { | ||||
| 362 | my($self) = @_; | ||||
| 363 | kill(2,$$); | ||||
| 98cc2b50 » | pab | 2007-12-28 | 364 | return {MSG=>[ [1, "Shutting down $0 (with pid $$)"] ], SCRAP=>[]}; | |
| e6b5ae79 » | pab | 2007-09-15 | 365 | } | |
| 366 | |||||
| 367 | ########################################################################## | ||||
| 368 | # Return version string | ||||
| 369 | sub _Command_Version { | ||||
| 370 | my($self) = @_; | ||||
| 9cf2543f » | pab | 2008-02-24 | 371 | my $uptime = ( ($self->Network->GetTime - $self->{_BootTime}) / 60); | |
| 0e1c6b12 » | pab | 2008-08-30 | 372 | return {MSG=>[ [1, sprintf("This is Bitflu %s (API:%s) running on Perl %vd. Uptime: %.3f minutes (%s)",$self->GetVersionString, | |
| 373 | APIVER, $^V, $uptime, "".localtime($self->{_BootTime}) )] ], SCRAP=>[]}; | ||||
| e6b5ae79 » | pab | 2007-09-15 | 374 | } | |
| 375 | |||||
| 376 | ########################################################################## | ||||
| 377 | # Return version string | ||||
| 378 | sub _Command_Date { | ||||
| 379 | my($self) = @_; | ||||
| 98cc2b50 » | pab | 2007-12-28 | 380 | return {MSG=>[ [1, "".localtime()] ], SCRAP=>[]}; | |
| e6b5ae79 » | pab | 2007-09-15 | 381 | } | |
| 382 | |||||
| 84c866d7 » | pab | 2008-02-15 | 383 | ########################################################################## | |
| 384 | # Printout logmessage | ||||
| 385 | sub _xlog { | ||||
| 386 | my($self, $msg, $force_stdout) = @_; | ||||
| caedb01c » | pab | 2008-06-29 | 387 | my $rmsg = localtime()." # $msg\n"; | |
| 388 | my $xfh = $self->{_LogFH}; | ||||
| 389 | my $lbuff = $self->{_LogBuff}; | ||||
| 390 | |||||
| 84c866d7 » | pab | 2008-02-15 | 391 | print $xfh $rmsg; | |
| 392 | |||||
| 393 | if($force_stdout && $xfh ne *STDOUT) { | ||||
| 394 | print STDOUT $rmsg; | ||||
| 395 | } | ||||
| caedb01c » | pab | 2008-06-29 | 396 | ||
| 397 | push(@$lbuff, $rmsg); | ||||
| 398 | shift(@$lbuff) if int(@$lbuff) >= LOGBUFF; | ||||
| 84c866d7 » | pab | 2008-02-15 | 399 | } | |
| 400 | |||||
| 401 | sub info { my($self,$msg) = @_; return if $self->Configuration->GetValue('loglevel') < 4; $self->_xlog($msg); } | ||||
| 402 | sub debug { my($self,$msg) = @_; return if $self->Configuration->GetValue('loglevel') < 10; $self->_xlog(" ** DEBUG ** $msg"); } | ||||
| 403 | sub warn { my($self,$msg) = @_; return if $self->Configuration->GetValue('loglevel') < 2; $self->_xlog("** WARNING ** $msg"); } | ||||
| 404 | sub yell { my($self,$msg) = @_; $self->_xlog($msg,1); } | ||||
| 405 | sub stop { my($self,$msg) = @_; $self->yell("EXITING # $msg"); exit(1); } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 406 | sub panic { | |
| 407 | my($self,$msg) = @_; | ||||
| 84c866d7 » | pab | 2008-02-15 | 408 | $self->yell("--------- BITFLU SOMEHOW MANAGED TO CRASH ITSELF; PANIC MESSAGE: ---------"); | |
| 409 | $self->yell($msg); | ||||
| 410 | $self->yell("--------- BACKTRACE START ---------"); | ||||
| 411 | $self->yell(Carp::longmess()); | ||||
| 412 | $self->yell("---------- BACKTRACE END ----------"); | ||||
| 413 | |||||
| 414 | $self->yell("SHA1-Module used : ".$self->Tools->{mname}); | ||||
| 415 | $self->yell("Perl Version : ".sprintf("%vd", $^V)); | ||||
| 416 | $self->yell("Perl Execname : ".$^X); | ||||
| 417 | $self->yell("OS-Name : ".$^O); | ||||
| 418 | $self->yell("Running since : ".gmtime($self->{_BootTime})); | ||||
| 419 | $self->yell("---------- LOADED PLUGINS ---------"); | ||||
| d2039c3b » | pab | 2008-01-02 | 420 | foreach my $plug (@{$self->{_Plugins}}) { | |
| 84c866d7 » | pab | 2008-02-15 | 421 | $self->yell(sprintf("%-32s -> %s",$plug->{file}, $plug->{package})); | |
| d2039c3b » | pab | 2008-01-02 | 422 | } | |
| 84c866d7 » | pab | 2008-02-15 | 423 | $self->yell("##################################"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 424 | exit(1); | |
| 425 | } | ||||
| 426 | |||||
| 427 | |||||
| 428 | 1; | ||||
| 429 | |||||
| 430 | |||||
| 431 | #################################################################################################################################################### | ||||
| 432 | #################################################################################################################################################### | ||||
| 433 | # Bitflu Queue manager | ||||
| 434 | # | ||||
| 435 | package Bitflu::QueueMgr; | ||||
| a6c39744 » | pab | 2008-03-21 | 436 | ||
| 3b5c9a66 » | pab | 2007-08-25 | 437 | use constant SHALEN => 40; | |
| a6c39744 » | pab | 2008-03-21 | 438 | use constant HPFX => 'history_'; | |
| 439 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 440 | sub new { | |
| 441 | my($class, %args) = @_; | ||||
| 442 | my $self = {super=> $args{super}}; | ||||
| 443 | bless($self,$class); | ||||
| 444 | return $self; | ||||
| 445 | } | ||||
| 446 | |||||
| 447 | ########################################################################## | ||||
| 448 | # Inits plugin: This resumes all found storage items | ||||
| 449 | sub init { | ||||
| 450 | my($self) = @_; | ||||
| 451 | my $queueIds = $self->{super}->Storage->GetStorageItems(); | ||||
| 452 | my $runners = $self->GetRunnersRef(); | ||||
| 453 | |||||
| 454 | foreach my $sid (@$queueIds) { | ||||
| 9c5f3648 » | pab | 2007-12-23 | 455 | $self->info("Resuming download $sid, this may take a few seconds..."); | |
| 3b5c9a66 » | pab | 2007-08-25 | 456 | my $this_storage = $self->{super}->Storage->OpenStorage($sid) or $self->panic("Unable to open storage for sid $sid"); | |
| 457 | my $owner = $this_storage->GetSetting('owner'); | ||||
| 458 | if(defined($owner) && defined($runners->{$owner})) { | ||||
| 459 | $runners->{$owner}->resume_this($sid); | ||||
| 460 | } | ||||
| 461 | else { | ||||
| 462 | $self->panic("StorageObject $sid is owned by '$owner', but plugin is not loaded/registered correctly"); | ||||
| 463 | } | ||||
| 464 | } | ||||
| bbbbb5fc » | pab | 2007-09-01 | 465 | $self->{super}->Admin->RegisterCommand('rename' , $self, 'admincmd_rename', 'Renames a download', | |
| 466 | [ [undef, "Renames a download"], [undef, "Usage: rename queue_id \"New Name\""] ]); | ||||
| 467 | $self->{super}->Admin->RegisterCommand('cancel' , $self, 'admincmd_cancel', 'Removes a file from the download queue', | ||||
| 468 | [ [undef, "Removes a file from the download queue"], [undef, "Usage: cancel queue_id [queue_id2 ...]"] ]); | ||||
| a6c39744 » | pab | 2008-03-21 | 469 | ||
| 470 | $self->{super}->Admin->RegisterCommand('history' , $self, 'admincmd_history', 'Manages download history', | ||||
| 471 | [ [undef, "Manages internal download history"], [undef, ''], | ||||
| 472 | [undef, "Usage: history [ queue_id [show forget] ] [list]"], [undef, ''], | ||||
| 473 | [undef, "history list : List all remembered downloads"], | ||||
| 474 | [undef, "history queue_id show : Shows details about queue_id"], | ||||
| 475 | [undef, "history queue_id forget : Removes history of queue_id"], | ||||
| 476 | ]); | ||||
| 477 | |||||
| 7dfb0491 » | pab | 2008-07-17 | 478 | $self->{super}->Admin->RegisterCommand('pause' , $self, 'admincmd_pause', 'Stops a download', | |
| 479 | [ [undef, "Stop given download"], [undef, ''], | ||||
| 480 | [undef, "Usage: pause queue_id [queue_id2 ...]"], [undef, ''], | ||||
| 481 | ]); | ||||
| 482 | |||||
| 483 | $self->{super}->Admin->RegisterCommand('resume' , $self, 'admincmd_resume', 'Resumes a paused download', | ||||
| 484 | [ [undef, "Resumes a paused download"], [undef, ''], | ||||
| 485 | [undef, "Usage: resume queue_id [queue_id2 ...]"], [undef, ''], | ||||
| 486 | ]); | ||||
| 487 | |||||
| 37de81bf » | pab | 2008-08-24 | 488 | $self->info("--- startup completed: bitflu ".$self->{super}->GetVersionString." is ready ---"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 489 | return 1; | |
| 490 | } | ||||
| 491 | |||||
| 7dfb0491 » | pab | 2008-07-17 | 492 | ||
| 493 | ########################################################################## | ||||
| 494 | # Pauses a download | ||||
| 495 | sub admincmd_pause { | ||||
| 496 | my($self, @args) = @_; | ||||
| 497 | |||||
| 498 | my @MSG = (); | ||||
| 499 | my $NOEXEC = ''; | ||||
| 500 | |||||
| 501 | if(int(@args)) { | ||||
| 502 | foreach my $cid (@args) { | ||||
| 503 | my $so = $self->{super}->Storage->OpenStorage($cid); | ||||
| 504 | if($so) { | ||||
| 505 | $so->SetSetting('_paused', 1); | ||||
| 506 | push(@MSG, [1, "$cid: download paused"]); | ||||
| 507 | } | ||||
| 508 | else { | ||||
| 509 | push(@MSG, [2, "$cid: does not exist in queue, cannot pause"]); | ||||
| 510 | } | ||||
| 511 | } | ||||
| 512 | } | ||||
| 513 | else { | ||||
| 514 | $NOEXEC .= 'Usage: pause queue_id'; | ||||
| 515 | } | ||||
| 516 | return({MSG=>\@MSG, SCRAP=>[], NOEXEC=>$NOEXEC}); | ||||
| 517 | } | ||||
| 518 | |||||
| 519 | ########################################################################## | ||||
| 520 | # Resumes a download | ||||
| 521 | sub admincmd_resume { | ||||
| 522 | my($self, @args) = @_; | ||||
| 523 | |||||
| 524 | my @MSG = (); | ||||
| 525 | my $NOEXEC = ''; | ||||
| 526 | |||||
| 527 | if(int(@args)) { | ||||
| 528 | foreach my $cid (@args) { | ||||
| 529 | my $so = $self->{super}->Storage->OpenStorage($cid); | ||||
| 530 | if($so) { | ||||
| 531 | $so->SetSetting('_paused', 0); | ||||
| 532 | push(@MSG, [1, "$cid: download resumed"]); | ||||
| 533 | } | ||||
| 534 | else { | ||||
| 535 | push(@MSG, [2, "$cid: does not exist in queue, cannot resume"]); | ||||
| 536 | } | ||||
| 537 | } | ||||
| 538 | } | ||||
| 539 | else { | ||||
| 540 | $NOEXEC .= 'Usage: resume queue_id'; | ||||
| 541 | } | ||||
| 542 | return({MSG=>\@MSG, SCRAP=>[], NOEXEC=>$NOEXEC}); | ||||
| 543 | } | ||||
| 544 | |||||
| 545 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 546 | ########################################################################## | |
| 547 | # Cancel a queue item | ||||
| 548 | sub admincmd_cancel { | ||||
| 549 | my($self, @args) = @_; | ||||
| 550 | |||||
| 551 | my $runners = $self->GetRunnersRef(); | ||||
| 98cc2b50 » | pab | 2007-12-28 | 552 | my @MSG = (); | |
| 553 | my $NOEXEC = ''; | ||||
| 752a0239 » | pab | 2007-11-25 | 554 | ||
| 555 | if(int(@args)) { | ||||
| 556 | foreach my $cid (@args) { | ||||
| 557 | my $storage = $self->{super}->Storage->OpenStorage($cid); | ||||
| 558 | if($storage) { | ||||
| 559 | my $owner = $storage->GetSetting('owner'); | ||||
| 560 | if(defined($owner) && defined($runners->{$owner})) { | ||||
| a6c39744 » | pab | 2008-03-21 | 561 | $self->ModifyHistory($cid, Canceled=>''); | |
| 752a0239 » | pab | 2007-11-25 | 562 | $runners->{$owner}->cancel_this($cid); | |
| 98cc2b50 » | pab | 2007-12-28 | 563 | push(@MSG, [1, "'$cid' canceled"]); | |
| 752a0239 » | pab | 2007-11-25 | 564 | } | |
| 565 | else { | ||||
| 566 | $self->panic("'$cid' has no owner, cannot cancel!"); | ||||
| 567 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 568 | } | |
| 569 | else { | ||||
| 98cc2b50 » | pab | 2007-12-28 | 570 | push(@MSG, [2, "'$cid' not removed from queue: No such item"]); | |
| 3b5c9a66 » | pab | 2007-08-25 | 571 | } | |
| 572 | } | ||||
| 573 | } | ||||
| 752a0239 » | pab | 2007-11-25 | 574 | else { | |
| 98cc2b50 » | pab | 2007-12-28 | 575 | $NOEXEC .= 'Usage: cancel queue_id [queue_id2 ...]'; | |
| 752a0239 » | pab | 2007-11-25 | 576 | } | |
| 577 | |||||
| 578 | |||||
| 98cc2b50 » | pab | 2007-12-28 | 579 | return({MSG=>\@MSG, SCRAP=>[], NOEXEC=>$NOEXEC}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 580 | } | |
| 581 | |||||
| 582 | ########################################################################## | ||||
| 583 | # Rename a queue item | ||||
| 584 | sub admincmd_rename { | ||||
| 585 | my($self, @args) = @_; | ||||
| 586 | |||||
| 98cc2b50 » | pab | 2007-12-28 | 587 | my $sha = $args[0]; | |
| 588 | my $name = $args[1]; | ||||
| 589 | my @MSG = (); | ||||
| 590 | my $NOEXEC = ''; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 591 | ||
| 98cc2b50 » | pab | 2007-12-28 | 592 | if(!defined($name)) { | |
| 593 | $NOEXEC .= "Usage: rename queue_id \"New Name\""; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 594 | } | |
| 98cc2b50 » | pab | 2007-12-28 | 595 | elsif(my $storage = $self->{super}->Storage->OpenStorage($sha)) { | |
| 596 | $storage->SetSetting('name', $name); | ||||
| 597 | push(@MSG, [1, "Renamed $sha into '$name'"]); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 598 | } | |
| 599 | else { | ||||
| 98cc2b50 » | pab | 2007-12-28 | 600 | push(@MSG, [2, "Unable to rename $sha: queue_id does not exist"]); | |
| 3b5c9a66 » | pab | 2007-08-25 | 601 | } | |
| 98cc2b50 » | pab | 2007-12-28 | 602 | return({MSG=>\@MSG, SCRAP=>[], NOEXEC=>$NOEXEC}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 603 | } | |
| 604 | |||||
| 605 | ########################################################################## | ||||
| a6c39744 » | pab | 2008-03-21 | 606 | # Manages download history | |
| 607 | sub admincmd_history { | ||||
| 608 | my($self,@args) = @_; | ||||
| 609 | |||||
| 610 | my $sha = ($args[0] || ''); | ||||
| 611 | my $cmd = ($args[1] || ''); | ||||
| 612 | my @MSG = (); | ||||
| 613 | my $NOEXEC = ''; | ||||
| 614 | my $hpfx = HPFX; | ||||
| 615 | my $hkey = $hpfx.$sha; | ||||
| 616 | my $strg = $self->{super}->Storage; | ||||
| 617 | |||||
| 618 | if($sha eq 'list') { | ||||
| 619 | my @cbl = $strg->ClipboardList; | ||||
| 620 | my $cbi = 0; | ||||
| 621 | foreach my $item (@cbl) { | ||||
| 622 | if(my($this_sid) = $item =~ /^$hpfx(.+)$/) { | ||||
| 623 | my $ll = "$1 : ".substr($self->GetHistory($this_sid)->{Name},0,64); | ||||
| 624 | push(@MSG, [ ($strg->OpenStorage($this_sid) ? 1 : 5 ), $ll]); | ||||
| 625 | $cbi++; | ||||
| 626 | } | ||||
| 627 | } | ||||
| 628 | push(@MSG, [1, "$cbi item".($cbi == 1 ? '' : 's')." stored in history"]); | ||||
| 629 | } | ||||
| 630 | elsif(length($sha)) { | ||||
| 631 | if(my $ref = $self->GetHistory($sha)) { | ||||
| 632 | if($cmd eq 'show') { | ||||
| c9743480 » | pab | 2008-08-17 | 633 | foreach my $k (sort keys(%$ref)) { | |
| a6c39744 » | pab | 2008-03-21 | 634 | push(@MSG,[1, sprintf("%20s -> %s",$k,$ref->{$k})]); | |
| 635 | } | ||||
| 636 | } | ||||
| 637 | elsif($cmd eq 'forget') { | ||||
| 638 | $strg->ClipboardRemove($hkey); | ||||
| 639 | push(@MSG, [1, "history for $sha has been removed"]); | ||||
| 640 | } | ||||
| 641 | else { | ||||
| 642 | push(@MSG, [2, "unknown subcommand, see 'help history'"]); | ||||
| 643 | } | ||||
| 644 | } | ||||
| 645 | else { | ||||
| 646 | push(@MSG, [2,"queue item $sha has no history"]); | ||||
| 647 | } | ||||
| 648 | } | ||||
| 649 | else { | ||||
| 650 | push(@MSG, [2,"See 'help history'"]); | ||||
| 651 | } | ||||
| 652 | |||||
| 653 | return({MSG=>\@MSG, SCRAP=>[], NOEXEC=>$NOEXEC}); | ||||
| 654 | } | ||||
| 655 | |||||
| 656 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 657 | # Add a new item to queue (Also creates a new storage) | |
| 658 | sub AddItem { | ||||
| 659 | my($self, %args) = @_; | ||||
| 660 | |||||
| 661 | my $name = $args{Name}; | ||||
| 662 | my $chunks = $args{Chunks} or $self->panic("No chunks?!"); | ||||
| 663 | my $size = $args{Size}; | ||||
| 664 | my $overst = $args{Overshoot}; | ||||
| 665 | my $flayout = $args{FileLayout} or $self->panic("FileLayout missing"); | ||||
| 4697a0af » | pab | 2007-12-26 | 666 | my $shaname = ($args{ShaName} || unpack("H*", $self->{super}->Tools->sha1($name))); | |
| 3b5c9a66 » | pab | 2007-08-25 | 667 | my $owner = ref($args{Owner}) or $self->panic("No owner?"); | |
| a6c39744 » | pab | 2008-03-21 | 668 | my $sobj = 0; | |
| 73a3d7ec » | pab | 2008-05-12 | 669 | my $history = $self->{super}->Configuration->GetValue('history'); | |
| 3b5c9a66 » | pab | 2007-08-25 | 670 | ||
| 671 | if($size == 0 && $chunks != 1) { | ||||
| 672 | $self->panic("Sorry: You can not create a dynamic storage with multiple chunks ($chunks != 1)"); | ||||
| 673 | } | ||||
| 674 | if(!defined($name)) { | ||||
| 675 | $self->panic("AddItem needs a name!"); | ||||
| 676 | } | ||||
| 677 | if(length($shaname) != SHALEN) { | ||||
| 678 | $self->panic("Invalid shaname: $shaname"); | ||||
| 679 | } | ||||
| 680 | |||||
| 681 | |||||
| a6c39744 » | pab | 2008-03-21 | 682 | if($self->{super}->Storage->OpenStorage($shaname)) { | |
| 683 | $@ = "$shaname: item exists in queue"; | ||||
| 684 | } | ||||
| 73a3d7ec » | pab | 2008-05-12 | 685 | elsif($history && $self->GetHistory($shaname)) { | |
| a6c39744 » | pab | 2008-03-21 | 686 | $@ = "$shaname: has already been downloaded. Use 'history $shaname forget' if you want do re-download it"; | |
| 73a3d7ec » | pab | 2008-05-12 | 687 | $self->warn($@); | |
| a6c39744 » | pab | 2008-03-21 | 688 | } | |
| 689 | elsif($sobj = $self->{super}->Storage->CreateStorage(StorageId => $shaname, Size=>$size, Chunks=>$chunks, Overshoot=>$overst, FileLayout=>$flayout)) { | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 690 | $sobj->SetSetting('owner', $owner); | |
| 691 | $sobj->SetSetting('name' , $name); | ||||
| 33a74a49 » | pab | 2007-12-22 | 692 | $sobj->SetSetting('createdat', $self->{super}->Network->GetTime); | |
| 73a3d7ec » | pab | 2008-05-12 | 693 | if($history) { | |
| 694 | $self->ModifyHistory($shaname, Name=>$name, Canceled=>'never', Started=>'', | ||||
| 695 | Ended=>'never', Committed=>'never'); | ||||
| 696 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 697 | } | |
| 698 | else { | ||||
| a6c39744 » | pab | 2008-03-21 | 699 | $self->panic("CreateStorage for $shaname failed"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 700 | } | |
| a6c39744 » | pab | 2008-03-21 | 701 | ||
| 3b5c9a66 » | pab | 2007-08-25 | 702 | return $sobj; | |
| 703 | } | ||||
| 704 | |||||
| 705 | ########################################################################## | ||||
| 706 | # Removes an item from the queue + storage | ||||
| 707 | sub RemoveItem { | ||||
| 708 | my($self,$sid) = @_; | ||||
| 709 | my $ret = $self->{super}->Storage->RemoveStorage($sid); | ||||
| 710 | if(!$ret) { | ||||
| 711 | $self->panic("Unable to remove storage-object $sid : $!"); | ||||
| 712 | } | ||||
| 713 | |||||
| 714 | delete($self->{statistics}->{$sid}) or $self->panic("Cannot remove non-existing statistics for $sid"); | ||||
| 715 | return 1; | ||||
| 716 | } | ||||
| 717 | |||||
| 718 | ########################################################################## | ||||
| a6c39744 » | pab | 2008-03-21 | 719 | # Updates/creates on-disk history of given sid | |
| 720 | # Note: Strings with length == 0 are replaced with the current time. Awkward. | ||||
| 721 | sub ModifyHistory { | ||||
| 722 | my($self,$sid, %args) = @_; | ||||
| 723 | if($self->{super}->Storage->OpenStorage($sid)) { | ||||
| 724 | my $old_ref = $self->GetHistory($sid); | ||||
| 725 | foreach my $k (keys(%args)) { | ||||
| 726 | my $v = $args{$k}; | ||||
| 727 | $v = "".localtime($self->{super}->Network->GetTime) if length($v) == 0; | ||||
| 728 | $old_ref->{$k} = $v; | ||||
| 729 | } | ||||
| b36be24e » | pab | 2008-03-24 | 730 | return $self->{super}->Storage->ClipboardSet(HPFX.$sid, $self->{super}->Tools->RefToCBx($old_ref)); | |
| a6c39744 » | pab | 2008-03-21 | 731 | } | |
| 732 | else { | ||||
| 733 | return 0; | ||||
| 734 | } | ||||
| 735 | } | ||||
| 736 | |||||
| 737 | ########################################################################## | ||||
| 738 | # Returns history of given sid | ||||
| 739 | sub GetHistory { | ||||
| 740 | my($self,$sid) = @_; | ||||
| b36be24e » | pab | 2008-03-24 | 741 | my $r = $self->{super}->Tools->CBxToRef($self->{super}->Storage->ClipboardGet(HPFX.$sid)); | |
| a6c39744 » | pab | 2008-03-21 | 742 | return $r; | |
| 743 | } | ||||
| 744 | |||||
| 745 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 746 | # Set private statistics | |
| 8ca1bb06 » | pab | 2007-12-24 | 747 | # You are supposed to set total_bytes, total_chunks, done_bytes, done_chunks, | |
| 748 | # uploaded_bytes, clients, active_clients, last_recv | ||||
| 749 | # ..and we do not save anything.. you'll need to do this on your own :-) | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 750 | sub SetStats { | |
| 751 | my($self, $id, $ref) = @_; | ||||
| 752 | foreach my $xk (keys(%$ref)) { | ||||
| 753 | $self->{statistics}->{$id}->{$xk} = $ref->{$xk}; | ||||
| 754 | } | ||||
| 755 | } | ||||
| 756 | |||||
| 757 | sub IncrementStats { | ||||
| 758 | my($self, $id, $ref) = @_; | ||||
| 759 | foreach my $xk (keys(%$ref)) { | ||||
| 760 | $self->SetStats($id,{$xk => $self->GetStat($id,$xk)+$ref->{$xk}}); | ||||
| 761 | } | ||||
| 762 | } | ||||
| 763 | sub DecrementStats { | ||||
| 764 | my($self, $id, $ref) = @_; | ||||
| 765 | foreach my $xk (keys(%$ref)) { | ||||
| 766 | $self->SetStats($id,{$xk => $self->GetStat($id,$xk)-$ref->{$xk}}); | ||||
| 767 | } | ||||
| 768 | } | ||||
| 769 | |||||
| 770 | ########################################################################## | ||||
| 771 | # Get private statistics | ||||
| 772 | sub GetStats { | ||||
| 773 | my($self,$id) = @_; | ||||
| 774 | return $self->{statistics}->{$id}; | ||||
| 775 | } | ||||
| 776 | |||||
| 777 | ########################################################################## | ||||
| 778 | # Get single statistics key | ||||
| 779 | sub GetStat { | ||||
| 780 | my($self,$id,$key) = @_; | ||||
| 781 | return $self->GetStats($id)->{$key}; | ||||
| 782 | } | ||||
| 783 | |||||
| 784 | ########################################################################## | ||||
| 785 | # Returns a list with all queue objects | ||||
| 786 | sub GetQueueList { | ||||
| 787 | my($self) = @_; | ||||
| 788 | my $xh = (); | ||||
| 789 | my $all_ids = $self->{super}->Storage->GetStorageItems(); | ||||
| 790 | foreach my $id (@$all_ids) { | ||||
| 791 | my $so = $self->{super}->Storage->OpenStorage($id) or $self->panic("Unable to open $id"); | ||||
| 792 | my $name = $so->GetSetting('name'); | ||||
| 793 | my $type = ($so->GetSetting('type') or "????"); | ||||
| 794 | $xh->{$type}->{$id} = { name=>$name }; | ||||
| 795 | } | ||||
| 796 | return $xh; | ||||
| 797 | } | ||||
| 798 | |||||
| 7dfb0491 » | pab | 2008-07-17 | 799 | ########################################################################## | |
| 800 | # Returns true if download is marked as paused | ||||
| 801 | sub IsPaused { | ||||
| 802 | my($self,$sid) = @_; | ||||
| 803 | my $so = $self->{super}->Storage->OpenStorage($sid) or $self->panic("$sid does not exist"); | ||||
| 804 | return ( $so->GetSetting('_paused') ? 1 : 0 ); | ||||
| 805 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 806 | ||
| 807 | ########################################################################## | ||||
| 808 | # Returns a list of bitflus _Runner array as reference hash | ||||
| 809 | sub GetRunnersRef { | ||||
| 810 | my($self) = @_; | ||||
| 811 | my $runners = (); | ||||
| bfb43a2a » | pab | 2008-09-07 | 812 | foreach my $rx (@{$self->{super}->{_Runners}}) { | |
| 813 | my $t = $rx->{target}; | ||||
| 814 | $runners->{ref($t)} = $t; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 815 | } | |
| 816 | return $runners; | ||||
| 817 | } | ||||
| 818 | |||||
| 819 | |||||
| 820 | |||||
| d2039c3b » | pab | 2008-01-02 | 821 | sub debug { my($self, $msg) = @_; $self->{super}->debug("QueueMGR: ".$msg); } | |
| 822 | sub info { my($self, $msg) = @_; $self->{super}->info("QueueMGR: ".$msg); } | ||||
| 823 | sub warn { my($self, $msg) = @_; $self->{super}->warn("QueueMGR: ".$msg); } | ||||
| 824 | sub panic { my($self, $msg) = @_; $self->{super}->panic("QueueMGR: ".$msg); } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 825 | ||
| 826 | 1; | ||||
| 827 | |||||
| 828 | ############################################################################################################### | ||||
| 4697a0af » | pab | 2007-12-26 | 829 | # Bitflu Sammelsurium | |
| 830 | package Bitflu::Tools; | ||||
| 9ab51800 » | pab | 2007-12-31 | 831 | ||
| 832 | use MIME::Base64 (); | ||||
| 8343f78d » | pab | 2008-01-06 | 833 | use IO::Socket; | |
| 33a74a49 » | pab | 2007-12-22 | 834 | ||
| 835 | ########################################################################## | ||||
| 836 | # Create new object and try to load a module | ||||
| b36be24e » | pab | 2008-03-24 | 837 | # Note: new() this gets called before ::Configuration is ready! | |
| 838 | # You can't use fancy stuff such as ->debug. ->stop should work | ||||
| 33a74a49 » | pab | 2007-12-22 | 839 | sub new { | |
| 840 | my($class, %args) = @_; | ||||
| 841 | my $self = { super => $args{super}, ns => '', mname => '' }; | ||||
| 842 | bless($self,$class); | ||||
| 843 | |||||
| 844 | foreach my $mname (qw(Digest::SHA Digest::SHA1)) { | ||||
| 845 | my $code = "use $mname; \$self->{ns} = $mname->new; \$self->{mname} = \$mname"; | ||||
| 846 | eval $code; | ||||
| 847 | } | ||||
| 848 | |||||
| b36be24e » | pab | 2008-03-24 | 849 | unless($self->{mname}) { | |
| 33a74a49 » | pab | 2007-12-22 | 850 | $self->stop("No SHA1-Module found. Bitflu requires 'Digest::SHA' (http://search.cpan.org)"); | |
| 851 | } | ||||
| 852 | |||||
| 853 | return $self; | ||||
| 854 | } | ||||
| 855 | |||||
| 856 | sub init { return 1 } | ||||
| 857 | |||||
| 4697a0af » | pab | 2007-12-26 | 858 | ########################################################################## | |
| 1e342af6 » | pab | 2008-05-04 | 859 | # Return hexed sha1 of $buff | |
| 33a74a49 » | pab | 2007-12-22 | 860 | sub sha1_hex { | |
| 861 | my($self, $buff) = @_; | ||||
| 862 | $self->{ns}->add($buff); | ||||
| 863 | return $self->{ns}->hexdigest; | ||||
| 864 | } | ||||
| 865 | |||||
| 4697a0af » | pab | 2007-12-26 | 866 | ########################################################################## | |
| 1e342af6 » | pab | 2008-05-04 | 867 | # Return sha1 of $buff | |
| 33a74a49 » | pab | 2007-12-22 | 868 | sub sha1 { | |
| 869 | my($self,$buff) = @_; | ||||
| 870 | $self->{ns}->add($buff); | ||||
| 871 | return $self->{ns}->digest; | ||||
| 872 | } | ||||
| 873 | |||||
| 4697a0af » | pab | 2007-12-26 | 874 | ########################################################################## | |
| 875 | # Encode string into base32 | ||||
| 876 | sub encode_b32 { | ||||
| 877 | my($self,$val) = @_; | ||||
| 878 | my $s = unpack("B*",$val); | ||||
| 879 | $s =~ s/(.{5})/000$1/g; # Convert 5-byte-chunks to 8-byte-chunks | ||||
| 880 | my $len = length($s); | ||||
| 881 | my $olen = $len % 8; | ||||
| 882 | |||||
| 883 | if($olen) { | ||||
| 884 | $s = substr($s,0,$len-$olen)."000".substr($s,-1*$olen).("0" x (5 - $olen)); | ||||
| 885 | } | ||||
| 886 | |||||
| 887 | $s = pack("B*",$s); | ||||
| 888 | $s =~ tr/\0-\37/A-Z2-7/; # Octal! | ||||
| 889 | return $s; | ||||
| 890 | } | ||||
| 891 | |||||
| 892 | ########################################################################## | ||||
| 893 | # Decode base32 into string | ||||
| 894 | sub decode_b32 { | ||||
| 895 | my($self,$val) = @_; | ||||
| 896 | my $s = uc($val); | ||||
| 897 | $s =~ tr/A-Z2-7/\0-\37/; | ||||
| 898 | $s = unpack("B*", $s); | ||||
| 899 | $s =~ s/000(.{5})/$1/g; | ||||
| 900 | if( my $olen = -1*(length($s)%8) ) { | ||||
| 901 | $s = substr($s,0,$olen); | ||||
| 902 | } | ||||
| 903 | return pack("B*",$s); | ||||
| 904 | } | ||||
| 905 | |||||
| 9ab51800 » | pab | 2007-12-31 | 906 | ########################################################################## | |
| 907 | # Decode base64 into string | ||||
| 908 | sub decode_b64 { | ||||
| 909 | my($self,$val) = @_; | ||||
| 910 | return MIME::Base64::decode($val); | ||||
| 911 | } | ||||
| 912 | |||||
| 4697a0af » | pab | 2007-12-26 | 913 | ||
| 914 | ########################################################################## | ||||
| 915 | # Parse a magnet link | ||||
| 916 | sub decode_magnet { | ||||
| 917 | my($self,$uri) = @_; | ||||
| 918 | my $xt = {}; | ||||
| 919 | if($uri =~ /^magnet:\?(.+)$/) { | ||||
| 920 | foreach my $item (split(/&/,$1)) { | ||||
| 921 | if($item =~ /^(([^=\.]+)(\.\d+)?)=(.+)$/) { | ||||
| 922 | my $mk = $2; | ||||
| 923 | my @it = split(/:/,$4); | ||||
| 924 | my $mv = pop(@it); | ||||
| 925 | my $sk = join(':',@it) || ":"; | ||||
| 926 | push(@{$xt->{$mk}}, {$sk => $mv}); | ||||
| 927 | } | ||||
| 928 | } | ||||
| 929 | } | ||||
| 930 | return $xt; | ||||
| 931 | } | ||||
| ae176dce » | pab | 2008-01-04 | 932 | ||
| 933 | sub ExpandRange { | ||||
| 934 | my($self,@a) = @_; | ||||
| 935 | my %dedupe = (); | ||||
| 936 | foreach my $chunk (@a) { | ||||
| 937 | if($chunk =~ /^(\d+)-(\d+)$/) { if($2 <= 0xFFFF) { for($1..$2) { $dedupe{$_} = 1; } } } | ||||
| 938 | elsif($chunk =~ /^(\d+)$/) { $dedupe{abs($1)} = 1; } | ||||
| 939 | } | ||||
| 940 | return \%dedupe; | ||||
| 941 | } | ||||
| 942 | |||||
| 8343f78d » | pab | 2008-01-06 | 943 | ########################################################################## | |
| 944 | # Resolve hostnames | ||||
| 945 | sub Resolve { | ||||
| 946 | my($self,$name) = @_; | ||||
| 947 | my @iplist = (); | ||||
| 948 | my @result = gethostbyname($name); | ||||
| 949 | @iplist = map{ inet_ntoa($_) } @result[4..$#result]; | ||||
| 950 | return List::Util::shuffle(@iplist); | ||||
| 951 | } | ||||
| 97dfa070 » | pab | 2008-01-12 | 952 | ||
| 953 | ########################################################################## | ||||
| 954 | # Escape a HTTP-URI-Escaped string | ||||
| 955 | sub UriUnescape { | ||||
| 956 | my($self,$string) = @_; | ||||
| 957 | $string =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; | ||||
| 958 | return $string; | ||||
| 959 | } | ||||
| 960 | |||||
| 961 | ########################################################################## | ||||
| 962 | # Escape string | ||||
| 963 | sub UriEscape { | ||||
| 964 | my($self,$string) = @_; | ||||
| 965 | $string =~ s/([^A-Za-z0-9\-_.!~*'()\/])/sprintf("%%%02X",ord($1))/eg; | ||||
| 966 | return $string; | ||||
| 967 | } | ||||
| b36be24e » | pab | 2008-03-24 | 968 | ||
| 969 | ########################################################################## | ||||
| 970 | # Converts a CBX into a hashref | ||||
| 971 | sub CBxToRef { | ||||
| 972 | my($self,$buff) = @_; | ||||
| 973 | my $r = undef; | ||||
| 974 | $buff ||= ''; | ||||
| 975 | foreach my $line (split(/\n/,$buff)) { | ||||
| 976 | chomp($line); | ||||
| 977 | if($line =~ /^#/ or $line =~ /^\s*$/) { | ||||
| 978 | next; # Comment or empty line | ||||
| 979 | } | ||||
| 980 | elsif($line =~ /^([a-zA-Z0-9_\.]+)\s*=\s*(.*)$/) { | ||||
| 981 | $r->{$1} = $2; | ||||
| 982 | } | ||||
| 983 | else { | ||||
| 984 | # Ignore. Can't use panic anyway | ||||
| 985 | } | ||||
| 986 | } | ||||
| 987 | return $r; | ||||
| 988 | } | ||||
| 989 | |||||
| 990 | ########################################################################## | ||||
| 991 | # Convert hashref into CBX | ||||
| 992 | sub RefToCBx { | ||||
| 993 | my($self,$ref) = @_; | ||||
| 994 | my @caller = caller; | ||||
| 995 | my $buff = "# Written by $caller[0]\@$caller[2] on ".gmtime()."\n"; | ||||
| 996 | foreach my $key (sort(keys(%$ref))) { | ||||
| 997 | my $val = $ref->{$key}; | ||||
| 998 | $key =~ tr/a-zA-Z0-9_\.//cd; | ||||
| 999 | $val =~ tr/\r\n//d; | ||||
| 1000 | $buff .= sprintf("%-25s = %s\n",$key, $val); | ||||
| 1001 | } | ||||
| 1002 | return $buff."# EOF #\n"; | ||||
| 1003 | } | ||||
| ae176dce » | pab | 2008-01-04 | 1004 | ||
| 1e342af6 » | pab | 2008-05-04 | 1005 | ########################################################################## | |
| 1006 | # Generates a 'find' like dirlist | ||||
| 1007 | sub GenDirList { | ||||
| 1008 | my($self,$dstruct, $dir) = @_; | ||||
| 1009 | push(@{$dstruct->{_}},$dir); | ||||
| 1010 | my $pfx = join('/',@{$dstruct->{_}}); | ||||
| 1011 | opendir(DIR, $pfx); | ||||
| 1012 | foreach my $dirent (readdir(DIR)) { | ||||
| 1013 | my $fp = "$pfx/".$dirent; | ||||
| 1014 | next if $dirent eq '.'; # No thanks | ||||
| 1015 | next if $dirent eq '..'; # Ditto | ||||
| 1016 | next if (-l $fp); # Won't look at symlinks | ||||
| 1017 | push(@{$dstruct->{list}},$fp); | ||||
| 1018 | $self->GenDirList($dstruct,$dirent) if -d $fp; | ||||
| 1019 | } | ||||
| 1020 | closedir(DIR); | ||||
| 1021 | pop(@{$dstruct->{_}}); | ||||
| 1022 | } | ||||
| 6933c336 » | pab | 2008-05-04 | 1023 | ||
| 1024 | ########################################################################## | ||||
| 1025 | # Getopts like support | ||||
| 1026 | sub GetOpts { | ||||
| 1027 | my($self,$args) = @_; | ||||
| 1028 | my @leftovers = (); | ||||
| 1029 | my $ctx = undef; | ||||
| 1030 | my $argref = {}; | ||||
| 1031 | foreach my $this_arg (@$args) { | ||||
| caedb01c » | pab | 2008-06-29 | 1032 | if($this_arg =~ /^--?(.+)/) { | |
| 6933c336 » | pab | 2008-05-04 | 1033 | $ctx = $1; | |
| 1034 | $argref->{$ctx} = defined if !exists $argref->{$ctx}; | ||||
| 1035 | } | ||||
| 1036 | elsif(defined($ctx)) { | ||||
| 1037 | $argref->{$ctx} = $this_arg; | ||||
| 1038 | $ctx = undef; | ||||
| 1039 | } | ||||
| 1040 | else { | ||||
| 1041 | push(@leftovers, $this_arg); | ||||
| 1042 | } | ||||
| 1043 | } | ||||
| 1044 | @$args = @leftovers; | ||||
| 1045 | return $argref; | ||||
| 1046 | } | ||||
| 1e342af6 » | pab | 2008-05-04 | 1047 | ||
| eeafdc86 » | pab | 2008-05-28 | 1048 | ########################################################################## | |
| 1049 | # Return exclusive name | ||||
| 1050 | sub GetExclusiveDirectory { | ||||
| 1051 | my($self,$base,$id) = @_; | ||||
| 1052 | my $xname = undef; | ||||
| 1053 | foreach my $sfx (0..0xFFFF) { | ||||
| 1054 | $xname = $base."/".$id; | ||||
| 1055 | $xname .= ".$sfx" if $sfx != 0; | ||||
| 1056 | unless(-e $xname) { | ||||
| 1057 | return $xname; | ||||
| 1058 | } | ||||
| 1059 | } | ||||
| 1060 | return undef; | ||||
| 1061 | } | ||||
| 3a9518d5 » | pab | 2008-10-22 | 1062 | ||
| 1063 | ########################################################################## | ||||
| 1064 | # looping sysread implementation | ||||
| 1065 | # *BSD doesn't like big LENGTH values on sysread | ||||
| 1066 | # This provides a crappy warper to 'fix' this problem | ||||
| 1067 | # syswrite() doesn't seem to suffer the same problem ... | ||||
| 1068 | sub Sysread { | ||||
| 1069 | my($self, $fh, $ref, $bytes_needed) = @_; | ||||
| 1070 | |||||
| 1071 | my $bytes_left = $bytes_needed; | ||||
| 1072 | my $buff = ''; | ||||
| 1073 | |||||
| 1074 | $self->panic("Cannot read $bytes_needed bytes") if $bytes_needed < 0; | ||||
| 1075 | |||||
| 1076 | while($bytes_left > 0) { | ||||
| 1077 | my $br = sysread($fh, $buff, $bytes_left); | ||||
| 1078 | if($br) { ${$ref} .= $buff; $bytes_left -= $br; } # Data | ||||
| 1079 | elsif(defined($br)) { last; } # EOF | ||||
| 1080 | else { return undef; } # Error | ||||
| 1081 | } | ||||
| 1082 | |||||
| 1083 | return ($bytes_needed-$bytes_left); | ||||
| 1084 | } | ||||
| eeafdc86 » | pab | 2008-05-28 | 1085 | ||
| 1086 | |||||
| 33a74a49 » | pab | 2007-12-22 | 1087 | sub debug { my($self, $msg) = @_; $self->{super}->debug(ref($self).": ".$msg); } | |
| 1088 | sub stop { my($self, $msg) = @_; $self->{super}->stop(ref($self).": ".$msg); } | ||||
| 1089 | |||||
| 1090 | 1; | ||||
| 1091 | |||||
| 1092 | |||||
| 1093 | ############################################################################################################### | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1094 | # Bitflu Admin-Dispatcher : Release 20070319_1 | |
| 1095 | package Bitflu::Admin; | ||||
| 1096 | |||||
| 1097 | ########################################################################## | ||||
| 1098 | # Guess what? | ||||
| 1099 | sub new { | ||||
| 1100 | my($class, %args) = @_; | ||||
| 1101 | my $self = {super=> $args{super}, cmdlist => {}, notifylist => {}}; | ||||
| 1102 | bless($self,$class); | ||||
| 1103 | return $self; | ||||
| 1104 | } | ||||
| 1105 | |||||
| 1106 | ########################################################################## | ||||
| 1107 | # Init plugin | ||||
| 1108 | sub init { | ||||
| 1109 | my($self) = @_; | ||||
| bbbbb5fc » | pab | 2007-09-01 | 1110 | $self->RegisterCommand("help", $self, 'admincmd_help' , 'Displays what you are reading now', | |
| 1111 | [ [undef, "Use 'help' to get a list of all commands"], [undef, "Type 'help command' to get help about 'command'"] ]); | ||||
| b6c764b5 » | pab | 2007-12-01 | 1112 | $self->RegisterCommand("plugins", $self, 'admincmd_plugins', 'Displays all loaded plugins'); | |
| 1113 | $self->RegisterCommand("useradmin",$self, 'admincmd_useradm', 'Create and modify accounts', | ||||
| 1114 | [ [undef, "Usage: useradmin [set username password] [delete username] [list]"] ]); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1115 | $self->RegisterNotify($self, 'receive_notify'); | |
| caedb01c » | pab | 2008-06-29 | 1116 | $self->RegisterCommand("log", $self, 'admincmd_log', 'Display last log output', | |
| 1117 | [ [undef, "Usage: log [-limit]"], [undef, 'Example: log -10 # <-- displays the last 10 log entries'] ] ); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1118 | return 1; | |
| 1119 | } | ||||
| 1120 | |||||
| 1121 | ########################################################################## | ||||
| caedb01c » | pab | 2008-06-29 | 1122 | # Return logbuffer | |
| 1123 | sub admincmd_log { | ||||
| 1124 | my($self, @args) = @_; | ||||
| 1125 | my @A = (); | ||||
| 1126 | my @log = @{$self->{super}->{_LogBuff}}; | ||||
| 1127 | my $opts = $self->{super}->Tools->GetOpts(\@args); | ||||
| 1128 | my $limit = int(((keys(%$opts))[0]) || 0); | ||||
| 1129 | my $logsize = int(@log); | ||||
| 1130 | my $logat = ( $limit ? ( $logsize - $limit ) : 0 ); | ||||
| 1131 | my $i = 0; | ||||
| 1132 | |||||
| 1133 | foreach my $ll (@log) { | ||||
| 1134 | next if $i++ < $logat; | ||||
| 1135 | chomp($ll); | ||||
| 1136 | push(@A, [undef, $ll]); | ||||
| 1137 | } | ||||
| 1138 | return({MSG=>\@A, SCRAP=>[]}); | ||||
| 1139 | } | ||||
| 1140 | |||||
| 1141 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1142 | # Display registered plugins | |
| 1143 | sub admincmd_plugins { | ||||
| 1144 | my($self) = @_; | ||||
| 1145 | |||||
| 1146 | my @A = ([1, "Hooks registered at bitflus NSFS (NotSoFairScheduler)"]); | ||||
| bfb43a2a » | pab | 2008-09-07 | 1147 | foreach my $rx (@{$self->{super}->{_Runners}}) { | |
| 1148 | push(@A,[undef,$rx->{target}]); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1149 | } | |
| 1150 | |||||
| 98cc2b50 » | pab | 2007-12-28 | 1151 | return({MSG=>\@A, SCRAP=>[]}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1152 | } | |
| 1153 | |||||
| 1154 | ########################################################################## | ||||
| 1155 | # Notification handler, we are just going to print them out using the logging | ||||
| 1156 | sub receive_notify { | ||||
| 1157 | my($self,$msg) = @_; | ||||
| 1158 | $self->info("#NOTIFICATION#: $msg"); | ||||
| 1159 | } | ||||
| 1160 | |||||
| 1161 | ########################################################################## | ||||
| 1162 | # BareBones help | ||||
| 1163 | sub admincmd_help { | ||||
| bbbbb5fc » | pab | 2007-09-01 | 1164 | my($self,$topic) = @_; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1165 | my @A = (); | |
| 1166 | |||||
| bbbbb5fc » | pab | 2007-09-01 | 1167 | if($topic) { | |
| e6b5ae79 » | pab | 2007-09-15 | 1168 | if(defined($self->GetCommands->{$topic})) { | |
| 1169 | my @instances = @{$self->GetCommands->{$topic}}; | ||||
| bbbbb5fc » | pab | 2007-09-01 | 1170 | ||
| 1171 | foreach my $ci (@instances) { | ||||
| 1172 | push(@A, [3, "Command '$topic' (Provided by plugin $ci->{class})"]); | ||||
| 1173 | if($ci->{longhelp}) { | ||||
| 1174 | push(@A, @{$ci->{longhelp}}); | ||||
| 1175 | } | ||||
| 1176 | else { | ||||
| 1177 | push(@A, [undef, $ci->{help}]); | ||||
| 1178 | } | ||||
| 1179 | push(@A, [undef, '']); | ||||
| 1180 | } | ||||
| 1181 | } | ||||
| 1182 | else { | ||||
| 1183 | push(@A, [2, "No help for '$topic', command does not exist"]); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1184 | } | |
| 1185 | } | ||||
| bbbbb5fc » | pab | 2007-09-01 | 1186 | else { | |
| e6b5ae79 » | pab | 2007-09-15 | 1187 | foreach my $xcmd (sort (keys %{$self->GetCommands})) { | |
| bbbbb5fc » | pab | 2007-09-01 | 1188 | my $lb = sprintf("%-20s", $xcmd); | |
| 1189 | my @hlps = (); | ||||
| e6b5ae79 » | pab | 2007-09-15 | 1190 | foreach my $instance (@{$self->GetCommands->{$xcmd}}) { | |
| bbbbb5fc » | pab | 2007-09-01 | 1191 | push(@hlps, "$instance->{help}");; | |
| 1192 | } | ||||
| 1193 | |||||
| 1194 | $lb .= join(' / ',@hlps); | ||||
| 1195 | |||||
| 1196 | push(@A, [undef, $lb]); | ||||
| 1197 | } | ||||
| 1198 | } | ||||
| 1199 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 1200 | ||
| 98cc2b50 » | pab | 2007-12-28 | 1201 | return({MSG=>\@A, SCRAP=>[]}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1202 | } | |
| 1203 | |||||
| 1204 | ########################################################################## | ||||
| b6c764b5 » | pab | 2007-12-01 | 1205 | # Handles useradm commands | |
| 1206 | sub admincmd_useradm { | ||||
| 1207 | my($self, @args) = @_; | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1208 | ||
| 1209 | my @A = (); | ||||
| 1210 | my $ERR = ''; | ||||
| b6c764b5 » | pab | 2007-12-01 | 1211 | ||
| 1212 | my($cmd,$usr,$pass) = @args; | ||||
| 1213 | |||||
| 1214 | if($cmd eq 'set' && $pass) { | ||||
| 1215 | $self->__useradm_modify(Inject => {User=>$usr, Pass=>$pass}); | ||||
| 1216 | push(@A, [1, "Useraccount updated"]); | ||||
| 1217 | } | ||||
| 1218 | elsif($cmd eq 'delete' && $usr) { | ||||
| 1219 | if(defined $self->__useradm_modify->{$usr}) { | ||||
| 1220 | # -> Account exists | ||||
| 1221 | $self->__useradm_modify(Drop => {User=>$usr}); | ||||
| 1222 | push(@A, [1, "Account '$usr' removed"]); | ||||
| 1223 | $self->panic("BUG") if (defined $self->__useradm_modify->{$usr}); # Paranoia check | ||||
| 1224 | } | ||||
| 1225 | else { | ||||
| 1226 | push(@A, [2, "Account '$usr' does not exist"]); | ||||
| 1227 | } | ||||
| 1228 | } | ||||
| 1229 | elsif($cmd eq 'list') { | ||||
| 1230 | push(@A, [3, "Configured accounts:"]); | ||||
| 1231 | foreach my $k (keys(%{$self->__useradm_modify})) { | ||||
| 1232 | push(@A, [undef,$k]); | ||||
| 1233 | } | ||||
| 1234 | } | ||||
| 1235 | else { | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1236 | $ERR .= "Usage error, type 'help useradmin' for more information"; | |
| b6c764b5 » | pab | 2007-12-01 | 1237 | } | |
| 98cc2b50 » | pab | 2007-12-28 | 1238 | return({MSG=>\@A, SCRAP=>[], NOEXEC=>$ERR}); | |
| b6c764b5 » | pab | 2007-12-01 | 1239 | } | |
| 1240 | |||||
| 1241 | ########################################################################## | ||||
| 1242 | # Create password entry | ||||
| 1243 | sub __useradm_mkentry { | ||||
| 1244 | my($self,$usr,$pass) = @_; | ||||
| 1245 | $usr =~ tr/: ;=//d; | ||||
| 1246 | return undef if length($usr) == 0; | ||||
| 4697a0af » | pab | 2007-12-26 | 1247 | return $usr.":".$self->{super}->Tools->sha1_hex("$usr;$pass"); | |
| b6c764b5 » | pab | 2007-12-01 | 1248 | } | |
| 1249 | |||||
| 1250 | ########################################################################## | ||||
| 1251 | # Modify current setting | ||||
| 1252 | sub __useradm_modify { | ||||
| 1253 | my($self,%args) = @_; | ||||
| 1254 | my @result = (); | ||||
| 1255 | my $allusr = {}; | ||||
| 1256 | my $to_inject = ''; | ||||
| 1257 | my $delta = 0; | ||||
| 9ab51800 » | pab | 2007-12-31 | 1258 | foreach my $entry (split(/;/,($self->{super}->Configuration->GetValue('useradm') || ''))) { | |
| b6c764b5 » | pab | 2007-12-01 | 1259 | if(my($user,$hash) = $entry =~ /^([^:]*):(.+)$/) { | |
| 9ab51800 » | pab | 2007-12-31 | 1260 | if ($user ne ($args{Inject}->{User} || '') && $user ne ($args{Drop}->{User} || '')) { | |
| b6c764b5 » | pab | 2007-12-01 | 1261 | push(@result,$entry); | |
| 1262 | } | ||||
| 1263 | else { | ||||
| 1264 | $delta++; | ||||
| 1265 | } | ||||
| 1266 | $allusr->{$user} = $entry; | ||||
| 1267 | } | ||||
| 1268 | else { | ||||
| 1269 | $self->warn("Useradmin: Wiping garbage entry: '$entry'"); | ||||
| 1270 | } | ||||
| 1271 | } | ||||
| 1272 | |||||
| 1273 | if(exists($args{Inject}->{User})) { | ||||
| 1274 | $to_inject = $args{Inject}->{User}; | ||||
| 1275 | $to_inject =~ tr/:; //d; | ||||
| 1276 | $delta++; | ||||
| 1277 | } | ||||
| 1278 | |||||
| 1279 | if(length($to_inject) > 0) { | ||||
| 1280 | push(@result,$self->__useradm_mkentry($to_inject,$args{Inject}->{Pass})); | ||||
| 1281 | } | ||||
| 1282 | |||||
| 1283 | $self->{super}->Configuration->SetValue('useradm', join(';', @result)) if $delta; | ||||
| 1284 | return $allusr; | ||||
| 1285 | } | ||||
| 1286 | |||||
| 1287 | |||||
| 1288 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1289 | # Register Notify handler | |
| 1290 | sub RegisterNotify { | ||||
| 1291 | my($self, $xref, $xcmd) = @_; | ||||
| 1292 | $self->debug("RegisterNotify: Will notify $xref via $xref->$xcmd"); | ||||
| 1293 | $self->{notifylist}->{$xref} = { class => $xref, cmd => $xcmd }; | ||||
| 1294 | } | ||||
| 1295 | |||||
| 1296 | ########################################################################## | ||||
| 1297 | # Send out notifications | ||||
| 1298 | sub SendNotify { | ||||
| 1299 | my($self,$msg) = @_; | ||||
| 1300 | foreach my $kx (keys(%{$self->{notifylist}})) { | ||||
| 1301 | my $nc = $self->{notifylist}->{$kx}; | ||||
| 1302 | my $class = $nc->{class}; my $cmd = $nc->{cmd}; | ||||
| 1303 | $class->$cmd($msg); | ||||
| 1304 | } | ||||
| 1305 | } | ||||
| 1306 | |||||
| 1307 | ########################################################################## | ||||
| 1308 | # Registers a new command to be used with ExecuteCommand | ||||
| 1309 | sub RegisterCommand { | ||||
| bbbbb5fc » | pab | 2007-09-01 | 1310 | my($self,$name,$xref,$xcmd,$helptext,$longhelp) = @_; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1311 | $self->debug("RegisterCommand: Hooking $name to $xref->$xcmd"); | |
| bbbbb5fc » | pab | 2007-09-01 | 1312 | push(@{$self->{cmdlist}->{$name}}, {class=>$xref, cmd=>$xcmd, help=>$helptext, longhelp=>$longhelp}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1313 | $helptext or $self->panic("=> $xcmd ; $xref"); | |
| 1314 | } | ||||
| 1315 | |||||
| 1316 | ########################################################################## | ||||
| e6b5ae79 » | pab | 2007-09-15 | 1317 | # Returns the full cmdlist | |
| 1318 | sub GetCommands { | ||||
| 1319 | my($self) = @_; | ||||
| 1320 | return $self->{cmdlist}; | ||||
| 1321 | } | ||||
| 1322 | |||||
| 1323 | ########################################################################## | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1324 | # Execute a command! | |
| 1325 | sub ExecuteCommand { | ||||
| 1326 | my($self,$command,@args) = @_; | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1327 | ||
| 1328 | |||||
| 1329 | my $plugin_hits = 0; | ||||
| 1330 | my $plugin_fails = 0; | ||||
| 1331 | my $plugin_ok = 0; | ||||
| 1332 | my @plugin_msg = (); | ||||
| 1333 | my @plugin_nex = (); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1334 | ||
| e6b5ae79 » | pab | 2007-09-15 | 1335 | if(ref($self->GetCommands->{$command}) eq "ARRAY") { | |
| 1336 | foreach my $ref (@{$self->GetCommands->{$command}}) { | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1337 | $plugin_hits++; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1338 | my $class = $ref->{class}; | |
| 1339 | my $cmd = $ref->{cmd}; | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1340 | my $bref = $class->$cmd(@args); | |
| 1341 | my $SCRAP = $bref->{SCRAP} or $self->panic("$class -> $cmd returned no SCRAP"); | ||||
| 1342 | my $MSG = $bref->{MSG} or $self->panic("$class -> $cmd returned no MSG"); | ||||
| 1343 | my $ERR = $bref->{NOEXEC}; | ||||
| 1344 | @args = @$SCRAP; | ||||
| 1345 | |||||
| 1346 | push(@plugin_msg, @$MSG); | ||||
| 1347 | |||||
| 1348 | if($ERR) { | ||||
| 1349 | push(@plugin_nex, $ERR); # Plugin usage error | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1350 | } | |
| 98cc2b50 » | pab | 2007-12-28 | 1351 | else { | |
| 1352 | $plugin_ok++; # Plugin could do something | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1353 | } | |
| 1354 | } | ||||
| 1355 | } | ||||
| 1356 | |||||
| 1357 | if($plugin_hits == 0) { | ||||
| 98cc2b50 » | pab | 2007-12-28 | 1358 | push(@plugin_msg, [2, "Unknown command '$command'"]); | |
| 1359 | $plugin_fails++; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1360 | } | |
| 02ad0fd9 » | pab | 2007-12-30 | 1361 | else { | |
| 1362 | foreach my $leftover (@args) { | ||||
| c9743480 » | pab | 2008-08-17 | 1363 | push(@plugin_msg, [2, "Failed to execute '$command $leftover'"]); | |
| 98cc2b50 » | pab | 2007-12-28 | 1364 | $plugin_fails++; | |
| 1365 | } | ||||
| 02ad0fd9 » | pab | 2007-12-30 | 1366 | ||
| 1367 | if($plugin_ok == 0) { | ||||
| 1368 | # Nothing executed, display all usage 'hints' | ||||
| 1369 | foreach my $xerr (@plugin_nex) { | ||||
| 1370 | push(@plugin_msg, [2, $xerr]); | ||||
| 1371 | $plugin_fails++; | ||||
| 1372 | } | ||||
| 1373 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1374 | } | |
| 98cc2b50 » | pab | 2007-12-28 | 1375 | return({MSG=>\@plugin_msg, FAILS=>$plugin_fails}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1376 | } | |
| 1377 | |||||
| b6c764b5 » | pab | 2007-12-01 | 1378 | ########################################################################## | |
| 1379 | # Returns TRUE if Authentication was successful (or disabled (= no accounts)) | ||||
| 1380 | sub AuthenticateUser { | ||||
| 1381 | my($self,%args) = @_; | ||||
| 1382 | my $numentry = int(keys(%{$self->__useradm_modify})); | ||||
| 1383 | return 1 if $numentry == 0; # No users, no security | ||||
| 1384 | |||||
| 1385 | my $expect = $self->__useradm_mkentry($args{User}, $args{Pass}); | ||||
| 1386 | if(defined($expect) && $self->__useradm_modify->{$args{User}} eq $expect ) { | ||||
| 1387 | return 1; | ||||
| 1388 | } | ||||
| 1389 | else { | ||||
| 1390 | return 0; | ||||
| 1391 | } | ||||
| 1392 | } | ||||
| 1393 | |||||
| d2039c3b » | pab | 2008-01-02 | 1394 | sub warn { my($self, $msg) = @_; $self->{super}->warn("Admin : ".$msg); } | |
| 1395 | sub debug { my($self, $msg) = @_; $self->{super}->debug("Admin : ".$msg); } | ||||
| 1396 | sub info { my($self, $msg) = @_; $self->{super}->info("Admin : ".$msg); } | ||||
| 1397 | sub panic { my($self, $msg) = @_; $self->{super}->panic("Admin : ".$msg); } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1398 | ||
| 1399 | 1; | ||||
| 1400 | |||||
| 1401 | |||||
| 1402 | ############################################################################################################### | ||||
| a90f2309 » | pab | 2007-12-20 | 1403 | # Bitflu Network-IO Lib : Release 20071220_1 | |
| 3b5c9a66 » | pab | 2007-08-25 | 1404 | package Bitflu::Network; | |
| 1405 | |||||
| 1406 | use strict; | ||||
| 1407 | use IO::Socket; | ||||
| 1408 | use IO::Select; | ||||
| 1409 | use POSIX; | ||||
| 1410 | |||||
| 839ea0fd » | pab | 2007-12-29 | 1411 | use constant NETSTATS => 2; # ReGen netstats each 2 seconds | |
| a90f2309 » | pab | 2007-12-20 | 1412 | use constant MAXONWIRE => 1024*1024; # Do not buffer more than 1mb per client connection | |
| 1413 | use constant BPS_MIN => 8; # Minimal upload speed per socket | ||||
| 1414 | use constant DEVNULL => '/dev/null'; # Path to /dev/null | ||||
| 1415 | use constant LT_UDP => 1; # Internal ID for UDP sockets | ||||
| 1416 | use constant LT_TCP => 2; # Internal ID for TCP sockets | ||||
| 8630fab0 » | pab | 2008-08-31 | 1417 | use constant BLIST_LIMIT => 1024; # NeverEver blacklist more than 1024 IPs per instance | |
| 1418 | use constant BLIST_TTL => 60*60; # BL entries are valid for 1 hour | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1419 | ||
| 1420 | ########################################################################## | ||||
| 1421 | # Creates a new Networking Object | ||||
| 1422 | sub new { | ||||
| 1423 | my($class, %args) = @_; | ||||
| 233883e5 » | pab | 2008-08-23 | 1424 | my $self = {super=> $args{super}, bpc=>BPS_MIN, NOWTIME => 0, timeflux=>0 , _bitflu_network => {}, avfds => 0, | |
| 3b5c9a66 » | pab | 2007-08-25 | 1425 | stats => {nextrun=>0, sent=>0, recv=>0, raw_recv=>0, raw_sent=>0} }; | |
| 1426 | bless($self,$class); | ||||
| 1427 | $self->SetTime; | ||||
| 1428 | $self->{avfds} = $self->TestFileDescriptors; | ||||
| 47dc3e98 » | pab | 2007-12-01 | 1429 | $self->debug("Reserved $self->{avfds} file descriptors for networking"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1430 | return $self; | |
| 1431 | } | ||||
| 1432 | |||||
| 1433 | ########################################################################## | ||||
| 1434 | # Register Admin commands | ||||
| 1435 | sub init { | ||||
| 1436 | my($self) = @_; | ||||
| d0b61b4e » | pab | 2008-06-23 | 1437 | $self->{super}->Admin->RegisterCommand('netstat' , $self, '_Command_Netstat', 'Displays networking information'); | |
| 1438 | $self->{super}->Admin->RegisterCommand('blacklist' , $self, '_Command_Blacklist', 'Show current in-memory IP-Blacklist'); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1439 | $self->SetTime; | |
| 1440 | return 1; | ||||
| 1441 | } | ||||
| 1442 | |||||
| 59365da4 » | pab | 2007-12-17 | 1443 | ########################################################################## | |
| 1444 | # Display netstat command | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1445 | sub _Command_Netstat { | |
| 1446 | my($self) = @_; | ||||
| 1447 | my @A = (); | ||||
| 1448 | my $bfn = $self->{_bitflu_network}; | ||||
| 1449 | |||||
| c664d5a6 » | pab | 2007-12-19 | 1450 | push(@A, [3, "Total file descriptors left : $self->{avfds}"]); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1451 | ||
| 1452 | foreach my $item (keys(%$bfn)) { | ||||
| c3035eb6 » | pab | 2008-06-08 | 1453 | if(exists($bfn->{$item}->{config})) { | |
| 98644351 » | pab | 2007-12-02 | 1454 | push(@A, [4, '-------------------------------------------------------------------------']); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1455 | push(@A, [1, "Handle: $item"]); | |
| 98644351 » | pab | 2007-12-02 | 1456 | push(@A, [undef,"Active connections : $bfn->{$item}->{config}->{cntMaxPeers}"]); | |
| 1457 | push(@A, [undef,"Connection hardlimit : $bfn->{$item}->{config}->{MaxPeers}"]); | ||||
| 1458 | push(@A, [undef,"Connections not yet established : ".int(keys(%{$bfn->{$item}->{establishing}}))]); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1459 | } | |
| 1460 | } | ||||
| 1461 | |||||
| 98cc2b50 » | pab | 2007-12-28 | 1462 | return({MSG=>\@A, SCRAP=>[]}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1463 | } | |
| 1464 | |||||
| d0b61b4e » | pab | 2008-06-23 | 1465 | sub _Command_Blacklist { | |
| c3035eb6 » | pab | 2008-06-08 | 1466 | my($self) = @_; | |
| 1467 | my @A = (); | ||||
| 1468 | my $bfn = $self->{_bitflu_network}; | ||||
| 1469 | |||||
| 1470 | foreach my $item (sort keys(%$bfn)) { | ||||
| 1471 | if(exists($bfn->{$item}->{config})) { | ||||
| 1472 | push(@A, [4, "Blacklist for ID $item"]); | ||||
| 1473 | my $blc = 0; | ||||
| 8630fab0 » | pab | 2008-08-31 | 1474 | while( my($k,$v) = each(%{$bfn->{$item}->{blacklist}->{bldb}}) ) { | |
| 7d437f18 » | pab | 2008-08-31 | 1475 | my $this_ttl = $v - $self->GetTime; | |
| 1476 | next if $this_ttl < 0; | ||||
| 1477 | push(@A, [2, sprintf(" %-24s (expires in %d seconds)",$k,$this_ttl)]); | ||||
| c3035eb6 » | pab | 2008-06-08 | 1478 | $blc++; | |
| 1479 | } | ||||
| 1480 | push(@A, [3, "$blc ip(s) are blacklisted"], [undef, '']); | ||||
| 1481 | } | ||||
| 1482 | } | ||||
| 1483 | |||||
| 1484 | return({MSG=>\@A, SCRAP=>[]}); | ||||
| 1485 | } | ||||
| 1486 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 1487 | ########################################################################## | |
| 1488 | # Test how many filedescriptors this OS / env can handle | ||||
| 1489 | sub TestFileDescriptors { | ||||
| 1490 | my($self) = @_; | ||||
| 1491 | my $i = 0; | ||||
| 1492 | my @fdx = (); | ||||
| 1493 | my $sysr = 0xF; | ||||
| 1494 | my $canhave = 0; | ||||
| 59365da4 » | pab | 2007-12-17 | 1495 | ||
| 1496 | open(FAKE, DEVNULL) or $self->stop("Unable to open ".DEVNULL.": $!"); | ||||
| 1497 | close(FAKE); | ||||
| 1498 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 1499 | while($i++ < 2048) { | |
| 59365da4 » | pab | 2007-12-17 | 1500 | unless( open($fdx[$i], DEVNULL) ) { | |
| 3b5c9a66 » | pab | 2007-08-25 | 1501 | last; | |
| 1502 | } | ||||
| 1503 | } | ||||
| 1504 | if($i > $sysr) { | ||||
| 1505 | $canhave = $i - $sysr; | ||||
| 1506 | } | ||||
| 1507 | else { | ||||
| 1508 | $self->panic("Sorry, bitfu can not run with only $i filedescriptors left"); | ||||
| 1509 | } | ||||
| 1510 | while(--$i > 0) { | ||||
| 1511 | close($fdx[$i]) or $self->panic("Unable to close TestFD # $i : $!"); | ||||
| 1512 | } | ||||
| 1513 | return $canhave; | ||||
| 1514 | } | ||||
| 1515 | |||||
| 1516 | ########################################################################## | ||||
| 1517 | # Refresh buffered time | ||||
| 1518 | sub SetTime { | ||||
| 1519 | my($self) = @_; | ||||
| 233883e5 » | pab | 2008-08-23 | 1520 | ||
| 1521 | my $NOW = time(); | ||||
| 1522 | |||||
| 1523 | if($NOW > $self->{NOWTIME}) { | ||||
| 1524 | $self->{NOWTIME} = $NOW; | ||||
| 1525 | } | ||||
| 1526 | elsif($NOW < $self->{NOWTIME}) { | ||||
| 1527 | $self->warn("Clock jumped backwards! Returning last known good time..."); | ||||
| 1528 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1529 | } | |
| 1530 | |||||
| 1531 | ########################################################################## | ||||
| 1532 | # Returns buffered time | ||||
| 1533 | sub GetTime { | ||||
| 1534 | my($self) = @_; | ||||
| 1535 | return $self->{NOWTIME}; | ||||
| 1536 | } | ||||
| 1537 | |||||
| 1538 | ########################################################################## | ||||
| 1539 | # Returns bandwidth statistics | ||||
| 1540 | sub GetStats { | ||||
| 1541 | my($self) = @_; | ||||
| 1542 | return $self->{stats}; | ||||
| 1543 | } | ||||
| 1544 | |||||
| 1545 | ########################################################################## | ||||
| 1546 | # Returns last IO for given socket | ||||
| 1547 | sub GetLastIO { | ||||
| 1548 | my($self,$socket) = @_; | ||||
| c664d5a6 » | pab | 2007-12-19 | 1549 | $self->panic("Cannot return lastio of vanished socket <$socket>") unless exists($self->{_bitflu_network}->{$socket}); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1550 | return $self->{_bitflu_network}->{$socket}->{lastio}; | |
| 1551 | } | ||||
| 1552 | |||||
| 59365da4 » | pab | 2007-12-17 | 1553 | ########################################################################## | |
| 02ad0fd9 » | pab | 2007-12-30 | 1554 | # Returns QueueLength of given socket | |
| 1555 | sub GetQueueLen { | ||||
| 1556 | my($self, $socket) = @_; | ||||
| 61deb2b5 » | pab | 2008-01-01 | 1557 | $self->panic("Cannot return qlen of vanished socket <$socket>") unless exists($self->{_bitflu_network}->{$socket}); | |
| 1558 | return ($self->{_bitflu_network}->{$socket}->{qlen} || 0); | ||||
| 1559 | } | ||||
| 1560 | |||||
| 1561 | ########################################################################## | ||||
| 1562 | # Returns how many bytes we can write to the queue | ||||
| 1563 | sub GetQueueFree { | ||||
| 1564 | my($self,$socket) = @_; | ||||
| 1565 | $self->panic("Cannot return qfree of vanished socket <$socket>") unless exists($self->{_bitflu_network}->{$socket}); | ||||
| 1566 | return(MAXONWIRE - $self->GetQueueLen($socket)); | ||||
| 02ad0fd9 » | pab | 2007-12-30 | 1567 | } | |
| 1568 | |||||
| 1569 | ########################################################################## | ||||
| a90f2309 » | pab | 2007-12-20 | 1570 | # Returns TRUE if socket is an INCOMING connection | |
| 1571 | sub IsIncoming { | ||||
| 1572 | my($self,$socket) = @_; | ||||
| 1573 | my $val = $self->{_bitflu_network}->{$socket}->{incoming}; | ||||
| 1574 | $self->panic("$socket has an undef value for 'incoming'") unless defined($val); | ||||
| 1575 | return $val; | ||||
| 1576 | } | ||||
| 1577 | |||||
| 1578 | ########################################################################## | ||||
| 59365da4 » | pab | 2007-12-17 | 1579 | # Create an UDP-Listen socket | |
| 46202084 » | pab | 2007-11-10 | 1580 | sub NewUdpListen { | |
| 1581 | my($self,%args) = @_; | ||||
| 1582 | return undef if(!defined($args{ID})); | ||||
| 1583 | return undef if(!defined($args{Port})); | ||||
| 1584 | |||||
| a90f2309 » | pab | 2007-12-20 | 1585 | if(exists($self->{_bitflu_network}->{$args{ID}})) { | |
| 46202084 » | pab | 2007-11-10 | 1586 | $self->panic("FATAL: $args{ID} has a listening socket, unable to create a second instance with the same ID"); | |
| 1587 | } | ||||
| 1588 | |||||
| 1589 | my $new_socket = IO::Socket::INET->new(LocalPort=>$args{Port}, LocalAddr=>$args{Bind}, Proto=>'udp') or return undef; | ||||
| a90f2309 » | pab | 2007-12-20 | 1590 | ||
| 156d901b » | pab | 2008-06-08 | 1591 | $self->{_bitflu_network}->{$args{ID}} = { select => undef, socket => $new_socket, rqi => 0, wqi => 0, config => { MaxPeers=>1, cntMaxPeers=>0, }, | |
| 1592 | blacklist => { pointer => 0, array => [], bldb => {}} }; | ||||
| a90f2309 » | pab | 2007-12-20 | 1593 | $self->{_bitflu_network}->{$args{ID}}->{listentype} = LT_UDP; | |
| 1594 | $self->{_bitflu_network}->{$args{ID}}->{select} = new IO::Select or $self->panic("Unable to create new IO::Select object: $!"); | ||||
| c664d5a6 » | pab | 2007-12-19 | 1595 | $self->{_bitflu_network}->{$args{ID}}->{select}->add($new_socket) or $self->panic("Unable to glue <$new_socket> to select object of $args{ID}: $!"); | |
| a90f2309 » | pab | 2007-12-20 | 1596 | $self->{_bitflu_network}->{$args{ID}}->{callbacks} = $args{Callbacks} or $self->panic("Unable to register UDP-Socket without any callbacks"); | |
| 46202084 » | pab | 2007-11-10 | 1597 | $self->Unblock($new_socket) or $self->panic("Unable to unblock $new_socket"); | |
| 1598 | return $new_socket; | ||||
| 1599 | } | ||||
| 1600 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 1601 | ########################################################################## | |
| 1602 | # Try to create a new listening socket | ||||
| c664d5a6 » | pab | 2007-12-19 | 1603 | # NewTcpListen(ID=>UniqueueRunnerId, Port=>PortToListen, Bind=>IPv4ToBind, Callbacks => {}) | |
| 3b5c9a66 » | pab | 2007-08-25 | 1604 | sub NewTcpListen { | |
| 1605 | my($self,%args) = @_; | ||||
| 1606 | return undef if(!defined($args{ID})); | ||||
| a90f2309 » | pab | 2007-12-20 | 1607 | my $socket = 0; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1608 | ||
| a90f2309 » | pab | 2007-12-20 | 1609 | if(exists($self->{_bitflu_network}->{$args{ID}})) { | |
| 3b5c9a66 » | pab | 2007-08-25 | 1610 | $self->panic("FATAL: $args{ID} has a listening socket, unable to create a second instance with the same ID"); | |
| 1611 | } | ||||
| a90f2309 » | pab | 2007-12-20 | 1612 | elsif($args{MaxPeers} < 1) { | |
| 1613 | $self->panic("$args{ID}: cannot reserve '$args{MaxPeers}' file descriptors"); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1614 | } | |
| a90f2309 » | pab | 2007-12-20 | 1615 | elsif($args{Port}) { | |
| 1616 | $socket = IO::Socket::INET->new(LocalPort=>$args{Port}, LocalAddr=>$args{Bind}, Proto=>'tcp', ReuseAddr=>1, Listen=>1) or return undef; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1617 | } | |
| a90f2309 » | pab | 2007-12-20 | 1618 | ||
| 156d901b » | pab | 2008-06-08 | 1619 | $self->{_bitflu_network}->{$args{ID}} = { select => undef, socket => $socket, rqi => 0, wqi => 0, config => { MaxPeers=>($args{MaxPeers}), cntMaxPeers=>0 }, | |
| 1620 | blacklist => { pointer => 0, array => [], bldb => {}} }; | ||||
| a90f2309 » | pab | 2007-12-20 | 1621 | $self->{_bitflu_network}->{$args{ID}}->{select} = new IO::Select or $self->panic("Unable to create new IO::Select object: $!"); | |
| 1622 | $self->{_bitflu_network}->{$args{ID}}->{listentype} = LT_TCP; | ||||
| c664d5a6 » | pab | 2007-12-19 | 1623 | $self->{_bitflu_network}->{$args{ID}}->{callbacks} = $args{Callbacks} or $self->panic("Unable to register TCP-Socket without any callbacks"); | |
| bfaf9db4 » | pab | 2008-05-09 | 1624 | $self->{_bitflu_network}->{$args{ID}}->{laddr_in} = sockaddr_in(0, ($args{Bind} ? inet_aton($args{Bind}) : INADDR_ANY)) or $self->panic("sockaddr failed"); | |
| a90f2309 » | pab | 2007-12-20 | 1625 | ||
| 1626 | if($socket) { | ||||
| 1627 | $self->{_bitflu_network}->{$args{ID}}->{select}->add($socket) or $self->panic("Unable to glue <$socket> to select object of $args{ID}: $!"); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1628 | } | |
| a90f2309 » | pab | 2007-12-20 | 1629 | ||
| 1630 | return $socket; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1631 | } | |
| 1632 | |||||
| 1633 | |||||
| 1634 | ########################################################################## | ||||
| 1635 | # Creates a new (outgoing) connection | ||||
| 1636 | # NewTcpConnection(ID=>UniqueRunnerId, Ipv4=>Ipv4, Port=>PortToConnect); | ||||
| 1637 | sub NewTcpConnection { | ||||
| 1638 | my($self, %args) = @_; | ||||
| 1639 | return undef if(!defined($args{ID})); | ||||
| 1640 | |||||
| a90f2309 » | pab | 2007-12-20 | 1641 | my $bfn_strct = $self->{_bitflu_network}->{$args{ID}}; | |
| 1642 | |||||
| 156d901b » | pab | 2008-06-08 | 1643 | if($self->{avfds} < 1) { | |
| 1644 | return undef; # No Filedescriptors left | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1645 | } | |
| 156d901b » | pab | 2008-06-08 | 1646 | elsif($bfn_strct->{config}->{cntMaxPeers} >= $bfn_strct->{config}->{MaxPeers}) { | |
| 1647 | return undef; # Maxpeers reached | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1648 | } | |
| a90f2309 » | pab | 2007-12-20 | 1649 | elsif($bfn_strct->{listentype} != LT_TCP) { | |
| 1650 | $self->panic("Cannot create TCP connection for socket of type ".$bfn_strct->{listentype}." using $args{ID}"); | ||||
| 1651 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1652 | ||
| 8343f78d » | pab | 2008-01-06 | 1653 | if(exists($args{Hostname})) { | |
| 156d901b » | pab | 2008-06-08 | 1654 | # -> Resolve | |
| 8343f78d » | pab | 2008-01-06 | 1655 | my @xresolved = $self->{super}->Tools->Resolve($args{Hostname}); | |
| 1656 | unless( ($args{Ipv4} = $xresolved[0] ) ) { | ||||
| 1657 | $self->warn("Cannot resolve $args{Hostname}"); | ||||
| 1658 | return undef; | ||||
| 1659 | } | ||||
| 1660 | } | ||||
| 1661 | |||||
| 1662 | if($args{Ipv4} !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { | ||||
| 1663 | $self->panic("Invalid IP: $args{Ipv4}"); | ||||
| 1664 | } | ||||
| 1665 | |||||
| 156d901b » | pab | 2008-06-08 | 1666 | if($self->IpIsBlacklisted($args{ID}, $args{Ipv4})) { | |
| caedb01c » | pab | 2008-06-29 | 1667 | $self->debug("Won't connect to blacklisted IP $args{Ipv4}"); | |
| 156d901b » | pab | 2008-06-08 | 1668 | return undef; | |
| 1669 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1670 | ||
| 1671 | my $proto = getprotobyname('tcp'); | ||||
| 1672 | my $sock = undef; | ||||
| 8343f78d » | pab | 2008-01-06 | 1673 | my $sin = undef; | |
| 1674 | |||||
| a90f2309 » | pab | 2007-12-20 | 1675 | socket($sock, AF_INET,SOCK_STREAM,$proto) or $self->panic("Failed to create a new socket : $!"); | |
| bfaf9db4 » | pab | 2008-05-09 | 1676 | bind($sock, $bfn_strct->{laddr_in}) or $self->panic("Failed to bind socket <$sock> to interface : $!"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1677 | eval { $sin = sockaddr_in($args{Port}, inet_aton($args{Ipv4})); }; | |
| 1678 | |||||
| 1679 | if(!defined($sin)) { | ||||
| 1680 | $self->warn("Unable to create socket for $args{Ipv4}:$args{Port}"); | ||||
| 1681 | return undef; | ||||
| 1682 | } | ||||
| 1683 | |||||
| 1684 | $self->Unblock($sock) or $self->panic("Failed to unblock new socket <$sock> : $!"); | ||||
| a90f2309 » | pab | 2007-12-20 | 1685 | if(exists($self->{_bitflu_network}->{$sock})) { | |
| 1686 | $self->panic("FATAL: DUPLICATE SOCKET-ID <$sock> ?!"); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1687 | } | |
| 1688 | |||||
| 1689 | # Write PerSocket information: establishing | outbuff | config | ||||
| a90f2309 » | pab | 2007-12-20 | 1690 | $bfn_strct->{establishing}->{$sock} = { socket => $sock, till => $self->GetTime+$args{Timeout}, sin => $sin }; | |
| 1691 | $self->{_bitflu_network}->{$sock} = { sockmap => $sock, handlemap => $args{ID}, fastwrite => 0, lastio => $self->GetTime, incoming => 0 }; | ||||
| 156d901b » | pab | 2008-06-08 | 1692 | $self->{avfds}--; | |
| 1693 | $bfn_strct->{config}->{cntMaxPeers}++; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1694 | return $sock; | |
| 1695 | } | ||||
| 1696 | |||||
| 1697 | |||||
| 1698 | ########################################################################## | ||||
| 1699 | # Run Network IO | ||||
| 1700 | # Run(UniqueIdToRun,{callbacks}); | ||||
| 1701 | sub Run { | ||||
| c664d5a6 » | pab | 2007-12-19 | 1702 | my($self, $handle_id) = @_; | |
| a90f2309 » | pab | 2007-12-20 | 1703 | my $select_handle = $self->{_bitflu_network}->{$handle_id}->{select} or $self->panic("$handle_id has no select handle"); | |
| c664d5a6 » | pab | 2007-12-19 | 1704 | my $callbacks = $self->{_bitflu_network}->{$handle_id}->{callbacks}; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1705 | $self->SetTime; | |
| 1706 | $self->_Throttle; | ||||
| 1707 | $self->_Establish($handle_id, $callbacks, $select_handle); | ||||
| 1708 | $self->_IOread($handle_id, $callbacks, $select_handle); | ||||
| 1709 | $self->_IOwrite($handle_id,$callbacks, $select_handle); | ||||
| 1710 | } | ||||
| 1711 | |||||
| 59365da4 » | pab | 2007-12-17 | 1712 | ########################################################################## | |
| 1713 | # Check establishing-queue | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1714 | sub _Establish { | |
| 1715 | my($self, $handle_id, $callbacks, $select_handle) = @_; | ||||
| 1716 | foreach my $ref (values(%{$self->{_bitflu_network}->{$handle_id}->{establishing}})) { | ||||
| 1717 | connect($ref->{socket},$ref->{sin}); | ||||
| 1718 | if($!{'EISCONN'}) { | ||||
| 1719 | delete($self->{_bitflu_network}->{$handle_id}->{establishing}->{$ref->{socket}}); | ||||
| 1720 | $select_handle->add($ref->{socket}); | ||||
| 1721 | } | ||||
| 1722 | elsif($ref->{till} < $self->GetTime) { | ||||
| 1723 | if(my $cbn = $callbacks->{Close}) { $handle_id->$cbn($ref->{socket}); } | ||||
| 1724 | $self->{_bitflu_network}->{$handle_id}->{config}->{cntMaxPeers}--; | ||||
| 1725 | $self->{avfds}++; | ||||
| 59365da4 » | pab | 2007-12-17 | 1726 | delete($self->{_bitflu_network}->{$handle_id}->{establishing}->{$ref->{socket}}) or $self->panic("Cannot remove ".$ref->{socket}." from $handle_id"); | |
| 1727 | delete($self->{_bitflu_network}->{$ref->{socket}}) or $self->panic("Cannot remove ".$ref->{socket}); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1728 | delete($self->{_bitflu_network}->{$handle_id}->{writeq}->{$ref->{socket}}); | |
| 1729 | close($ref->{socket}); | ||||
| 1730 | } | ||||
| 1731 | } | ||||
| 1732 | } | ||||
| 1733 | |||||
| a90f2309 » | pab | 2007-12-20 | 1734 | ########################################################################## | |
| 1735 | # Read from a bunch of sockets | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1736 | sub _IOread { | |
| 1737 | my($self, $handle_id, $callbacks, $select_handle) = @_; | ||||
| 1738 | |||||
| 1739 | |||||
| 1740 | if($self->{_bitflu_network}->{$handle_id}->{rqi} == 0) { | ||||
| 1741 | # Refill cache | ||||
| 1742 | my @sq = $select_handle->can_read(0); | ||||
| 1743 | $self->{_bitflu_network}->{$handle_id}->{rq} = \@sq; | ||||
| 1744 | $self->{_bitflu_network}->{$handle_id}->{rqi} = int(@sq); | ||||
| 1745 | } | ||||
| 1746 | |||||
| 71598963 » | pab | 2007-08-26 | 1747 | my $rpr = $self->{super}->Configuration->GetValue('readpriority'); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1748 | ||
| 1749 | while($self->{_bitflu_network}->{$handle_id}->{rqi} > 0) { | ||||
| a90f2309 » | pab | 2007-12-20 | 1750 | my $handle_ref = $self->{_bitflu_network}->{$handle_id}; # Get HandleID structure | |
| 1751 | my $tor = --$handle_ref->{rqi}; # Current Index to Read | ||||
| 1752 | my $socket = ${$handle_ref->{rq}}[$tor] or $self->panic(); # Current Socket | ||||
| 1753 | if($socket eq $handle_ref->{socket} && $handle_ref->{listentype} == LT_TCP) { | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1754 | my $new_sock = $socket->accept(); | |
| 7eb8f783 » | pab | 2007-12-22 | 1755 | my $new_ip = ''; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1756 | if(!defined($new_sock)) { | |
| 1757 | $self->info("Unable to accept new socket <$new_sock> : $!"); | ||||
| 1758 | } | ||||
| 156d901b » | pab | 2008-06-08 | 1759 | elsif($self->{avfds} < 1) { | |
| 3b5c9a66 » | pab | 2007-08-25 | 1760 | $self->warn("System has no file-descriptors left, dropping new incoming connection"); | |
| 1761 | $new_sock->close() or $self->panic("Unable to close <$new_sock> : $!"); | ||||
| 1762 | } | ||||
| 1763 | elsif(!$self->Unblock($new_sock)) { | ||||
| 1764 | $self->info("Unable to unblock $new_sock : $!"); | ||||
| 1765 | $new_sock->close() or $self->panic("Unable to close <$new_sock> : $!"); | ||||
| 1766 | } | ||||
| 7eb8f783 » | pab | 2007-12-22 | 1767 | elsif(!($new_ip = $new_sock->peerhost)) { | |
| 9c5f3648 » | pab | 2007-12-23 | 1768 | $self->debug("Unable to obtain peerhost from $new_sock : $!"); | |
| 7eb8f783 » | pab | 2007-12-22 | 1769 | $new_sock->close() or $self->panic("Unable to close <$new_sock> : $!"); | |
| 1770 | } | ||||
| 156d901b » | pab | 2008-06-08 | 1771 | elsif($handle_ref->{config}->{cntMaxPeers} >= $handle_ref->{config}->{MaxPeers}) { | |
| 3b5c9a66 » | pab | 2007-08-25 | 1772 | $self->warn("Handle <$handle_id> is full: Dropping new socket"); | |
| 1773 | $new_sock->close() or $self->panic("Unable to close <$new_sock> : $!"); | ||||
| 1774 | } | ||||
| 156d901b » | pab | 2008-06-08 | 1775 | elsif($self->IpIsBlacklisted($handle_id, $new_ip)) { | |
| 1776 | $self->warn("Refusing incoming connection from blacklisted IP $new_ip"); | ||||
| 1777 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1778 | else { | |
| a90f2309 » | pab | 2007-12-20 | 1779 | $self->{_bitflu_network}->{$new_sock} = { sockmap => $new_sock, handlemap => $handle_id, fastwrite => 0, lastio => $self->GetTime, incoming => 1 }; | |
| 3b5c9a66 » | pab | 2007-08-25 | 1780 | $select_handle->add($new_sock); | |
| 156d901b » | pab | 2008-06-08 | 1781 | $self->{avfds}--; | |
| 1782 | $handle_ref->{config}->{cntMaxPeers}++; | ||||
| 7eb8f783 » | pab | 2007-12-22 | 1783 | if(my $cbn = $callbacks->{Accept}) { $handle_id->$cbn($new_sock,$new_ip); } | |
| 3b5c9a66 » | pab | 2007-08-25 | 1784 | } | |
| 1785 | } | ||||
| a90f2309 » | pab | 2007-12-20 | 1786 | elsif(exists($self->{_bitflu_network}->{$socket})) { | |
| 30afc404 » | pab | 2007-12-18 | 1787 | my $full_buffer = ''; | |
| 1788 | my $full_bufflen = 0; | ||||
| 1789 | my $last_bufflen = 0; | ||||
| 1790 | |||||
| a90f2309 » | pab | 2007-12-20 | 1791 | for(0..8) { | |
| 30afc404 » | pab | 2007-12-18 | 1792 | my $pb = ''; | |
| ca8e7c3f » | pab | 2007-12-18 | 1793 | $last_bufflen = ( read($socket,$pb,POSIX::BUFSIZ) || 0 ); # Removes warnings ;-) | |
| 30afc404 » | pab | 2007-12-18 | 1794 | $full_buffer .= $pb; | |
| 1795 | $full_bufflen += $last_bufflen; | ||||
| c664d5a6 » | pab | 2007-12-19 | 1796 | last if $last_bufflen != POSIX::BUFSIZ; | |
| 30afc404 » | pab | 2007-12-18 | 1797 | } | |
| 1798 | |||||
| 1799 | if($full_bufflen != 0) { | ||||
| 1800 | # We read 'something'. If there was an error, we'll pick it up next time | ||||
| 1801 | $self->{stats}->{raw_recv} += $full_bufflen; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1802 | $self->{_bitflu_network}->{$socket}->{lastio} = $self->GetTime; | |
| 30afc404 » | pab | 2007-12-18 | 1803 | if(my $cbn = $callbacks->{Data}) { $handle_id->$cbn($socket, \$full_buffer, $full_bufflen); } | |
| 3b5c9a66 » | pab | 2007-08-25 | 1804 | } | |
| 1805 | else { | ||||
| 1806 | if(my $cbn = $callbacks->{Close}) { $handle_id->$cbn($socket); } | ||||
| 1807 | $self->RemoveSocket($handle_id,$socket); | ||||
| 1808 | } | ||||
| 1809 | } | ||||
| a90f2309 » | pab | 2007-12-20 | 1810 | elsif($handle_ref->{listentype} == LT_UDP) { | |
| 156d901b » | pab | 2008-06-08 | 1811 | my $new_ip = ''; | |
| 46202084 » | pab | 2007-11-10 | 1812 | my $buffer = undef; | |
| 156d901b » | pab | 2008-06-08 | 1813 | ||
| 1814 | $socket->recv($buffer,POSIX::BUFSIZ); # Read data from socket | ||||
| 1815 | |||||
| 1816 | if(!($new_ip = $socket->peerhost)) { | ||||
| 1817 | # Weirdo.. | ||||
| 1818 | $self->warn("<$socket> had no peerhost, data dropped"); | ||||
| 1819 | } | ||||
| 1820 | elsif($self->IpIsBlacklisted($handle_id, $new_ip)) { | ||||
| 1821 | $self->warn("Dropping UDP-Data from blacklisted IP $new_ip"); | ||||
| 1822 | } | ||||
| 1823 | elsif(my $cbn = $callbacks->{Data}) { | ||||
| 1824 | $handle_id->$cbn($socket, \$buffer); | ||||
| 1825 | } | ||||
| 46202084 » | pab | 2007-11-10 | 1826 | } | |
| a90f2309 » | pab | 2007-12-20 | 1827 | else { | |
| 1828 | $self->warn("Skipping read from <$socket> / Not active?"); | ||||
| 1829 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1830 | last if --$rpr < 0; | |
| 1831 | } | ||||
| 1832 | } | ||||
| 1833 | |||||
| a90f2309 » | pab | 2007-12-20 | 1834 | ########################################################################## | |
| 1835 | # Write to some sockets | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1836 | sub _IOwrite { | |
| 1837 | my($self, $handle_id, $callbacks, $select_handle) = @_; | ||||
| a90f2309 » | pab | 2007-12-20 | 1838 | ||
| 1839 | my $handle_ref = $self->{_bitflu_network}->{$handle_id}; | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1840 | ||
| 59365da4 » | pab | 2007-12-17 | 1841 | if($handle_ref->{wqi} == 0) { | |
| 3b5c9a66 » | pab | 2007-08-25 | 1842 | # Refill cache | |
| 59365da4 » | pab | 2007-12-17 | 1843 | my @sq = (values(%{$handle_ref->{writeq}})); | |
| 1844 | $handle_ref->{wq} = \@sq; | ||||
| 1845 | $handle_ref->{wqi} = int(@sq); | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1846 | } | |
| 1847 | |||||
| 1848 | my $wpr = $self->{super}->Configuration->GetValue('writepriority'); | ||||
| 59365da4 » | pab | 2007-12-17 | 1849 | while($handle_ref->{wqi} > 0) { | |
| 1850 | my $tow = --$handle_ref->{wqi}; | ||||
| 1851 | my $socket = ${$handle_ref->{wq}}[$tow]; | ||||
| 1852 | $self->panic("No socket!") unless $socket; | ||||
| c664d5a6 » | pab | 2007-12-19 | 1853 | next unless exists($self->{_bitflu_network}->{$handle_id}->{writeq}->{$socket}); # Socket vanished or no writequeue | |
| a90f2309 » | pab | 2007-12-20 | 1854 | $self->_TryWrite(Socket=>$socket, Handle=>$handle_id, CanKill=>1); | |
| 3b5c9a66 » | pab | 2007-08-25 | 1855 | last if --$wpr < 0; | |
| 1856 | } | ||||
| 1857 | } | ||||
| 1858 | |||||
| a90f2309 » | pab | 2007-12-20 | 1859 | ||
| 1860 | ########################################################################## | ||||
| 1861 | # Try to write data to a socket | ||||
| c664d5a6 » | pab | 2007-12-19 | 1862 | sub _TryWrite { | |
| 1863 | my($self, %args) = @_; | ||||
| 1864 | |||||
| a90f2309 » | pab | 2007-12-20 | 1865 | my $socket = $args{Socket} or $self->panic; | |
| 1866 | my $handle_id = $args{Handle} or $self->panic; | ||||
| 1867 | my $socket_strct = $self->{_bitflu_network}->{$socket} or $self->panic; | ||||
| 1868 | my $handle_strct = $self->{_bitflu_network}->{$args{Handle}} or $self->panic; | ||||
| 1869 | my $select_handle = $handle_strct->{select} or $self->panic; | ||||
| 1870 | my $bufsize = ($self->{bpc} + $socket_strct->{fastwrite}) or $self->panic; | ||||
| 1871 | my $cankill = $args{CanKill}; | ||||
| c664d5a6 » | pab | 2007-12-19 | 1872 | ||
| a90f2309 » | pab | 2007-12-20 | 1873 | if(!$select_handle->exists($socket)) { return; } # not yet connected | |
| c664d5a6 » | pab | 2007-12-19 | 1874 | ||
| a90f2309 » | pab | 2007-12-20 | 1875 | my $bytes_sent = syswrite($socket, $socket_strct->{outbuff}, ($bufsize > (POSIX::BUFSIZ) ? (POSIX::BUFSIZ) : $bufsize) ); | |
| c664d5a6 » | pab | 2007-12-19 | 1876 | ||
| 1877 | if($!{'EISCONN'}) { | ||||
| 1878 | #$self->debug("EISCONN returned."); | ||||
| 1879 | } | ||||
| 1880 | elsif(!defined($bytes_sent)) { | ||||
| 1881 | if($!{'EAGAIN'} or $!{'EWOULDBLOCK'}) { | ||||
| 1882 | #$self->warn("$wsocket returned EAGAIN"); | ||||
| 1883 | } | ||||
| 1884 | elsif($cankill) { | ||||
| 1885 | if(my $cbn = $handle_strct->{callbacks}->{Close}) { $handle_id->$cbn($socket); } | ||||
| 1886 | $self->RemoveSocket($handle_id,$socket); | ||||
| 1887 | } | ||||
| a90f2309 » | pab | 2007-12-20 | 1888 | else { | |
| 97dfa070 » | pab | 2008-01-12 | 1889 | $self->debug("Delaying kill of $handle_id -> $socket [Write failed with: $!]"); | |
| a90f2309 » | pab | 2007-12-20 | 1890 | } | |
| c664d5a6 » | pab | 2007-12-19 | 1891 | } | |
| 1892 | else { | ||||
| 1893 | $self->{stats}->{raw_sent} += $bytes_sent; | ||||
| 1894 | $socket_strct->{qlen} -= $bytes_sent; | ||||
| a90f2309 » | pab | 2007-12-20 | 1895 | $socket_strct->{outbuff} = substr($socket_strct->{outbuff},$bytes_sent); | |
| 1896 | $socket_strct->{fastwrite} = 0 if( ($socket_strct->{fastwrite} -= $bytes_sent) < 0); | ||||
| c664d5a6 » | pab | 2007-12-19 | 1897 | if($socket_strct->{qlen} == 0) { | |
| 1898 | delete($handle_strct->{writeq}->{$socket}) or $self->panic("Deleting non-existing socket: Handle: $handle_id ; Sock: $socket"); | ||||
| 1899 | } | ||||
| 1900 | } | ||||
| 1901 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1902 | ||
| 1903 | |||||
| a90f2309 » | pab | 2007-12-20 | 1904 | ########################################################################## | |
| 1905 | # Calculate new value for bcp | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 1906 | sub _Throttle { | |
| 1907 | my($self) = @_; | ||||
| 1908 | return if $self->GetTime <= $self->{stats}->{nextrun}; | ||||
| 1909 | my $UPSPEED = $self->{super}->Configuration->GetValue('upspeed') * 1024; | ||||
| 1910 | |||||
| 1911 | if($self->{stats}->{nextrun} != 0) { | ||||
| 1912 | my $resolution = $self->GetTime - $self->{stats}->{nextrun} + NETSTATS; | ||||
| 1913 | $self->{stats}->{sent} = $self->{stats}->{raw_sent} / $resolution; | ||||
| 1914 | $self->{stats}->{recv} = $self->{stats}->{raw_recv} / $resolution; | ||||
| 1915 | $self->{stats}->{raw_sent} = 0; | ||||
| 1916 | $self->{stats}->{raw_recv} = 0; | ||||
| 1917 | # Throttle upspeed | ||||
| 1918 | my $current_upspeed = $self->{stats}->{sent}; | ||||
| 1919 | my $wanted_upspeed = $UPSPEED; | ||||
| 1920 | my $upspeed_drift = $UPSPEED-$current_upspeed; | ||||
| 1921 | my $upspeed_adjust = 1; # = Nothing | ||||
| 1922 | |||||
| 1923 | if($upspeed_drift < -500) { | ||||
| 1924 | $upspeed_adjust = ($wanted_upspeed/($current_upspeed+1)); | ||||
| 1925 | } | ||||
| 1926 | elsif($upspeed_drift > 500) { | ||||
| 1927 | $upspeed_adjust = ($wanted_upspeed/($current_upspeed+1)); | ||||
| 1928 | } | ||||
| 1929 | |||||
| 1930 | $upspeed_adjust = 1.3 if $upspeed_adjust > 1.3; # Do not bump up too fast.. | ||||
| 1931 | $self->{bpc} = int($self->{bpc} * $upspeed_adjust); | ||||
| 1932 | if($self->{bpc} < BPS_MIN) { $self->{bpc} = BPS_MIN } | ||||
| 1933 | elsif($self->{bpc} > POSIX::BUFSIZ) { $self->{bpc} = POSIX::BUFSIZ } | ||||
| 1934 | } | ||||
| 1935 | |||||
| 1936 | $self->{stats}->{nextrun} = NETSTATS + $self->GetTime; | ||||
| 1937 | } | ||||
| 1938 | |||||
| 1939 | |||||
| 1940 | |||||
| 1941 | ########################################################################## | ||||
| 1942 | # Remove socket | ||||
| 1943 | # RemoveSocket(UniqueRunId, Socket) | ||||
| 1944 | sub RemoveSocket { | ||||
| 1945 | my($self,$handle_id, $socket) = @_; | ||||
| 1946 | |||||
| 1947 | if($self->{_bitflu_network}->{$handle_id}->{select}->exists($socket)) { | ||||
| 1948 | $self->{_bitflu_network}->{$handle_id}->{select}->remove($socket) or $self->panic("Unable to remove <$socket>"); | ||||
| 1949 | } | ||||
| 1950 | elsif(delete($self->{_bitflu_network}->{$handle_id}->{establishing}->{$socket})) { | ||||
| 1951 | # Kill unestablished sock | ||||
| 1952 | } | ||||
| 1953 | else { | ||||
| 1954 | $self->panic("FATAL: <$socket> was not attached to IO::Select and not establishing!"); | ||||
| 1955 | } | ||||
| 1956 | |||||
| 1957 | # Correct statistics | ||||
| 1958 | $self->{_bitflu_network}->{$handle_id}->{config}->{cntMaxPeers}--; | ||||
| 1959 | $self->{avfds}++; | ||||
| 1960 | |||||
| 1961 | # Wipe socket itself + writeq | ||||
| 1962 | delete($self->{_bitflu_network}->{$socket}) or $self->panic("Unable to remove non-existent socketmap for <$socket>"); | ||||
| 1963 | delete($self->{_bitflu_network}->{$handle_id}->{writeq}->{$socket}); | ||||
| 1964 | close($socket) or $self->panic("Unable to close socket $socket : $!"); | ||||
| 1965 | } | ||||
| 1966 | |||||
| 46202084 » | pab | 2007-11-10 | 1967 | ||
| a90f2309 » | pab | 2007-12-20 | 1968 | ########################################################################## | |
| 1969 | # Send UPD datagram | ||||
| 46202084 » | pab | 2007-11-10 | 1970 | sub SendUdp { | |
| 1971 | my($self, $socket, %args) = @_; | ||||
| 1972 | my $ip = $args{Ip} or $self->panic("No IP given"); | ||||
| 1973 | my $port = $args{Port} or $self->panic("No Port given"); | ||||
| 156d901b » | pab | 2008-06-08 | 1974 | my $id = $args{ID} or $self->panic("No ID given"); | |
| 46202084 » | pab | 2007-11-10 | 1975 | my $data = $args{Data}; | |
| 156d901b » | pab | 2008-06-08 | 1976 | if($self->IpIsBlacklisted($id, $ip)) { | |
| 1977 | $self->warn("Won't send UDP-Data to blacklisted IP $ip"); | ||||
| 1978 | return undef; | ||||
| 1979 | } | ||||
| 1980 | else { | ||||
| 1981 | my $hisip = IO::Socket::inet_aton($ip); | ||||
| 1982 | my $hispn = IO::Socket::sockaddr_in($port, $hisip); | ||||
| 1983 | my $bs = send($socket,$data,0,$hispn); | ||||
| 1984 | return $bs; | ||||
| 1985 | } | ||||
| 46202084 » | pab | 2007-11-10 | 1986 | } | |
| 1987 | |||||
| a90f2309 » | pab | 2007-12-20 | 1988 | ########################################################################## | |
| 1989 | # FastWrite data | ||||
| c664d5a6 » | pab | 2007-12-19 | 1990 | sub WriteDataNow { | |
| 1991 | my($self,$socket,$buffer) = @_; | ||||
| a90f2309 » | pab | 2007-12-20 | 1992 | $self->{_bitflu_network}->{$socket}->{fastwrite} += length($buffer); | |
| c664d5a6 » | pab | 2007-12-19 | 1993 | $self->WriteData($socket,$buffer); | |
| 1994 | } | ||||
| 1995 | |||||
| 3b5c9a66 » | pab | 2007-08-25 | 1996 | ########################################################################## | |
| 1997 | # Write Data to socket | ||||
| 1998 | # WriteData(UniqueRunId, Socket, DataToWRite) | ||||
| 1999 | sub WriteData { | ||||
| 2000 | my($self, $socket, $buffer) = @_; | ||||
| 2001 | |||||
| 2002 | my $gotspace = 1; | ||||
| 61deb2b5 » | pab | 2008-01-01 | 2003 | my $queued_bytes = $self->GetQueueLen($socket); | |
| 3b5c9a66 » | pab | 2007-08-25 | 2004 | my $this_bytes = length($buffer); | |
| 2005 | my $total_bytes = $queued_bytes + $this_bytes; | ||||
| a90f2309 » | pab | 2007-12-20 | 2006 | my $handle_id = $self->{_bitflu_network}->{$socket}->{handlemap} or $self->panic("No handleid for $socket ?"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 2007 | ||
| 2008 | if($total_bytes > MAXONWIRE) { | ||||
| 61deb2b5 » | pab | 2008-01-01 | 2009 | $self->warn("<$socket> Buffer overrun! Too much unsent data: $total_bytes bytes"); | |
| 3b5c9a66 » | pab | 2007-08-25 | 2010 | $gotspace = 0; | |
| 2011 | } | ||||
| a90f2309 » | pab | 2007-12-20 | 2012 | elsif($self->{_bitflu_network}->{$handle_id}->{listentype} != LT_TCP) { | |
| 2013 | $self->panic("Cannot write tcp data to non-tcp socket $socket ($self->{_bitflu_network}->{$handle_id}->{listentype})"); | ||||
| 2014 | } | ||||
| 3b5c9a66 » | pab | 2007-08-25 | 2015 | else { | |
| 2016 | $self->{_bitflu_network}->{$socket}->{outbuff} .= $buffer; | ||||
| 2017 | $self->{_bitflu_network}->{$socket}->{lastio} = $self->GetTime; | ||||
| 2018 | $self->{_bitflu_network}->{$socket}->{qlen} | ||||
