Ejemplo n.º 1
0
static void
resize(void)
{
	/* Get terminal dimensions */
	ioctl(0, TIOCGWINSZ, &w);

	/* Clear, move to top separator and set color */
	printf(CLEAR_FULL MOVE(2, 1) FG(239));

	/* Draw upper separator */
	for (int i = 0; i < w.ws_col; i++)
		printf("―");

	/* Draw bottom bar, set color back to default */
	printf(MOVE(%d, 1) " >>> " FG(250), w.ws_row);

	/* Mark all buffers as resized for next draw */
	rirc->resized = 1;

	channel *c = ccur;
	do {
		c->resized = 1;
	} while ((c = channel_switch(c, 1)) != ccur);

	/* Draw everything else */
	draw(D_FULL);
}
Ejemplo n.º 2
0
/* API for registering VOLATILE wrappers */
PHPAPI int php_stream_filter_register_factory_volatile(const char *filterpattern, php_stream_filter_factory *factory)
{
	if (!FG(stream_filters)) {
		ALLOC_HASHTABLE(FG(stream_filters));
		zend_hash_init(FG(stream_filters), zend_hash_num_elements(&stream_filters_hash), NULL, NULL, 1);
		zend_hash_copy(FG(stream_filters), &stream_filters_hash, NULL);
	}

	return zend_hash_str_add_ptr(FG(stream_filters), (char*)filterpattern, strlen(filterpattern), factory) ? SUCCESS : FAILURE;
}
Ejemplo n.º 3
0
Archivo: draw.c Proyecto: sirpengi/rirc
void
resize(void)
{
	/* Get terminal dimensions */
	ioctl(0, TIOCGWINSZ, &w);

	/* Clear, set separator color, move to top separator */
	printf(CLEAR_FULL  FG(239)  MOVE(2, 1));

	/* Draw upper separator */
	for (i = 0; i < w.ws_col; i++)
		printf("―");

	/* Draw bottom bar, set color back to default */
	printf(MOVE(%d, 1)" >>> " FG(250), w.ws_row);

	/* Draw everything else */
	draw(D_FULL);
}
Ejemplo n.º 4
0
void
drawmenu(void) {
	int curpos;
	Item *item;

	dc->x = 0;
	dc->y = 0;
	dc->h = bh;
	drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol));

	if(prompt && *prompt) {
		dc->w = promptw;
		drawtext(dc, prompt, selcol);
		dc->x = dc->w;
	}
	/* draw input field */
	dc->w = (lines > 0 || !matches) ? mw - dc->x : inputw;
	drawtext(dc, text, normcol);
	if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w)
		drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol));

    /* // Draw hits */
    dc->w = textw(dc, hitstxt);
    dc->x = mw - dc->w;
    drawtext(dc, hitstxt, selcol);
    dc->x = 0;

	if(lines > 0) {
		/* draw vertical list */
		dc->w = mw - dc->x;
		for(item = curr; item != next; item = item->right) {
			dc->y += dc->h;
			drawtext(dc, item->text, (item == sel) ? selcol :
			                         (item->out)   ? outcol : normcol);
		}
	}
	else if(matches) {
		/* draw horizontal list */
		dc->x += inputw;
		dc->w = textw(dc, "<");
		if(curr->left)
			drawtext(dc, "<", normcol);
		for(item = curr; item != next; item = item->right) {
			dc->x += dc->w;
			dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">"));
			drawtext(dc, item->text, (item == sel) ? selcol :
			                         (item->out)   ? outcol : normcol);
		}
		dc->w = textw(dc, ">");
		dc->x = mw - dc->w;
		if(next)
			drawtext(dc, ">", normcol);
	}
	mapdc(dc, win, mw, mh);
}
Ejemplo n.º 5
0
/* We allow very simple pattern matching for filter factories:
 * if "convert.charset.utf-8/sjis" is requested, we search first for an exact
 * match. If that fails, we try "convert.charset.*", then "convert.*"
 * This means that we don't need to clog up the hashtable with a zillion
 * charsets (for example) but still be able to provide them all as filters */
PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval *filterparams, uint8_t persistent)
{
	HashTable *filter_hash = (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
	php_stream_filter_factory *factory = NULL;
	php_stream_filter *filter = NULL;
	size_t n;
	char *period;

	n = strlen(filtername);

	if (NULL != (factory = zend_hash_str_find_ptr(filter_hash, filtername, n))) {
		filter = factory->create_filter(filtername, filterparams, persistent);
	} else if ((period = strrchr(filtername, '.'))) {
		/* try a wildcard */
		char *wildname;

		wildname = emalloc(n+3);
		memcpy(wildname, filtername, n+1);
		period = wildname + (period - filtername);
		while (period && !filter) {
			*period = '\0';
			strncat(wildname, ".*", 2);
			if (NULL != (factory = zend_hash_str_find_ptr(filter_hash, wildname, strlen(wildname)))) {
				filter = factory->create_filter(filtername, filterparams, persistent);
			}

			*period = '\0';
			period = strrchr(wildname, '.');
		}
		efree(wildname);
	}

	if (filter == NULL) {
		/* TODO: these need correct docrefs */
		if (factory == NULL)
			php_error_docref(NULL, E_WARNING, "unable to locate filter \"%s\"", filtername);
		else
			php_error_docref(NULL, E_WARNING, "unable to create or locate filter \"%s\"", filtername);
	}

	return filter;
}
Ejemplo n.º 6
0
Archivo: draw.c Proyecto: Yomin/dmenu
void
drawtextn(DC *dc, const char *text, size_t n, unsigned long col[ColLast]) {
	int x = dc->x + dc->font.height/2;
	int y = dc->y + dc->font.ascent+1;

	XSetForeground(dc->dpy, dc->gc, FG(dc, col));
	if(dc->font.set)
		XmbDrawString(dc->dpy, dc->canvas, dc->font.set, dc->gc, x, y, text, n);
	else {
		XSetFont(dc->dpy, dc->gc, dc->font.xfont->fid);
		XDrawString(dc->dpy, dc->canvas, dc->gc, x, y, text, n);
	}
}
Ejemplo n.º 7
0
Archivo: draw.c Proyecto: sirpengi/rirc
int
print_line(int row, line *l)
{
	if (l < ccur->chat)
		l += SCROLLBACK_BUFFER;

	if (!l->len || l == ccur->cur_line)
		return 3;

	int count = 1;
	char *ptr1, *ptr2, *wrap;

	ptr1 = l->text;
	ptr2 = l->text + l->len;

	while ((ptr1 = word_wrap(ptr1, ptr2)) != NULL && ptr1 != ptr2)
		count++;

	if (row - count > 2)
		row = print_line(row - count, l - 1) + count - 1;

	ptr1 = l->text;
	if ((wrap = word_wrap(ptr1, ptr2)) != NULL)
		row = print_more(wrap, ptr2, row);
	else
		wrap = ptr2;

	int from_fg;
	char *from_bg = "";

	if (l->type == LINE_JOIN || l->type == LINE_PART || l->type == LINE_QUIT)
		from_fg = 239;
	else if (l->type == LINE_PINGED)
		from_fg = 255, from_bg = BG(1);
	else
		from_fg = nick_col(l->from);

	if (row > 2) {
		printf("\x1b[%d;1H\x1b[2K", row);
		printf(FG(239)" %02d:%02d  %*s"FG(%d)"%s%s"BG_R FG(239)" ~ "FG(250),
				l->time_h, l->time_m,
				(int)(ccur->nick_pad - strlen(l->from)), "",
				from_fg, from_bg, l->from);
		while (ptr1 < wrap)
			putchar(*ptr1++);
	}
Ejemplo n.º 8
0
static inline int sapi_cli_select(int fd)
{
	fd_set wfd, dfd;
	struct timeval tv;
	int ret;

	FD_ZERO(&wfd);
	FD_ZERO(&dfd);

	PHP_SAFE_FD_SET(fd, &wfd);

	tv.tv_sec = (long)FG(default_socket_timeout);
	tv.tv_usec = 0;

	ret = php_select(fd+1, &dfd, &wfd, &dfd, &tv);

	return ret != -1;
}
Ejemplo n.º 9
0
/* {{{ php_ssh2_session_connect
 * Connect to an SSH server with requested methods
 */
LIBSSH2_SESSION *php_ssh2_session_connect(char *host, int port, zval *methods, zval *callbacks)
{
	LIBSSH2_SESSION *session;
	int socket;
	php_ssh2_session_data *data;
	struct timeval tv;
	zend_string *hash_lookup_zstring;

	tv.tv_sec = FG(default_socket_timeout);
	tv.tv_usec = 0;

	socket = php_network_connect_socket_to_host(host, port, SOCK_STREAM, 0, &tv, NULL, NULL, NULL, 0, STREAM_SOCKOP_NONE);

	if (socket <= 0) {
		php_error_docref(NULL, E_WARNING, "Unable to connect to %s on port %d", host, port);
		return NULL;
	}

	data = ecalloc(1, sizeof(php_ssh2_session_data));
	data->socket = socket;

	session = libssh2_session_init_ex(php_ssh2_alloc_cb, php_ssh2_free_cb, php_ssh2_realloc_cb, data);
	if (!session) {
		php_error_docref(NULL, E_WARNING, "Unable to initialize SSH2 session");
		efree(data);
		closesocket(socket);
		return NULL;
	}
	libssh2_banner_set(session, LIBSSH2_SSH_DEFAULT_BANNER " PHP");

	/* Override method preferences */
	if (methods) {
		zval *container;

		if (php_ssh2_set_method(session, HASH_OF(methods), "kex", sizeof("kex") - 1, LIBSSH2_METHOD_KEX)) {
			php_error_docref(NULL, E_WARNING, "Failed overriding KEX method");
		}
		if (php_ssh2_set_method(session, HASH_OF(methods), "hostkey", sizeof("hostkey") - 1, LIBSSH2_METHOD_HOSTKEY)) {
			php_error_docref(NULL, E_WARNING, "Failed overriding HOSTKEY method");
		}

		hash_lookup_zstring = zend_string_init("client_to_server", sizeof("client_to_server") - 1, 0);
		if ((container = zend_hash_find(HASH_OF(methods), hash_lookup_zstring)) != NULL && Z_TYPE_P(container) == IS_ARRAY) {
			if (php_ssh2_set_method(session, HASH_OF(container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_CS)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding client to server CRYPT method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_CS)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding client to server MAC method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_CS)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding client to server COMP method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_CS)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding client to server LANG method");
			}
		}
		zend_string_release(hash_lookup_zstring);

		hash_lookup_zstring = zend_string_init("server_to_client", sizeof("server_to_client") - 1, 0);
		if ((container = zend_hash_find(HASH_OF(methods), hash_lookup_zstring)) != NULL && Z_TYPE_P(container) == IS_ARRAY) {
			if (php_ssh2_set_method(session, HASH_OF(container), "crypt", sizeof("crypt") - 1, LIBSSH2_METHOD_CRYPT_SC)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding server to client CRYPT method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "mac", sizeof("mac") - 1, LIBSSH2_METHOD_MAC_SC)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding server to client MAC method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "comp", sizeof("comp") - 1, LIBSSH2_METHOD_COMP_SC)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding server to client COMP method");
			}
			if (php_ssh2_set_method(session, HASH_OF(container), "lang", sizeof("lang") - 1, LIBSSH2_METHOD_LANG_SC)) {
				php_error_docref(NULL, E_WARNING, "Failed overriding server to client LANG method");
			}
		}
		zend_string_release(hash_lookup_zstring);

	}

	/* Register Callbacks */
	if (callbacks) {
		/* ignore debug disconnect macerror */

		if (php_ssh2_set_callback(session, HASH_OF(callbacks), "ignore", sizeof("ignore") - 1, LIBSSH2_CALLBACK_IGNORE, data)) {
			php_error_docref(NULL, E_WARNING, "Failed setting IGNORE callback");
		}

		if (php_ssh2_set_callback(session, HASH_OF(callbacks), "debug", sizeof("debug") - 1, LIBSSH2_CALLBACK_DEBUG, data)) {
			php_error_docref(NULL, E_WARNING, "Failed setting DEBUG callback");
		}

		if (php_ssh2_set_callback(session, HASH_OF(callbacks), "macerror", sizeof("macerror") - 1, LIBSSH2_CALLBACK_MACERROR, data)) {
			php_error_docref(NULL, E_WARNING, "Failed setting MACERROR callback");
		}

		if (php_ssh2_set_callback(session, HASH_OF(callbacks), "disconnect", sizeof("disconnect") - 1, LIBSSH2_CALLBACK_DISCONNECT, data)) {
			php_error_docref(NULL, E_WARNING, "Failed setting DISCONNECT callback");
		}
	}

	if (libssh2_session_startup(session, socket)) {
		int last_error = 0;
		char *error_msg = NULL;

		last_error = libssh2_session_last_error(session, &error_msg, NULL, 0);
		php_error_docref(NULL, E_WARNING, "Error starting up SSH connection(%d): %s", last_error, error_msg);
		closesocket(socket);
		libssh2_session_free(session);
		efree(data);
		return NULL;
	}

	return session;
}
Ejemplo n.º 10
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, 
		const char *path, const char *mode, int options, char **opened_path, 
		php_stream_context *context, int redirect_max, int flags STREAMS_DC TSRMLS_DC) /* {{{ */
{
	php_stream *stream = NULL;
	php_url *resource = NULL;
	int use_ssl;
	int use_proxy = 0;
	char *scratch = NULL;
	char *tmp = NULL;
	char *ua_str = NULL;
	zval **ua_zval = NULL, **tmpzval = NULL, *ssl_proxy_peer_name = NULL;
	int scratch_len = 0;
	int body = 0;
	char location[HTTP_HEADER_BLOCK_SIZE];
	zval *response_header = NULL;
	int reqok = 0;
	char *http_header_line = NULL;
	char tmp_line[128];
	size_t chunk_size = 0, file_size = 0;
	int eol_detect = 0;
	char *transport_string, *errstr = NULL;
	int transport_len, have_header = 0, request_fulluri = 0, ignore_errors = 0;
	char *protocol_version = NULL;
	int protocol_version_len = 3; /* Default: "1.0" */
	struct timeval timeout;
	char *user_headers = NULL;
	int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0);
	int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
	int follow_location = 1;
	php_stream_filter *transfer_encoding = NULL;
	int response_code;

	tmp_line[0] = '\0';

	if (redirect_max < 1) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Redirection limit reached, aborting");
		return NULL;
	}

	resource = php_url_parse(path);
	if (resource == NULL) {
		return NULL;
	}

	if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
		if (!context || 
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == FAILURE ||
			Z_TYPE_PP(tmpzval) != IS_STRING ||
			Z_STRLEN_PP(tmpzval) <= 0) {
			php_url_free(resource);
			return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context);
		}
		/* Called from a non-http wrapper with http proxying requested (i.e. ftp) */
		request_fulluri = 1;
		use_ssl = 0;
		use_proxy = 1;

		transport_len = Z_STRLEN_PP(tmpzval);
		transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
	} else {
		/* Normal http request (possibly with proxy) */
	
		if (strpbrk(mode, "awx+")) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections");
			php_url_free(resource);
			return NULL;
		}

		use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';
		/* choose default ports */
		if (use_ssl && resource->port == 0)
			resource->port = 443;
		else if (resource->port == 0)
			resource->port = 80;

		if (context &&
			php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == SUCCESS &&
			Z_TYPE_PP(tmpzval) == IS_STRING &&
			Z_STRLEN_PP(tmpzval) > 0) {
			use_proxy = 1;
			transport_len = Z_STRLEN_PP(tmpzval);
			transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
		} else {
			transport_len = spprintf(&transport_string, 0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", resource->host, resource->port);
		}
	}

	if (context && php_stream_context_get_option(context, wrapper->wops->label, "timeout", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		timeout.tv_sec = (time_t) Z_DVAL_PP(tmpzval);
		timeout.tv_usec = (size_t) ((Z_DVAL_PP(tmpzval) - timeout.tv_sec) * 1000000);
	} else {
		timeout.tv_sec = FG(default_socket_timeout);
		timeout.tv_usec = 0;
	}

	stream = php_stream_xport_create(transport_string, transport_len, options,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
			NULL, &timeout, context, &errstr, NULL);
    
	if (stream) {
		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &timeout);
	}
			
	if (errstr) {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", errstr);
		efree(errstr);
		errstr = NULL;
	}

	efree(transport_string);

	if (stream && use_proxy && use_ssl) {
		smart_str header = {0};

		/* Set peer_name or name verification will try to use the proxy server name */
		if (!context || php_stream_context_get_option(context, "ssl", "peer_name", &tmpzval) == FAILURE) {
			MAKE_STD_ZVAL(ssl_proxy_peer_name);
			ZVAL_STRING(ssl_proxy_peer_name, resource->host, 1);
			php_stream_context_set_option(stream->context, "ssl", "peer_name", ssl_proxy_peer_name);
		}

		smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1);
		smart_str_appends(&header, resource->host);
		smart_str_appendc(&header, ':');
		smart_str_append_unsigned(&header, resource->port);
		smart_str_appendl(&header, " HTTP/1.0\r\n", sizeof(" HTTP/1.0\r\n")-1);

	    /* check if we have Proxy-Authorization header */
		if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS) {
			char *s, *p;

			if (Z_TYPE_PP(tmpzval) == IS_ARRAY) {
				HashPosition pos;
				zval **tmpheader = NULL;

				for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(tmpzval), &pos);
					SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(tmpzval), (void *)&tmpheader, &pos);
					zend_hash_move_forward_ex(Z_ARRVAL_PP(tmpzval), &pos)) {
					if (Z_TYPE_PP(tmpheader) == IS_STRING) {
						s = Z_STRVAL_PP(tmpheader);
						do {
							while (*s == ' ' || *s == '\t') s++;
							p = s;
							while (*p != 0 && *p != ':' && *p != '\r' && *p !='\n') p++;
							if (*p == ':') {
								p++;
								if (p - s == sizeof("Proxy-Authorization:") - 1 &&
								    zend_binary_strcasecmp(s, sizeof("Proxy-Authorization:") - 1,
								        "Proxy-Authorization:", sizeof("Proxy-Authorization:") - 1) == 0) {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
									smart_str_appendl(&header, s, p - s);
									smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);
									goto finish;
								} else {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
								}
							}
							s = p;
							while (*s == '\r' || *s == '\n') s++;
						} while (*s != 0);
					}
				}
			} else if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) {
				s = Z_STRVAL_PP(tmpzval);
				do {
					while (*s == ' ' || *s == '\t') s++;
					p = s;
					while (*p != 0 && *p != ':' && *p != '\r' && *p !='\n') p++;
					if (*p == ':') {
						p++;
						if (p - s == sizeof("Proxy-Authorization:") - 1 &&
						    zend_binary_strcasecmp(s, sizeof("Proxy-Authorization:") - 1,
						        "Proxy-Authorization:", sizeof("Proxy-Authorization:") - 1) == 0) {
							while (*p != 0 && *p != '\r' && *p !='\n') p++;
							smart_str_appendl(&header, s, p - s);
							smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);
							goto finish;
						} else {
							while (*p != 0 && *p != '\r' && *p !='\n') p++;
						}
					}
					s = p;
					while (*s == '\r' || *s == '\n') s++;
				} while (*s != 0);
			}
		}
