From: Markus Fischer Date: Wed, 2 Jan 2002 14:58:17 +0000 (+0000) Subject: - Added ftp_set_option(), ftp_get_option() and support for setting a X-Git-Tag: PRE_ISSET_PATCH~333 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9bde60d1487f9108ab6bd2595c12afe542082782;p=php - Added ftp_set_option(), ftp_get_option() and support for setting a custom timeout. # Adding custom buffer size would be next, no promises though. --- 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 #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