Permalink
Browse files

Added a thin layer over the C socket API in rawnet.idr

  • Loading branch information...
1 parent b1223b5 commit 5f43a171791f42fc13cc4817f4b7dc88d3de79ec Edwin Brady committed Jun 2, 2011
Showing with 388 additions and 1 deletion.
  1. +2 −1 Makefile
  2. +186 −0 rawnet.c
  3. +33 −0 rawnet.h
  4. +104 −0 rawnet.idr
  5. +11 −0 tcpclient.idr
  6. +22 −0 tcpserver.idr
  7. +15 −0 udpclient.idr
  8. +15 −0 udpserver.idr
View
@@ -1,7 +1,8 @@
CFLAGS = -g `epic -includedirs`
-go: bittwiddle.o
+go: bittwiddle.o rawnet.o
idris ResIO.idr
bittwiddle.o: bittwiddle.h bittwiddle.c
+rawnet.o: rawnet.h rawnet.c
View
186 rawnet.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <closure.h>
+#include <rawnet.h>
+#include <bittwiddle.h>
+
+int prim_socket(int family, int socktype) {
+ int dom, ty;
+ if (family==0) { dom = AF_UNIX; } else { dom = AF_INET; }
+ if (socktype==0) { ty = SOCK_STREAM; } else { ty = SOCK_DGRAM; }
+
+ return socket(dom, ty, 0);
+}
+
+int prim_connect(int socket, char* host, int port)
+{
+ struct sockaddr_in name;
+ struct hostent *hostinfo;
+
+ hostinfo = gethostbyname(host);
+ if (hostinfo == NULL) {
+ return -1;
+ }
+
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr = *(struct in_addr*)hostinfo->h_addr;
+
+ return connect(socket, (struct sockaddr*)(&name),
+ sizeof(struct sockaddr_in));
+}
+
+int prim_bind(int socket, char* host, int port)
+{
+ struct sockaddr_in name;
+ struct hostent *hostinfo;
+
+ hostinfo = gethostbyname(host);
+ if (hostinfo == NULL) {
+ return -1;
+ }
+
+ memset((char *) &name, 0, sizeof(name));
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr = *(struct in_addr*)hostinfo->h_addr;
+
+ return bind(socket, (struct sockaddr*)(&name),
+ sizeof(struct sockaddr_in));
+}
+
+int prim_bind_any(int socket, int port)
+{
+ struct sockaddr_in name;
+
+ memset((char *) &name, 0, sizeof(name));
+ name.sin_family = AF_INET;
+ name.sin_port = htons(port);
+ name.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ return bind(socket, (struct sockaddr*)(&name),
+ sizeof(name));
+}
+
+int prim_listen(int socket, int maxconn)
+{
+ return listen(socket, maxconn);
+}
+
+#define NOADDR (CONSTRUCTOR1(1, MKINT(0)))
+#define EMPTYPKT (CONSTRUCTOR2(0, MKPTR(0), 0))
+
+// VAL is (SockID & SockAddr)
+VAL prim_accept(int socket)
+{
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(struct sockaddr_in);
+
+ int sock = accept(socket, (struct sockaddr*)&addr, &len);
+ VAL sockaddr;
+ if (sock==-1) {
+ sockaddr = NOADDR;
+ } else {
+ sockaddr = CONSTRUCTOR2(0, MKSTR(inet_ntoa(addr.sin_addr)),
+ MKINT(addr.sin_port));
+ }
+
+ return CONSTRUCTOR2(0, CONSTRUCTOR1(0, MKINT(sock)), sockaddr);
+}
+
+int prim_sendTo(int socket, char* host, int port, VAL stuff)
+{
+ VAL pkt = GETPTR(PROJECT(stuff,0));
+ int len = GETINT(PROJECT(stuff,1));
+ int words = len >> 5;
+ if ((len & 31)!=0) ++words;
+
+ struct sockaddr_in other;
+ memset((char *) &other, 0, sizeof(other));
+
+ other.sin_family = AF_INET;
+ other.sin_port = htons(port);
+ if (inet_aton(host, &other.sin_addr)==0) {
+ return -1;
+ }
+
+ return sendto(socket, pkt, words*sizeof(uint32_t), 0,
+ (struct sockaddr*)&other, sizeof(other));
+}
+
+// VAL is RawPacket
+int prim_send(int socket, VAL stuff)
+{
+ VAL pkt = GETPTR(PROJECT(stuff,0));
+ int len = GETINT(PROJECT(stuff,1));
+ int words = len >> 5;
+ if ((len & 31)!=0) ++words;
+
+ return send(socket, pkt, words*sizeof(uint32_t), 0);
+}
+
+// VAL is (RawPacket & SockAddr)
+VAL prim_recvFrom(int socket)
+{
+ struct sockaddr_in other;
+
+ socklen_t slen = sizeof(other);
+
+ // TMP HACK: 512 should be enough for the purposes of this experiment...
+ // Do it properly some time.
+ uint32_t* buf = (uint32_t*)EMALLOC(512*sizeof(uint32_t));
+
+ if (!isReadable(socket, 10000)) {
+ return CONSTRUCTOR2(0, EMPTYPKT, NOADDR);
+ }
+ int recvlen = recvfrom(socket, buf, 512*sizeof(uint32_t), 0,
+ (struct sockaddr*)&other, &slen);
+ if (recvlen == -1) {
+ return CONSTRUCTOR2(0, EMPTYPKT, NOADDR);
+ }
+
+ return CONSTRUCTOR2(0,
+ CONSTRUCTOR2(0, MKPTR(buf), MKINT(recvlen << 3)),
+ CONSTRUCTOR2(0, MKSTR(inet_ntoa(other.sin_addr)),
+ MKINT(ntohs(other.sin_port))));
+}
+
+// VAL is RawPacket
+VAL prim_recv(int socket)
+{
+ // TMP HACK: 512 should be enough for the purposes of this experiment...
+ // Do it properly some time.
+ uint32_t* buf = (uint32_t*)EMALLOC(512*sizeof(uint32_t));
+
+ if (!isReadable(socket, 10000)) {
+ return CONSTRUCTOR2(0, EMPTYPKT, NOADDR);
+ }
+
+ int recvlen = recv(socket, buf, 512*sizeof(word32), 0);
+
+ if (recvlen==-1) {
+ return CONSTRUCTOR2(0, EMPTYPKT, NOADDR);
+ }
+
+ return CONSTRUCTOR2(0, MKPTR(buf), MKINT(recvlen << 3));
+}
+
+void prim_shutdown(int socket, int how)
+{
+ if (how==0) {
+ shutdown(socket, SHUT_RD);
+ }
+ else {
+ shutdown(socket, SHUT_WR);
+ }
+}
View
@@ -0,0 +1,33 @@
+#ifndef _RAWNET_H
+#define _RAWNET_H
+
+#include <stdint.h>
+#include <closure.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int prim_socket(int family, int socktype);
+int prim_connect(int socket, char* host, int port);
+int prim_bind(int socket, char* host, int port);
+int prim_bind_any(int socket, int port);
+int prim_listen(int socket, int maxconn);
+// VAL is (Socket & SockAddr)
+VAL prim_accept(int socket);
+
+int prim_sendTo(int socket, char* host, int port, VAL stuff);
+// VAL is RawPacket
+int prim_send(int socket, VAL stuff);
+
+// VAL is (RawPacket & SockAddr)
+VAL prim_recvFrom(int socket);
+// VAL is RawPacket
+VAL prim_recv(int socket);
+
+void prim_shutdown(int socket, int how);
+
+#endif
View
@@ -0,0 +1,104 @@
+include "bittwiddle.idr"; -- for packet formats
+
+%include "rawnet.h"
+%lib "rawnet.o"
+
+data SockID = MkSock Int;
+
+data SocketType = Stream | Datagram;
+data Family = UNIX | INET;
+data RW = Read | Write;
+
+data SockAddr = HostPort String Int | Port Int;
+
+_prim_socket : Family -> SocketType -> IO SockID;
+_prim_connect : SockID -> SockAddr -> IO Int;
+_prim_bind : SockID -> SockAddr -> IO Int;
+_prim_listen : SockID -> Int -> IO Int;
+_prim_accept : SockID -> IO (SockID & SockAddr);
+
+_prim_sendTo : SockID -> RawPacket -> SockAddr -> IO Int;
+_prim_send : SockID -> RawPacket -> IO Int;
+
+_prim_recvFrom : SockID -> IO (RawPacket & SockAddr);
+_prim_recv : SockID -> IO RawPacket;
+
+_prim_close : SockID -> IO ();
+_prim_shutdown : SockID -> RW -> IO ();
+
+------------ Implementation ------------
+
+sockInt : SocketType -> Int;
+sockInt Stream = 0;
+sockInt Datagram = 1;
+
+intSock : Int -> SocketType;
+intSock 0 = Stream;
+intSock 1 = Datagram;
+
+famInt : Family -> Int;
+famInt UNIX = 0;
+famInt INET = 1;
+
+intFam : Int -> Family;
+intFam 0 = UNIX;
+intFam 1 = INET;
+
+validSockID : SockID -> Bool;
+validSockID (MkSock s) = s >= 0;
+
+validPacket : RawPacket -> Bool;
+validPacket (RPkt p _) = not (isNull p);
+
+f_socket = mkForeign (FFun "prim_socket" [FInt, FInt] FInt); [%eval]
+f_connect = mkForeign (FFun "prim_connect" [FInt, FStr, FInt] FInt); [%eval]
+f_bind = mkForeign (FFun "prim_bind" [FInt, FStr, FInt] FInt); [%eval]
+f_bind_any = mkForeign (FFun "prim_bind_any" [FInt, FInt] FInt); [%eval]
+f_listen = mkForeign (FFun "prim_listen" [FInt, FInt] FInt); [%eval]
+f_accept = mkForeign (FFun "prim_accept" [FInt] (FAny (SockID & SockAddr))); [%eval]
+
+f_sendTo = mkForeign (FFun "prim_sendTo" [FInt, FStr, FInt, FAny RawPacket] FInt); [%eval]
+f_send = mkForeign (FFun "prim_send" [FInt, FAny RawPacket] FInt); [%eval]
+f_recvFrom = mkForeign (FFun "prim_recvFrom" [FInt] (FAny (RawPacket & SockAddr))); [%eval]
+f_recv = mkForeign (FFun "prim_recv" [FInt] (FAny RawPacket)); [%eval]
+
+f_closesock = mkForeign (FFun "close" [FInt] FInt); [%eval]
+f_shutdown = mkForeign (FFun "prim_shutdown" [FInt, FInt] FUnit); [%eval]
+
+_prim_socket : Family -> SocketType -> IO SockID;
+_prim_socket fam ty = do { i <- f_socket (famInt fam) (sockInt ty);
+ return (MkSock i); };
+
+_prim_connect : SockID -> SockAddr -> IO Int;
+_prim_connect (MkSock s) (HostPort h p) = f_connect s h p;
+_prim_connect (MkSock s) (Port p) = return (-1);
+
+_prim_bind : SockID -> SockAddr -> IO Int;
+_prim_bind (MkSock s) (HostPort h p) = f_bind s h p;
+_prim_bind (MkSock s) (Port p) = f_bind_any s p;
+
+_prim_listen : SockID -> Int -> IO Int;
+_prim_listen (MkSock s) m = f_listen s m;
+
+_prim_accept : SockID -> IO (SockID & SockAddr);
+_prim_accept (MkSock s) = f_accept s;
+
+_prim_sendTo : SockID -> RawPacket -> SockAddr -> IO Int;
+_prim_sendTo (MkSock s) pkt (HostPort h p) = f_sendTo s h p pkt;
+_prim_sendTo (MkSock s) pkt (Port p) = return (-1);
+
+_prim_send : SockID -> RawPacket -> IO Int;
+_prim_send (MkSock s) pkt = f_send s pkt;
+
+_prim_recvFrom : SockID -> IO (RawPacket & SockAddr);
+_prim_recvFrom (MkSock s) = f_recvFrom s;
+
+_prim_recv : SockID -> IO RawPacket;
+_prim_recv (MkSock s) = f_recv s;
+
+_prim_close : SockID -> IO ();
+_prim_close (MkSock s) = do { f_closesock s; return II; };
+
+_prim_shutdown : SockID -> RW -> IO ();
+_prim_shutdown (MkSock s) Read = f_shutdown s 0;
+_prim_shutdown (MkSock s) Write = f_shutdown s 1;
View
@@ -0,0 +1,11 @@
+include "rawnet.idr";
+
+main = do { sock <- _prim_socket INET Stream;
+ r <- _prim_connect sock (HostPort "127.0.0.1" 4567);
+ putStrLn (showInt r);
+ pkt <- newPacket 32;
+ _prim_send sock pkt;
+ sleep 1;
+ dg <- _prim_recv sock;
+ putStrLn "Done";
+};
View
@@ -0,0 +1,22 @@
+include "rawnet.idr";
+
+process : (SockID & SockAddr) -> IO ();
+process (c, HostPort h p) = do { putStrLn "About to receive";
+ pkt <- _prim_recv c;
+ putStrLn ("Received from " ++ h ++ ":" ++ showInt p);
+ _prim_send c pkt;
+ return II;
+ };
+
+serverLoop : SockID -> IO ();
+serverLoop sock = do { req <- _prim_accept sock;
+ process req;
+ serverLoop sock;
+ };
+
+main = do { sock <- _prim_socket INET Stream;
+ r <- _prim_bind sock (Port 4567);
+ putStrLn (showInt r);
+ r <- _prim_listen sock 5;
+ putStrLn (showInt r);
+ serverLoop sock; };
View
@@ -0,0 +1,15 @@
+include "rawnet.idr";
+
+dump : (RawPacket & SockAddr) -> IO ();
+dump (pkt, HostPort h p) = putStrLn ("Received stuff from " ++ h ++ ":" ++
+ showInt p);
+dump (pkt, _) = putStrLn ("Got nothing");
+
+main = do { sock <- _prim_socket INET Datagram;
+ pkt <- newPacket 32;
+ -- r <- _prim_bind sock (Port 0);
+ _prim_sendTo sock pkt (HostPort "127.0.0.1" 4567);
+ sleep 1;
+ dg <- _prim_recvFrom sock;
+ dump dg;
+};
Oops, something went wrong.

0 comments on commit 5f43a17

Please sign in to comment.