ANN: network-socket-options 0.1

I added a new package containing wrappers for getsockopt and setsockopt: http://hackage.haskell.org/package/network-socket-options The network package already has getSocketOption and setSocketOption. The problem is, these don't work for socket options that aren't represented by integers, such as SO_LINGER: http://trac.haskell.org/network/ticket/23 Another, less serious problem is that getSocketOption and setSocketOption don't leverage the type system as well as they could. Many options are boolean values; it'd be better to get and set them with 'Bool's instead of 'Int's. network-socket-options implements options using getter and setter functions, e.g.: getLinger :: HasSocket sock => sock -> IO (Maybe Seconds) setLinger :: HasSocket sock => sock -> Maybe Seconds -> IO () type Seconds = Int The HasSocket type class is defined to overload the getters and setters to work on raw file descriptors, not just Socket objects. This functionality should probably go in the network package itself. However, I decided to release it as a separate package so I could start using it sooner. If people like it enough, perhaps the network package can absorb it, as was done with network-bytestring. -Joey Adams

On 21 February 2012 14:57, Joey Adams
I added a new package containing wrappers for getsockopt and setsockopt:
http://hackage.haskell.org/package/network-socket-options
The network package already has getSocketOption and setSocketOption. The problem is, these don't work for socket options that aren't represented by integers, such as SO_LINGER:
http://trac.haskell.org/network/ticket/23
Another, less serious problem is that getSocketOption and setSocketOption don't leverage the type system as well as they could. Many options are boolean values; it'd be better to get and set them with 'Bool's instead of 'Int's.
network-socket-options implements options using getter and setter functions, e.g.:
getLinger :: HasSocket sock => sock -> IO (Maybe Seconds)
setLinger :: HasSocket sock => sock -> Maybe Seconds -> IO ()
type Seconds = Int
The HasSocket type class is defined to overload the getters and setters to work on raw file descriptors, not just Socket objects.
This functionality should probably go in the network package itself. However, I decided to release it as a separate package so I could start using it sooner. If people like it enough, perhaps the network package can absorb it, as was done with network-bytestring.
Hi Joey, awesome! I've prepared some patches for network to add this module and its tests, in this branch: https://github.com/kfish/network/tree/options I didn't modify any other modules, perhaps Network.Socket.Options should be re-exported from Network.Socket, and perhaps {get,set}SocketOption should be deprecated? network$ autoreconf network$ cabal configure --enable-tests network$ cabal build network$ cabal test Running 3 test suites... Test suite options: RUNNING... Test suite options: PASS Test suite logged to: dist/test/network-2.3.0.11-options.log Test suite uri: RUNNING... Test suite uri: PASS Test suite logged to: dist/test/network-2.3.0.11-uri.log Test suite simple: RUNNING... Test suite simple: PASS Test suite logged to: dist/test/network-2.3.0.11-simple.log 3 of 3 test suites (3 of 3 test cases) passed. Conrad.

On Tue, Feb 21, 2012 at 7:36 PM, Conrad Parker
awesome! I've prepared some patches for network to add this module and its tests, in this branch:
Cool, thanks!
I didn't modify any other modules, perhaps Network.Socket.Options should be re-exported from Network.Socket, and perhaps {get,set}SocketOption should be deprecated?
I agree with deprecating getSocketOption and setSocketOption. Don't remove them, just deprecate them. Network.Socket.Options doesn't implement all of the options {get,set}SocketOption has, yet (e.g. RecvLowWater). I'm not sure about re-exporting Network.Socket.Options, though. That's a lot to dump into the namespace. Particularly worrisome names include: * getError * getType Note the following: * I'm going to release network-socket-options 0.1.1 pretty soon. It will add higher-level functions for setting socket timeouts, to work around the lack of a proper IO manager for Windows: http://trac.haskell.org/network/ticket/2 http://trac.haskell.org/network/ticket/31#comment:1 * Network.Socket has a getPeerCred function, which gets the SO_PEERCRED socket option. Perhaps it should be moved to Network.Socket.Options (re-exported in Network.Socket for backward compatibility) and generalized with HasSocket like the other options. * A couple of the tests in my test suite require root access. Consider them optional, as they cover ground already pretty well-covered by the other tests. Thanks for the integration work. -Joey

