~ubuntu-branches/ubuntu/saucy/curl/saucy-201307251546

« back to all changes in this revision

Viewing changes to lib/ftp.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2013-02-12 08:54:32 UTC
  • mfrom: (3.4.34 sid)
  • Revision ID: package-import@ubuntu.com-20130212085432-r1fyi0b37enr93pp
Tags: 7.29.0-1ubuntu1
* Resynchronise with Debian. Remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.
* Add warning to debian/patches/series.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
20
20
 *
21
21
 ***************************************************************************/
22
22
 
23
 
#include "setup.h"
 
23
#include "curl_setup.h"
24
24
 
25
25
#ifndef CURL_DISABLE_FTP
26
26
 
27
 
#ifdef HAVE_UNISTD_H
28
 
#include <unistd.h>
29
 
#endif
30
 
 
31
 
#ifdef HAVE_SYS_SOCKET_H
32
 
#include <sys/socket.h>
33
 
#endif
34
27
#ifdef HAVE_NETINET_IN_H
35
28
#include <netinet/in.h>
36
29
#endif
108
101
#endif
109
102
 
110
103
/* Local API functions */
111
 
static void state(struct connectdata *conn,
112
 
                  ftpstate newstate);
 
104
#ifndef DEBUGBUILD
 
105
static void _state(struct connectdata *conn,
 
106
                   ftpstate newstate);
 
107
#define state(x,y) _state(x,y)
 
108
#else
 
109
static void _state(struct connectdata *conn,
 
110
                   ftpstate newstate,
 
111
                   int lineno);
 
112
#define state(x,y) _state(x,y,__LINE__)
 
113
#endif
 
114
 
113
115
static CURLcode ftp_sendquote(struct connectdata *conn,
114
116
                              struct curl_slist *quote);
115
117
static CURLcode ftp_quit(struct connectdata *conn);
156
158
                             struct pingpong *pp,
157
159
                             int *ftpcode,
158
160
                             size_t *size);
 
161
static CURLcode ftp_dophase_done(struct connectdata *conn,
 
162
                                 bool connected);
159
163
 
160
164
/* easy-to-use macro: */
161
165
#define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
418
422
 * connection for a negative response regarding a failure in connecting
419
423
 *
420
424
 */
421
 
static CURLcode ReceivedServerConnect(struct connectdata* conn, bool* received)
 
425
static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
422
426
{
423
427
  struct SessionHandle *data = conn->data;
424
428
  curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
521
525
  else {
522
526
    /* FTP download: */
523
527
    Curl_setup_transfer(conn, SECONDARYSOCKET,
524
 
        conn->proto.ftpc.retr_size_saved, FALSE,
525
 
        ftp->bytecountp, -1, NULL); /* no upload here */
 
528
                        conn->proto.ftpc.retr_size_saved, FALSE,
 
529
                        ftp->bytecountp, -1, NULL); /* no upload here */
526
530
  }
527
531
 
528
532
  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
535
539
 *
536
540
 * AllowServerConnect()
537
541
 *
538
 
 * When we've issue the PORT command, we have told the server to connect
539
 
 * to us. This function
540
 
 *   - will sit and wait here until the server has connected for easy interface
541
 
 *   - will check whether data connection is established if so it is accepted
542
 
 *   for multi interface
 
542
 * When we've issue the PORT command, we have told the server to connect to
 
543
 * us. This function checks whether data connection is established if so it is
 
544
 * accepted.
543
545
 *
544
546
 */
