Skip to content

Network 2.8 missing conversions for Socket family and type. #427

Description

@vdukhovni

In Network 2.8, it is difficult to create a new socket of the same shape as an existing socket due to missing interfaces. In C, I can do this via:

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>

typedef int SOCKET; /* Unix */
#define INVALID_SOCKET ((SOCKET)-1);

SOCKET cloneSocket(SOCKET s)
{
    struct sockaddr_storage saddr;
    struct sockaddr *sa = (struct sockaddr *)&saddr;
    socklen_t len;
    SOCKET s2 = INVALID_SOCKET;
    int stype;
    int sproto;

    len = sizeof(stype);
    if (getsockopt(s, SOL_SOCKET, SO_TYPE, &stype, &len) == -1 ||
        getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &sproto, &len) == -1)
        return s2;

    len = sizeof(saddr);
    memset(&saddr, 0, len);
    if (getsockname(s, sa, &len) != -1)
        s2 = socket(sa->sa_family, stype, sproto);

    return s2;
}

But Network.Socket does not export a way to recover the address family of a socket other than case matching the constructor, and no way to map the integer returned from (getSocketOption sock Type) back to a SocketType that can be used to create a new socket, and SO_PROTOCOL is missing entirely, so one can simply hope that defaultProtocol is good enough.

As systems evolve and new values for some of these fields are added, the "sum type" representation of these fields creates constant compatibility issues. These could in some cases be much better handled via PatternSynonyms than fixed sum types. Something like the below suitably refined (e.g. Perhaps SocketFamily can be 8 bits on BSD and 16 bits on Linux, with some Haskell type defined accordingly to match the platform's sa_family_t)

{-# LANGUAGE CPP #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

#include <sys/param.h>
#include <sys/socket.h>

module Network.Socket.Types
    ( AddressFamily
        ( AF_INET
        , AF_INET6
        , AF_UNIX
        )
    ) where

import Data.Word

newtype AddressFamily = AddressFamily { packAddressFamily :: Word16 }
        deriving (Eq)

#ifdef AF_INET
pattern AF_INET :: AddressFamily
pattern AF_INET = AddressFamily (#const AF_INET)
#else
pattern AF_INET = AddressFamily 0
#endif

#ifdef AF_INET6
pattern AF_INET6 :: AddressFamily
pattern AF_INET6 = AddressFamily (#const AF_INET6)
#else
pattern AF_INET6 = AddressFamily 0
#endif

#ifdef AF_UNIX
pattern AF_UNIX :: AddressFamily
pattern AF_UNIX = AddressFamily (#const AF_UNIX)
#else
pattern AF_UNIX = AddressFamily 0
#endif

instance Show AddressFamily where
    show AF_INET = "inet"
    show AF_INET6 = "inet6"
    show AF_UNIX = "unix"
    show (AddressFamily n) = "<family" ++ show n ++ ">"

and so on for various similar cases.

Activity

  1. kazu-yamamoto commented on Oct 10, 2019

    @kazu-yamamoto
    Collaborator

    I don't have motivation to improve 2.8 by myself. But if you send a PR, I would love to merge it and @eborden will release a new version.

  2. eborden commented on Oct 14, 2019

    @eborden
    Collaborator

    ☝️ agreed. 2.x is in end of life. PRs are accepted for bug fixes, but we are focusing on 3.x.

  3. eborden commented on Oct 14, 2019

    @eborden
    Collaborator

    @vdukhovni it is also good to note that stackage nightly is on 3.x, which is a good indicator that support will spread across the ecosystem.

  4. vdukhovni commented on Oct 14, 2019

    @vdukhovni
    Author

    The reason I reported an issue with 2.8, is that I am looking to contribute a PR for warp that fixes races in its acceptor loop shutdown logic. And I don't know which version of network might be used by someone building an updated version of warp. Can I assume it will be a 3.x build?

    And in fact, though I've not yet opened a similar issue for 3.x, some of the same sort of usability gaps exist in 3.x. The various sum types in Network don't necessarily have exposed to/from int instances, which then makes some get/set option calls less than useful.

    @kazu-yamamoto asked about what to do for 4.x. My take is that there are some deep structural issues with the API. More structures need to become opaque, and more getter (and as appropriate setter) interfaces provided. Pattern synonyms need to be used to generalize some types away from a fixed list of hoices.

  5. kazu-yamamoto commented on Oct 15, 2019

    @kazu-yamamoto
    Collaborator

    Warp supports both network v2 and v3 currently. But personally, I assume network v3 for Warp.

    If you want to bring big changes to network, v4 is perfectly suitable. For instance, we should change fix #426 probably resulting in breaking backward compatibility.

  6. kazu-yamamoto commented on Apr 8, 2020

    @kazu-yamamoto
    Collaborator

    @vdukhovni I believe that we are ready to accept this proposal. Would you send a PR?

  7. kazu-yamamoto commented on May 19, 2020

    @kazu-yamamoto
    Collaborator

    @vdukhovni If you wan to include this new feature to v3.1.2.0, please send us a PR as soon as possible. You can add this new feature in any new versions.

  8. vdukhovni commented on May 21, 2020

    @vdukhovni
    Author

    OK, I'll try to get that done shortly.

  9. vdukhovni commented on May 25, 2020

    @vdukhovni
    Author

    Thanks for merging #459 . Let me know if you want to make the Read instance of Family more comprehensive...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions