PLplot
5.10.0
|
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)