Commits

Ruslan Osmanov committed 20130fd

Fix: address argument of the listener accept callback contained garbage in case of a client connected via UNIX domain socket
Add: EventBuffer::write, EventUtil::setSocketOption methods and some constants

  • Participants
  • Parent commits b8a8902

Comments (0)

Files changed (7)

File classes/buffer.c

 }
 /* }}} */
 
+/* {{{ proto int EventBuffer::write(mixed fd[, int howmuch]);
+ *
+ * Write contents of the buffer to a file descriptor.
+ * The buffer will be drained after the bytes have been successfully written.
+ *
+ * Returns the number of bytes written, or &false; on error.
+ */
+PHP_METHOD(EventBuffer, write)
+{
+	zval                *zbuf  = getThis();
+	php_event_buffer_t  *b;
+	zval               **ppzfd;
+	evutil_socket_t      fd;
+	long                 res;
+	long                 howmuch = -1;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l",
+				&ppzfd) == FAILURE) {
+		return;
+	}
+
+	fd = php_event_zval_to_fd(ppzfd TSRMLS_CC);
+	if (fd == -1) {
+		RETURN_FALSE;
+	}
+
+	PHP_EVENT_FETCH_BUFFER(b, zbuf);
+
+	if (howmuch < 0) {
+		res = evbuffer_write(b->buf, fd);
+	} else {
+		res = evbuffer_write_atmost(b->buf, fd, howmuch);
+	}
+
+	if (res == -1) {
+		RETURN_FALSE;
+	}
+
+	RETVAL_LONG(res);
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4

File classes/event_util.c

 }
 /* }}} */
 
+/* {{{ proto bool EventUtil::setSocketOption(mixed socket, int level, int optname, int|array optval)
+   Sets socket options for the socket */
+PHP_METHOD(EventUtil, setSocketOption)
+{
+	zval            **ppzfd    , **zoptval;
+	struct linger     lv;
+	int               ov;
+	int               optlen;
+	int               retval;
+	struct timeval    tv;
+	long              level;
+	long              optname;
+	void             *opt_ptr;
+	HashTable        *opt_ht;
+	zval            **l_onoff  , **l_linger;
+	zval            **sec      , **usec;
+	evutil_socket_t   fd;
+	
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZllZ",
+				&ppzfd, &level, &optname, &zoptval) == FAILURE) {
+		return;
+	}
+
+	fd = php_event_zval_to_fd(ppzfd TSRMLS_CC);
+	if (fd == -1) {
+		RETURN_FALSE;
+	}
+
+	errno = 0;
+
+	switch (optname) {
+		case SO_LINGER: {
+			const char l_onoff_key[]  = "l_onoff";
+			const char l_linger_key[] = "l_linger";
+
+			convert_to_array_ex(zoptval);
+			opt_ht = HASH_OF(*zoptval);
+
+			if (zend_hash_find(opt_ht, l_onoff_key, sizeof(l_onoff_key), (void **) &l_onoff) == FAILURE) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_onoff_key);
+				RETURN_FALSE;
+			}
+			if (zend_hash_find(opt_ht, l_linger_key, sizeof(l_linger_key), (void **) &l_linger) == FAILURE) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", l_linger_key);
+				RETURN_FALSE;
+			}
+
+			convert_to_long_ex(l_onoff);
+			convert_to_long_ex(l_linger);
+
+			lv.l_onoff  = (unsigned short) Z_LVAL_PP(l_onoff);
+			lv.l_linger = (unsigned short) Z_LVAL_PP(l_linger);
+
+			optlen = sizeof(lv);
+			opt_ptr = &lv;
+			break;
+		}
+
+		case SO_RCVTIMEO:
+		case SO_SNDTIMEO: {
+			const char sec_key[]  = "sec";
+			const char usec_key[] = "usec";
+
+			convert_to_array_ex(zoptval);
+			opt_ht = HASH_OF(*zoptval);
+
+			if (zend_hash_find(opt_ht, sec_key, sizeof(sec_key), (void **) &sec) == FAILURE) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", sec_key);
+				RETURN_FALSE;
+			}
+			if (zend_hash_find(opt_ht, usec_key, sizeof(usec_key), (void **) &usec) == FAILURE) {
+				php_error_docref(NULL TSRMLS_CC, E_WARNING, "no key \"%s\" passed in optval", usec_key);
+				RETURN_FALSE;
+			}
+
+			convert_to_long_ex(sec);
+			convert_to_long_ex(usec);
+
+			tv.tv_sec  = Z_LVAL_PP(sec);
+			tv.tv_usec = Z_LVAL_PP(usec);
+
+			optlen  = sizeof(tv);
+			opt_ptr = &tv;
+			break;
+		}
+		
+		default:
+			convert_to_long_ex(zoptval);
+			ov = Z_LVAL_PP(zoptval);
+
+			optlen = sizeof(ov);
+			opt_ptr = &ov;
+			break;
+	}
+
+	retval = setsockopt(fd, level, optname, opt_ptr, optlen);
+	if (retval != 0) {
+		if (retval != -2) { /* error, but message already emitted */
+			php_error_docref(NULL TSRMLS_CC, E_WARNING,
+					"Unable to set socket option, errno: %d", errno);
+		}
+
+		RETURN_FALSE;
+	}
+
+	RETVAL_TRUE;
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4

