home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Networking / ncftp-2.4.2-MIHS / src / Xfer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-28  |  13.5 KB  |  664 lines

  1. /* Xfer.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #include <signal.h>
  6. #include <setjmp.h>
  7. #include <errno.h>
  8.  
  9. #define _xfer_c_ 1
  10.  
  11. #include "Util.h"
  12. #include "Main.h"
  13. #include "Xfer.h"
  14. #include "RCmd.h"
  15. #include "FTP.h"
  16. #include "Progress.h"
  17. #include "Sio.h"
  18.  
  19. /* Large buffer to hold blocks of data during transferring. */
  20. char *gXferBuf = NULL;
  21. char *gAsciiSendBuf = NULL;
  22.  
  23. /* Size of the transfer buffer.  */
  24. size_t gXferBufSize = kXferBufSize;
  25.  
  26. /* Stores whether we had an interrupt occur during the transfer. */
  27. int gXferAbortFlag = 0;
  28.  
  29. char *gSecondaryBufPtr;
  30. char *gSecondaryBufLimit;
  31.  
  32. int gUsingBufferGets;
  33. jmp_buf gXferTimeoutJmp;
  34.  
  35. NetReadProc gNetReadProc;
  36. NetWriteProc gNetWriteProc;
  37.  
  38. extern int gDebug, gMode;
  39. extern int gStdout;
  40. extern int gNetworkTimeout;
  41.  
  42.  
  43. void 
  44. InitXferBuffer(void)
  45. {
  46.     gXferBufSize = (size_t) kXferBufSize;
  47.     gXferBuf = malloc(gXferBufSize);
  48.     if (gXferBuf == NULL) {
  49.         fprintf(stderr, "Not enough memory for transfer buffer.\n");
  50.         Exit(kExitOutOfMemory);
  51.     }
  52. }                               /* InitXferBuffer */
  53.  
  54.  
  55.  
  56.  
  57. int 
  58. BufferGets(char *buf, size_t bufsize, XferSpecPtr xp)
  59. {
  60.     int err;
  61.     char *src;
  62.     char *dst;
  63.     char *dstlim;
  64.     int len;
  65.     int nr;
  66.  
  67.     gUsingBufferGets = 1;
  68.     err = 0;
  69.     dst = buf;
  70.     dstlim = dst + bufsize - 1;               /* Leave room for NUL. */
  71.     src = gSecondaryBufPtr;
  72.     for (; dst < dstlim;) {
  73.         if (src >= gSecondaryBufLimit) {
  74.             /* Fill the buffer. */
  75.             nr = (*gNetReadProc) (xp);
  76.             if (nr == 0) {
  77.                 /* EOF. */
  78.                 goto done;
  79.             } else if (nr < 0) {
  80.                 /* Error. */
  81.                 err = -1;
  82.                 goto done;
  83.             }
  84.             gSecondaryBufPtr = gXferBuf;
  85.             gSecondaryBufLimit = gXferBuf + nr;
  86.             src = gSecondaryBufPtr;
  87.         }
  88.         if (*src == '\r') {
  89.             ++src;
  90.         } else {
  91.             if (*src == '\n') {
  92.                 *dst++ = *src++;
  93.                 goto done;
  94.             }
  95.             *dst++ = *src++;
  96.         }
  97.     }
  98.  
  99.       done:
  100.     gSecondaryBufPtr = src;
  101.     *dst = '\0';
  102.     len = (int) (dst - buf);
  103.     if (err < 0)
  104.         return (err);
  105.     return (len);
  106. }                               /* BufferGets */
  107.  
  108.  
  109.  
  110.  
  111. /* We get here upon a signal we can handle during transfers. */
  112. void 
  113. XferSigHandler(int sigNum)
  114. {
  115.     gXferAbortFlag = sigNum;
  116. #if 1
  117.     /* Not a good thing to do in general from a signal handler... */
  118.     TraceMsg("XferSigHandler: SIG %d.\n", sigNum);
  119. #endif
  120.     return;
  121. }                               /* XferSigHandler */
  122.  
  123.  
  124.  
  125.  
  126. /* This initializes a transfer information block to zeroes, and
  127.  * also initializes the two Response blocks.
  128.  */
  129. XferSpecPtr 
  130. InitXferSpec(void)
  131. {
  132.     XferSpecPtr xp;
  133.  
  134.     xp = (XferSpecPtr) calloc(SZ(1), sizeof(XferSpec));
  135.     if (xp == NULL)
  136.         OutOfMemory();
  137.     xp->cmdResp = InitResponse();
  138.     xp->xferResp = InitResponse();
  139.     return (xp);
  140. }                               /* InitXferSpec */
  141.  
  142.  
  143.  
  144.  
  145. /* Disposes the transfer information block, and the responses within it. */
  146. void 
  147. DoneWithXferSpec(XferSpecPtr xp)
  148. {
  149.     DoneWithResponse(xp->cmdResp);
  150.     DoneWithResponse(xp->xferResp);
  151.     CLEARXFERSPEC(xp);
  152.     free(xp);
  153. }                               /* DoneWithXferSpec */
  154.  
  155.  
  156.  
  157.  
  158. void 
  159. AbortDataTransfer(XferSpecPtr xp)
  160. {
  161.     DebugMsg("Start Abort\n");
  162.     SendTelnetInterrupt();                   /* Probably could get by w/o doing this. */
  163.  
  164.     /* If we aborted too late, and the server already sent the whole thing,
  165.      * it will just respond a 226 Transfer completed to our ABOR.
  166.      * But if we actually aborted, we'll get a 426 reply instead, then the
  167.      * server will send another 226 reply.  So if we get a 426 we'll
  168.      * print that quick and get rid of it by NULLing it out;  RDataCmd()
  169.      * will then do its usual GetResponse and get the pending 226.
  170.      *
  171.      * If we get the 226 here, we don't want RDataCmd() to try and get
  172.      * another response.  It will check to see if there is already is
  173.      * one, and if so, not get a response.
  174.      */
  175.     (void) RCmd(xp->xferResp, "ABOR");
  176.  
  177.     if (xp->xferResp->code == 426) {
  178.         TraceMsg("(426) Aborted in time.\n");
  179.         ReInitResponse(xp->xferResp);
  180.     }
  181.     CloseDataConnection(1);                   /* Must close (by protocol). */
  182.  
  183.     DebugMsg("End Abort\n");
  184. }                               /* AbortDataTransfer */
  185.  
  186.  
  187.  
  188.  
  189. static void
  190. AbortXfer(XferSpecPtr xp)
  191. {
  192.     Sig_t origIntr, origPipe;
  193.  
  194.     /* Don't interrupt while aborting. */
  195.     origIntr = SIGNAL(SIGINT, SIG_IGN);
  196.     origPipe = SIGNAL(SIGPIPE, SIG_IGN);
  197.  
  198.     /* It's important to make sure that the local file gets it's times 
  199.      * set correctly, so that reget works like it should.
  200.      * When we call AbortDataTransfer, often the server just hangs up.
  201.      */
  202.     if ((xp->netMode == kNetReading) && (xp->outStream != gStdout))
  203.         SetLocalFileTimes(xp->doUTime, xp->remoteModTime, xp->localFileName);
  204.     if (gXferAbortFlag == SIGPIPE) {
  205.         if (gDebug)
  206.             EPrintF("\r** Broken pipe: Lost data connection **\n");
  207.         else
  208.             EPrintF("\r** Lost data connection **\n");
  209.     } else if ((gXferAbortFlag == SIGINT) || (gXferAbortFlag == 0)) {
  210.         EPrintF("\r** Aborting Transfer **\n");
  211.     } else {
  212.         EPrintF("\r** Aborting Transfer (%d) **\n", gXferAbortFlag);
  213.     }
  214.     AbortDataTransfer(xp);
  215.     (void) SIGNAL(SIGINT, origIntr);
  216.     (void) SIGNAL(SIGPIPE, origPipe);
  217. }                               /* AbortXfer */
  218.  
  219.  
  220.  
  221. void
  222. EndTransfer(XferSpecPtr xp)
  223. {
  224.     if (xp->aborted == 1)
  225.         AbortXfer(xp);
  226.     else if ((gMode == 'B') && (xp->netMode != kNetReading)) {
  227.         /* Send EOF block if using Block mode store. */
  228.         BlockModeWrite(xp, NULL, 0);
  229.     }
  230.     gXferAbortFlag = 0;
  231.  
  232.     /* Always call EndProgress, because that does logging too. */
  233.     EndProgress(xp);
  234.     (void) SIGNAL(SIGINT, xp->origIntr);
  235.     (void) SIGNAL(SIGPIPE, xp->origPipe);
  236. }                               /* EndTransfer */
  237.  
  238.  
  239.  
  240. void
  241. StartTransfer(XferSpecPtr xp)
  242. {
  243.     gXferAbortFlag = 0;
  244.     errno = 0;
  245.  
  246.     /* In case we happen to use BufferGets, this line sets the buffer pointer
  247.      * so that the first thing BufferGets will do is reset and fill the buffer
  248.      * using real I/O.
  249.      */
  250.     gSecondaryBufPtr = gXferBuf + gXferBufSize;
  251.     gUsingBufferGets = 0;
  252.  
  253.     xp->outIsTTY = (xp->outStream < 0) ? 0 : isatty(xp->outStream);
  254.     xp->inIsTTY = (xp->inStream < 0) ? 0 : isatty(xp->inStream);
  255.  
  256.     /* Always call StartProgress, because that initializes the logging * stuff too. */
  257.     StartProgress(xp);
  258.  
  259.     if (gMode == 'B') {
  260.         gNetReadProc = BlockModeRead;
  261.         gNetWriteProc = BlockModeWrite;
  262.     } else {
  263.         gNetReadProc = StreamModeRead;
  264.         gNetWriteProc = StreamModeWrite;
  265.     }
  266.  
  267.     xp->origIntr = SIGNAL(SIGINT, XferSigHandler);
  268.     xp->origPipe = SIGNAL(SIGPIPE, XferSigHandler);
  269. }                               /* StartTransfer */
  270.  
  271.  
  272.  
  273. int
  274. StdAsciiFileReceive(XferSpecPtr xp)
  275. {
  276.     int nread, nwrote;
  277.     int fd;
  278.     char *xbuf;
  279.     char *i, *o;
  280.     int ct;
  281.  
  282.     fd = xp->outStream;
  283.     xbuf = gXferBuf;
  284.  
  285.     for (;;) {
  286.         nread = (*gNetReadProc) (xp);
  287.         if (nread <= 0)
  288.             break;
  289.  
  290.         /* In ASCII mode, all end-of-lines are denoted by CR/LF.
  291.          * For UNIX, we don't want that, we want just LFs, so
  292.          * skip all the CR's.
  293.          */
  294.         for (i = o = xbuf, ct = 0; ct < nread; ct++, ++i) {
  295.             if (*i != '\r')
  296.                 *o++ = *i;
  297.         }
  298.         nread = (int) (o - xbuf);
  299.  
  300.         nwrote = Swrite(fd, xbuf, nread, gNetworkTimeout);
  301.         if (nwrote <= 0)
  302.             break;
  303.     }
  304.     return (nread);                       /* 0 or -1 */
  305. }                               /* StdAsciiFileReceive */
  306.  
  307.  
  308.  
  309.  
  310. int
  311. StdAsciiFileSend(XferSpecPtr xp)
  312. {
  313.     int nread, nwrote;
  314.     int fd;
  315.     size_t aBufSize;
  316.     char *cp1, *cp2, *lim;
  317.  
  318.     /* For ASCII sends, we have a special case where
  319.      * we use another buffer.  We don't want to write
  320.      * single lines at a time on the stream for
  321.      * efficiency (especially with block transfer mode).
  322.      * We need to assume that the entire block 
  323.      * we read from the file could be all \n's which is
  324.      * why we only read half the maximum size of the
  325.      * transfer buffer (because each \n must be
  326.      * converted to \r\n).
  327.      */
  328.     aBufSize = (gXferBufSize / 2);
  329.     if (gAsciiSendBuf == NULL) {
  330.         /* Only allocate this on a need basis,
  331.          * since ASCII sends are very rare.
  332.          */
  333.         gAsciiSendBuf = malloc(aBufSize + 1);
  334.         gAsciiSendBuf[aBufSize] = '\0';
  335.         if (gAsciiSendBuf == NULL) {
  336.             fprintf(stderr, "Not enough memory for ascii send buffer.\n");
  337.             Exit(kExitOutOfMemory);
  338.         }
  339.     }
  340.     fd = xp->inStream;
  341.     for (;;) {
  342.         nread = Sread(fd, gAsciiSendBuf, aBufSize, gNetworkTimeout, 0);
  343.         if (nread <= 0) {
  344.             if ((nread < 0) && (errno == EINTR))
  345.                 continue;
  346.             break;
  347.         }
  348.         cp1 = gAsciiSendBuf;
  349.         lim = cp1 + nread;
  350.         cp2 = gXferBuf;
  351.         while (cp1 < lim) {
  352.             if (*cp1 == '\n')
  353.                 *cp2++ = '\r';
  354.             *cp2++ = *cp1++;
  355.         }
  356.  
  357.         nread = (int) (cp2 - gXferBuf);
  358.         nwrote = (*gNetWriteProc) (xp, gXferBuf, nread);
  359.         if (nwrote <= 0)
  360.             break;
  361.     }
  362.     return (nread);                       /* 0 or -1 */
  363. }                               /* StdAsciiFileSend */
  364.  
  365.  
  366.  
  367.  
  368. int
  369. StdFileReceive(XferSpecPtr xp)
  370. {
  371.     int nread, nwrote;
  372.     int fd;
  373.     char *xbuf;
  374.  
  375.     xbuf = gXferBuf;
  376.     fd = xp->outStream;
  377.  
  378.     /* Special case the most common ones,
  379.      * so we don't repeatedly have to evaluate
  380.      * the NetProc.
  381.      */
  382.     if (gNetReadProc == StreamModeRead) {
  383.         for (;;) {
  384.             nread = StreamModeRead(xp);
  385.             if (nread <= 0)
  386.                 break;
  387.             nwrote = Swrite(fd, xbuf, nread, gNetworkTimeout);
  388.             if (nwrote < 0) {
  389.                 nread = nwrote;
  390.                 break;
  391.             }
  392.         }
  393.     } else {
  394.         for (;;) {
  395.             nread = (*gNetReadProc) (xp);
  396.             if (nread <= 0)
  397.                 break;
  398.             nwrote = Swrite(fd, xbuf, nread, gNetworkTimeout);
  399.             if (nwrote < 0) {
  400.                 nread = nwrote;
  401.                 break;
  402.             }
  403.         }
  404.     }
  405.     return (nread);                       /* 0 or -1 */
  406. }                               /* StdFileReceive */
  407.  
  408.  
  409.  
  410.  
  411. int
  412. StdFileSend(XferSpecPtr xp)
  413. {
  414.     int nread, nwrote;
  415.     int fd;
  416.     char *xbuf;
  417.     size_t xbsize;
  418.  
  419.     xbuf = gXferBuf;
  420.     xbsize = gXferBufSize;
  421.     fd = xp->inStream;
  422.     nwrote = 0;
  423.  
  424.     /* Special case the most common ones,
  425.      * so we don't repeatedly have to evaluate
  426.      * the NetProc.
  427.      */
  428.     if (gNetWriteProc == StreamModeWrite) {
  429.         for (;;) {
  430.             nread = Sread(fd, xbuf, xbsize, gNetworkTimeout, 0);
  431.             if (nread <= 0) {
  432.                 if ((nread < 0) && (errno == EINTR))
  433.                     continue;
  434.                 break;
  435.             }
  436.             nwrote = StreamModeWrite(xp, xbuf, nread);
  437.             if (nwrote < 0)
  438.                 break;
  439.         }
  440.     } else {
  441.         for (;;) {
  442.             nread = Sread(fd, xbuf, xbsize, gNetworkTimeout, 0);
  443.             if (nread <= 0) {
  444.                 if ((nread < 0) && (errno == EINTR))
  445.                     continue;
  446.                 break;
  447.             }
  448.             nwrote = (*gNetWriteProc) (xp, xbuf, nread);
  449.             if (nwrote < 0)
  450.                 break;
  451.         }
  452.     }
  453.     return (nwrote);                   /* 0 or -1 */
  454. }                               /* StdFileSend */
  455.  
  456.  
  457.  
  458.  
  459. int
  460. StreamModeRead(XferSpecPtr xp)
  461. {
  462.     int in;
  463.     int nRead;
  464.  
  465.     in = xp->inStream;
  466.  
  467.     for (;;) {
  468.         if (gXferAbortFlag > 0) {
  469.             xp->aborted = 1;
  470.             nRead = -1;
  471.             goto done;
  472.         }
  473.         nRead = Sread(in, gXferBuf, gXferBufSize, gNetworkTimeout, 0);
  474.         if (nRead <= 0) {
  475.             if (nRead == 0)
  476.                 break;               /* EOF. */
  477.             if (errno == EINTR) {
  478.                 if (xp->doReports)
  479.                     ProgressReport(xp, kOptionalUpdate);
  480.                 continue;
  481.             }
  482.             Error(kDoPerror, "Error occurred during read!\n");
  483.             xp->aborted = 1;
  484.             nRead = -1;
  485.             goto done;
  486.         }
  487.         break;
  488.     }
  489.  
  490.     xp->bytesTransferred += nRead;
  491.     if (xp->doReports)
  492.         ProgressReport(xp, kOptionalUpdate);
  493.  
  494.       done:
  495.     return (nRead);
  496. }                               /* StreamModeRead */
  497.  
  498.  
  499.  
  500. int
  501. StreamModeWrite(XferSpecPtr xp, char *wbuf, int nRead)
  502. {
  503.     int out;
  504.     int nPut, totalPut;
  505.  
  506.     out = xp->outStream;
  507.  
  508.     for (totalPut = 0;;) {
  509.         if (gXferAbortFlag > 0) {
  510.             xp->aborted = 1;
  511.             totalPut = -1;
  512.             goto done;
  513.         }
  514.         nPut = Swrite(out, wbuf, (size_t) nRead, gNetworkTimeout);
  515.         if (nPut < 0) {
  516.             if (errno != EINTR) {
  517.                 Error(kDoPerror, "Error occurred during write!\n");
  518.                 xp->aborted = 1;
  519.                 totalPut = -1;
  520.                 goto done;
  521.             }
  522.         } else {
  523.             totalPut += nPut;
  524.             if (nPut == nRead)
  525.                 break;
  526.             /* Short write; just write the rest * of it. */
  527.             wbuf += nPut;
  528.             nRead -= nPut;
  529.         }
  530.         if (xp->doReports)
  531.             ProgressReport(xp, kOptionalUpdate);
  532.     }
  533.  
  534.     xp->bytesTransferred += nRead;
  535.     if (xp->doReports)
  536.         ProgressReport(xp, kOptionalUpdate);
  537.  
  538.       done:
  539.     return (totalPut);
  540. }                               /* StreamModeWrite */
  541.  
  542.  
  543.  
  544.  
  545. int
  546. BlockModeRead(XferSpecPtr xp)
  547. {
  548.     int in;
  549.     int nRead;
  550.     size_t bsize;
  551.     FTPBlockHeader h;
  552.  
  553.     in = xp->inStream;
  554.  
  555.     if (xp->atEof != 0) {
  556.         nRead = 0;
  557.     } else for (;;) {
  558.         if (gXferAbortFlag > 0) {
  559.             xp->aborted = 1;
  560.             nRead = -1;
  561.             goto done;
  562.         }
  563.         nRead = Sread(in, (char *) &h, (size_t) 3, gNetworkTimeout, 1);
  564.         if (nRead < 3) {
  565.             /* Could not read block header. */
  566.             Error(kDoPerror, "Error occurred during read!\n");
  567.             xp->aborted = 1;
  568.             nRead = -1;
  569.             goto done;
  570.         }
  571.         bsize = (h.byteCount[0] << 8) | (h.byteCount[1]);
  572.         if (bsize == 0) {
  573.             nRead = 0;
  574.             if ((h.desc & kLastBlock) != 0) {
  575.                 xp->atEof = 1;
  576.                 break;           /* EOF, done. */
  577.             }
  578.             continue;           /* Empty block? */
  579.         }
  580.         if (gXferAbortFlag > 0) {
  581.             xp->aborted = 1;
  582.             nRead = -1;
  583.             goto done;
  584.         }
  585.         nRead = Sread(in, gXferBuf, bsize, gNetworkTimeout, 1);
  586.         if (nRead <= 0) {
  587.             Error(kDoPerror, "Error occurred during read!\n");
  588.             xp->aborted = 1;
  589.             nRead = -1;
  590.             goto done;
  591.         }
  592.         if ((h.desc & kLastBlock) != 0)
  593.             xp->atEof = 1;
  594.         break;
  595.     }
  596.  
  597.     xp->bytesTransferred += nRead;
  598.     if (xp->doReports)
  599.         ProgressReport(xp, kOptionalUpdate);
  600.  
  601.       done:
  602.     return (nRead);
  603. }                               /* BlockModeRead */
  604.  
  605.  
  606.  
  607. int
  608. BlockModeWrite(XferSpecPtr xp, char *wbuf, int nRead)
  609. {
  610.     int out;
  611.     unsigned short c;
  612.     int nPut;
  613.     FTPBlockHeader h;
  614.  
  615.     out = xp->outStream;
  616.  
  617.     if (xp->atEof != 0) {
  618.         /* Already sent EOF. */
  619.         return (-1);
  620.     }
  621.     if (gXferAbortFlag > 0) {
  622.         xp->aborted = 1;
  623.         nPut = -1;
  624.         goto done;
  625.     }
  626.     h.desc = (unsigned char) kRegularBlock;
  627.     if (nRead == 0) {
  628.         /* Send EOF block, which was just the header. */
  629.         h.desc = kLastBlock;
  630.     }
  631.     c = ((unsigned short) (nRead & 0xffff));
  632.     h.byteCount[0] = (unsigned char) ((c >> 8) & 0xff);
  633.     h.byteCount[1] = (unsigned char) (c & 0xff);
  634.  
  635.     nPut = Swrite(out, (char *) &h, (size_t) 3, gNetworkTimeout);
  636.     if (nPut <= 0) {
  637.         Error(kDoPerror, "Error occurred during write!\n");
  638.         xp->aborted = 1;
  639.         nPut = -1;
  640.         goto done;
  641.     }
  642.     if (nRead == 0) {
  643.         /* Already sent EOF block, which was just the header. */
  644.         xp->atEof = 1;
  645.         return (1);    /* Probably should not return zero. */
  646.     }
  647.     nPut = Swrite(out, (char *) wbuf, (size_t) nRead, gNetworkTimeout);
  648.     if (nPut <= 0) {
  649.         Error(kDoPerror, "Error occurred during write!\n");
  650.         xp->aborted = 1;
  651.         nPut = -1;
  652.         goto done;
  653.     }
  654.  
  655.     xp->bytesTransferred += nRead;
  656.     if (xp->doReports)
  657.         ProgressReport(xp, kOptionalUpdate);
  658.  
  659.       done:
  660.     return (nPut);
  661. }                               /* BlockModeWrite */
  662.  
  663. /* eof */
  664.