227 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * The SocketHandler class will handle a single socket.
 | 
						|
 * It takes care of the very basic socket functions.
 | 
						|
 * @author jpt
 | 
						|
 * @package Socket
 | 
						|
 */
 | 
						|
class Socket_SocketHandler {
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Socket ressource
 | 
						|
	 * @var ressource
 | 
						|
	 */
 | 
						|
	protected $socket;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @var boolean
 | 
						|
	 */
 | 
						|
	protected $isConnected;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @var boolean
 | 
						|
	 */
 | 
						|
	protected $isBound;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @var boolean
 | 
						|
	 */
 | 
						|
	protected $isListening;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Default constructor. Sets the socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @param ressource $socket
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function __construct($socket) {
 | 
						|
		if(is_resource($socket) === FALSE) throw new Exception_SocketException("Invalid socket ressource!", 1289663108);
 | 
						|
		$this->socket = $socket;
 | 
						|
		$this->isBound = FALSE;
 | 
						|
		$this->isConnected = FALSE;
 | 
						|
		$this->isListening = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Destructor. Closes socket.
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function __destruct() {
 | 
						|
		$this->close();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Returns socket
 | 
						|
	 * @return ressource
 | 
						|
	 */
 | 
						|
	public function getSocket() {
 | 
						|
		return $this->socket;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @return boolean
 | 
						|
	 */
 | 
						|
	public function isConnected() {
 | 
						|
		return $this->isConnected;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Sets isConnected-flag.
 | 
						|
	 * @param boolean $connected
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function setConnected($connected) {
 | 
						|
		$this->isConnected = $connected;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @return boolean
 | 
						|
	 */
 | 
						|
	public function isListening() {
 | 
						|
		return $this->isListening;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Connects to a specified address.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @param string $address
 | 
						|
	 * @param int $port
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function connect($address, $port) {
 | 
						|
		if($this->isConnected === TRUE) throw new Exception_SocketException("Socket is already connected!", 1289663170);
 | 
						|
		$result = socket_connect($this->socket, $address, $port);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		$this->isConnected = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Binds the socket to an address + port.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @param string $address
 | 
						|
	 * @param int $port
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function bind($address, $port) {
 | 
						|
		if($this->isBound === TRUE) throw new Exception_SocketException("Socket is already bound!", 1289663212);
 | 
						|
		$result = socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		$result = socket_bind($this->socket, $address, $port);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		$this->isBound = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Let's the socket listen for incoming connections.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function listen() {
 | 
						|
		if($this->isBound === FALSE) throw new Exception_SocketException("Cannot listen on unbound socket!", 1289663220);
 | 
						|
		$result = socket_listen($this->socket);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		$this->isListening = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Tells the SocketHandler that he got accepted.
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function hasBeenAccepted() {
 | 
						|
		$this->isConnected = TRUE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Accepts a connection to a socket that is bound and listens
 | 
						|
	 * The ressource has to be added to the SocketPool manually
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return ressource
 | 
						|
	 */
 | 
						|
	public function accept() {
 | 
						|
		if($this->isBound === FALSE) throw new Exception_SocketException("Cannot accept connections from unbound socket!", 1289663239);
 | 
						|
		if($this->isListening === FALSE) throw new Exception_SocketException("Cannot accept connections from socket that is not listening!", 1289663241);
 | 
						|
		$accept = socket_accept($this->socket);
 | 
						|
		if($accept === FALSE) $this->handleSocketError();
 | 
						|
		return $accept;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Returns ip + port of the remote socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return string
 | 
						|
	 */
 | 
						|
	public function getRemoteName() {
 | 
						|
		if($this->isConnected === FALSE) throw new Exception_SocketException("Socket not connected, cannot retrieve remote name!", 1289928192);
 | 
						|
		$result = socket_getpeername($this->socket, $address, $port);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		return $address . ":" . $port;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Returns ip + port of the local socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return string
 | 
						|
	 */
 | 
						|
	public function getLocalName() {
 | 
						|
		if($this->isBound === FALSE ^ $this->isConnected === FALSE) throw new Exception_SocketException("Socket is not bound or connected, no local name available!", 1289928256);
 | 
						|
		$result = socket_getsockname($this->socket, $address, $port);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		return $address . ":" . $port;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Writes data to the socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @param string $data
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function write($data) {
 | 
						|
		$result = socket_write($this->socket, $data);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Reads data from the socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @param int $length
 | 
						|
	 * @return string
 | 
						|
	 */
 | 
						|
	public function read($length = 16384) {
 | 
						|
		$result = socket_read($this->socket, $length, PHP_BINARY_READ);
 | 
						|
		if($result === FALSE) $this->handleSocketError();
 | 
						|
		return $result;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Shuts the socket down after waiting a bit (waiting might be optional).
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	public function close() {
 | 
						|
		usleep(100000);
 | 
						|
		if($this->isConnected === TRUE) {
 | 
						|
			$result = socket_shutdown($this->socket);
 | 
						|
			if($result === FALSE) $this->handleSocketError();
 | 
						|
		}
 | 
						|
		if(is_resource($this->socket)) {
 | 
						|
			$result = socket_close($this->socket);
 | 
						|
			if($result === FALSE) $this->handleSocketError();
 | 
						|
		}
 | 
						|
		$this->isConnected = FALSE;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Gets last error from socket.
 | 
						|
	 * @throws Exception_SocketException
 | 
						|
	 * @return void
 | 
						|
	 */
 | 
						|
	protected function handleSocketError() {
 | 
						|
		if(is_resource($this->socket) === FALSE) throw new Exception_SocketException("No socket resource available!", 1290954177);
 | 
						|
		$errno = socket_last_error($this->socket);
 | 
						|
		$error = socket_strerror($errno);
 | 
						|
		socket_clear_error();
 | 
						|
		$errormsg = "[" . $errno . "] " . $error;
 | 
						|
		throw new Exception_SocketException("A socket error occured: " . $errormsg, 1289663360);
 | 
						|
	}
 | 
						|
}
 | 
						|
?>
 |