@@ -1,6 +1,7 @@
1// C-Side of the Idris network library
1// C-Side of the Idris network library
2// (C) Simon Fowler, 2014
2// (C) Simon Fowler, 2014
3// MIT Licensed. Have fun!
3// MIT Licensed. Have fun!
4#include <errno.h>
5#include <errno.h>
5#include <netdb.h>
6#include <netdb.h>
6#include <stdbool.h>
7#include <stdbool.h>
@@ -12,7 +13,21 @@
12#include <netinet/in.h>
13#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <arpa/inet.h>
15−#include "idris_net.h"
16+void buf_htonl(void* buf, int len) {
17+ int* buf_i = (int*) buf;
19+ for (i = 0; i < (len / sizeof(int)) + 1; i++) {
20+ buf_i[i] = htonl(buf_i[i]);
24+void buf_ntohl(void* buf, int len) {
25+ int* buf_i = (int*) buf;
27+ for (i = 0; i < (len / sizeof(int)) + 1; i++) {
28+ buf_i[i] = ntohl(buf_i[i]);
17void* idrnet_malloc(int size) {
32void* idrnet_malloc(int size) {
18 return malloc(size);
33 return malloc(size);
@@ -22,9 +37,12 @@ void idrnet_free(void* ptr) {
22 free(ptr);
37 free(ptr);
40+// We call this from quite a few functions. Given a textual host and an int port,
41+// populates a struct addrinfo.
42+int idrnet_getaddrinfo(struct addrinfo** address_res, char* host, int port,
25−int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
43+ int family, int socket_type) {
26 struct addrinfo hints;
45 struct addrinfo hints;
27− struct addrinfo* address_res;
28 // Convert port into string
46 // Convert port into string
29 char str_port[8];
47 char str_port[8];
30 sprintf(str_port, "%d", port);
48 sprintf(str_port, "%d", port);
@@ -38,43 +56,42 @@ int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
38 // then we want to instruct the C library to fill in the IP automatically
56 // then we want to instruct the C library to fill in the IP automatically
39 if (strlen(host) == 0) {
57 if (strlen(host) == 0) {
40 hints.ai_flags = AI_PASSIVE; // fill in IP automatically
58 hints.ai_flags = AI_PASSIVE; // fill in IP automatically
59+ return getaddrinfo(NULL, str_port, &hints, address_res);
61+ return getaddrinfo(host, str_port, &hints, address_res);
43− int addr_res = getaddrinfo(host, str_port, &hints, &address_res);
63+}
65+int idrnet_bind(int sockfd, int family, int socket_type, char* host, int port) {
66+ struct addrinfo* address_res;
67+ int addr_res = idrnet_getaddrinfo(&address_res, host, port, family, socket_type);
44 if (addr_res == -1) {
68 if (addr_res == -1) {
69+ //printf("Lib err: bind getaddrinfo\n");
45 return -1;
70 return -1;
48 int bind_res = bind(sockfd, address_res->ai_addr, address_res->ai_addrlen);
73 int bind_res = bind(sockfd, address_res->ai_addr, address_res->ai_addrlen);
49 if (bind_res == -1) {
74 if (bind_res == -1) {
75+ //freeaddrinfo(address_res);
76+ //printf("Lib err: bind\n");
50 return -1;
77 return -1;
56int idrnet_connect(int sockfd, int family, int socket_type, char* host, int port) {
82int idrnet_connect(int sockfd, int family, int socket_type, char* host, int port) {
58− sprintf(str_port, "%d", port);
59− struct addrinfo hints;
60 struct addrinfo* remote_host;
83 struct addrinfo* remote_host;
61−
84+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, socket_type);
62− // Set up hints structure for getaddrinfo
63− memset(&hints, 0, sizeof(hints));
64− hints.ai_family = family;
65− hints.ai_socktype = socket_type;
67− // Get info about the remote host (DNS lookup etc)
68− int addr_res = getaddrinfo(host, str_port, &hints, &remote_host);
69 if (addr_res == -1) {
85 if (addr_res == -1) {
70 return -1;
86 return -1;
73 int connect_res = connect(sockfd, remote_host->ai_addr, remote_host->ai_addrlen);
89 int connect_res = connect(sockfd, remote_host->ai_addr, remote_host->ai_addrlen);
74 if (connect_res == -1) {
90 if (connect_res == -1) {
91+ freeaddrinfo(remote_host);
75 return -1;
92 return -1;
77−
94+ freeaddrinfo(remote_host);
@@ -88,9 +105,15 @@ char* idrnet_sockaddr_ipv4(void* sockaddr) {
88 struct sockaddr_in* addr = (struct sockaddr_in*) sockaddr;
105 struct sockaddr_in* addr = (struct sockaddr_in*) sockaddr;
89 char* ip_addr = (char*) malloc(sizeof(char) * INET_ADDRSTRLEN);
106 char* ip_addr = (char*) malloc(sizeof(char) * INET_ADDRSTRLEN);
90 inet_ntop(AF_INET, &(addr->sin_addr), ip_addr, INET_ADDRSTRLEN);
107 inet_ntop(AF_INET, &(addr->sin_addr), ip_addr, INET_ADDRSTRLEN);
108+ //printf("Lib: ip_addr: %s\n", ip_addr);
91 return ip_addr;
109 return ip_addr;
112+int idrnet_sockaddr_ipv4_port(void* sockaddr) {
113+ struct sockaddr_in* addr = (struct sockaddr_in*) addr;
114+ return ((int) ntohs(addr->sin_port));
94void* idrnet_create_sockaddr() {
117void* idrnet_create_sockaddr() {
95 return malloc(sizeof(struct sockaddr_storage));
118 return malloc(sizeof(struct sockaddr_storage));
@@ -108,33 +131,43 @@ int idrnet_send(int sockfd, char* data) {
110int idrnet_send_buf(int sockfd, void* data, int len) {
133int idrnet_send_buf(int sockfd, void* data, int len) {
134+ void* buf_cpy = malloc(len);
135+ memset(buf_cpy, 0, len);
136+ memcpy(buf_cpy, data, len);
137+ buf_htonl(buf_cpy, len);
111− return send(sockfd, data, len, 0);
138+ int res = send(sockfd, buf_cpy, len, 0);
114void* idrnet_recv(int sockfd, int len) {
143void* idrnet_recv(int sockfd, int len) {
115 idrnet_recv_result* res_struct =
144 idrnet_recv_result* res_struct =
116 (idrnet_recv_result*) malloc(sizeof(idrnet_recv_result));
145 (idrnet_recv_result*) malloc(sizeof(idrnet_recv_result));
118 char* buf = malloc(len + 1);
146 char* buf = malloc(len + 1);
147+ memset(buf, 0, len + 1);
119 int recv_res = recv(sockfd, buf, len, 0);
148 int recv_res = recv(sockfd, buf, len, 0);
120 res_struct->result = recv_res;
149 res_struct->result = recv_res;
122 if (recv_res > 0) { // Data was received
151 if (recv_res > 0) { // Data was received
123 buf[recv_res + 1] = 0x00; // Null-term, so Idris can interpret it
152 buf[recv_res + 1] = 0x00; // Null-term, so Idris can interpret it
125− res_struct->payload = (void*) buf;
154+ res_struct->payload = buf;
126 return (void*) res_struct;
155 return (void*) res_struct;
129int idrnet_recv_buf(int sockfd, void* buf, int len) {
158int idrnet_recv_buf(int sockfd, void* buf, int len) {
130− return recv(sockfd, buf, len, 0);
159+ int recv_res = recv(sockfd, buf, len, 0);
160+ if (recv_res != -1) {
161+ buf_ntohl(buf, len);
133int idrnet_get_recv_res(void* res_struct) {
166int idrnet_get_recv_res(void* res_struct) {
134 return (((idrnet_recv_result*) res_struct)->result);
167 return (((idrnet_recv_result*) res_struct)->result);
137−void* idrnet_get_recv_payload(void* res_struct) {
170+char* idrnet_get_recv_payload(void* res_struct) {
138 return (((idrnet_recv_result*) res_struct)->payload);
171 return (((idrnet_recv_result*) res_struct)->payload);
@@ -151,3 +184,137 @@ int idrnet_errno() {
151 return errno;
184 return errno;
188+int idrnet_sendto(int sockfd, char* data, char* host, int port, int family) {
190+ struct addrinfo* remote_host;
191+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, SOCK_DGRAM);
192+ if (addr_res == -1) {
196+ int send_res = sendto(sockfd, data, strlen(data), 0,
197+ remote_host->ai_addr, remote_host->ai_addrlen);
198+ freeaddrinfo(remote_host);
202+int idrnet_sendto_buf(int sockfd, void* buf, int buf_len, char* host, int port, int family) {
204+ struct addrinfo* remote_host;
205+ int addr_res = idrnet_getaddrinfo(&remote_host, host, port, family, SOCK_DGRAM);
206+ if (addr_res == -1) {
207+ //printf("lib err: sendto getaddrinfo \n");
211+ buf_htonl(buf, buf_len);
213+ int send_res = sendto(sockfd, buf, buf_len, 0,
214+ remote_host->ai_addr, remote_host->ai_addrlen);
215+ if (send_res == -1) {
216+ perror("lib err: sendto \n");
218+ //freeaddrinfo(remote_host);
224+void* idrnet_recvfrom(int sockfd, int len) {
226+ * int recvfrom(int sockfd, void *buf, int len, unsigned int flags,
227+ struct sockaddr *from, int *fromlen);
229+ // Allocate the required structures, and nuke them
230+ struct sockaddr_storage* remote_addr =
231+ (struct sockaddr_storage*) malloc(sizeof(struct sockaddr_storage));
232+ char* buf = (char*) malloc(len + 1);
233+ idrnet_recvfrom_result* ret =
234+ (idrnet_recvfrom_result*) malloc(sizeof(idrnet_recvfrom_result));
235+ memset(remote_addr, 0, sizeof(struct sockaddr_storage));
236+ memset(buf, 0, len + 1);
237+ memset(ret, 0, sizeof(idrnet_recvfrom_result));
238+ socklen_t fromlen = sizeof(struct sockaddr_storage);
240+ int recv_res = recvfrom(sockfd, buf, len, 0, (struct sockaddr*) remote_addr, &fromlen);
241+ ret->result = recv_res;
242+ // Check for failure...
243+ if (recv_res == -1) {
247+ // If data was received, process and populate
248+ ret->result = recv_res;
249+ ret->remote_addr = remote_addr;
250+ // Ensure the last byte is NULL, since in this mode we're sending strings
252+ ret->payload = (void*) buf;
259+void* idrnet_recvfrom_buf(int sockfd, void* buf, int len) {
260+ // Allocate the required structures, and nuke them
261+ struct sockaddr_storage* remote_addr =
262+ (struct sockaddr_storage*) malloc(sizeof(struct sockaddr_storage));
263+ idrnet_recvfrom_result* ret =
264+ (idrnet_recvfrom_result*) malloc(sizeof(idrnet_recvfrom_result));
265+ memset(remote_addr, 0, sizeof(struct sockaddr_storage));
266+ memset(ret, 0, sizeof(idrnet_recvfrom_result));
267+ socklen_t fromlen = 0;
269+ int recv_res = recvfrom(sockfd, buf, len, 0, (struct sockaddr*) remote_addr, &fromlen);
270+ // Check for failure... But don't free the buffer! Not our job.
271+ ret->result = recv_res;
272+ if (recv_res == -1) {
275+ // Payload will be NULL -- since it's been put into the user-specified buffer. We
276+ // still need the return struct to get our hands on the remote address, though.
278+ buf_ntohl(buf, len);
279+ ret->payload = NULL;
280+ ret->remote_addr = remote_addr;
285+int idrnet_get_recvfrom_res(void* res_struct) {
286+ return (((idrnet_recvfrom_result*) res_struct)->result);
289+char* idrnet_get_recvfrom_payload(void* res_struct) {
290+ return (((idrnet_recvfrom_result*) res_struct)->payload);
293+void* idrnet_get_recvfrom_sockaddr(void* res_struct) {
294+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
295+ return recv_struct->remote_addr;
298+int idrnet_get_recvfrom_port(void* res_struct) {
299+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
300+ if (recv_struct->remote_addr != NULL) {
301+ struct sockaddr_in* remote_addr_in =
302+ (struct sockaddr_in*) recv_struct->remote_addr;
303+ return ((int) ntohs(remote_addr_in->sin_port));
308+void idrnet_free_recvfrom_struct(void* res_struct) {
309+ idrnet_recvfrom_result* recv_struct = (idrnet_recvfrom_result*) res_struct;
310+ if (recv_struct != NULL) {
311+ if (recv_struct->payload != NULL) {
312+ free(recv_struct->payload);
314+ if (recv_struct->remote_addr != NULL) {
315+ free(recv_struct->remote_addr);