| Bryan Duxbury | c0e2ef5 | 2011-01-26 18:25:17 +0000 | [diff] [blame] | 1 | <?php | 
 | 2 |  | 
 | 3 | include_once $GLOBALS['THRIFT_ROOT'].'/server/TServer.php'; | 
 | 4 |  | 
 | 5 | /** | 
 | 6 |  * A forking implementation of a Thrift server. | 
 | 7 |  * | 
 | 8 |  * @package thrift.server | 
 | 9 |  */ | 
 | 10 | class TForkingServer extends TServer { | 
 | 11 |   /** | 
 | 12 |    * Flag for the main serving loop | 
 | 13 |    * | 
 | 14 |    * @var bool | 
 | 15 |    */ | 
 | 16 |   private $stop_ = false; | 
 | 17 |  | 
 | 18 |   /** | 
 | 19 |    * List of children. | 
 | 20 |    * | 
 | 21 |    * @var array | 
 | 22 |    */ | 
 | 23 |   private $children_ = array(); | 
 | 24 |  | 
 | 25 |   /** | 
 | 26 |    * Listens for new client using the supplied | 
 | 27 |    * transport. We fork when a new connection | 
 | 28 |    * arrives. | 
 | 29 |    * | 
 | 30 |    * @return void | 
 | 31 |    */ | 
 | 32 |   public function serve() { | 
 | 33 |     $this->transport_->listen(); | 
 | 34 |  | 
 | 35 |     while (!$this->stop_) { | 
 | 36 |       try { | 
 | 37 |         $transport = $this->transport_->accept(); | 
 | 38 |  | 
 | 39 |         if ($transport != null) { | 
 | 40 |           $pid = pcntl_fork(); | 
 | 41 |  | 
 | 42 |           if ($pid > 0) { | 
 | 43 |             $this->handleParent($transport, $pid); | 
 | 44 |           } | 
 | 45 |           else if ($pid === 0) { | 
 | 46 |             $this->handleChild($transport); | 
 | 47 |           } | 
 | 48 |           else { | 
 | 49 |             throw new TException('Failed to fork'); | 
 | 50 |           } | 
 | 51 |         } | 
 | 52 |       } | 
 | 53 |       catch (TTransportException $e) { } | 
 | 54 |  | 
 | 55 |       $this->collectChildren(); | 
 | 56 |     } | 
 | 57 |   } | 
 | 58 |  | 
 | 59 |   /** | 
 | 60 |    * Code run by the parent | 
 | 61 |    * | 
 | 62 |    * @param TTransport $transport | 
 | 63 |    * @param int $pid | 
 | 64 |    * @return void | 
 | 65 |    */ | 
 | 66 |   private function handleParent(TTransport $transport, $pid) { | 
 | 67 |     $this->children_[$pid] = $transport; | 
 | 68 |   } | 
 | 69 |  | 
 | 70 |   /** | 
 | 71 |    * Code run by the child. | 
 | 72 |    * | 
 | 73 |    * @param TTransport $transport | 
 | 74 |    * @return void | 
 | 75 |    */ | 
 | 76 |   private function handleChild(TTransport $transport) { | 
 | 77 |     try { | 
 | 78 |       $inputTransport = $this->inputTransportFactory_->getTransport($transport); | 
 | 79 |       $outputTransport = $this->outputTransportFactory_->getTransport($transport); | 
 | 80 |       $inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport); | 
 | 81 |       $outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport); | 
 | 82 |       while ($this->processor_->process($inputProtocol, $outputProtocol)) { } | 
 | 83 |       @$transport->close(); | 
 | 84 |     } | 
 | 85 |     catch (TTransportException $e) { } | 
 | 86 |      | 
 | 87 |     exit(0); | 
 | 88 |   } | 
 | 89 |  | 
 | 90 |   /** | 
 | 91 |    * Collects any children we may have | 
 | 92 |    * | 
 | 93 |    * @return void | 
 | 94 |    */ | 
 | 95 |   private function collectChildren() { | 
 | 96 |     foreach ($this->children_ as $pid => $transport) { | 
 | 97 |       if (pcntl_waitpid($pid, $status, WNOHANG) > 0) { | 
 | 98 |         unset($this->children_[$pid]); | 
 | 99 |         if ($transport) @$transport->close(); | 
 | 100 |       } | 
 | 101 |     } | 
 | 102 |   } | 
 | 103 |  | 
 | 104 |   /** | 
 | 105 |    * Stops the server running. Kills the transport | 
 | 106 |    * and then stops the main serving loop | 
 | 107 |    * | 
 | 108 |    * @return void | 
 | 109 |    */ | 
 | 110 |   public function stop() { | 
 | 111 |     $this->transport_->close(); | 
 | 112 |     $this->stop_ = true; | 
 | 113 |   } | 
 | 114 | } |