Skip to content

Commit 0bd5ce6

Browse files
committed
Add recv and send, using WSARecv and WSASend
1 parent 86d9fb7 commit 0bd5ce6

File tree

3 files changed

+67
-12
lines changed

3 files changed

+67
-12
lines changed

Winsock.hsc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ module Winsock (
66
socket,
77
connect,
88
close,
9+
recvBuf,
10+
sendBuf,
11+
12+
recv,
13+
send,
914
) where
1015

1116
#include <windows.h>
@@ -26,6 +31,9 @@ import qualified IOCP.Manager as Manager
2631

2732
import Control.Applicative ((<$>))
2833
import Control.Monad (void)
34+
import Data.ByteString (ByteString)
35+
import Data.ByteString.Internal (createAndTrim)
36+
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
2937
import Data.IORef
3038
import Data.Word
3139
import Foreign.C
@@ -40,6 +48,8 @@ import qualified System.Win32.Types as Win32
4048
newtype Socket = Socket IOCPHandle
4149
deriving Eq
4250

51+
-- Note: Functions that take a 'Socket' expect WinSock to already be initialized.
52+
4353
socket :: NS.Family -> NS.SocketType -> NS.ProtocolNumber -> IO Socket
4454
socket family stype protocol = do
4555
initWinsock
@@ -69,6 +79,40 @@ close (Socket ih) =
6979
Manager.closeWith ih $
7080
Win32.failIf_ (/= 0) "close" . c_closesocket . castHANDLEToSOCKET
7181

82+
recvBuf :: Socket -> Ptr a -> Int -> IO Int
83+
recvBuf (Socket ih) buf len =
84+
withIOCP ih 0 startCB completionCB
85+
where
86+
startCB h ol =
87+
Win32.failIfFalse_ "recv" $
88+
c_winsock_recv (castHANDLEToSOCKET h) (castPtr buf) (fromIntegral len) ol
89+
90+
completionCB err numBytes
91+
| err == 0 = return (fromIntegral numBytes)
92+
| otherwise = FFI.throwWinErr "recv" err
93+
94+
sendBuf :: Socket -> Ptr a -> Int -> IO Int
95+
sendBuf (Socket ih) buf len =
96+
withIOCP ih 0 startCB completionCB
97+
where
98+
startCB h ol =
99+
Win32.failIfFalse_ "send" $
100+
c_winsock_send (castHANDLEToSOCKET h) (castPtr buf) (fromIntegral len) ol
101+
102+
completionCB err numBytes
103+
| err == 0 = return (fromIntegral numBytes)
104+
| otherwise = FFI.throwWinErr "send" err
105+
106+
recv :: Socket -> Int -> IO ByteString
107+
recv sock len =
108+
createAndTrim len $ \buf ->
109+
recvBuf sock buf len
110+
111+
send :: Socket -> ByteString -> IO Int
112+
send sock bs =
113+
unsafeUseAsCStringLen bs $ \(buf, len) ->
114+
sendBuf sock buf len
115+
72116
newtype Winsock = Winsock (Ptr ())
73117

74118
getWinsock :: IO Winsock
@@ -97,3 +141,9 @@ foreign import ccall unsafe
97141

98142
foreign import WINDOWS_CCONV safe "winsock2.h closesocket"
99143
c_closesocket :: SOCKET -> IO CInt
144+
145+
foreign import ccall unsafe
146+
c_winsock_recv :: SOCKET -> Ptr CChar -> #{type u_long} -> LPOVERLAPPED -> IO BOOL
147+
148+
foreign import ccall unsafe
149+
c_winsock_send :: SOCKET -> Ptr CChar -> #{type u_long} -> LPOVERLAPPED -> IO BOOL

cbits/Winsock.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,18 +104,6 @@ Winsock *c_winsock_init(void)
104104
return NULL;
105105
}
106106

107-
static BOOL bind_inet(SOCKET sock, ULONG address, USHORT port)
108-
{
109-
struct sockaddr_in addr;
110-
int rc;
111-
memset(&addr, 0, sizeof(addr));
112-
addr.sin_family = AF_INET;
113-
addr.sin_addr.s_addr = address;
114-
addr.sin_port = port;
115-
rc = bind(sock, (SOCKADDR *) &addr, sizeof(addr));
116-
return (rc == 0);
117-
}
118-
119107
BOOL c_winsock_connect(Winsock *winsock, SOCKET sock, SOCKADDR *addr, int addrLen, OVERLAPPED *ol)
120108
{
121109
// ConnectEx requires the socket to be initially bound.
@@ -134,3 +122,18 @@ BOOL c_winsock_connect(Winsock *winsock, SOCKET sock, SOCKADDR *addr, int addrLe
134122
BOOL ok = winsock->ConnectEx(sock, addr, addrLen, NULL, 0, NULL, ol);
135123
return (ok || WSAGetLastError() == ERROR_IO_PENDING);
136124
}
125+
126+
BOOL c_winsock_recv(SOCKET sock, char *buf, u_long bufsize, OVERLAPPED *ol)
127+
{
128+
WSABUF wsabuf = {.len = bufsize, .buf = buf};
129+
DWORD flags = 0;
130+
int rc = WSARecv(sock, &wsabuf, 1, NULL, &flags, ol, NULL);
131+
return (rc == 0 || WSAGetLastError() == ERROR_IO_PENDING);
132+
}
133+
134+
BOOL c_winsock_send(SOCKET sock, char *buf, u_long bufsize, OVERLAPPED *ol)
135+
{
136+
WSABUF wsabuf = {.len = bufsize, .buf = buf};
137+
int rc = WSASend(sock, &wsabuf, 1, NULL, 0, ol, NULL);
138+
return (rc == 0 || WSAGetLastError() == ERROR_IO_PENDING);
139+
}

iocp.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ library
3232
build-tools: hsc2hs
3333

3434
ghc-options: -Wall -fwarn-tabs -fno-warn-missing-signatures
35+
cc-options: -Wall
3536

3637
build-depends : base == 4.*
38+
, bytestring
3739
, Win32
3840
, network

0 commit comments

Comments
 (0)