545
547
static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
546
548
{
547
549
  struct SessionHandle *data = conn->data;
548
550
  long timeout_ms;
549
 
  long interval_ms;
550
551
  CURLcode ret = CURLE_OK;
551
552
 
552
553
  *connected = FALSE;
555
556
  /* Save the time we start accepting server connect */
556
557
  Curl_pgrsTime(data, TIMER_STARTACCEPT);
557
558
 
558
 
  for(;;) {
559
 
    timeout_ms = ftp_timeleft_accept(data);
560
 
    if(timeout_ms < 0) {
561
 
      /* if a timeout was already reached, bail out */
562
 
      failf(data, "Accept timeout occurred while waiting server connect");
563
 
      return CURLE_FTP_ACCEPT_TIMEOUT;
564
 
    }
565
 
 
566
 
    /* see if the connection request is already here */
567
 
    ret = ReceivedServerConnect(conn, connected);
568
 
    if(ret)
569
 
      return ret;
570
 
 
571
 
    if(*connected) {
572
 
      ret = AcceptServerConnect(conn);
573
 
      if(ret)
574
 
        return ret;
575
 
 
576
 
      ret = InitiateTransfer(conn);
577
 
      if(ret)
578
 
        return ret;
579
 
 
580
 
      break; /* connection is accepted, break the loop */
581
 
    }
582
 
    else {
583
 
      if(data->state.used_interface == Curl_if_easy) {
584
 
        interval_ms = 1000;
585
 
        if(timeout_ms < interval_ms)
586
 
          interval_ms = timeout_ms;
587
 
 
588
 
        /* sleep for 1 second and then continue */
589
 
        Curl_socket_ready(CURL_SOCKET_BAD, CURL_SOCKET_BAD, interval_ms);
590
 
      }
591
 
      else {
592
 
        /* Add timeout to multi handle and break out of the loop */
593
 
        if(ret == CURLE_OK && *connected == FALSE) {
594
 
          if(data->set.accepttimeout > 0)
595
 
            Curl_expire(data, data->set.accepttimeout);
596
 
          else
597
 
            Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
598
 
        }
599
 
 
600
 
        break; /* connection was not accepted immediately */
601
 
      }
 
559
  timeout_ms = ftp_timeleft_accept(data);
 
560
  if(timeout_ms < 0) {
 
561
    /* if a timeout was already reached, bail out */
 
562
    failf(data, "Accept timeout occurred while waiting server connect");
 
563
    return CURLE_FTP_ACCEPT_TIMEOUT;
 
564
  }
 
565
 
 
566
  /* see if the connection request is already here */
 
567
  ret = ReceivedServerConnect(conn, connected);
 
568
  if(ret)
 
569
    return ret;
 
570
 
 
571
  if(*connected) {
 
572
    ret = AcceptServerConnect(conn);
 
573
    if(ret)
 
574
      return ret;
 
575
 
 
576
    ret = InitiateTransfer(conn);
 
577
    if(ret)
 
578
      return ret;
 
579
  }
 
580
  else {
 
581
    /* Add timeout to multi handle and break out of the loop */
 
582
    if(ret == CURLE_OK && *connected == FALSE) {
 
583
      if(data->set.accepttimeout > 0)
 
584
        Curl_expire(data, data->set.accepttimeout);
 
585
      else
 
586
        Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
602
587
    }
603
588
  }
604
589
 
632
617
                             size_t *size) /* size of the response */
633
618
{
634
619
  struct connectdata *conn = pp->conn;
 
620
  struct SessionHandle *data = conn->data;
635
621
#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
636
 
  struct SessionHandle *data = conn->data;
637
622
  char * const buf = data->state.buffer;
638
623
#endif
639
624
  CURLcode result = CURLE_OK;
661
646
#endif
662
647
 
663
648
  /* store the latest code for later retrieval */
664
 
  conn->data->info.httpcode=code;
 
649
  data->info.httpcode=code;
665
650
 
666
651
  if(ftpcode)
667
652
    *ftpcode = code;
668
653
 
669
 
  if(421 == code)
 
654
  if(421 == code) {
670
655
    /* 421 means "Service not available, closing control connection." and FTP
671
656
     * servers use it to signal that idle session timeout has been exceeded.
672
 
     * If we ignored the response, it could end up hanging in some cases. */
 
657
     * If we ignored the response, it could end up hanging in some cases.
 
658
     *
 
659
     * This response code can come at any point so having it treated
 
660
     * generically is a good idea.
 
661
     */
 
662
    infof(data, "We got a 421 - timeout!\n");
 
663
    state(conn, FTP_STOP);
673
664
    return CURLE_OPERATION_TIMEDOUT;
 
665
  }
674
666
 
675
667
  return result;
676
668
}
787
779
}
788
780
 
789
781
/* This is the ONLY way to change FTP state! */
790
 
static void state(struct connectdata *conn,
791
 
                  ftpstate newstate)
 
782
static void _state(struct connectdata *conn,
 
783
                   ftpstate newstate
 
784
#ifdef DEBUGBUILD
 
785
                   , int lineno
 
786
#endif
 
787
  )
792
788
{
793
789
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
794
790
  /* for debug purposes */
833
829
  struct ftp_conn *ftpc = &conn->proto.ftpc;
834
830
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
835
831
  if(ftpc->state != newstate)
836
 
    infof(conn->data, "FTP %p state change from %s to %s\n",
837
 
          ftpc, names[ftpc->state], names[newstate]);
 
832
    infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
 
833
          ftpc, lineno, names[ftpc->state], names[newstate]);
838
834
#endif
839
835
  ftpc->state = newstate;
840
836
}
1793
1789
  return result;
