PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/HTTP/Proxy/Engine/Legacy.pm

http://github.com/book/HTTP-Proxy
Perl | 180 lines | 118 code | 54 blank | 8 comment | 18 complexity | 93c2ea06db8a877f8c992d551b3c644d MD5 | raw file
  1. package HTTP::Proxy::Engine::Legacy;
  2. use strict;
  3. use POSIX 'WNOHANG';
  4. use HTTP::Proxy;
  5. use HTTP::Proxy::Engine;
  6. our @ISA = qw( HTTP::Proxy::Engine );
  7. our %defaults = (
  8. max_clients => 12,
  9. );
  10. __PACKAGE__->make_accessors( qw( kids select ), keys %defaults );
  11. sub start {
  12. my $self = shift;
  13. $self->kids( [] );
  14. $self->select( IO::Select->new( $self->proxy->daemon ) );
  15. }
  16. sub run {
  17. my $self = shift;
  18. my $proxy = $self->proxy;
  19. my $kids = $self->kids;
  20. # check for new connections
  21. my @ready = $self->select->can_read(1);
  22. for my $fh (@ready) { # there's only one, anyway
  23. # single-process proxy (useful for debugging)
  24. if ( $self->max_clients == 0 ) {
  25. $proxy->max_keep_alive_requests(1); # do not block simultaneous connections
  26. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS",
  27. "No fork allowed, serving the connection" );
  28. $proxy->serve_connections($fh->accept);
  29. $proxy->new_connection;
  30. next;
  31. }
  32. if ( @$kids >= $self->max_clients ) {
  33. $proxy->log( HTTP::Proxy::ERROR, "PROCESS",
  34. "Too many child process, serving the connection" );
  35. $proxy->serve_connections($fh->accept);
  36. $proxy->new_connection;
  37. next;
  38. }
  39. # accept the new connection
  40. my $conn = $fh->accept;
  41. my $child = fork;
  42. if ( !defined $child ) {
  43. $conn->close;
  44. $proxy->log( HTTP::Proxy::ERROR, "PROCESS", "Cannot fork" );
  45. $self->max_clients( $self->max_clients - 1 )
  46. if $self->max_clients > @$kids;
  47. next;
  48. }
  49. # the parent process
  50. if ($child) {
  51. $conn->close;
  52. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", "Forked child process $child" );
  53. push @$kids, $child;
  54. }
  55. # the child process handles the whole connection
  56. else {
  57. $SIG{INT} = 'DEFAULT';
  58. $proxy->serve_connections($conn);
  59. exit; # let's die!
  60. }
  61. }
  62. $self->reap_zombies if @$kids;
  63. }
  64. sub stop {
  65. my $self = shift;
  66. my $kids = $self->kids;
  67. # wait for remaining children
  68. # EOLOOP
  69. kill INT => @$kids;
  70. $self->reap_zombies while @$kids;
  71. }
  72. # private reaper sub
  73. sub reap_zombies {
  74. my $self = shift;
  75. my $kids = $self->kids;
  76. my $proxy = $self->proxy;
  77. while (1) {
  78. my $pid = waitpid( -1, WNOHANG );
  79. last if $pid == 0 || $pid == -1; # AS/Win32 returns negative PIDs
  80. @$kids = grep { $_ != $pid } @$kids;
  81. $proxy->{conn}++; # Cannot use the interface for RO attributes
  82. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", "Reaped child process $pid" );
  83. $proxy->log( HTTP::Proxy::PROCESS, "PROCESS", @$kids . " remaining kids: @$kids" );
  84. }
  85. }
  86. 1;
  87. __END__
  88. =head1 NAME
  89. HTTP::Proxy::Engine::Legacy - The "older" HTTP::Proxy engine
  90. =head1 SYNOPSIS
  91. my $proxy = HTTP::Proxy->new( engine => 'Legacy' );
  92. =head1 DESCRIPTION
  93. This engine reproduces the older child creation algorithm of L<HTTP::Proxy>.
  94. Angelos Karageorgiou C<< <angelos@unix.gr> >> reports:
  95. I<I got the Legacy engine to work really fast under C<Win32> with the following trick:>
  96. max_keep_alive_requests(1);
  97. max_clients(120);
  98. $HTTP::VERSION(1.0); # just in case
  99. I<and it smokes.>
  100. I<It seems that forked children are really slow when calling select for handling C<keep-alive>d requests!>
  101. =head1 METHODS
  102. The module defines the following methods, used by L<HTTP::Proxy> main loop:
  103. =over 4
  104. =item start()
  105. Initialise the engine.
  106. =item run()
  107. Implements the forking logic: a new process is forked for each new
  108. incoming TCP connection.
  109. =item stop()
  110. Reap remaining child processes.
  111. =back
  112. The following method is used by the engine internally:
  113. =over 4
  114. =item reap_zombies()
  115. Process the dead child processes.
  116. =back
  117. =head1 SEE ALSO
  118. L<HTTP::Proxy>, L<HTTP::Proxy::Engine>.
  119. =head1 AUTHOR
  120. Philippe "BooK" Bruhat, C<< <book@cpan.org> >>.
  121. =head1 COPYRIGHT
  122. Copyright 2005-2015, Philippe Bruhat.
  123. =head1 LICENSE
  124. This module is free software; you can redistribute it or modify it under
  125. the same terms as Perl itself.
  126. =cut