The sockatmark() Function The most common use of urgent data is to mark a section of the TCP stream as invalid so that it can be discarded. For example, the UNIX rlogin (remote login) server uses this feature to accommodate the user 's urgent request to kill a runaway remote program. It isn't sufficient for the rlogin server to terminate the program, because it may have already transmitted substantial output to the rlogin client at the user's end of the connection. The server must tell the client to ignore all output up to the point at which the user hit the interrupt key. This is where the sockatmark() function comes in: $flag = sockatmark($socket) sockatmark() is used to determine the location of the urgent data pointer. In the normal out-of- band case, sock_atmark() returns true if the next sysread () will return the byte following the urgent data. In the case of SO_OOBINLINE sockets, sock_atmark() returns true if the next sysread() will return the urgent data itself. | Recall that sysread() always pauses at the location of the urgent pointer. The reason for this feature is to give the process a chance to call sockatmark() . This code fragment shows the idiom: # read until we get to the mark until (sockatmark($socket)) { my $result = sysread($socket,$data,1024); die "socket closed before reaching mark" unless $result; } Each time through, sysread() is called to read (and in this case discard) 1,024 bytes of data from the socket. The loop terminates normally when the urgent data pointer is reached, or abnormally if the socket is closed (or encounters another error) before the urgent pointer is found. After the loop ends, the next read will return the urgent data byte if the SO_OOBINLINE option was set or, if the option was unset, it returns the normal data byte following that. Implementing sockatmark() Although the sockatmark() function is part of the POSIX standard, it hasn't yet made it into Perl as a built-in function, or, indeed, into the standard libraries of many operating systems. To use it, you must call your own version using an ioctl() call. $result = ioctl($handle, $command, $operand) Perl's ioctl() function is similar to fcntl() (Chapter 13), accepting a previously opened filehandle as the first argument, an integer constant corresponding to the command to perform as the second, and an operand to pass or receive data from the operation. The format of the operand depends on the operation. The function returns undef if the ioctl() call failed; otherwise , it returns a true value. | To implement the sockatmark() function, we must call ioctl() with a command of SIOCATMARK , the constant value for which can be found in a converted C header file, typically sys/ioctl.ph . After calling ioctl() , the operand is filled with a packed integer argument containing 1 if the socket is currently at the urgent data mark and 0 otherwise: require "sys/ioctl.ph"; sub sockatmark { my $s = shift; my $d; return unless ioctl($s,SIOCATMARK,$d); return unpack("i",$d) != 0; } This looks simple, but there's a hitch. The particular header file needed is not standard across all operating systems and is variously named sys/ioctl.ph , sys/socket.ph , sys/sockio. ph , or sys/sockios.ph . This makes it difficult to write portable code. Furthermore, none of these converted header files is part of the standard Perl distribution, but they must be created manually using a finicky and sometimes unreliable Perl script called h2ph . This tool is documented in the online POD documentation, but the capsule usage is as follows : % cd /usr/include % h2ph -r -l . This assumes that you are using a UNIX system that keeps its header files in /usr/include . Users of other operating systems that have a C or C++ compiler installed must locate their compiler's header directory and run h2ph from there. Even then, h2ph occasionally generates incorrect Perl code and the resulting .ph files may need to be patched by hand. Having generated the converted header files, we're still stuck with having to guess which one contains the SIOCATMARK constant. One approach is to try several possibilities until one works. The following code snippet first uses a hard-coded value for Win32 systems, and then tries a series of possible .ph file paths. If none succeeds, it dies. $^O eq 'Win32' && eval "sub SIOCATMARK { 0x40047307 }"; defined &SIOCATMARK eval { require "sys/ioctl.ph" }; defined &SIOCATMARK eval { require "sys/socket.ph" }; defined &SIOCATMARK eval { require "sys/sockio.ph" }; defined &SIOCATMARK eval { require "sys/sockios.ph" }; defined &SIOCATMARK or die "Can't determine value for SIOCATMARK"; Figure 17.5 lists a small module named Sockatmark.pm that implements the sockatmark() call. When loaded, it adds an atmark() method to the IO::Socket class, allowing you to interrogate the socket directly: Figure 17.5. The Sockatmark.pm module use Sockatmark; warn "at the mark" if $sock->atmark; Alternatively, you can explicitly import the sockatmark() function in the use line: use Sockatmark 'sockatmark'; warn "at the mark" if sockatmark($sock); |