@@ -4,210 +4,20 @@
4||| Modified (C) The Idris Community, 2015, 2016
4||| Modified (C) The Idris Community, 2015, 2016
5module Network.Socket
5module Network.Socket
7+import public Network.Socket.Data
8+import Network.Socket.Raw
7%include C "idris_net.h"
10%include C "idris_net.h"
8%include C "sys/types.h"
11%include C "sys/types.h"
9%include C "sys/socket.h"
12%include C "sys/socket.h"
10%include C "netdb.h"
13%include C "netdb.h"
12−-- ------------------------------------------------------------ [ Type Aliases ]
14−public export
15+%access export
24−||| Generally good enough to just set it to 0.
29−||| SocketError: Error thrown by a socket operation
34−||| SocketDescriptor: Native C Socket Descriptor
36−SocketDescriptor : Type
37−SocketDescriptor = Int
43−-- --------------------------------------------------------------- [ Constants ]
45−||| Backlog used within listen() call -- number of incoming calls
50−-- FIXME: This *must* be pulled in from C
55−-- -------------------------------------------------------------- [ Interfaces ]
58−interface ToCode a where
61−-- --------------------------------------------------------- [ Socket Families ]
65−||| The ones that people might actually use. We're not going to need US
66−||| Government proprietary ones.
68−data SocketFamily : Type where
70− AF_UNSPEC : SocketFamily
72− ||| IP / UDP etc. IPv4
73− AF_INET : SocketFamily
75− ||| IP / UDP etc. IPv6
76− AF_INET6 : SocketFamily
79−Show SocketFamily where
80− show AF_UNSPEC = "AF_UNSPEC"
81− show AF_INET = "AF_INET"
82− show AF_INET6 = "AF_INET6"
85−ToCode SocketFamily where
90−getSocketFamily : Int -> Maybe SocketFamily
92− Prelude.List.lookup i [ (0, AF_UNSPEC)
97−-- ------------------------------------------------------------ [ Socket Types ]
100−data SocketType : Type where
101− ||| Not a socket, used in certain operations
102− NotASocket : SocketType
108− Datagram : SocketType
111− RawSocket : SocketType
114−Show SocketType where
115− show NotASocket = "Not a socket"
116− show Stream = "Stream"
117− show Datagram = "Datagram"
118− show RawSocket = "Raw"
121−ToCode SocketType where
122− toCode NotASocket = 0
125− toCode RawSocket = 3
127−-- ---------------------------------------------------------------- [ Pointers ]
129−data RecvStructPtr = RSPtr Ptr
130−data RecvfromStructPtr = RFPtr Ptr
133−data BufPtr = BPtr Ptr
136−data SockaddrPtr = SAPtr Ptr
138−-- --------------------------------------------------------------- [ Addresses ]
140−||| Network Addresses
142−data SocketAddress : Type where
143− IPv4Addr : Int -> Int -> Int -> Int -> SocketAddress
145− ||| Not implemented (yet)
146− IPv6Addr : SocketAddress
148− Hostname : String -> SocketAddress
150− ||| Used when there's a parse error
151− InvalidAddress : SocketAddress
154−Show SocketAddress where
155− show (IPv4Addr i1 i2 i3 i4) = concat $ Prelude.List.intersperse "." (map show [i1, i2, i3, i4])
156− show IPv6Addr = "NOT IMPLEMENTED YET"
157− show (Hostname host) = host
158− show InvalidAddress = "Invalid"
160−-- --------------------------------------------------------- [ UDP Information ]
162−-- TODO: Expand to non-string payloads
164−record UDPRecvData where
165− constructor MkUDPRecvData
166− remote_addr : SocketAddress
172−record UDPAddrInfo where
173− constructor MkUDPAddrInfo
174− remote_addr : SocketAddress
177−-- ---------------------------------------------------------- [ Socket Utilies ]
179−||| Frees a given pointer
181−sock_free : BufPtr -> IO ()
182−sock_free (BPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
185−sockaddr_free : SockaddrPtr -> IO ()
186−sockaddr_free (SAPtr ptr) = foreign FFI_C "idrnet_free" (Ptr -> IO ()) ptr
188−||| Allocates an amount of memory given by the ByteLength parameter.
190−||| Used to allocate a mutable pointer to be given to the Recv functions.
192−sock_alloc : ByteLength -> IO BufPtr
193−sock_alloc bl = map BPtr $ foreign FFI_C "idrnet_malloc" (Int -> IO Ptr) bl
195−-- ----------------------------------------------------------------- [ Sockets ]
196−||| The metadata about a socket
199− constructor MkSocket
200− descriptor : SocketDescriptor
201− family : SocketFamily
202− socketType : SocketType
203− protocolNumber : ProtocolNumber
206-- ----------------------------------------------------- [ Network Socket API. ]
17-- ----------------------------------------------------- [ Network Socket API. ]
208||| Creates a UNIX socket with the given family, socket type and protocol
19||| Creates a UNIX socket with the given family, socket type and protocol
209||| number. Returns either a socket or an error.
20||| number. Returns either a socket or an error.
211socket : (fam : SocketFamily)
21socket : (fam : SocketFamily)
212 -> (ty : SocketType)
22 -> (ty : SocketType)
213 -> (pnum : ProtocolNumber)
23 -> (pnum : ProtocolNumber)
@@ -222,34 +32,30 @@ socket sf st pn = do
222 else pure $ Right (MkSocket socket_res sf st pn)
32 else pure $ Right (MkSocket socket_res sf st pn)
224||| Close a socket
34||| Close a socket
226close : Socket -> IO ()
35close : Socket -> IO ()
227close sock = foreign FFI_C "close" (Int -> IO ()) (descriptor sock)
36close sock = foreign FFI_C "close" (Int -> IO ()) (descriptor sock)
230−saString : (Maybe SocketAddress) -> String
231−saString (Just sa) = show sa
232−saString Nothing = ""
234||| Binds a socket to the given socket address and port.
38||| Binds a socket to the given socket address and port.
235||| Returns 0 on success, an error code otherwise.
39||| Returns 0 on success, an error code otherwise.
237bind : (sock : Socket)
40bind : (sock : Socket)
238 -> (addr : Maybe SocketAddress)
41 -> (addr : Maybe SocketAddress)
239 -> (port : Port)
42 -> (port : Port)
240 -> IO Int
43 -> IO Int
241bind sock addr port = do
44bind sock addr port = do
242− bind_res <- foreign FFI_C "idrnet_bind"
45+ bind_res <- foreign FFI_C "idrnet_bind"
243− (Int -> Int -> Int -> String -> Int -> IO Int)
46+ (Int -> Int -> Int -> String -> Int -> IO Int)
244− (descriptor sock) (toCode $ family sock)
47+ (descriptor sock) (toCode $ family sock)
245− (toCode $ socketType sock) (saString addr) port
48+ (toCode $ socketType sock) (saString addr) port
246− if bind_res == (-1)
49+ if bind_res == (-1)
247− then getErrno
50+ then getErrno
248− else pure 0
51+ else pure 0
53+ saString : Maybe SocketAddress -> String
54+ saString (Just sa) = show sa
55+ saString Nothing = ""
250||| Connects to a given address and port.
57||| Connects to a given address and port.
251||| Returns 0 on success, and an error number on error.
58||| Returns 0 on success, and an error number on error.
253connect : (sock : Socket)
59connect : (sock : Socket)
254 -> (addr : SocketAddress)
60 -> (addr : SocketAddress)
255 -> (port : Port)
61 -> (port : Port)
@@ -266,7 +72,6 @@ connect sock addr port = do
266||| Listens on a bound socket.
72||| Listens on a bound socket.
268||| @sock The socket to listen on.
74||| @sock The socket to listen on.
270listen : (sock : Socket) -> IO Int
75listen : (sock : Socket) -> IO Int
271listen sock = do
76listen sock = do
272 listen_res <- foreign FFI_C "listen" (Int -> Int -> IO Int)
77 listen_res <- foreign FFI_C "listen" (Int -> Int -> IO Int)
@@ -275,40 +80,6 @@ listen sock = do
275 then getErrno
80 then getErrno
276 else pure 0
81 else pure 0
278−||| Parses a textual representation of an IPv4 address into a SocketAddress
279−parseIPv4 : String -> SocketAddress
282− (i1 :: i2 :: i3 :: i4 :: _) => IPv4Addr i1 i2 i3 i4
283− otherwise => InvalidAddress
285− toInt' : String -> Integer
288− toInt : String -> Int
289− toInt s = fromInteger $ toInt' s
292− splitted = map toInt (Prelude.Strings.split (\c => c == '.') str)
294−||| Retrieves a socket address from a sockaddr pointer
295−getSockAddr : SockaddrPtr -> IO SocketAddress
296−getSockAddr (SAPtr ptr) = do
297− addr_family_int <- foreign FFI_C "idrnet_sockaddr_family"
301− -- ASSUMPTION: Foreign call returns a valid int
302− assert_total (case getSocketFamily addr_family_int of
304− ipv4_addr <- foreign FFI_C "idrnet_sockaddr_ipv4"
308− pure $ parseIPv4 ipv4_addr
309− Just AF_INET6 => pure IPv6Addr
310− Just AF_UNSPEC => pure InvalidAddress)
312||| Accept a connection on the provided socket.
83||| Accept a connection on the provided socket.
314||| Returns on failure a `SocketError`
85||| Returns on failure a `SocketError`
@@ -317,7 +88,6 @@ getSockAddr (SAPtr ptr) = do
317||| + `SocketAddress` :: The
88||| + `SocketAddress` :: The
319||| @sock The socket used to establish connection.
90||| @sock The socket used to establish connection.
321accept : (sock : Socket)
91accept : (sock : Socket)
322 -> IO (Either SocketError (Socket, SocketAddress))
92 -> IO (Either SocketError (Socket, SocketAddress))
323accept sock = do
93accept sock = do
@@ -346,7 +116,6 @@ accept sock = do
347||| @sock The socket on which to send the message.
117||| @sock The socket on which to send the message.
348||| @msg The data to send.
118||| @msg The data to send.
350send : (sock : Socket)
119send : (sock : Socket)
351 -> (msg : String)
120 -> (msg : String)
352 -> IO (Either SocketError ResultCode)
121 -> IO (Either SocketError ResultCode)
@@ -359,20 +128,6 @@ send sock dat = do
359 then map Left getErrno
128 then map Left getErrno
360 else pure $ Right send_res
129 else pure $ Right send_res
362−freeRecvStruct : RecvStructPtr -> IO ()
363−freeRecvStruct (RSPtr p) =
364− foreign FFI_C "idrnet_free_recv_struct"
368−||| Utility to extract data.
369−freeRecvfromStruct : RecvfromStructPtr -> IO ()
370−freeRecvfromStruct (RFPtr p) =
371− foreign FFI_C "idrnet_free_recvfrom_struct"
376||| Receive data on the specified socket.
131||| Receive data on the specified socket.
378||| Returns on failure a `SocketError`
133||| Returns on failure a `SocketError`
@@ -382,7 +137,6 @@ freeRecvfromStruct (RFPtr p) =
383||| @sock The socket on which to receive the message.
138||| @sock The socket on which to receive the message.
384||| @len How much of the data to send.
139||| @len How much of the data to send.
386recv : (sock : Socket)
140recv : (sock : Socket)
387 -> (len : ByteLength)
141 -> (len : ByteLength)
388 -> IO (Either SocketError (String, ResultCode))
142 -> IO (Either SocketError (String, ResultCode))
@@ -413,48 +167,6 @@ recv sock len = do
413 freeRecvStruct (RSPtr recv_struct_ptr)
167 freeRecvStruct (RSPtr recv_struct_ptr)
414 pure $ Right (payload, recv_res)
168 pure $ Right (payload, recv_res)
416−||| Sends the data in a given memory location
418−||| Returns on failure a `SocketError`
419−||| Returns on success the `ResultCode`
421−||| @sock The socket on which to send the message.
422−||| @ptr The location containing the data to send.
423−||| @len How much of the data to send.
424−sendBuf : (sock : Socket)
426− -> (len : ByteLength)
427− -> IO (Either SocketError ResultCode)
428−sendBuf sock (BPtr ptr) len = do
429− send_res <- foreign FFI_C "idrnet_send_buf"
430− (Int -> Ptr -> Int -> IO Int)
431− (descriptor sock) ptr len
434− then map Left getErrno
435− else pure $ Right send_res
437−||| Receive data from a given memory location.
439−||| Returns on failure a `SocketError`
440−||| Returns on success the `ResultCode`
442−||| @sock The socket on which to receive the message.
443−||| @ptr The location containing the data to receive.
444−||| @len How much of the data to receive.
445−recvBuf : (sock : Socket)
447− -> (len : ByteLength)
448− -> IO (Either SocketError ResultCode)
449−recvBuf sock (BPtr ptr) len = do
450− recv_res <- foreign FFI_C "idrnet_recv_buf"
451− (Int -> Ptr -> Int -> IO Int)
452− (descriptor sock) ptr len
454− if (recv_res == (-1))
455− then map Left getErrno
456− else pure $ Right recv_res
458||| Send a message.
170||| Send a message.
460||| Returns on failure a `SocketError`
172||| Returns on failure a `SocketError`
@@ -464,7 +176,6 @@ recvBuf sock (BPtr ptr) len = do
464||| @addr Address of the recipient.
176||| @addr Address of the recipient.
465||| @port The port on which to send the message.
177||| @port The port on which to send the message.
466||| @msg The message to send.
178||| @msg The message to send.
468sendTo : (sock : Socket)
179sendTo : (sock : Socket)
469 -> (addr : SocketAddress)
180 -> (addr : SocketAddress)
470 -> (port : Port)
181 -> (port : Port)
@@ -479,58 +190,6 @@ sendTo sock addr p dat = do
479 then map Left getErrno
190 then map Left getErrno
480 else pure $ Right sendto_res
191 else pure $ Right sendto_res
482−||| Send a message stored in some buffer.
484−||| Returns on failure a `SocketError`
485−||| Returns on success the `ResultCode`
487−||| @sock The socket on which to send the message.
488−||| @addr Address of the recipient.
489−||| @port The port on which to send the message.
490−||| @ptr A Pointer to the buffer containing the message.
491−||| @len The size of the message.
492−sendToBuf : (sock : Socket)
493− -> (addr : SocketAddress)
496− -> (len : ByteLength)
497− -> IO (Either SocketError ResultCode)
498−sendToBuf sock addr p (BPtr dat) len = do
499− sendto_res <- foreign FFI_C "idrnet_sendto_buf"
500− (Int -> Ptr -> Int -> String -> Int -> Int -> IO Int)
501− (descriptor sock) dat len (show addr) p (toCode $ family sock)
503− if sendto_res == (-1)
504− then map Left getErrno
505− else pure $ Right sendto_res
507−||| Utility function to get the payload of the sent message as a `String`.
508−foreignGetRecvfromPayload : RecvfromStructPtr -> IO String
509−foreignGetRecvfromPayload (RFPtr p) =
510− foreign FFI_C "idrnet_get_recvfrom_payload"
514−||| Utility function to return senders socket address.
515−foreignGetRecvfromAddr : RecvfromStructPtr -> IO SocketAddress
516−foreignGetRecvfromAddr (RFPtr p) = do
517− sockaddr_ptr <- map SAPtr $ foreign FFI_C "idrnet_get_recvfrom_sockaddr"
520− getSockAddr sockaddr_ptr
522−||| Utility function to return sender's IPV4 port.
523−foreignGetRecvfromPort : RecvfromStructPtr -> IO Port
524−foreignGetRecvfromPort (RFPtr p) = do
525− sockaddr_ptr <- foreign FFI_C "idrnet_get_recvfrom_sockaddr"
528− port <- foreign FFI_C "idrnet_sockaddr_ipv4_port"
534||| Receive a message.
193||| Receive a message.
536||| Returns on failure a `SocketError`.
195||| Returns on failure a `SocketError`.
@@ -542,7 +201,6 @@ foreignGetRecvfromPort (RFPtr p) = do
542||| @sock The channel on which to receive.
201||| @sock The channel on which to receive.
543||| @len Size of the expected message.
202||| @len Size of the expected message.
546recvFrom : (sock : Socket)
204recvFrom : (sock : Socket)
547 -> (len : ByteLength)
205 -> (len : ByteLength)
548 -> IO (Either SocketError (UDPAddrInfo, String, ResultCode))
206 -> IO (Either SocketError (UDPAddrInfo, String, ResultCode))
@@ -570,42 +228,3 @@ recvFrom sock bl = do
570 freeRecvfromStruct recv_ptr'
228 freeRecvfromStruct recv_ptr'
571 pure $ Right (MkUDPAddrInfo addr port, payload, result)
229 pure $ Right (MkUDPAddrInfo addr port, payload, result)
573−||| Receive a message placed on a 'known' buffer.
575−||| Returns on failure a `SocketError`.
576−||| Returns on success a pair of
577−||| + `UDPAddrInfo` :: The address of the sender.
578−||| + `Int` :: Result value from underlying function.
580−||| @sock The channel on which to receive.
581−||| @ptr Pointer to the buffer to place the message.
582−||| @len Size of the expected message.
584−recvFromBuf : (sock : Socket)
586− -> (len : ByteLength)
587− -> IO (Either SocketError (UDPAddrInfo, ResultCode))
588−recvFromBuf sock (BPtr ptr) bl = do
589− recv_ptr <- foreign FFI_C "idrnet_recvfrom_buf"
590− (Int -> Ptr -> Int -> IO Ptr)
591− (descriptor sock) ptr bl
593− let recv_ptr' = RFPtr recv_ptr
595− if !(nullPtr recv_ptr)
596− then map Left getErrno
598− result <- foreign FFI_C "idrnet_get_recvfrom_res"
603− freeRecvfromStruct recv_ptr'
606− port <- foreignGetRecvfromPort recv_ptr'
607− addr <- foreignGetRecvfromAddr recv_ptr'
608− freeRecvfromStruct recv_ptr'
609− pure $ Right (MkUDPAddrInfo addr port, result + 1)
611−-- --------------------------------------------------------------------- [ EOF ]