Initial commit
This commit is contained in:
102
src/HTTPU/Endpoint.php
Normal file
102
src/HTTPU/Endpoint.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
8
src/HTTPU/EndpointException.php
Normal file
8
src/HTTPU/EndpointException.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace NoccyLabs\UPnP\HTTPU;
|
||||
|
||||
class EndpointException extends HTTPUException
|
||||
{
|
||||
}
|
||||
|
10
src/HTTPU/HTTPUException.php
Normal file
10
src/HTTPU/HTTPUException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace NoccyLabs\UPnP\HTTPU;
|
||||
|
||||
use NoccyLabs\UPnP\UPnPException;
|
||||
|
||||
class HTTPUException extends UPnPException
|
||||
{
|
||||
}
|
||||
|
28
src/HTTPU/MSearchRequest.php
Normal file
28
src/HTTPU/MSearchRequest.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
13
src/HTTPU/MSearchResponse.php
Normal file
13
src/HTTPU/MSearchResponse.php
Normal 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
53
src/HTTPU/Request.php
Normal 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
45
src/HTTPU/Response.php
Normal 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'];
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user