finish:
		smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);

		if (php_stream_write(stream, header.c, header.len) != header.len) {
			php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
			php_stream_close(stream);
			stream = NULL;
		}
 	 	smart_str_free(&header);

 	 	if (stream) {
 	 		char header_line[HTTP_HEADER_BLOCK_SIZE];

			/* get response header */
			while (php_stream_gets(stream, header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL) {
				if (header_line[0] == '\n' ||
				    header_line[0] == '\r' ||
				    header_line[0] == '\0') {
				  break;
				}
			}
		}

		/* enable SSL transport layer */
		if (stream) {
			if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_ANY_CLIENT, NULL TSRMLS_CC) < 0 ||
			    php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy");
				php_stream_close(stream);
				stream = NULL;
			}
		}
	}

	if (stream == NULL)
		goto out;

	/* avoid buffering issues while reading header */
	if (options & STREAM_WILL_CAST)
		chunk_size = php_stream_set_chunk_size(stream, 1);
	
	/* avoid problems with auto-detecting when reading the headers -> the headers
	 * are always in canonical \r\n format */
	eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);
	stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);

	php_stream_context_set(stream, context TSRMLS_CC);

	php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

	if (header_init && context && php_stream_context_get_option(context, "http", "max_redirects", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_long_ex(tmpzval);
		redirect_max = Z_LVAL_PP(tmpzval);
	}

	if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) {
		if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
			/* As per the RFC, automatically redirected requests MUST NOT use other methods than
			 * GET and HEAD unless it can be confirmed by the user */
			if (!redirected
				|| (Z_STRLEN_PP(tmpzval) == 3 && memcmp("GET", Z_STRVAL_PP(tmpzval), 3) == 0)
				|| (Z_STRLEN_PP(tmpzval) == 4 && memcmp("HEAD",Z_STRVAL_PP(tmpzval), 4) == 0)
			) {
				scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval);
				scratch = emalloc(scratch_len);
				strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1);
				strncat(scratch, " ", 1);
			}
		}
	}
 
	if (context && php_stream_context_get_option(context, "http", "protocol_version", &tmpzval) == SUCCESS) {
		SEPARATE_ZVAL(tmpzval);
		convert_to_double_ex(tmpzval);
		protocol_version_len = spprintf(&protocol_version, 0, "%.1F", Z_DVAL_PP(tmpzval));
	}

	if (!scratch) {
		scratch_len = strlen(path) + 29 + protocol_version_len;
		scratch = emalloc(scratch_len);
		strncpy(scratch, "GET ", scratch_len);
	}

	/* Should we send the entire path in the request line, default to no. */
	if (!request_fulluri &&
		context &&
		php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) {
		zval ztmp = **tmpzval;

		zval_copy_ctor(&ztmp);
		convert_to_boolean(&ztmp);
		request_fulluri = Z_BVAL(ztmp) ? 1 : 0;
		zval_dtor(&ztmp);
	}

	if (request_fulluri) {
		/* Ask for everything */
		strcat(scratch, path);
	} else {
		/* Send the traditional /path/to/file?query_string */

		/* file */
		if (resource->path && *resource->path) {
			strlcat(scratch, resource->path, scratch_len);
		} else {
			strlcat(scratch, "/", scratch_len);
		}

		/* query string */
		if (resource->query) {
			strlcat(scratch, "?", scratch_len);
			strlcat(scratch, resource->query, scratch_len);
		}
	}

	/* protocol version we are speaking */
	if (protocol_version) {
		strlcat(scratch, " HTTP/", scratch_len);
		strlcat(scratch, protocol_version, scratch_len);
		strlcat(scratch, "\r\n", scratch_len);
	} else {
		strlcat(scratch, " HTTP/1.0\r\n", scratch_len);
	}

	/* send it */
	php_stream_write(stream, scratch, strlen(scratch));

	if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS) {
		tmp = NULL;
		
		if (Z_TYPE_PP(tmpzval) == IS_ARRAY) {
			HashPosition pos;
			zval **tmpheader = NULL;
			smart_str tmpstr = {0};

			for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(tmpzval), &pos);
				SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(tmpzval), (void *)&tmpheader, &pos);
				zend_hash_move_forward_ex(Z_ARRVAL_PP(tmpzval), &pos)
			) {
				if (Z_TYPE_PP(tmpheader) == IS_STRING) {
					smart_str_appendl(&tmpstr, Z_STRVAL_PP(tmpheader), Z_STRLEN_PP(tmpheader));
					smart_str_appendl(&tmpstr, "\r\n", sizeof("\r\n") - 1);
				}
			}
			smart_str_0(&tmpstr);
			/* Remove newlines and spaces from start and end. there's at least one extra \r\n at the end that needs to go. */
			if (tmpstr.c) {
				tmp = php_trim(tmpstr.c, strlen(tmpstr.c), NULL, 0, NULL, 3 TSRMLS_CC);
				smart_str_free(&tmpstr);
			}
		}
		if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) {
			/* Remove newlines and spaces from start and end php_trim will estrndup() */
			tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC);
		}
		if (tmp && strlen(tmp) > 0) {
			char *s;

			user_headers = estrdup(tmp);

			/* Make lowercase for easy comparison against 'standard' headers */
			php_strtolower(tmp, strlen(tmp));

			if (!header_init) {
				/* strip POST headers on redirect */
				strip_header(user_headers, tmp, "content-length:");
				strip_header(user_headers, tmp, "content-type:");
			}

			if ((s = strstr(tmp, "user-agent:")) && 
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_USER_AGENT;
			}
			if ((s = strstr(tmp, "host:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_HOST;
			}
			if ((s = strstr(tmp, "from:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_FROM;
				}
			if ((s = strstr(tmp, "authorization:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_AUTH;
			}
			if ((s = strstr(tmp, "content-length:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_CONTENT_LENGTH;
			}
			if ((s = strstr(tmp, "content-type:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_TYPE;
			}
			if ((s = strstr(tmp, "connection:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				 have_header |= HTTP_HEADER_CONNECTION;
			}
			/* remove Proxy-Authorization header */
			if (use_proxy && use_ssl && (s = strstr(tmp, "proxy-authorization:")) &&
			    (s == tmp || *(s-1) == '\r' || *(s-1) == '\n' || 
			                 *(s-1) == '\t' || *(s-1) == ' ')) {
				char *p = s + sizeof("proxy-authorization:") - 1;
				
				while (s > tmp && (*(s-1) == ' ' || *(s-1) == '\t')) s--;
				while (*p != 0 && *p != '\r' && *p != '\n') p++;
				while (*p == '\r' || *p == '\n') p++;
				if (*p == 0) {
					if (s == tmp) {
						efree(user_headers);
						user_headers = NULL;
					} else {
						while (s > tmp && (*(s-1) == '\r' || *(s-1) == '\n')) s--;
						user_headers[s - tmp] = 0;
					}
				} else {
					memmove(user_headers + (s - tmp), user_headers + (p - tmp), strlen(p) + 1);
				}
			}

		}
		if (tmp) {
			efree(tmp);
		}
	}

	/* auth header if it was specified */
	if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user) {
		/* decode the strings first */
		php_url_decode(resource->user, strlen(resource->user));

		/* scratch is large enough, since it was made large enough for the whole URL */
		strcpy(scratch, resource->user);
		strcat(scratch, ":");

		/* Note: password is optional! */
		if (resource->pass) {
			php_url_decode(resource->pass, strlen(resource->pass));
			strcat(scratch, resource->pass);
		}

		tmp = (char*)php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);
		
		if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
			php_stream_write(stream, scratch, strlen(scratch));
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
		}

		efree(tmp);
		tmp = NULL;
	}

	/* if the user has configured who they are, send a From: line */
	if (((have_header & HTTP_HEADER_FROM) == 0) && FG(from_address)) {
		if (snprintf(scratch, scratch_len, "From: %s\r\n", FG(from_address)) > 0)
			php_stream_write(stream, scratch, strlen(scratch));
	}

	/* Send Host: header so name-based virtual hosts work */
	if ((have_header & HTTP_HEADER_HOST) == 0) {
		if ((use_ssl && resource->port != 443 && resource->port != 0) || 
			(!use_ssl && resource->port != 80 && resource->port != 0)) {
			if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0)
				php_stream_write(stream, scratch, strlen(scratch));
		} else {
			if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) {
				php_stream_write(stream, scratch, strlen(scratch));
			}
		}
	}

	/* Send a Connection: close header when using HTTP 1.1 or later to avoid
	 * hanging when the server interprets the RFC literally and establishes a
	 * keep-alive connection, unless the user specifically requests something
	 * else by specifying a Connection header in the context options. */
	if (protocol_version &&
	    ((have_header & HTTP_HEADER_CONNECTION) == 0) &&
	    (strncmp(protocol_version, "1.0", MIN(protocol_version_len, 3)) > 0)) {
		php_stream_write_string(stream, "Connection: close\r\n");
	}

	if (context && 
	    php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS &&
		Z_TYPE_PP(ua_zval) == IS_STRING) {
		ua_str = Z_STRVAL_PP(ua_zval);
	} else if (FG(user_agent)) {
		ua_str = FG(user_agent);
	}

	if (((have_header & HTTP_HEADER_USER_AGENT) == 0) && ua_str) {
#define _UA_HEADER "User-Agent: %s\r\n"
		char *ua;
		size_t ua_len;
		
		ua_len = sizeof(_UA_HEADER) + strlen(ua_str);
		
		/* ensure the header is only sent if user_agent is not blank */
		if (ua_len > sizeof(_UA_HEADER)) {
			ua = emalloc(ua_len + 1);
			if ((ua_len = slprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) {
				ua[ua_len] = 0;
				php_stream_write(stream, ua, ua_len);
			} else {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header");
			}

			if (ua) {
				efree(ua);
			}
		}	
	}

	if (user_headers) {
		/* A bit weird, but some servers require that Content-Length be sent prior to Content-Type for POST
		 * see bug #44603 for details. Since Content-Type maybe part of user's headers we need to do this check first.
		 */
		if (
				header_init &&
				context &&
				!(have_header & HTTP_HEADER_CONTENT_LENGTH) &&
				php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
				Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0
		) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
			have_header |= HTTP_HEADER_CONTENT_LENGTH;
		}

		php_stream_write(stream, user_headers, strlen(user_headers));
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		efree(user_headers);
	}

	/* Request content, such as for POST requests */
	if (header_init && context &&
		php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS &&
		Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
		if (!(have_header & HTTP_HEADER_CONTENT_LENGTH)) {
			scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval));
			php_stream_write(stream, scratch, scratch_len);
		}
		if (!(have_header & HTTP_HEADER_TYPE)) {
			php_stream_write(stream, "Content-Type: application/x-www-form-urlencoded\r\n",
				sizeof("Content-Type: application/x-www-form-urlencoded\r\n") - 1);
			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded");
		}
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
		php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
	} else {
		php_stream_write(stream, "\r\n", sizeof("\r\n")-1);
	}

	location[0] = '\0';

	if (!EG(active_symbol_table)) {
		zend_rebuild_symbol_table(TSRMLS_C);
	}

	if (header_init) {
		zval *ztmp;
		MAKE_STD_ZVAL(ztmp);
		array_init(ztmp);
		ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", ztmp);
	}

	{
		zval **rh;
		zend_hash_find(EG(active_symbol_table), "http_response_header", sizeof("http_response_header"), (void **) &rh);
		response_header = *rh;
	}

	if (!php_stream_eof(stream)) {
		size_t tmp_line_len;
		/* get response header */

		if (php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL) {
			zval *http_response;

			if (tmp_line_len > 9) {
				response_code = atoi(tmp_line + 9);
			} else {
				response_code = 0;
			}
			if (context && SUCCESS==php_stream_context_get_option(context, "http", "ignore_errors", &tmpzval)) {
				ignore_errors = zend_is_true(*tmpzval TSRMLS_CC);
			}
			/* when we request only the header, don't fail even on error codes */
			if ((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) {
				reqok = 1;
			}
			/* all status codes in the 2xx range are defined by the specification as successful;
			 * all status codes in the 3xx range are for redirection, and so also should never
			 * fail */
			if (response_code >= 200 && response_code < 400) {
				reqok = 1;
			} else {
				switch(response_code) {
					case 403:
						php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT,
								tmp_line, response_code);
						break;
					default:
						/* safety net in the event tmp_line == NULL */
						if (!tmp_line_len) {
							tmp_line[0] = '\0';
						}
						php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
								tmp_line, response_code);
				}
			}
			if (tmp_line[tmp_line_len - 1] == '\n') {
				--tmp_line_len;
				if (tmp_line[tmp_line_len - 1] == '\r') {
					--tmp_line_len;
				}
			}
			MAKE_STD_ZVAL(http_response);
			ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1);
			zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL);
		}
	} else {
		php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!");
		goto out;
	}
	
	/* read past HTTP headers */
	
	http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE);

	while (!body && !php_stream_eof(stream)) {
		size_t http_header_line_length;
		if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') {
			char *e = http_header_line + http_header_line_length - 1;
			if (*e != '\n') {
				do { /* partial header */
					if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) == NULL) {
						php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Failed to read HTTP headers");
						goto out;
					}
					e = http_header_line + http_header_line_length - 1;
				} while (*e != '\n');
				continue;
			}
			while (*e == '\n' || *e == '\r') {
				e--;
			}
			http_header_line_length = e - http_header_line + 1;
			http_header_line[http_header_line_length] = '\0';

			if (!strncasecmp(http_header_line, "Location: ", 10)) {
				if (context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
					SEPARATE_ZVAL(tmpzval);
					convert_to_long_ex(tmpzval);
					follow_location = Z_LVAL_PP(tmpzval);
				} else if (!(response_code >= 300 && response_code < 304 || 307 == response_code || 308 == response_code)) {
					/* we shouldn't redirect automatically
					if follow_location isn't set and response_code not in (300, 301, 302, 303 and 307) 
					see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1
					RFC 7238 defines 308: http://tools.ietf.org/html/rfc7238 */
					follow_location = 0;
				}
				strlcpy(location, http_header_line + 10, sizeof(location));
			} else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
				php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
			} else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
				file_size = atoi(http_header_line + 16);
				php_stream_notify_file_size(context, file_size, http_header_line, 0);
			} else if (!strncasecmp(http_header_line, "Transfer-Encoding: chunked", sizeof("Transfer-Encoding: chunked"))) {

				/* create filter to decode response body */
				if (!(options & STREAM_ONLY_GET_HEADERS)) {
					long decode = 1;

					if (context && php_stream_context_get_option(context, "http", "auto_decode", &tmpzval) == SUCCESS) {
						SEPARATE_ZVAL(tmpzval);
						convert_to_boolean(*tmpzval);
						decode = Z_LVAL_PP(tmpzval);
					}
					if (decode) {
						transfer_encoding = php_stream_filter_create("dechunk", NULL, php_stream_is_persistent(stream) TSRMLS_CC);
						if (transfer_encoding) {
							/* don't store transfer-encodeing header */
							continue;
						}
					}
				}
			}

			if (http_header_line[0] == '\0') {
				body = 1;
			} else {
				zval *http_header;

				MAKE_STD_ZVAL(http_header);

				ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1);
				
				zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header, sizeof(zval *), NULL);
			}
		} else {
			break;
		}
	}

	if (!reqok || (location[0] != '\0' && follow_location)) {
		if (!follow_location || (((options & STREAM_ONLY_GET_HEADERS) || ignore_errors) && redirect_max <= 1)) {
			goto out;
		}

		if (location[0] != '\0')
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);

		php_stream_close(stream);
		stream = NULL;

		if (location[0] != '\0') {

			char new_path[HTTP_HEADER_BLOCK_SIZE];
			char loc_path[HTTP_HEADER_BLOCK_SIZE];

			*new_path='\0';
			if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) && 
							strncasecmp(location, "https://", sizeof("https://")-1) && 
							strncasecmp(location, "ftp://", sizeof("ftp://")-1) && 
							strncasecmp(location, "ftps://", sizeof("ftps://")-1))) 
			{
				if (*location != '/') {
					if (*(location+1) != '\0' && resource->path) {
						char *s = strrchr(resource->path, '/');
						if (!s) {
							s = resource->path;
							if (!s[0]) {
								efree(s);
								s = resource->path = estrdup("/");
							} else {
								*s = '/';
							}
						}
						s[1] = '\0'; 
						if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location);
						} else {
							snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location);
						}
					} else {
						snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
					}
				} else {
					strlcpy(loc_path, location, sizeof(loc_path));
				}
				if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path);
				} else {
					snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path);
				}
			} else {
				strlcpy(new_path, location, sizeof(new_path));
			}

			php_url_free(resource);
			/* check for invalid redirection URLs */
			if ((resource = php_url_parse(new_path)) == NULL) {
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path);
				goto out;
			}

