@@ -26,6 +26,7 @@ module Network.Socket.Options (
26
26
, getSockOpt
27
27
, setSockOpt
28
28
, StructLinger (.. )
29
+ , SocketTimeout (.. )
29
30
) where
30
31
31
32
import qualified Text.Read as P
@@ -38,7 +39,9 @@ import Network.Socket.Internal
38
39
import Network.Socket.Types
39
40
import Network.Socket.ReadShow
40
41
41
- -----------------------------------------------------------------------------
42
+ #include <sys/time.h>
43
+
44
+ ----------------------------------------------------------------
42
45
-- Socket Properties
43
46
44
47
-- | Socket options for use with 'setSocketOption' and 'getSocketOption'.
@@ -55,18 +58,75 @@ data SocketOption = SockOpt
55
58
#endif
56
59
deriving (Eq )
57
60
61
+ ----------------------------------------------------------------
62
+
63
+ socketOptionBijection :: Bijection SocketOption String
64
+ socketOptionBijection =
65
+ [ (UnsupportedSocketOption , " UnsupportedSocketOption" )
66
+ , (Debug , " Debug" )
67
+ , (ReuseAddr , " ReuseAddr" )
68
+ , (SoDomain , " SoDomain" )
69
+ , (Type , " Type" )
70
+ , (SoProtocol , " SoProtocol" )
71
+ , (SoError , " SoError" )
72
+ , (DontRoute , " DontRoute" )
73
+ , (Broadcast , " Broadcast" )
74
+ , (SendBuffer , " SendBuffer" )
75
+ , (RecvBuffer , " RecvBuffer" )
76
+ , (KeepAlive , " KeepAlive" )
77
+ , (OOBInline , " OOBInline" )
78
+ , (Linger , " Linger" )
79
+ , (ReusePort , " ReusePort" )
80
+ , (RecvLowWater , " RecvLowWater" )
81
+ , (SendLowWater , " SendLowWater" )
82
+ , (RecvTimeOut , " RecvTimeOut" )
83
+ , (SendTimeOut , " SendTimeOut" )
84
+ , (UseLoopBack , " UseLoopBack" )
85
+ , (MaxSegment , " MaxSegment" )
86
+ , (NoDelay , " NoDelay" )
87
+ , (UserTimeout , " UserTimeout" )
88
+ , (Cork , " Cork" )
89
+ , (TimeToLive , " TimeToLive" )
90
+ , (RecvIPv4TTL , " RecvIPv4TTL" )
91
+ , (RecvIPv4TOS , " RecvIPv4TOS" )
92
+ , (RecvIPv4PktInfo , " RecvIPv4PktInfo" )
93
+ , (IPv6Only , " IPv6Only" )
94
+ , (RecvIPv6HopLimit , " RecvIPv6HopLimit" )
95
+ , (RecvIPv6TClass , " RecvIPv6TClass" )
96
+ , (RecvIPv6PktInfo , " RecvIPv6PktInfo" )
97
+ ]
98
+
99
+ instance Show SocketOption where
100
+ showsPrec = bijectiveShow socketOptionBijection def
101
+ where
102
+ defname = " SockOpt"
103
+ unwrap = \ (CustomSockOpt nm) -> nm
104
+ def = defShow defname unwrap showIntInt
105
+
106
+
107
+ instance Read SocketOption where
108
+ readPrec = bijectiveRead socketOptionBijection def
109
+ where
110
+ defname = " SockOpt"
111
+ def = defRead defname CustomSockOpt readIntInt
112
+
113
+ ----------------------------------------------------------------
114
+
115
+ pattern UnsupportedSocketOption :: SocketOption
116
+ pattern UnsupportedSocketOption = SockOpt (- 1 ) (- 1 )
117
+
58
118
-- | Does the 'SocketOption' exist on this system?
59
119
isSupportedSocketOption :: SocketOption -> Bool
60
120
isSupportedSocketOption opt = opt /= SockOpt (- 1 ) (- 1 )
61
121
62
- -- | Get the 'SocketType' of an active socket.
63
- --
64
- -- Since: 3.0.1.0
65
- getSocketType :: Socket -> IO SocketType
66
- getSocketType s = unpackSocketType <$> getSockOpt s Type
122
+ -- | Execute the given action only when the specified socket option is
123
+ -- supported. Any return value is ignored.
124
+ whenSupported :: SocketOption -> IO a -> IO ()
125
+ whenSupported s action
126
+ | isSupportedSocketOption s = action >> return ()
127
+ | otherwise = return ()
67
128
68
- pattern UnsupportedSocketOption :: SocketOption
69
- pattern UnsupportedSocketOption = SockOpt (- 1 ) (- 1 )
129
+ ----------------------------------------------------------------
70
130
71
131
#ifdef SOL_SOCKET
72
132
-- | SO_ACCEPTCONN, read-only
@@ -192,14 +252,14 @@ pattern SendLowWater = SockOpt (#const SOL_SOCKET) (#const SO_SNDLOWAT)
192
252
#else
193
253
pattern SendLowWater = SockOpt (- 1 ) (- 1 )
194
254
#endif
195
- -- | SO_RCVTIMEO: this does not work at this moment.
255
+ -- | SO_RCVTIMEO: timeout in microseconds
196
256
pattern RecvTimeOut :: SocketOption
197
257
#ifdef SO_RCVTIMEO
198
258
pattern RecvTimeOut = SockOpt (# const SOL_SOCKET ) (# const SO_RCVTIMEO )
199
259
#else
200
260
pattern RecvTimeOut = SockOpt (- 1 ) (- 1 )
201
261
#endif
202
- -- | SO_SNDTIMEO: this does not work at this moment.
262
+ -- | SO_SNDTIMEO: timeout in microseconds
203
263
pattern SendTimeOut :: SocketOption
204
264
#ifdef SO_SNDTIMEO
205
265
pattern SendTimeOut = SockOpt (# const SOL_SOCKET ) (# const SO_SNDTIMEO )
@@ -317,41 +377,7 @@ pattern CustomSockOpt xy <- ((\(SockOpt x y) -> (x, y)) -> xy)
317
377
where
318
378
CustomSockOpt (x, y) = SockOpt x y
319
379
320
- #if __GLASGOW_HASKELL__ >= 806
321
- {-# COMPLETE CustomSockOpt #-}
322
- #endif
323
- #ifdef SO_LINGER
324
- -- | Low level 'SO_LINBER' option value, which can be used with 'setSockOpt'.
325
- --
326
- data StructLinger = StructLinger {
327
- -- | Set the linger option on.
328
- sl_onoff :: CInt ,
329
-
330
- -- | Linger timeout.
331
- sl_linger :: CInt
332
- }
333
- deriving (Eq , Ord , Show )
334
-
335
- instance Storable StructLinger where
336
- sizeOf _ = (# const sizeof(struct linger))
337
- alignment _ = alignment (0 :: CInt )
338
-
339
- peek p = do
340
- onoff <- (# peek struct linger, l_onoff) p
341
- linger <- (# peek struct linger, l_linger) p
342
- return $ StructLinger onoff linger
343
-
344
- poke p (StructLinger onoff linger) = do
345
- (# poke struct linger, l_onoff) p onoff
346
- (# poke struct linger, l_linger) p linger
347
- #endif
348
-
349
- -- | Execute the given action only when the specified socket option is
350
- -- supported. Any return value is ignored.
351
- whenSupported :: SocketOption -> IO a -> IO ()
352
- whenSupported s action
353
- | isSupportedSocketOption s = action >> return ()
354
- | otherwise = return ()
380
+ ----------------------------------------------------------------
355
381
356
382
-- | Set a socket option that expects an 'Int' value.
357
383
setSocketOption :: Socket
@@ -363,6 +389,8 @@ setSocketOption s so@Linger v = do
363
389
let arg = if v == 0 then StructLinger 0 0 else StructLinger 1 (fromIntegral v)
364
390
setSockOpt s so arg
365
391
#endif
392
+ setSocketOption s so@ RecvTimeOut v = setSockOpt s so $ SocketTimeout $ fromIntegral v
393
+ setSocketOption s so@ SendTimeOut v = setSockOpt s so $ SocketTimeout $ fromIntegral v
366
394
setSocketOption s sa v = setSockOpt s sa (fromIntegral v :: CInt )
367
395
368
396
-- | Set a socket option.
@@ -378,6 +406,8 @@ setSockOpt s (SockOpt level opt) v = do
378
406
throwSocketErrorIfMinus1_ " Network.Socket.setSockOpt" $
379
407
c_setsockopt fd level opt ptr sz
380
408
409
+ ----------------------------------------------------------------
410
+
381
411
-- | Get a socket option that gives an 'Int' value.
382
412
getSocketOption :: Socket
383
413
-> SocketOption -- Option Name
@@ -387,6 +417,12 @@ getSocketOption s so@Linger = do
387
417
StructLinger onoff linger <- getSockOpt s so
388
418
return $ fromIntegral $ if onoff == 0 then 0 else linger
389
419
#endif
420
+ getSocketOption s so@ RecvTimeOut = do
421
+ SocketTimeout to <- getSockOpt s so
422
+ return $ fromIntegral to
423
+ getSocketOption s so@ SendTimeOut = do
424
+ SocketTimeout to <- getSockOpt s so
425
+ return $ fromIntegral to
390
426
getSocketOption s so = do
391
427
n :: CInt <- getSockOpt s so
392
428
return $ fromIntegral n
@@ -404,56 +440,75 @@ getSockOpt s (SockOpt level opt) = do
404
440
c_getsockopt fd level opt ptr ptr_sz
405
441
peek ptr
406
442
443
+ ----------------------------------------------------------------
407
444
408
- socketOptionBijection :: Bijection SocketOption String
409
- socketOptionBijection =
410
- [ (UnsupportedSocketOption , " UnsupportedSocketOption" )
411
- , (Debug , " Debug" )
412
- , (ReuseAddr , " ReuseAddr" )
413
- , (SoDomain , " SoDomain" )
414
- , (Type , " Type" )
415
- , (SoProtocol , " SoProtocol" )
416
- , (SoError , " SoError" )
417
- , (DontRoute , " DontRoute" )
418
- , (Broadcast , " Broadcast" )
419
- , (SendBuffer , " SendBuffer" )
420
- , (RecvBuffer , " RecvBuffer" )
421
- , (KeepAlive , " KeepAlive" )
422
- , (OOBInline , " OOBInline" )
423
- , (Linger , " Linger" )
424
- , (ReusePort , " ReusePort" )
425
- , (RecvLowWater , " RecvLowWater" )
426
- , (SendLowWater , " SendLowWater" )
427
- , (RecvTimeOut , " RecvTimeOut" )
428
- , (SendTimeOut , " SendTimeOut" )
429
- , (UseLoopBack , " UseLoopBack" )
430
- , (MaxSegment , " MaxSegment" )
431
- , (NoDelay , " NoDelay" )
432
- , (UserTimeout , " UserTimeout" )
433
- , (Cork , " Cork" )
434
- , (TimeToLive , " TimeToLive" )
435
- , (RecvIPv4TTL , " RecvIPv4TTL" )
436
- , (RecvIPv4TOS , " RecvIPv4TOS" )
437
- , (RecvIPv4PktInfo , " RecvIPv4PktInfo" )
438
- , (IPv6Only , " IPv6Only" )
439
- , (RecvIPv6HopLimit , " RecvIPv6HopLimit" )
440
- , (RecvIPv6TClass , " RecvIPv6TClass" )
441
- , (RecvIPv6PktInfo , " RecvIPv6PktInfo" )
442
- ]
445
+ -- | Get the 'SocketType' of an active socket.
446
+ --
447
+ -- Since: 3.0.1.0
448
+ getSocketType :: Socket -> IO SocketType
449
+ getSocketType s = unpackSocketType <$> getSockOpt s Type
443
450
444
- instance Show SocketOption where
445
- showsPrec = bijectiveShow socketOptionBijection def
446
- where
447
- defname = " SockOpt"
448
- unwrap = \ (CustomSockOpt nm) -> nm
449
- def = defShow defname unwrap showIntInt
451
+ ----------------------------------------------------------------
450
452
453
+ #if __GLASGOW_HASKELL__ >= 806
454
+ {-# COMPLETE CustomSockOpt #-}
455
+ #endif
456
+ #ifdef SO_LINGER
457
+ -- | Low level 'SO_LINBER' option value, which can be used with 'setSockOpt'.
458
+ --
459
+ data StructLinger = StructLinger {
460
+ -- | Set the linger option on.
461
+ sl_onoff :: CInt ,
451
462
452
- instance Read SocketOption where
453
- readPrec = bijectiveRead socketOptionBijection def
454
- where
455
- defname = " SockOpt"
456
- def = defRead defname CustomSockOpt readIntInt
463
+ -- | Linger timeout.
464
+ sl_linger :: CInt
465
+ }
466
+ deriving (Eq , Ord , Show )
467
+
468
+ instance Storable StructLinger where
469
+ sizeOf _ = (# const sizeof(struct linger))
470
+ alignment _ = alignment (0 :: CInt )
471
+
472
+ peek p = do
473
+ onoff <- (# peek struct linger, l_onoff) p
474
+ linger <- (# peek struct linger, l_linger) p
475
+ return $ StructLinger onoff linger
476
+
477
+ poke p (StructLinger onoff linger) = do
478
+ (# poke struct linger, l_onoff) p onoff
479
+ (# poke struct linger, l_linger) p linger
480
+ #endif
481
+
482
+ ----------------------------------------------------------------
483
+
484
+ -- | Timeout in microseconds.
485
+ -- This will be converted into struct timeval on Unix and
486
+ -- DWORD (as milliseconds) on Windows.
487
+ newtype SocketTimeout = SocketTimeout Word32 deriving (Eq , Ord , Show )
488
+
489
+ #if defined(mingw32_HOST_OS)
490
+ instance Storable SocketTimeout where
491
+ sizeOf (SocketTimeout to) = sizeOf to -- DWORD as milliseconds
492
+ alignment _ = 0
493
+ peek ptr = do
494
+ to <- peek (castPtr ptr)
495
+ return $ SocketTimeout (to * 1000 )
496
+ poke ptr (SocketTimeout to) = poke (castPtr ptr) (to `div` 1000 )
497
+ #else
498
+ instance Storable SocketTimeout where
499
+ sizeOf _ = (# size struct timeval)
500
+ alignment _ = (# const offsetof(struct {char x__; struct timeval (y__); }, y__))
501
+ peek ptr = do
502
+ sec <- (# peek struct timeval, tv_sec) ptr
503
+ usec <- (# peek struct timeval, tv_usec) ptr
504
+ return $ SocketTimeout (sec * 1000000 + usec)
505
+ poke ptr (SocketTimeout to) = do
506
+ let (sec, usec) = to `divMod` 1000000
507
+ (# poke struct timeval, tv_sec) ptr sec
508
+ (# poke struct timeval, tv_usec) ptr usec
509
+ #endif
510
+
511
+ ----------------------------------------------------------------
457
512
458
513
foreign import CALLCONV unsafe " getsockopt"
459
514
c_getsockopt :: CInt -> CInt -> CInt -> Ptr a -> Ptr CInt -> IO CInt
0 commit comments