|
3 | 3 | namespace Clue\React\Multicast; |
4 | 4 |
|
5 | 5 | use React\EventLoop\LoopInterface; |
6 | | -use Socket\React\Datagram\Factory as DatagramFactory; |
7 | | -use Socket\Raw\Factory as RawFactory; |
| 6 | +use React\Datagram\Socket as DatagramSocket; |
8 | 7 | use BadMethodCallException; |
| 8 | +use RuntimeException; |
9 | 9 |
|
10 | 10 | class Factory |
11 | 11 | { |
12 | 12 | private $loop; |
13 | | - private $rawFactory; |
14 | | - private $datagramFactory; |
15 | 13 |
|
16 | | - public function __construct(LoopInterface $loop, RawFactory $rawFactory = null, DatagramFactory $datagramFactory = null) |
| 14 | + public function __construct(LoopInterface $loop) |
17 | 15 | { |
18 | | - if ($rawFactory === null) { |
19 | | - $rawFactory = new RawFactory(); |
20 | | - } |
21 | | - |
22 | | - if ($datagramFactory === null) { |
23 | | - $datagramFactory = new DatagramFactory($loop); |
24 | | - } |
25 | | - |
26 | | - $this->rawFactory = $rawFactory; |
27 | | - $this->datagramFactory = $datagramFactory; |
| 16 | + $this->loop = $loop; |
28 | 17 | } |
29 | 18 |
|
30 | 19 | public function createSender() |
31 | 20 | { |
32 | | - $socket = $this->rawFactory->createUdp4(); |
33 | | - return $this->datagramFactory->createFromRaw($socket); |
| 21 | + $stream = @stream_socket_server('udp://0.0.0.0:0', $errno, $errstr, STREAM_SERVER_BIND); |
| 22 | + if ($stream === false) { |
| 23 | + throw new RuntimeException('Unable to create sending socket: ' . $errstr, $errno); |
| 24 | + } |
| 25 | + |
| 26 | + return new DatagramSocket($this->loop, $stream); |
34 | 27 | } |
35 | 28 |
|
36 | 29 | public function createReceiver($address) |
37 | 30 | { |
38 | 31 | if (!defined('MCAST_JOIN_GROUP')) { |
39 | | - throw new BadMethodCallException('MCAST_JOIN_GROUP not defined'); |
| 32 | + throw new BadMethodCallException('MCAST_JOIN_GROUP not defined (requires PHP 5.4+)'); |
| 33 | + } |
| 34 | + if (!function_exists('socket_import_stream')) { |
| 35 | + throw new BadMethodCallException('Function socket_import_stream missing (requires ext-sockets and PHP 5.4+)'); |
40 | 36 | } |
41 | 37 |
|
42 | 38 | $parts = parse_url('udp://' . $address); |
43 | 39 |
|
44 | | - $socket = $this->rawFactory->createUdp4(); |
| 40 | + $stream = @stream_socket_server('udp://0.0.0.0:' . $parts['port'], $errno, $errstr, STREAM_SERVER_BIND); |
| 41 | + if ($stream === false) { |
| 42 | + throw new RuntimeException('Unable to create receiving socket: ' . $errstr, $errno); |
| 43 | + } |
| 44 | + |
| 45 | + $socket = socket_import_stream($stream); |
| 46 | + if ($stream === false) { |
| 47 | + throw new RuntimeException('Unable to access underlying socket resource'); |
| 48 | + } |
45 | 49 |
|
46 | 50 | // allow multiple processes to bind to the same address |
47 | | - $socket->setOption(SOL_SOCKET, SO_REUSEADDR, 1); |
| 51 | + $ret = socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); |
| 52 | + if ($ret === false) { |
| 53 | + throw new RuntimeException('Unable to enable SO_REUSEADDR'); |
| 54 | + } |
48 | 55 |
|
49 | 56 | // join multicast group and bind to port |
50 | | - $socket->setOption( |
| 57 | + $ret = socket_set_option( |
| 58 | + $socket, |
51 | 59 | IPPROTO_IP, |
52 | 60 | MCAST_JOIN_GROUP, |
53 | 61 | array('group' => $parts['host'], 'interface' => 0) |
54 | 62 | ); |
55 | | - $socket->bind('0.0.0.0:' . $parts['port']); |
| 63 | + if ($ret === false) { |
| 64 | + throw new RuntimeException('Unable to join multicast group'); |
| 65 | + } |
56 | 66 |
|
57 | | - return $this->datagramFactory->createFromRaw($socket); |
| 67 | + return new DatagramSocket($this->loop, $stream); |
58 | 68 | } |
59 | 69 | } |
0 commit comments