php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #72733 It would be nice to have something like getaddrinfo.
Submitted: 2016-08-02 13:28 UTC Modified: 2016-10-25 13:16 UTC
From: email at davekok dot nl Assigned:
Status: Closed Package: Sockets related
PHP Version: 7.2 OS: Any
Private report: No CVE-ID: None
 [2016-08-02 13:28 UTC] email at davekok dot nl
Description:
------------
Currently it is rather hard to support both IPv4 and IPv6 in PHP when using sockets. It would be rather nice if getaddrinfo system function would be available to PHP scripts. If have yet to find a alternative for PHP that works just as clean.


Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-08-03 23:06 UTC] dave at mudsite dot com
I'm not certain I'm following what is hard about supporting both.  socket_create()'s first argument allows you to choose to have this socket be an AF_INET or AF_INET6.  Unless you're attempting to pull information about a host wherein you can get all addresses about a host for a specific purpose a-la: http://www.logix.cz/michal/devel/various/getaddrinfo.c.xp
 [2016-08-07 04:12 UTC] kalle@php.net
-Status: Open +Status: Feedback
 [2016-08-07 04:12 UTC] kalle@php.net
Could you expand your idea with some code examples of what you do now and how you propose a solution to visualize this some more?
 [2016-08-07 07:02 UTC] email at davekok dot nl
-Status: Feedback +Status: Open
 [2016-08-07 07:02 UTC] email at davekok dot nl
That is indeed the point. Mostly I only have a hostname, not an IP address and knowing whether a hostname supports or requires IPv6 is hard to find out. It requires you to do your own DNS queries. There is no gethostbyname for IPv6 in PHP.

A simple socket wrapper could look something like this with getaddrinfo.

  <?php

  class Socket {
    private $address;
    private $socket;

    public function __construct(string $host, string $service) {
      $addresses = socket_addrinfo($host, $service, [
        "ai_family"=>PF_UNSPEC,
        "ai_socktype"=>SOCK_STREAM
      ]);
      if ($addresses === false) throw new Exception("host not found");
      $this->address = reset($addresses);
      $this->socket = socket_create(
        $address["ai_family"],
        $address["ai_socktype"],
        $address["ai_protocol"]
      );
      if (!$this->socket) throw new Exception("error creating socket");
    }

    public function bind() {
      socket_bind($this->socket, $this->address["ai_addr"]);
    }

    public function listen(int $backlog = 0) {
      socket_listen($this->socket, $backlog);
    }

    public function connect() {
      socket_connect($this->socket, $this->address["ai_addr"]);
    }

    // other socket stuff
  }

As an additional benefit you don't even need to know the port number you can just use the service name.
 [2016-08-07 07:19 UTC] email at davekok dot nl
Oh perhaps it would have been a better example if the socket type hint would also by in the constructor.
 [2016-08-07 19:41 UTC] dave at mudsite dot com
