summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/ftp/ftp.c81
-rw-r--r--ext/ftp/ftp.h8
-rw-r--r--ext/ftp/php_ftp.c127
-rw-r--r--ext/ftp/php_ftp.h4
4 files changed, 171 insertions, 49 deletions
diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c
index df20efd49a..c9a23bedaf 100644
--- a/ext/ftp/ftp.c
+++ b/ext/ftp/ftp.c
@@ -66,11 +66,12 @@ static int ftp_putcmd( ftpbuf_t *ftp,
const char *args);
/* wrapper around send/recv to handle timeouts */
-static int my_send(int s, void *buf, size_t len);
-static int my_recv(int s, void *buf, size_t len);
-static int my_connect(int s, const struct sockaddr *addr,
+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(int s, struct sockaddr *addr, int *addrlen);
+static int my_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr,
+ int *addrlen);
/* reads a line the socket , returns true on success, false on error */
static int ftp_readline(ftpbuf_t *ftp);
@@ -85,7 +86,7 @@ static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
static databuf_t* ftp_getdata(ftpbuf_t *ftp);
/* accepts the data connection, returns updated data buffer */
-static databuf_t* data_accept(databuf_t *data);
+static databuf_t* data_accept(databuf_t *data, ftpbuf_t *ftp);
/* closes the data connection, returns NULL */
static databuf_t* data_close(databuf_t *data);
@@ -104,7 +105,7 @@ union ipbox {
/* {{{ ftp_open
*/
ftpbuf_t*
-ftp_open(const char *host, short port)
+ftp_open(const char *host, short port, long timeout_sec)
{
int fd = -1;
ftpbuf_t *ftp;
@@ -134,13 +135,16 @@ ftp_open(const char *host, short port)
return NULL;
}
+ /* Default Settings */
+ ftp->timeout_sec = timeout_sec;
+
/* connect */
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
goto bail;
}
- if (my_connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
+ if (my_connect(ftp, fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
perror("connect");
goto bail;
}
@@ -533,24 +537,30 @@ ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type)
if (ftp == NULL)
return 0;
- if (!ftp_type(ftp, type))
+ if (!ftp_type(ftp, type)) {
goto bail;
+ }
- if ((data = ftp_getdata(ftp)) == NULL)
+ if ((data = ftp_getdata(ftp)) == NULL) {
goto bail;
+ }
- if (!ftp_putcmd(ftp, "RETR", path))
+ if (!ftp_putcmd(ftp, "RETR", path)) {
goto bail;
- if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125))
+ }
+ if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
goto bail;
+ }
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL) {
goto bail;
+ }
lastch = 0;
- while ((rcvd = my_recv(data->fd, data->buf, FTP_BUFSIZE))) {
- if (rcvd == -1)
+ while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
+ if (rcvd == -1) {
goto bail;
+ }
if (type == FTPTYPE_ASCII) {
for (ptr = data->buf; rcvd; rcvd--, ptr++) {
@@ -571,11 +581,13 @@ ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type)
data = data_close(data);
- if (ferror(outfp))
+ if (ferror(outfp)) {
goto bail;
+ }
- if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250))
+ if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
goto bail;
+ }
return 1;
bail:
@@ -608,7 +620,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, f
if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125))
goto bail;
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL)
goto bail;
size = 0;
@@ -616,7 +628,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, f
while ((ch = FP_FGETC(insocket, infp, issock))!=EOF && !FP_FEOF(insocket, infp, issock)) {
/* flush if necessary */
if (FTP_BUFSIZE - size < 2) {
- if (my_send(data->fd, data->buf, size) != size)
+ if (my_send(ftp, data->fd, data->buf, size) != size)
goto bail;
ptr = data->buf;
size = 0;
@@ -631,7 +643,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, int insocket, int issock, f
size++;
}
- if (size && my_send(data->fd, data->buf, size) != size)
+ if (size && my_send(ftp, data->fd, data->buf, size) != size)
goto bail;
if (!issock && ferror(infp))
@@ -792,7 +804,7 @@ ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
}
data = ftp->outbuf;
- if (my_send(ftp->fd, data, size) != size)
+ if (my_send(ftp, ftp->fd, data, size) != size)
return 0;
return 1;
@@ -841,8 +853,9 @@ ftp_readline(ftpbuf_t *ftp)
}
data = eol;
- if ((rcvd = my_recv(ftp->fd, data, size)) < 1)
+ if ((rcvd = my_recv(ftp, ftp->fd, data, size)) < 1) {
return 0;
+ }
} while (size);
return 0;
@@ -896,7 +909,7 @@ ftp_getresp(ftpbuf_t *ftp)
/* {{{ my_send
*/
int
-my_send(int s, void *buf, size_t len)
+my_send(ftpbuf_t *ftp, int s, void *buf, size_t len)
{
fd_set write_set;
struct timeval tv;
@@ -904,7 +917,7 @@ my_send(int s, void *buf, size_t len)
size = len;
while (size) {
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&write_set);
@@ -933,13 +946,13 @@ my_send(int s, void *buf, size_t len)
/* {{{ my_recv
*/
int
-my_recv(int s, void *buf, size_t len)
+my_recv(ftpbuf_t *ftp, int s, void *buf, size_t len)
{
fd_set read_set;
struct timeval tv;
int n;
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&read_set);
@@ -960,7 +973,7 @@ my_recv(int s, void *buf, size_t len)
/* {{{ my_connect
*/
int
-my_connect(int s, const struct sockaddr *addr, int addrlen)
+my_connect(ftpbuf_t *ftp, int s, const struct sockaddr *addr, int addrlen)
#ifndef PHP_WIN32
{
fd_set conn_set;
@@ -980,7 +993,7 @@ my_connect(int s, const struct sockaddr *addr, int addrlen)
FD_ZERO(&conn_set);
FD_SET(s, &conn_set);
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
n = select(s + 1, &conn_set, &conn_set, NULL, &tv);
@@ -1015,13 +1028,13 @@ my_connect(int s, const struct sockaddr *addr, int addrlen)
/* {{{ my_accept
*/
int
-my_accept(int s, struct sockaddr *addr, int *addrlen)
+my_accept(ftpbuf_t *ftp, int s, struct sockaddr *addr, int *addrlen)
{
fd_set accept_set;
struct timeval tv;
int n;
- tv.tv_sec = FTP_TIMEOUT;
+ tv.tv_sec = ftp->timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&accept_set);
FD_SET(s, &accept_set);
@@ -1078,7 +1091,7 @@ ftp_getdata(ftpbuf_t *ftp)
ftp->pasv = 1;
/* connect */
- if (my_connect(fd, (struct sockaddr*) &ftp->pasvaddr,
+ if (my_connect(ftp, fd, (struct sockaddr*) &ftp->pasvaddr,
sizeof(ftp->pasvaddr)) == -1)
{
perror("connect");
@@ -1144,7 +1157,7 @@ bail:
/* {{{ data_accept
*/
databuf_t*
-data_accept(databuf_t *data)
+data_accept(databuf_t *data, ftpbuf_t *ftp)
{
struct sockaddr_in addr;
int size;
@@ -1153,7 +1166,7 @@ data_accept(databuf_t *data)
return data;
size = sizeof(addr);
- data->fd = my_accept(data->listener, (struct sockaddr*) &addr, &size);
+ data->fd = my_accept(ftp, data->listener, (struct sockaddr*) &addr, &size);
closesocket(data->listener);
data->listener = -1;
@@ -1213,13 +1226,13 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path)
goto bail;
/* pull data buffer into tmpfile */
- if ((data = data_accept(data)) == NULL)
+ if ((data = data_accept(data, ftp)) == NULL)
goto bail;
size = 0;
lines = 0;
lastch = 0;
- while ((rcvd = my_recv(data->fd, data->buf, FTP_BUFSIZE))) {
+ while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
if (rcvd == -1)
goto bail;
diff --git a/ext/ftp/ftp.h b/ext/ftp/ftp.h
index 8cd6c2f704..9546e53c44 100644
--- a/ext/ftp/ftp.h
+++ b/ext/ftp/ftp.h
@@ -27,9 +27,10 @@
#include <netinet/in.h>
#endif
-/* XXX these should be configurable at runtime XXX */
+#define FTP_DEFAULT_TIMEOUT 90
+
+/* XXX this should be configurable at runtime XXX */
#define FTP_BUFSIZE 4096
-#define FTP_TIMEOUT 90
typedef enum ftptype {
FTPTYPE_ASCII,
@@ -50,6 +51,7 @@ typedef struct ftpbuf
ftptype_t type; /* current transfer type */
int pasv; /* 0=off; 1=pasv; 2=ready */
struct sockaddr_in pasvaddr; /* passive mode address */
+ long timeout_sec; /* User configureable timeout (seconds) */
} ftpbuf_t;
typedef struct databuf
@@ -64,7 +66,7 @@ typedef struct databuf
/* open a FTP connection, returns ftpbuf (NULL on error)
* port is the ftp port in network byte order, or 0 for the default
*/
-ftpbuf_t* ftp_open(const char *host, short port);
+ftpbuf_t* ftp_open(const char *host, short port, long timeout_sec);
/* quits from the ftp session (it still needs to be closed)
* return true on success, false on error
diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c
index c69c290142..80f8790f38 100644
--- a/ext/ftp/php_ftp.c
+++ b/ext/ftp/php_ftp.c
@@ -58,6 +58,8 @@ function_entry php_ftp_functions[] = {
PHP_FE(ftp_delete, NULL)
PHP_FE(ftp_site, NULL)
PHP_FE(ftp_close, NULL)
+ PHP_FE(ftp_set_option, NULL)
+ PHP_FE(ftp_get_option, NULL)
PHP_FALIAS(ftp_quit, ftp_close, NULL)
{NULL, NULL, NULL}
};
@@ -88,15 +90,12 @@ static void ftp_destructor_ftpbuf(zend_rsrc_list_entry *rsrc TSRMLS_DC)
PHP_MINIT_FUNCTION(ftp)
{
- le_ftpbuf = zend_register_list_destructors_ex(ftp_destructor_ftpbuf, NULL, "ftp", module_number);
- REGISTER_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_IMAGE", FTPTYPE_IMAGE,
- CONST_PERSISTENT | CONST_CS);
- REGISTER_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII,
- CONST_PERSISTENT | CONST_CS);
+ le_ftpbuf = zend_register_list_destructors_ex(ftp_destructor_ftpbuf, NULL, le_ftpbuf_name, module_number);
+ REGISTER_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_IMAGE", FTPTYPE_IMAGE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("FTP_TIMEOUT_SEC", PHP_FTP_OPT_TIMEOUT_SEC, CONST_PERSISTENT | CONST_CS);
return SUCCESS;
}
@@ -123,14 +122,21 @@ PHP_FUNCTION(ftp_connect)
{
ftpbuf_t *ftp;
char *host;
- int host_len, port = 21;
+ int host_len, port = 0;
+ long timeout_sec = FTP_DEFAULT_TIMEOUT;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &host, &host_len, &port) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &host, &host_len, &port, &timeout_sec) == FAILURE) {
return;
}
+ if (timeout_sec <= 0) {
+ php_error(E_WARNING, "%s(): timeout has to be greater than 0",
+ get_active_function_name(TSRMLS_C));
+ RETURN_FALSE;
+ }
+
/* connect */
- ftp = ftp_open(host, htons((short)port));
+ ftp = ftp_open(host, htons((short)port), timeout_sec);
if (ftp == NULL) {
RETURN_FALSE;
}
@@ -701,6 +707,103 @@ PHP_FUNCTION(ftp_close)
zend_list_delete(Z_LVAL_P(z_ftp));
}
/* }}} */
+
+/* Temporarely copied over from zend_API.c until it gets exposed */
+static char *ze_zval_type_name(zval *arg)
+{
+ switch (Z_TYPE_P(arg)) {
+ case IS_NULL:
+ return "null";
+
+ case IS_LONG:
+ return "integer";
+
+ case IS_DOUBLE:
+ return "double";
+
+ case IS_STRING:
+ return "string";
+
+ case IS_ARRAY:
+ return "array";
+
+ case IS_OBJECT:
+ return "object";
+
+ case IS_BOOL:
+ return "boolean";
+
+ case IS_RESOURCE:
+ return "resource";
+
+ default:
+ return "unknown";
+ }
+}
+
+
+/* {{{ proto bool ftp_set_option(resource stream, int option, mixed value)
+ Sets an FTP option. */
+PHP_FUNCTION(ftp_set_option)
+{
+ zval *z_ftp, *z_value;
+ long option;
+ ftpbuf_t *ftp;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rlz", &z_ftp, &option, &z_value) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+
+ switch (option) {
+ case PHP_FTP_OPT_TIMEOUT_SEC:
+ if (Z_TYPE_P(z_value) != IS_LONG) {
+ php_error(E_WARNING, "%s(): option TIMEOUT_SEC expects value of type long, %s given",
+ get_active_function_name(TSRMLS_C), ze_zval_type_name(z_value));
+ RETURN_FALSE;
+ }
+ if (Z_LVAL_P(z_value) <= 0) {
+ php_error(E_WARNING, "%s(): timeout has to be greater than 0",
+ get_active_function_name(TSRMLS_C));
+ RETURN_FALSE;
+ }
+ ftp->timeout_sec = Z_LVAL_P(z_value);
+ RETURN_TRUE;
+ break;
+ default:
+ php_error(E_WARNING, "%s(): unknown option '%d'", get_active_function_name(TSRMLS_C), option);
+ RETURN_FALSE;
+ break;
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed ftp_get_option(resource stream, int option)
+ Gets an FTP option. */
+PHP_FUNCTION(ftp_get_option)
+{
+ zval *z_ftp;
+ long option;
+ ftpbuf_t *ftp;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &z_ftp, &option) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ftp, ftpbuf_t*, &z_ftp, -1, le_ftpbuf_name, le_ftpbuf);
+
+ switch (option) {
+ case PHP_FTP_OPT_TIMEOUT_SEC:
+ RETURN_LONG(ftp->timeout_sec);
+ break;
+ default:
+ php_error(E_WARNING, "%s(): unknown option '%d'", get_active_function_name(TSRMLS_C), option);
+ RETURN_FALSE;
+ break;
+ }
+}
+/* }}} */
#endif /* HAVE_FTP */
diff --git a/ext/ftp/php_ftp.h b/ext/ftp/php_ftp.h
index 4d93a1ffe9..4172ed295e 100644
--- a/ext/ftp/php_ftp.h
+++ b/ext/ftp/php_ftp.h
@@ -27,6 +27,8 @@
extern zend_module_entry php_ftp_module_entry;
#define php_ftp_module_ptr &php_ftp_module_entry
+#define PHP_FTP_OPT_TIMEOUT_SEC 0
+
PHP_MINIT_FUNCTION(ftp);
PHP_MINFO_FUNCTION(ftp);
@@ -52,6 +54,8 @@ PHP_FUNCTION(ftp_rename);
PHP_FUNCTION(ftp_delete);
PHP_FUNCTION(ftp_site);
PHP_FUNCTION(ftp_close);
+PHP_FUNCTION(ftp_set_option);
+PHP_FUNCTION(ftp_get_option);
#define phpext_ftp_ptr php_ftp_module_ptr