summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/ftp/ftp.c203
-rw-r--r--ext/ftp/ftp.h6
2 files changed, 95 insertions, 114 deletions
diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c
index c9a23bedaf..e44186ec39 100644
--- a/ext/ftp/ftp.c
+++ b/ext/ftp/ftp.c
@@ -35,6 +35,7 @@
#include <winsock.h>
#else
#include <sys/socket.h>
+#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
@@ -68,8 +69,6 @@ static int ftp_putcmd( ftpbuf_t *ftp,
/* wrapper around send/recv to handle timeouts */
static int my_send(ftpbuf_t *ftp, int s, void *buf, size_t len);
static int my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len);
-static int my_connect(ftpbuf_t *ftp, int s, const struct sockaddr *addr,
- int addrlen);
static int my_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr,
int *addrlen);
@@ -107,27 +106,10 @@ union ipbox {
ftpbuf_t*
ftp_open(const char *host, short port, long timeout_sec)
{
- int fd = -1;
ftpbuf_t *ftp;
- struct sockaddr_in addr;
- struct hostent *he;
int size;
- /* set up the address */
- if ((he = gethostbyname(host)) == NULL) {
-#if 0
- herror("gethostbyname");
-#endif
- return NULL;
- }
-
- memset(&addr, 0, sizeof(addr));
- memcpy(&addr.sin_addr, he->h_addr, he->h_length);
- addr.sin_family = AF_INET;
- addr.sin_port = port ? port : htons(21);
-
-
/* alloc the ftp structure */
ftp = calloc(1, sizeof(*ftp));
if (ftp == NULL) {
@@ -135,29 +117,21 @@ ftp_open(const char *host, short port, long timeout_sec)
return NULL;
}
- /* Default Settings */
- ftp->timeout_sec = timeout_sec;
-
- /* connect */
- if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
- perror("socket");
+ ftp->fd = php_hostconnect(host, port ? port : 21, SOCK_STREAM, (int) timeout_sec);
+ if (ftp->fd == -1) {
goto bail;
}
- if (my_connect(ftp, fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
- perror("connect");
- goto bail;
- }
+ /* Default Settings */
+ ftp->timeout_sec = timeout_sec;
- size = sizeof(addr);
- if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) {
+ size = sizeof(ftp->localaddr);
+ memset(&ftp->localaddr, 0, size);
+ if (getsockname(ftp->fd, (struct sockaddr*) &ftp->localaddr, &size) == -1) {
perror("getsockname");
goto bail;
}
- ftp->localaddr = addr.sin_addr;
- ftp->fd = fd;
-
if (!ftp_getresp(ftp) || ftp->resp != 220) {
goto bail;
}
@@ -165,8 +139,8 @@ ftp_open(const char *host, short port, long timeout_sec)
return ftp;
bail:
- if (fd != -1)
- closesocket(fd);
+ if (ftp->fd != -1)
+ closesocket(ftp->fd);
free(ftp);
return NULL;
}
@@ -487,6 +461,8 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
union ipbox ipbox;
unsigned long b[6];
int n;
+ struct sockaddr *sa;
+ struct sockaddr_in *sin;
if (ftp == NULL)
return 0;
@@ -498,6 +474,47 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
if (!pasv)
return 1;
+ n = sizeof(ftp->pasvaddr);
+ memset(&ftp->pasvaddr, 0, n);
+ sa = (struct sockaddr *) &ftp->pasvaddr;
+
+#ifdef HAVE_IPV6
+ if (getpeername(ftp->fd, sa, &n) < 0)
+ return 0;
+
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
+ char *endptr, delimiter;
+
+ /* try EPSV first */
+ if (!ftp_putcmd(ftp, "EPSV", NULL))
+ return 0;
+ if (!ftp_getresp(ftp))
+ return 0;
+
+ if (ftp->resp == 229) {
+ /* parse out the port */
+ for (ptr = ftp->inbuf; *ptr && *ptr != '('; ptr++);
+ if (!*ptr)
+ return 0;
+ delimiter = *++ptr;
+ for (n = 0; *ptr && n < 3; ptr++) {
+ if (*ptr == delimiter)
+ n++;
+ }
+
+ sin6->sin6_port = htons((unsigned short) strtol(ptr, &endptr, 10));
+ if (ptr == endptr || *endptr != delimiter)
+ return 0;
+
+ ftp->pasv = 2;
+ return 1;
+ }
+ }
+
+ /* fall back to PASV */
+#endif
+
if (!ftp_putcmd(ftp, "PASV", NULL))
return 0;
if (!ftp_getresp(ftp) || ftp->resp != 227)
@@ -513,10 +530,10 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
for (n=0; n<6; n++)
ipbox.c[n] = (unsigned char) b[n];
- memset(&ftp->pasvaddr, 0, sizeof(ftp->pasvaddr));
- ftp->pasvaddr.sin_family = AF_INET;
- ftp->pasvaddr.sin_addr.s_addr = ipbox.l[0];
- ftp->pasvaddr.sin_port = ipbox.s[2];
+ sin = (struct sockaddr_in *) sa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ipbox.l[0];
+ sin->sin_port = ipbox.s[2];
ftp->pasv = 2;
@@ -970,61 +987,6 @@ my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len)
}
/* }}} */
-/* {{{ my_connect
- */
-int
-my_connect(ftpbuf_t *ftp, int s, const struct sockaddr *addr, int addrlen)
-#ifndef PHP_WIN32
-{
- fd_set conn_set;
- int flags;
- int n;
- int error = 0;
- struct timeval tv;
-
- flags = fcntl(s, F_GETFL, 0);
- fcntl(s, F_SETFL, flags | O_NONBLOCK);
-
- n = connect(s, addr, addrlen);
- if (n == -1 && errno != EINPROGRESS)
- return -1;
-
- if (n) {
- FD_ZERO(&conn_set);
- FD_SET(s, &conn_set);
-
- tv.tv_sec = ftp->timeout_sec;
- tv.tv_usec = 0;
-
- n = select(s + 1, &conn_set, &conn_set, NULL, &tv);
- if (n < 1) {
- if (n == 0)
- errno = ETIMEDOUT;
- return -1;
- }
-
- if (FD_ISSET(s, &conn_set)) {
- n = sizeof(error);
- n = getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &n);
- if (n == -1 || error) {
- if (error)
- errno = error;
- return -1;
- }
- }
- }
-
- fcntl(s, F_SETFL, flags);
-
- return 0;
-}
-#else
-{
- return connect(s, addr, addrlen);
-}
-#endif
-/* }}} */
-
/* {{{ my_accept
*/
int
@@ -1059,10 +1021,12 @@ ftp_getdata(ftpbuf_t *ftp)
{
int fd = -1;
databuf_t *data;
- struct sockaddr_in addr;
+ php_sockaddr_storage addr;
+ struct sockaddr *sa;
int size;
union ipbox ipbox;
char arg[sizeof("255, 255, 255, 255, 255, 255")];
+ struct timeval tv;
/* ask for a passive connection if we need one */
@@ -1079,25 +1043,26 @@ ftp_getdata(ftpbuf_t *ftp)
data->fd = -1;
Z_TYPE_P(data) = Z_TYPE_P(ftp);
+ sa = (struct sockaddr *) &ftp->localaddr;
/* bind/listen */
- if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+ if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
perror("socket");
goto bail;
}
+ size = sizeof(php_sockaddr_storage);
+
/* passive connection handler */
if (ftp->pasv) {
/* clear the ready status */
ftp->pasv = 1;
/* connect */
- if (my_connect(ftp, fd, (struct sockaddr*) &ftp->pasvaddr,
- sizeof(ftp->pasvaddr)) == -1)
- {
+ tv.tv_sec = ftp->timeout_sec;
+ tv.tv_usec = 0;
+ if (php_connect_nonb(fd, (struct sockaddr*) &ftp->pasvaddr, size, &tv) == -1) {
perror("connect");
- closesocket(fd);
- free(data);
- return NULL;
+ goto bail;
}
data->fd = fd;
@@ -1109,17 +1074,13 @@ ftp_getdata(ftpbuf_t *ftp)
/* active (normal) connection */
/* bind to a local address */
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- addr.sin_port = 0;
+ php_any_addr(sa->sa_family, &addr, 0);
- if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
+ if (bind(fd, (struct sockaddr*) &addr, size) == -1) {
perror("bind");
goto bail;
}
- size = sizeof(addr);
if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) {
perror("getsockname");
goto bail;
@@ -1132,9 +1093,27 @@ ftp_getdata(ftpbuf_t *ftp)
data->listener = fd;
+#ifdef HAVE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ /* need to use EPRT */
+ char eprtarg[INET6_ADDRSTRLEN + sizeof("|x||xxxxx|")];
+ char out[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &((struct sockaddr_in6*) sa)->sin6_addr, out, sizeof(out));
+ sprintf(eprtarg, "|2|%s|%hu|", out, ntohs(((struct sockaddr_in6 *) &addr)->sin6_port));
+
+ if (!ftp_putcmd(ftp, "EPRT", eprtarg))
+ goto bail;
+
+ if (!ftp_getresp(ftp) || ftp->resp != 200)
+ goto bail;
+
+ return data;
+ }
+#endif
+
/* send the PORT */
- ipbox.l[0] = ftp->localaddr.s_addr;
- ipbox.s[2] = addr.sin_port;
+ ipbox.l[0] = ((struct sockaddr_in*) sa)->sin_addr.s_addr;
+ ipbox.s[2] = ((struct sockaddr_in*) &addr)->sin_port;
sprintf(arg, "%u,%u,%u,%u,%u,%u",
ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3],
ipbox.c[4], ipbox.c[5]);
@@ -1159,7 +1138,7 @@ bail:
databuf_t*
data_accept(databuf_t *data, ftpbuf_t *ftp)
{
- struct sockaddr_in addr;
+ php_sockaddr_storage addr;
int size;
if (data->fd != -1)
diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h
index 9546e53c44..416c36df83 100644
--- a/ext/ftp/ftp.h
+++ b/ext/ftp/ftp.h
@@ -22,6 +22,8 @@
#ifndef FTP_H
#define FTP_H
+#include "php_network.h"
+
#include <stdio.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -40,7 +42,7 @@ typedef enum ftptype {
typedef struct ftpbuf
{
int fd; /* control connection */
- struct in_addr localaddr; /* local inet address */
+ php_sockaddr_storage localaddr; /* local address */
int resp; /* last response code */
char inbuf[FTP_BUFSIZE]; /* last response text */
char *extra; /* extra characters */
@@ -50,7 +52,7 @@ typedef struct ftpbuf
char *syst; /* cached system type */
ftptype_t type; /* current transfer type */
int pasv; /* 0=off; 1=pasv; 2=ready */
- struct sockaddr_in pasvaddr; /* passive mode address */
+ php_sockaddr_storage pasvaddr; /* passive mode address */
long timeout_sec; /* User configureable timeout (seconds) */
} ftpbuf_t;