@@ -444,11 +444,18 @@ static inline HANDLE dup_fd_as_handle(int fd)
444
444
# define close_descriptor (fd ) close(fd)
445
445
#endif
446
446
447
+ /* Determines the type of a descriptor item. */
448
+ typedef enum _descriptor_type {
449
+ DESCRIPTOR_TYPE_STD ,
450
+ DESCRIPTOR_TYPE_PIPE ,
451
+ DESCRIPTOR_TYPE_SOCKET
452
+ } descriptor_type ;
453
+
447
454
/* One instance of this struct is created for each item in `$descriptorspec` argument to `proc_open`
448
455
* They are used within `proc_open` and freed before it returns */
449
456
typedef struct _descriptorspec_item {
450
457
int index ; /* desired FD # in child process */
451
- int is_pipe ;
458
+ descriptor_type type ;
452
459
php_file_descriptor_t childend ; /* FD # opened for use in child
453
460
* (will be copied to `index` in child) */
454
461
php_file_descriptor_t parentend ; /* FD # opened for use in parent
@@ -679,7 +686,7 @@ static int set_proc_descriptor_to_pty(descriptorspec_item *desc, int *master_fd,
679
686
}
680
687
}
681
688
682
- desc -> is_pipe = 1 ;
689
+ desc -> type = DESCRIPTOR_TYPE_PIPE ;
683
690
desc -> childend = dup (* slave_fd );
684
691
desc -> parentend = dup (* master_fd );
685
692
desc -> mode_flags = O_RDWR ;
@@ -690,6 +697,19 @@ static int set_proc_descriptor_to_pty(descriptorspec_item *desc, int *master_fd,
690
697
#endif
691
698
}
692
699
700
+ /* Mark the descriptor close-on-exec, so it won't be inherited by children */
701
+ static php_file_descriptor_t make_descriptor_cloexec (php_file_descriptor_t fd )
702
+ {
703
+ #ifdef PHP_WIN32
704
+ return dup_handle (fd , FALSE, TRUE);
705
+ #else
706
+ #if defined(F_SETFD ) && defined(FD_CLOEXEC )
707
+ fcntl (fd , F_SETFD , FD_CLOEXEC );
708
+ #endif
709
+ return fd ;
710
+ #endif
711
+ }
712
+
693
713
static int set_proc_descriptor_to_pipe (descriptorspec_item * desc , zend_string * zmode )
694
714
{
695
715
php_file_descriptor_t newpipe [2 ];
@@ -699,7 +719,7 @@ static int set_proc_descriptor_to_pipe(descriptorspec_item *desc, zend_string *z
699
719
return FAILURE ;
700
720
}
701
721
702
- desc -> is_pipe = 1 ;
722
+ desc -> type = DESCRIPTOR_TYPE_PIPE ;
703
723
704
724
if (strncmp (ZSTR_VAL (zmode ), "w" , 1 ) != 0 ) {
705
725
desc -> parentend = newpipe [1 ];
@@ -711,17 +731,42 @@ static int set_proc_descriptor_to_pipe(descriptorspec_item *desc, zend_string *z
711
731
desc -> mode_flags = O_RDONLY ;
712
732
}
713
733
714
- #ifdef PHP_WIN32
715
- /* don't let the child inherit the parent side of the pipe */
716
- desc -> parentend = dup_handle (desc -> parentend , FALSE, TRUE);
734
+ desc -> parentend = make_descriptor_cloexec (desc -> parentend );
717
735
736
+ #ifdef PHP_WIN32
718
737
if (ZSTR_LEN (zmode ) >= 2 && ZSTR_VAL (zmode )[1 ] == 'b' )
719
738
desc -> mode_flags |= O_BINARY ;
720
739
#endif
721
740
722
741
return SUCCESS ;
723
742
}
724
743
744
+ #ifdef PHP_WIN32
745
+ #define create_socketpair (socks ) socketpair_win32(AF_INET, SOCK_STREAM, 0, (socks), 0)
746
+ #else
747
+ #define create_socketpair (socks ) socketpair(AF_UNIX, SOCK_STREAM, 0, (socks))
748
+ #endif
749
+
750
+ static int set_proc_descriptor_to_socket (descriptorspec_item * desc )
751
+ {
752
+ php_socket_t sock [2 ];
753
+
754
+ if (create_socketpair (sock )) {
755
+ zend_string * err = php_socket_error_str (php_socket_errno ());
756
+ php_error_docref (NULL , E_WARNING , "Unable to create socket pair: %s" , ZSTR_VAL (err ));
757
+ zend_string_release (err );
758
+ return FAILURE ;
759
+ }
760
+
761
+ desc -> type = DESCRIPTOR_TYPE_SOCKET ;
762
+ desc -> parentend = make_descriptor_cloexec ((php_file_descriptor_t ) sock [0 ]);
763
+
764
+ /* Pass sock[1] to child because it will never use overlapped IO on Windows. */
765
+ desc -> childend = (php_file_descriptor_t ) sock [1 ];
766
+
767
+ return SUCCESS ;
768
+ }
769
+
725
770
static int set_proc_descriptor_to_file (descriptorspec_item * desc , zend_string * file_path ,
726
771
zend_string * file_mode )
727
772
{
@@ -827,6 +872,9 @@ static int set_proc_descriptor_from_array(zval *descitem, descriptorspec_item *d
827
872
goto finish ;
828
873
}
829
874
retval = set_proc_descriptor_to_pipe (& descriptors [ndesc ], zmode );
875
+ } else if (zend_string_equals_literal (ztype , "socket" )) {
876
+ /* Set descriptor to socketpair */
877
+ retval = set_proc_descriptor_to_socket (& descriptors [ndesc ]);
830
878
} else if (zend_string_equals_literal (ztype , "file" )) {
831
879
/* Set descriptor to file */
832
880
if ((zfile = get_string_parameter (descitem , 1 , "file name parameter for 'file'" )) == NULL ) {
@@ -903,7 +951,7 @@ static int close_parentends_of_pipes(descriptorspec_item *descriptors, int ndesc
903
951
* Also, dup() the child end of all pipes as necessary so they will use the FD
904
952
* number which the user requested */
905
953
for (int i = 0 ; i < ndesc ; i ++ ) {
906
- if (descriptors [i ].is_pipe ) {
954
+ if (descriptors [i ].type != DESCRIPTOR_TYPE_STD ) {
907
955
close (descriptors [i ].parentend );
908
956
}
909
957
if (descriptors [i ].childend != descriptors [i ].index ) {
@@ -1194,12 +1242,13 @@ PHP_FUNCTION(proc_open)
1194
1242
/* Clean up all the child ends and then open streams on the parent
1195
1243
* ends, where appropriate */
1196
1244
for (i = 0 ; i < ndesc ; i ++ ) {
1197
- char * mode_string = NULL ;
1198
1245
php_stream * stream = NULL ;
1199
1246
1200
1247
close_descriptor (descriptors [i ].childend );
1201
1248
1202
- if (descriptors [i ].is_pipe ) {
1249
+ if (descriptors [i ].type == DESCRIPTOR_TYPE_PIPE ) {
1250
+ char * mode_string = NULL ;
1251
+
1203
1252
switch (descriptors [i ].mode_flags ) {
1204
1253
#ifdef PHP_WIN32
1205
1254
case O_WRONLY |O_BINARY :
@@ -1219,32 +1268,31 @@ PHP_FUNCTION(proc_open)
1219
1268
mode_string = "r+" ;
1220
1269
break ;
1221
1270
}
1271
+
1222
1272
#ifdef PHP_WIN32
1223
1273
stream = php_stream_fopen_from_fd (_open_osfhandle ((zend_intptr_t )descriptors [i ].parentend ,
1224
1274
descriptors [i ].mode_flags ), mode_string , NULL );
1225
1275
php_stream_set_option (stream , PHP_STREAM_OPTION_PIPE_BLOCKING , blocking_pipes , NULL );
1226
1276
#else
1227
1277
stream = php_stream_fopen_from_fd (descriptors [i ].parentend , mode_string , NULL );
1228
- # if defined(F_SETFD ) && defined(FD_CLOEXEC )
1229
- /* Mark the descriptor close-on-exec, so it won't be inherited by
1230
- * potential other children */
1231
- fcntl (descriptors [i ].parentend , F_SETFD , FD_CLOEXEC );
1232
- # endif
1233
1278
#endif
1234
- if (stream ) {
1235
- zval retfp ;
1279
+ } else if (descriptors [i ].type == DESCRIPTOR_TYPE_SOCKET ) {
1280
+ stream = php_stream_sock_open_from_socket ((php_socket_t ) descriptors [i ].parentend , NULL );
1281
+ } else {
1282
+ proc -> pipes [i ] = NULL ;
1283
+ }
1236
1284
1237
- /* nasty hack; don't copy it */
1238
- stream -> flags |= PHP_STREAM_FLAG_NO_SEEK ;
1285
+ if ( stream ) {
1286
+ zval retfp ;
1239
1287
1240
- php_stream_to_zval ( stream , & retfp );
1241
- add_index_zval ( pipes , descriptors [ i ]. index , & retfp ) ;
1288
+ /* nasty hack; don't copy it */
1289
+ stream -> flags |= PHP_STREAM_FLAG_NO_SEEK ;
1242
1290
1243
- proc -> pipes [ i ] = Z_RES ( retfp );
1244
- Z_ADDREF ( retfp );
1245
- }
1246
- } else {
1247
- proc -> pipes [ i ] = NULL ;
1291
+ php_stream_to_zval ( stream , & retfp );
1292
+ add_index_zval ( pipes , descriptors [ i ]. index , & retfp );
1293
+
1294
+ proc -> pipes [ i ] = Z_RES ( retfp );
1295
+ Z_ADDREF ( retfp ) ;
1248
1296
}
1249
1297
}
1250
1298
0 commit comments