#define CHECK_FOR_CNTRL_CHARS(val) { \
	if (val) { \
		unsigned char *s, *e; \
		int l; \
		l = php_url_decode(val, strlen(val)); \
		s = (unsigned char*)val; e = s + l; \
		while (s < e) { \
			if (iscntrl(*s)) { \
				php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path); \
				goto out; \
			} \
			s++; \
		} \
	} \
}
			/* check for control characters in login, password & path */
			if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) {
				CHECK_FOR_CNTRL_CHARS(resource->user)
				CHECK_FOR_CNTRL_CHARS(resource->pass)
				CHECK_FOR_CNTRL_CHARS(resource->path)
			}
			stream = php_stream_url_wrap_http_ex(wrapper, new_path, mode, options, opened_path, context, --redirect_max, HTTP_WRAPPER_REDIRECTED STREAMS_CC TSRMLS_CC);
		} else {
Ejemplo n.º 11
0
 VT get(const V& v) const
 {
   return FG()(v);
 }
Ejemplo n.º 12
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
		const char *path, const char *mode, int options, zend_string **opened_path,
		php_stream_context *context, int redirect_max, int flags STREAMS_DC) /* {{{ */
{
	php_stream *stream = NULL;
	php_url *resource = NULL;
	int use_ssl;
	int use_proxy = 0;
	zend_string *tmp = NULL;
	char *ua_str = NULL;
	zval *ua_zval = NULL, *tmpzval = NULL, ssl_proxy_peer_name;
	int body = 0;
	char location[HTTP_HEADER_BLOCK_SIZE];
	zval response_header;
	int reqok = 0;
	char *http_header_line = NULL;
	char tmp_line[128];
	size_t chunk_size = 0, file_size = 0;
	int eol_detect = 0;
	char *transport_string;
	zend_string *errstr = NULL;
	size_t transport_len;
	int have_header = 0;
	zend_bool request_fulluri = 0, ignore_errors = 0;
	struct timeval timeout;
	char *user_headers = NULL;
	int header_init = ((flags & HTTP_WRAPPER_HEADER_INIT) != 0);
	int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
	zend_bool follow_location = 1;
	php_stream_filter *transfer_encoding = NULL;
	int response_code;
	zend_array *symbol_table;
	smart_str req_buf = {0};
	zend_bool custom_request_method;

	ZVAL_UNDEF(&response_header);
	tmp_line[0] = '\0';

	if (redirect_max < 1) {
		php_stream_wrapper_log_error(wrapper, options, "Redirection limit reached, aborting");
		return NULL;
	}

	resource = php_url_parse(path);
	if (resource == NULL) {
		return NULL;
	}

	if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
		if (!context ||
			(tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "proxy")) == NULL ||
			Z_TYPE_P(tmpzval) != IS_STRING ||
			Z_STRLEN_P(tmpzval) <= 0) {
			php_url_free(resource);
			return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context);
		}
		/* Called from a non-http wrapper with http proxying requested (i.e. ftp) */
		request_fulluri = 1;
		use_ssl = 0;
		use_proxy = 1;

		transport_len = Z_STRLEN_P(tmpzval);
		transport_string = estrndup(Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval));
	} else {
		/* Normal http request (possibly with proxy) */

		if (strpbrk(mode, "awx+")) {
			php_stream_wrapper_log_error(wrapper, options, "HTTP wrapper does not support writeable connections");
			php_url_free(resource);
			return NULL;
		}

		use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';
		/* choose default ports */
		if (use_ssl && resource->port == 0)
			resource->port = 443;
		else if (resource->port == 0)
			resource->port = 80;

		if (context &&
			(tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "proxy")) != NULL &&
			Z_TYPE_P(tmpzval) == IS_STRING &&
			Z_STRLEN_P(tmpzval) > 0) {
			use_proxy = 1;
			transport_len = Z_STRLEN_P(tmpzval);
			transport_string = estrndup(Z_STRVAL_P(tmpzval), Z_STRLEN_P(tmpzval));
		} else {
			transport_len = spprintf(&transport_string, 0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", resource->host, resource->port);
		}
	}

	if (context && (tmpzval = php_stream_context_get_option(context, wrapper->wops->label, "timeout")) != NULL) {
		double d = zval_get_double(tmpzval);
#ifndef PHP_WIN32
		timeout.tv_sec = (time_t) d;
		timeout.tv_usec = (size_t) ((d - timeout.tv_sec) * 1000000);
#else
		timeout.tv_sec = (long) d;
		timeout.tv_usec = (long) ((d - timeout.tv_sec) * 1000000);
#endif
	} else {
#ifndef PHP_WIN32
		timeout.tv_sec = FG(default_socket_timeout);
#else
		timeout.tv_sec = (long)FG(default_socket_timeout);
#endif
		timeout.tv_usec = 0;
	}

	stream = php_stream_xport_create(transport_string, transport_len, options,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT,
			NULL, &timeout, context, &errstr, NULL);

	if (stream) {
		php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &timeout);
	}

	if (errstr) {
		php_stream_wrapper_log_error(wrapper, options, "%s", ZSTR_VAL(errstr));
		zend_string_release(errstr);
		errstr = NULL;
	}

	efree(transport_string);

	if (stream && use_proxy && use_ssl) {
		smart_str header = {0};

		/* Set peer_name or name verification will try to use the proxy server name */
		if (!context || (tmpzval = php_stream_context_get_option(context, "ssl", "peer_name")) == NULL) {
			ZVAL_STRING(&ssl_proxy_peer_name, resource->host);
			php_stream_context_set_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name", &ssl_proxy_peer_name);
			zval_ptr_dtor(&ssl_proxy_peer_name);
		}

		smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1);
		smart_str_appends(&header, resource->host);
		smart_str_appendc(&header, ':');
		smart_str_append_unsigned(&header, resource->port);
		smart_str_appendl(&header, " HTTP/1.0\r\n", sizeof(" HTTP/1.0\r\n")-1);

	    /* check if we have Proxy-Authorization header */
		if (context && (tmpzval = php_stream_context_get_option(context, "http", "header")) != NULL) {
			char *s, *p;

			if (Z_TYPE_P(tmpzval) == IS_ARRAY) {
				zval *tmpheader = NULL;

				ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(tmpzval), tmpheader) {
					if (Z_TYPE_P(tmpheader) == IS_STRING) {
						s = Z_STRVAL_P(tmpheader);
						do {
							while (*s == ' ' || *s == '\t') s++;
							p = s;
							while (*p != 0 && *p != ':' && *p != '\r' && *p !='\n') p++;
							if (*p == ':') {
								p++;
								if (p - s == sizeof("Proxy-Authorization:") - 1 &&
								    zend_binary_strcasecmp(s, sizeof("Proxy-Authorization:") - 1,
								        "Proxy-Authorization:", sizeof("Proxy-Authorization:") - 1) == 0) {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
									smart_str_appendl(&header, s, p - s);
									smart_str_appendl(&header, "\r\n", sizeof("\r\n")-1);
									goto finish;
								} else {
									while (*p != 0 && *p != '\r' && *p !='\n') p++;
								}
							}
							s = p;
							while (*s == '\r' || *s == '\n') s++;
						} while (*s != 0);
					}
				} ZEND_HASH_FOREACH_END();
			} else if (Z_TYPE_P(tmpzval) == IS_STRING && Z_STRLEN_P(tmpzval)) {
Ejemplo n.º 13
0
static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
{
	char *algo, *data, *digest, *key, *K;
	int algo_len, data_len, key_len, i;
	zend_uchar data_type = IS_STRING, key_type = IS_STRING;
	zend_bool raw_output = raw_output_default;
	const php_hash_ops *ops;
	void *context;
	php_stream *stream = NULL;

#if PHP_MAJOR_VERSION >= 6
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "stt|b", &algo, &algo_len, &data, &data_len, &data_type, &key, &key_len, &key_type, &raw_output) == FAILURE) {
		return;
	}

	if (data_type == IS_UNICODE) {
		if (isfilename) {
			if (php_stream_path_encode(NULL, &data, &data_len, (UChar *)data, data_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
				RETURN_FALSE;
			}
		} else {
			data = zend_unicode_to_ascii((UChar*)data, data_len TSRMLS_CC);
			if (!data) {
				/* Non-ASCII Unicode string passed for raw hashing */
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary or ASCII-Unicode string expected, non-ASCII-Unicode string received");
				RETURN_FALSE;
			}
		}
	}
	if (key_type == IS_UNICODE) {
		key = zend_unicode_to_ascii((UChar*)key, key_len TSRMLS_CC);
		if (!key) {
			/* Non-ASCII Unicode key passed for raw hashing */
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary or ASCII-Unicode key expected, non-ASCII-Unicode key received");
			if (data_type == IS_UNICODE) {
				efree(data);
			}
			RETURN_FALSE;
		}
	}
#else
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &algo, &algo_len, &data, &data_len, &key, &key_len, &raw_output) == FAILURE) {
		return;
	}
#endif
	/* Assume failure */
	RETVAL_FALSE;

	ops = php_hash_fetch_ops(algo, algo_len);
	if (!ops) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
		goto hmac_done;
	}
	if (isfilename) {
		stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, DEFAULT_CONTEXT);
		if (!stream) {
			/* Stream will report errors opening file */
			goto hmac_done;
		}
	}

	context = emalloc(ops->context_size);
	ops->hash_init(context);

	K = emalloc(ops->block_size);
	memset(K, 0, ops->block_size);

	if (key_len > ops->block_size) {
		/* Reduce the key first */
		ops->hash_update(context, (unsigned char *) key, key_len);
		ops->hash_final((unsigned char *) K, context);

		/* Make the context ready to start over */
		ops->hash_init(context);
	} else {
		memcpy(K, key, key_len);
	}
			
	/* XOR ipad */
	for(i=0; i < ops->block_size; i++) {
		K[i] ^= 0x36;
	}
	ops->hash_update(context, (unsigned char *) K, ops->block_size);

	if (isfilename) {
		char buf[1024];
		int n;

		while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
			ops->hash_update(context, (unsigned char *) buf, n);
		}
		php_stream_close(stream);
	} else {
		ops->hash_update(context, (unsigned char *) data, data_len);
	}

	digest = emalloc(ops->digest_size + 1);
	ops->hash_final((unsigned char *) digest, context);

	/* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */
	for(i=0; i < ops->block_size; i++) {
		K[i] ^= 0x6A;
	}

	/* Feed this result into the outter hash */
	ops->hash_init(context);
	ops->hash_update(context, (unsigned char *) K, ops->block_size);
	ops->hash_update(context, (unsigned char *) digest, ops->digest_size);
	ops->hash_final((unsigned char *) digest, context);

	/* Zero the key */
	memset(K, 0, ops->block_size);
	efree(K);
	efree(context);

	if (raw_output) {
		digest[ops->digest_size] = 0;

		/* Raw output is binary only */
		RETVAL_STRINGL(digest, ops->digest_size, 0);
	} else {
		char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);

		php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
		hex_digest[2 * ops->digest_size] = 0;
		efree(digest);

		/* hexits can be binary or unicode */
#if PHP_MAJOR_VERSION >= 6
		RETVAL_RT_STRINGL(hex_digest, 2 * ops->digest_size, ZSTR_AUTOFREE);
#else
		RETVAL_STRINGL(hex_digest, 2 * ops->digest_size, 0);
#endif
	}

hmac_done:
	if (data_type != IS_STRING) {
		efree(data);
	}
	if (key_type != IS_STRING) {
		efree(key);
	}
}
Ejemplo n.º 14
0
static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
{
	zend_string *digest;
	char *algo, *data;
	size_t algo_len, data_len;
	zend_bool raw_output = raw_output_default;
	const php_hash_ops *ops;
	void *context;
	php_stream *stream = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &algo, &algo_len, &data, &data_len, &raw_output) == FAILURE) {
		return;
	}

	ops = php_hash_fetch_ops(algo, algo_len);
	if (!ops) {
		php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", algo);
		RETURN_FALSE;
	}
	if (isfilename) {
		if (CHECK_NULL_PATH(data, data_len)) {
			php_error_docref(NULL, E_WARNING, "Invalid path");
			RETURN_FALSE;
		}
		stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, FG(default_context));
		if (!stream) {
			/* Stream will report errors opening file */
			RETURN_FALSE;
		}
	}

	context = emalloc(ops->context_size);
	ops->hash_init(context);

	if (isfilename) {
		char buf[1024];
		size_t n;

		while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
			ops->hash_update(context, (unsigned char *) buf, n);
		}
		php_stream_close(stream);
	} else {
		ops->hash_update(context, (unsigned char *) data, data_len);
	}

	digest = zend_string_alloc(ops->digest_size, 0);
	ops->hash_final((unsigned char *) ZSTR_VAL(digest), context);
	efree(context);

	if (raw_output) {
		ZSTR_VAL(digest)[ops->digest_size] = 0;
		RETURN_NEW_STR(digest);
	} else {
		zend_string *hex_digest = zend_string_safe_alloc(ops->digest_size, 2, 0, 0);

		php_hash_bin2hex(ZSTR_VAL(hex_digest), (unsigned char *) ZSTR_VAL(digest), ops->digest_size);
		ZSTR_VAL(hex_digest)[2 * ops->digest_size] = 0;
		zend_string_release(digest);
		RETURN_NEW_STR(hex_digest);
	}
}
Ejemplo n.º 15
0
static int php_sockop_set_option(php_stream *stream, int option, int value, void *ptrparam)
{
	int oldmode, flags;
	php_netstream_data_t *sock = (php_netstream_data_t*)stream->abstract;
	php_stream_xport_param *xparam;

	if (!sock) {
		return PHP_STREAM_OPTION_RETURN_NOTIMPL;
	}

	switch(option) {
		case PHP_STREAM_OPTION_CHECK_LIVENESS:
			{
				struct timeval tv;
				char buf;
				int alive = 1;

				if (value == -1) {
					if (sock->timeout.tv_sec == -1) {
						tv.tv_sec = FG(default_socket_timeout);
						tv.tv_usec = 0;
					} else {
						tv = sock->timeout;
					}
				} else {
					tv.tv_sec = value;
					tv.tv_usec = 0;
				}

				if (sock->socket == -1) {
					alive = 0;
				} else if (php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) {
#ifdef PHP_WIN32
					int ret;
#else
					ssize_t ret;
#endif
					int err;

					ret = recv(sock->socket, &buf, sizeof(buf), MSG_PEEK);
					err = php_socket_errno();
					if (0 == ret || /* the counterpart did properly shutdown*/
						(0 > ret && err != EWOULDBLOCK && err != EAGAIN)) { /* there was an unrecoverable error */
						alive = 0;
					}
				}
				return alive ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR;
			}

		case PHP_STREAM_OPTION_BLOCKING:
			oldmode = sock->is_blocked;
			if (SUCCESS == php_set_sock_blocking(sock->socket, value)) {
				sock->is_blocked = value;
				return oldmode;
			}
			return PHP_STREAM_OPTION_RETURN_ERR;

		case PHP_STREAM_OPTION_READ_TIMEOUT:
			sock->timeout = *(struct timeval*)ptrparam;
			sock->timeout_event = 0;
			return PHP_STREAM_OPTION_RETURN_OK;

		case PHP_STREAM_OPTION_META_DATA_API:
			add_assoc_bool((zval *)ptrparam, "timed_out", sock->timeout_event);
			add_assoc_bool((zval *)ptrparam, "blocked", sock->is_blocked);
			add_assoc_bool((zval *)ptrparam, "eof", stream->eof);
			return PHP_STREAM_OPTION_RETURN_OK;

		case PHP_STREAM_OPTION_XPORT_API:
			xparam = (php_stream_xport_param *)ptrparam;

			switch (xparam->op) {
				case STREAM_XPORT_OP_LISTEN:
					xparam->outputs.returncode = (listen(sock->socket, xparam->inputs.backlog) == 0) ?  0: -1;
					return PHP_STREAM_OPTION_RETURN_OK;

				case STREAM_XPORT_OP_GET_NAME:
					xparam->outputs.returncode = php_network_get_sock_name(sock->socket,
							xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
							xparam->want_addr ? &xparam->outputs.addr : NULL,
							xparam->want_addr ? &xparam->outputs.addrlen : NULL
							);
					return PHP_STREAM_OPTION_RETURN_OK;

				case STREAM_XPORT_OP_GET_PEER_NAME:
					xparam->outputs.returncode = php_network_get_peer_name(sock->socket,
							xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
							xparam->want_addr ? &xparam->outputs.addr : NULL,
							xparam->want_addr ? &xparam->outputs.addrlen : NULL
							);
					return PHP_STREAM_OPTION_RETURN_OK;

				case STREAM_XPORT_OP_SEND:
					flags = 0;
					if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
						flags |= MSG_OOB;
					}
					xparam->outputs.returncode = sock_sendto(sock,
							xparam->inputs.buf, xparam->inputs.buflen,
							flags,
							xparam->inputs.addr,
							xparam->inputs.addrlen);
					if (xparam->outputs.returncode == -1) {
						char *err = php_socket_strerror(php_socket_errno(), NULL, 0);
						php_error_docref(NULL, E_WARNING,
						   	"%s\n", err);
						efree(err);
					}
					return PHP_STREAM_OPTION_RETURN_OK;

				case STREAM_XPORT_OP_RECV:
					flags = 0;
					if ((xparam->inputs.flags & STREAM_OOB) == STREAM_OOB) {
						flags |= MSG_OOB;
					}
					if ((xparam->inputs.flags & STREAM_PEEK) == STREAM_PEEK) {
						flags |= MSG_PEEK;
					}
					xparam->outputs.returncode = sock_recvfrom(sock,
							xparam->inputs.buf, xparam->inputs.buflen,
							flags,
							xparam->want_textaddr ? &xparam->outputs.textaddr : NULL,
							xparam->want_addr ? &xparam->outputs.addr : NULL,
							xparam->want_addr ? &xparam->outputs.addrlen : NULL
							);
					return PHP_STREAM_OPTION_RETURN_OK;


#ifdef HAVE_SHUTDOWN
# ifndef SHUT_RD
#  define SHUT_RD 0
# endif
# ifndef SHUT_WR
#  define SHUT_WR 1
# endif
# ifndef SHUT_RDWR
#  define SHUT_RDWR 2
# endif
				case STREAM_XPORT_OP_SHUTDOWN: {
					static const int shutdown_how[] = {SHUT_RD, SHUT_WR, SHUT_RDWR};

					xparam->outputs.returncode = shutdown(sock->socket, shutdown_how[xparam->how]);
					return PHP_STREAM_OPTION_RETURN_OK;
				}
#endif

				default:
					return PHP_STREAM_OPTION_RETURN_NOTIMPL;
			}

		default:
			return PHP_STREAM_OPTION_RETURN_NOTIMPL;
	}
}
Ejemplo n.º 16
0
/* TODO:
 *
 * Colorize line types
 *
 * Functional first draft, could use some cleaning up */
