1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2021 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Ruslan Osmanov <osmanov@php.net>                             |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php_ev.h"
20 #include "util.h"
21 #include "zend_exceptions.h"
22 
23 /* {{{ php_ev_zval_to_fd
24  * Get numeric file descriptor from PHP stream or Socket resource */
php_ev_zval_to_fd(zval * pfd)25 php_socket_t php_ev_zval_to_fd(zval *pfd)
26 {
27 	php_socket_t  file_desc = -1;
28 	php_stream   *stream;
29 #ifdef PHP_EV_USE_SOCKETS
30 	php_socket   *php_sock;
31 #endif
32 
33 	if (Z_TYPE_P(pfd) == IS_RESOURCE) {
34 		/* PHP stream or PHP socket resource  */
35 		if ((stream = (php_stream *)zend_fetch_resource2(Z_RES_P(pfd), NULL, php_file_le_stream(), php_file_le_pstream())) != NULL) {
36 			if (php_stream_is(stream, PHP_STREAM_IS_MEMORY) || php_stream_is(stream, PHP_STREAM_IS_TEMP)) {
37 				zend_throw_exception(zend_exception_get_default(),
38 						"Cannot fetch file descriptor from memory based stream", 0);
39 				return -1;
40 			}
41 
42 			php_stream_from_zval_no_verify(stream, pfd);
43 
44 			if (stream == NULL) {
45 				zend_throw_exception(zend_exception_get_default(), "Stream resource is invalid", 0);
46 				return -1;
47 			}
48 
49 			/* PHP stream */
50 			if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT) == SUCCESS) {
51 				if (php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT,
52 							(void *) &file_desc, 1) != SUCCESS || file_desc < 0) {
53 					return -1;
54 				}
55 			} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD) == SUCCESS) {
56 				if (php_stream_cast(stream, PHP_STREAM_AS_FD,
57 							(void *) &file_desc, 1) != SUCCESS || file_desc < 0) {
58 					return -1;
59 				}
60 			} else if (php_stream_can_cast(stream, PHP_STREAM_AS_STDIO) == SUCCESS) {
61 				if (php_stream_cast(stream, PHP_STREAM_AS_STDIO,
62 							(void *) &file_desc, 1) != SUCCESS || file_desc < 0) {
63 					return -1;
64 				}
65 			} else { /* STDIN, STDOUT, STDERR etc. */
66 				file_desc = Z_LVAL_P(pfd);
67 			}
68 		} else {
69 			/* PHP socket resource */
70 #ifdef PHP_EV_USE_SOCKETS
71 			if ((php_sock = (php_socket *)zend_fetch_resource(Z_RES_P(pfd),
72 							php_sockets_le_socket_name, php_sockets_le_socket())) != NULL) {
73 				if (php_sock->error) {
74 					if (!php_sock->blocking && php_sock->error == EINPROGRESS) {
75 #ifdef PHP_EV_DEBUG
76 						php_error_docref(NULL, E_NOTICE, "Operation is in progress");
77 #endif
78 					} else {
79 						return -1;
80 					}
81 				}
82 				return php_sock->bsd_socket;
83 			} else {
84 				zend_throw_exception(zend_exception_get_default(),
85 						"Expected either valid PHP stream or valid PHP socket resource", 0);
86 			}
87 #else
88 			zend_throw_exception(zend_exception_get_default(), "Expected a valid PHP stream resource", 0);
89 #endif
90 			return -1;
91 		}
92 	} else if (Z_TYPE_P(pfd) == IS_LONG) {
93 		/* Numeric fd */
94 		file_desc = Z_LVAL_P(pfd);
95 		if (file_desc < 0) {
96 			zend_throw_exception(zend_exception_get_default(), "Invalid file descriptor", 0);
97 			return -1;
98 		}
99 	} else {
100 		zend_throw_exception(zend_exception_get_default(), "Invalid file descriptor", 0);
101 		return -1;
102 	}
103 
104 	return file_desc;
105 }
106 /* }}} */
107 
108 /**
109  * @note `error` must be freed, if not NULL
110  */
php_ev_import_func_info(php_ev_func_info * pf,zval * zcb,char * error)111 int php_ev_import_func_info(php_ev_func_info *pf, zval *zcb, char *error)/*{{{*/
112 {
113 	if (zcb) {
114 		zend_fcall_info_cache  fcc;
115 		zend_object           *obj_ptr;
116 
117 		if (!zend_is_callable_ex(zcb, NULL, IS_CALLABLE_STRICT, NULL, &fcc, &error)) {
118 			return FAILURE;
119 		}
120 
121 		PHP_EV_EFREE(error);
122 
123 		pf->ce       = fcc.calling_scope;
124 		pf->func_ptr = fcc.function_handler;
125 		obj_ptr      = fcc.object;
126 
127 		if (Z_TYPE_P(zcb) == IS_OBJECT) {
128 			ZVAL_COPY(&pf->closure, zcb);
129 		} else {
130 			ZVAL_UNDEF(&pf->closure);
131 		}
132 
133 		if (obj_ptr && !(pf->func_ptr->common.fn_flags & ZEND_ACC_STATIC)) {
134 			ZVAL_OBJ(&pf->obj, obj_ptr);
135 			Z_ADDREF(pf->obj);
136 		} else {
137 			ZVAL_UNDEF(&pf->obj);
138 		}
139 	} else {
140 		pf->ce       = NULL;
141 		pf->func_ptr = NULL;
142 		ZVAL_UNDEF(&pf->closure);
143 		ZVAL_UNDEF(&pf->obj);
144 	}
145 
146 	return SUCCESS;
147 }
148 /*}}}*/
149 
php_ev_func_info_free(php_ev_func_info * pf,zend_bool self)150 void php_ev_func_info_free(php_ev_func_info *pf, zend_bool self)/*{{{*/
151 {
152 	if (!Z_ISUNDEF(pf->obj)) {
153 		zval_ptr_dtor(&pf->obj);
154 		ZVAL_UNDEF(&pf->obj);
155 	}
156 	if (!Z_ISUNDEF(pf->closure)) {
157 		zval_ptr_dtor(&pf->closure);
158 		ZVAL_UNDEF(&pf->closure);
159 	}
160 	if (self != FALSE) {
161 		efree(pf);
162 	}
163 }
164 /*}}}*/
165 
166 /*
167  * Local variables:
168  * tab-width: 4
169  * c-basic-offset: 4
170  * End:
171  * vim600: noet sw=4 ts=4 sts=4 fdm=marker
172  * vim<600: noet sw=4 ts=4 sts=4
173  */
174