I took a stab at this(https://github.com/bp1222/php-src/commit/785284cdbc8a46d7c1b07567bb0d06d348112684).  implementing a 

array socket_getaddrinfo(string $node, mixed $service[, array $hints])

This attempt returns an array of resources, each resource being a C addrinfo struct.  To use, I just made a socket_addrinfo_connect and socket_addrinfo_bind to accept the resource to connect/bind.

Although in your desired example, you'd want to just have an array of info from addrinfo returned, and you call create&connect/bind with returned variables.

Not sure if one would be preferable over the other, I would assume implementing your use would be better as it wouldn't require resources & would be a couple less functions declared.
 [2016-08-08 15:41 UTC] email at davekok dot nl
I would indeed prefer an array to be returned rather then a resource with a additional functions. Otherwise great work!!
 [2016-08-10 03:11 UTC] dave at mudsite dot com
After playing around a bit I think the resource means is preferable.  I'm sure discussions on the merits of both will be raised though RFC process[1].  I feel the resource method is superior because it's the actual sockaddr structure behind it.  So if you do a getaddrinfo("127.0.0.1", "ssh", NULL), the sockaddr structure already has into it the correct port to use.  Whereas the addrinfo structure doesn't contain the port you're looking for.  Your example uses `$this->address["ai_addr"]`, however, ai_addr isn't a port number like you're using it.  It's the sockaddr structure.  So I envision the typical array-return to look weird like this:

<?php
$infos = socket_getaddrinfo('127.0.0.1', 'ssh', array(
    'ai_family' => AF_INET,
    'ai_socktype' => SOCK_STREAM
));
$info = reset($infos);
$sock = socket_create(
    $address["ai_family"],
    $address["ai_socktype"],
    $address["ai_protocol"]
);
socket_bind($sock, 22);


Whereas a resource based implementation could be:<?php
$infos = socket_getaddrinfo('127.0.0.1', 'ssh', array(
    'ai_family' => AF_INET,
    'ai_socktype' => SOCK_STREAM
));
$info = reset($infos);
$sock = socket_addrinfo_bind($info);


But I digress.

[1] - Draft RFC: https://wiki.php.net/rfc/socket_getaddrinfo
 [2016-08-10 11:35 UTC] email at davekok dot nl
I think it would be useful if the socket api remains as much as possible similar to how it is known in other languages. So the second where socket_bind and socket_listen are used to receive a addrinfo resource would be my preference.

Is there any reason to add a socket_addrinfo_close function. Can this not be garbage collected?
 [2016-08-10 11:44 UTC] email at davekok dot nl
If at all possible I still like the array approach. As this allows the PHP programmer access to the information within the addrinfo struct. Could socket_create, socket_bind and socket_listen not be modified to also allow an array? I have no problem with having to also specify the socket resource separately. Hiding this in a addrinfo resource seems wrong somehow.

If a resource is used instead of an array. Information functions to retrieve the information within would be very much appreciated.
 [2016-08-11 03:15 UTC] dave at mudsite dot com
I see what you're looking for.  I've gone ahead and did a 3rd attempt at this guy with the use of:

    $addrinfo = socket_getaddrinfo('127.0.0.1', 2000, array(
        'ai_family' => AF_INET,
        'ai_socktype' => SOCK_STREAM,
    ));

    echo "Server: Starting\n";

    $info = reset($addrinfo);
    $sock = socket_create($info['ai_family'], $info['ai_socktype'], $info['ai_protocol']);
    if ($sock) {
        socket_bind($sock, $info['ai_addr']) or die("Could not bind");
        socket_listen($sock) or die("Could not listen");

$info['ai_addr'] here is a resource of the underlying sockaddr structure.  I foresee this implementation a bit more contentious to advocate.  Due to the fact that socket_connect, and socket_bind change signatures from

  socket_(connect/bind) (resource $sock, string $address[, int port])
to being
  socket_(connect/bind) (resource $sock, mixed $arg[, int port])
  where $arg can be string address where 3rd argument is used
  or
  where $args is resource of sockaddr and 3rd arg is ignored


I'll make sure to document all this for the RFC and see what everyone has to say about it.
 [2016-08-12 08:09 UTC] email at davekok dot nl
I love this final version. Having $info['ai_addr'] be a resource is excellent. However I suspect someone if not me will request to add a function that can take this resource and return the IP address and port. Properly something to consider. Otherwise I am really happy with this version.
 [2016-09-02 18:13 UTC] cmb@php.net
Automatic comment on behalf of dave@mudsite.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7373ce914914e9a434216554a7e29aa4d1775d97
Log: Fix #72733: Expose getaddrinfo C function, and supporting connect/bind
 [2016-09-02 18:13 UTC] cmb@php.net
-Status: Open +Status: Closed
 [2016-10-10 11:17 UTC] krakjoe@php.net
Automatic comment on behalf of dave@mudsite.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7373ce914914e9a434216554a7e29aa4d1775d97
Log: Fix #72733: Expose getaddrinfo C function, and supporting connect/bind
 [2016-10-25 13:16 UTC] email at davekok dot nl
-PHP Version: 7.0.9 +PHP Version: 7.2
 [2016-10-25 13:16 UTC] email at davekok dot nl
Btw, missing from the implementation is a way to set that the socket port should be reusable. Any change that can be added somehow. Perhaps a second parameter to socket_addrinfo_bind containing an array of socket options? As far as I know the SO_REUSEADDR has to be set before bind is called.
 [2017-01-12 09:12 UTC] krakjoe@php.net
Automatic comment on behalf of dave@mudsite.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=7373ce914914e9a434216554a7e29aa4d1775d97
Log: Fix #72733: Expose getaddrinfo C function, and supporting connect/bind
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Wed Sep 30 16:01:24 2020 UTC