static void
draw_buffer(channel *c)
{
	/* Dynamically draw the current channel's buffer such that:
	 *
	 * - The scrollback line should always be drawn in full when possible
	 * - Lines wrap on whitespace when possible
	 * - The top-most lines draws partially when required
	 * - Buffers requiring fewer rows than available draw from the top down
	 *
	 * Rows are numbered from the top down, 1 to w.ws_row, so for w.ws_row = N,
	 * the drawable area for the buffer is bounded [r3, rN-2]:
	 *      __________________________
	 * r1   |     (channel bar)      |
	 * r2   |------------------------|
	 * r3   |    ::buffer start::    |
	 *      |                        |
	 * ...  |                        |
	 *      |                        |
	 * rN-2 |     ::buffer end::     |
	 * rN-1 |------------------------|
	 * rN   |______(input bar) ______|
	 *
	 *
	 * So the general steps for drawing are:
	 *
	 * 1. Starting from line L = scrollback, traverse backwards through the
	 *    buffer summing the rows required to draw lines, until the sum
	 *    exceeds the number of rows available
	 *
	 * 2. L now points to the top-most line to be drawn. L might not be able
	 *    to draw in full, so discard the excessive word-wrapped segments and
	 *    draw the remainder
	 *
	 * 3. Traverse forward through the buffer, drawing lines until buffer_head
	 *    is encountered
	 *
	 * 4. Clear any remaining rows that might exist in the case where the lines
	 *    in the channel's buffer are insufficient to fill all rows
	 */

	printf(CURSOR_SAVE);

	/* Establish current, min and max row for drawing */
	int buffer_start = 3, buffer_end = w.ws_row - 2;
	int print_row = buffer_start;
	int max_row = buffer_end - buffer_start + 1;
	int count_row = 0;

	/* Insufficient rows for drawing */
	if (buffer_end < buffer_start)
		return;

	/* (#terminal columns) - strlen((widest nick in c)) - strlen(" HH:MM   ~ ") */
	int text_cols = w.ws_col - c->draw.nick_pad - 11;

	/* Insufficient columns for drawing */
	if (text_cols < 1)
		goto clear_remainder;

	line *tmp, *l = c->draw.scrollback;


	/* Empty buffer */
	if (l->text == NULL)
		goto clear_remainder;

	/* If the window has been resized, force all cached line rows to be recalculated */
	if (c->resized) {
		for (tmp = c->buffer; tmp < &c->buffer[SCROLLBACK_BUFFER]; tmp++)
			tmp->rows = 0;

		c->resized = 0;
	}

	/* 1. Find top-most drawable line */
	for (;;) {

		/* Store the number of rows until a resize */
		if (l->rows == 0)
			l->rows = count_line_rows(text_cols, l);

		count_row += l->rows;

		if (count_row >= max_row)
			break;

		tmp = (l == c->buffer) ? &c->buffer[SCROLLBACK_BUFFER - 1] : l - 1;

		if (tmp->text == NULL || tmp == c->buffer_head)
			break;

		l = tmp;
	}

	/* 2. Handle top-most line if it can't draw in full */
	if (count_row > max_row) {
		char *ptr1 = l->text;
		char *ptr2 = l->text + l->len;

		while (count_row-- > max_row)
			word_wrap(text_cols, &ptr1, ptr2);

		do {
			printf(MOVE(%d, %d) CLEAR_LINE, print_row++, (int)c->draw.nick_pad + 10);
			printf(FG(239) "~" FG(250) " ");

			char *print = ptr1;
			char *wrap = word_wrap(text_cols, &ptr1, ptr2);

			while (print < wrap)
				putchar(*print++);
		} while (*ptr1);


		if (l == c->buffer_head)
			goto clear_remainder;

		l = (l == &c->buffer[SCROLLBACK_BUFFER - 1]) ? c->buffer : l + 1;

		if (l->text == NULL)
			goto clear_remainder;
	}
Ejemplo n.º 17
0
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
    char *host;
    int host_len;
    long port = -1;
    zval *zerrno = NULL, *zerrstr = NULL;
    double timeout = FG(default_socket_timeout);
    unsigned long conv;
    struct timeval tv;
    char *hashkey = NULL;
    php_stream *stream = NULL;
    int err;
    char *hostname = NULL;
    long hostname_len;
    char *errstr = NULL;

    RETVAL_FALSE;
    
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lzzd", &host, &host_len, &port, &zerrno, &zerrstr, &timeout) == FAILURE) {
        RETURN_FALSE;
    }

    if (persistent) {
        spprintf(&hashkey, 0, "fcgi_sockopen__%s:%ld", host, port);
    }

    if (port > 0) {
        hostname_len = spprintf(&hostname, 0, "%s:%ld", host, port);
    } else {
        hostname_len = host_len;
        hostname = host;
    }
    
    /* prepare the timeout value for use */
    conv = (unsigned long) (timeout * 1000000.0);
    tv.tv_sec = conv / 1000000;
    tv.tv_usec = conv % 1000000;

    if (zerrno) {
        zval_dtor(zerrno);
        ZVAL_LONG(zerrno, 0);
    }
    if (zerrstr) {
        zval_dtor(zerrstr);
        ZVAL_STRING(zerrstr, "", 1);
    }

    stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS,
            STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err);

    if (port > 0) {
        efree(hostname);
    }
    if (stream == NULL) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s:%ld (%s)", host, port, errstr == NULL ? "Unknown error" : errstr);
    }

    if (hashkey) {
        efree(hashkey);
    }
    
    if (stream == NULL) {
        if (zerrno) {
            zval_dtor(zerrno);
            ZVAL_LONG(zerrno, err);
        }
        if (zerrstr && errstr) {
            /* no need to dup; we need to efree buf anyway */
            zval_dtor(zerrstr);
            ZVAL_STRING(zerrstr, errstr, 0);
        }
        else if (!zerrstr && errstr) {
            efree(errstr);
        } 

        RETURN_FALSE;
    }

    if (errstr) {
        efree(errstr);
    }
        
    php_stream_to_zval(stream, return_value);
}
Ejemplo n.º 18
0
static bool graffiti(struct vidbuffer *src, struct vidbuffer *dst)
{
	int y, x;
	int ystart, yend, isntsc;
	int xstart, xend;
	uae_u8 *srcbuf, *srcend;
	uae_u8 *dstbuf;
	bool command, hires, found;
	int xadd, xpixadd, extrapix;
	int waitline = 0, dbl;
	uae_u8 read_mask = 0xff, color = 0, color2 = 0;

	if (!(bplcon0 & 0x0100)) // GAUD
		return false;

	command = true;
	found = false;
	isntsc = (beamcon0 & 0x20) ? 0 : 1;
	if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
		isntsc = currprefs.ntscmode ? 1 : 0;

	dbl = gfxvidinfo.ychange == 1 ? 2 : 1;

	ystart = isntsc ? VBLANK_ENDLINE_NTSC : VBLANK_ENDLINE_PAL;
	yend = isntsc ? MAXVPOS_NTSC : MAXVPOS_PAL;
	if (src->yoffset >= (ystart << VRES_MAX))
		ystart = src->yoffset >> VRES_MAX;

	xadd = gfxvidinfo.xchange == 1 ? src->pixbytes * 2 : src->pixbytes;
	xpixadd = gfxvidinfo.xchange == 1 ? 4 : 2;

	xstart = 0x1c * 2 + 1;
	xend = 0xf0 * 2 + 1;

	srcbuf = src->bufmem + (((ystart << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((xstart << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;
	srcend = src->bufmem + (((yend << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes;
	extrapix = 0;

	dstbuf = dst->bufmem + (((ystart << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * dst->rowbytes + (((xstart << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * dst->pixbytes;

	y = 0;
	while (srcend > srcbuf && dst->bufmemend > dstbuf) {
		uae_u8 *srcp = srcbuf + extrapix;
		uae_u8 *dstp = dstbuf;

		x = xstart;
		while (x < xend) {
			
			uae_u8 mask = 0x80;
			uae_u8 chunky[4] = { 0, 0, 0, 0 };
			while (mask) {
				if (FR(src, srcp)) // R
					chunky[3] |= mask;
				if (FG(src, srcp)) // G
					chunky[2] |= mask;
				if (FB(src, srcp)) // B
					chunky[1] |= mask;
				if (FI(src, srcp)) // I
					chunky[0] |= mask;
				srcp += xadd;
				mask >>= 1;
			}

			if (command) {
				if (chunky[0] || chunky[1] || chunky[2] || chunky[3] || found) {
					for (int pix = 0; pix < 2; pix++) {
						uae_u8 cmd = chunky[pix * 2 + 0];
						uae_u8 parm = chunky[pix * 2 + 1];

#if 0
						//if (cmd != 0)
							write_log(_T("X=%d Y=%d %02x = %02x (%d %d)\n"), x, y, cmd, parm, color, color2);
#endif

						if (automatic && cmd >= 0x40)
							return false;
						if (cmd != 0)
							found = true;
						if (cmd & 8) {
							command = false;
							dbl = 1;
							waitline = 2;
							if (cmd & 16) {
								hires = true;
								xadd /= 2;
								xpixadd /= 2;
								extrapix = -4 * src->pixbytes;
							} else {
								hires = false;
							}
							if (xpixadd == 0) // shres needed
								return false;
							if (monitor != MONITOREMU_GRAFFITI)
								clearmonitor(dst);
						} else if (cmd & 4) {
							if ((cmd & 3) == 1) {
								read_mask = parm;
							} else if ((cmd & 3) == 2) {
								graffiti_palette[color * 4 + color2] = (parm << 2) | (parm & 3);
								color2++;
								if (color2 == 3) {
									color2 = 0;
									color++;
								}
							} else if ((cmd & 3) == 0) {
								color = parm;
								color2 = 0;
							}
						}
					}
				}

				memset(dstp, 0, dst->pixbytes * 4 * 2);
				dstp += dst->pixbytes * 4 * 2;

			} else if (waitline) {
			
				memset(dstp, 0, dst->pixbytes * 4 * 2);
				dstp += dst->pixbytes * 4 * 2;
			
			} else {

				for (int pix = 0; pix < 4; pix++) {
					uae_u8 r, g, b, c;
					
					c = chunky[pix] & read_mask;
					r = graffiti_palette[c * 4 + 0];
					g = graffiti_palette[c * 4 + 1];
					b = graffiti_palette[c * 4 + 2];
					PRGB(dst, dstp, r, g, b);
					dstp += dst->pixbytes;
					PRGB(dst, dstp, r, g, b);
					dstp += dst->pixbytes;
					
					if (gfxvidinfo.xchange == 1 && !hires) {
						PRGB(dst, dstp, r, g, b);
						dstp += dst->pixbytes;
						PRGB(dst, dstp, r, g, b);
						dstp += dst->pixbytes;
					}
				}

			}

			x += xpixadd;
		}

		y++;
		srcbuf += src->rowbytes * dbl;
		dstbuf += dst->rowbytes * dbl;
		if (waitline > 0)
			waitline--;
	}

	dst->nativepositioning = true;

	if (monitor != MONITOREMU_GRAFFITI) {
		monitor = MONITOREMU_GRAFFITI;
		write_log (_T("GRAFFITI %s mode\n"), hires ? _T("hires") : _T("lores"));
	}

	return true;
}
Ejemplo n.º 19
0
static bool a2024(struct vidbuffer *src, struct vidbuffer *dst)
{
	int y;
	uae_u8 *srcbuf, *dstbuf;
	uae_u8 *dataline;
	int px, py, doff, pxcnt, dbl;
	int panel_width, panel_width_draw, panel_height, srcxoffset;
	bool f64, interlace, expand, wpb, less16;
	uae_u8 enp, dpl;
	bool hires, ntsc, found;
	int idline;
	int total_width, total_height;
	
	dbl = gfxvidinfo.ychange == 1 ? 2 : 1;
	doff = (128 * 2 / gfxvidinfo.xchange) * src->pixbytes;
	found = false;

	for (idline = 21; idline <= 29; idline += 8) {
		if (src->yoffset > (idline << VRES_MAX))
			continue;
		// min 178 max 234
		dataline = src->bufmem + (((idline << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((200 << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;

#if 0
		write_log (_T("%02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x\n"),
			dataline[0 * doff + 0], dataline[0 * doff + 1], dataline[0 * doff + 2],
			dataline[1 * doff + 0], dataline[1 * doff + 1], dataline[1 * doff + 2],
			dataline[2 * doff + 0], dataline[2 * doff + 1], dataline[2 * doff + 2],
			dataline[3 * doff + 0], dataline[3 * doff + 1], dataline[3 * doff + 2]);
#endif

		if (FB(src, &dataline[0 * doff]))			// 0:B = 0
			continue;
		if (!FI(src, &dataline[0 * doff]))			// 0:I = 1
			continue;
		if (FI(src, &dataline[2 * doff]))			// 2:I = 0
			continue;
		if (!FI(src, &dataline[3 * doff]))			// 3:I = 1
			continue;

		ntsc = idline < 26;
		found = true;
		break;
	}

	if (!found)
		return false;

	px = py = 0;
	if (FB(src, &dataline[1 * doff])) // 1:B FN2
		px |= 2;
	if (FG(src, &dataline[1 * doff])) // 1:G FN1
		px |= 1;
	if (FR(src, &dataline[1 * doff])) // 1:R FN0
		py |= 1;

	f64 = FR(src, &dataline[0 * doff]) != 0;		// 0:R
	interlace = FG(src, &dataline[0 * doff]) != 0;	// 0:G (*Always zero)
	expand = FI(src, &dataline[1 * doff]) != 0;		// 1:I (*Always set)
	enp = FR(src, &dataline[2 * doff]) ? 1 : 0;		// 2:R (*ENP=3)
	enp |= FG(src, &dataline[2 * doff]) ? 2 : 0;	// 2:G
	wpb = FB(src, &dataline[2 * doff]) != 0;		// 2:B (*Always zero)
	dpl = FR(src, &dataline[3 * doff]) ? 1 : 0;		// 3:R (*DPL=3)
	dpl |= FG(src, &dataline[3 * doff]) ? 2 : 0;	// 3:G
	less16 = FB(src, &dataline[3 * doff]) != 0;		// 3:B

	/* (*) = AOS A2024 driver static bits. Not yet implemented in emulation. */

	if (f64) {
		panel_width = 336;
		panel_width_draw = px == 2 ? 352 : 336;
		pxcnt = 3;
		hires = false;
		srcxoffset = 113;
		if (px > 2)
			return false;
		total_width = 336 + 336 + 352;
	} else {
		panel_width = 512;
		panel_width_draw = 512;
		pxcnt = 2;
		hires = true;
		srcxoffset = 129;
		if (px > 1)
			return false;
		total_width = 512 + 512;
	}
	panel_height = ntsc ? 400 : 512;

	if (monitor != MONITOREMU_A2024) {
		clearmonitor(dst);
	}

#if 0
	write_log (_T("0 = F6-4:%d INTERLACE:%d\n"), f64, interlace);
	write_log (_T("1 = FN:%d EXPAND:%d\n"), py + px *2, expand);
	write_log (_T("2 = ENP:%d WPB=%d\n"), enp, wpb);
	write_log (_T("3 = DPL:%d LESS16=%d\n"), dpl, less16);
#endif
#if 0
	write_log (_T("%02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %dx%d\n"),
		dataline[0 * doff + 0], dataline[0 * doff + 1], dataline[0 * doff + 2],
		dataline[1 * doff + 0], dataline[1 * doff + 1], dataline[1 * doff + 2],
		dataline[2 * doff + 0], dataline[2 * doff + 1], dataline[2 * doff + 2],
		dataline[3 * doff + 0], dataline[3 * doff + 1], dataline[3 * doff + 2],
		px, py);
#endif

	if (less16) {
		total_width -= 16;
		if (px == pxcnt - 1)
			panel_width_draw -= 16;
	}
	total_height = panel_height * dbl;
	
	srcbuf = src->bufmem + (((44 << VRES_MAX) - src->yoffset) / gfxvidinfo.ychange) * src->rowbytes + (((srcxoffset << RES_MAX) - src->xoffset) / gfxvidinfo.xchange) * src->pixbytes;
	dstbuf = dst->bufmem + py * (panel_height / gfxvidinfo.ychange) * dst->rowbytes + px * ((panel_width * 2) / gfxvidinfo.xchange) * dst->pixbytes;

	for (y = 0; y < (panel_height / (dbl == 1 ? 1 : 2)) / gfxvidinfo.ychange; y++) {
#if 0
		memcpy (dstbuf, srcbuf, ((panel_width * 2) / gfxvidinfo.xchange) * dst->pixbytes);
#else
		uae_u8 *srcp = srcbuf;
		uae_u8 *dstp1 = dstbuf;
		uae_u8 *dstp2 = dstbuf + dst->rowbytes;
		int x;
		for (x = 0; x < (panel_width_draw * 2) / gfxvidinfo.xchange; x++) {
			uae_u8 c1 = 0, c2 = 0;
			if (FR(src, srcp)) // R
				c1 |= 2;
			if (FG(src, srcp)) // G
				c2 |= 2;
			if (FB(src, srcp)) // B
				c1 |= 1;
			if (FI(src, srcp)) // I
				c2 |= 1;
			if (dpl == 0) {
				c1 = c2 = 0;
			} else if (dpl == 1) {
				c1 &= 1;
				c1 |= c1 << 1;
				c2 &= 1;
				c2 |= c2 << 1;
			} else if (dpl == 2) {
				c1 &= 2;
				c1 |= c1 >> 1;
				c2 &= 2;
				c2 |= c2 >> 1;
			}
			if (dbl == 1) {
				c1 = (c1 + c2 + 1) / 2;
				c1 = (c1 << 6) | (c1 << 4) | (c1 << 2) | (c1 << 0);
				PRGB(dst, dstp1, c1, c1, c1);
			} else {
				c1 = (c1 << 6) | (c1 << 4) | (c1 << 2) | (c1 << 0);
				c2 = (c2 << 6) | (c2 << 4) | (c2 << 2) | (c2 << 0);
				PRGB(dst, dstp1, c1, c1, c1);
				PRGB(dst, dstp2, c2, c2, c2);
				dstp2 += dst->pixbytes;
			}
			srcp += src->pixbytes;
			if (!hires)
				srcp += src->pixbytes;
			dstp1 += dst->pixbytes;
		}
#endif
		srcbuf += src->rowbytes * dbl;
		dstbuf += dst->rowbytes * dbl;
	}
Ejemplo n.º 20
0
		int flags, const char *persistent_id,
		struct timeval *timeout,
		php_stream_context *context,
		zend_string **error_string,
		int *error_code
		STREAMS_DC)
{
	php_stream *stream = NULL;
	php_stream_transport_factory factory = NULL;
	const char *p, *protocol = NULL;
	size_t n = 0;
	int failed = 0;
	zend_string *error_text = NULL;
	struct timeval default_timeout = { 0, 0 };

	default_timeout.tv_sec = FG(default_socket_timeout);

	if (timeout == NULL) {
		timeout = &default_timeout;
	}

	/* check for a cached persistent socket */
	if (persistent_id) {
		switch(php_stream_from_persistent_id(persistent_id, &stream)) {
			case PHP_STREAM_PERSISTENT_SUCCESS:
				/* use a 0 second timeout when checking if the socket
				 * has already died */
				if (PHP_STREAM_OPTION_RETURN_OK == php_stream_set_option(stream, PHP_STREAM_OPTION_CHECK_LIVENESS, 0, NULL)) {
					return stream;
				}
				/* dead - kill it */
Ejemplo n.º 21
0
static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
{
	char *algo, *data, *digest;
	int algo_len, data_len;
	zend_uchar data_type = IS_STRING;
	zend_bool raw_output = raw_output_default;
	const php_hash_ops *ops;
	void *context;
	php_stream *stream = NULL;

#if PHP_MAJOR_VERSION >= 6
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "st|b", &algo, &algo_len, &data, &data_len, &data_type, &raw_output) == FAILURE) {
		return;
	}

	if (data_type == IS_UNICODE) {
		if (isfilename) {
			if (php_stream_path_encode(NULL, &data, &data_len, (UChar *)data, data_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
				RETURN_FALSE;
			}
		} else {
			data = zend_unicode_to_ascii((UChar*)data, data_len TSRMLS_CC);
			if (!data) {
				/* Non-ASCII Unicode string passed for raw hashing */
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "Binary or ASCII-Unicode string expected, non-ASCII-Unicode string received");
				RETURN_FALSE;
			}
		}
	}
#else
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|b", &algo, &algo_len, &data, &data_len, &raw_output) == FAILURE) {
		return;
	}
#endif
	/* Assume failure */
	RETVAL_FALSE;

	ops = php_hash_fetch_ops(algo, algo_len);
	if (!ops) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo);
		goto hash_done;
	}
	if (isfilename) {
		stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, DEFAULT_CONTEXT);
		if (!stream) {
			/* Stream will report errors opening file */
			goto hash_done;
		}
	}

	context = emalloc(ops->context_size);
	ops->hash_init(context);

	if (isfilename) {
		char buf[1024];
		int n;

		while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
			ops->hash_update(context, (unsigned char *) buf, n);
		}
		php_stream_close(stream);
	} else {
		ops->hash_update(context, (unsigned char *) data, data_len);
	}

	digest = emalloc(ops->digest_size + 1);
	ops->hash_final((unsigned char *) digest, context);
	efree(context);

	if (raw_output) {
		digest[ops->digest_size] = 0;

		/* Raw output is binary only */
		RETVAL_STRINGL(digest, ops->digest_size, 0);
	} else {
		char *hex_digest = safe_emalloc(ops->digest_size, 2, 1);

		php_hash_bin2hex(hex_digest, (unsigned char *) digest, ops->digest_size);
		hex_digest[2 * ops->digest_size] = 0;
		efree(digest);

		/* hexits can be binary or unicode */
#if PHP_MAJOR_VERSION >= 6
		RETVAL_RT_STRINGL(hex_digest, 2 * ops->digest_size, ZSTR_AUTOFREE);
#else
		RETVAL_STRINGL(hex_digest, 2 * ops->digest_size, 0);
#endif
	}

hash_done:
	if (data_type != IS_STRING) {
		efree(data);
	}
}
Ejemplo n.º 22
0
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
	char *host;
	size_t host_len;
	zend_long port = -1;
	zval *zerrno = NULL, *zerrstr = NULL;
	double timeout = (double)FG(default_socket_timeout);
#ifndef PHP_WIN32
	time_t conv;
#else
	long conv;
#endif
	struct timeval tv;
	char *hashkey = NULL;
	php_stream *stream = NULL;
	int err;
	char *hostname = NULL;
	size_t hostname_len;
	zend_string *errstr = NULL;

	RETVAL_FALSE;

	ZEND_PARSE_PARAMETERS_START(1, 5)
		Z_PARAM_STRING(host, host_len)
		Z_PARAM_OPTIONAL
		Z_PARAM_LONG(port)
		Z_PARAM_ZVAL(zerrno)
		Z_PARAM_ZVAL(zerrstr)
		Z_PARAM_DOUBLE(timeout)
	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

	if (persistent) {
		spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port);
	}

	if (port > 0) {
		hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port);
	} else {
		hostname_len = host_len;
		hostname = host;
	}

	/* prepare the timeout value for use */
#ifndef PHP_WIN32
	conv = (time_t) (timeout * 1000000.0);
	tv.tv_sec = conv / 1000000;
#else
	conv = (long) (timeout * 1000000.0);
	tv.tv_sec = conv / 1000000;
#endif
	tv.tv_usec = conv % 1000000;

	stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS,
			STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err);

	if (port > 0) {
		efree(hostname);
	}
	if (stream == NULL) {
		php_error_docref(NULL, E_WARNING, "unable to connect to %s:" ZEND_LONG_FMT " (%s)", host, port, errstr == NULL ? "Unknown error" : ZSTR_VAL(errstr));
	}

	if (hashkey) {
		efree(hashkey);
	}

	if (stream == NULL) {
		if (zerrno) {
			ZEND_TRY_ASSIGN_LONG(zerrno, err);
		}
		if (errstr) {
			if (zerrstr) {
				ZEND_TRY_ASSIGN_STR(zerrstr, errstr);
			} else {
				zend_string_release(errstr);
			}
		}

		RETURN_FALSE;
	}

	if (zerrno) {
		ZEND_TRY_ASSIGN_LONG(zerrno, 0);
	}
	if (zerrstr) {
		ZEND_TRY_ASSIGN_EMPTY_STRING(zerrstr);
	}

	if (errstr) {
		zend_string_release_ex(errstr, 0);
	}

	php_stream_to_zval(stream, return_value);
}
Ejemplo n.º 23
0
Archivo: filter.c Proyecto: 899/php-src
/* Normal hash selection/retrieval call */
PHPAPI HashTable *_php_get_stream_filters_hash(TSRMLS_D)
{
	return (FG(stream_filters) ? FG(stream_filters) : &stream_filters_hash);
}
Ejemplo n.º 24
0
/* Hash a single block, 64 bytes long and 4-byte aligned. */
static void md5_hash_block(const void *buffer, md5_ctx_t *ctx)
{
	uint32_t correct_words[16];
	const uint32_t *words = buffer;

# if MD5_SIZE_VS_SPEED > 0
	static const uint32_t C_array[] = {
		/* round 1 */
		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
		/* round 2 */
		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
		0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
		/* round 3 */
		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
		/* round 4 */
		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
	};

	static const char P_array[] ALIGN1 = {
#  if MD5_SIZE_VS_SPEED > 1
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,	/* 1 */
#  endif	/* MD5_SIZE_VS_SPEED > 1 */
		1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,	/* 2 */
		5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,	/* 3 */
		0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9	/* 4 */
	};

#  if MD5_SIZE_VS_SPEED > 1
	static const char S_array[] ALIGN1 = {
		7, 12, 17, 22,
		5, 9, 14, 20,
		4, 11, 16, 23,
		6, 10, 15, 21
	};
#  endif	/* MD5_SIZE_VS_SPEED > 1 */
# endif

	uint32_t A = ctx->A;
	uint32_t B = ctx->B;
	uint32_t C = ctx->C;
	uint32_t D = ctx->D;

	/* Process all bytes in the buffer with 64 bytes in each round of
	   the loop.  */
		uint32_t *cwp = correct_words;
		uint32_t A_save = A;
		uint32_t B_save = B;
		uint32_t C_save = C;
		uint32_t D_save = D;

# if MD5_SIZE_VS_SPEED > 1
#  define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))

		const uint32_t *pc;
		const char *pp;
		const char *ps;
		int i;
		uint32_t temp;

		for (i = 0; i < 16; i++) {
			cwp[i] = SWAP_LE32(words[i]);
		}
		words += 16;

#  if MD5_SIZE_VS_SPEED > 2
		pc = C_array;
		pp = P_array;
		ps = S_array - 4;

		for (i = 0; i < 64; i++) {
			if ((i & 0x0f) == 0)
				ps += 4;
			temp = A;
			switch (i >> 4) {
			case 0:
				temp += FF(B, C, D);
				break;
			case 1:
				temp += FG(B, C, D);
				break;
			case 2:
				temp += FH(B, C, D);
				break;
			case 3:
				temp += FI(B, C, D);
			}
			temp += cwp[(int) (*pp++)] + *pc++;
			CYCLIC(temp, ps[i & 3]);
			temp += B;
			A = D;
			D = C;
			C = B;
			B = temp;
		}
#  else
		pc = C_array;
		pp = P_array;
		ps = S_array;

		for (i = 0; i < 16; i++) {
			temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++;
			CYCLIC(temp, ps[i & 3]);
			temp += B;
			A = D;
			D = C;
			C = B;
			B = temp;
		}

		ps += 4;
		for (i = 0; i < 16; i++) {
			temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++;
			CYCLIC(temp, ps[i & 3]);
			temp += B;
			A = D;
			D = C;
			C = B;
			B = temp;
		}
		ps += 4;
		for (i = 0; i < 16; i++) {
			temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++;
			CYCLIC(temp, ps[i & 3]);
			temp += B;
			A = D;
			D = C;
			C = B;
			B = temp;
		}
		ps += 4;
		for (i = 0; i < 16; i++) {
			temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++;
			CYCLIC(temp, ps[i & 3]);
			temp += B;
			A = D;
			D = C;
			C = B;
			B = temp;
		}

#  endif	/* MD5_SIZE_VS_SPEED > 2 */
# else
		/* First round: using the given function, the context and a constant
		   the next context is computed.  Because the algorithms processing
		   unit is a 32-bit word and it is determined to work on words in
		   little endian byte order we perhaps have to change the byte order
		   before the computation.  To reduce the work for the next steps
		   we store the swapped words in the array CORRECT_WORDS.  */

#  define OP(a, b, c, d, s, T) \
	do { \
		a += FF (b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \
		++words; \
		CYCLIC (a, s); \
		a += b; \
	} while (0)

		/* It is unfortunate that C does not provide an operator for
		   cyclic rotation.  Hope the C compiler is smart enough.  */
		/* gcc 2.95.4 seems to be --aaronl */
#  define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))

		/* Before we start, one word to the strange constants.
		   They are defined in RFC 1321 as

		   T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
		 */

#  if MD5_SIZE_VS_SPEED == 1
		const uint32_t *pc;
		const char *pp;
		int i;
#  endif	/* MD5_SIZE_VS_SPEED */

		/* Round 1.  */
#  if MD5_SIZE_VS_SPEED == 1
		pc = C_array;
		for (i = 0; i < 4; i++) {
			OP(A, B, C, D, 7, *pc++);
			OP(D, A, B, C, 12, *pc++);
			OP(C, D, A, B, 17, *pc++);
			OP(B, C, D, A, 22, *pc++);
		}
#  else
		OP(A, B, C, D, 7, 0xd76aa478);
		OP(D, A, B, C, 12, 0xe8c7b756);
		OP(C, D, A, B, 17, 0x242070db);
		OP(B, C, D, A, 22, 0xc1bdceee);
		OP(A, B, C, D, 7, 0xf57c0faf);
		OP(D, A, B, C, 12, 0x4787c62a);
		OP(C, D, A, B, 17, 0xa8304613);
		OP(B, C, D, A, 22, 0xfd469501);
		OP(A, B, C, D, 7, 0x698098d8);
		OP(D, A, B, C, 12, 0x8b44f7af);
		OP(C, D, A, B, 17, 0xffff5bb1);
		OP(B, C, D, A, 22, 0x895cd7be);
		OP(A, B, C, D, 7, 0x6b901122);
		OP(D, A, B, C, 12, 0xfd987193);
		OP(C, D, A, B, 17, 0xa679438e);
		OP(B, C, D, A, 22, 0x49b40821);
#  endif	/* MD5_SIZE_VS_SPEED == 1 */

		/* For the second to fourth round we have the possibly swapped words
		   in CORRECT_WORDS.  Redefine the macro to take an additional first
		   argument specifying the function to use.  */
#  undef OP
#  define OP(f, a, b, c, d, k, s, T) \
	do { \
		a += f (b, c, d) + correct_words[k] + T; \
		CYCLIC (a, s); \
		a += b; \
	} while (0)

		/* Round 2.  */
#  if MD5_SIZE_VS_SPEED == 1
		pp = P_array;
		for (i = 0; i < 4; i++) {
			OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
			OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++);
			OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++);
			OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++);
		}
#  else
		OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
		OP(FG, D, A, B, C, 6, 9, 0xc040b340);
		OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
		OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
		OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
		OP(FG, D, A, B, C, 10, 9, 0x02441453);
		OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
		OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
		OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
		OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
		OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
		OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
		OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
		OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
		OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
		OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
#  endif	/* MD5_SIZE_VS_SPEED == 1 */

		/* Round 3.  */
#  if MD5_SIZE_VS_SPEED == 1
		for (i = 0; i < 4; i++) {
			OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
			OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
			OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++);
			OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++);
		}
#  else
		OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
		OP(FH, D, A, B, C, 8, 11, 0x8771f681);
		OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
		OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
		OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
		OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
		OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
		OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
		OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
		OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
		OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
		OP(FH, B, C, D, A, 6, 23, 0x04881d05);
		OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
		OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
		OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
		OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
#  endif	/* MD5_SIZE_VS_SPEED == 1 */

		/* Round 4.  */
#  if MD5_SIZE_VS_SPEED == 1
		for (i = 0; i < 4; i++) {
			OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
			OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
			OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++);
			OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++);
		}
#  else
		OP(FI, A, B, C, D, 0, 6, 0xf4292244);
		OP(FI, D, A, B, C, 7, 10, 0x432aff97);
		OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
		OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
		OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
		OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
		OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
		OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
		OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
		OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
		OP(FI, C, D, A, B, 6, 15, 0xa3014314);
		OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
		OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
		OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
		OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
		OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
#  endif	/* MD5_SIZE_VS_SPEED == 1 */
# endif	/* MD5_SIZE_VS_SPEED > 1 */

		/* Add the starting values of the context.  */
		A += A_save;
		B += B_save;
		C += C_save;
		D += D_save;

	/* Put checksum in context given as argument.  */
	ctx->A = A;
	ctx->B = B;
	ctx->C = C;
	ctx->D = D;
}
Ejemplo n.º 25
0
	ret = (php_stream*) pemalloc(sizeof(php_stream), persistent_id ? 1 : 0);

	memset(ret, 0, sizeof(php_stream));

	ret->readfilters.stream = ret;
	ret->writefilters.stream = ret;

#if STREAM_DEBUG
fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persistent_id);
#endif

	ret->ops = ops;
	ret->abstract = abstract;
	ret->is_persistent = persistent_id ? 1 : 0;
	ret->chunk_size = FG(def_chunk_size);

	if (FG(auto_detect_line_endings)) {
		ret->flags |= PHP_STREAM_FLAG_DETECT_EOL;
	}

	if (persistent_id) {
		zend_rsrc_list_entry le;

		le.type = le_pstream;
		le.ptr = ret;
		le.refcount = 0;

		if (FAILURE == zend_hash_update(&EG(persistent_list), (char *)persistent_id,
					strlen(persistent_id) + 1,
					(void *)&le, sizeof(le), NULL)) {
Ejemplo n.º 26
0
/* {{{ php_ftp_fopen_connect
 */
static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char *path, const char *mode, int options,
										 char **opened_path, php_stream_context *context, php_stream **preuseid,
										 php_url **presource, int *puse_ssl, int *puse_ssl_on_data)
{
	php_stream *stream = NULL, *reuseid = NULL;
	php_url *resource = NULL;
	int result, use_ssl, use_ssl_on_data = 0, tmp_len;
	char tmp_line[512];
	char *transport;
	int transport_len;

	resource = php_url_parse(path);
	if (resource == NULL || resource->path == NULL) {
		if (resource && presource) {
			*presource = resource;
		}
		return NULL;
	}

	use_ssl = resource->scheme && (strlen(resource->scheme) > 3) && resource->scheme[3] == 's';

	/* use port 21 if one wasn't specified */
	if (resource->port == 0)
		resource->port = 21;
	
	transport_len = (int)spprintf(&transport, 0, "tcp://%s:%d", resource->host, resource->port);
	stream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL);
	efree(transport);
	if (stream == NULL) {
		result = 0; /* silence */
		goto connect_errexit;
	}

	php_stream_context_set(stream, context);
	php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

	/* Start talking to ftp server */
	result = GET_FTP_RESULT(stream);
	if (result > 299 || result < 200) {
		php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, result);
		goto connect_errexit;
	}

	if (use_ssl)	{
	
		/* send the AUTH TLS request name */
		php_stream_write_string(stream, "AUTH TLS\r\n");

		/* get the response */
		result = GET_FTP_RESULT(stream);
		if (result != 234) {
			/* AUTH TLS not supported try AUTH SSL */
			php_stream_write_string(stream, "AUTH SSL\r\n");
			
			/* get the response */
			result = GET_FTP_RESULT(stream);
			if (result != 334) {
				use_ssl = 0;
			} else {
				/* we must reuse the old SSL session id */
				/* if we talk to an old ftpd-ssl */
				reuseid = stream;
			}
		} else {
			/* encrypt data etc */


		}

	}
	
	if (use_ssl) {
		if (php_stream_xport_crypto_setup(stream,
				STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0
				|| php_stream_xport_crypto_enable(stream, 1) < 0) {
			php_stream_wrapper_log_error(wrapper, options, "Unable to activate SSL mode");
			php_stream_close(stream);
			stream = NULL;
			goto connect_errexit;
		}
	
		/* set PBSZ to 0 */
		php_stream_write_string(stream, "PBSZ 0\r\n");

		/* ignore the response */
		result = GET_FTP_RESULT(stream);
		
		/* set data connection protection level */
#if FTPS_ENCRYPT_DATA
		php_stream_write_string(stream, "PROT P\r\n");

		/* get the response */
		result = GET_FTP_RESULT(stream);
		use_ssl_on_data = (result >= 200 && result<=299) || reuseid;
#else
		php_stream_write_string(stream, "PROT C\r\n");

		/* get the response */
		result = GET_FTP_RESULT(stream);
#endif
	}

#define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) {	\
	unsigned char *s = val, *e = s + val_len;	\
	while (s < e) {	\
		if (iscntrl(*s)) {	\
			php_stream_wrapper_log_error(wrapper, options, err_msg, val);	\
			goto connect_errexit;	\
		}	\
		s++;	\
	}	\
} 

	/* send the user name */
	if (resource->user != NULL) {
		tmp_len = (int)php_raw_url_decode(resource->user, (int)strlen(resource->user));

		PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s")

		php_stream_printf(stream, "USER %s\r\n", resource->user);
	} else {
		php_stream_write_string(stream, "USER anonymous\r\n");
	}
	
	/* get the response */
	result = GET_FTP_RESULT(stream);
	
	/* if a password is required, send it */
	if (result >= 300 && result <= 399) {
		php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0);

		if (resource->pass != NULL) {
			tmp_len = (int)php_raw_url_decode(resource->pass, (int)strlen(resource->pass));

			PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s")

			php_stream_printf(stream, "PASS %s\r\n", resource->pass);
		} else {
			/* if the user has configured who they are,
			   send that as the password */
			if (FG(from_address)) {
				php_stream_printf(stream, "PASS %s\r\n", FG(from_address));
			} else {
				php_stream_write_string(stream, "PASS anonymous\r\n");
			}
		}

		/* read the response */
		result = GET_FTP_RESULT(stream);

		if (result > 299 || result < 200) {
			php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
		} else {
			php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, result);
		}
	}
	if (result > 299 || result < 200) {
		goto connect_errexit;
	}

	if (puse_ssl) {
		*puse_ssl = use_ssl;
	}
	if (puse_ssl_on_data) {
		*puse_ssl_on_data = use_ssl_on_data;
	}
	if (preuseid) {
		*preuseid = reuseid;
	}
	if (presource) {
		*presource = resource;
	}

	return stream;

connect_errexit:
	if (resource) {
		php_url_free(resource);	
	}

	if (stream) {
		php_stream_close(stream);
	}

	return NULL;
}
Ejemplo n.º 27
0
static void md5_process_block64(md5_ctx_t *ctx)
{

	/* Before we start, one word to the strange constants.
	   They are defined in RFC 1321 as
	   T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
	 */
	static const uint32_t C_array[] = {
		/* round 1 */
		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
		/* round 2 */
		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
		0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
		/* round 3 */
		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
		/* round 4 */
		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
	};
	static const char P_array[] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
		1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
		5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */
		0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9  /* 4 */
	};

	uint32_t *words = (void*) ctx->wbuffer;
	uint32_t A = ctx->hash[0];
	uint32_t B = ctx->hash[1];
	uint32_t C = ctx->hash[2];
	uint32_t D = ctx->hash[3];

 /* 2 or 3 */

	static const char S_array[] = {
		7, 12, 17, 22,
		5, 9, 14, 20,
		4, 11, 16, 23,
		6, 10, 15, 21
	};
	const uint32_t *pc;
	const char *pp;
	const char *ps;
	int i;
	uint32_t temp;

 /* MD5_SIZE_VS_SPEED == 2 */
	pc = C_array;
	pp = P_array;
	ps = S_array;

	for (i = 0; i < 16; i++) {
		temp = A + FF(B, C, D) + words[(int) (*pp++)] + *pc++;
		temp = rotl32(temp, ps[i & 3]);
		temp += B;
		A = D;
		D = C;
		C = B;
		B = temp;
	}
	ps += 4;
	for (i = 0; i < 16; i++) {
		temp = A + FG(B, C, D) + words[(int) (*pp++)] + *pc++;
		temp = rotl32(temp, ps[i & 3]);
		temp += B;
		A = D;
		D = C;
		C = B;
		B = temp;
	}
	ps += 4;
	for (i = 0; i < 16; i++) {
		temp = A + FH(B, C, D) + words[(int) (*pp++)] + *pc++;
		temp = rotl32(temp, ps[i & 3]);
		temp += B;
		A = D;
		D = C;
		C = B;
		B = temp;
	}
	ps += 4;
	for (i = 0; i < 16; i++) {
		temp = A + FI(B, C, D) + words[(int) (*pp++)] + *pc++;
		temp = rotl32(temp, ps[i & 3]);
		temp += B;
		A = D;
		D = C;
		C = B;
		B = temp;
	}

	/* Add checksum to the starting values */
	ctx->hash[0] += A;
	ctx->hash[1] += B;
	ctx->hash[2] += C;
	ctx->hash[3] += D;

}
Ejemplo n.º 28
0
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
{
	char *host;
	int host_len;
	long port = -1;
	zval *zerrno = NULL, *zerrstr = NULL, *zcontext = NULL;
	double timeout = FG(default_socket_timeout);
	unsigned long conv;
	struct timeval tv;
	char *hashkey = NULL;
	php_stream *stream = NULL;
	php_stream_context *context = NULL;
	int err;

	RETVAL_FALSE;
	
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lzzdr", &host, &host_len, &port, &zerrno, &zerrstr, &timeout, &zcontext) == FAILURE) {
		RETURN_FALSE;
	}
	if (zcontext) {
		ZEND_FETCH_RESOURCE(context, php_stream_context*, &zcontext, -1, "stream-context", php_le_stream_context());
	}

	if (persistent) {
		spprintf(&hashkey, 0, "pfsockopen__%s:%ld", host, port);

		switch(php_stream_from_persistent_id(hashkey, &stream TSRMLS_CC)) {
			case PHP_STREAM_PERSISTENT_SUCCESS:
				if (_php_network_is_stream_alive(stream TSRMLS_CC)) {
					php_stream_to_zval(stream, return_value);
				} else {
					/* it died; we need to replace it */
					php_stream_pclose(stream);
					break;
				}
				
				/* fall through */
			case PHP_STREAM_PERSISTENT_FAILURE:
				efree(hashkey);
				return;
		}
	}

	/* prepare the timeout value for use */
	conv = (unsigned long) (timeout * 1000000.0);
	tv.tv_sec = conv / 1000000;
	tv.tv_usec = conv % 1000000;

	if (zerrno)	{
		zval_dtor(zerrno);
		ZVAL_LONG(zerrno, 0);
	}
	if (zerrstr) {
		zval_dtor(zerrstr);
		ZVAL_STRING(zerrstr, "", 1);
	}

	if (port > 0)	{ /* connect to a host */
		enum php_sslflags_t { php_ssl_none, php_ssl_v23, php_ssl_tls };
		enum php_sslflags_t ssl_flags = php_ssl_none;
		struct {
			char *proto;
			int protolen;
			int socktype;
			enum php_sslflags_t ssl_flags;
			/* more flags to be added here */
		} sockmodes[] = {
			{ "udp://", 6, SOCK_DGRAM,	php_ssl_none },
			{ "tcp://", 6, SOCK_STREAM,	php_ssl_none },
			{ "ssl://", 6, SOCK_STREAM, php_ssl_v23 },
			{ "tls://", 6, SOCK_STREAM, php_ssl_tls },
			/* more modes to be added here */
			{ NULL, 0, 0 }
		};
		int socktype = SOCK_STREAM;
		int i;

		for (i = 0; sockmodes[i].proto != NULL; i++) {
			if (strncmp(host, sockmodes[i].proto, sockmodes[i].protolen) == 0) {
				ssl_flags = sockmodes[i].ssl_flags;		
				socktype = sockmodes[i].socktype;
				host += sockmodes[i].protolen;
				break;
			}
		}
#ifndef HAVE_OPENSSL_EXT
		if (ssl_flags != php_ssl_none) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "no SSL support in this build");
		}
		else
