on master help sign in
Update Network library

(Taken from @SimonJF's IdrisNet2 library at https://github.com/SimonJF/IdrisNet2)

commitb92213c36d35caff1b32a43625de8eda48733acb authorEdwin Brady <ecb10@st-andrews.ac.uk> dateSat 14 Jun 2014, 14:19 (12 years ago) parentf48942b
3 files changed+369−70
libs/base/Network/Socket.idr+139−36 rts/idris_net.c+188−33 rts/idris_net.h+42−1
libs/base/Network/Socket.idr+139−36
@@ -1,10 +1,10 @@
11-- Time to do this properly.
22-- Low-Level C Sockets bindings for Idris. Used by higher-level, cleverer things.
33-- (C) SimonJF, MIT Licensed, 2014
4−module Network.Socket
4+module IdrisNet.Socket
55
66%include C "idris_net.h"
7−%include C "sys/types.h" -- Pushing my luck, might need to re-export everything
7+%include C "sys/types.h"
88%include C "sys/socket.h"
99%include C "netdb.h"
1010
@@ -54,6 +54,12 @@ instance ToCode SocketType where
5454 toCode Datagram = 2
5555 toCode Raw = 3
5656
57+
58+data RecvStructPtr = RSPtr Ptr
59+data RecvfromStructPtr = RFPtr Ptr
60+data BufPtr = BPtr Ptr
61+data SockaddrPtr = SAPtr Ptr
62+
5763-- Protocol Number. Generally good enough to just set it to 0.
5864ProtocolNumber : Type
5965ProtocolNumber = Int
@@ -88,16 +94,35 @@ BACKLOG = 20
8894EAGAIN : Int
8995EAGAIN = 11
9096
91−-- Allocates an amount of memory given by the ByteLength parameter.
92−-- Used to allocate a mutable pointer to be given to the Recv functions.
93−private
94−alloc : ByteLength -> IO Ptr
95−alloc bl = mkForeign (FFun "idrnet_malloc" [FInt] FPtr) bl
97+-- TODO: Expand to non-string payloads
98+record UDPRecvData : Type where
99+ MkUDPRecvData :
100+ (remote_addr : SocketAddress) ->
101+ (remote_port : Port) ->
102+ (recv_data : String) ->
103+ (data_len : Int) ->
104+ UDPRecvData
105+
106+record UDPAddrInfo : Type where
107+ MkUDPAddrInfo :
108+ (remote_addr : SocketAddress) ->
109+ (remote_port : Port) ->
110+ UDPAddrInfo
96111
97112-- Frees a given pointer
98−private
99−free : Ptr -> IO ()
100−free ptr = mkForeign (FFun "idrnet_free" [FPtr] FUnit) ptr
113+public
114+sock_free : BufPtr -> IO ()
115+sock_free (BPtr ptr) = mkForeign (FFun "idrnet_free" [FPtr] FUnit) ptr
116+
117+public
118+sockaddr_free : SockaddrPtr -> IO ()
119+sockaddr_free (SAPtr ptr) = mkForeign (FFun "idrnet_free" [FPtr] FUnit) ptr
120+
121+-- Allocates an amount of memory given by the ByteLength parameter.
122+-- Used to allocate a mutable pointer to be given to the Recv functions.
123+public
124+sock_alloc : ByteLength -> IO BufPtr
125+sock_alloc bl = map BPtr $ mkForeign (FFun "idrnet_malloc" [FInt] FPtr) bl
101126
102127record Socket : Type where
103128 MkSocket : (descriptor : SocketDescriptor) ->
@@ -123,12 +148,17 @@ socket sf st pn = do
123148close : Socket -> IO ()
124149close sock = mkForeign (FFun "close" [FInt] FUnit) (descriptor sock)
125150
151+private
152+saString : (Maybe SocketAddress) -> String
153+saString (Just sa) = show sa
154+saString Nothing = ""
155+
126156-- Binds a socket to the given socket address and port.
127157-- Returns 0 on success, an error code otherwise.
128−bind : Socket -> SocketAddress -> Port -> IO Int
158+bind : Socket -> (Maybe SocketAddress) -> Port -> IO Int
129159bind sock addr port = do
130160 bind_res <- (mkForeign (FFun "idrnet_bind" [FInt, FInt, FInt, FString, FInt] FInt)
131− (descriptor sock) (toCode $ family sock) (toCode $ socketType sock) (show addr) port)
161+ (descriptor sock) (toCode $ family sock) (toCode $ socketType sock) (saString addr) port)
132162 if bind_res == (-1) then -- error
133163 getErrno
134164 else return 0 -- Success
@@ -152,11 +182,10 @@ listen sock = do
152182 else return 0
153183
154184-- Parses a textual representation of an IPv4 address into a SocketAddress
155−private
156185parseIPv4 : String -> SocketAddress
157186parseIPv4 str = case splitted of
158− (i1 :: i2 :: i3 :: i4 :: _) => IPv4Addr i1 i2 i3 i4
159− _ => InvalidAddress
187+ (i1 :: i2 :: i3 :: i4 :: _) => IPv4Addr i1 i2 i3 i4
188+ _ => InvalidAddress
160189 where toInt' : String -> Integer
161190 toInt' = cast
162191 toInt : String -> Int
@@ -166,32 +195,30 @@ parseIPv4 str = case splitted of
166195
167196
168197-- Retrieves a socket address from a sockaddr pointer
169−private
170−getSockAddr : Ptr -> IO SocketAddress
171−getSockAddr ptr = do
198+getSockAddr : SockaddrPtr -> IO SocketAddress
199+getSockAddr (SAPtr ptr) = do
172200 addr_family_int <- mkForeign (FFun "idrnet_sockaddr_family" [FPtr] FInt) ptr
173− -- FIXME: Is this really a safe assertion? Depends where the Ptr came
174− -- from!
175− assert_total $ case getSocketFamily addr_family_int of
201+ -- putStrLn $ "Addr family int: " ++ (show addr_family_int)
202+ -- ASSUMPTION: Foreign call returns a valid int
203+ assert_total (case getSocketFamily addr_family_int of
176204 Just AF_INET => do
177205 ipv4_addr <- mkForeign (FFun "idrnet_sockaddr_ipv4" [FPtr] FString) ptr
178206 return $ parseIPv4 ipv4_addr
179207 Just AF_INET6 => return IPv6Addr
180− Just AF_UNSPEC => return IPv6Addr -- FIXME: Horrible hack
208+ Just AF_UNSPEC => return InvalidAddress)
181209
182−-- Accepts a connection from a listening socket.
183210accept : Socket -> IO (Either SocketError (Socket, SocketAddress))
184211accept sock = do
185212 -- We need a pointer to a sockaddr structure. This is then passed into
186213 -- idrnet_accept and populated. We can then query it for the SocketAddr and free it.
187− sockaddr_ptr <- mkForeign (FFun "idrnet_create_sockaddr" [] FPtr)
214+ sockaddr_ptr <- mkForeign (FFun "idrnet_create_sockaddr" [] FPtr)
188215 accept_res <- mkForeign (FFun "idrnet_accept" [FInt, FPtr] FInt) (descriptor sock) sockaddr_ptr
189216 if accept_res == (-1) then
190217 map Left getErrno
191218 else do
192219 let (MkSocket _ fam ty p_num) = sock
193− sockaddr <- getSockAddr sockaddr_ptr
194− free sockaddr_ptr
220+ sockaddr <- getSockAddr (SAPtr sockaddr_ptr)
221+ sockaddr_free (SAPtr sockaddr_ptr)
195222 return $ Right ((MkSocket accept_res fam ty p_num), sockaddr)
196223
197224send : Socket -> String -> IO (Either SocketError ByteLength)
@@ -202,10 +229,12 @@ send sock dat = do
202229 else
203230 return $ Right send_res
204231
205−private
206−freeRecvStruct : Ptr -> IO ()
207−freeRecvStruct p = mkForeign (FFun "idrnet_free_recv_struct" [FPtr] FUnit) p
208232
233+freeRecvStruct : RecvStructPtr -> IO ()
234+freeRecvStruct (RSPtr p) = mkForeign (FFun "idrnet_free_recv_struct" [FPtr] FUnit) p
235+
236+freeRecvfromStruct : RecvfromStructPtr -> IO ()
237+freeRecvfromStruct (RFPtr p) = mkForeign (FFun "idrnet_free_recvfrom_struct" [FPtr] FUnit) p
209238
210239recv : Socket -> Int -> IO (Either SocketError (String, ByteLength))
211240recv sock len = do
@@ -215,32 +244,106 @@ recv sock len = do
215244 recv_res <- mkForeign (FFun "idrnet_get_recv_res" [FPtr] FInt) recv_struct_ptr
216245 if recv_res == (-1) then do
217246 errno <- getErrno
218− freeRecvStruct recv_struct_ptr
247+ freeRecvStruct (RSPtr recv_struct_ptr)
219248 return $ Left errno
220249 else
221250 if recv_res == 0 then do
222− freeRecvStruct recv_struct_ptr
251+ freeRecvStruct (RSPtr recv_struct_ptr)
223252 return $ Left 0
224253 else do
225254 payload <- mkForeign (FFun "idrnet_get_recv_payload" [FPtr] FString) recv_struct_ptr
226− freeRecvStruct recv_struct_ptr
255+ freeRecvStruct (RSPtr recv_struct_ptr)
227256 return $ Right (payload, recv_res)
228257
229258
230259-- Sends the data in a given memory location
231−sendBuf : Socket -> Ptr -> ByteLength -> IO (Either SocketError ByteLength)
232−sendBuf sock ptr len = do
260+sendBuf : Socket -> BufPtr -> ByteLength -> IO (Either SocketError ByteLength)
261+sendBuf sock (BPtr ptr) len = do
233262 send_res <- mkForeign (FFun "idrnet_send_buf" [FInt, FPtr, FInt] FInt) (descriptor sock) ptr len
234263 if send_res == (-1) then
235264 map Left getErrno
236265 else
237266 return $ Right send_res
238267
239−recvBuf : Socket -> Ptr -> ByteLength -> IO (Either SocketError ByteLength)
240−recvBuf sock ptr len = do
268+recvBuf : Socket -> BufPtr -> ByteLength -> IO (Either SocketError ByteLength)
269+recvBuf sock (BPtr ptr) len = do
241270 recv_res <- mkForeign (FFun "idrnet_recv_buf" [FInt, FPtr, FInt] FInt) (descriptor sock) ptr len
242271 if (recv_res == (-1)) then
243272 map Left getErrno
244273 else
245274 return $ Right recv_res
246275
276+sendTo : Socket -> SocketAddress -> Port -> String -> IO (Either SocketError ByteLength)
277+sendTo sock addr p dat = do
278+ sendto_res <- mkForeign (FFun "idrnet_sendto" [FInt, FString, FString, FInt, FInt] FInt)
279+ (descriptor sock) dat (show addr) p (toCode $ family sock)
280+ if sendto_res == (-1) then
281+ map Left getErrno
282+ else
283+ return $ Right sendto_res
284+
285+
286+sendToBuf : Socket -> SocketAddress -> Port -> BufPtr -> ByteLength -> IO (Either SocketError ByteLength)
287+sendToBuf sock addr p (BPtr dat) len = do
288+ sendto_res <- mkForeign (FFun "idrnet_sendto_buf" [FInt, FPtr, FInt, FString, FInt, FInt] FInt)
289+ (descriptor sock) dat len (show addr) p (toCode $ family sock)
290+ if sendto_res == (-1) then
291+ map Left getErrno
292+ else
293+ return $ Right sendto_res
294+
295+
296+foreignGetRecvfromPayload : RecvfromStructPtr -> IO String
297+foreignGetRecvfromPayload (RFPtr p) = mkForeign (FFun "idrnet_get_recvfrom_payload" [FPtr] FString) p
298+
299+foreignGetRecvfromAddr : RecvfromStructPtr -> IO SocketAddress
300+foreignGetRecvfromAddr (RFPtr p) = do
301+ sockaddr_ptr <- map SAPtr $ mkForeign (FFun "idrnet_get_recvfrom_sockaddr" [FPtr] FPtr) p
302+ getSockAddr sockaddr_ptr
303+
304+
305+foreignGetRecvfromPort : RecvfromStructPtr -> IO Port
306+foreignGetRecvfromPort (RFPtr p) = do
307+ sockaddr_ptr <- mkForeign (FFun "idrnet_get_recvfrom_sockaddr" [FPtr] FPtr) p
308+ port <- mkForeign (FFun "idrnet_sockaddr_ipv4_port" [FPtr] FInt) sockaddr_ptr
309+ return port
310+
311+recvFrom : Socket -> ByteLength -> IO (Either SocketError (UDPAddrInfo, String, ByteLength))
312+recvFrom sock bl = do
313+ recv_ptr <- mkForeign (FFun "idrnet_recvfrom" [FInt, FInt] FPtr)
314+ (descriptor sock) bl
315+ let recv_ptr' = RFPtr recv_ptr
316+ if !(nullPtr recv_ptr) then -- ! notation = monadic bind shortcut, not "not"
317+ map Left getErrno
318+ else do
319+ result <- mkForeign (FFun "idrnet_get_recvfrom_res" [FPtr] FInt) recv_ptr
320+ if result == -1 then do
321+ freeRecvfromStruct recv_ptr'
322+ map Left getErrno
323+ else do
324+ payload <- foreignGetRecvfromPayload recv_ptr'
325+ port <- foreignGetRecvfromPort recv_ptr'
326+ addr <- foreignGetRecvfromAddr recv_ptr'
327+ freeRecvfromStruct recv_ptr'
328+ return $ Right (MkUDPAddrInfo addr port, payload, result)
329+
330+
331+recvFromBuf : Socket -> BufPtr -> ByteLength -> IO (Either SocketError (UDPAddrInfo, ByteLength))
332+recvFromBuf sock (BPtr ptr) bl = do
333+ recv_ptr <- mkForeign (FFun "idrnet_recvfrom_buf" [FInt, FPtr, FInt] FPtr) (descriptor sock) ptr bl
334+ let recv_ptr' = RFPtr recv_ptr
335+ if !(nullPtr recv_ptr) then -- ! notation = monadic bind shortcut, not "not"
336+ map Left getErrno
337+ else do
338+ result <- mkForeign (FFun "idrnet_get_recvfrom_res" [FPtr] FInt) recv_ptr
339+ if result == -1 then do
340+ freeRecvfromStruct recv_ptr'
341+ map Left getErrno
342+ else do
343+ port <- foreignGetRecvfromPort recv_ptr'
344+ addr <- foreignGetRecvfromAddr recv_ptr'
345+ freeRecvfromStruct recv_ptr'
346+ return $ Right (MkUDPAddrInfo addr port, result + 1)
347+
348+
349+
rts/idris_net.c+188−33
@@ -1,19 +1,22 @@
11// C-Side of the Idris network library
22// (C) Simon Fowler, 2014
33// MIT Licensed. Have fun!
4−#include <errno.h>
5−#include <netdb.h>
6−#include <stdbool.h>
7−#include <stdlib.h>
8−#include <stdio.h>
9−#include <string.h>
10−#include <sys/types.h>
11−#include <sys/socket.h>
12−#include <netinet/in.h>
13−#include <arpa/inet.h>
14−
154#include "idris_net.h"
165
6+void buf_htonl(void* buf, int len) {
7+ int* buf_i = (int*) buf;
8+ for (int i = 0; i < (len / sizeof(int)) + 1; i++) {
9+ buf_i[i] = htonl(buf_i[i]);
10+ }
11+}
12+
13+void buf_ntohl(void* buf, int len) {
14+ int* buf_i = (int*) buf;
15+ for (int i = 0; i < (len / sizeof(int)) + 1; i++) {
16+ buf_i[i] = ntohl(buf_i[i]);
17+ }
18+}
19+
1720void* idrnet_malloc(int size) {
1821 return malloc(size);
1922}
@@ -22,9 +25,12 @@ void idrnet_free(void* ptr) {
2225 free(ptr);
2326}
2427
25−int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
28+// We call this from quite a few functions. Given a textual host and an int port,
29+// populates a struct addrinfo.
30+int idrnet_getaddrinfo(struct addrinfo** address_res, char* host, int port,
31+ int family, int socket_type) {
32+
2633 struct addrinfo hints;
27− struct addrinfo* address_res;
2834 // Convert port into string
2935 char str_port[8];
3036 sprintf(str_port, "%d", port);
@@ -38,43 +44,42 @@ int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
3844 // then we want to instruct the C library to fill in the IP automatically
3945 if (strlen(host) == 0) {
4046 hints.ai_flags = AI_PASSIVE; // fill in IP automatically
41− }
47+ return getaddrinfo(NULL, str_port, &hints, address_res);
48+ }
49+ return getaddrinfo(host, str_port, &hints, address_res);
4250
43− int addr_res = getaddrinfo(host, str_port, &hints, &address_res);
51+}
52+
53+int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
54+ struct addrinfo* address_res;
55+ int addr_res = idrnet_getaddrinfo(&address_res, host, port, family, socket_type);
4456 if (addr_res == -1) {
57+ //printf("Lib err: bind getaddrinfo\n");
4558 return -1;
4659 }
4760
4861 int bind_res = bind(sockfd, address_res->ai_addr, address_res->ai_addrlen);
4962 if (bind_res == -1) {
63+ //freeaddrinfo(address_res);
64+ //printf("Lib err: bind\n");
5065 return -1;
5166 }
52−
5367 return 0;
5468}
5569
5670int idrnet_connect(int sockfd, int family, int socket_type, char* host, int port) {
57− char str_port[8];
58− sprintf(str_port, "%d", port);
59− struct addrinfo hints;
6071 struct addrinfo* remote_host;
61−
62− // Set up hints structure for getaddrinfo
63− memset(&hints, 0, sizeof(hints));
64− hints.ai_family = family;
65− hints.ai_socktype = socket_type;
66−
67− // Get info about the remote host (DNS lookup etc)
68− int addr_res = getaddrinfo(host, str_port, &hints, &remote_host);
72+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, socket_type);
6973 if (addr_res == -1) {
7074 return -1;
7175 }
7276
7377 int connect_res = connect(sockfd, remote_host->ai_addr, remote_host->ai_addrlen);
7478 if (connect_res == -1) {
79+ freeaddrinfo(remote_host);
7580 return -1;
7681 }
77−
82+ freeaddrinfo(remote_host);
7883 return 0;
7984}
8085
@@ -88,9 +93,15 @@ char* idrnet_sockaddr_ipv4(void* sockaddr) {
8893 struct sockaddr_in* addr = (struct sockaddr_in*) sockaddr;
8994 char* ip_addr = (char*) malloc(sizeof(char) * INET_ADDRSTRLEN);
9095 inet_ntop(AF_INET, &(addr->sin_addr), ip_addr, INET_ADDRSTRLEN);
96+ //printf("Lib: ip_addr: %s\n", ip_addr);
9197 return ip_addr;
9298}
9399
100+int idrnet_sockaddr_ipv4_port(void* sockaddr) {
101+ struct sockaddr_in* addr = (struct sockaddr_in*) addr;
102+ return ((int) ntohs(addr->sin_port));
103+}
104+
94105void* idrnet_create_sockaddr() {
95106 return malloc(sizeof(struct sockaddr_storage));
96107}
@@ -108,33 +119,43 @@ int idrnet_send(int sockfd, char* data) {
108119}
109120
110121int idrnet_send_buf(int sockfd, void* data, int len) {
111− return send(sockfd, data, len, 0);
122+ void* buf_cpy = malloc(len);
123+ memset(buf_cpy, 0, len);
124+ memcpy(buf_cpy, data, len);
125+ buf_htonl(buf_cpy, len);
126+ int res = send(sockfd, buf_cpy, len, 0);
127+ free(buf_cpy);
128+ return res;
112129}
113130
114131void* idrnet_recv(int sockfd, int len) {
115132 idrnet_recv_result* res_struct =
116133 (idrnet_recv_result*) malloc(sizeof(idrnet_recv_result));
117−
118134 char* buf = malloc(len + 1);
135+ memset(buf, 0, len + 1);
119136 int recv_res = recv(sockfd, buf, len, 0);
120137 res_struct->result = recv_res;
121138
122139 if (recv_res > 0) { // Data was received
123140 buf[recv_res + 1] = 0x00; // Null-term, so Idris can interpret it
124141 }
125− res_struct->payload = (void*) buf;
142+ res_struct->payload = buf;
126143 return (void*) res_struct;
127144}
128145
129146int idrnet_recv_buf(int sockfd, void* buf, int len) {
130− return recv(sockfd, buf, len, 0);
147+ int recv_res = recv(sockfd, buf, len, 0);
148+ if (recv_res != -1) {
149+ buf_ntohl(buf, len);
150+ }
151+ return recv_res;
131152}
132153
133154int idrnet_get_recv_res(void* res_struct) {
134155 return (((idrnet_recv_result*) res_struct)->result);
135156}
136157
137−void* idrnet_get_recv_payload(void* res_struct) {
158+char* idrnet_get_recv_payload(void* res_struct) {
138159 return (((idrnet_recv_result*) res_struct)->payload);
139160}
140161
@@ -151,3 +172,137 @@ int idrnet_errno() {
151172 return errno;
152173}
153174
175+
176+int idrnet_sendto(int sockfd, char* data, char* host, int port, int family) {
177+
178+ struct addrinfo* remote_host;
179+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, SOCK_DGRAM);
180+ if (addr_res == -1) {
181+ return -1;
182+ }
183+
184+ int send_res = sendto(sockfd, data, strlen(data), 0,
185+ remote_host->ai_addr, remote_host->ai_addrlen);
186+ freeaddrinfo(remote_host);
187+ return send_res;
188+}
189+
190+int idrnet_sendto_buf(int sockfd, void* buf, int buf_len, char* host, int port, int family) {
191+
192+ struct addrinfo* remote_host;
193+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, SOCK_DGRAM);
194+ if (addr_res == -1) {
195+ //printf("lib err: sendto getaddrinfo \n");
196+ return -1;
197+ }
198+
199+ buf_htonl(buf, buf_len);
200+
201+ int send_res = sendto(sockfd, buf, buf_len, 0,
202+ remote_host->ai_addr, remote_host->ai_addrlen);
203+ if (send_res == -1) {
204+ perror("lib err: sendto \n");
205+ }
206+ //freeaddrinfo(remote_host);
207+ return send_res;
208+}
209+
210+
211+
212+void* idrnet_recvfrom(int sockfd, int len) {
213+/*
214+ * int recvfrom(int sockfd, void *buf, int len, unsigned int flags,
215+ struct sockaddr *from, int *fromlen);
216+*/
217+ // Allocate the required structures, and nuke them
218+ struct sockaddr_storage* remote_addr =
219+ (struct sockaddr_storage*) malloc(sizeof(struct sockaddr_storage));
220+ char* buf = (char*) malloc(len + 1);
221+ idrnet_recvfrom_result* ret =
222+ (idrnet_recvfrom_result*) malloc(sizeof(idrnet_recvfrom_result));
223+ memset(remote_addr, 0, sizeof(struct sockaddr_storage));
224+ memset(buf, 0, len + 1);
225+ memset(ret, 0, sizeof(idrnet_recvfrom_result));
226+ socklen_t fromlen = sizeof(struct sockaddr_storage);
227+
228+ int recv_res = recvfrom(sockfd, buf, len, 0, (struct sockaddr*) remote_addr, &fromlen);
229+ ret->result = recv_res;
230+ // Check for failure...
231+ if (recv_res == -1) {
232+ free(buf);
233+ free(remote_addr);
234+ } else {
235+ // If data was received, process and populate
236+ ret->result = recv_res;
237+ ret->remote_addr = remote_addr;
238+ // Ensure the last byte is NULL, since in this mode we're sending strings
239+ buf[len] = 0x00;
240+ ret->payload = (void*) buf;
241+ }
242+
243+ return ret;
244+}
245+
246+
247+void* idrnet_recvfrom_buf(int sockfd, void* buf, int len) {
248+ // Allocate the required structures, and nuke them
249+ struct sockaddr_storage* remote_addr =
250+ (struct sockaddr_storage*) malloc(sizeof(struct sockaddr_storage));
251+ idrnet_recvfrom_result* ret =
252+ (idrnet_recvfrom_result*) malloc(sizeof(idrnet_recvfrom_result));
253+ memset(remote_addr, 0, sizeof(struct sockaddr_storage));
254+ memset(ret, 0, sizeof(idrnet_recvfrom_result));
255+ socklen_t fromlen = 0;
256+
257+ int recv_res = recvfrom(sockfd, buf, len, 0, (struct sockaddr*) remote_addr, &fromlen);
258+ // Check for failure... But don't free the buffer! Not our job.
259+ ret->result = recv_res;
260+ if (recv_res == -1) {
261+ free(remote_addr);
262+ }
263+ // Payload will be NULL -- since it's been put into the user-specified buffer. We
264+ // still need the return struct to get our hands on the remote address, though.
265+ if (recv_res > 0) {
266+ buf_ntohl(buf, len);
267+ ret->payload = NULL;
268+ ret->remote_addr = remote_addr;
269+ }
270+ return ret;
271+}
272+
273+int idrnet_get_recvfrom_res(void* res_struct) {
274+ return (((idrnet_recvfrom_result*) res_struct)->result);
275+}
276+
277+char* idrnet_get_recvfrom_payload(void* res_struct) {
278+ return (((idrnet_recvfrom_result*) res_struct)->payload);
279+}
280+
281+void* idrnet_get_recvfrom_sockaddr(void* res_struct) {
282+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
283+ return recv_struct->remote_addr;
284+}
285+
286+int idrnet_get_recvfrom_port(void* res_struct) {
287+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
288+ if (recv_struct->remote_addr != NULL) {
289+ struct sockaddr_in* remote_addr_in =
290+ (struct sockaddr_in*) recv_struct->remote_addr;
291+ return ((int) ntohs(remote_addr_in->sin_port));
292+ }
293+ return -1;
294+}
295+
296+void idrnet_free_recvfrom_struct(void* res_struct) {
297+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
298+ if (recv_struct != NULL) {
299+ if (recv_struct->payload != NULL) {
300+ free(recv_struct->payload);
301+ }
302+ if (recv_struct->remote_addr != NULL) {
303+ free(recv_struct->remote_addr);
304+ }
305+ }
306+}
307+
308+
rts/idris_net.h+42−1
@@ -1,11 +1,30 @@
11#ifndef IDRISNET_H
22#define IDRISNET_H
33
4+#include <errno.h>
5+#include <netdb.h>
6+#include <stdbool.h>
7+#include <stdlib.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <sys/types.h>
11+#include <sys/socket.h>
12+#include <netinet/in.h>
13+#include <arpa/inet.h>
14+
415typedef struct idrnet_recv_result {
516 int result;
617 void* payload;
718} idrnet_recv_result;
819
20+// Same type of thing as idrnet_recv_result, but for UDP, so stores some
21+// address information
22+typedef struct idrnet_recvfrom_result {
23+ int result;
24+ void* payload;
25+ struct sockaddr_storage* remote_addr;
26+} idrnet_recvfrom_result;
27+
928// Memory management functions
1029void* idrnet_malloc(int size);
1130void idrnet_free(void* ptr);
@@ -22,6 +41,7 @@ int idrnet_connect(int sockfd, int family, int socket_type, char* host, int port
2241// Accessor functions for struct_sockaddr
2342int idrnet_sockaddr_family(void* sockaddr);
2443char* idrnet_sockaddr_ipv4(void* sockaddr);
44+int idrnet_sockaddr_ipv4_port(void* sockaddr);
2545void* idrnet_create_sockaddr();
2646
2747// Accept
@@ -37,8 +57,29 @@ void* idrnet_recv(int sockfd, int len);
3757// Receives directly into a buffer
3858int idrnet_recv_buf(int sockfd, void* buf, int len);
3959
60+// UDP Send
61+int idrnet_sendto(int sockfd, char* data, char* host, int port, int family);
62+int idrnet_sendto_buf(int sockfd, void* buf, int buf_len, char* host, int port, int family);
63+
64+
65+// UDP Receive
66+void* idrnet_recvfrom(int sockfd, int len);
67+void* idrnet_recvfrom_buf(int sockfd, void* buf, int len);
68+
4069// Receive structure accessors
4170int idrnet_get_recv_res(void* res_struct);
42−void* idrnet_get_recv_payload(void* res_struct);
71+char* idrnet_get_recv_payload(void* res_struct);
4372void idrnet_free_recv_struct(void* res_struct);
73+
74+// Recvfrom structure accessors
75+int idrnet_get_recvfrom_res(void* res_struct);
76+char* idrnet_get_recvfrom_payload(void* res_struct);
77+void* idrnet_get_recvfrom_sockaddr(void* res_struct);
78+void idrnet_free_recvfrom_struct(void* res_struct);
79+
80+
81+int idrnet_getaddrinfo(struct addrinfo** address_res, char* host,
82+ int port, int family, int socket_type);
83+
84+
4485#endif