2727#include "phpdbg_utils.h"
2828#include "phpdbg_set.h"
2929
30+ #include <sys/socket.h>
31+ #include <sys/select.h>
32+ #include <sys/time.h>
33+ #include <sys/types.h>
34+ #include <unistd.h>
35+ #include <arpa/inet.h>
36+
3037ZEND_DECLARE_MODULE_GLOBALS (phpdbg );
3138
3239#if PHP_VERSION_ID >= 50500
@@ -477,6 +484,7 @@ const opt_struct OPTIONS[] = { /* {{{ */
477484 {'O' , 1 , "opline log" },
478485 {'r' , 0 , "run" },
479486 {'E' , 0 , "step-through-eval" },
487+ {'l' , 1 , "listen" },
480488 {'-' , 0 , NULL }
481489}; /* }}} */
482490
@@ -535,6 +543,90 @@ static inline void phpdbg_sigint_handler(int signo) /* {{{ */
535543 }
536544} /* }}} */
537545
546+ int phpdbg_open_socket (short port ) /* {{{ */
547+ {
548+ int fd = socket (AF_INET , SOCK_STREAM , 0 );
549+
550+ switch (fd ) {
551+ case -1 :
552+ return -1 ;
553+
554+ default : {
555+ int boolean = 1 ;
556+
557+ switch (setsockopt (fd , SOL_SOCKET , SO_REUSEADDR , & boolean , sizeof (int ))) {
558+ case -1 :
559+ close (fd );
560+ return -2 ;
561+
562+ default : {
563+ struct sockaddr_in address ;
564+
565+ memset (& address , 0 , sizeof (address ));
566+
567+ address .sin_port = htons (port );
568+ address .sin_family = AF_INET ;
569+
570+ if (!inet_pton (AF_INET , "127.0.0.1" , & address .sin_addr )) {
571+ close (fd );
572+ return -3 ;
573+ }
574+
575+ switch (bind (fd , (struct sockaddr * )& address , sizeof (address ))) {
576+ case -1 :
577+ close (fd );
578+ return -4 ;
579+
580+ default : {
581+ listen (fd , 5 );
582+ }
583+ }
584+ }
585+ }
586+ }
587+ }
588+
589+ return fd ;
590+ } /* }}} */
591+
592+ int phpdbg_open_sockets (short listen [2 ], FILE * streams [2 ]) /* {{{ */
593+ {
594+ int sockets [2 ] = {
595+ phpdbg_open_socket (listen [0 ]),
596+ phpdbg_open_socket (listen [1 ])
597+ };
598+ int accepted [2 ] = {-1 , -1 };
599+
600+ streams [0 ] = NULL ;
601+ streams [1 ] = NULL ;
602+
603+ if (sockets [0 ] < 0 || sockets [1 ] < 0 ) {
604+ if (sockets [0 ] >= 0 )
605+ close (sockets [0 ]);
606+ if (sockets [1 ] >= 0 )
607+ close (sockets [1 ]);
608+ return FAILURE ;
609+ }
610+
611+ {
612+ struct sockaddr_in address ;
613+ socklen_t size = sizeof (address );
614+
615+ memset (& address , 0 , size );
616+ accepted [0 ] = accept (
617+ sockets [0 ], & address , & size );
618+
619+ memset (& address , 0 , size );
620+ accepted [1 ] = accept (
621+ sockets [1 ], & address , & size );
622+ }
623+
624+ streams [0 ] = fdopen (accepted [0 ], "r" );
625+ streams [1 ] = fdopen (accepted [1 ], "w" );
626+
627+ return SUCCESS ;
628+ } /* }}} */
629+
538630int main (int argc , char * * argv ) /* {{{ */
539631{
540632 sapi_module_struct * phpdbg = & phpdbg_sapi_module ;
@@ -556,6 +648,8 @@ int main(int argc, char **argv) /* {{{ */
556648 int run = 0 ;
557649 int step = 0 ;
558650 char * bp_tmp_file ;
651+ short listen [2 ];
652+ FILE * streams [2 ] = {NULL , NULL };
559653
560654#ifdef ZTS
561655 void * * * tsrm_ls ;
@@ -599,7 +693,9 @@ int main(int argc, char **argv) /* {{{ */
599693 opt = 0 ;
600694 run = 0 ;
601695 step = 0 ;
602-
696+ listen [0 ] = 0 ;
697+ listen [1 ] = 0 ;
698+
603699 while ((opt = php_getopt (argc , argv , OPTIONS , & php_optarg , & php_optind , 0 , 2 )) != -1 ) {
604700 switch (opt ) {
605701 case 'r' :
@@ -693,9 +789,23 @@ int main(int argc, char **argv) /* {{{ */
693789 case 'q' : /* hide banner */
694790 show_banner = 0 ;
695791 break ;
792+
793+ /* if you pass a listen port, we will accept input on listen port */
794+ /* and write output to listen port * 2 */
795+
796+ case 'l' : /* set listen settings */
797+ listen [0 ] = atoi (php_optarg );
798+ listen [1 ] = (listen [0 ] * 2 );
799+ break ;
696800 }
697801 }
698802
803+ if (!cleaning &&
804+ (listen [0 ] && listen [1 ])) {
805+ phpdbg_open_sockets (listen , streams );
806+ /* now is a sensible time to announce listen settings on the console */
807+ }
808+
699809 phpdbg -> ini_defaults = phpdbg_ini_defaults ;
700810 phpdbg -> phpinfo_as_text = 1 ;
701811 phpdbg -> php_ini_ignore_cwd = 1 ;
@@ -733,10 +843,21 @@ int main(int argc, char **argv) /* {{{ */
733843
734844 PG (modules_activated ) = 0 ;
735845
736- /* set up basic io here */
737- PHPDBG_G (io )[PHPDBG_STDIN ] = stdin ;
738- PHPDBG_G (io )[PHPDBG_STDOUT ] = stdout ;
739- PHPDBG_G (io )[PHPDBG_STDERR ] = stderr ;
846+ /* setup io here */
847+ if (streams [0 ] && streams [1 ]) {
848+ PHPDBG_G (flags ) |= PHPDBG_IS_REMOTE ;
849+ /* remote console */
850+ PHPDBG_G (io )[PHPDBG_STDIN ] = streams [0 ];
851+ PHPDBG_G (io )[PHPDBG_STDOUT ] = streams [1 ];
852+ PHPDBG_G (io )[PHPDBG_STDERR ] = stderr ;
853+
854+ signal (SIGPIPE , SIG_IGN );
855+ } else {
856+ /* local console */
857+ PHPDBG_G (io )[PHPDBG_STDIN ] = stdin ;
858+ PHPDBG_G (io )[PHPDBG_STDOUT ] = stdout ;
859+ PHPDBG_G (io )[PHPDBG_STDERR ] = stderr ;
860+ }
740861
741862 if (exec ) { /* set execution context */
742863 PHPDBG_G (exec ) = phpdbg_resolve_path (
0 commit comments