File classes/listener.c

 		args[1] = &arg_fd;
 
 		MAKE_STD_ZVAL(arg_address);
+		/* A client connected via UNIX domain can't be bound to the socket.
+		 * I.e. the socket is most likely abstract(unnamed), and has no sense here. */
+#ifdef AF_UNIX
+		if (address->sa_family == AF_UNIX) {
+			ZVAL_NULL(arg_address);
+		} else {
+			array_init(arg_address);
+			sockaddr_parse(address, arg_address);
+		}
+#else
 		array_init(arg_address);
 		sockaddr_parse(address, arg_address);
+#endif
 		args[2] = &arg_address;
 
 		if (arg_data) {
     <email>osmanov@php.net</email>
     <active>yes</active>
   </lead>
-  <date>2013-03-25</date>
+  <date>2013-03-30</date>
   <!--{{{ Current version -->
   <version>
     <release>1.5.2</release>
   <license uri="http://www.php.net/license">PHP</license>
   <notes><![CDATA[
   Fix: bug #64551 with build failed on Mac OS X
+  Fix: address argument of the listener accept callback contained garbage in case of a client connected via UNIX domain socket
+  Add: EventBuffer::write, EventUtil::setSocketOption methods and some constants
   ]]></notes>
   <!--}}}-->
   <!--{{{ Contents -->
       <license uri="http://www.php.net/license">PHP</license>
       <notes><![CDATA[
   Fix: bug #64551 with build failed on Mac OS X
+  Fix: address argument of the listener accept callback contained garbage in case of a client connected via UNIX domain socket
+  Add: EventBuffer::write, EventUtil::setSocketOption methods and some constants
   ]]></notes>
     </release>
     <!--}}}-->
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, AF_UNIX,   AF_UNIX);
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, AF_UNSPEC, AF_UNSPEC);
 
