added SOCKS library for socket I/O

This commit is contained in:
Justin Meza 2014-05-05 01:46:00 -04:00
parent 1fc16cd54a
commit 816ffa2b5d
9 changed files with 584 additions and 8 deletions

View File

@ -29,6 +29,7 @@ SET(HDRS
unicode.h
error.h
binding.h
inet.h
)
SET(SRCS
@ -40,6 +41,7 @@ SET(SRCS
unicode.c
error.c
binding.c
inet.c
)
add_executable(lci ${SRCS} ${HDRS})

146
binding.c
View File

@ -1,4 +1,5 @@
#include "binding.h"
#include "inet.h" /* for SOCKS */
ValueObject *getArg(struct scopeobject *scope, char *name)
{
@ -8,6 +9,102 @@ ValueObject *getArg(struct scopeobject *scope, char *name)
return val;
}
ReturnObject *iopenWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "addr");
ValueObject *arg2 = getArg(scope, "port");
char *addr = getString(arg1);
int port = getInteger(arg2);
inet_host_t *h = malloc(sizeof(inet_host_t));
inet_open(h, IN_PROT_TCP, addr, port);
ValueObject *ret = createBlobValueObject(h);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *ilookupWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "addr");
char *addr = getString(arg1);
char *h = inet_lookup(addr);
ValueObject *ret = createStringValueObject(h);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *iacceptWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "local");
inet_host_t *host = (inet_host_t *)getBlob(arg1);
inet_host_t *h = malloc(sizeof(inet_host_t));
inet_accept(h, host);
ValueObject *ret = createBlobValueObject(h);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *iconnectWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "local");
ValueObject *arg2 = getArg(scope, "addr");
ValueObject *arg3 = getArg(scope, "port");
inet_host_t *host = (inet_host_t *)getBlob(arg1);
char *addr = getString(arg2);
int port = getInteger(arg3);
inet_host_t *h = malloc(sizeof(inet_host_t));
inet_setup(h, IN_PROT_TCP, addr, port);
inet_connect(host, h);
ValueObject *ret = createBlobValueObject(h);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *icloseWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "local");
inet_host_t *host = (inet_host_t *)getBlob(arg1);
inet_close(host);
ValueObject *ret = createBlobValueObject(host);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *isendWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "local");
ValueObject *arg2 = getArg(scope, "remote");
ValueObject *arg3 = getArg(scope, "data");
inet_host_t *local = (inet_host_t *)getBlob(arg1);
inet_host_t *remote = (inet_host_t *)getBlob(arg2);
char *data = getString(arg3);
int n = inet_send(local, remote, data, strlen(data));
ValueObject *ret = createIntegerValueObject(n);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *ireceiveWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "local");
ValueObject *arg2 = getArg(scope, "remote");
ValueObject *arg3 = getArg(scope, "amount");
inet_host_t *local = (inet_host_t *)getBlob(arg1);
inet_host_t *remote = (inet_host_t *)getBlob(arg2);
int amount = getInteger(arg3);
char *data = malloc(sizeof(char) * amount);
inet_receive(remote, local, data, amount, -1);
ValueObject *ret = createStringValueObject(data);
return createReturnObject(RT_RETURN, ret);
}
ReturnObject *fopenWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "filename");
@ -58,6 +155,16 @@ ReturnObject *fcloseWrapper(struct scopeobject *scope)
return createReturnObject(RT_DEFAULT, NULL);
}
ReturnObject *rewindWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "file");
FILE *file = (FILE *)getBlob(arg1);
rewind(file);
return createReturnObject(RT_DEFAULT, NULL);
}
ReturnObject *strlenWrapper(struct scopeobject *scope)
{
ValueObject *arg1 = getArg(scope, "string");
@ -100,10 +207,11 @@ void loadLibrary(ScopeObject *scope, IdentifierNode *target)
lib = createScopeObject(scope);
if (!lib) goto loadLibraryAbort;
loadBinding(lib, "FOPENIN", "filename mode", &fopenWrapper);
loadBinding(lib, "FREADIN", "file length", &freadWrapper);
loadBinding(lib, "FWRITIN", "file data", &fwriteWrapper);
loadBinding(lib, "FCLOSIN", "file", &fcloseWrapper);
loadBinding(lib, "OPEN", "filename mode", &fopenWrapper);
loadBinding(lib, "LUK", "file length", &freadWrapper);
loadBinding(lib, "SCRIBBEL", "file data", &fwriteWrapper);
loadBinding(lib, "AGEIN", "file", &rewindWrapper);
loadBinding(lib, "CLOSE", "file", &fcloseWrapper);
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
if (!id) goto loadLibraryAbort;
@ -116,13 +224,35 @@ void loadLibrary(ScopeObject *scope, IdentifierNode *target)
if (!updateScopeValue(scope, scope, id, val)) goto loadLibraryAbort;
deleteIdentifierNode(id);
}
else if (!strcmp(name, "STRING")) {
} else if (!strcmp(name, "SOCKS")) {
lib = createScopeObject(scope);
if (!lib) goto loadLibraryAbort;
loadBinding(lib, "STRLENIN", "string", &strlenWrapper);
loadBinding(lib, "STRATIN", "string position", &stratWrapper);
loadBinding(lib, "RESOLV", "addr", &ilookupWrapper);
loadBinding(lib, "BIND", "addr port", &iopenWrapper);
loadBinding(lib, "LISTN", "local timeout", &iacceptWrapper);
loadBinding(lib, "KONN", "local addr port", &iconnectWrapper);
loadBinding(lib, "CLOSE", "local", &icloseWrapper);
loadBinding(lib, "PUT", "local remote data", &isendWrapper);
loadBinding(lib, "GET", "local remote amount", &ireceiveWrapper);
id = createIdentifierNode(IT_DIRECT, (void *)copyString("SOCKS"), NULL, NULL, 0);
if (!id) goto loadLibraryAbort;
if (!createScopeValue(scope, scope, id)) goto loadLibraryAbort;
val = createArrayValueObject(lib);
if (!val) goto loadLibraryAbort;
lib = NULL;
if (!updateScopeValue(scope, scope, id, val)) goto loadLibraryAbort;
deleteIdentifierNode(id);
} else if (!strcmp(name, "STRING")) {
lib = createScopeObject(scope);
if (!lib) goto loadLibraryAbort;
loadBinding(lib, "LEN", "string", &strlenWrapper);
loadBinding(lib, "AT", "string position", &stratWrapper);
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STRING"), NULL, NULL, 0);
if (!id) goto loadLibraryAbort;

304
inet.c Normal file
View File

@ -0,0 +1,304 @@
#include "inet.h"
// inet_setup (TCP:client / UDP:client)
//
// Sets up an inet_host structure.
void
inet_setup(inet_host_t *host,
int protocol,
const char *addr,
unsigned short port)
{
// Set up our inet_host structure
host->protocol = protocol;
// Set up our sockaddr_in structure
host->addr.sin_family = AF_INET;
host->addr.sin_port = htons(port);
host->addr.sin_addr.s_addr =
(addr == IN_ADDR_ANY ? IN_ADDR_ANY : inet_addr(addr));
memset(host->addr.sin_zero, 0, sizeof(host->addr.sin_zero));
}
// inet_open (TCP / UDP)
//
// Prepares `host' for transmission.
//
// `protocol' specifies the protocol to use for the transmission and is either
// `IN_PROT_TCP' or `IN_PROT_UDP'.
//
// `addr' is the IP address the host session structure will use: either a string
// of the form `X.X.X.X', where each `X' is the textual representation of a
// number in the range 0 to 255, or `IN_ADDR_ANY' to specify the current host's
// IP address.
//
// `port' is the port number to bind to on the host machine. Specifying
// IN_PORT_ANY attempts to use any available port assigned by the kernel. Use
// this option when the port your host structure is bound to does not matter.
//
// Returns one of:
// 0 Success.
// -EIN_SOCK Error acquiring socket file descriptor.
// -EIN_BIND Error binding socket to port.
int
inet_open(inet_host_t *host,
int protocol,
const char *addr,
unsigned short port)
{
// If we are not able to get a socket, fail with a socket error
host->fd = socket(PF_INET, protocol, 0);
if (host->fd < 0) {
perror("Error acquiring socket file descriptor!\n");
return -EIN_SOCK;
}
// Set up our sockaddr_in structure
inet_setup(host, protocol, addr, port);
// If we are not able to bind to a port, fail with a bind error
if (bind(host->fd, (struct sockaddr *)&(host->addr),
sizeof(host->addr)) < 0) {
perror("Error acquiring socket file descriptor!\n");
return -EIN_BIND;
}
// Set up our host protocol
host->protocol = protocol;
return 0;
}
// inet_accept (TCP:server)
//
// Accepts an incoming connection from the `remote' host to the `local' host.
//
// Returns one of:
// 0 Success.
// -EIN_PROT Incorrect protocol.
// -EIN_LSTN Error listening.
// -EIN_ACPT Error accepting connection.
int
inet_accept(inet_host_t *remote,
inet_host_t *local)
{
socklen_t len = sizeof(remote->addr);
// Make sure we only accept TCP sessions
if (local->protocol != IN_PROT_TCP) {
fprintf(stderr, "Error accepting from non-TCP protocol!\n");
return -EIN_PROT;
}
// Listen for an acceptable connection
if (listen(local->fd, IN_BACKLOG) < 0) {
perror("Error encountered while listening!\n");
return -EIN_LSTN;
}
// Accept the connection
remote->fd = accept(local->fd, (struct sockaddr *)&(remote->addr), &len);
if (remote->fd < 0) {
perror("Error accepting connection!\n");
return -EIN_ACPT;
}
return 0;
}
// inet_connect (TCP:client)
//
// Connects the `local' host to the `remote' host.
//
// Returns one of:
// 0 Success.
// -EIN_PROT Incorrect protocol.
// -EIN_CONN Error connecting to port.
int
inet_connect(inet_host_t *local,
inet_host_t *remote)
{
// Make sure we only connect TCP sessions
if (local->protocol != IN_PROT_TCP) {
fprintf(stderr, "Error accepting from non-TCP protocol!\n");
return -EIN_PROT;
}
// Connect to remote host
if (connect(local->fd, (struct sockaddr *)&(remote->addr), sizeof(remote->addr)) < 0) {
perror("Error connecting to remote host!\n");
return -EIN_CONN;
}
// Link `local->fd' and `remote->fd' on the client because `inet_send' always
// sends data through `remote->fd' for TCP connections (this makes sense
// intuitively, as one would send data *to* a remote address). However, a TCP
// client (which would be the only host to call this function) always
// communicates through it's `local->fd' and leaves `remote->fd' unused so we
// may safely repurpose it for the sake of continuity.
remote->fd = local->fd;
return 0;
}
// inet_receive (TCP / UDP)
//
// Receives a `len' bytes sent from `remote' to `local' and stores them in
// `data'. If no message is received within `timeout' seconds, -EIN_TIME is
// returned.
//
// Setting `timeout' to 0 causes the function to return immediately if there is
// no data to receive and setting `timeout' to -1 causes the function to block
// until data is ready to be received.
//
// Returns one of:
// Number of bytes received Success.
// -EIN_TIME Timeout.
// -EIN_RECV Error receiving data.
int
inet_receive(inet_host_t *remote,
inet_host_t *local,
void *data,
int len,
int timeout)
{
fd_set fds;
struct timeval time;
int size;
// Set the timeout interval
time.tv_sec = timeout;
time.tv_usec = 0;
// Initialize the file descriptor set
FD_ZERO(&fds);
// Depending on the protocol, receive data
switch (local->protocol) {
case IN_PROT_TCP:
FD_SET(remote->fd, &fds);
// Block for a specified amount of time
if (timeout != -1)
select(remote->fd + 1, &fds, NULL, NULL, &time);
else
select(remote->fd + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(remote->fd, &fds)) {
size = recv(remote->fd, data, len, 0);
if (size < 0) {
perror("Error receiving data!\n");
return -EIN_RECV;
}
}
else
return -EIN_TIME;
break;
case IN_PROT_UDP: {
socklen_t n = sizeof(remote->addr);
FD_SET(local->fd, &fds);
// Block for a specified amount of time
if (timeout != -1)
select(local->fd + 1, &fds, NULL, NULL, &time);
else
select(local->fd + 1, &fds, NULL, NULL, NULL);
if (FD_ISSET(local->fd, &fds)) {
size = recvfrom(local->fd, data, len, 0,
(struct sockaddr *)&(remote->addr), &n);
if (size < 0) {
perror("Error receiving data!\n");
return -EIN_RECV;
}
}
else
return -EIN_TIME;
break;
}
}
return size;
}
// inet_send (TCP / UDP)
//
// Sends `len' bytes of `data' from `local' to `remote'.
//
// Returns one of:
// Number of bytes sent Success.
// -EIN_SEND Error sending data.
int
inet_send(inet_host_t *local,
inet_host_t *remote,
void *data,
int len)
{
int size;
// Depending on the protocol, send data
switch (local->protocol) {
case IN_PROT_TCP:
size = send(remote->fd, data, len, 0);
if (size < 0) {
perror("Error sending data!\n");
return -EIN_SEND;
}
break;
case IN_PROT_UDP: {
size = sendto(local->fd, data, len, 0,
(struct sockaddr *)&(remote->addr), sizeof(remote->addr));
if (size < 0) {
perror("Error sending data!\n");
return -EIN_SEND;
}
break;
}
}
return size;
}
// inet_close (TCP / UDP)
//
// Closes an inet connection.
//
// Returns one of:
// 0 Success.
// -1 Invalid `host' pointer.
int
inet_close(inet_host_t *host)
{
// Sanity check
if (!host) return -1;
// Close the file descriptor
if (host->fd) close(host->fd);
return 0;
}
// inet_lookup
//
// Looks up information by resolving a DNS name and returns a pointer to the
// resolved IP address.
//
// Returns one of:
// 0 Unable to resolve name.
// Pointer to resolved IP address Must be freed by caller.
char *
inet_lookup(const char *name)
{
char *hostname;
char *temp;
struct hostent *ent;
// If unable to get host by name, quit with lookup error
if (!(ent = gethostbyname(name))) {
herror("gethostbyname");
return 0;
}
// Copy the looked up name
temp = inet_ntoa(*((struct in_addr *)ent->h_addr));
hostname = malloc(sizeof(char) * (strlen(temp) + 1));
strcpy(hostname, temp);
return hostname;
}

113
inet.h Normal file
View File

@ -0,0 +1,113 @@
// inet.h
// A library for simplifying networked communication.
// 2008-4-27
//
// MAINTAINER
//
// Justin J. Meza <justin dot meza at gmail dot com>
//
// LICENSE
//
// You are free to use, modify, and re-distribute this software provided
// that you make any modifications publicly available. Additionally, this
// software is provided without any warranty; use of this software is at the
// user's own risk. The author disclaims any liability for malfunctions as a
// result of this software or any derivative works produced with it.
//
// Please report and bugs, fixes, and improvements to the maintainer.
//
// This library allows two `host's (specifically, two processes) to connect and
// exchange data in a session using either TCP or UDP.
//
// The following two diagrams list the general order of function calls required
// to handle a session for TCP and UDP. The order of function calls in `SETUP'
// must be strictly followed; `TRANSMISSION' and `TEARDOWN' function calls may
// be done in any order and some examples are listed.
//
// Functions are labeled in the form ([TCP]:[client|server] /
// [UDP]:[client|server]) to denote whether the function is meant to be used by
// TCP, UDP, or either connection type and furthermore whether only clients,
// servers, or either are meant to call the function.
//
// +===========================================+
// | TCP |
// +=====================+=====================+
// | SERVER | CLIENT |
// +---------------------+---------------------+
// | inet_open | inet_open |\ \
// | inet_accept | inet_setup | | SETUP |
// | | inet_connect |/ |
// | | | |
// | inet_receive | inet_send |\ TRANSMISSION > SESSION
// | inet_send | inet_receive |/ |
// | | | |
// | inet_close(local) | inet_close(local) |\ TEARDOWN |
// | inet_close(remote) | |/ /
// +---------------------+---------------------+
//
// +===========================================+
// | UDP |
// +=====================+=====================+
// | SERVER | CLIENT |
// +---------------------+---------------------+
// | inet_open | inet_open |\ SETUP \
// | | inet_setup |/ |
// | | | |
// | inet_receive | inet_send |\ TRANSMISSION > SESSION
// | inet_send | inet_receive |/ |
// | | | |
// | inet_close | inet_close |> TEARDOWN /
// +---------------------+---------------------+
#ifndef __INET_H__
#define __INET_H__
#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 <sys/time.h>
#define IN_PORT_ANY 0
#define IN_ADDR_ANY INADDR_ANY
#define IN_PROT_TCP SOCK_STREAM
#define IN_PROT_UDP SOCK_DGRAM
#define IN_BACKLOG 10 // Number of simultaneous incoming connections to allow
#define IN_HOSTLEN 64 //
// Set up our error codes
typedef enum err_code {
EIN_SOCK = 2, // Error acquiring socket file descriptor
EIN_BIND, // Error binding socket to port
EIN_CONN, // Error connecting to port
EIN_PROT, // Incorrect protocol
EIN_LSTN, // Error listening
EIN_ACPT, // Error accepting connection
EIN_SEND, // Error sending data
EIN_RECV, // Error receiving data
EIN_TIME, // Timeout
} err_code_t;
// Structure representing an internet host
typedef struct inet_host {
int fd;
int protocol;
struct sockaddr_in addr;
} inet_host_t;
void inet_setup(inet_host_t *, int, const char *, unsigned short);
int inet_open(inet_host_t *, int, const char *, unsigned short);
int inet_accept(inet_host_t *, inet_host_t *);
int inet_connect(inet_host_t *, inet_host_t *);
int inet_receive(inet_host_t *, inet_host_t *, void *, int, int);
int inet_send(inet_host_t *, inet_host_t *, void *, int);
int inet_close(inet_host_t *);
char *inet_lookup(const char *);
#endif // __INET_H__

View File

@ -0,0 +1,6 @@
HAI 1.4
CAN HAS SOCKS?
I HAS A addr
addr R I IZ SOCKS'Z RESOLV YR "localhost" MKAY
VISIBLE addr
KTHXBYE

View File

@ -0,0 +1 @@
127.0.0.1

View File

@ -0,0 +1,8 @@
HAI 1.4
CAN HAS SOCKS?
I HAS A sock
I HAS A conn
sock R I IZ SOCKS'Z BIND YR "127.0.0.1" AN YR 13337 MKAY
I IZ SOCKS'Z CLOSE YR sock MKAY
VISIBLE "done"
KTHXBYE

View File

@ -0,0 +1 @@
done

View File

@ -0,0 +1,11 @@
HAI 1.4
CAN HAS SOCKS?
I HAS A sock
I HAS A conn
sock R I IZ SOCKS'Z BIND YR "127.0.0.1" AN YR 13337 MKAY
conn R I IZ SOCKS'Z LISTN YR sock MKAY
I HAS A cmd
cmd R I IZ SOCKS'Z GET YR sock AN YR conn AN YR 10 MKAY
VISIBLE "CMD IZ " AN cmd
BTW $ cat "HAI" | nc 127.0.0.1 13337
KTHXBYE