1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
{-# LANGUAGE OverloadedStrings #-}
module Network.Socket.ByteStringSpec (main, spec) where
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)
import Data.Bits
import Data.Maybe
import Control.Monad
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as C
import Network.Socket
import Network.Socket.ByteString
import Network.Test.Common
import System.Environment
import Test.Hspec
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "send" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` testMsg
client sock = send sock testMsg
tcpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock = do
close sock
send sock testMsg `shouldThrow` anyException
tcpTest client server
it "checks -1 correctly on Windows" $ do
sock <- socket AF_INET Stream defaultProtocol
send sock "hello world" `shouldThrow` anyException
describe "sendAll" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` testMsg
client sock = sendAll sock testMsg
tcpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock = do
close sock
sendAll sock testMsg `shouldThrow` anyException
tcpTest client server
describe "sendTo" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` testMsg
client sock addr = sendTo sock testMsg addr
udpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock addr = do
close sock
sendTo sock testMsg addr `shouldThrow` anyException
udpTest client server
describe "sendAllTo" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` testMsg
client sock addr = sendAllTo sock testMsg addr
udpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock addr = do
close sock
sendAllTo sock testMsg addr `shouldThrow` anyException
udpTest client server
describe "sendMany" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` S.append seg1 seg2
client sock = sendMany sock [seg1, seg2]
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
tcpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock = do
close sock
sendMany sock [seg1, seg2] `shouldThrow` anyException
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
tcpTest client server
describe "sendManyTo" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` S.append seg1 seg2
client sock addr = sendManyTo sock [seg1, seg2] addr
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
udpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock addr = do
close sock
sendManyTo sock [seg1, seg2] addr `shouldThrow` anyException
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
udpTest client server
describe "recv" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` testMsg
client sock = send sock testMsg
tcpTest client server
it "throws when closed" $ do
let server sock = do
close sock
recv sock 1024 `shouldThrow` anyException
client sock = send sock testMsg
tcpTest client server
it "can treat overflow" $ do
let server sock = do
seg1 <- recv sock (S.length testMsg - 3)
seg2 <- recv sock 1024
let msg = S.append seg1 seg2
msg `shouldBe` testMsg
client sock = send sock testMsg
tcpTest client server
it "returns empty string at EOF" $ do
let client s = recv s 4096 `shouldReturn` S.empty
server s = shutdown s ShutdownSend
tcpTest client server
it "checks -1 correctly on Windows" $ do
sock <- socket AF_INET Stream defaultProtocol
recv sock 1024 `shouldThrow` anyException
describe "recvFrom" $ do
it "works well" $ do
let server sock = do
(msg, _) <- recvFrom sock 1024
testMsg `shouldBe` msg
client sock = do
addr <- getPeerName sock
sendTo sock testMsg addr
tcpTest client server
it "throws when closed" $ do
let server sock = do
close sock
recvFrom sock 1024 `shouldThrow` anyException
client sock = do
addr <- getPeerName sock
sendTo sock testMsg addr
tcpTest client server
it "can treat overflow" $ do
let server sock = do
(seg1, _) <- recvFrom sock (S.length testMsg - 3)
(seg2, _) <- recvFrom sock 1024
let msg = S.append seg1 seg2
testMsg `shouldBe` msg
client sock = send sock testMsg
tcpTest client server
it "returns empty string at EOF" $ do
let server sock = do
(seg1, _) <- recvFrom sock (S.length testMsg - 3)
seg1 `shouldBe` S.empty
client sock = shutdown sock ShutdownSend
tcpTest client server
describe "sendMsg" $ do
it "works well" $ do
let server sock = recv sock 1024 `shouldReturn` S.append seg1 seg2
client sock addr = sendMsg sock addr [seg1, seg2] [] mempty
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
udpTest client server
it "throws when closed" $ do
let server _ = return ()
client sock addr = do
close sock
sendMsg sock addr [seg1, seg2] [] mempty `shouldThrow` anyException
seg1 = C.pack "This is a "
seg2 = C.pack "test message."
udpTest client server
describe "recvMsg" $ do
it "works well" $ do
let server sock = do
(_, msg, cmsgs, flags) <- recvMsg sock 1024 0 mempty
msg `shouldBe` seg
cmsgs `shouldBe` []
flags `shouldBe` mempty
client sock addr = sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest client server
it "receives truncated flag" $ do
let server sock = do
(_, _, _, flags) <- recvMsg sock (S.length seg - 2) 0 mempty
flags .&. MSG_TRUNC `shouldBe` MSG_TRUNC
client sock addr = sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest client server
it "peek" $ do
let server sock = do
(_, msgs, _, _flags) <- recvMsg sock 1024 0 MSG_PEEK
-- flags .&. MSG_PEEK `shouldBe` MSG_PEEK -- Mac only
(_, msgs', _, _) <- recvMsg sock 1024 0 mempty
msgs `shouldBe` msgs'
client sock addr = sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest client server
it "receives control messages for IPv4" $ do
-- This test behaves strange on AppVeyor and I don't know why so skip
-- TOS for now.
isAppVeyor <- isJust <$> lookupEnv "APPVEYOR"
-- Avoid race condition between the client sending the message and
-- the server finishing its socket configuration. Otherwise the
-- message may be received with default socket options!
serverReady <- newEmptyMVar
let server sock = do
whenSupported RecvIPv4TTL $ setSocketOption sock RecvIPv4TTL 1
whenSupported RecvIPv4PktInfo $ setSocketOption sock RecvIPv4PktInfo 1
whenSupported RecvIPv4TOS $ setSocketOption sock RecvIPv4TOS 1
putMVar serverReady ()
(_, _, cmsgs, _) <- recvMsg sock 1024 128 mempty
whenSupported RecvIPv4PktInfo $
((lookupCmsg CmsgIdIPv4PktInfo cmsgs >>= decodeCmsg) :: Maybe IPv4PktInfo) `shouldNotBe` Nothing
when (not isAppVeyor) $ do
whenSupported RecvIPv4TTL $
((lookupCmsg CmsgIdIPv4TTL cmsgs >>= decodeCmsg) :: Maybe IPv4TTL) `shouldNotBe` Nothing
whenSupported RecvIPv4TOS $
((lookupCmsg CmsgIdIPv4TOS cmsgs >>= decodeCmsg) :: Maybe IPv4TOS) `shouldNotBe` Nothing
client sock addr = takeMVar serverReady >> sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest client server
it "receives control messages for IPv6" $ do
-- Avoid race condition between the client sending the message and
-- the server finishing its socket configuration. Otherwise the
-- message may be received with default socket options!
serverReady <- newEmptyMVar
let server sock = do
whenSupported RecvIPv6HopLimit $ setSocketOption sock RecvIPv6HopLimit 1
whenSupported RecvIPv6TClass $ setSocketOption sock RecvIPv6TClass 1
whenSupported RecvIPv6PktInfo $ setSocketOption sock RecvIPv6PktInfo 1
putMVar serverReady ()
(_, _, cmsgs, _) <- recvMsg sock 1024 128 mempty
whenSupported RecvIPv6HopLimit $
((lookupCmsg CmsgIdIPv6HopLimit cmsgs >>= decodeCmsg) :: Maybe IPv6HopLimit) `shouldNotBe` Nothing
whenSupported RecvIPv6TClass $
((lookupCmsg CmsgIdIPv6TClass cmsgs >>= decodeCmsg) :: Maybe IPv6TClass) `shouldNotBe` Nothing
whenSupported RecvIPv6PktInfo $
((lookupCmsg CmsgIdIPv6PktInfo cmsgs >>= decodeCmsg) :: Maybe IPv6PktInfo) `shouldNotBe` Nothing
client sock addr = takeMVar serverReady >> sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest6 client server
it "receives truncated control messages" $ do
-- Avoid race condition between the client sending the message and
-- the server finishing its socket configuration. Otherwise the
-- message may be received with default socket options!
serverReady <- newEmptyMVar
let server sock = do
whenSupported RecvIPv4TTL $ setSocketOption sock RecvIPv4TTL 1
whenSupported RecvIPv4TOS $ setSocketOption sock RecvIPv4TOS 1
whenSupported RecvIPv4PktInfo $ setSocketOption sock RecvIPv4PktInfo 1
putMVar serverReady ()
(_, _, _, flags) <- recvMsg sock 1024 10 mempty
flags .&. MSG_CTRUNC `shouldBe` MSG_CTRUNC
client sock addr = takeMVar serverReady >> sendTo sock seg addr
seg = C.pack "This is a test message"
udpTest client server
|