commit
211c14c5b5
@ -0,0 +1,4 @@
|
||||
libsipc/test
|
||||
*.o
|
||||
*.so
|
||||
*.socket
|
@ -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
|
||||
./$@
|
@ -0,0 +1,56 @@
|
||||
#ifndef _LIBSIPC_H
|
||||
#define _LIBSIPC_H
|
||||
#include <stddef.h>
|
||||
|
||||
#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 */
|
@ -0,0 +1,277 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/un.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sipc.h>
|
||||
|
||||
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;
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
#include <sipc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
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 <socket>\nusage: %s -p <socket> <message>\nusage: %s -c <socket>\n", argv[0], argv[0], argv[0]);
|
||||
return rc;
|
||||
}
|
Loading…
Reference in new issue