diff options
author | Wez Furlong <wez@php.net> | 2001-05-05 18:36:22 +0000 |
---|---|---|
committer | Wez Furlong <wez@php.net> | 2001-05-05 18:36:22 +0000 |
commit | 3ffb8e3800db8733d1bba602200a51a47985c17a (patch) | |
tree | ce32f12f4ea0cb0ff9aa30bf8a744f5b09062c67 /main/streams.c | |
parent | d5763bbdcbb6323aa99392145399deb6f58ec3aa (diff) | |
download | php-git-3ffb8e3800db8733d1bba602200a51a47985c17a.tar.gz |
Nuke buffering from php_streams, move connect_nonb() from fsock.c to network.c
and rename to php_connect_nonb().
Use php_connect_nonb() instead of connect() in php_hostconnect() -> timeouts
should now work in php_hostconnect().
sock streams abstraction now uses php_sockbuf as the "abstract" pointer.
Diffstat (limited to 'main/streams.c')
-rwxr-xr-x | main/streams.c | 317 |
1 files changed, 58 insertions, 259 deletions
diff --git a/main/streams.c b/main/streams.c index c25d0db73b..df0350d266 100755 --- a/main/streams.c +++ b/main/streams.c @@ -22,6 +22,12 @@ #if HAVE_PHP_STREAM +#ifdef PHP_WIN32 +#define EWOULDBLOCK WSAEWOULDBLOCK +#else +#include "build-defs.h" +#endif + #define MAX_CHUNK_SIZE 8192 #define TOREAD(stream) ((stream)->readbuf.writepos - (stream)->readbuf.readpos) @@ -32,92 +38,8 @@ #define READ_MAX(stream, max) if (stream->is_blocked) stream_read_total(sock, max); else stream_readahead(sock) - -PHPAPI int php_stream_buf_init(php_stream_buffer * buffer, int persistent, size_t chunksize) -{ - memset(buffer, 0, sizeof(php_stream_buffer)); - - /* defer memory allocation until first use */ - buffer->persistent = persistent; - buffer->chunksize = chunksize; - - return SUCCESS; -} - -PHPAPI int php_stream_buf_cleanup(php_stream_buffer * buffer) -{ - if (buffer->buffer) { - pefree(buffer->buffer, buffer->persistent); - buffer->buffer = NULL; - } - return SUCCESS; -} - -/* append data to the buffer ready for reading */ -PHPAPI int php_stream_buf_append(php_stream_buffer * buffer, const char * buf, size_t size) -{ - if (!buffer->dirty && buffer->buffer && (buffer->writepos + size > buffer->buflen)) { - /* if a lot of memory is sitting idle, reclaim it, but only if we are "clean" */ - if (buffer->readpos > 4 * buffer->chunksize) { - memmove(buffer->buffer + buffer->readpos, buffer->buffer, buffer->writepos - buffer->readpos); - - buffer->writepos -= buffer->readpos; - buffer->readpos = 0; - } - } - while (buffer->writepos + size > buffer->buflen) { - /* grow it */ - buffer->buflen += buffer->chunksize; - buffer->buffer = perealloc(buffer->buffer, buffer->buflen, buffer->persistent); - } - memcpy(buffer->buffer + buffer->writepos, buf, size); - buffer->writepos += size; - return SUCCESS; -} - -/* write data into the buffer at the present read position. - When done, if we overlapped the writepos, move it to so that - it occurs just after the zone we wrote. -*/ -PHPAPI int php_stream_buf_overwrite(php_stream_buffer * buffer, const char * buf, size_t size) -{ - /* ensure that there it enough memory */ - while (buffer->readpos + size > buffer->buflen) { - buffer->buflen += buffer->chunksize; - buffer->buffer = perealloc(buffer->buffer, buffer->buflen, buffer->persistent); - } - memcpy(buffer->buffer + buffer->readpos, buf, size); - if (buffer->readpos + size > buffer->writepos) - buffer->writepos = buffer->readpos + size; - - buffer->dirty = 1; - - return SUCCESS; -} - -/* read data out of buffer */ -PHPAPI size_t php_stream_buf_read(php_stream_buffer * buffer, char * buf, size_t size) -{ - size_t ret; - - ret = MIN(size, buffer->writepos - buffer->readpos); - - if (ret == 0) { - if (buf) - buf[0] = 0; - } - else { - if (buf) - memcpy(buf, buffer->buffer + buffer->readpos, ret); - buffer->readpos += ret; - } - return ret; -} - - - /* allocate a new stream for a particular ops */ -PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, size_t bufsize, int persistent, const char * mode) +PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, int persistent, const char * mode) { php_stream * ret; @@ -131,10 +53,6 @@ PHPAPI php_stream * php_stream_alloc(php_stream_ops * ops, void * abstract, size strncpy(ret->mode, mode, sizeof(ret->mode)); - if (bufsize) { - ret->is_buffered = 1; - php_stream_buf_init(&ret->readbuf, persistent, bufsize); - } return ret; } @@ -143,97 +61,44 @@ PHPAPI int php_stream_free(php_stream * stream, int call_dtor) int ret = 1; if (call_dtor) { + + if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { + /* calling fclose on an fopencookied stream will ultimately + call this very same function. If we were called via fclose, + the cookie_closer unsets the fclose_stdiocast flags, so + we can be sure that we only reach here when PHP code calls + php_stream_free. + Lets let the cookie code clean it all up. + */ + return fclose(stream->stdiocast); + } + + php_stream_flush(stream); ret = stream->ops->close(stream); + + /* tidy up any FILE* that might have been fdopened */ + if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FDOPEN && stream->stdiocast) + { + fclose(stream->stdiocast); + stream->stdiocast = NULL; + } } - php_stream_buf_cleanup(&stream->readbuf); pefree(stream, stream->is_persistent); return ret; } -/* get a chunk into the stream read buffer */ -static size_t stream_read_chunk(php_stream * stream) -{ - size_t nr, ret = 0; - char buf[MAX_CHUNK_SIZE]; - - /* do timeout check here ? */ - - nr = stream->ops->read(stream, buf, stream->readbuf.chunksize); - - if (nr > 0) { - if (php_stream_buf_append(&stream->readbuf, buf, nr)) - ret = nr; - } - else if (nr == 0 || (nr < 0 && errno != EWOULDBLOCK)) { - stream->eof = 1; - } - return ret; -} - - -/* read 1 + readahead chunks into buffer, if possible */ -static size_t stream_readahead(php_stream * stream) -{ - size_t nr_bytes; - size_t nr_read = 0; - int i; - - for(i = 0; !stream->eof && i < (stream->readahead + 1); i++) { - nr_bytes = stream_read_chunk(stream); - if(nr_bytes == 0) - break; - nr_read += nr_bytes; - } - return nr_read; -} - -static void stream_read_total(php_stream * stream, size_t size) -{ - while(!stream->eof && TOREAD(stream) < size && !stream->timeout_event) { - stream_readahead(stream); - } -} - - PHPAPI size_t php_stream_read(php_stream * stream, char * buf, size_t size) { - size_t ret = 0; - - if (stream->is_buffered) { - /* fill the buffer with enough bytes */ - stream_read_total(stream, size); - - if(size < 0) - return ret; - - ret = php_stream_buf_read(&stream->readbuf, buf, size); - } - else - ret = stream->ops->read(stream, buf, size); - - return ret; + return stream->ops->read(stream, buf, size); } PHPAPI int php_stream_eof(php_stream * stream) { - int ret = 0; - - if (stream->is_buffered) { - - if(!stream->is_blocked) - stream_read_chunk(stream); - - if(!TOREAD(stream) && stream->eof) - ret = 1; - } - else { - /* we will define our stream reading function so that it - must return EOF when an EOF condition occurs, when - working in unbuffered mode and called with these args */ - ret = stream->ops->read(stream, NULL, 0) == EOF ? 1 : 0; - } - return ret; + /* we define our stream reading function so that it + must return EOF when an EOF condition occurs, when + working in unbuffered mode and called with these args */ + return stream->ops->read(stream, NULL, 0) == EOF ? 1 : 0; } PHPAPI int php_stream_getc(php_stream * stream) @@ -245,9 +110,6 @@ PHPAPI int php_stream_getc(php_stream * stream) return EOF; } - -#define SEARCHCR() p = memchr(READPTR(stream), '\n', MIN(TOREAD(stream), maxlen)) - PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen) { @@ -256,46 +118,7 @@ PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen) return buf; } - if (stream->is_buffered) { - /* buffered fgets */ - char * p = NULL; - size_t amount = 0; - - SEARCHCR(); - - if (!p) { - if (stream->is_blocked) { - while (!p && !stream->eof && !stream->timeout_event && TOREAD(stream) < maxlen) - { - stream_read_chunk(stream); - SEARCHCR(); - } - } - else { - stream_read_chunk(stream); - SEARCHCR(); - } - } - - if (p) - amount = (ptrdiff_t)p - (ptrdiff_t)READPTR(stream) + 1; - else - amount = TOREAD(stream); - - amount = MIN(amount, maxlen); - php_stream_buf_read(&stream->readbuf, buf, amount); - buf[amount] = '\0'; - - /* signal error only if we don't return data from this call - and there is not data to read and if the eof flag is set */ - - if (amount || TOREAD(stream) || !stream->eof) { - return buf; - } - - return NULL; - } - else if (stream->ops->gets) { + if (stream->ops->gets) { return stream->ops->gets(stream, buf, maxlen); } else { @@ -318,47 +141,19 @@ PHPAPI char *php_stream_gets(php_stream * stream, char *buf, size_t maxlen) } } -static int stream_commit(php_stream * stream) -{ - zend_error(E_WARNING, "buffered writes not yet implemented!"); - return FAILURE; -} - PHPAPI int php_stream_flush(php_stream * stream) { - if (!stream->is_buffered && stream->ops->flush) - { - return stream->ops->flush(stream); - } - zend_error(E_WARNING, "php_stream_flush is not yet implemented on buffered streams!"); - return EOF; + return stream->ops->flush(stream); } PHPAPI size_t php_stream_write(php_stream * stream, const char * buf, size_t count) { - size_t ret = 0; - if (strchr(stream->mode, 'w') == NULL) { zend_error(E_WARNING, "%s(): stream was not opened for writing", get_active_function_name()); return 0; } - if (stream->is_buffered) { - /* commit buffer before appending, to preserve memory */ - stream_commit(stream); - - /* dump it into the buffer */ - php_stream_buf_overwrite(&stream->readbuf, buf, count); - - /* commit if it makes sense */ - stream_commit(stream); - - ret = count; - } - else - ret = stream->ops->write(stream, buf, count); - - return ret; + return stream->ops->write(stream, buf, count); } PHPAPI off_t php_stream_tell(php_stream * stream) @@ -372,26 +167,13 @@ PHPAPI off_t php_stream_tell(php_stream * stream) PHPAPI int php_stream_seek(php_stream * stream, off_t offset, int whence) { - if (stream->is_buffered) { - /*TODO: implement! - stream_commit(stream); - stream->readbuf.readpos = 0; - stream->readbuf.writepos = 0; - if (stream->ops->seek) - return stream->ops->seek(stream, offset, whence); - */ - goto cant_seek; - } - else if (stream->ops->seek) { + if (stream->ops->seek) return stream->ops->seek(stream, offset, whence); - } -cant_seek: - zend_error(E_ERROR, "streams of type %s do not support seeking", stream->ops->label); + zend_error(E_WARNING, "streams of type %s do not support seeking", stream->ops->label); return -1; } - /*------- STDIO stream implementation -------*/ static size_t php_stdiop_write(php_stream * stream, const char * buf, size_t count) @@ -464,7 +246,7 @@ PHPAPI php_stream * php_stream_fopen(const char * filename, const char * mode) FILE * fp = fopen(filename, mode); if (fp) { - php_stream * ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, 0, mode); + php_stream * ret = php_stream_alloc(&php_stream_stdio_ops, fp, 0, mode); if (ret) return ret; @@ -489,7 +271,10 @@ static int stream_cookie_seeker(void *cookie, off_t position, int whence) { } static int stream_cookie_closer(void *cookie) { - return php_stream_close(((php_stream *)cookie)); + php_stream * stream = (php_stream*)cookie; + /* prevent recursion */ + stream->fclose_stdiocast = PHP_STREAM_FCLOSE_NONE; + return php_stream_close(stream); } static COOKIE_IO_FUNCTIONS_T stream_cookie_functions = @@ -497,6 +282,8 @@ static COOKIE_IO_FUNCTIONS_T stream_cookie_functions = stream_cookie_reader, stream_cookie_writer, stream_cookie_seeker, stream_cookie_closer }; +#else +/* TODO: use socketpair() to emulate fopecookie, as suggested by Hartmut ? */ #endif PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int show_err) @@ -519,8 +306,10 @@ PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int sho *ret = fopencookie(stream, stream->mode, stream_cookie_functions); - if (*ret != NULL) + if (*ret != NULL) { + stream->fclose_stdiocast = 1; goto exit_success; + } /* must be either: a) programmer error @@ -539,7 +328,10 @@ PHPAPI int php_stream_cast(php_stream * stream, int castas, void ** ret, int sho exit_fail: if (show_err) { - const char * cast_names[3] = { "STDIO FILE*", "File Descriptor", "Socket Descriptor" }; + /* these names depend on the values of the PHP_STREAM_AS_XXX defines in php_streams.h */ + static const char * cast_names[3] = { + "STDIO FILE*", "File Descriptor", "Socket Descriptor" + }; zend_error(E_WARNING, "%s(): cannot represent a stream of type %s as a %s", get_active_function_name(), stream->ops->label, @@ -558,3 +350,10 @@ exit_success: } #endif +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim: tw=78 sw=4 ts=4 + */ |