#endif
		stream = php_stream_sock_open_host(host, (unsigned short)port, socktype, &tv, hashkey);

		/* Preserve error */
		err = php_socket_errno();

		if (stream == NULL) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to connect to %s:%ld", host, port);
		} else if (context) {
			php_stream_context_set(stream, context);
		}
		
#ifdef HAVE_OPENSSL_EXT
		if (stream && ssl_flags != php_ssl_none) {
			int ssl_ret = FAILURE;
			switch(ssl_flags)	{
				case php_ssl_v23:
					ssl_ret = php_stream_sock_ssl_activate_with_method(stream, 1, SSLv23_client_method(), NULL TSRMLS_CC);
					break;
				case php_ssl_tls:
					ssl_ret = php_stream_sock_ssl_activate_with_method(stream, 1, TLSv1_client_method(), NULL TSRMLS_CC);
					break;
				default:
					/* unknown ?? */
					break;
			}
			if (ssl_ret == FAILURE) {
				php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to activate SSL mode %d", ssl_flags);
				php_stream_close(stream);
				stream = NULL;
			}
		}
#endif
		
	} else {
		/* FIXME: Win32 - this probably does not return sensible errno and errstr */
		stream = php_stream_sock_open_unix(host, host_len, hashkey, &tv);
		err = php_socket_errno();
	}

	if (hashkey)
		efree(hashkey);
	
	if (stream == NULL)	{
		if (zerrno) {
			zval_dtor(zerrno);
			ZVAL_LONG(zerrno, err);
		}
		if (zerrstr) {
			char *buf = php_socket_strerror(err, NULL, 0);

			/* no need to dup; we would only need to efree buf anyway */
			zval_dtor(zerrstr);
			ZVAL_STRING(zerrstr, buf, 0);
		}
		RETURN_FALSE;
	}
	
	if (zcontext) {
		zend_list_addref(Z_RESVAL_P(zcontext));
	}
	php_stream_to_zval(stream, return_value);
}
Ejemplo n.º 29
0
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int header_init STREAMS_DC TSRMLS_DC)
{
    php_stream *stream = NULL;
    php_url *resource = NULL;
    int use_ssl;
    char *scratch = NULL;
    char *tmp = NULL;
    char *ua_str = NULL;
    zval **ua_zval = NULL, **tmpzval = NULL;
    int scratch_len = 0;
    int body = 0;
    char location[HTTP_HEADER_BLOCK_SIZE];
    zval **response_header = NULL;
    int reqok = 0;
    char *http_header_line = NULL;
    char tmp_line[128];
    size_t chunk_size = 0, file_size = 0;
    int eol_detect, have_header = 0;

    if (redirect_max < 1) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Circular redirect, aborting.");
        return NULL;
    }

    if (strpbrk(mode, "aw+")) {
        php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections.");
        return NULL;
    }

    resource = php_url_parse(path);
    if (resource == NULL) {
        return NULL;
    }

    if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) {
        php_url_free(resource);
        return php_stream_open_wrapper_ex(path, mode, ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
    }

    use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's';

    /* choose default ports */
    if (use_ssl && resource->port == 0)
        resource->port = 443;
    else if (resource->port == 0)
        resource->port = 80;

    stream = php_stream_sock_open_host(resource->host, resource->port, SOCK_STREAM, NULL, 0);
    if (stream == NULL) {
        eol_detect = 0;
        goto out;
    }

    /* avoid problems with auto-detecting when reading the headers -> the headers
     * are always in canonical \r\n format */
    eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);
    stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC);

    php_stream_context_set(stream, context);

    php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0);

