bind = $bind; $this->port = $port; $this->type = $type; $this->_init(); } /** * Bind to our Socket * * @throws SocketException */ private function _bindSocket(): void { if (socket_bind($this->server,$this->bind,$this->port) === FALSE) throw new SocketException(SocketException::CANT_BIND_SOCKET,socket_strerror(socket_last_error($this->server))); } /** * Create our Socket * * @throws SocketException */ private function _createSocket(): void { /** * Check dependencies */ if (! extension_loaded('sockets')) throw new SocketException(SocketException::CANT_ACCEPT,'Missing sockets extension'); if (! extension_loaded('pcntl')) throw new SocketException(SocketException::CANT_ACCEPT,'Missing pcntl extension'); switch ($this->type) { case SOCK_STREAM: $this->server = socket_create(AF_INET|AF_INET6,$this->type,SOL_TCP); break; case SOCK_DGRAM: $this->server = socket_create(AF_INET|AF_INET6,$this->type,SOL_UDP); break; default: throw new \Exception('Unknown socket_type:'.$this->type); } if ($this->server === FALSE) throw new SocketException(SocketException::CANT_CREATE_SOCKET,socket_strerror(socket_last_error())); socket_set_option($this->server,SOL_SOCKET,SO_REUSEADDR,1); } /** * Setup Socket and Bind * * @throws SocketException */ private function _init(): void { $this->_createSocket(); $this->_bindSocket(); } /** * Our main loop where we listen for connections * * @throws SocketException */ public function listen() { if (! $this->handler) throw new SocketException(SocketException::CANT_LISTEN,'Handler not set.'); if (in_array($this->type,[SOCK_STREAM,SOCK_SEQPACKET])) if (socket_listen($this->server,$this->backlog) === FALSE) throw new SocketException(SocketException::CANT_LISTEN,socket_strerror(socket_last_error($this->server))); Log::info(sprintf('%s:- Listening on [%s:%d]',self::LOGKEY,$this->bind,$this->port)); switch ($this->type) { case SOCK_STREAM: $this->loop_tcp(); break; case SOCK_DGRAM: $this->loop_udp(); break; } socket_close($this->server); Log::info(sprintf('%s:= Closed [%s:%d]',self::LOGKEY,$this->bind,$this->port)); } /** * Manage and execute incoming connections * * @throws SocketException */ private function loop_tcp() { while (TRUE) { if (($accept = socket_accept($this->server)) === FALSE) throw new SocketException(SocketException::CANT_ACCEPT,socket_strerror(socket_last_error($this->server))); try { $r = new SocketClient($accept); } catch (\ErrorException $e) { Log::error(sprintf('%s:! Creating Socket client failed? [%s]',self::LOGKEY,$e->getMessage())); continue; } $this->handler[0]->{$this->handler[1]}($r); } } private function loop_udp() { while (TRUE) { $r = new SocketClient($this->server); if ($r->hasData(30)) { $this->handler[0]->{$this->handler[1]}($r); // Sleep so our thread has a chance to pick up the data from our connection usleep(50000); } } } /** * Set our connection handler Class and Method * * @param array $handler */ public function setConnectionHandler(array $handler): void { $this->handler = $handler; } }