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.

199 lines
6.1 KiB

  1. # ======================================================================
  2. #
  3. # Copyright (C) 2000 Lincoln D. Stein
  4. # Slightly modified by Paul Kulchenko to work on multiple platforms
  5. #
  6. # ======================================================================
  7. package IO::SessionData;
  8. use strict;
  9. use Carp;
  10. use IO::SessionSet;
  11. use vars '$VERSION';
  12. $VERSION = 1.00;
  13. use constant BUFSIZE => 3000;
  14. BEGIN {
  15. my @names = qw(EWOULDBLOCK EAGAIN EINPROGRESS);
  16. my %WOULDBLOCK =
  17. (eval {require Errno} ? map {Errno->can($_)->() => 1} grep {Errno->can($_)} @names : ()),
  18. (eval {require POSIX} ? map {POSIX->can($_)->() => 1} grep {POSIX->can($_)} @names : ());
  19. sub WOULDBLOCK { $WOULDBLOCK{shift()} }
  20. }
  21. # Class method: new()
  22. # Create a new IO::SessionData object. Intended to be called from within
  23. # IO::SessionSet, not directly.
  24. sub new {
  25. my $pack = shift;
  26. my ($sset,$handle,$writeonly) = @_;
  27. # make the handle nonblocking
  28. $handle->blocking(0);
  29. my $self = bless {
  30. outbuffer => '',
  31. sset => $sset,
  32. handle => $handle,
  33. write_limit => BUFSIZE,
  34. writeonly => $writeonly,
  35. choker => undef,
  36. choked => undef,
  37. },$pack;
  38. $self->readable(1) unless $writeonly;
  39. return $self;
  40. }
  41. # Object method: handle()
  42. # Return the IO::Handle object corresponding to this IO::SessionData
  43. sub handle { return shift->{handle} }
  44. # Object method: sessions()
  45. # Return the IO::SessionSet controlling this object.
  46. sub sessions { return shift->{sset} }
  47. # Object method: pending()
  48. # returns number of bytes pending in the out buffer
  49. sub pending { return length shift->{outbuffer} }
  50. # Object method: write_limit([$bufsize])
  51. # Get or set the limit on the size of the write buffer.
  52. # Write buffer will grow to this size plus whatever extra you write to it.
  53. sub write_limit {
  54. my $self = shift;
  55. return defined $_[0] ? $self->{write_limit} = $_[0]
  56. : $self->{write_limit};
  57. }
  58. # set a callback to be called when the contents of the write buffer becomes larger
  59. # than the set limit.
  60. sub set_choke {
  61. my $self = shift;
  62. return defined $_[0] ? $self->{choker} = $_[0]
  63. : $self->{choker};
  64. }
  65. # Object method: write($scalar)
  66. # $obj->write([$data]) -- append data to buffer and try to write to handle
  67. # Returns number of bytes written, or 0E0 (zero but true) if data queued but not
  68. # written. On other errors, returns undef.
  69. sub write {
  70. my $self = shift;
  71. return unless my $handle = $self->handle; # no handle
  72. return unless defined $self->{outbuffer}; # no buffer for queued data
  73. $self->{outbuffer} .= $_[0] if defined $_[0];
  74. my $rc;
  75. if ($self->pending) { # data in the out buffer to write
  76. local $SIG{PIPE}='IGNORE';
  77. $rc = syswrite($handle,$self->{outbuffer});
  78. # able to write, so truncate out buffer apropriately
  79. if ($rc) {
  80. substr($self->{outbuffer},0,$rc) = '';
  81. } elsif (WOULDBLOCK($!)) { # this is OK
  82. $rc = '0E0';
  83. } else { # some sort of write error, such as a PIPE error
  84. return $self->bail_out($!);
  85. }
  86. } else {
  87. $rc = '0E0'; # nothing to do, but no error either
  88. }
  89. $self->adjust_state;
  90. # Result code is the number of bytes successfully transmitted
  91. return $rc;
  92. }
  93. # Object method: read($scalar,$length [,$offset])
  94. # Just like sysread(), but returns the number of bytes read on success,
  95. # 0EO ("0 but true") if the read would block, and undef on EOF and other failures.
  96. sub read {
  97. my $self = shift;
  98. return unless my $handle = $self->handle;
  99. my $rc = sysread($handle,$_[0],$_[1],$_[2]||0);
  100. return $rc if defined $rc;
  101. return '0E0' if WOULDBLOCK($!);
  102. return;
  103. }
  104. # Object method: close()
  105. # Close the session and remove it from the monitored list.
  106. sub close {
  107. my $self = shift;
  108. unless ($self->pending) {
  109. $self->sessions->delete($self);
  110. close($self->handle);
  111. } else {
  112. $self->readable(0);
  113. $self->{closing}++; # delayed close
  114. }
  115. }
  116. # Object method: adjust_state()
  117. # Called periodically from within write() to control the
  118. # status of the handle on the IO::SessionSet's IO::Select sets
  119. sub adjust_state {
  120. my $self = shift;
  121. # make writable if there's anything in the out buffer
  122. $self->writable($self->pending > 0);
  123. # make readable if there's no write limit, or the amount in the out
  124. # buffer is less than the write limit.
  125. $self->choke($self->write_limit <= $self->pending) if $self->write_limit;
  126. # Try to close down the session if it is flagged
  127. # as in the closing state.
  128. $self->close if $self->{closing};
  129. }
  130. # choke gets called when the contents of the write buffer are larger
  131. # than the limit. The default action is to inactivate the session for further
  132. # reading until the situation is cleared.
  133. sub choke {
  134. my $self = shift;
  135. my $do_choke = shift;
  136. return if $self->{choked} == $do_choke; # no change in state
  137. if (ref $self->set_choke eq 'CODE') {
  138. $self->set_choke->($self,$do_choke);
  139. } else {
  140. $self->readable(!$do_choke);
  141. }
  142. $self->{choked} = $do_choke;
  143. }
  144. # Object method: readable($flag)
  145. # Flag the associated IO::SessionSet that we want to do reading on the handle.
  146. sub readable {
  147. my $self = shift;
  148. my $is_active = shift;
  149. return if $self->{writeonly};
  150. $self->sessions->activate($self,'read',$is_active);
  151. }
  152. # Object method: writable($flag)
  153. # Flag the associated IO::SessionSet that we want to do writing on the handle.
  154. sub writable {
  155. my $self = shift;
  156. my $is_active = shift;
  157. $self->sessions->activate($self,'write',$is_active);
  158. }
  159. # Object method: bail_out([$errcode])
  160. # Called when an error is encountered during writing (such as a PIPE).
  161. # Default behavior is to flush all buffered outgoing data and to close
  162. # the handle.
  163. sub bail_out {
  164. my $self = shift;
  165. my $errcode = shift; # save errorno
  166. delete $self->{outbuffer}; # drop buffered data
  167. $self->close;
  168. $! = $errcode; # restore errno
  169. return;
  170. }
  171. 1;