• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

tcpip.c

Go to the documentation of this file.
00001 // $Id: tcpip.c 11680 2011-03-27 17:57:51Z airwin $
00002 //
00003 // Maurice LeBrun
00004 // 6-Jan-94
00005 //
00006 // Functions to handle a variety of TPC-IP related chores, in particular
00007 // socket i/o for data transfer to the Tcl-DP driver.  For the latter, the
00008 // Tcl-DP routines were modified to use binary records; copyright follows:
00009 //
00010 // Copyright 1992 Telecom Finland
00011 //
00012 // Permission to use, copy, modify, and distribute this
00013 // software and its documentation for any purpose and without
00014 // fee is hereby granted, provided that this copyright
00015 // notice appears in all copies.  Telecom Finland
00016 // makes no representations about the suitability of this
00017 // software for any purpose.  It is provided "as is" without
00018 // express or implied warranty.
00019 //
00020 // Copyright (c) 1993 The Regents of the University of California.
00021 // All rights reserved.
00022 //
00023 // Permission to use, copy, modify, and distribute this software and its
00024 // documentation for any purpose, without fee, and without written agreement is
00025 // hereby granted, provided that the above copyright notice and the following
00026 // two paragraphs appear in all copies of this software.
00027 //
00028 // IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
00029 // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
00030 // OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
00031 // CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 //
00033 // THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00034 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00035 // AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
00036 // ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
00037 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
00038 //
00039 //
00040 // Copyright (C) 2004  Joao Cardoso
00041 //
00042 // This file is part of PLplot.
00043 //
00044 // PLplot is free software; you can redistribute it and/or modify
00045 // it under the terms of the GNU Library General Public License as published
00046 // by the Free Software Foundation; either version 2 of the License, or
00047 // (at your option) any later version.
00048 //
00049 // PLplot is distributed in the hope that it will be useful,
00050 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00051 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00052 // GNU Library General Public License for more details.
00053 //
00054 // You should have received a copy of the GNU Library General Public License
00055 // along with PLplot; if not, write to the Free Software
00056 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00057 //
00058 
00059 //
00060 // #define DEBUG
00061 //
00062 
00063 #include "plDevs.h"
00064 #include "plConfig.h"
00065 
00066 #if defined ( PLD_tk ) || defined ( ENABLE_tk )
00067 
00068 // This file is meant to be compiled with non-ANSI compilers ("cc").
00069 // The reason for doing it this way is to ensure that the full C
00070 // environment of the target machine is visible (at the time of writing
00071 // this, parts of this code are not covered by any international
00072 // standard).  ANSI compilers are required to omit these extra symbols,
00073 // and at the moment there is no way to get them back except for by
00074 // vendor-specific defines, e.g. _HPUX_SOURCE (HP), _ALL_SOURCE (AIX),
00075 // _DGUX_SOURCE (DGUX).  This is an omission in the POSIX standard more
00076 // than anything else, and will probably be rectified at some point.  So
00077 // for now, instead of relying on a hodgepodge of vendor specific symbols
00078 // I forego the ANSI compiler here and go with good (bad) old "cc".
00079 //
00080 
00081 #ifdef _POSIX_SOURCE
00082 #undef _POSIX_SOURCE
00083 #endif
00084 #ifdef caddr_t
00085 #undef caddr_t
00086 #endif
00087 #define PLARGS( a )    ( )
00088 
00089 #include <stdio.h>
00090 #include <stdlib.h>
00091 #include <math.h>
00092 #include <string.h>
00093 #if defined ( __sgi ) && !defined ( SVR3 )
00094 #include <sys/select.h>
00095 #endif
00096 #ifdef PL_HAVE_UNISTD_H
00097 #include <unistd.h>
00098 #endif
00099 
00100 #include "tcpip.h"
00101 #include <tcl.h>
00102 #include <tk.h>
00103 
00104 #include <sys/stat.h>
00105 #include <sys/types.h>
00106 #include <fcntl.h>
00107 #include <ctype.h>
00108 #include <sys/uio.h>
00109 #include <errno.h>
00110 
00111 extern int errno;
00112 
00113 #ifndef MIN
00114 #define MIN( a, b )    ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
00115 #endif
00116 
00117 //
00118 // This is a "magic number" prepended to the beginning of the packet
00119 // Used to help resync the packet machanism in the event of errors.
00120 //
00121 #define PACKET_MAGIC    0x6feeddcc
00122 
00123 //
00124 // For TCP, it's possible to get a line in pieces.  In case everything we
00125 // want isn't there, we need a place to store partial results when we're
00126 // in non-blocking mode.  The partial buffers below are created
00127 // dynamically to store incomplete data in these cases.
00128 //
00129 
00130 typedef struct PartialRead
00131 {
00132     char *buffer;               // Buffer of characters
00133     int  bufSize;               // Size of buffer
00134     int  offset;                // Offset of current character within buffer
00135     struct PartialRead *next;   // Next buffer in chain
00136 } PartialRead;
00137 
00138 #define MAX_OPEN_FILES    128
00139 
00140 static PartialRead *partial[MAX_OPEN_FILES];
00141 
00142 static void pl_FreeReadBuffer   PLARGS( (int fd) );
00143 static void pl_Unread           PLARGS( ( int fd, char *buffer,
00144                                           int numBytes, int copy ) );
00145 static int pl_Read             PLARGS( ( int fd, char *buffer, int numReq ) );
00146 
00147 //
00148 //--------------------------------------------------------------------------
00149 //
00150 // pl_FreeReadBuffer --
00151 //
00152 //      This function is called to free up all the memory associated
00153 //      with a file once the file is closed.
00154 //
00155 // Results:
00156 //      None.
00157 //
00158 // Side effects:
00159 //      Any data buffered locally will be lost.
00160 //
00161 //--------------------------------------------------------------------------
00162 //
00163 
00164 static void
00165 pl_FreeReadBuffer( fd )
00166 int fd;
00167 {
00168     PartialRead *readList;
00169 
00170     while ( partial[fd] != NULL )
00171     {
00172         readList    = partial[fd];
00173         partial[fd] = readList->next;
00174         free( readList->buffer );
00175         free( readList );
00176     }
00177 }
00178 
00179 //
00180 //--------------------------------------------------------------------------
00181 //
00182 // pl_Unread --
00183 //
00184 //      This function puts data back into the read chain on a
00185 //      file descriptor.  It's basically an extended "ungetc".
00186 //
00187 // Results:
00188 //      None.
00189 //
00190 // Side effects:
00191 //      Subsequent calls to pl_Read on the fd will get this data.
00192 //
00193 //--------------------------------------------------------------------------
00194 //
00195 
00196 static void
00197 pl_Unread( fd, buffer, numBytes, copy )
00198 int fd;                         // File descriptor
00199 char *buffer;                   // Data to unget
00200 int  numBytes;                  // Number of bytes to unget
00201 int  copy;                      // Should we copy the data, or use this
00202                                 // buffer?
00203 {
00204     PartialRead *new;
00205 
00206     new = (PartialRead *) malloc( sizeof ( PartialRead ) );
00207     if ( copy )
00208     {
00209         new->buffer = (char *) malloc( numBytes );
00210         memcpy( new->buffer, buffer, numBytes );
00211     }
00212     else
00213     {
00214         new->buffer = buffer;
00215     }
00216     new->bufSize = numBytes;
00217     new->offset  = 0;
00218     new->next    = partial[fd];
00219     partial[fd]  = new;
00220 }
00221 
00222 //
00223 //--------------------------------------------------------------------------
00224 //
00225 // pl_Read --
00226 //
00227 //      This function implements a "read"-like command, but
00228 //      buffers partial reads.  The semantics are the same as
00229 //      with read.
00230 //
00231 // Results:
00232 //      Number of bytes read, or -1 on error (with errno set).
00233 //
00234 // Side effects:
00235 //      All available data is read from the file descriptor.
00236 //
00237 //--------------------------------------------------------------------------
00238 //
00239 
00240 static int
00241 pl_Read( fd, buffer, numReq )
00242 int fd;                         // File descriptor to read from
00243 char *buffer;                   // Place to put the data
00244 int  numReq;                    // Number of bytes to get
00245 {
00246     PartialRead *readList;
00247     PartialRead *tmp;
00248     int         numRead;
00249     int         numToCopy;
00250 
00251     readList = partial[fd];
00252 
00253     //
00254     // If there's no data left over from a previous read, then just do a read
00255     // This is the common case.
00256     //
00257     if ( readList == NULL )
00258     {
00259         numRead = read( fd, buffer, numReq );
00260 #ifdef DEBUG
00261         {
00262             int j;
00263             fprintf( stderr, "received %d bytes starting with:", numRead );
00264             for ( j = 0; j < MIN( 8, numRead ); j++ )
00265                 fprintf( stderr, " %x", 0x000000FF & (unsigned long) buffer[j] );
00266             fprintf( stderr, "\n" );
00267         }
00268 #endif
00269         return numRead;
00270     }
00271 
00272     //
00273     // There's data left over from a previous read.  Yank it in and
00274     // only call read() if we didn't get enough data (this keeps the fd
00275     // readable if they only request as much data as is in the buffers).
00276     //
00277     numRead = 0;
00278     while ( ( readList != NULL ) && ( numRead < numReq ) )
00279     {
00280         numToCopy = readList->bufSize - readList->offset;
00281         if ( numToCopy + numRead > numReq )
00282         {
00283             numToCopy = numReq - numRead;
00284         }
00285         memcpy( buffer + numRead, readList->buffer + readList->offset, numToCopy );
00286 
00287         //
00288         // Consume the data
00289         //
00290         tmp          = readList;
00291         readList     = readList->next;
00292         tmp->offset += numToCopy;
00293         if ( tmp->offset == tmp->bufSize )
00294         {
00295             free( tmp->buffer );
00296             free( tmp );
00297             partial[fd] = readList;
00298         }
00299         numRead += numToCopy;
00300     }
00301 
00302     //
00303     // Only call read if at the end of a previously incomplete packet.
00304     //
00305     if ( ( numRead < numReq ) )
00306     {
00307         numToCopy = numReq - numRead;
00308         numRead  += read( fd, buffer + numRead, numToCopy );
00309     }
00310 
00311     return numRead;
00312 }
00313 
00314 //--------------------------------------------------------------------------
00315 //  This part for Tcl-DP only
00316 //--------------------------------------------------------------------------
00317 
00318 #ifdef PLD_dp
00319 
00320 #include <dp.h>
00321 
00322 #include <arpa/inet.h>
00323 #include <netdb.h>
00324 #include <netinet/in.h>
00325 #include <sys/socket.h>
00326 
00327 //--------------------------------------------------------------------------
00328 // plHost_ID
00329 //
00330 // Tcl command -- return the IP address for the current host.
00331 //
00332 // Derived from source code in "UNIX Network Programming" by W. Richard
00333 // Stevens, Prentice Hall, 1990.
00334 //--------------------------------------------------------------------------
00335 
00336 static char *
00337 get_inet( listptr, length )
00338 char **listptr;
00339 int length;
00340 {
00341     struct in_addr *ptr;
00342 
00343     while ( ( ptr = (struct in_addr *) *listptr++ ) == NULL )
00344         continue;
00345 
00346     return inet_ntoa( *ptr );
00347 }
00348 
00349 int
00350 plHost_ID( clientData, interp, argc, argv )
00351 ClientData clientData;
00352 Tcl_Interp *interp;
00353 int        argc;
00354 char       **argv;
00355 {
00356     register struct hostent *hostptr;
00357     char hostname[100];
00358 
00359     if ( gethostname( hostname, 100 ) )
00360     {
00361         Tcl_AppendResult( interp, "Error -- cannot get host name",
00362             (char *) NULL );
00363         return TCL_ERROR;
00364     }
00365 
00366     if ( ( hostptr = gethostbyname( hostname ) ) == NULL )
00367     {
00368         Tcl_AppendResult( interp, "Error -- cannot get host info for node ",
00369             hostname, (char *) NULL );
00370         return TCL_ERROR;
00371     }
00372 
00373     Tcl_SetResult( interp,
00374         get_inet( hostptr->h_addr_list, hostptr->h_length ),
00375         TCL_VOLATILE );
00376 
00377     return TCL_OK;
00378 }
00379 
00380 #endif  // PLD_dp
00381 
00382 //
00383 //--------------------------------------------------------------------------
00384 //
00385 // pl_PacketReceive --
00386 //
00387 //      This procedure is a modified version of Tdp_PacketReceive,
00388 //      from the Tcl-DP distribution.  It reads the socket,
00389 //      returning a complete packet.  If the entire packet cannot
00390 //      be read, the partial packet is buffered until the rest is
00391 //      available.  Some capabilities have been removed from the
00392 //      original, such as the check for a non-server TCP socket,
00393 //      since there's no access to the optFlags array from here,
00394 //      and the peek capability, since I don't need it.
00395 //
00396 // Results:
00397 //      Packet contents stored in pdfs->buffer and pdfs->bp set
00398 //      to the number of bytes read (zero if incomplete).
00399 //
00400 // Side effects:
00401 //      The file descriptor passed in is read.
00402 //
00403 //--------------------------------------------------------------------------
00404 //
00405 int
00406 pl_PacketReceive( interp, iodev, pdfs )
00407 Tcl_Interp * interp;
00408 PLiodev *iodev;
00409 PDFstrm *pdfs;
00410 {
00411     int           j, numRead;
00412     unsigned int  packetLen, header[2];
00413     int           headerSize;
00414     unsigned char hbuf[8];
00415     char          *errMsg;
00416 
00417     pdfs->bp = 0;
00418 
00419     //
00420     // Read in the header (8 bytes)
00421     //
00422     headerSize = 8;
00423     numRead    = pl_Read( iodev->fd, (char *) hbuf, headerSize );
00424 
00425     if ( numRead <= 0 )
00426     {
00427 #ifdef DEBUG
00428         fprintf( stderr, "Incorrect header read, numRead = %d\n", numRead );
00429 #endif
00430         goto readError;
00431     }
00432 
00433     //
00434     // Check for incomplete read.  If so, put it back and return.
00435     //
00436     if ( numRead < headerSize )
00437     {
00438 #ifdef DEBUG
00439         fprintf( stderr, "Incomplete header read, numRead = %d\n", numRead );
00440 #endif
00441         pl_Unread( iodev->fd, (char *) hbuf, numRead, 1 );
00442         Tcl_ResetResult( interp );
00443         return TCL_OK;
00444     }
00445 
00446     //
00447     // Convert header character stream into ints.  This works when the
00448     // connecting machine has a different size int and takes care of the
00449     // endian problem to boot.  It is also mostly backward compatible since
00450     // network byte ordering (big endian) is used.
00451     //
00452 
00453     j = 0;
00454 
00455     header[0]  = 0;
00456     header[0] |= hbuf[j++] << 24;
00457     header[0] |= hbuf[j++] << 16;
00458     header[0] |= hbuf[j++] << 8;
00459     header[0] |= hbuf[j++];
00460 
00461     header[1]  = 0;
00462     header[1] |= hbuf[j++] << 24;
00463     header[1] |= hbuf[j++] << 16;
00464     header[1] |= hbuf[j++] << 8;
00465     header[1] |= hbuf[j++];
00466 
00467     //
00468     // Format of each packet:
00469     //
00470     //          First 4 bytes are PACKET_MAGIC.
00471     //          Next 4 bytes are packetLen.
00472     //          Next packetLen-headerSize is zero terminated string
00473     //
00474     if ( header[0] != PACKET_MAGIC )
00475     {
00476         fprintf( stderr, "Badly formatted packet, numRead = %d\n", numRead );
00477         Tcl_AppendResult( interp, "Error reading from ", iodev->typeName,
00478             ": badly formatted packet", (char *) NULL );
00479         return TCL_ERROR;
00480     }
00481     packetLen = header[1] - headerSize;
00482 
00483     //
00484     // Expand the size of the buffer, as needed.
00485     //
00486 
00487     if ( header[1] > (unsigned) pdfs->bufmax )
00488     {
00489         free( (void *) pdfs->buffer );
00490         pdfs->bufmax = header[1] + 32;
00491         pdfs->buffer = (unsigned char *) malloc( pdfs->bufmax );
00492     }
00493 
00494     //
00495     // Read in the packet, and if it's not all there, put it back.
00496     //
00497     // We have to be careful here, because we could block if just the
00498     // header came in (making the file readable at the beginning of this
00499     // function) but the rest of the packet is still out on the network.
00500     //
00501 
00502     if ( iodev->type == 0 )
00503     {
00504         numRead = pl_Read( iodev->fd, (char *) pdfs->buffer, packetLen );
00505     }
00506     else
00507     {
00508 #ifdef PLD_dp
00509         if ( Tdp_FDIsReady( iodev->fd ) & TCL_FILE_READABLE )
00510         {
00511             numRead = pl_Read( iodev->fd, (char *) pdfs->buffer, packetLen );
00512         }
00513         else
00514         {
00515 #ifdef DEBUG
00516             fprintf( stderr, "Packet not ready, putting back header\n" );
00517 #endif
00518             pl_Unread( iodev->fd, (char *) hbuf, headerSize, 1 );
00519             Tcl_ResetResult( interp );
00520             return TCL_OK;
00521         }
00522 #endif
00523     }
00524 
00525     if ( numRead <= 0 )
00526     {
00527         goto readError;
00528     }
00529 
00530     if ( (unsigned) numRead != packetLen )
00531     {
00532 #ifdef DEBUG
00533         fprintf( stderr, "Incomplete packet read, numRead = %d\n", numRead );
00534 #endif
00535         pl_Unread( iodev->fd, (char *) pdfs->buffer, numRead, 1 );
00536         pl_Unread( iodev->fd, (char *) hbuf, headerSize, 1 );
00537         return TCL_OK;
00538     }
00539 
00540     pdfs->bp = numRead;
00541 #ifdef DEBUG
00542     fprintf( stderr, "received %d byte packet starting with:", numRead );
00543     for ( j = 0; j < 4; j++ )
00544     {
00545         fprintf( stderr, " %x", 0x000000FF & (unsigned long) pdfs->buffer[j] );
00546     }
00547     fprintf( stderr, "\n" );
00548 #endif
00549 
00550     return TCL_OK;
00551 
00552 readError:
00553     //
00554     //
00555     // If we're in non-blocking mode, and this would block, return.
00556     // If the connection is closed (numRead == 0), don't return an
00557     // error message.  Otherwise, return one.
00558     //
00559     // In either case, we close the file, delete the file handler, and
00560     // return a null string.
00561     //
00562 
00563     if ( errno == EWOULDBLOCK || errno == EAGAIN )
00564     {
00565         Tcl_ResetResult( interp );
00566         return TCL_OK;
00567     }
00568 
00569     // Record the error before closing the file
00570     if ( numRead != 0 )
00571     {
00572         errMsg = (char *) Tcl_PosixError( interp );
00573     }
00574     else
00575     {
00576         errMsg = NULL;  // Suppresses spurious compiler warning
00577     }
00578 
00579     //
00580     // Remove the file handler and close the file.
00581     //
00582     if ( iodev->type == 0 )
00583     {
00584 // Exclude UNIX-only feature
00585 #if !defined ( MAC_TCL ) && !defined ( __WIN32__ ) && !defined ( __CYGWIN__ )
00586         Tk_DeleteFileHandler( iodev->fd );
00587 #endif
00588         close( iodev->fd );
00589     }
00590     pl_FreeReadBuffer( iodev->fd );
00591 
00592     Tcl_ResetResult( interp );
00593     if ( numRead == 0 )
00594     {
00595         return TCL_OK;
00596     }
00597     else
00598     {
00599         Tcl_AppendResult( interp, "pl_PacketReceive -- error reading from ",
00600             iodev->typeName, ": ", errMsg, (char *) NULL );
00601         return TCL_ERROR;
00602     }
00603 }
00604 
00605 //
00606 //--------------------------------------------------------------------------
00607 //
00608 // pl_PacketSend --
00609 //
00610 //      This procedure is a modified version of Tdp_PacketSend,
00611 //      from the Tcl-DP distribution.  It writes a complete packet
00612 //      to a socket or file-oriented device.
00613 //
00614 // Results:
00615 //      A standard tcl result.
00616 //
00617 // Side effects:
00618 //      The specified buffer is written to the file descriptor passed
00619 //      in.
00620 //
00621 //--------------------------------------------------------------------------
00622 //
00623 
00624 int
00625 pl_PacketSend( interp, iodev, pdfs )
00626 Tcl_Interp * interp;
00627 PLiodev *iodev;
00628 PDFstrm *pdfs;
00629 {
00630     int           j, numSent;
00631     unsigned char hbuf[8];
00632     unsigned int  packetLen, header[2];
00633     int           len;
00634     char          *buffer, tmp[256];
00635 
00636     //
00637     // Format up the packet:
00638     //    First 4 bytes are PACKET_MAGIC.
00639     //    Next 4 bytes are packetLen.
00640     //    Next packetLen-8 bytes are buffer contents.
00641     //
00642 
00643     packetLen = pdfs->bp + 8;
00644 
00645     header[0] = PACKET_MAGIC;
00646     header[1] = packetLen;
00647 
00648     //
00649     // Convert header ints to character stream.
00650     // Network byte ordering (big endian) is used.
00651     //
00652 
00653     j = 0;
00654 
00655     hbuf[j++] = ( header[0] & (unsigned long) 0xFF000000 ) >> 24;
00656     hbuf[j++] = ( header[0] & (unsigned long) 0x00FF0000 ) >> 16;
00657     hbuf[j++] = ( header[0] & (unsigned long) 0x0000FF00 ) >> 8;
00658     hbuf[j++] = ( header[0] & (unsigned long) 0x000000FF );
00659 
00660     hbuf[j++] = ( header[1] & (unsigned long) 0xFF000000 ) >> 24;
00661     hbuf[j++] = ( header[1] & (unsigned long) 0x00FF0000 ) >> 16;
00662     hbuf[j++] = ( header[1] & (unsigned long) 0x0000FF00 ) >> 8;
00663     hbuf[j++] = ( header[1] & (unsigned long) 0x000000FF );
00664 
00665     //
00666     // Send it off, with error checking.
00667     // Simulate writev using memcpy to put together
00668     // the msg so it can go out in a single write() call.
00669     //
00670 
00671     len    = pdfs->bp + 8;
00672     buffer = (char *) malloc( len );
00673 
00674     memcpy( buffer, (char *) hbuf, 8 );
00675     memcpy( buffer + 8, (char *) pdfs->buffer, pdfs->bp );
00676 
00677 #ifdef DEBUG
00678     fprintf( stderr, "sending  %d byte packet starting with:", len );
00679     for ( j = 0; j < 12; j++ )
00680     {
00681         fprintf( stderr, " %x", 0x000000FF & (unsigned long) buffer[j] );
00682     }
00683     fprintf( stderr, "\n" );
00684 #endif
00685     numSent = write( iodev->fd, buffer, len );
00686 
00687     free( buffer );
00688 
00689     if ( (unsigned) numSent != packetLen )
00690     {
00691         if ( ( errno == 0 ) || ( errno == EWOULDBLOCK || errno == EAGAIN ) )
00692         {
00693             //
00694             // Non-blocking I/O: return number of bytes actually sent.
00695             //
00696             Tcl_ResetResult( interp );
00697             sprintf( tmp, "%d", numSent - 8 );
00698             Tcl_SetResult( interp, tmp, TCL_VOLATILE );
00699             return TCL_OK;
00700         }
00701         else if ( errno == EPIPE )
00702         {
00703             //
00704             // Got a broken pipe signal, which means the far end closed
00705             // the connection.  Close the file and return 0 bytes sent.
00706             //
00707             if ( iodev->type == 0 )
00708             {
00709                 close( iodev->fd );
00710             }
00711             sprintf( tmp, "0" );
00712             Tcl_SetResult( interp, tmp, TCL_VOLATILE );
00713             return TCL_OK;
00714         }
00715         else
00716         {
00717             Tcl_AppendResult( interp, "pl_PacketSend -- error writing to ",
00718                 iodev->typeName, ": ",
00719                 Tcl_PosixError( interp ), (char *) NULL );
00720         }
00721 
00722         return TCL_ERROR;
00723     }
00724 
00725     //
00726     // Return the number of bytes sent (minus the header).
00727     //
00728     sprintf( tmp, "%d", numSent - 8 );
00729     Tcl_SetResult( interp, tmp, TCL_VOLATILE );
00730     return TCL_OK;
00731 }
00732 
00733 #else
00734 int
00735 pldummy_tcpip()
00736 {
00737     return 0;
00738 }
00739 
00740 #endif  // defined(PLD_tk) || defined (ENABLE_tk)

Generated on Wed Oct 12 2011 20:42:23 for PLplot by  doxygen 1.7.1