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