1794
1790
}
1795
1791
 
 
1792
/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
 
1793
   problems */
 
1794
static CURLcode ftp_epsv_disable(struct connectdata *conn)
 
1795
{
 
1796
  CURLcode result = CURLE_OK;
 
1797
  infof(conn->data, "got positive EPSV response, but can't connect. "
 
1798
        "Disabling EPSV\n");
 
1799
  /* disable it for next transfer */
 
1800
  conn->bits.ftp_use_epsv = FALSE;
 
1801
  conn->data->state.errorbuf = FALSE; /* allow error message to get
 
1802
                                         rewritten */
 
1803
  PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL);
 
1804
  conn->proto.ftpc.count1++;
 
1805
  /* remain in the FTP_PASV state */
 
1806
  return result;
 
1807
}
 
1808
 
1796
1809
static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1797
1810
                                    int ftpcode)
1798
1811
{
1837
1850
            break;
1838
1851
          }
1839
1852
        }
 
1853
        if(num > 0xffff) {
 
1854
          failf(data, "Illegal port number in EPSV reply");
 
1855
          return CURLE_FTP_WEIRD_PASV_REPLY;
 
1856
        }
1840
1857
        if(ptr) {
1841
1858
          newport = (unsigned short)(num & 0xffff);
1842
1859
 
1975
1992
 
1976
1993
  Curl_resolv_unlock(data, addr); /* we're done using this address */
1977
1994
 
1978
 
  if(result && ftpc->count1 == 0 && ftpcode == 229) {
1979
 
    infof(data, "got positive EPSV response, but can't connect. "
1980
 
          "Disabling EPSV\n");
1981
 
    /* disable it for next transfer */
1982
 
    conn->bits.ftp_use_epsv = FALSE;
1983
 
    data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1984
 
    PPSENDF(&ftpc->pp, "PASV", NULL);
1985
 
    ftpc->count1++;
1986
 
    /* remain in the FTP_PASV state */
1987
 
    return result;
1988
 
 }
 
1995
  if(result) {
 
1996
    if(ftpc->count1 == 0 && ftpcode == 229)
 
1997
      return ftp_epsv_disable(conn);
1989
1998
 
1990
 
  if(result)
1991
1999
    return result;
 
2000
  }
1992
2001
 
1993
2002
  conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
1994
2003
 
2028
2037
    break;
2029
2038
  }
2030
2039
 
2031
 
  if(result)
 
2040
  if(result) {
 
2041
    if(ftpc->count1 == 0 && ftpcode == 229)
 
2042
      return ftp_epsv_disable(conn);
2032
2043
    return result;
 
2044
  }
2033
2045
 
