php/php-src — pull request #220 by takigama (2012-10-18 07:48:25+00:00)
Title: Exposing the sin6_scope_id parameter in socket_recvfrom, socket_sendto and socket_connect for IPv6 link-local unicast/multicast communications.

This patch adds an extra optional parameter to the functions which sets/gets the sin6_scope_id member. The optional parameter is IPv6 only.

```
int socket_recvfrom(resource socket, string &buf, int len, int flags, string &name [, int &port [, int &ifindex]])
int socket_sendto(resource socket, string buf, int len, int flags, string addr [, int port [, int ifindex]])
bool socket_connect(resource socket, string addr [, int port [, int ifindex]])
```

When dealing with link-local connections in IPv6 as all interfaces have a connection to the same subnet, knowing which interface a packet was received on or where to send it to has become important.

At the OS layer, the sockaddr_in6 structure carries an extra member called sin6_scope_id (which is set by the OS when receiving packets and is used to determine the interface for outgoing packets). This member exists in all current OS's that implement the sockets functionality.

With connection-less unicast or multicast protcols, the current socket_recvfrom() function has no mechanism for telling you the interface the data was received on, and hence there is no way of replying to a packet reliably. For example, in linux what will happen when sin6_scope_id is not set when sending a packet with a link-local destination depends on the kernel version (v2.4+ drop the packet as invalid, 3.0+ send it via the interface with the lowest index) and as such a packet received on eth1 might mistakenly be replied to via eth0.

There are other mechanisms which have been defined for dealing with this (for eg, an address can be specified as [fe80::1:2:3:4%eth0] which tells the OS to send the packet via eth0. The bind could be done on a per-interface basis, etc etc. However this patch implements a simple mechanism for dealing with it.

The use-case for this is where a service binding to a port (udp for example) receives a packet from another host via either multicast or unicast and the service wishes to reply then it can be done like so:

```
$socket = socket_create(AF_INET6, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, "::0", 34000);
$return = socket_recvfrom($socket, $buffer, $length, $flags, $from, $port, $ifindex);
socket_sendto($socket, "somereply", strlen("somereply"), $flags, $from, $port, $ifindex);
```

The extra argument ($ifindex) is set when socket_recvfrom is called and then can be passed straight into socket_sendto

Alternatively, this could also be used with socket_connect to then setup a TCP connection via
```
socket_connect($socket, $from, $port, $ifindex);
```

With the ifindex argument, this ensures the packet will exit via an appropriate interface.