Initial commit

This commit is contained in:
2017-02-16 16:29:55 +01:00
commit c3531ce5fa
21 changed files with 1383 additions and 0 deletions

102
src/HTTPU/Endpoint.php Normal file
View File

@ -0,0 +1,102 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class Endpoint
{
protected $socket;
/**
*
* @param string $bind The IP to bind to (0.0.0.0 for all)
* @throws EndpointException
*/
public function __construct($bind='0.0.0.0', $port=0, $reuse_port=false)
{
//Create the socket.
$socket = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// Handle errors on failure
if (!$socket) {
$errno = socket_last_error();
$errmsg = socket_error($errno);
throw new EndpointException("Could not create socket: {$errmsg} ({$errno})");
}
//Set socket options.
socket_set_nonblock($socket);
socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, 1);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
if ($reuse_port) {
socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1);
}
if(!socket_bind($socket, $bind, $port)) {
$errno = socket_last_error();
$errmsg = socket_error($errno);
throw new EndpointException("Could not bind socket to {$bind}:{$port}: {$errmsg} ({$errno})");
}
$this->socket = $socket;
}
public function __destruct()
{
if ($this->socket) {
@socket_close($this->socket);
}
}
/**
*
*
* @param Request $request The request to send
* @return Response[] The received responses if any
*/
public function send(Request $request, $wait_time=5)
{
// Get the details from the request
$buffer = $request->getBuffer();
$addr = $request->getAddress();
$port = $request->getPort();
if (false === socket_sendto($this->socket, $buffer, strlen($buffer), 0, $addr, $port)) {
$errno = socket_last_error();
$errmsg = socket_error($errno);
throw new EndpointException("Send failed: {$errmsg} ({$errno})");
}
// Wait $wait_time seconds for responses to arrive
$read_expires = microtime(true) + $wait_time;
$responses = [];
while (microtime(true) < $read_expires) {
if (socket_recvfrom($this->socket, $data, 5120, MSG_DONTWAIT, $raddr, $rport)) {
//while(is_string($data = socket_read($this->socket, 5120))) {
$response = Response::createFromString($data, $raddr);
if ($response) {
$responses[] = $response;
}
}
usleep(10000);
}
return $responses;
/*
while(socket_select($read, $write, $except, 3)) {
//Read received packets with a maximum size of 5120 bytes.
while(is_string($data = socket_read($this->socket, 5120))) {
echo "READ: {$data}\n";
return $data;
}
}
*/
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class EndpointException extends HTTPUException
{
}

View File

@ -0,0 +1,10 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
use NoccyLabs\UPnP\UPnPException;
class HTTPUException extends UPnPException
{
}

View File

@ -0,0 +1,28 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class MSearchRequest extends Request
{
protected $max_wait = 0;
public function __construct($host='239.255.255.250', $port='1900')
{
parent::__construct('M-SEARCH * HTTP/1.1', $host, $port);
$this->headers['Man'] = '"ssdp:discover"';
$this->headers['MX'] = max(0,$this->max_wait);
}
public function setMaxWait($seconds)
{
$this->max_wait = $seconds;
}
public function setSearchType($search_type)
{
$this->headers['ST'] = $search_type;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class MSearchResponse extends Response
{
public function getId()
{
return "foo";
}
}

53
src/HTTPU/Request.php Normal file
View File

@ -0,0 +1,53 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class Request
{
protected $request;
protected $host;
protected $port;
public function __construct($request_line, $host, $port)
{
$this->request = $request_line;
$this->host = $host;
$this->port = $port;
}
public function getAddress()
{
return $this->host;
}
public function getPort()
{
return $this->port;
}
public function getBuffer()
{
$this->headers['Host'] = sprintf("%s:%d", $this->host, $this->port);
$buffer = $this->request . "\r\n";
foreach ($this->headers as $key=>$value) {
$buffer.= sprintf("%s: %s\r\n", $key, $value);
}
$buffer.= "\r\n";
return $buffer;
}
public function setUserAgent($os, $os_version, $product, $product_version)
{
$this->headers['User-Agent'] = sprintf("%s/%s UPnP/1.1 %s/%s",
$os, $os_version,
$product, $product_version
);
}
}

45
src/HTTPU/Response.php Normal file
View File

@ -0,0 +1,45 @@
<?php
namespace NoccyLabs\UPnP\HTTPU;
class Response
{
protected $headers = [];
protected $ip;
public function __construct(array $headers, $ip)
{
$this->headers = $headers;
$this->ip = $ip;
}
public static function createFromString($string, $ip)
{
$data = explode("\r\n", trim($string));
$status = array_shift($data);
$headers = [];
foreach ($data as $line) {
list ($header, $value) = array_map("trim", explode(":",$line,2));
$headers[strtolower($header)] = $value;
}
// Test for search responses using the ST header
if (array_key_exists('st', $headers)) {
return new MSearchResponse($headers, $ip);
}
}
public function getIp()
{
return $this->ip;
}
public function getLocation()
{
return $this->headers['location'];
}
}