Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
5.0 KiB

  1. # ======================================================================
  2. #
  3. # Copyright (C) 2000 Lincoln D. Stein
  4. #
  5. # ======================================================================
  6. package IO::SessionSet;
  7. use strict;
  8. use Carp;
  9. use IO::Select;
  10. use IO::Handle;
  11. use IO::SessionData;
  12. use vars '$DEBUG';
  13. $DEBUG = 0;
  14. # Class method new()
  15. # Create a new Session set.
  16. # If passed a listening socket, use that to
  17. # accept new IO::SessionData objects automatically.
  18. sub new {
  19. my $pack = shift;
  20. my $listen = shift;
  21. my $self = bless {
  22. sessions => {},
  23. readers => IO::Select->new(),
  24. writers => IO::Select->new(),
  25. },$pack;
  26. # if initialized with an IO::Handle object (or subclass)
  27. # then we treat it as a listening socket.
  28. if ( defined($listen) and $listen->can('accept') ) {
  29. $self->{listen_socket} = $listen;
  30. $self->{readers}->add($listen);
  31. }
  32. return $self;
  33. }
  34. # Object method: sessions()
  35. # Return list of all the sessions currently in the set.
  36. sub sessions { return values %{shift->{sessions}} };
  37. # Object method: add()
  38. # Add a handle to the session set. Will automatically
  39. # create a IO::SessionData wrapper around the handle.
  40. sub add {
  41. my $self = shift;
  42. my ($handle,$writeonly) = @_;
  43. warn "Adding a new session for $handle.\n" if $DEBUG;
  44. return $self->{sessions}{$handle} = $self->SessionDataClass->new($self,$handle,$writeonly);
  45. }
  46. # Object method: delete()
  47. # Remove a session from the session set. May pass either a handle or
  48. # a corresponding IO::SessionData wrapper.
  49. sub delete {
  50. my $self = shift;
  51. my $thing = shift;
  52. my $handle = $self->to_handle($thing);
  53. my $sess = $self->to_session($thing);
  54. warn "Deleting session $sess handle $handle.\n" if $DEBUG;
  55. delete $self->{sessions}{$handle};
  56. $self->{readers}->remove($handle);
  57. $self->{writers}->remove($handle);
  58. }
  59. # Object method: to_handle()
  60. # Return a handle, given either a handle or a IO::SessionData object.
  61. sub to_handle {
  62. my $self = shift;
  63. my $thing = shift;
  64. return $thing->handle if $thing->isa('IO::SessionData');
  65. return $thing if defined (fileno $thing);
  66. return; # undefined value
  67. }
  68. # Object method: to_session
  69. # Return a IO::SessionData object, given either a handle or the object itself.
  70. sub to_session {
  71. my $self = shift;
  72. my $thing = shift;
  73. return $thing if $thing->isa('IO::SessionData');
  74. return $self->{sessions}{$thing} if defined (fileno $thing);
  75. return; # undefined value
  76. }
  77. # Object method: activate()
  78. # Called with parameters ($session,'read'|'write' [,$activate])
  79. # If called without the $activate argument, will return true
  80. # if the indicated handle is on the read or write IO::Select set.
  81. # May use either a session object or a handle as first argument.
  82. sub activate {
  83. my $self = shift;
  84. my ($thing,$rw,$act) = @_;
  85. croak 'Usage $obj->activate($session,"read"|"write" [,$activate])'
  86. unless @_ >= 2;
  87. my $handle = $self->to_handle($thing);
  88. my $select = lc($rw) eq 'read' ? 'readers' : 'writers';
  89. my $prior = defined $self->{$select}->exists($handle);
  90. if (defined $act && $act != $prior) {
  91. $self->{$select}->add($handle) if $act;
  92. $self->{$select}->remove($handle) unless $act;
  93. warn $act ? 'Activating' : 'Inactivating',
  94. " handle $handle for ",
  95. $rw eq 'read' ? 'reading':'writing',".\n" if $DEBUG;
  96. }
  97. return $prior;
  98. }
  99. # Object method: wait()
  100. # Wait for I/O. Handles writes automatically. Returns a list of IO::SessionData
  101. # objects ready for reading.
  102. # If there is a listen socket, then will automatically do an accept() and return
  103. # a new IO::SessionData object for that.
  104. sub wait {
  105. my $self = shift;
  106. my $timeout = shift;
  107. # Call select() to get the list of sessions that are ready for reading/writing.
  108. croak "IO::Select->select() returned error: $!"
  109. unless my ($read,$write) =
  110. IO::Select->select($self->{readers},$self->{writers},undef,$timeout);
  111. # handle queued writes automatically
  112. foreach (@$write) {
  113. my $session = $self->to_session($_);
  114. warn "Writing pending data (",$session->pending+0," bytes) for $_.\n" if $DEBUG;
  115. my $rc = $session->write;
  116. }
  117. # Return list of sessions that are ready for reading.
  118. # If one of the ready handles is the listen socket, then
  119. # create a new session.
  120. # Otherwise return the ready handles as a list of IO::SessionData objects.
  121. my @sessions;
  122. foreach (@$read) {
  123. if ($_ eq $self->{listen_socket}) {
  124. my $newhandle = $_->accept;
  125. warn "Accepting a new handle $newhandle.\n" if $DEBUG;
  126. my $newsess = $self->add($newhandle) if $newhandle;
  127. push @sessions,$newsess;
  128. } else {
  129. push @sessions,$self->to_session($_);
  130. }
  131. }
  132. return @sessions;
  133. }
  134. # Class method: SessionDataClass
  135. # Return the string containing the name of the session data
  136. # wrapper class. Subclass and override to use a different
  137. # session data class.
  138. sub SessionDataClass { return 'IO::SessionData'; }
  139. 1;