@@ -451,7 +451,7 @@ static inline HANDLE dup_fd_as_handle(int fd)
451
451
* They are used within `proc_open` and freed before it returns */
452
452
typedef struct _descriptorspec_item {
453
453
int index ; /* desired FD # in child process */
454
- int is_pipe ;
454
+ int is_pipe ; /* =1 for pipe / tty, =2 for socketpair */
455
455
php_file_descriptor_t childend ; /* FD # opened for use in child
456
456
* (will be copied to `index` in child) */
457
457
php_file_descriptor_t parentend ; /* FD # opened for use in parent
@@ -725,6 +725,40 @@ static int set_proc_descriptor_to_pipe(descriptorspec_item *desc, zend_string *z
725
725
return SUCCESS ;
726
726
}
727
727
728
+ static int set_proc_descriptor_to_socket (descriptorspec_item * desc )
729
+ {
730
+ php_socket_t sock [2 ];
731
+
732
+ #ifdef PHP_WIN32
733
+ if (socketpair (AF_INET , SOCK_STREAM , 0 , sock )) {
734
+ #else
735
+ if (socketpair (AF_UNIX , SOCK_STREAM , 0 , sock )) {
736
+ #endif
737
+ zend_string * err = php_socket_error_str (php_socket_errno ());
738
+ php_error_docref (NULL , E_WARNING , "Unable to create socket pair %s" , ZSTR_VAL (err ));
739
+ zend_string_release (err );
740
+ return FAILURE ;
741
+ }
742
+
743
+ /* Pass sock[1] to child because it will not use overlapped IO on Windows (even when AcceptEx() is not available). */
744
+ desc -> childend = (php_file_descriptor_t ) sock [1 ];
745
+ desc -> is_pipe = 2 ;
746
+
747
+ #ifdef PHP_WIN32
748
+ /* Don't let the child inherit the parent socket */
749
+ desc -> parentend = dup_handle ((php_file_descriptor_t ) sock [0 ], FALSE, TRUE);
750
+ #else
751
+ desc -> parentend = sock [0 ];
752
+
753
+ #if defined(F_SETFD ) && defined(FD_CLOEXEC )
754
+ /* Don't let the child inherit the parent socket */
755
+ fcntl (desc -> parentend , F_SETFD , FD_CLOEXEC );
756
+ #endif
757
+ #endif
758
+
759
+ return SUCCESS ;
760
+ }
761
+
728
762
static int set_proc_descriptor_to_file (descriptorspec_item * desc , zend_string * file_path ,
729
763
zend_string * file_mode )
730
764
{
@@ -830,6 +864,9 @@ static int set_proc_descriptor_from_array(zval *descitem, descriptorspec_item *d
830
864
goto finish ;
831
865
}
832
866
retval = set_proc_descriptor_to_pipe (& descriptors [ndesc ], zmode );
867
+ } else if (zend_string_equals_literal (ztype , "socket" )) {
868
+ /* Set descriptor to socketpair */
869
+ retval = set_proc_descriptor_to_socket (& descriptors [ndesc ]);
833
870
} else if (zend_string_equals_literal (ztype , "file" )) {
834
871
/* Set descriptor to file */
835
872
if ((zfile = get_string_parameter (descitem , 1 , "file name parameter for 'file'" )) == NULL ) {
@@ -907,15 +944,24 @@ static int close_parentends_of_pipes(descriptorspec_item *descriptors, int ndesc
907
944
* number which the user requested */
908
945
for (int i = 0 ; i < ndesc ; i ++ ) {
909
946
if (descriptors [i ].is_pipe ) {
910
- close (descriptors [i ].parentend );
947
+ if (descriptors [i ].is_pipe == 2 ) {
948
+ closesocket (descriptors [i ].parentend );
949
+ } else {
950
+ close (descriptors [i ].parentend );
951
+ }
911
952
}
912
953
if (descriptors [i ].childend != descriptors [i ].index ) {
913
954
if (dup2 (descriptors [i ].childend , descriptors [i ].index ) < 0 ) {
914
955
php_error_docref (NULL , E_WARNING , "Unable to copy file descriptor %d (for pipe) into " \
915
956
"file descriptor %d: %s" , descriptors [i ].childend , descriptors [i ].index , strerror (errno ));
916
957
return FAILURE ;
917
958
}
918
- close (descriptors [i ].childend );
959
+
960
+ if (descriptors [i ].is_pipe == 2 ) {
961
+ closesocket (descriptors [i ].childend );
962
+ } else {
963
+ close (descriptors [i ].childend );
964
+ }
919
965
}
920
966
}
921
967
@@ -1204,37 +1250,44 @@ PHP_FUNCTION(proc_open)
1204
1250
close_descriptor (descriptors [i ].childend );
1205
1251
1206
1252
if (descriptors [i ].is_pipe ) {
1207
- switch (descriptors [i ].mode_flags ) {
1253
+ if (descriptors [i ].is_pipe == 1 ) {
1254
+ switch (descriptors [i ].mode_flags ) {
1208
1255
#ifdef PHP_WIN32
1209
- case O_WRONLY |O_BINARY :
1210
- mode_string = "wb" ;
1211
- break ;
1212
- case O_RDONLY |O_BINARY :
1213
- mode_string = "rb" ;
1214
- break ;
1256
+ case O_WRONLY |O_BINARY :
1257
+ mode_string = "wb" ;
1258
+ break ;
1259
+ case O_RDONLY |O_BINARY :
1260
+ mode_string = "rb" ;
1261
+ break ;
1215
1262
#endif
1216
- case O_WRONLY :
1217
- mode_string = "w" ;
1218
- break ;
1219
- case O_RDONLY :
1220
- mode_string = "r" ;
1221
- break ;
1222
- case O_RDWR :
1223
- mode_string = "r+" ;
1224
- break ;
1263
+ case O_WRONLY :
1264
+ mode_string = "w" ;
1265
+ break ;
1266
+ case O_RDONLY :
1267
+ mode_string = "r" ;
1268
+ break ;
1269
+ case O_RDWR :
1270
+ mode_string = "r+" ;
1271
+ break ;
1272
+ }
1225
1273
}
1274
+
1275
+ if (descriptors [i ].is_pipe == 2 ) {
1276
+ stream = _php_stream_sock_open_from_socket ((php_socket_t ) descriptors [i ].parentend , NULL STREAMS_CC );
1277
+ } else {
1226
1278
#ifdef PHP_WIN32
1227
- stream = php_stream_fopen_from_fd (_open_osfhandle ((zend_intptr_t )descriptors [i ].parentend ,
1228
- descriptors [i ].mode_flags ), mode_string , NULL );
1229
- php_stream_set_option (stream , PHP_STREAM_OPTION_PIPE_BLOCKING , blocking_pipes , NULL );
1279
+ stream = php_stream_fopen_from_fd (_open_osfhandle ((zend_intptr_t )descriptors [i ].parentend ,
1280
+ descriptors [i ].mode_flags ), mode_string , NULL );
1281
+ php_stream_set_option (stream , PHP_STREAM_OPTION_PIPE_BLOCKING , blocking_pipes , NULL );
1230
1282
#else
1231
- stream = php_stream_fopen_from_fd (descriptors [i ].parentend , mode_string , NULL );
1283
+ stream = php_stream_fopen_from_fd (descriptors [i ].parentend , mode_string , NULL );
1232
1284
# if defined(F_SETFD ) && defined(FD_CLOEXEC )
1233
- /* Mark the descriptor close-on-exec, so it won't be inherited by
1234
- * potential other children */
1235
- fcntl (descriptors [i ].parentend , F_SETFD , FD_CLOEXEC );
1285
+ /* Mark the descriptor close-on-exec, so it won't be inherited by
1286
+ * potential other children */
1287
+ fcntl (descriptors [i ].parentend , F_SETFD , FD_CLOEXEC );
1236
1288
# endif
1237
1289
#endif
1290
+ }
1238
1291
if (stream ) {
1239
1292
zval retfp ;
1240
1293
0 commit comments