I released network-socket-options 0.2, adding setSocketTimeouts and setHandleTimeouts. I'll post an announcement in a separate thread once the Haddock documentation is generated. -Joey

Hi Conrad and Joey,
On Tue, Feb 21, 2012 at 4:36 PM, Conrad Parker
awesome! I've prepared some patches for network to add this module and its tests, in this branch:
https://github.com/kfish/network/tree/options
I didn't modify any other modules, perhaps Network.Socket.Options should be re-exported from Network.Socket, and perhaps {get,set}SocketOption should be deprecated?
I think that makes sense. The API looks fine except: HasSocket - I don't think we want to abstract over sockets here, as we don't do so in the rest of the module. Seconds and Microseconds - These seem a bit misplaced here. I'd say so with Int. setHandleTimeout - If we want to keep it at all it should go in Network and not be conditionally exported. timeouts - we need to think about how this interacts with the I/O manager and provide a consistent API across platforms. I suggest we leave them out until we have done so. I've thought about doing this change before, but I didn't have time to fully explore the design space. I'm happy to accept these patches if someone does that for me. :) In particular: * Should we use an algebraic data type to represent options? I don't think so, for the reason pointed out in one of the source code comments in Joey's library. * Are we covering all possible options? Can there be custom options that can no longer be set by the user since we're enumerating a fixed set of options? * Are there any other design trade-offs? Someone needs to read the getsockopt and setsockopt man pages thoroughly and make sure we cover all the cases. * Are we covering all major OSes in the API? -- Johan

Thanks for the review!
On Wed, Feb 22, 2012 at 11:15 AM, Johan Tibell
The API looks fine except:
HasSocket - I don't think we want to abstract over sockets here, as we don't do so in the rest of the module.
I know it's a bit ugly, but not having it makes it hard to work with unmanaged sockets (e.g. those buried under Handles). If the functions take a managed Socket, you'd have to say something like: setRecvTimeout (MkSocket fd undefined undefined undefined undefined) 120000000 If they take CInt instead, users of the higher-level API would have to say: setRecvTimeout (fdSocket sock) 120000000 Perhaps representing options with ADTs isn't such a bad idea after all. That way, we could have something like: setSocketOption :: SetSockOpt opt => Socket -> opt -> IO () setRawSocketOption :: SetSockOpt opt => CInt -> opt -> IO () Usage might look like: setSocketOption sock $ RecvTimeout 120000000 Type t <- getSocketOption sock
Seconds and Microseconds - These seem a bit misplaced here. I'd say so with Int.
I use Int64 for Microseconds, to avoid truncation when Int is 32 bits. 2^31-1 microseconds is only 35 minutes and 47.483647 seconds. Perhaps I should just use Int and Int64, and be sure to document what units are used. It'd be nice to use a strongly-typed time package like time-units, but: * It involves conversion to and from Integer * It doesn't tell the whole story. Most quantity values in socket options are truncated and even modified for OS-specific reasons.
setHandleTimeout - If we want to keep it at all it should go in Network and not be conditionally exported.
I agree. setHandleTimeouts should simply be a no-op on non-GHC.
timeouts - we need to think about how this interacts with the I/O manager and provide a consistent API across platforms. I suggest we leave them out until we have done so.
The ideal solution would be to not even need these. GHC ought to have proper IO manager support for Windows, or at least use socket timeouts or similar to prevent OS threads from hanging indefinitely on IO operations. setHandleTimeouts is a workaround, and will be deprecated as soon as it is no longer necessary.
I've thought about doing this change before, but I didn't have time to fully explore the design space. I'm happy to accept these patches if someone does that for me. :)
In particular:
* Should we use an algebraic data type to represent options? I don't think so, for the reason pointed out in one of the source code comments in Joey's library.
We can separate getters and setters using typeclasses GetSockOpt and SetSockOpt, and having newtype wrappers for each socket option. See my setSocketOption example above. I would do this, but I have other things I need to work on.
* Are we covering all possible options? Can there be custom options that can no longer be set by the user since we're enumerating a fixed set of options? * Are there any other design trade-offs? Someone needs to read the getsockopt and setsockopt man pages thoroughly and make sure we cover all the cases. * Are we covering all major OSes in the API?
network-socket-options isn't comprehensive. It currently should have all of the SOL_SOCKET and IPPROTO_TCP options present in both Linux and Windows. It compiles on both. I haven't tested on Mac OS X or FreeBSD. I think it'd be better to start with at least some options, and add more as users ask for them. One problem with adding every option we possibly can right now is that none of the options will get documented. If a user asks for a specific option and provides a reason for needing it, we can include this information in the documentation. -Joey