2034
2046
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2035
2047
    /* FIX: this MUST wait for a proper connect first if 'connected' is
2055
2067
 
2056
2068
    if(result)
2057
2069
      return result;
 
2070
 
 
2071
    if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
 
2072
      /* the CONNECT procedure is not complete, the tunnel is not yet up */
 
2073
      state(conn, FTP_STOP); /* this phase is completed */
 
2074
      conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
 
2075
 
 
2076
      return result;
 
2077
    }
2058
2078
  }
2059
2079
 
2060
2080
  conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
2061
2081
 
 
2082
  conn->bits.do_more = TRUE;
2062
2083
  state(conn, FTP_STOP); /* this phase is completed */
2063
2084
 
2064
2085
  return result;
2092
2113
  else {
2093
2114
    infof(data, "Connect data stream actively\n");
2094
2115
    state(conn, FTP_STOP); /* end of DO phase */
 
2116
    result = ftp_dophase_done(conn, FALSE);
2095
2117
  }
2096
2118
 
2097
2119
  return result;
2394
2416
 
2395
2417
  if(ftpcode>=400) {
2396
2418
    failf(data, "Failed FTP upload: %0d", ftpcode);
 
2419
    state(conn, FTP_STOP);
2397
2420
    /* oops, we never close the sockets! */
2398
2421
    return CURLE_UPLOAD_FAILED;
2399
2422
  }
2411
2434
    if(!connected) {
2412
2435
      struct ftp_conn *ftpc = &conn->proto.ftpc;
2413
2436
      infof(data, "Data conn was not available immediately\n");
2414
 
      /* as there's not necessarily an immediate action on the control
2415
 
         connection now, we halt the state machine */
2416
 
      state(conn, FTP_STOP);
2417
2437
      ftpc->wait_data_conn = TRUE;
2418
2438
    }
2419
2439
 
3192
3212
{
3193
3213
  CURLcode result;
3194
3214
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3195
 
  struct SessionHandle *data=conn->data;
3196
3215
  struct pingpong *pp = &ftpc->pp;
3197
3216
 
3198
3217
  *done = FALSE; /* default to not done yet */
3226
3245
     response */
3227
3246
  state(conn, FTP_WAIT220);
3228
3247
 
3229
 
  if(data->state.used_interface == Curl_if_multi)
3230
 
    result = ftp_multi_statemach(conn, done);
3231
 
  else {
3232
 
    result = ftp_easy_statemach(conn);
3233
 
    if(!result)
3234
 
      *done = TRUE;
3235
 
  }
 
3248
  result = ftp_multi_statemach(conn, done);
3236
3249
 
3237
3250
  return result;
3238
3251
}
3663
3676
  /* the ftp struct is inited in ftp_connect() */
3664
3677
  struct FTP *ftp = data->state.proto.ftp;
3665
3678
 
 
3679
  *complete = FALSE;
 
3680
 
3666
3681
  /* if the second connection isn't done yet, wait for it */
3667
3682
  if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
 
3683
    if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
 
3684
      /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
 
3685
         aren't used so we blank their arguments. TODO: make this nicer */
 
3686
      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
 
3687
 
 
3688
      return result;
 
3689
    }
 
3690
 
3668
3691
    result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
3669
3692
 
3670
3693
    /* Ready to do more? */
3675
3698
      return result;
3676
3699
  }
3677
3700
 
 
3701
  if(ftpc->state) {
 
3702
    /* already in a state so skip the intial commands.
 
3703
       They are only done to kickstart the do_more state */
 
3704
    result = ftp_multi_statemach(conn, complete);
 
3705
 
 
3706
    /* if we got an error or if we don't wait for a data connection return
 
3707
       immediately */
 
3708
    if(result || (ftpc->wait_data_conn != TRUE))
 
3709
      return result;
 
3710
 
 
3711
    if(ftpc->wait_data_conn)
 
3712
      /* if we reach the end of the FTP state machine here, *complete will be
 
3713
         TRUE but so is ftpc->wait_data_conn, which says we need to wait for
 
3714
         the data connection and therefore we're not actually complete */
 
3715
      *complete = FALSE;
 
3716
  }
 
3717
 
3678
3718
  if(ftp->transfer <= FTPTRANSFER_INFO) {
3679
3719
    /* a transfer is about to take place, or if not a file name was given
3680
3720
       so we'll do a SIZE on it later and then we need the right TYPE first */
3701
3741
      result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
3702
3742
      if(result)
3703
3743
        return result;
 
3744
 
 
3745
      result = ftp_multi_statemach(conn, complete);
3704
3746
    }
3705
3747
    else {
3706
3748
      /* download */
3727
3769
        if(result)
3728
3770
          return result;
3729
3771
      }
 
3772
 
 
3773
      result = ftp_multi_statemach(conn, complete);
3730
3774
    }
3731
 
    result = ftp_easy_statemach(conn);
 
3775
    return result;
3732
3776
  }
3733
3777
 
3734
3778
  if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
3771
3815
    ftp->transfer = FTPTRANSFER_INFO;
3772
3816
  }
3773
3817
 
3774
 
 
3775
3818
  *dophase_done = FALSE; /* not done yet */
3776
3819
 
3777
3820
  /* start the first command in the DO phase */
3780
3823
    return result;
3781
3824
 
3782
3825
  /* run the state-machine */
3783
 
  if(conn->data->state.used_interface == Curl_if_multi)
3784
 
    result = ftp_multi_statemach(conn, dophase_done);
3785
 
  else {
3786
 
    result = ftp_easy_statemach(conn);
3787
 
    *dophase_done = TRUE; /* with the easy interface we are done here */
3788
 
  }
 
3826
  result = ftp_multi_statemach(conn, dophase_done);
 
3827
 
3789
3828
  *connected = conn->bits.tcpconnect[FIRSTSOCKET];
3790
3829
 
3791
3830
  if(*dophase_done)
3792
 
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
 
3831
    DEBUGF(infof(conn->data, "DO phase is complete1\n"));
3793
3832
 
3794
3833
  return result;
3795
3834
}
4402
4441
static CURLcode ftp_dophase_done(struct connectdata *conn,
4403
4442
                                 bool connected)
4404
4443
{
4405
 
  CURLcode result = CURLE_OK;
4406
4444
  struct FTP *ftp = conn->data->state.proto.ftp;
4407
4445
  struct ftp_conn *ftpc = &conn->proto.ftpc;
4408
4446
 
4409
4447
  if(connected) {
4410
4448
    bool completed;
4411
 
    result = ftp_do_more(conn, &completed);
4412
 
  }
 
4449
    CURLcode result = ftp_do_more(conn, &completed);
4413
4450
 
4414
 
  if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
4415
 
    /* Failure detected, close the second socket if it was created already */
4416
 
    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
4417
 
    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
4418
 
    return result;
 
4451
    if(result) {
 
4452
      if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
 
4453
        /* close the second socket if it was created already */
 
4454
        Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
 
4455
        conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
 
4456
      }
 
4457
      return result;
 
4458
    }
4419
4459
  }
4420
4460
 
4421
4461
  if(ftp->transfer != FTPTRANSFER_BODY)
4427
4467
 
4428
4468
  ftpc->ctl_valid = TRUE; /* seems good */
4429
4469
 
4430
 
  return result;
 
4470
  return CURLE_OK;
4431
4471
}
4432
4472
 
4433
4473
/* called from multi.c while DOing */
4441
4481
  else if(*dophase_done) {
4442
4482
    result = ftp_dophase_done(conn, FALSE /* not connected */);
4443
4483
 
4444
 
    DEBUGF(infof(conn->data, "DO phase is complete\n"));
 
4484
    DEBUGF(infof(conn->data, "DO phase is complete2\n"));
4445
4485
  }
4446
4486
  return result;
4447
4487
}
4486
4526
      return CURLE_OK;
4487
4527
 
4488
4528
    result = ftp_dophase_done(conn, connected);
 
4529
 
4489
4530
    if(result)
4490
4531
      return result;
4491
4532
  }