+	/* Socket options */
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_DEBUG,     SO_DEBUG);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_REUSEADDR, SO_REUSEADDR);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_KEEPALIVE, SO_KEEPALIVE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_DONTROUTE, SO_DONTROUTE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_LINGER,    SO_LINGER);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_BROADCAST, SO_BROADCAST);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_OOBINLINE, SO_OOBINLINE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_SNDBUF,    SO_SNDBUF);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_RCVBUF,    SO_RCVBUF);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_SNDLOWAT,  SO_SNDLOWAT);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_RCVLOWAT,  SO_RCVLOWAT);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_SNDTIMEO,  SO_SNDTIMEO);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_RCVTIMEO,  SO_RCVTIMEO);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_TYPE,      SO_TYPE);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SO_ERROR,     SO_ERROR);
+#ifdef TCP_NODELAY
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, TCP_NODELAY, TCP_NODELAY);
+#endif
+
+	/* Socket protocol levels */
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SOL_SOCKET, SOL_SOCKET);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SOL_TCP,    IPPROTO_TCP);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, SOL_UDP,    IPPROTO_UDP);
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, IPPROTO_IP, IPPROTO_IP);
+#if HAVE_IPV6
+	REGISTER_EVENT_CLASS_CONST_LONG(php_event_util_ce, IPPROTO_IPV6, IPPROTO_IPV6);
+#endif
+
+
+
+
 #ifdef HAVE_EVENT_EXTRA_LIB
 	/* DNS options */
 	REGISTER_EVENT_CLASS_CONST_LONG(php_event_dns_base_ce, OPTION_SEARCH,      DNS_OPTION_SEARCH);
 	ZEND_ARG_INFO(0, size)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_evbuffer_write, 0, 0, 1)
+	ZEND_ARG_INFO(0, fd)
+	ZEND_ARG_INFO(0, howmuch)
+ZEND_END_ARG_INFO();
+
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_event_socket_1, 0, 0, 0)
 	ZEND_ARG_INFO(0, socket)
 	ZEND_ARG_INFO(1, port)
 ZEND_END_ARG_INFO();
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_event_util_set_socket_option, 0, 0, 4)
+	ZEND_ARG_INFO(0, socket)
+	ZEND_ARG_INFO(0, level)
+	ZEND_ARG_INFO(0, optname)
+	ZEND_ARG_INFO(0, optval)
+ZEND_END_ARG_INFO();
+
 
 /* ARGINFO END }}} */
 
 	PHP_ME(EventBuffer, search,        arginfo_evbuffer_search,        ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, searchEol,     arginfo_evbuffer_search_eol,    ZEND_ACC_PUBLIC)
 	PHP_ME(EventBuffer, pullup,        arginfo_evbuffer_pullup,        ZEND_ACC_PUBLIC)
+	PHP_ME(EventBuffer, write,         arginfo_evbuffer_write,         ZEND_ACC_PUBLIC)
 
 	PHP_FE_END
 };
 const zend_function_entry php_event_util_ce_functions[] = {/* {{{ */
 	PHP_ABSTRACT_ME(EventUtil, __construct, NULL)
 
-	PHP_ME(EventUtil, getLastSocketErrno,    arginfo_event_socket_1,             ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-	PHP_ME(EventUtil, getLastSocketError,    arginfo_event_socket_1,             ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, getLastSocketErrno, arginfo_event_socket_1, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, getLastSocketError, arginfo_event_socket_1, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 
 #ifdef            HAVE_EVENT_OPENSSL_LIB
 	PHP_ME(EventUtil, sslRandPoll,           arginfo_event__void,                ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 #endif
-	PHP_ME(EventUtil, getSocketName,         arginfo_event_util_get_socket_name, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, getSocketName,   arginfo_event_util_get_socket_name,   ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+	PHP_ME(EventUtil, setSocketOption, arginfo_event_util_set_socket_option, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
 
 	PHP_FE_END
 };
 PHP_METHOD(EventBuffer, search);
 PHP_METHOD(EventBuffer, searchEol);
 PHP_METHOD(EventBuffer, pullup);
+PHP_METHOD(EventBuffer, write);
 
 PHP_METHOD(EventUtil, getLastSocketErrno);
 PHP_METHOD(EventUtil, getLastSocketError);
 PHP_METHOD(EventUtil, sslRandPoll);
 #endif
 PHP_METHOD(EventUtil, getSocketName);
+PHP_METHOD(EventUtil, setSocketOption);
 
 PHP_METHOD(EventBufferPosition, __construct);