home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / plplot / plplot_2 / drivers / tk / tcpip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-05  |  20.0 KB  |  736 lines

  1. /* $Id: tcpip.c,v 1.13 1994/08/05 21:50:22 mjl Exp $
  2.  * $Log: tcpip.c,v $
  3.  * Revision 1.13  1994/08/05  21:50:22  mjl
  4.  * Fixed bug responsible for DP driver not working on a Cray.  Works great
  5.  * now, including distributed rendering.  Added much debug code.
  6.  *
  7.  * Revision 1.12  1994/07/28  07:42:39  mjl
  8.  * Fix for side-effect of defining caddr_t in plConfig.h.
  9.  *
  10.  * Revision 1.11  1994/07/26  21:08:47  mjl
  11.  * Put in a user-suggested portability fix (lost track of who sent it).
  12.  *
  13.  * Revision 1.10  1994/07/25  06:04:21  mjl
  14.  * Desuckified header inclusions, and added test for unistd.h before
  15.  * including it.
  16.  *
  17.  * Revision 1.9  1994/07/22  22:20:59  mjl
  18.  * Eliminated a gcc -Wall warning.
  19.  *
  20.  * Revision 1.8  1994/07/21  08:41:56  mjl
  21.  * Introduced some casts to satisfy the IRIX compiler.
  22.  *
  23.  * Revision 1.7  1994/07/19  22:31:46  mjl
  24.  * All device drivers: enabling macro renamed to PLD_<driver>, where <driver>
  25.  * is xwin, ps, etc.  See plDevs.h for more detail.  All internal header file
  26.  * inclusion changed to /not/ use a search path so that it will work better
  27.  * with makedepend.
  28.  *
  29.  * Revision 1.6  1994/06/30  18:45:04  mjl
  30.  * Minor changes to pass gcc -Wall without warnings and other cleaning up.
  31.  *
  32.  * Revision 1.5  1994/05/14  05:42:52  mjl
  33.  * Fixed the call to pl_UnRead the header -- a bogus argument was causing
  34.  * spurious packet transmission failures.
  35.  *
  36.  * Revision 1.4  1994/04/08  12:00:05  mjl
  37.  * Function name changes to reduce namespace pollution.  Robustness improved
  38.  * in packet reader (changes stolen from Tcl-DP3.1 update).
  39.  *
  40.  * Revision 1.3  1994/02/07  23:00:43  mjl
  41.  * Simplified and genericized pl_PacketReceive and pl_PacketSend functions so
  42.  * that they work with FIFO's as well as sockets: data stream is now fully
  43.  * packetized.  Functions require a PLiodev struct to be passed in,
  44.  * containing lots of useful information about the connection.
  45.  *
  46.  * Revision 1.2  1994/02/01  22:44:35  mjl
  47.  * Changes to support distributed operation between machines with different
  48.  * int/long sizes.
  49.  *
  50.  * Revision 1.1  1994/01/15  17:50:09  mjl
  51.  * Added to hold primarily socket related code.  The latter were taken from
  52.  * the Tcl-DP distribution and modified to use binary i/o to/from the memory
  53.  * buffer pointed to by pdfs->buffer (pdfs a PDFstrm *).
  54. */
  55.  
  56. /* 
  57.  * tcpip.c
  58.  * Maurice LeBrun
  59.  * 6-Jan-94
  60.  *
  61.  * Functions to handle a variety of TPC-IP related chores, in particular
  62.  * socket i/o for data transfer to the Tcl-DP driver.  For the latter, the
  63.  * Tcl-DP routines were modified to use binary records; copyright follows:
  64.  *
  65.  * Copyright 1992 Telecom Finland
  66.  *
  67.  * Permission to use, copy, modify, and distribute this
  68.  * software and its documentation for any purpose and without
  69.  * fee is hereby granted, provided that this copyright
  70.  * notice appears in all copies.  Telecom Finland
  71.  * makes no representations about the suitability of this
  72.  * software for any purpose.  It is provided "as is" without
  73.  * express or implied warranty.
  74.  *
  75.  * Copyright (c) 1993 The Regents of the University of California.
  76.  * All rights reserved.
  77.  * 
  78.  * Permission to use, copy, modify, and distribute this software and its
  79.  * documentation for any purpose, without fee, and without written agreement is
  80.  * hereby granted, provided that the above copyright notice and the following
  81.  * two paragraphs appear in all copies of this software.
  82.  * 
  83.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  84.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  85.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  86.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  87.  * 
  88.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  89.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  90.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  91.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  92.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  93.  */
  94.  
  95. /*
  96. #define DEBUG
  97. */
  98.  
  99. #include "plDevs.h"
  100.  
  101. #if defined(PLD_dp) || defined (PLD_tk)
  102.  
  103. /* This file is meant to be compiled with non-ANSI compilers ("cc").
  104.  * The reason for doing it this way is to ensure that the full C
  105.  * environment of the target machine is visible (at the time of writing
  106.  * this, parts of this code are not covered by any international
  107.  * standard).  ANSI compilers are required to omit these extra symbols,
  108.  * and at the moment there is no way to get them back except for by
  109.  * vendor-specific defines (HP: _HPUX_SOURCE, AIX: _ALL_SOURCE, DGUX:
  110.  * _DGUX_SOURCE).  This is an omission in the POSIX standard more than
  111.  * anything else, and will probably be rectified at some point.  So for
  112.  * now, instead of relying on a hodgepodge of vendor specific symbols I
  113.  * forego the ANSI compiler here and go with good (bad) old "cc".
  114.  */
  115.  
  116. #include "plConfig.h"
  117. #ifdef _POSIX_SOURCE
  118. #undef _POSIX_SOURCE
  119. #endif
  120. #ifdef caddr_t
  121. #undef caddr_t
  122. #endif
  123. #define PLARGS(a)    ()
  124.  
  125. #include <stdio.h>
  126. #include <stdlib.h>
  127. #include <math.h>
  128. #include <string.h>
  129. #if defined(__sgi) && !defined(SVR3)
  130. #include <sys/select.h> 
  131. #endif
  132. #ifdef HAVE_UNISTD_H
  133. #include <unistd.h>
  134. #endif
  135.  
  136. #include "pdf.h"
  137. #include <tcl.h>
  138. #include <tk.h>
  139.  
  140. #include <sys/stat.h>
  141. #include <sys/types.h>
  142. #include <fcntl.h>
  143. #include <ctype.h>
  144. #include <sys/uio.h>
  145. #include <errno.h>
  146.  
  147. extern int errno;
  148.  
  149. #ifndef MIN
  150. #define MIN(a,b)    (((a) < (b)) ? (a) : (b))
  151. #endif
  152.  
  153. /*
  154.  * This is a "magic number" prepended to the beginning of the packet
  155.  * Used to help resync the packet machanism in the event of errors.
  156.  */
  157. #define PACKET_MAGIC    0x6feeddcc
  158.  
  159. /*
  160.  * For TCP, it's possible to get a line in pieces.  In case everything we
  161.  * want isn't there, we need a place to store partial results when we're
  162.  * in non-blocking mode.  The partial buffers below are created
  163.  * dynamically to store incomplete data in these cases. 
  164. */
  165.  
  166. typedef struct PartialRead {
  167.     char *buffer;        /* Buffer of characters */
  168.     int bufSize;        /* Size of buffer */
  169.     int offset;            /* Offset of current character within buffer */
  170.     struct PartialRead *next;    /* Next buffer in chain */
  171. } PartialRead;
  172.  
  173. #define MAX_OPEN_FILES    128
  174.  
  175. static PartialRead *partial[MAX_OPEN_FILES];
  176.  
  177. static void pl_FreeReadBuffer    PLARGS((int fd));
  178. static void pl_Unread        PLARGS((int fd, char *buffer,
  179.                     int numBytes, int copy));
  180. static int  pl_Read        PLARGS((int fd, char *buffer, int numReq));
  181.  
  182. /*
  183.  *--------------------------------------------------------------
  184.  *
  185.  * pl_FreeReadBuffer --
  186.  *
  187.  *    This function is called to free up all the memory associated
  188.  *    with a file once the file is closed.
  189.  *
  190.  * Results:
  191.  *    None.
  192.  *
  193.  * Side effects:
  194.  *    Any data buffered locally will be lost.
  195.  *
  196.  *--------------------------------------------------------------
  197.  */
  198.  
  199. static void
  200. pl_FreeReadBuffer(fd)
  201.     int fd;
  202. {
  203.     PartialRead *readList;
  204.  
  205.     while (partial[fd] != NULL) {
  206.     readList = partial[fd];
  207.     partial[fd] = readList->next;
  208.     free (readList->buffer);
  209.     free (readList);
  210.     }
  211. }
  212.  
  213. /*
  214.  *--------------------------------------------------------------
  215.  *
  216.  * pl_Unread --
  217.  *
  218.  *    This function puts data back into the read chain on a
  219.  *    file descriptor.  It's basically an extended "ungetc".
  220.  *
  221.  * Results:
  222.  *    None.
  223.  *
  224.  * Side effects:
  225.  *    Subsequent calls to pl_Read on the fd will get this data.
  226.  *
  227.  *--------------------------------------------------------------
  228.  */
  229.  
  230. static void
  231. pl_Unread (fd, buffer, numBytes, copy)
  232.     int fd;                     /* File descriptor */
  233.     char *buffer;               /* Data to unget */
  234.     int numBytes;               /* Number of bytes to unget */
  235.     int copy;            /* Should we copy the data, or use this */
  236.                 /* buffer? */
  237. {
  238.     PartialRead *new;
  239.  
  240.     new = (PartialRead *) malloc (sizeof(PartialRead));
  241.     if (copy) {
  242.     new->buffer = (char *) malloc (numBytes);
  243.     memcpy (new->buffer, buffer, numBytes);
  244.     } else {
  245.     new->buffer = buffer;
  246.     }
  247.     new->bufSize = numBytes;
  248.     new->offset = 0;
  249.     new->next = partial[fd];
  250.     partial[fd] = new;
  251. }
  252.  
  253. /*
  254.  *--------------------------------------------------------------
  255.  *
  256.  * pl_Read --
  257.  *
  258.  *    This function implements a "read"-like command, but
  259.  *    buffers partial reads.  The semantics are the same as
  260.  *    with read.
  261.  *
  262.  * Results:
  263.  *    Number of bytes read, or -1 on error (with errno set).
  264.  *
  265.  * Side effects:
  266.  *    All available data is read from the file descriptor.
  267.  *
  268.  *--------------------------------------------------------------
  269.  */
  270.  
  271. static int
  272. pl_Read (fd, buffer, numReq)
  273.     int fd;            /* File descriptor to read from */
  274.     char *buffer;        /* Place to put the data */
  275.     int numReq;            /* Number of bytes to get */
  276. {
  277.     PartialRead *readList;
  278.     PartialRead *tmp;
  279.     int numRead;
  280.     int numToCopy;
  281.  
  282.     readList = partial[fd];
  283.  
  284.     /*
  285.      * If there's no data left over from a previous read, then just do a read
  286.      * This is the common case.
  287.      */
  288.     if (readList == NULL) {
  289.     numRead = read(fd, buffer, numReq);
  290. #ifdef DEBUG
  291.     {
  292.         int j;
  293.         fprintf(stderr, "received %d bytes starting with:", numRead);
  294.         for (j = 0; j < MIN(8,numRead); j++)
  295.         fprintf(stderr, " %x", 0x000000FF & (unsigned long) buffer[j]);
  296.         fprintf(stderr, "\n");
  297.     }
  298. #endif
  299.     return numRead;
  300.     }
  301.  
  302.     /*
  303.      * There's data left over from a previous read.  Yank it in and
  304.      * only call read() if we didn't get enough data (this keeps the fd
  305.      * readable if they only request as much data as is in the buffers).
  306.      */
  307.     numRead = 0;
  308.     while ((readList != NULL) && (numRead < numReq)) {
  309.     numToCopy = readList->bufSize - readList->offset;
  310.     if (numToCopy + numRead > numReq) {
  311.         numToCopy = numReq - numRead;
  312.     }
  313.     memcpy (buffer+numRead, readList->buffer+readList->offset, numToCopy);
  314.  
  315.     /*
  316.      * Consume the data
  317.      */
  318.     tmp = readList;
  319.     readList = readList->next;
  320.     tmp->offset += numToCopy;
  321.     if (tmp->offset == tmp->bufSize) {
  322.         free (tmp->buffer);
  323.         free (tmp);
  324.         partial[fd] = readList;
  325.     }
  326.     numRead += numToCopy;
  327.     }
  328.  
  329.     /*
  330.      * Only call read if at the end of a previously incomplete packet. 
  331.      */
  332.     if ((numRead < numReq)) {
  333.     numToCopy = numReq - numRead;
  334.     numRead += read(fd, buffer+numRead, numToCopy);
  335.     }
  336.  
  337.     return numRead;
  338. }
  339.  
  340. /*----------------------------------------------------------------------*\
  341.  *  This part for Tcl-DP only
  342. \*----------------------------------------------------------------------*/
  343.  
  344. #ifdef PLD_dp
  345.  
  346. #include <dp.h>
  347.  
  348. #include <arpa/inet.h>
  349. #include <netdb.h>
  350. #include <netinet/in.h>
  351. #include <sys/socket.h>
  352.  
  353. /*----------------------------------------------------------------------*\
  354.  * plHost_ID
  355.  *
  356.  * Tcl command -- return the IP address for the current host.  
  357.  *
  358.  * Derived from source code in "UNIX Network Programming" by W. Richard
  359.  * Stevens, Prentice Hall, 1990.
  360. \*----------------------------------------------------------------------*/
  361.  
  362. static char *
  363. get_inet(listptr, length)
  364.     char **listptr;
  365.     int length;
  366. {
  367.     struct in_addr    *ptr;
  368.  
  369.     while ( (ptr = (struct in_addr *) *listptr++) == NULL)
  370.     continue;
  371.  
  372.     return inet_ntoa(*ptr);
  373. }
  374.  
  375. int
  376. plHost_ID(clientData, interp, argc, argv)
  377.     ClientData clientData;
  378.     Tcl_Interp *interp;
  379.     int argc;
  380.     char **argv;
  381. {
  382.     register struct hostent    *hostptr;
  383.     char            hostname[100];
  384.  
  385.     if (gethostname(hostname, 100)) {
  386.     Tcl_AppendResult(interp, "Error -- cannot get host name", 
  387.              (char *) NULL);
  388.     return TCL_ERROR;
  389.     }
  390.  
  391.     if ( (hostptr = gethostbyname(hostname)) == NULL) {
  392.     Tcl_AppendResult(interp, "Error -- cannot get host info for node ",
  393.              hostname, (char *) NULL);
  394.     return TCL_ERROR;
  395.     }
  396.  
  397.     Tcl_SetResult(interp,
  398.           get_inet(hostptr->h_addr_list, hostptr->h_length),
  399.           TCL_VOLATILE);
  400.  
  401.     return TCL_OK;
  402. }
  403.  
  404. #endif    /* PLD_dp */
  405.  
  406. /*
  407.  *--------------------------------------------------------------
  408.  *
  409.  * pl_PacketReceive --
  410.  *
  411.  *      This procedure is a modified version of Tdp_PacketReceive,
  412.  *    from the Tcl-DP distribution.  It reads the socket, 
  413.  *    returning a complete packet.  If the entire packet cannot
  414.  *    be read, the partial packet is buffered until the rest is
  415.  *    available.  Some capabilities have been removed from the
  416.  *    original (i.e. the check for a non-server TCP socket, since
  417.  *    there's no access to the optFlags array from here, and the 
  418.  *    peek capability, since I don't need it).
  419.  *
  420.  * Results:
  421.  *    Packet contents stored in pdfs->buffer and pdfs->bp set
  422.  *    to the number of bytes read (zero if incomplete).
  423.  *
  424.  * Side effects:
  425.  *    The file descriptor passed in is read.
  426.  *
  427.  *--------------------------------------------------------------
  428.  */
  429. int
  430. pl_PacketReceive(interp, iodev, pdfs)
  431.     Tcl_Interp *interp;
  432.     PLiodev *iodev;
  433.     PDFstrm *pdfs;
  434. {
  435.     int j, numRead;
  436.     unsigned int packetLen, header[2];
  437.     int headerSize;
  438.     unsigned char hbuf[8];
  439.     char *errMsg;
  440.  
  441.     pdfs->bp = 0;
  442.  
  443.     /*
  444.      * Read in the header (8 bytes)
  445.      */
  446.     headerSize = 8;
  447.     numRead = pl_Read (iodev->fd, (char *) hbuf, headerSize);
  448.  
  449.     if (numRead <= 0) {
  450. #ifdef DEBUG
  451.     fprintf(stderr, "Incorrect header read, numRead = %d\n", numRead);
  452. #endif
  453.     goto readError;
  454.     }
  455.  
  456.     /*
  457.      * Check for incomplete read.  If so, put it back and return.
  458.      */
  459.     if (numRead < headerSize) {
  460. #ifdef DEBUG
  461.     fprintf(stderr, "Incomplete header read, numRead = %d\n", numRead);
  462. #endif
  463.     pl_Unread (iodev->fd, (char *) hbuf, numRead, 1);
  464.     Tcl_ResetResult(interp);
  465.     return TCL_OK;
  466.     }
  467.  
  468.     /*
  469.      * Convert header character stream into ints.  This works when the
  470.      * connecting machine has a different size int (the old way didn't),
  471.      * and takes care of the endian problem to boot.  It is also mostly
  472.      * backward compatible since network byte ordering (big endian) is
  473.      * used.  
  474.      */
  475.  
  476.     j = 0;
  477.  
  478.     header[0] = 0;
  479.     header[0] |= hbuf[j++] << 24;
  480.     header[0] |= hbuf[j++] << 16;
  481.     header[0] |= hbuf[j++] << 8;
  482.     header[0] |= hbuf[j++];
  483.  
  484.     header[1] = 0;
  485.     header[1] |= hbuf[j++] << 24;
  486.     header[1] |= hbuf[j++] << 16;
  487.     header[1] |= hbuf[j++] << 8;
  488.     header[1] |= hbuf[j++];
  489.  
  490.     /*
  491.      * Format of each packet:
  492.      *
  493.      *        First 4 bytes are PACKET_MAGIC.
  494.      *        Next 4 bytes are packetLen.
  495.      *        Next packetLen-headerSize is zero terminated string
  496.      */
  497.     if (header[0] != PACKET_MAGIC) {
  498.     fprintf(stderr, "Badly formatted packet, numRead = %d\n", numRead);
  499.         Tcl_AppendResult(interp, "Error reading from ", iodev->typename,
  500.              ": badly formatted packet", (char *) NULL);
  501.     return TCL_ERROR;
  502.     }
  503.     packetLen = header[1] - headerSize;
  504.  
  505.     /*
  506.      * Expand the size of the buffer, as needed.
  507.      */
  508.  
  509.     if (header[1] > pdfs->bufmax) {
  510.     free((void *) pdfs->buffer);
  511.     pdfs->bufmax = header[1] + 32;
  512.     pdfs->buffer = (unsigned char *) malloc(pdfs->bufmax);
  513.     }
  514.  
  515.     /*
  516.      * Read in the packet, and if it's not all there, put it back.
  517.      *
  518.      * We have to be careful here, because we could block when if just
  519.      * the header came in (making the file readable at the beginning of this
  520.      * function) but the rest of the packet is still out on the network.
  521.      */
  522.  
  523.     if (iodev->type == 0) 
  524.     numRead = pl_Read (iodev->fd, (char *) pdfs->buffer, packetLen);
  525.     else {
  526. #ifdef PLD_dp
  527.     if (Tdp_FDIsReady(iodev->fd) & TCL_FILE_READABLE) {
  528.         numRead = pl_Read (iodev->fd, (char *) pdfs->buffer, packetLen);
  529.     } else {
  530. #ifdef DEBUG
  531.         fprintf(stderr, "Packet not ready, putting back header\n");
  532. #endif
  533.         pl_Unread (iodev->fd, (char *) hbuf, headerSize, 1);
  534.         Tcl_ResetResult(interp);
  535.         return TCL_OK;
  536.     }
  537. #endif
  538.     }
  539.  
  540.     if (numRead <= 0) {
  541.     goto readError;
  542.     }
  543.  
  544.     if (numRead != packetLen) {
  545. #ifdef DEBUG
  546.     fprintf(stderr, "Incomplete packet read, numRead = %d\n", numRead);
  547. #endif
  548.     pl_Unread (iodev->fd, (char *) pdfs->buffer, numRead, 1);
  549.     pl_Unread (iodev->fd, (char *) hbuf, headerSize, 1);
  550.     return TCL_OK;
  551.     }
  552.  
  553.     pdfs->bp = numRead;
  554. #ifdef DEBUG
  555.     fprintf(stderr, "received %d byte packet starting with:", numRead);
  556.     for (j = 0; j < 4; j++)
  557.     fprintf(stderr, " %x", 0x000000FF & (unsigned long) pdfs->buffer[j]);
  558.     fprintf(stderr, "\n");
  559. #endif
  560.  
  561.     return TCL_OK;
  562.  
  563. readError:
  564.     /*
  565.      *
  566.      * If we're in non-blocking mode, and this would block, return.
  567.      * If the connection is closed (numRead == 0), don't return an
  568.      * error message.  Otherwise, return one.
  569.      *
  570.      * In either case, we close the file, delete the file handler, and
  571.      * return a null string.
  572.      */
  573.  
  574.     if (errno == EWOULDBLOCK || errno == EAGAIN) {
  575.     Tcl_ResetResult(interp);
  576.     return TCL_OK;
  577.     }
  578.  
  579.     /* Record the error before closing the file */
  580.     if (numRead != 0) {
  581.     errMsg = Tcl_PosixError (interp);
  582.     } else {
  583.     errMsg = NULL;    /* Suppresses spurious compiler warning */
  584.     }
  585.  
  586.     /* 
  587.      * Remove the file handler and close the file.  
  588.      */
  589.     if (iodev->type == 0) {
  590.     Tk_DeleteFileHandler(iodev->fd);
  591.     close(iodev->fd);
  592.     }
  593.     pl_FreeReadBuffer(iodev->fd);
  594.  
  595.     Tcl_ResetResult(interp);
  596.     if (numRead == 0) {
  597.     return TCL_OK;
  598.     } else {
  599.     Tcl_AppendResult (interp, "pl_PacketReceive -- error reading from ",
  600.               iodev->typename, ": ", errMsg, (char *) NULL);
  601.     return TCL_ERROR;
  602.     }
  603. }
  604.  
  605. /*
  606.  *--------------------------------------------------------------
  607.  *
  608.  * pl_PacketSend --
  609.  *
  610.  *      This procedure is a modified version of Tdp_PacketSend,
  611.  *    from the Tcl-DP distribution.  It writes a complete packet
  612.  *    to a socket or file-oriented device.  
  613.  *
  614.  * Results:
  615.  *    A standard tcl result.
  616.  *
  617.  * Side effects:
  618.  *    The specified buffer is written to the file descriptor passed
  619.  *    in.
  620.  *
  621.  *--------------------------------------------------------------
  622.  */
  623.  
  624. int
  625. pl_PacketSend(interp, iodev, pdfs)
  626.     Tcl_Interp *interp;
  627.     PLiodev *iodev;
  628.     PDFstrm *pdfs;
  629. {
  630.     int j, numSent;
  631.     unsigned char hbuf[8];
  632.     unsigned int packetLen, header[2];
  633.     int len;
  634.     char *buffer;
  635.     char tmp[256];
  636.  
  637.     /*
  638.      * Format up the packet:
  639.      *      First 4 bytes are PACKET_MAGIC.
  640.      *      Next 4 bytes are packetLen.
  641.      *      Next packetLen-8 bytes are buffer contents.
  642.      */
  643.  
  644.     packetLen = pdfs->bp + 8;
  645.  
  646.     header[0] = PACKET_MAGIC;
  647.     header[1] = packetLen;
  648.  
  649.     /*
  650.      * Convert header ints to character stream.  
  651.      * Network byte ordering (big endian) is used.
  652.      */
  653.  
  654.     j = 0;
  655.  
  656.     hbuf[j++] = (header[0] & (unsigned long) 0xFF000000) >> 24;
  657.     hbuf[j++] = (header[0] & (unsigned long) 0x00FF0000) >> 16;
  658.     hbuf[j++] = (header[0] & (unsigned long) 0x0000FF00) >> 8;
  659.     hbuf[j++] = (header[0] & (unsigned long) 0x000000FF);
  660.  
  661.     hbuf[j++] = (header[1] & (unsigned long) 0xFF000000) >> 24;
  662.     hbuf[j++] = (header[1] & (unsigned long) 0x00FF0000) >> 16;
  663.     hbuf[j++] = (header[1] & (unsigned long) 0x0000FF00) >> 8;
  664.     hbuf[j++] = (header[1] & (unsigned long) 0x000000FF);
  665.  
  666.     /*
  667.      * Send it off, with error checking.
  668.      * Simulate writev using memcpy to put together
  669.      * the msg so it can go out in a single write() call.
  670.      */
  671.  
  672.     len = pdfs->bp + 8;
  673.     buffer = (char *) malloc(len);
  674.  
  675.     memcpy(buffer, (char *) hbuf, 8);
  676.     memcpy(buffer + 8, (char *) pdfs->buffer, pdfs->bp);
  677.  
  678. #ifdef DEBUG
  679.     fprintf(stderr, "sending  %d byte packet starting with:", len);
  680.     for (j = 0; j < 12; j++)
  681.     fprintf(stderr, " %x", 0x000000FF & (unsigned long) buffer[j]);
  682.     fprintf(stderr, "\n");
  683. #endif
  684.     numSent = write(iodev->fd, buffer, len);
  685.  
  686.     free(buffer);
  687.  
  688.     if (numSent != packetLen) {
  689.  
  690.     if ((errno == 0) || (errno == EWOULDBLOCK || errno == EAGAIN)) {
  691.         /*
  692.          * Non-blocking I/O: return number of bytes actually sent.
  693.          */
  694.         Tcl_ResetResult(interp);
  695.         sprintf (tmp, "%d", numSent - 8);
  696.         Tcl_SetResult(interp, tmp, TCL_VOLATILE);
  697.         return TCL_OK;
  698.     } else if (errno == EPIPE) {
  699.         /*
  700.          * Got a broken pipe signal, which means the far end closed the
  701.          * connection.  Close the file, delete the file handler, and
  702.          * return 0 bytes sent.
  703.          */
  704.         if (iodev->type == 0) {
  705.         Tk_DeleteFileHandler(iodev->fd);
  706.         close(iodev->fd);
  707.         }
  708.         sprintf (tmp, "0");
  709.         Tcl_SetResult(interp, tmp, TCL_VOLATILE);
  710.         return TCL_OK;
  711.     } else {
  712.         Tcl_AppendResult (interp, "pl_PacketSend -- error writing to ",
  713.                   iodev->typename, ": ",
  714.                   Tcl_PosixError (interp), (char *) NULL);
  715.     }
  716.  
  717.     return TCL_ERROR;
  718.     }
  719.  
  720.     /*
  721.      * Return the number of bytes sent (minus the header).
  722.      */
  723.     sprintf (tmp, "%d", numSent - 8);
  724.     Tcl_SetResult(interp, tmp, TCL_VOLATILE);
  725.     return TCL_OK;
  726. }
  727.  
  728. #else
  729. int
  730. pldummy_tcpip()
  731. {
  732.     return 0;
  733. }
  734.  
  735. #endif    /* defined(PLD_dp) || defined(PLD_tk) */
  736.