#ifdef HAVE_OPENSSL_EXT
    if (use_ssl)	{

        if (context) {
            /* set the CN we expect to be on the remote cert.
             * You still need to have enabled verification (verify_peer) in the context for
             * this to have an effect */
            zval *cn;

            ALLOC_INIT_ZVAL(cn);
            ZVAL_STRING(cn, resource->host, 1);
            php_stream_context_set_option(context, "ssl", "CN_match", cn);
        }

        if (php_stream_sock_ssl_activate(stream, 1) == FAILURE)	{
            php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Unable to activate SSL mode");
            php_stream_close(stream);
            stream = NULL;
            goto out;
        }
    }
#endif

    if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) {
        if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) {
            scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval);
            scratch = (char *)emalloc(scratch_len);
            strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1);
            strcat(scratch, " ");
        }
    }

    if (!scratch) {
        scratch_len = strlen(path) + 32;
        scratch = (char *)emalloc(scratch_len);
        strcpy(scratch, "GET ");
    }

    /* file */
    if (resource->path && *resource->path)
        strlcat(scratch, resource->path, scratch_len);
    else
        strlcat(scratch, "/", scratch_len);

    /* query string */
    if (resource->query)	{
        strlcat(scratch, "?", scratch_len);
        strlcat(scratch, resource->query, scratch_len);
    }

    /* protocol version we are speaking */
    strlcat(scratch, " HTTP/1.0\r\n", scratch_len);

    /* send it */
    php_stream_write(stream, scratch, strlen(scratch));

    if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS && Z_STRLEN_PP(tmpzval)) {
        /* Remove newlines and spaces from start and end, php_trim will estrndup() */
        tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC);
        if (strlen(tmp) > 0) {
            /* Output trimmed headers with \r\n at the end */
            php_stream_write(stream, tmp, strlen(tmp));
            php_stream_write(stream, "\r\n", sizeof("\r\n") - 1);

            /* Make lowercase for easy comparison against 'standard' headers */
            php_strtolower(tmp, strlen(tmp));
            if (strstr(tmp, "user-agent:")) {
                have_header |= HTTP_HEADER_USER_AGENT;
            }
            if (strstr(tmp, "host:")) {
                have_header |= HTTP_HEADER_HOST;
            }
            if (strstr(tmp, "from:")) {
                have_header |= HTTP_HEADER_FROM;
            }
            if (strstr(tmp, "authorization:")) {
                have_header |= HTTP_HEADER_AUTH;
            }
        }
        efree(tmp);
    }

    /* auth header if it was specified */
    if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user && resource->pass) {
        /* decode the strings first */
        php_url_decode(resource->user, strlen(resource->user));
        php_url_decode(resource->pass, strlen(resource->pass));

        /* scratch is large enough, since it was made large enough for the whole URL */
        strcpy(scratch, resource->user);
        strcat(scratch, ":");
        strcat(scratch, resource->pass);

        tmp = (char *)php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL);

        if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) {
            php_stream_write(stream, scratch, strlen(scratch));
            php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0);
        }

        efree(tmp);
        tmp = NULL;
    }

    /* if the user has configured who they are, send a From: line */
    if (((have_header & HTTP_HEADER_FROM) == 0) && cfg_get_string("from", &tmp) == SUCCESS)	{
        if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0) {
            php_stream_write(stream, scratch, strlen(scratch));
        }
    }

    /* Send Host: header so name-based virtual hosts work */
    if ((have_header & HTTP_HEADER_HOST) == 0) {
        if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80))	{
            if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) {
                php_stream_write(stream, scratch, strlen(scratch));
            }
        } else {
            if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) {
                php_stream_write(stream, scratch, strlen(scratch));
            }
        }
    }

    if (context &&
            php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS) {
        ua_str = Z_STRVAL_PP(ua_zval);
    } else if (FG(user_agent)) {
        ua_str = FG(user_agent);
    }

    if (ua_str) {
#define _UA_HEADER "User-Agent: %s\r\n"
        char *ua;
        size_t ua_len;

        ua_len = sizeof(_UA_HEADER) + strlen(ua_str);

        /* ensure the header is only sent if user_agent is not blank */
        if (ua_len > sizeof(_UA_HEADER)) {
            ua = (char *)emalloc(ua_len + 1);
            if ((ua_len = snprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) {
                ua[ua_len] = 0;
                php_stream_write(stream, ua, ua_len);
            } else {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header");
            }

            if (ua) {
                efree(ua);
            }
        }
    }

    php_stream_write(stream, "\r\n", sizeof("\r\n")-1);

    /* Request content, such as for POST requests */
    if (context && php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS && Z_STRLEN_PP(tmpzval) > 0) {
        php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval));
        php_stream_write(stream, "\r\n\r\n", sizeof("\r\n\r\n")-1);
    }

    location[0] = '\0';

    /*
     * We need to read the HTTP response header one-by-one, because
     * the original author did not know about MSG_PEEK.
     * The chunk_size will be reset later, once we have read the
     * header completely.
     */
    if (options & STREAM_WILL_CAST)
        chunk_size = php_stream_set_chunk_size(stream, 1);

    if (!header_init && FAILURE == zend_hash_find(EG(active_symbol_table),
            "http_response_header", sizeof("http_response_header"), (void **) &response_header)) {
        header_init = 1;
    }

    if (header_init) {
        zval *tmp;
        MAKE_STD_ZVAL(tmp);
        array_init(tmp);
        ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", tmp);

        zend_hash_find(EG(active_symbol_table),
                       "http_response_header", sizeof("http_response_header"), (void **) &response_header);
    }


    if (!php_stream_eof(stream)) {
        size_t tmp_line_len;
        /* get response header */

        if (_php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len TSRMLS_CC) != NULL) {
            zval *http_response;
            int response_code;

            MAKE_STD_ZVAL(http_response);
            ZVAL_NULL(http_response);

            if (tmp_line_len > 9) {
                response_code = atoi(tmp_line + 9);
            } else {
                response_code = 0;
            }
            switch(response_code) {
            case 200:
            case 302:
            case 301:
                reqok = 1;
                break;
            case 403:
                php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT,
                                        tmp_line, response_code);
                break;
            default:
                /* safety net in the event tmp_line == NULL */
                if (!tmp_line_len) {
                    tmp_line[0] = '\0';
                }
                php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE,
                                        tmp_line, response_code);
            }

            Z_STRLEN_P(http_response) = tmp_line_len;
            Z_STRVAL_P(http_response) = estrndup(tmp_line, Z_STRLEN_P(http_response));
            if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\n') {
                Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0;
                Z_STRLEN_P(http_response)--;
                if (Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=='\r') {
                    Z_STRVAL_P(http_response)[Z_STRLEN_P(http_response)-1]=0;
                    Z_STRLEN_P(http_response)--;
                }
            }
            Z_TYPE_P(http_response) = IS_STRING;
            zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), &http_response, sizeof(zval *), NULL);
        }
    } else {
        php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!");
        goto out;
    }

    /* read past HTTP headers */

    http_header_line = (char *)emalloc(HTTP_HEADER_BLOCK_SIZE);

    while (!body && !php_stream_eof(stream))	{

        if (php_stream_gets(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL)	{
            char *p;
            int found_eol = 0;
            int http_header_line_length;

            http_header_line[HTTP_HEADER_BLOCK_SIZE-1] = '\0';

            p = http_header_line;
            while(*p) {
                while(*p == '\n' || *p == '\r')	{
                    *p = '\0';
                    p--;
                    found_eol = 1;
                }
                if (found_eol)
                    break;
                p++;
            }
            http_header_line_length = p-http_header_line+1;

            if (!strncasecmp(http_header_line, "Location: ", 10)) {
                strlcpy(location, http_header_line + 10, sizeof(location));
            } else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) {
                php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0);
            } else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) {
                file_size = atoi(http_header_line + 16);
                php_stream_notify_file_size(context, file_size, http_header_line, 0);
            }

            if (http_header_line[0] == '\0') {
                body = 1;
            } else {
                zval *http_header;

                MAKE_STD_ZVAL(http_header);

                ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1);

                zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), &http_header, sizeof(zval *), NULL);
            }
        } else {
            break;
        }
    }

    if (!reqok || location[0] != '\0')	{
        if (location[0] != '\0')
            php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0);

        php_stream_close(stream);
        stream = NULL;

        if (location[0] != '\0')	{

            zval *entry, **entryp;
            char new_path[HTTP_HEADER_BLOCK_SIZE];
            char loc_path[HTTP_HEADER_BLOCK_SIZE];

            *new_path='\0';
            if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) &&
                                       strncasecmp(location, "https://", sizeof("https://")-1) &&
                                       strncasecmp(location, "ftp://", sizeof("ftp://")-1) &&
                                       strncasecmp(location, "ftps://", sizeof("ftps://")-1)))
            {
                if (*location != '/') {
                    if (*(location+1) != '\0' && resource->path) {
                        char *s = strrchr(resource->path, '/');
                        if (!s) {
                            s = resource->path;
                            if (!s[0]) {
                                efree(s);
                                s = resource->path = estrdup("/");
                            } else {
                                *s = '/';
                            }
                        }
                        s[1] = '\0';
                        if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') {
                            snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location);
                        } else {
                            snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location);
                        }
                    } else {
                        snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location);
                    }
                } else {
                    strlcpy(loc_path, location, sizeof(loc_path));
                }
                if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
                    snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path);
                } else {
                    snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path);
                }
            } else {
                strlcpy(new_path, location, sizeof(new_path));
            }
            stream = php_stream_url_wrap_http_ex(NULL, new_path, mode, options, opened_path, context, --redirect_max, 0 STREAMS_CC TSRMLS_CC);
            if (stream && stream->wrapperdata)	{
                entryp = &entry;
                MAKE_STD_ZVAL(entry);
                ZVAL_EMPTY_STRING(entry);
                zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), entryp, sizeof(zval *), NULL);
                zend_hash_internal_pointer_reset(Z_ARRVAL_P(stream->wrapperdata));
                while (zend_hash_get_current_data(Z_ARRVAL_P(stream->wrapperdata), (void **)&entryp) == SUCCESS) {
                    zval_add_ref(entryp);
                    zend_hash_next_index_insert(Z_ARRVAL_PP(response_header), entryp, sizeof(zval *), NULL);
                    zend_hash_move_forward(Z_ARRVAL_P(stream->wrapperdata));
                }
                zval_dtor(stream->wrapperdata);
                FREE_ZVAL(stream->wrapperdata);
            }
        } else {
            php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed! %s", tmp_line);
        }
    }
