added SOCKS library for socket I/O
This commit is contained in:
parent
1fc16cd54a
commit
816ffa2b5d
|
@ -29,6 +29,7 @@ SET(HDRS
|
||||||
unicode.h
|
unicode.h
|
||||||
error.h
|
error.h
|
||||||
binding.h
|
binding.h
|
||||||
|
inet.h
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(SRCS
|
SET(SRCS
|
||||||
|
@ -40,6 +41,7 @@ SET(SRCS
|
||||||
unicode.c
|
unicode.c
|
||||||
error.c
|
error.c
|
||||||
binding.c
|
binding.c
|
||||||
|
inet.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(lci ${SRCS} ${HDRS})
|
add_executable(lci ${SRCS} ${HDRS})
|
||||||
|
|
146
binding.c
146
binding.c
|
@ -1,4 +1,5 @@
|
||||||
#include "binding.h"
|
#include "binding.h"
|
||||||
|
#include "inet.h" /* for SOCKS */
|
||||||
|
|
||||||
ValueObject *getArg(struct scopeobject *scope, char *name)
|
ValueObject *getArg(struct scopeobject *scope, char *name)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +9,102 @@ ValueObject *getArg(struct scopeobject *scope, char *name)
|
||||||
return val;
|
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)
|
ReturnObject *fopenWrapper(struct scopeobject *scope)
|
||||||
{
|
{
|
||||||
ValueObject *arg1 = getArg(scope, "filename");
|
ValueObject *arg1 = getArg(scope, "filename");
|
||||||
|
@ -58,6 +155,16 @@ ReturnObject *fcloseWrapper(struct scopeobject *scope)
|
||||||
return createReturnObject(RT_DEFAULT, NULL);
|
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)
|
ReturnObject *strlenWrapper(struct scopeobject *scope)
|
||||||
{
|
{
|
||||||
ValueObject *arg1 = getArg(scope, "string");
|
ValueObject *arg1 = getArg(scope, "string");
|
||||||
|
@ -100,10 +207,11 @@ void loadLibrary(ScopeObject *scope, IdentifierNode *target)
|
||||||
lib = createScopeObject(scope);
|
lib = createScopeObject(scope);
|
||||||
if (!lib) goto loadLibraryAbort;
|
if (!lib) goto loadLibraryAbort;
|
||||||
|
|
||||||
loadBinding(lib, "FOPENIN", "filename mode", &fopenWrapper);
|
loadBinding(lib, "OPEN", "filename mode", &fopenWrapper);
|
||||||
loadBinding(lib, "FREADIN", "file length", &freadWrapper);
|
loadBinding(lib, "LUK", "file length", &freadWrapper);
|
||||||
loadBinding(lib, "FWRITIN", "file data", &fwriteWrapper);
|
loadBinding(lib, "SCRIBBEL", "file data", &fwriteWrapper);
|
||||||
loadBinding(lib, "FCLOSIN", "file", &fcloseWrapper);
|
loadBinding(lib, "AGEIN", "file", &rewindWrapper);
|
||||||
|
loadBinding(lib, "CLOSE", "file", &fcloseWrapper);
|
||||||
|
|
||||||
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
|
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0);
|
||||||
if (!id) goto loadLibraryAbort;
|
if (!id) goto loadLibraryAbort;
|
||||||
|
@ -116,13 +224,35 @@ void loadLibrary(ScopeObject *scope, IdentifierNode *target)
|
||||||
|
|
||||||
if (!updateScopeValue(scope, scope, id, val)) goto loadLibraryAbort;
|
if (!updateScopeValue(scope, scope, id, val)) goto loadLibraryAbort;
|
||||||
deleteIdentifierNode(id);
|
deleteIdentifierNode(id);
|
||||||
}
|
} else if (!strcmp(name, "SOCKS")) {
|
||||||
else if (!strcmp(name, "STRING")) {
|
|
||||||
lib = createScopeObject(scope);
|
lib = createScopeObject(scope);
|
||||||
if (!lib) goto loadLibraryAbort;
|
if (!lib) goto loadLibraryAbort;
|
||||||
|
|
||||||
loadBinding(lib, "STRLENIN", "string", &strlenWrapper);
|
loadBinding(lib, "RESOLV", "addr", &ilookupWrapper);
|
||||||
loadBinding(lib, "STRATIN", "string position", &stratWrapper);
|
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);
|
id = createIdentifierNode(IT_DIRECT, (void *)copyString("STRING"), NULL, NULL, 0);
|
||||||
if (!id) goto loadLibraryAbort;
|
if (!id) goto loadLibraryAbort;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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__
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
127.0.0.1
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
done
|
|
@ -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
|
Loading…
Reference in New Issue