Hi,
On Wed, Feb 22, 2012 at 10:43 AM, Joey Adams
I know it's a bit ugly, but not having it makes it hard to work with unmanaged sockets (e.g. those buried under Handles). If the functions take a managed Socket, you'd have to say something like:
setRecvTimeout (MkSocket fd undefined undefined undefined undefined) 120000000
If they take CInt instead, users of the higher-level API would have to say:
setRecvTimeout (fdSocket sock) 120000000
But the network package doesn't try to let you work with raw file descriptors elsewhere (e.g. send and recv.) I'm not saying that functions on Fds aren't useful, they are, just that the network package is the wrong place for them. I'd put them in the unix package.
I use Int64 for Microseconds, to avoid truncation when Int is 32 bits. 2^31-1 microseconds is only 35 minutes and 47.483647 seconds. Perhaps I should just use Int and Int64, and be sure to document what units are used.
We should use whatever the underlying OS uses. If that's a 32-bit int, using a 64-bit int on the Haskell side doesn't help us. The goal here is to faithfully match the underlying APIs.
network-socket-options isn't comprehensive. It currently should have all of the SOL_SOCKET and IPPROTO_TCP options present in both Linux and Windows. It compiles on both. I haven't tested on Mac OS X or FreeBSD.
I think it'd be better to start with at least some options, and add more as users ask for them. One problem with adding every option we possibly can right now is that none of the options will get documented. If a user asks for a specific option and provides a reason for needing it, we can include this information in the documentation.
Starting small is fine, but we should think ahead so we don't paint ourselves into a corner. As long as it's possible to add other options in a natural way, it's fine. -- Johan

On Wed, Feb 22, 2012 at 10:23 PM, Johan Tibell
But the network package doesn't try to let you work with raw file descriptors elsewhere (e.g. send and recv.) I'm not saying that functions on Fds aren't useful, they are, just that the network package is the wrong place for them. I'd put them in the unix package.
Putting them in the unix package means they won't be available for Windows (where I needed them the most).
I use Int64 for Microseconds, to avoid truncation when Int is 32 bits. 2^31-1 microseconds is only 35 minutes and 47.483647 seconds. Perhaps I should just use Int and Int64, and be sure to document what units are used.
We should use whatever the underlying OS uses. If that's a 32-bit int, using a 64-bit int on the Haskell side doesn't help us. The goal here is to faithfully match the underlying APIs.
For SO_RCVTIMEO and SO_SNDTIMEO, Windows and Unix use different representations. Windows uses DWORD (unsigned 32-bit) milliseconds, while Unix uses struct timeval, which has microsecond precision. -Joey

On 24 February 2012 01:01, Joey Adams
On Wed, Feb 22, 2012 at 10:23 PM, Johan Tibell
wrote: But the network package doesn't try to let you work with raw file descriptors elsewhere (e.g. send and recv.) I'm not saying that functions on Fds aren't useful, they are, just that the network package is the wrong place for them. I'd put them in the unix package.
Putting them in the unix package means they won't be available for Windows (where I needed them the most).
what about unix-compat (and making that a dep of network)? Conrad.
participants (3)
-
Conrad Parker
-
Joey Adams
-
Johan Tibell