From 211c14c5b5373936fe0b72c28bd295b9eed34b33 Mon Sep 17 00:00:00 2001 From: Avril Date: Sun, 12 May 2019 20:00:25 +0100 Subject: [PATCH] Initial commit --- .gitignore | 4 + libsipc/Makefile | 19 +++ libsipc/include/sipc.h | 56 +++++++++ libsipc/src/sipc.c | 277 +++++++++++++++++++++++++++++++++++++++++ libsipc/src/test.c | 158 +++++++++++++++++++++++ 5 files changed, 514 insertions(+) create mode 100644 .gitignore create mode 100644 libsipc/Makefile create mode 100644 libsipc/include/sipc.h create mode 100644 libsipc/src/sipc.c create mode 100644 libsipc/src/test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5df3ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +libsipc/test +*.o +*.so +*.socket diff --git a/libsipc/Makefile b/libsipc/Makefile new file mode 100644 index 0000000..62c1225 --- /dev/null +++ b/libsipc/Makefile @@ -0,0 +1,19 @@ +TRANS:=src/sipc.c +INCLUDE:=include/ +CFLAGS:= -c -Wall -pedantic -fPIC -I$(INCLUDE) + +all: clean libsipc test + +clean: + rm -f *.o + rm -f *.so + rm -f test + rm -f *.socket + +libsipc: + gcc $(CFLAGS) $(TRANS) + gcc -shared -o $@.so *.o + +test: libsipc + gcc -Wall -pedantic -I$(INCLUDE) -Wl,-rpath=./ src/test.c -o $@ -L./ -lsipc + ./$@ diff --git a/libsipc/include/sipc.h b/libsipc/include/sipc.h new file mode 100644 index 0000000..4c1c5c3 --- /dev/null +++ b/libsipc/include/sipc.h @@ -0,0 +1,56 @@ +#ifndef _LIBSIPC_H +#define _LIBSIPC_H +#include + +#define SI_MAX_MESSAGE_SIZE 1024 + +#define SI_ERROR_STRING_SIZE 256 +#define SI_TYPE_STRING_SIZE 256 + +#define SI_SEND_OKAY 0 +#define SI_SEND_PARTIAL 1 +#define SI_SEND_ERROR -1 +#define SI_SEND_FAILURE -2 + +#define SIQ_PRINTF_BUFFER_SIZE 256 + +typedef enum { + SI_STRING = 0, + SI_BINARY, + SI_CLOSE, + _SI_ERROR, +} si_type; + +typedef struct { + si_type type; + unsigned int data_len; + unsigned char data[]; +} si_message; + +typedef enum { + SIE_ACCEPT= 0, //Sock accept failure + SIE_READ, //Sock read failure + SIE_PCONCLS, //Sock closed before read complete + SIE_INVALID, //Invalid message +} si_error; + +typedef int (*si_callback)(const si_message *msg); +typedef int (*si_error_callback)(si_error err); + +int si_bind(const char* file); //Returns sd, or -1 on failure. +int si_listen(int sd, si_error_callback on_error, si_callback on_message); //Returns non-zero on clean exit, -1 on error. +void si_close(int sd); //Close sock (must be called after si_listen() + +char* si_error_string(si_error err); +char* si_type_string(si_type ty); + +int si_connect(const char* file); //Returns sd, or -1 on failure. +int si_sendmsg(int sd, const si_message *msg); //Returns 0 on okay, 1 if whole message could not be sent, -1 on send error, -2 on weird send error. (see SI_SEND_*) + +//Quick funcs +int siqs_string(int sd, const char* string); //quick send string +int siqs_close(int sd); //quick send close +int siqs_binary(int sd, const unsigned char* buffer, size_t size); //quick send binary +int siqs_printf(int sd, const char* format, ...); //quick send string (printf format) + +#endif /* _LIBSIPC_H */ diff --git a/libsipc/src/sipc.c b/libsipc/src/sipc.c new file mode 100644 index 0000000..a17e436 --- /dev/null +++ b/libsipc/src/sipc.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int si_bind(const char* file) +{ + int sd, rc; + struct sockaddr_un server; + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + if(sd<0) + { + return -1; + } + + memset(&server,0,sizeof(server)); + server.sun_family = AF_UNIX; + strncpy(server.sun_path, file, sizeof(server.sun_path)); + + rc = bind(sd, (struct sockaddr *)&server, SUN_LEN(&server)); + if(rc<0) + { + close(sd); + return -1; + } + + return sd; +} + +static int _si_valid_header(const si_message *msg) +{ + int kk = (int)msg->type; + return kk>=0 && kk<_SI_ERROR && msg->data_len < SI_MAX_MESSAGE_SIZE; +} + +static int _si_read_rest(int sd, si_message *message) +{ + int read = 0; + int rd=0; + + while( (read += (rd = recv(sd, message->data, message->data_len, 0))) < message->data_len) + { + if(rd<0) return -1; + else if(rd==0) return 1; + } + + return 0; +} + +int si_listen(int sd, si_error_callback on_error, si_callback on_message) +{ + int rc = listen(sd, 10); + if(rc<0) { + return -1; + } + + while(1) { + int csd = accept(sd, NULL,NULL); + if(csd<0) { + rc = on_error(SIE_ACCEPT); + if(rc<0) break; + } + unsigned char buffer[sizeof(si_message)]; + si_message *message = (si_message*)buffer; + int read=0; + int rd=0; + rc=0; + while( (read += (rd = recv(csd, buffer, sizeof(si_message), 0))) < sizeof(si_message)) + { + if(rd<0) + { + rc = on_error(SIE_READ); + break; + } else if(rd==0) + { + rc = on_error(SIE_PCONCLS); + break; + } + } + if(rc<0) { + close(csd); + break; + } else { + //message header has been read. + si_message *full; + if(_si_valid_header(message)) + { + full = malloc(sizeof(si_message)+message->data_len+1); + memset(full,0,sizeof(si_message)+message->data_len+1); //always have null-term + memcpy(full, message, sizeof(si_message)); + rc = _si_read_rest(csd, full); + } + else { + rc = on_error(SIE_INVALID); + } + if(rc!=0) { + if(rc==-1) + rc = on_error(SIE_READ); + else + rc = on_error(SIE_PCONCLS); + if(rc<0) { + close(csd); + break; + } + } else { + //Message has been read. + rc = on_message(full); + free(full); + } + } + close(csd); + if(rc!=0) break; + } + return rc; +} + +void si_close(int sd) +{ + close(sd); +} + +char *si_error_string(si_error err) +{ + static char buffer[SI_ERROR_STRING_SIZE]; + memset(buffer, 0, SI_ERROR_STRING_SIZE); +#define put(...) snprintf(buffer, SI_ERROR_STRING_SIZE-1, __VA_ARGS__) + switch(err) { + case SIE_ACCEPT: + put("SIE_ACCEPT: Socket accept error"); + break; + case SIE_READ: + put("SIE_READ: Socket read error"); + break; + case SIE_PCONCLS: + put("SIE_PCONCLS: Socket closed"); + break; + case SIE_INVALID: + put("SIE_INVALID: Bad message"); + default: + put("SIE_UNKNOWN: Unknown EC %d", (int)err); + break; + } +#undef put + return buffer; +} + +char *si_type_string(si_type type) +{ + static char buffer[SI_ERROR_STRING_SIZE]; + memset(buffer, 0, SI_ERROR_STRING_SIZE); +#define put(...) snprintf(buffer, SI_ERROR_STRING_SIZE-1, __VA_ARGS__) + switch(type) { + case SI_STRING: + put("SI_STRING"); + break; + case SI_BINARY: + put("SI_BINARY"); + break; + case SI_CLOSE: + put("SI_CLOSE"); + break; + default: + put("SI_UNKNWON"); + break; + } +#undef put + return buffer; +} + +int si_connect(const char *file) +{ + int sd=-1, rc; + struct sockaddr_un server; + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + + if(sd<0) { + return -1; + } + + memset(&server,0,sizeof(server)); + server.sun_family = AF_UNIX; + strncpy(server.sun_path, file, sizeof(server.sun_path)); + + rc = connect(sd, (struct sockaddr*)&server, SUN_LEN(&server)); + if(rc<0) { + close(sd); + return -1; + } + + return sd; +} + +int si_sendmsg(int sd, const si_message *msg) +{ + int rc = send(sd, msg, sizeof(si_message)+msg->data_len, 0); + if(rc<0) + return SI_SEND_ERROR; + else if(rc==0) + return SI_SEND_FAILURE; + else if(rc != sizeof(si_message)+msg->data_len) + return SI_SEND_PARTIAL; + + return SI_SEND_OKAY; +} + +//Quick send functions + +int siqs_string(int sd, const char* string) +{ + si_message *msg = malloc(sizeof(si_message)+strlen(string)); + memset(msg,0,sizeof(si_message)+strlen(string)); + + msg->type = SI_STRING; + msg->data_len = strlen(string); + + memcpy(msg->data, string, msg->data_len); + + int rc = si_sendmsg(sd, msg); + + free(msg); + + return rc; +} + +int siqs_close(int sd) +{ + si_message *msg = malloc(sizeof(si_message)); + memset(msg,0,sizeof(si_message)); + + msg->type = SI_CLOSE; + msg->data_len=0; + + int rc = si_sendmsg(sd, msg); + + free(msg); + return rc; +} + +int siqs_binary(int sd, const unsigned char* buffer, size_t size) +{ + si_message *msg = malloc(sizeof(si_message)+size); + memset(msg,0,sizeof(si_message)+size); + + msg->type = SI_BINARY; + msg->data_len = size; + + memcpy(msg->data, buffer, msg->data_len); + + int rc = si_sendmsg(sd, msg); + + free(msg); + return rc; +} + +int siqs_printf(int sd, const char* format, ...) +{ + char buffer[SIQ_PRINTF_BUFFER_SIZE]; + va_list list; + va_start(list, format); + memset(buffer,0,SIQ_PRINTF_BUFFER_SIZE); + + vsnprintf(buffer, SIQ_PRINTF_BUFFER_SIZE-1, format, list); + + int rc = siqs_string(sd, buffer); + + va_end(list); + + return rc; +} diff --git a/libsipc/src/test.c b/libsipc/src/test.c new file mode 100644 index 0000000..c90146c --- /dev/null +++ b/libsipc/src/test.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include + +int on_error(si_error err) +{ + printf("[E] <- %s\n", si_error_string(err)); + + return 0; +} + +int on_message(const si_message *msg) +{ + char* text; + const char* strty = si_type_string(msg->type); + + int rc=0; + + switch(msg->type) + { + case SI_CLOSE: + rc=1; + text = "..."; + break; + case SI_STRING: + text = (char*) msg->data; + break; + case SI_BINARY: + text = "..."; + break; + default: + text= "(unbound)"; + break; + } + + printf("<- (%s) %s\n", strty, text); + + return rc; +} + +int server(const char* bindto) +{ + int sd = si_bind(bindto); + int rc=-1; + if(sd<0) { + printf("error binding\n"); + } else { + rc = si_listen(sd, &on_error, &on_message); + printf("listen stopped with rc %d\n", rc); + if(rc>=0) //positive rc is okay + rc=0; + } + si_close(sd); + return rc; +} + +int cli_return(int rrc) +{ + int rc=-1; + switch(rrc) { + case SI_SEND_OKAY: + printf("send okay\n"); + rc=0; + break; + case SI_SEND_ERROR: + printf("send error\n"); + break; + case SI_SEND_FAILURE: + printf("send failure\n"); + break; + case SI_SEND_PARTIAL: + printf("partial send failure\n"); + break; + default: + printf("unknown send error"); + break; + } + return rc; +} + +int client(const char* conto, const char* string) +{ + si_message *msg = malloc(sizeof(si_message)+strlen(string)); + memset(msg,0,sizeof(si_message)+strlen(string)); + + msg->type = SI_STRING; + msg->data_len = strlen(string); + + memcpy(msg->data, string, msg->data_len); + + int rc=-1; + + int sd = si_connect(conto); + if(sd<0) { + printf("connect error\n"); + } else { + int rrc = si_sendmsg(sd, msg); + rc = cli_return(rrc); + si_close(sd); + } + + free(msg); + return rc; +} + +int client_close(const char* conto) +{ + si_message *msg = malloc(sizeof(si_message)); + memset(msg,0,sizeof(si_message)); + + msg->type = SI_CLOSE; + msg->data_len=0; + + int rc=-1; + int sd = si_connect(conto); + if(sd<0) { + printf("connect error\n"); + } else { + int rrc = si_sendmsg(sd, msg); + rc = cli_return(rrc); + si_close(sd); + } + + free(msg); + return rc; +} + +int main(int argc, char** argv) +{ + int rc=0; + if(argv[1] && argv[2] && argv[1][0]=='-') { + + switch(argv[1][1]) { + case 'l': + //Listen + rc = server(argv[2]); + break; + case 'p': + //Write + if(argv[3]) + { + rc = client(argv[2], argv[3]); + printf("client rc %d\n", rc); + } else printf("no message\n"); + break; + case 'c': + //Close + client_close(argv[2]); + break; + default: + printf("i don't know how to do that\n"); + break; + } + } else printf("usage: %s -l \nusage: %s -p \nusage: %s -c \n", argv[0], argv[0], argv[0]); + return rc; +}