out:
    if (http_header_line)
        efree(http_header_line);
    if (scratch)
        efree(scratch);
    php_url_free(resource);

    if (stream) {
        if (header_init) {
            stream->wrapperdata = *response_header;
            zval_add_ref(response_header);
        }
        php_stream_notify_progress_init(context, 0, file_size);
        /* Restore original chunk size now that we're done with headers (if applicable) */
        if (options & STREAM_WILL_CAST)
            php_stream_set_chunk_size(stream, chunk_size);

        /* restore the users auto-detect-line-endings setting */
        stream->flags |= eol_detect;

        /* as far as streams are concerned, we are now at the start of
         * the stream */
        stream->position = 0;
    }

    return stream;
}
Ejemplo n.º 30
0
/* Returns the bytes read on success
 * Returns -31 on unknown failure
 * Returns -80 on timeout
 * Returns -32 when remote server closes the connection
 */
int php_mongo_io_stream_read(mongo_connection *con, mongo_server_options *options, int timeout, void *data, int size, char **error_message)
{
	int num = 1, received = 0;
	TSRMLS_FETCH();

	int socketTimeoutMS = options->socketTimeoutMS ? options->socketTimeoutMS : FG(default_socket_timeout) * 1000;

	/* Convert negative values to -1 second, which implies no timeout */
	socketTimeoutMS = socketTimeoutMS < 0 ? -1000 : socketTimeoutMS;
	timeout = timeout < 0 ? -1000 : timeout;

	/* Socket timeout behavior varies based on the following:
	 * - Negative => no timeout (i.e. block indefinitely)
	 * - Zero => not specified (no changes to existing configuration)
	 * - Positive => used specified timeout (revert to previous value later) */
	if (timeout && timeout != socketTimeoutMS) {
		struct timeval rtimeout = {0, 0};

		rtimeout.tv_sec = timeout / 1000;
		rtimeout.tv_usec = (timeout % 1000) * 1000;

		php_stream_set_option(con->socket, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &rtimeout);
		mongo_manager_log(MonGlo(manager), MLOG_CON, MLOG_FINE, "Setting the stream timeout to %d.%06d", rtimeout.tv_sec, rtimeout.tv_usec);
	} else {
		mongo_manager_log(MonGlo(manager), MLOG_CON, MLOG_FINE, "No timeout changes for %s", con->hash);
	}

	php_mongo_stream_notify_io(options, MONGO_STREAM_NOTIFY_IO_READ, 0, size TSRMLS_CC);

	/* this can return FAILED if there is just no more data from db */
	while (received < size && num > 0) {
		int len = 4096 < (size - received) ? 4096 : size - received;
		ERROR_HANDLER_DECLARATION(error_handler)

		ERROR_HANDLER_REPLACE(error_handler, mongo_ce_ConnectionException);
		num = php_stream_read(con->socket, (char *) data, len);
		ERROR_HANDLER_RESTORE(error_handler);

		if (num < 0) {
			/* Doesn't look like this can happen, php_sockop_read overwrites
			 * the failure from recv() to return 0 */
			*error_message = strdup("Read from socket failed");
			return -31;
		}

		/* It *may* have failed. It also may simply have no data */
		if (num == 0) {
			zval *metadata;

			MAKE_STD_ZVAL(metadata);
			array_init(metadata);
			if (php_stream_populate_meta_data(con->socket, metadata)) {
				zval **tmp;

				if (zend_hash_find(Z_ARRVAL_P(metadata), "timed_out", sizeof("timed_out"), (void**)&tmp) == SUCCESS) {
					convert_to_boolean_ex(tmp);
					if (Z_BVAL_PP(tmp)) {
						struct timeval rtimeout = {0, 0};

						if (timeout > 0 && options->socketTimeoutMS != timeout) {
							rtimeout.tv_sec = timeout / 1000;
							rtimeout.tv_usec = (timeout % 1000) * 1000;
						} else {
							/* Convert timeout=-1 to -1second, which PHP interprets as no timeout */
							int socketTimeoutMS = options->socketTimeoutMS == -1 ? -1000 : options->socketTimeoutMS;
							rtimeout.tv_sec = socketTimeoutMS / 1000;
							rtimeout.tv_usec = (socketTimeoutMS % 1000) * 1000;
						}
						*error_message = malloc(256);
						snprintf(*error_message, 256, "Read timed out after reading %d bytes, waited for %d.%06d seconds", num, rtimeout.tv_sec, rtimeout.tv_usec);
						zval_ptr_dtor(&metadata);
						return -80;
					}
				}
				if (zend_hash_find(Z_ARRVAL_P(metadata), "eof", sizeof("eof"), (void**)&tmp) == SUCCESS) {
					convert_to_boolean_ex(tmp);
					if (Z_BVAL_PP(tmp)) {
						*error_message = strdup("Remote server has closed the connection");
						zval_ptr_dtor(&metadata);
						return -32;
					}
				}
			}
			zval_ptr_dtor(&metadata);
		}

		data = (char*)data + num;
		received += num;
	}
	/* PHP may have sent notify-progress of *more then* 'received' in some
	 * cases.
	 * PHP will read 8192 byte chunks at a time, but if we request less data
	 * then that PHP will just buffer the rest, which is fine.  It could
	 * confuse users a little, why their progress update was higher then the
	 * max-bytes-expected though... */
	php_mongo_stream_notify_io(options, MONGO_STREAM_NOTIFY_IO_COMPLETED, received, size TSRMLS_CC);

	/* If the timeout was changed, revert to the previous value now */
	if (timeout && timeout != socketTimeoutMS) {
		struct timeval rtimeout = {0, 0};

		/* If socketTimeoutMS was never specified, revert to default_socket_timeout */
		if (options->socketTimeoutMS == 0) {
			mongo_manager_log(MonGlo(manager), MLOG_CON, MLOG_FINE, "Stream timeout will be reverted to default_socket_timeout (%d)", FG(default_socket_timeout));
		}

		rtimeout.tv_sec = socketTimeoutMS / 1000;
		rtimeout.tv_usec = (socketTimeoutMS % 1000) * 1000;

		php_stream_set_option(con->socket, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &rtimeout);
		mongo_manager_log(MonGlo(manager), MLOG_CON, MLOG_FINE, "Now setting stream timeout back to %d.%06d", rtimeout.tv_sec, rtimeout.tv_usec);
	}

	return received;
}