libipc split into its own, separate repository.

more_to_read
Luka Vandervelden 2018-11-20 18:44:49 +09:00
parent ab3d9dd344
commit 878432e7eb
97 changed files with 379 additions and 6444 deletions

326
Makefile Normal file
View File

@ -0,0 +1,326 @@
PACKAGE = 'ipc'
VERSION = '0.1.0'
PREFIX := /usr/local
BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib
SHAREDIR := $(PREFIX)/share
INCLUDEDIR := $(PREFIX)/include
MANDIR := $(SHAREDIR)/man
CC := cc
AR := ar
RANLIB := ranlib
CFLAGS :=
LDFLAGS :=
Q := @
all: libipc src/ipc.h man/libipc.7
@:
libipc: libipc.so libipc.a
@:
libipc.install: libipc.so.install libipc.a.install
libipc.clean: libipc.so.clean libipc.a.clean
libipc.uninstall: libipc.so.uninstall libipc.a.uninstall
src/ipc.h.install: src/ipc.h
@echo ' IN > $(INCLUDEDIR)/ipc.h'
$(Q)mkdir -p '$(DESTDIR)$(INCLUDEDIR)'
$(Q)install -m0644 src/ipc.h $(DESTDIR)$(INCLUDEDIR)/ipc.h
src/ipc.h.clean: src/ipc.h
$(Q):
src/ipc.h.uninstall:
@echo ' RM > $(INCLUDEDIR)/ipc.h'
$(Q)rm -f '$(DESTDIR)$(INCLUDEDIR)/ipc.h'
man/libipc.7: man/libipc.7.md
@echo ' MAN > man/libipc.7'
$(Q)pandoc -s --from markdown --to man 'man/libipc.7.md' -o 'man/libipc.7'
man/libipc.7.install: man/libipc.7
@echo ' IN > $(MANDIR)/man7/libipc.7'
$(Q)mkdir -p '$(DESTDIR)$(MANDIR)/man7'
$(Q)install -m0644 man/libipc.7 $(DESTDIR)$(MANDIR)/man7/libipc.7
man/libipc.7.clean:
@echo ' RM > man/libipc.7'
$(Q)rm -f man/libipc.7
man/libipc.7.uninstall:
@echo ' RM > $(MANDIR)/man7/libipc.7'
$(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7'
libipc.so: src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o
@echo ' LD > libipc.so'
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o
libipc.so.install: libipc.so
@echo ' IN > $(LIBDIR)/libipc.so.0.1.0'
$(Q)mkdir -p '$(DESTDIR)$(LIBDIR)'
$(Q)install -m0755 libipc.so $(DESTDIR)$(LIBDIR)/libipc.so.0.1.0
@echo ' LN > $(LIBDIR)/libipc.so.0.1'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so.0.1'
@echo ' LN > $(LIBDIR)/libipc.so.0'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so.0'
@echo ' LN > $(LIBDIR)/libipc.so'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.1.0' '$(DESTDIR)/$(LIBDIR)/libipc.so'
libipc.so.clean:
@echo ' RM > libipc.so'
$(Q)rm -f libipc.so
libipc.so.uninstall:
@echo ' RM > $(LIBDIR)/libipc.so.0.1.0'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.1.0'
@echo ' RM > $(LIBDIR)/libipc.so.0.1'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.1'
@echo ' RM > $(LIBDIR)/libipc.so.0'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0'
@echo ' RM > $(LIBDIR)/libipc.so'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so'
libipc.a: src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o
@echo ' LD > libipc.a'
$(Q)$(AR) rc 'libipc.a' src/client.o src/communication.o src/logger.o src/message.o src/usocket.o src/utils.o
libipc.a.install: libipc.a
@echo ' IN > $(LIBDIR)/libipc.a'
$(Q)mkdir -p '$(DESTDIR)$(LIBDIR)'
$(Q)install -m0755 libipc.a $(DESTDIR)$(LIBDIR)/libipc.a
libipc.a.clean:
@echo ' RM > libipc.a'
$(Q)rm -f libipc.a
libipc.a.uninstall:
@echo ' RM > $(LIBDIR)/libipc.a'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.a'
src/client.o: src/client.c src/client.h
@echo ' CC > src/client.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/client.c -fPIC -o src/client.o
src/client.o.install:
src/client.o.clean:
@echo ' RM > src/client.o'
$(Q)rm -f src/client.o
src/client.o.uninstall:
src/communication.o: src/communication.c src/communication.h src/utils.h src/error.h src/event.h
@echo ' CC > src/communication.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/communication.c -fPIC -o src/communication.o
src/communication.o.install:
src/communication.o.clean:
@echo ' RM > src/communication.o'
$(Q)rm -f src/communication.o
src/communication.o.uninstall:
src/logger.o: src/logger.c src/logger.h
@echo ' CC > src/logger.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/logger.c -fPIC -o src/logger.o
src/logger.o.install:
src/logger.o.clean:
@echo ' RM > src/logger.o'
$(Q)rm -f src/logger.o
src/logger.o.uninstall:
src/message.o: src/message.c src/message.h src/error.h src/usocket.h
@echo ' CC > src/message.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/message.c -fPIC -o src/message.o
src/message.o.install:
src/message.o.clean:
@echo ' RM > src/message.o'
$(Q)rm -f src/message.o
src/message.o.uninstall:
src/usocket.o: src/usocket.c src/usocket.h src/utils.h src/error.h
@echo ' CC > src/usocket.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/usocket.c -fPIC -o src/usocket.o
src/usocket.o.install:
src/usocket.o.clean:
@echo ' RM > src/usocket.o'
$(Q)rm -f src/usocket.o
src/usocket.o.uninstall:
src/utils.o: src/utils.c src/utils.h
@echo ' CC > src/utils.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c src/utils.c -fPIC -o src/utils.o
src/utils.o.install:
src/utils.o.clean:
@echo ' RM > src/utils.o'
$(Q)rm -f src/utils.o
src/utils.o.uninstall:
$(DESTDIR)$(PREFIX):
@echo ' DIR > $(PREFIX)'
$(Q)mkdir -p $(DESTDIR)$(PREFIX)
$(DESTDIR)$(BINDIR):
@echo ' DIR > $(BINDIR)'
$(Q)mkdir -p $(DESTDIR)$(BINDIR)
$(DESTDIR)$(LIBDIR):
@echo ' DIR > $(LIBDIR)'
$(Q)mkdir -p $(DESTDIR)$(LIBDIR)
$(DESTDIR)$(SHAREDIR):
@echo ' DIR > $(SHAREDIR)'
$(Q)mkdir -p $(DESTDIR)$(SHAREDIR)
$(DESTDIR)$(INCLUDEDIR):
@echo ' DIR > $(INCLUDEDIR)'
$(Q)mkdir -p $(DESTDIR)$(INCLUDEDIR)
$(DESTDIR)$(MANDIR):
@echo ' DIR > $(MANDIR)'
$(Q)mkdir -p $(DESTDIR)$(MANDIR)
install: subdirs.install libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/client.o.install src/communication.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install src/client.o.install src/communication.o.install src/logger.o.install src/message.o.install src/usocket.o.install src/utils.o.install
@:
subdirs.install:
uninstall: subdirs.uninstall libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/client.o.uninstall src/communication.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/client.o.uninstall src/communication.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall
@:
subdirs.uninstall:
test: all subdirs subdirs.test
@:
subdirs.test:
clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/client.o.clean src/communication.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean src/client.o.clean src/communication.o.clean src/logger.o.clean src/message.o.clean src/usocket.o.clean src/utils.o.clean
distclean: clean
dist: dist-gz dist-xz dist-bz2
$(Q)rm -- $(PACKAGE)-$(VERSION)
distdir:
$(Q)rm -rf -- $(PACKAGE)-$(VERSION)
$(Q)ln -s -- . $(PACKAGE)-$(VERSION)
dist-gz: $(PACKAGE)-$(VERSION).tar.gz
$(PACKAGE)-$(VERSION).tar.gz: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.gz'
$(Q)tar czf $(PACKAGE)-$(VERSION).tar.gz \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/error.h \
$(PACKAGE)-$(VERSION)/src/ipc.h \
$(PACKAGE)-$(VERSION)/src/event.h \
$(PACKAGE)-$(VERSION)/man/libipc.7.md \
$(PACKAGE)-$(VERSION)/src/client.c \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/client.h \
$(PACKAGE)-$(VERSION)/src/communication.h \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h
dist-xz: $(PACKAGE)-$(VERSION).tar.xz
$(PACKAGE)-$(VERSION).tar.xz: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.xz'
$(Q)tar cJf $(PACKAGE)-$(VERSION).tar.xz \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/error.h \
$(PACKAGE)-$(VERSION)/src/ipc.h \
$(PACKAGE)-$(VERSION)/src/event.h \
$(PACKAGE)-$(VERSION)/man/libipc.7.md \
$(PACKAGE)-$(VERSION)/src/client.c \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/client.h \
$(PACKAGE)-$(VERSION)/src/communication.h \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h
dist-bz2: $(PACKAGE)-$(VERSION).tar.bz2
$(PACKAGE)-$(VERSION).tar.bz2: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.bz2'
$(Q)tar cjf $(PACKAGE)-$(VERSION).tar.bz2 \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/src/error.h \
$(PACKAGE)-$(VERSION)/src/ipc.h \
$(PACKAGE)-$(VERSION)/src/event.h \
$(PACKAGE)-$(VERSION)/man/libipc.7.md \
$(PACKAGE)-$(VERSION)/src/client.c \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/client.h \
$(PACKAGE)-$(VERSION)/src/communication.h \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h
help:
@echo ' :: ipc-0.1.0'
@echo ''
@echo 'Generic targets:'
@echo ' - help  Prints this help message.'
@echo ' - all  Builds all targets.'
@echo ' - dist  Creates tarballs of the files of the project.'
@echo ' - install  Installs the project.'
@echo ' - clean  Removes compiled files.'
@echo ' - uninstall  Deinstalls the project.'
@echo ''
@echo 'CLI-modifiable variables:'
@echo ' - CC  ${CC}'
@echo ' - CFLAGS  ${CFLAGS}'
@echo ' - LDFLAGS  ${LDFLAGS}'
@echo ' - DESTDIR  ${DESTDIR}'
@echo ' - PREFIX  ${PREFIX}'
@echo ' - BINDIR  ${BINDIR}'
@echo ' - LIBDIR  ${LIBDIR}'
@echo ' - SHAREDIR  ${SHAREDIR}'
@echo ' - INCLUDEDIR  ${INCLUDEDIR}'
@echo ' - MANDIR  ${MANDIR}'
@echo ''
@echo 'Project targets: '
@echo ' - libipc  library'
@echo ' - src/ipc.h  header'
@echo ' - man/libipc.7  man'
@echo ''
@echo 'Makefile options:'
@echo ' - gnu: false'
@echo ' - colors: true'
@echo ''
@echo 'Rebuild the Makefile with:'
@echo ' zsh ./build.zsh -c'
.PHONY: all subdirs clean distclean dist install uninstall help

157
README.md
View File

@ -1,158 +1,7 @@
# Problem
End-user applications are huge, with tons of libraries used and are a pain in the ass to maintain.
Libraries are huge, with a lot of things happening, with changes that break everything on a regular basis, with almost each time very few people working on it.
Libraries are written for every project, most of the code can be re-used because it is not fundamentally bounded to a single project.
# libipc
Start a new project is not an easy task neither.
libipc - Simple, easy-to-use IPC library
- What language to use?
- I am doing something already coded somewhere?
- Is this library working on every platform?
- Are the libraries I need (and the good version) available for my platform, do I need to install SomeBullshitOS or ProtoContenerizator3000 to code?
See the introductory [man page](man/libipc.7.md).
# How to change that?
**Network protocols**
Network protocols are awesome: very few changes, well documented, programming language agnostics.
Don't (just) write libraries, write applications !
Your need a functionality in your application, why do you have to code it ?
Just ask a service !
**Example**
You want to download a file, you will always have the same input: a string corresponding to the file to get, such as _ftp://example.com/file.txt_.
You don't have to worry about the protocol to use in your own application, the burden is on the dedicated *downloading* service.
# Benefits
**Awesome abstractions**.
You will be able to do things without any code.
* applications don't have to know if the services they use is on the network or on your own computer
* applications don't need to change anything to handle new protocols, no recompilation
* applications can be statically compiled, the memory footprint should be extremely low (yes, even for a browser)
Let's write *abstractions* together, and less application-specific code !
**Simple applications**.
You only need to code the specific parts of your own application.
The only thing your application should have to take care is its functionality, and to communicate to services providing abstractions.
**Consistency**.
Everything will be developed in the same repository: same [coding standards][codingstyle], changes will be tested on every provided applications…
**Code review**.
We should always try to provide new abstractions, reducing the code needed in both services and end-user applications.
To that end, code review is a must.
**No need to rewrite everything**.
You have great libraries?
Don't redevelop them!
We can use already existing libraries to provide new functionalities to our programs: we just have to write a service and to define new messages to request it, period.
**Language independent**.
You have an awesome library to do X, but it's written in an obscure language.
Who cares?
Write a simple service that can be requested following our protocol, everybody will be able to use your library without painful-to-maintain bindings!
We may even assist you doing that by providing templates for your language, or check the other services!
**The end of "oh, I would like to dev something but this requires too much painful-to-install dependencies"**.
You only need the communication library and the service running (not even on your own computer) without any other dependencies.
That's it, you're good to go!
# Not adapted to everything
If you need incredible performances for your application, maybe this won't fit.
There is no silver bullet or one-fit-all solution.
Still, we think performances won't be much of a problem for most of the everyday life applications and if there are performances hits we still have plenty of room for optimisations!
# Application and services
- Services: daemons providing a feature (windowing, audio, network, input, pubsub, …)
- Applications: end-user applications (browser, mail user agent, instant messaging app, …)
#### Examples
A browser that can download everything, via every existing protocol.
No any specific code in the browser itself and no configuration.
You want to play a game on your raspberry pi, but it is not powerful enough, run your application on your laptop but take the inputs from the rpi (or anywhere on the network) !
No specific code needed.
# TODO
Figures, a lot of them, to explain everything.
# Connection init (draft)
## How things happen
1. Service creates a unix socket /tmp/service-index-version.sock
1. Application connects to /tmp/service-index-version.sock
__legend__:
- service: service name
- index: process index (to launch a service several times)
- version: service version
# Networking point of view (what should go in the sockets)
#### Connection
1. Application connects to /tmp/service-index-version.sock
1. Service acknowledges (empty message)
#### Disconnection
1. Application sends a message "CLOSE" to the server
#### Data
1. Application or server sends a message "DATA", no acknowledgement
# Message formats
In order to communicate between the application and the service, we use the Type-Length-Value format.
This will be used with some conventions.
The type will be a simple byte :
* <0 - 15> : control, meta data
* <16 - 127> : later use
* <128 - 255> : application specific (windowing system, audio system, …)
index | abbreviation | semantic
0 | close | to close the communication between the application and the service
1 | connection | to connect to the service
2 | error | to send an error message
3 | ack | to send an acknowledgment
4 | message | to send data
# Service Status
Go to the relevant directory for details.
- pongd: stable
- tcpd: experimental
- pubsub: experimental
# Inspiration
This project is inspired by a number of great projects:
- [OpenBSD][openbsd] and UNIX in general for most of the concepts
- Plan9 for the great abstractions and simplicity
- [suckless][suckless] for the [coding style][codingstyle] and [cat-v][catv] for the philosophy
[codingstyle]: http://suckless.org/coding_style
[suckless]: http://suckless.org
[catv]: http://cat-v.org
[openbsd]: https://openbsd.org

View File

@ -1,25 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c ../../core/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin

View File

@ -1,34 +0,0 @@
#include "../../core/client.h"
#include <string.h> /* memset */
#include <stdio.h>
int main()
{
int ret;
struct ipc_clients clients;
memset(&clients, 0, sizeof(struct ipc_clients));
struct ipc_client client_tab[5];
memset(&client_tab, 0, sizeof(struct ipc_client) * 5);
int i;
for (i = 0; i < 5; i++) {
client_tab[i].proc_fd = i;
ret = ipc_client_add(&clients, &client_tab[i]);
if (ret == -1) {
printf("erreur realloc\n");
}
}
ipc_clients_print(&clients);
ret = ipc_client_del(&clients, &client_tab[2]);
if(ret < 0) {
printf("erreur %d\n", ret );
}
ipc_clients_print(&clients);
ipc_clients_free (&clients);
return 0;
}

View File

@ -1,61 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include "../../core/usocket.h"
#define handle_err(fun,msg)\
fprintf (stderr, "%s: file %s line %d %s\n", fun, __FILE__, __LINE__, msg);
#define UPATH "/tmp/ipc/usock-path.sock"
#define MSG "coucou"
int main (int argc, char * argv[])
{
argc = argc;
argv = argv;
int fd = 0;
size_t msize = BUFSIZ;
char *buf = NULL;
struct timeval t1;
struct timeval t2;
if ( (buf = malloc (BUFSIZ)) == NULL) {
handle_err ("main", "malloc");
return EXIT_FAILURE;
}
memset (buf, 0, BUFSIZ);
if (usock_connect (&fd, UPATH) < 0) {
handle_err("main", "usock_listen < 0");
return EXIT_FAILURE;
}
gettimeofday (&t1, NULL);
if (usock_send (fd, MSG, strlen(MSG)) < 0) {
handle_err("main", "usock_send < 0");
return EXIT_FAILURE;
}
if (usock_recv (fd, &buf, &msize) < 0) {
handle_err("main", "usock_recv < 0");
return EXIT_FAILURE;
}
gettimeofday (&t2, NULL);
printf ("it took %ld µs to send then recv a message\n"
, t2.tv_usec - t1.tv_usec);
if (usock_close (fd) < 0) {
handle_err("main", "usock_close < 0");
return EXIT_FAILURE;
}
if (buf != NULL)
free (buf);
return EXIT_SUCCESS;
}

View File

@ -1,69 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../../core/usocket.h"
#define handle_err(fun,msg)\
fprintf (stderr, "%s: file %s line %d %s\n", fun, __FILE__, __LINE__, msg);
#define UPATH "/tmp/ipc/usock-path.sock"
int main (int argc, char * argv[])
{
argc = argc;
argv = argv;
int fd = 0;
int pfd = 0;
size_t msize = BUFSIZ;
char *buf = NULL;
if ( (buf = malloc (BUFSIZ)) == NULL) {
handle_err ("main", "malloc");
return EXIT_FAILURE;
}
memset (buf, 0, BUFSIZ);
// socket + bind + listen
if (usock_init (&fd, UPATH) < 0) {
handle_err("main", "usock_init < 0");
return EXIT_FAILURE;
}
if (usock_accept (fd, &pfd) < 0) {
handle_err("main", "usock_accept < 0");
return EXIT_FAILURE;
}
if (usock_recv (pfd, &buf, &msize) < 0) {
handle_err("main", "usock_recv < 0");
return EXIT_FAILURE;
}
if (usock_send (pfd, buf, msize) < 0) {
handle_err("main", "usock_send < 0");
return EXIT_FAILURE;
}
if (usock_close (fd) < 0) {
handle_err("main", "usock_close fd < 0");
return EXIT_FAILURE;
}
if (usock_close (pfd) < 0) {
handle_err("main", "usock_close pfd < 0");
return EXIT_FAILURE;
}
if (usock_remove (UPATH) < 0) {
handle_err("main", "usock_remove < 0");
return EXIT_FAILURE;
}
if (buf != NULL)
free (buf);
return EXIT_SUCCESS;
}

View File

@ -1,54 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../core/message.h"
#include "../../core/error.h"
#include "../../core/communication.h"
#define MSG "coucou"
#define SERVICE_NAME "test"
int main (int argc, char *argv[], char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (application_connection (argc, argv, env, &srv, SERVICE_NAME, NULL, 0) < 0) {
handle_err("main", "server_init < 0");
return EXIT_FAILURE;
}
printf ("msg to send: %s\n", MSG);
ipc_message_format_data (&m, MSG, strlen(MSG) +1);
printf ("msg to send in the client: ");
print_msg (&m);
if (application_write (&srv, &m) < 0) {
handle_err("main", "application_write < 0");
return EXIT_FAILURE;
}
ipc_message_free (&m);
if (application_read (&srv, &m) < 0) {
handle_err("main", "application_read < 0");
return EXIT_FAILURE;
}
printf ("msg recv: %s\n", m.payload);
ipc_message_free (&m);
if (application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -1,74 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../core/error.h"
#include "../../core/communication.h"
#define MSG "coucou"
#define SERVICE_NAME "test"
int main (int argc, char *argv[], char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset(&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
struct ipc_client p;
memset (&p, 0, sizeof (struct ipc_client));
// init service
if (server_init (argc, argv, env, &srv, SERVICE_NAME) < 0) {
handle_err("main", "server_init < 0");
return EXIT_FAILURE;
}
if (server_accept (&srv, &p) < 0) {
handle_err("main", "server_accept < 0");
return EXIT_FAILURE;
}
if (server_read (&p, &m) < 0) {
handle_err("main", "server_read < 0");
return EXIT_FAILURE;
}
printf ("msg recv: %s\n", m.payload);
if (server_write (&p, &m) < 0) {
handle_err("main", "server_write < 0");
return EXIT_FAILURE;
}
ipc_message_free (&m);
// client quits
if (server_read (&p, &m) < 0) {
handle_err("main", "server_read < 0");
return EXIT_FAILURE;
}
if (m.type == MSG_TYPE_CLOSE) {
printf ("the client quits\n");
}
else {
fprintf (stderr, "err: should have received the client dis msg\n");
}
ipc_message_free (&m);
if (server_close_client (&p) < 0) {
handle_err("main", "server_close_client < 0");
return EXIT_FAILURE;
}
if (server_close (&srv) < 0) {
handle_err("main", "server_close < 0");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -1,55 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../core/usocket.h"
#define handle_err(fun,msg)\
fprintf (stderr, "%s: file %s line %d %s\n", fun, __FILE__, __LINE__, msg);
#define UPATH "/tmp/ipc/usock-path.sock"
#define MSG "coucou"
int main (int argc, char * argv[])
{
argc = argc;
argv = argv;
int fd = 0;
size_t msize = BUFSIZ;
char *buf = NULL;
if ( (buf = malloc (BUFSIZ)) == NULL) {
handle_err ("main", "malloc");
return EXIT_FAILURE;
}
memset (buf, 0, BUFSIZ);
if (usock_connect (&fd, UPATH) < 0) {
handle_err("main", "usock_listen < 0");
return EXIT_FAILURE;
}
if (usock_send (fd, MSG, strlen(MSG)) < 0) {
handle_err("main", "usock_send < 0");
return EXIT_FAILURE;
}
if (usock_recv (fd, &buf, &msize) < 0) {
handle_err("main", "usock_recv < 0");
return EXIT_FAILURE;
}
printf ("msg recv: %s\n", buf);
if (usock_close (fd) < 0) {
handle_err("main", "usock_close < 0");
return EXIT_FAILURE;
}
if (buf != NULL)
free (buf);
return EXIT_SUCCESS;
}

View File

@ -1,75 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../../core/usocket.h"
#define handle_err(fun,msg)\
fprintf (stderr, "%s: file %s line %d %s\n", fun, __FILE__, __LINE__, msg);
#define UPATH "/tmp/ipc/usock-path.sock"
int main (int argc, char * argv[])
{
argc = argc;
argv = argv;
int fd = 0;
int pfd = 0;
size_t msize = BUFSIZ;
char *buf = NULL;
if ( (buf = malloc (BUFSIZ)) == NULL) {
handle_err ("main", "malloc");
return EXIT_FAILURE;
}
memset (buf, 0, BUFSIZ);
// socket + bind + listen
if (usock_init (&fd, UPATH) < 0) {
handle_err("main", "usock_init < 0");
return EXIT_FAILURE;
}
if (usock_accept (fd, &pfd) < 0) {
handle_err("main", "usock_accept < 0");
return EXIT_FAILURE;
}
printf ("new connection\n");
if (usock_recv (pfd, &buf, &msize) < 0) {
handle_err("main", "usock_recv < 0");
return EXIT_FAILURE;
}
printf ("msg recv: %s\n", buf);
if (usock_send (pfd, buf, msize) < 0) {
handle_err("main", "usock_send < 0");
return EXIT_FAILURE;
}
if (usock_close (fd) < 0) {
handle_err("main", "usock_close fd < 0");
return EXIT_FAILURE;
}
if (usock_close (pfd) < 0) {
handle_err("main", "usock_close pfd < 0");
return EXIT_FAILURE;
}
if (usock_remove (UPATH) < 0) {
handle_err("main", "usock_remove < 0");
return EXIT_FAILURE;
}
if (buf != NULL)
free (buf);
return EXIT_SUCCESS;
}

View File

@ -1,26 +0,0 @@
.TH "COMMUNICATION-CLIENT" "1" "19/12/2016" "\ \&" "\ \&"
.nh
.ad l
.SH "NAME"
communication-client \- communication lib test (communication.c)
.SH "SYNOPSIS"
.sp
\fBcommunication-client\fR
.SH "DESCRIPTION"
.sp
\fBcommunication-client\fR is about regression tests of the communication library.
It acts as a simple client connecting to a "\fBtest\fR" service, it sends a message and wait for a response then quits.
.sp
This program has currently no options.
.SH "SEE ALSO"
.sp
\fBcommunication-server\fR(1)
.SH "BUGS"
.sp
Thanks to report bugs to karchnu+bugs@karchnu.fr
.SH "AUTHORS"
.sp
Philippe PITTOLI
.SH "WWW"
.sp
\fBhttps://git.karchnu.fr/Karchnu/perfectos-junk

View File

@ -1,26 +0,0 @@
.TH "COMMUNICATION-SERVER" "1" "19/12/2016" "\ \&" "\ \&"
.nh
.ad l
.SH "NAME"
communication-server \- communication lib test (communication.c)
.SH "SYNOPSIS"
.sp
\fBcommunication-server\fR
.SH "DESCRIPTION"
.sp
\fBcommunication-server\fR is about regression tests of the communication library.
It acts as a simple server for the "\fBtest\fR" service, it waits for a client, then waits for a message and sends it back before quitting.
.sp
This program has currently no options.
.SH "SEE ALSO"
.sp
\fBcommunication-client\fR(1)
.SH "BUGS"
.sp
Thanks to report bugs to karchnu+bugs@karchnu.fr
.SH "AUTHORS"
.sp
Philippe PITTOLI
.SH "WWW"
.sp
\fBhttps://git.karchnu.fr/Karchnu/perfectos-junk

View File

@ -1,26 +0,0 @@
.TH "USOCK-CLIENT" "1" "19/12/2016" "\ \&" "\ \&"
.nh
.ad l
.SH "NAME"
usock-client \- communication lib test (usock.c)
.SH "SYNOPSIS"
.sp
\fBusock-client\fR
.SH "DESCRIPTION"
.sp
\fBusock-client\fR is about regression tests of the communication library.
It acts as a simple client connecting to a unix socket, it sends a message and wait for a response then quits.
.sp
This program has currently no options.
.SH "SEE ALSO"
.sp
\fBusock-server\fR(1)
.SH "BUGS"
.sp
Thanks to report bugs to karchnu+bugs@karchnu.fr
.SH "AUTHORS"
.sp
Philippe PITTOLI
.SH "WWW"
.sp
\fBhttps://git.karchnu.fr/Karchnu/perfectos-junk

View File

@ -1,26 +0,0 @@
.TH "USOCK-SERVER" "1" "19/12/2016" "\ \&" "\ \&"
.nh
.ad l
.SH "NAME"
usock-server \- communication lib test (usock.c)
.SH "SYNOPSIS"
.sp
\fBusock-server\fR
.SH "DESCRIPTION"
.sp
\fBusock-server\fR is about regression tests of the communication library.
It acts as a simple unix socket server waiting a connection from a client, it then waits for a message and sends it back before quitting.
.sp
This program has currently no options.
.SH "SEE ALSO"
.sp
\fBusock-client\fR(1)
.SH "BUGS"
.sp
Thanks to report bugs to karchnu+bugs@karchnu.fr
.SH "AUTHORS"
.sp
Philippe PITTOLI
.SH "WWW"
.sp
\fBhttps://git.karchnu.fr/Karchnu/perfectos-junk

View File

@ -1,291 +0,0 @@
PACKAGE = 'ipc'
VERSION = '0.0.1'
PREFIX := /usr/local
BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib
SHAREDIR := $(PREFIX)/share
INCLUDEDIR := $(PREFIX)/include
MANDIR := $(SHAREDIR)/man
CC := cc
AR := ar
RANLIB := ranlib
CFLAGS :=
LDFLAGS :=
Q := @
all: libipc
@:
libipc: libipc.so libipc.a
@:
libipc.install: libipc.so.install libipc.a.install
libipc.clean: libipc.so.clean libipc.a.clean
libipc.uninstall: libipc.so.uninstall libipc.a.uninstall
libipc.so: client.o communication.o logger.o message.o usocket.o utils.o
@echo ' LD > libipc.so'
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) client.o communication.o logger.o message.o usocket.o utils.o
libipc.so.install: libipc.so
@echo ' IN > $(LIBDIR)/libipc.so.0.0.1'
$(Q)mkdir -p '$(DESTDIR)$(LIBDIR)'
$(Q)install -m0755 libipc.so $(DESTDIR)$(LIBDIR)/libipc.so.0.0.1
@echo ' LN > $(LIBDIR)/libipc.so.0.0'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.0.1' '$(DESTDIR)/$(LIBDIR)/libipc.so.0.0'
@echo ' LN > $(LIBDIR)/libipc.so.0'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.0.1' '$(DESTDIR)/$(LIBDIR)/libipc.so.0'
@echo ' LN > $(LIBDIR)/libipc.so'
$(Q)ln -sf '$(LIBDIR)/libipc.so.0.0.1' '$(DESTDIR)/$(LIBDIR)/libipc.so'
libipc.so.clean:
@echo ' RM > libipc.so'
$(Q)rm -f libipc.so
libipc.so.uninstall:
@echo ' RM > $(LIBDIR)/libipc.so.0.0.1'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.0.1'
@echo ' RM > $(LIBDIR)/libipc.so.0.0'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0.0'
@echo ' RM > $(LIBDIR)/libipc.so.0'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so.0'
@echo ' RM > $(LIBDIR)/libipc.so'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so'
libipc.a: client.o communication.o logger.o message.o usocket.o utils.o
@echo ' LD > libipc.a'
$(Q)$(AR) rc 'libipc.a' client.o communication.o logger.o message.o usocket.o utils.o
libipc.a.install: libipc.a
@echo ' IN > $(LIBDIR)/libipc.a'
$(Q)mkdir -p '$(DESTDIR)$(LIBDIR)'
$(Q)install -m0755 libipc.a $(DESTDIR)$(LIBDIR)/libipc.a
libipc.a.clean:
@echo ' RM > libipc.a'
$(Q)rm -f libipc.a
libipc.a.uninstall:
@echo ' RM > $(LIBDIR)/libipc.a'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.a'
client.o: client.c ./client.h
@echo ' CC > client.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c client.c -fPIC -o client.o
client.o.install:
client.o.clean:
@echo ' RM > client.o'
$(Q)rm -f client.o
client.o.uninstall:
communication.o: communication.c ./communication.h ./utils.h ./error.h ./event.h
@echo ' CC > communication.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c communication.c -fPIC -o communication.o
communication.o.install:
communication.o.clean:
@echo ' RM > communication.o'
$(Q)rm -f communication.o
communication.o.uninstall:
logger.o: logger.c ./logger.h
@echo ' CC > logger.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c logger.c -fPIC -o logger.o
logger.o.install:
logger.o.clean:
@echo ' RM > logger.o'
$(Q)rm -f logger.o
logger.o.uninstall:
message.o: message.c ./message.h ./error.h ./usocket.h
@echo ' CC > message.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c message.c -fPIC -o message.o
message.o.install:
message.o.clean:
@echo ' RM > message.o'
$(Q)rm -f message.o
message.o.uninstall:
usocket.o: usocket.c ./usocket.h ./utils.h ./error.h
@echo ' CC > usocket.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c usocket.c -fPIC -o usocket.o
usocket.o.install:
usocket.o.clean:
@echo ' RM > usocket.o'
$(Q)rm -f usocket.o
usocket.o.uninstall:
utils.o: utils.c ./utils.h
@echo ' CC > utils.o'
$(Q)$(CC) $(CFLAGS) -fPIC -c utils.c -fPIC -o utils.o
utils.o.install:
utils.o.clean:
@echo ' RM > utils.o'
$(Q)rm -f utils.o
utils.o.uninstall:
$(DESTDIR)$(PREFIX):
@echo ' DIR > $(PREFIX)'
$(Q)mkdir -p $(DESTDIR)$(PREFIX)
$(DESTDIR)$(BINDIR):
@echo ' DIR > $(BINDIR)'
$(Q)mkdir -p $(DESTDIR)$(BINDIR)
$(DESTDIR)$(LIBDIR):
@echo ' DIR > $(LIBDIR)'
$(Q)mkdir -p $(DESTDIR)$(LIBDIR)
$(DESTDIR)$(SHAREDIR):
@echo ' DIR > $(SHAREDIR)'
$(Q)mkdir -p $(DESTDIR)$(SHAREDIR)
$(DESTDIR)$(INCLUDEDIR):
@echo ' DIR > $(INCLUDEDIR)'
$(Q)mkdir -p $(DESTDIR)$(INCLUDEDIR)
$(DESTDIR)$(MANDIR):
@echo ' DIR > $(MANDIR)'
$(Q)mkdir -p $(DESTDIR)$(MANDIR)
install: subdirs.install libipc.install libipc.so.install libipc.a.install client.o.install communication.o.install logger.o.install message.o.install usocket.o.install utils.o.install client.o.install communication.o.install logger.o.install message.o.install usocket.o.install utils.o.install
@:
subdirs.install:
uninstall: subdirs.uninstall libipc.uninstall libipc.so.uninstall libipc.a.uninstall client.o.uninstall communication.o.uninstall logger.o.uninstall message.o.uninstall usocket.o.uninstall utils.o.uninstall client.o.uninstall communication.o.uninstall logger.o.uninstall message.o.uninstall usocket.o.uninstall utils.o.uninstall
@:
subdirs.uninstall:
test: all subdirs subdirs.test
@:
subdirs.test:
clean: libipc.clean libipc.so.clean libipc.a.clean client.o.clean communication.o.clean logger.o.clean message.o.clean usocket.o.clean utils.o.clean client.o.clean communication.o.clean logger.o.clean message.o.clean usocket.o.clean utils.o.clean
distclean: clean
dist: dist-gz dist-xz dist-bz2
$(Q)rm -- $(PACKAGE)-$(VERSION)
distdir:
$(Q)rm -rf -- $(PACKAGE)-$(VERSION)
$(Q)ln -s -- . $(PACKAGE)-$(VERSION)
dist-gz: $(PACKAGE)-$(VERSION).tar.gz
$(PACKAGE)-$(VERSION).tar.gz: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.gz'
$(Q)tar czf $(PACKAGE)-$(VERSION).tar.gz \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/error.h \
$(PACKAGE)-$(VERSION)/ipc.h \
$(PACKAGE)-$(VERSION)/event.h \
$(PACKAGE)-$(VERSION)/client.c \
$(PACKAGE)-$(VERSION)/communication.c \
$(PACKAGE)-$(VERSION)/logger.c \
$(PACKAGE)-$(VERSION)/message.c \
$(PACKAGE)-$(VERSION)/usocket.c \
$(PACKAGE)-$(VERSION)/utils.c \
$(PACKAGE)-$(VERSION)/client.h \
$(PACKAGE)-$(VERSION)/communication.h \
$(PACKAGE)-$(VERSION)/logger.h \
$(PACKAGE)-$(VERSION)/message.h \
$(PACKAGE)-$(VERSION)/usocket.h \
$(PACKAGE)-$(VERSION)/utils.h
dist-xz: $(PACKAGE)-$(VERSION).tar.xz
$(PACKAGE)-$(VERSION).tar.xz: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.xz'
$(Q)tar cJf $(PACKAGE)-$(VERSION).tar.xz \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/error.h \
$(PACKAGE)-$(VERSION)/ipc.h \
$(PACKAGE)-$(VERSION)/event.h \
$(PACKAGE)-$(VERSION)/client.c \
$(PACKAGE)-$(VERSION)/communication.c \
$(PACKAGE)-$(VERSION)/logger.c \
$(PACKAGE)-$(VERSION)/message.c \
$(PACKAGE)-$(VERSION)/usocket.c \
$(PACKAGE)-$(VERSION)/utils.c \
$(PACKAGE)-$(VERSION)/client.h \
$(PACKAGE)-$(VERSION)/communication.h \
$(PACKAGE)-$(VERSION)/logger.h \
$(PACKAGE)-$(VERSION)/message.h \
$(PACKAGE)-$(VERSION)/usocket.h \
$(PACKAGE)-$(VERSION)/utils.h
dist-bz2: $(PACKAGE)-$(VERSION).tar.bz2
$(PACKAGE)-$(VERSION).tar.bz2: distdir
@echo ' TAR > $(PACKAGE)-$(VERSION).tar.bz2'
$(Q)tar cjf $(PACKAGE)-$(VERSION).tar.bz2 \
$(PACKAGE)-$(VERSION)/Makefile \
$(PACKAGE)-$(VERSION)/project.zsh \
$(PACKAGE)-$(VERSION)/error.h \
$(PACKAGE)-$(VERSION)/ipc.h \
$(PACKAGE)-$(VERSION)/event.h \
$(PACKAGE)-$(VERSION)/client.c \
$(PACKAGE)-$(VERSION)/communication.c \
$(PACKAGE)-$(VERSION)/logger.c \
$(PACKAGE)-$(VERSION)/message.c \
$(PACKAGE)-$(VERSION)/usocket.c \
$(PACKAGE)-$(VERSION)/utils.c \
$(PACKAGE)-$(VERSION)/client.h \
$(PACKAGE)-$(VERSION)/communication.h \
$(PACKAGE)-$(VERSION)/logger.h \
$(PACKAGE)-$(VERSION)/message.h \
$(PACKAGE)-$(VERSION)/usocket.h \
$(PACKAGE)-$(VERSION)/utils.h
help:
@echo ' :: ipc-0.0.1'
@echo ''
@echo 'Generic targets:'
@echo ' - help  Prints this help message.'
@echo ' - all  Builds all targets.'
@echo ' - dist  Creates tarballs of the files of the project.'
@echo ' - install  Installs the project.'
@echo ' - clean  Removes compiled files.'
@echo ' - uninstall  Deinstalls the project.'
@echo ''
@echo 'CLI-modifiable variables:'
@echo ' - CC  ${CC}'
@echo ' - CFLAGS  ${CFLAGS}'
@echo ' - LDFLAGS  ${LDFLAGS}'
@echo ' - DESTDIR  ${DESTDIR}'
@echo ' - PREFIX  ${PREFIX}'
@echo ' - BINDIR  ${BINDIR}'
@echo ' - LIBDIR  ${LIBDIR}'
@echo ' - SHAREDIR  ${SHAREDIR}'
@echo ' - INCLUDEDIR  ${INCLUDEDIR}'
@echo ' - MANDIR  ${MANDIR}'
@echo ''
@echo 'Project targets: '
@echo ' - libipc  library'
@echo ''
@echo 'Makefile options:'
@echo ' - gnu: false'
@echo ' - colors: true'
@echo ''
@echo 'Rebuild the Makefile with:'
@echo ' zsh ./build.zsh -c'
.PHONY: all subdirs clean distclean dist install uninstall help

View File

@ -1,249 +0,0 @@
@[Link("ipc")]
lib LibIPC
struct Service
version : LibC::UInt
index : LibC::UInt
spath : LibC::Char[4096] # [PATH_MAX]
fd : LibC::Int
end
struct Client
version : LibC::UInt
index : LibC::UInt
fd : LibC::Int
end
enum MessageType
ServerClose
Error
Data
end
struct Message
type : UInt8
length : LibC::UInt
payload : LibC::Char*
end
struct Clients
clients : Client**
size : LibC::Int
end
enum EventType
NotSet
Error
Stdin
Connection
Disconnection
Message
end
struct Event
type : EventType
origin : Client*
m : Message*
end
# FIXME: IPC.initialize:
# - throw exceptions on error.
# - Make most arguments optional.
fun ipc_server_init(env : LibC::Char**, service : Service*, sname : LibC::Char*) : LibC::Int
# FIXME: IPC.(destroy?)
fun ipc_server_close(Service*) : LibC::Int
fun ipc_server_close_client(Client*) : LibC::Int
fun ipc_server_accept(Service*, Client*) : LibC::Int
fun ipc_server_read(Client*, Message*) : LibC::Int
fun ipc_server_write(Client*, Message*) : LibC::Int
fun ipc_server_select(Clients*, Service*, Clients*, LibC::Int*) : LibC::Int
fun ipc_service_poll_event(Clients*, Service*, Event*) : LibC::Int
fun ipc_application_connection(LibC::Char**, Service*, LibC::Char*) : LibC::Int
fun ipc_application_close(Service*) : LibC::Int
fun ipc_application_read(Service*, Message*) : LibC::Int
fun ipc_application_write(Service*, Message*) : LibC::Int
fun ipc_client_add(Clients*, Client*) : LibC::Int
fun ipc_client_del(Clients*, Client*) : LibC::Int
fun ipc_server_client_copy(Client*) : Client*
fun ipc_server_client_eq(Client*, Client*) : LibC::Int
fun ipc_server_client_gen(Client*, LibC::UInt, LibC::UInt)
fun ipc_clients_free(Clients*)
end
class IPC::Exception < ::Exception
end
class IPC::Service
@closed = false
@clients = LibIPC::Clients.new
# FIXME: getter only as long as proper bindings are unfinished
getter service = LibIPC::Service.new
def initialize(name : String)
if LibIPC.ipc_server_init(LibC.environ, pointerof(@service), name) < 0
raise Exception.new "ipc_server_init < 0" # FIXME: Add proper descriptions here.
end
# Very important as there are filesystem side-effects.
at_exit { close }
end
def initialize(name : String, &block : Proc(IPC::Event::Connection | IPC::Event::Disconnection | IPC::Event::Message, Nil))
initialize name
loop &block
close
end
def close
return if @closed
# FIXME: Probably check its not been closed already.
if LibIPC.ipc_server_close(pointerof(@service)) < 0
raise Exception.new "ipc_server_close < 0"
end
@closed = true
end
def finalize
close
end
def accept
::IPC::Server::Client.new pointerof(@service)
end
def loop(&block)
::loop do
event = LibIPC::Event.new
r = LibIPC.ipc_service_poll_event pointerof(@clients), pointerof(@service), pointerof(event)
if r < 0
raise Exception.new "ipc_service_poll_event < 0"
end
client = IPC::RemoteClient.new event.origin.unsafe_as(Pointer(LibIPC::Client)).value
pp! event
message = event.m.unsafe_as(Pointer(LibIPC::Message))
unless message.null?
pp! message.value
end
case event.type
when LibIPC::EventType::Connection
yield IPC::Event::Connection.new client
when LibIPC::EventType::Message
message = event.m.unsafe_as(Pointer(LibIPC::Message)).value
yield IPC::Event::Message.new IPC::Message.new(message.type, message.length, message.payload), client
when LibIPC::EventType::Disconnection
yield IPC::Event::Disconnection.new client
end
end
end
end
class IPC::Message
enum Type
CLOSE
CONNECTION
SYN
ACK
DATA
end
getter type : UInt8
getter payload : String
def initialize(type, length, payload)
@type = type.to_u8
@payload = String.new payload, length
end
end
class IPC::RemoteClient
getter client : LibIPC::Client
def initialize(@client)
end
def send(type : UInt8, payload : String)
message = LibIPC::Message.new type: type, length: payload.bytesize, payload: payload.to_unsafe
if LibIPC.ipc_server_write(pointerof(@client), pointerof(message)) < 0
raise Exception.new "ipc_server_write < 0"
end
end
end
class IPC::Event
class Connection
getter client : IPC::RemoteClient
def initialize(@client)
end
end
class Disconnection
getter client : IPC::RemoteClient
def initialize(@client)
end
end
class Message
getter message : ::IPC::Message
getter client : IPC::RemoteClient
def initialize(@message, @client)
end
end
end
class IPC::Client
@service = LibIPC::Service.new
def initialize(@service_name : String)
if LibIPC.ipc_application_connection(LibC.environ, pointerof(@service), @service_name) < 0
raise Exception.new "ipc_application_connection < 0"
end
end
def initialize(name, &block)
initialize(name)
yield self
close
end
def send(type, payload : String)
message = LibIPC::Message.new type: type, length: payload.bytesize, payload: payload.to_unsafe
if LibIPC.ipc_application_write(pointerof(@service), pointerof(message)) < 0
raise Exception.new "ipc_application_write < 0"
end
end
def read
message = LibIPC::Message.new
if LibIPC.ipc_application_read(pointerof(@service), pointerof(message)) < 0
raise Exception.new "ipc_application_read < 0"
end
IPC::Message.new message.type, message.length, message.payload
end
def close
if LibIPC.ipc_application_close(pointerof(@service)) < 0
raise Exception.new "ipc_application_close < 0"
end
end
end

View File

@ -1,10 +0,0 @@
package=ipc
version=0.0.1
targets=(libipc)
type[libipc]=library
sources[libipc]="$(ls *.c)"
dist=(Makefile project.zsh error.h ipc.h event.h)

2
diags/.gitignore vendored
View File

@ -1,2 +0,0 @@
*.png
*.pdf

View File

@ -1,8 +0,0 @@
# writing convention
Each diagram filename should be formatted as:
seq-service.diag: message sequence diagram
pkt-service-info.pktdiag: message format
See the currently available files as examples.

View File

@ -1,46 +0,0 @@
#!/bin/bash
if [ "$FONT" = "" ]
then
FONT=/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf
fi
echo "font : $FONT"
# $1 = program, $2 = filename extension
function graphit()
{
PROG=$1
FNEXT=$2
ls *.$FNEXT 2>/dev/null 1>&2
if [ $? -eq 0 ]; then
for i in *\.$FNEXT
do
PDF=$(echo ${i} | sed "s/$FNEXT$/pdf/")
if [ ! -f ${PDF} ] || [ $(stat -c "%X" ${PDF}) -lt $(stat -c "%X" ${i}) ]
then
PROGOPT="-Tpdf"
case $PROG in
"seqdiag" | "packetdiag" | "nwdiag")
PROGOPT="$PROGOPT -a -f $FONT"
echo ${PROG} ${PROGOPT} ${i}
${PROG} ${PROGOPT} ${i}
;;
"dot")
echo "${PROG} ${PROGOPT} ${i} > ${PDF}"
${PROG} ${PROGOPT} ${i} > ${PDF}
;;
esac
echo touch ${PDF}
touch ${PDF}
fi
done
fi
}
graphit "seqdiag" "diag"
graphit "packetdiag" "pktdiag"
graphit "nwdiag" "nwdiag"
graphit "dot" "gviz-dot"

View File

@ -1,13 +0,0 @@
packetdiag {
colwidth = 64
node_height = 60
node_width = 15
default_fontsize = 16; // default value is 11
// basic header (type then length)
0-7: type\n1 byte [color = "#CCEECC"]
8-23: length\n2 bytes [color = "#CCEECC"]
// payload
24-63: END\n3 bytes [color = "#CCCCEE"]
}

View File

@ -1,13 +0,0 @@
packetdiag {
colwidth = 64
node_height = 60
node_width = 15
default_fontsize = 16; // default value is 11
// basic header (type then length)
0-7: type\n1 byte [color = "#CCEECC"]
8-23: length\n2 bytes [color = "#CCEECC"]
// payload
24-63: service name\nn bytes [color = "#CCCCEE"]
}

View File

@ -1,13 +0,0 @@
packetdiag {
colwidth = 64
node_height = 60
node_width = 15
default_fontsize = 16; // default value is 11
// basic header (type then length)
0-7: type\n1 byte [color = "#CCEECC"]
8-23: length\n2 bytes [color = "#CCEECC"]
// payload
24-63: environment variable (one per packet)\nex: REMOTED_URI=tcp://user:pass@host.example.com:9000\nn bytes [color = "#CCCCEE"]
}

View File

@ -1,38 +0,0 @@
diagram {
edge_length = 300;
default_fontsize = 16; // default value is 11
span_height = 8; // default value is 40
node_height = 60; // default value is 40
activation = none;
// Numbering edges automaticaly
autonumber = True;
// Change note color
default_note_color = lightblue;
client [label = "client\nlocal"];
remoted [label = "remoted\nlocal"];
transportd [label = "transportd\n(ex: tcpd)\nlocal"];
transportd2 [label = "transportd\n(ex: tcpd)\nremote"];
remoted2 [label = "remoted\nremote"];
service [label = "service\nremote"];
client -> remoted [label = "service-name (ex: pongd)"];
client -> remoted [label = "REMOTED_VAR=URI
ex: tcp://user:password@example.com:9000", fontsize=13];
client -> remoted [label = "END (mark the end of the options)"
, rightnote = "Remoted: authenticates, authorizes, determines the right transport daemon and
applies forwarding rules", fontsize=13];
remoted -> transportd [label = "connect URI + service name"];
transportd -> transportd2 [label = "connection init
service name + URI"];
transportd2 -> remoted2 [label = "connection request
service name + URI"];
remoted2 -> transportd2 [label = "authorization (yes|no)"];
transportd2 -> transportd [label = "connection established"];
transportd -> remoted [label = "socket"];
remoted -> client [label = "socket"];
client -> service [label = "connection"];
}

View File

@ -1,22 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -lcbor -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
clean:
-rm $(OBJECTS)
mrproper: clean
rm *.bin

View File

@ -1,13 +0,0 @@
#!/bin/bash
PARAMS="-ac 2 -ar 44000 -f s16le -acodec pcm_mulaw"
if [ $# != 1 ]
then
echo "usage: $0 music-file" 1>&2
exit 1
fi
FILE="$1"
ffmpeg -loglevel 0 -i ${FILE} ${PARAMS} -

View File

@ -1,13 +0,0 @@
#!/bin/bash
PARAMS="-ac 2 -ar 44000 -f s16le -acodec pcm_mulaw"
if [ $# != 1 ]
then
echo "usage: $0 music-file" 1>&2
exit 1
fi
FILE="$1"
ffmpeg ${PARAMS} -i - ${FILE}

View File

@ -1,19 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread -lcbor
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -lcbor -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
mrproper:
rm *.bin

View File

@ -1,36 +0,0 @@
#include "cbor.h"
#include <stdio.h>
/*
* Reads data from a file. Example usage:
* $ ./examples/readfile examples/data/nested_array.cbor
*/
int main(int argc, char * argv[])
{
(void) argc;
(void) argv;
if (argc != 2) {
fprintf (stderr, "usage: %s file\n", argv[0]);
exit (1);
}
FILE * f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
size_t length = (size_t)ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char * buffer = malloc(length);
fread(buffer, length, 1, f);
/* Assuming `buffer` contains `info.st_size` bytes of input data */
struct cbor_load_result result;
cbor_item_t * item = cbor_load(buffer, length, &result);
/* Pretty-print the result */
cbor_describe(item, stdout);
fflush(stdout);
/* Deallocate the result */
cbor_decref(&item);
fclose(f);
}

View File

@ -1,29 +0,0 @@
#include "cbor.h"
#include <stdio.h>
int main(int argc, char * argv[])
{
(void) argc;
(void) argv;
/* Preallocate the map structure */
cbor_item_t * root = cbor_new_definite_map(2);
/* Add the content */
cbor_map_add(root, (struct cbor_pair) {
.key = cbor_move(cbor_build_string("Is CBOR awesome?")),
.value = cbor_move(cbor_build_bool(true))
});
cbor_map_add(root, (struct cbor_pair) {
.key = cbor_move(cbor_build_uint8(42)),
.value = cbor_move(cbor_build_string("Is the answer"))
});
/* Output: `length` bytes of data in the `buffer` */
unsigned char * buffer;
size_t buffer_size, length = cbor_serialize_alloc(root, &buffer, &buffer_size);
fwrite(buffer, 1, length, stdout);
free(buffer);
fflush(stdout);
cbor_decref(&root);
}

View File

@ -1,50 +0,0 @@
#include "cbor.h"
#include <stdio.h>
#include <string.h>
/*
* * Illustrates how one might skim through a map (which is assumed to have
* * string keys and values only), looking for the value of a specific key
* *
* * Use the examples/data/map.cbor input to test this.
* */
const char * key = "a secret key";
bool key_found = false;
void find_string(void * _ctx, cbor_data buffer, size_t len)
{
(void) _ctx;
if (key_found) {
printf("Found the value: %*s\n", (int) len, buffer);
key_found = false;
} else if (len == strlen(key)) {
key_found = (memcmp(key, buffer, len) == 0);
}
}
int main(int argc, char * argv[])
{
(void) argc;
(void) argv;
FILE * f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
size_t length = (size_t)ftell(f);
fseek(f, 0, SEEK_SET);
unsigned char * buffer = malloc(length);
fread(buffer, length, 1, f);
struct cbor_callbacks callbacks = cbor_empty_callbacks;
struct cbor_decoder_result decode_result;
size_t bytes_read = 0;
callbacks.string = find_string;
while (bytes_read < length) {
decode_result = cbor_stream_decode(buffer + bytes_read,
length - bytes_read,
&callbacks, NULL);
bytes_read += decode_result.read;
}
fclose(f);
}

View File

@ -1,56 +0,0 @@
#include "../lib/communication.h"
#define SERVICE "windowing"
void
ohshit(int32_t rvalue, const char* str) {
fprintf(stderr, "%s\n", str);
exit(rvalue);
}
int32_t main(int32_t argc, char * argv[], char *env[])
{
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
ipc_server_init (argc, argv, env, &srv, SERVICE, NULL);
printf ("Listening on %s.\n", srv.spath);
// creates the service named pipe, that listens to client applications
if (server_create (&srv))
ohshit(1, "service_create error");
/*
* PROCESS
*/
struct ipc_client p;
memset (&p, 0, sizeof (struct ipc_client));
int32_t index = 0; // first time we communication with the service
int32_t version = 1;
printf ("app creation\n");
if (application_create (&p, index, version)) // called by the application
ohshit (1, "application_create");
/*
* some exchanges between App and S
* specific code, talks between applications
* then App wants to end the communication
*/
printf ("destroying app\n");
// the application will shut down, and remove the application named pipes
if (application_destroy (&p))
ohshit (1, "application_destroy");
/*
* /PROCESS
*/
// the application will shut down, and remove the service named pipe
if (server_close (&srv))
ohshit (1, "server_close error");
return EXIT_SUCCESS;
}

View File

@ -1,56 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "../lib/queue.h"
// create the head of the list
LIST_HEAD(mlist, node);
// elements structure of the list
struct node {
int32_t content;
LIST_ENTRY(node) entries;
};
int32_t main(int32_t argc, char * argv[])
{
(void) argc;
(void) argv;
// the list
struct mlist *list;
list = malloc (sizeof(struct mlist));
LIST_INIT(list);
// create the elements
struct node *n1 = malloc (sizeof(struct node));
n1->content = 10;
struct node *n2 = malloc (sizeof(struct node));
n2->content = 20;
// insert element into the list
LIST_INSERT_HEAD(list, n1, entries);
LIST_INSERT_HEAD(list, n2, entries);
// loop over the list
struct node *np = NULL;
LIST_FOREACH(np, list, entries) {
printf ("elem : %d\n", np->content);
}
// remove elements from the list
LIST_REMOVE(n1, entries);
LIST_REMOVE(n2, entries);
// to be sure that nothing still is into the list
np = NULL;
LIST_FOREACH(np, list, entries) {
printf ("\033[31mSHOULD NOT BE PRINTED : %d\033[00m\n", np->content);
}
// free the elements then the list itself
free (n1);
free (n2);
free (list);
return EXIT_SUCCESS;
}

View File

@ -1,55 +0,0 @@
#include "../lib/pubsubd.h"
#include <cbor.h>
#include <stdlib.h>
#include <string.h>
#define PKT_CLOSE 0
#define PKT_MSG 1
#define PKT_ERROR 2
void
ohshit(int32_t rvalue, const char* str) {
fprintf (stderr, "\033[31merr: %s\033[00m\n", str);
exit (rvalue);
}
void usage (char **argv)
{
printf ( "NOT DONE YET\n");
printf ( "usage: %s [type [param]]...\n", argv[0]);
printf ( "ex: echo data | %s char_t 1\n", argv[0]);
printf ( " This sends a CBOR msg [ 1, \"data\" ]\n");
}
int32_t
main(int32_t argc, char **argv)
{
if (argc == 2 && strcmp ("-h", argv[1]) == 0) {
usage (argv);
exit (1);
}
uint8_t buf[BUFSIZ];
memset (buf, 0, BUFSIZ);
ssize_t buflen = read (0, buf, BUFSIZ);
/* Preallocate the map structure */
cbor_item_t * root = cbor_new_definite_map(1);
/* Add the content */
cbor_map_add(root, (struct cbor_pair) {
.key = cbor_move(cbor_build_uint8(PKT_MSG)),
.value = cbor_move(cbor_build_bytestring(buf, buflen))
});
/* Output: `length` bytes of data in the `buffer` */
uint8_t * buffer;
size_t buffer_size, length = cbor_serialize_alloc (root, &buffer, &buffer_size);
fwrite(buffer, 1, length, stdout);
free(buffer);
fflush(stdout);
cbor_decref(&root);
return EXIT_SUCCESS;
}

View File

@ -1,33 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int32_t main(int32_t argc, char * argv[])
{
(void) argc;
(void) argv;
char *fifopathin = "/tmp/123000-1-in";
size_t msize = 100;
char buf[BUFSIZ];
FILE *in = fopen (fifopathin, "rb");
printf ("opened\n");
if ((msize = fread (buf, msize, 1, in))) {
printf ("error read %ld\n", msize);
return EXIT_FAILURE;
}
printf ("%s\n", buf);
sleep (10);
printf ("read end\n");
fclose (in);
return EXIT_SUCCESS;
}

View File

@ -1,32 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int32_t main(int32_t argc, char * argv[])
{
(void) argc;
(void) argv;
char *fifopathin = "/tmp/123000-1-in";
size_t msize;
FILE *out = fopen (fifopathin, "wb");
printf ("opened\n");
char *buf = "coucou";
printf ("write %s\n", buf);
if ((msize = fread (buf, 6, 1, out))) {
printf ("error read %ld\n", msize);
return EXIT_FAILURE;
}
sleep (10);
printf ("write end\n");
fclose (out);
return EXIT_SUCCESS;
}

View File

@ -1,270 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
#include <stdarg.h>
#define USOCK "./.socket"
#define handle_error(msg) \
do { log_error (msg); exit(EXIT_FAILURE); } while (0)
#define handle_err(fun,msg)\
do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0)
void log_format (const char* tag, const char* message, va_list args) {
time_t now;
time(&now);
char * date =ctime(&now);
date[strlen(date) - 1] = '\0';
printf("%s:%s: ", date, tag);
vprintf(message, args);
printf("\n");
}
void log_error (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("error", message, args);
va_end(args);
}
void log_info (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("info", message, args);
va_end(args);
}
void log_debug (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("debug", message, args);
va_end(args);
}
static
int32_t recvsockfd (int32_t socket) // receive fd from socket
{
struct ipc_messagehdr msg = {0};
/* On Mac OS X, the struct iovec is needed, even if it points to minimal data */
char m_buffer[1];
struct iovec io = { .iov_base = m_buffer, .iov_len = sizeof(m_buffer) };
msg.msg_iov = &io;
msg.msg_iovlen = 1;
char c_buffer[256];
msg.msg_control = c_buffer;
msg.msg_controllen = sizeof(c_buffer);
if (recvmsg(socket, &msg, 0) < 0)
handle_err ("recvsockfd", "Failed to receive message\n");
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
printf ("About to extract fd\n");
int32_t fd;
memmove(&fd, CMSG_DATA(cmsg), sizeof(fd));
printf ("Extracted fd %d\n", fd);
return fd;
}
int32_t usock_connect (int32_t *fd, const char *path)
{
assert (fd != NULL);
assert (path != NULL);
if (fd == NULL) {
handle_err ("usock_connect", "fd == NULL");
return -1;
}
if (path == NULL) {
handle_err ("usock_connect", "path == NULL");
return -1;
}
int32_t sfd;
struct sockaddr_un my_addr;
socklen_t peer_addr_size;
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
handle_err ("usock_connect", "sfd == -1");
return -1;
}
// clear structure
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, path, strlen (path));
peer_addr_size = sizeof(struct sockaddr_un);
if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
handle_err ("usock_connect", "connect == -1");
perror("connect()");
exit(errno);
}
*fd = sfd;
return 0;
}
int32_t usock_init (int32_t *fd, const char *path)
{
assert (fd != NULL);
assert (path != NULL);
if (fd == NULL) {
handle_err ("usock_init", "fd == NULL");
return -1;
}
if (path == NULL) {
handle_err ("usock_init", "path == NULL");
return -1;
}
int32_t sfd;
struct sockaddr_un my_addr;
socklen_t peer_addr_size;
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
handle_err ("usock_init", "sfd == -1");
return -1;
}
// clear structure
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, path, strlen (path));
// TODO FIXME
// delete the unix socket if already created
peer_addr_size = sizeof(struct sockaddr_un);
if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
handle_err ("usock_init", "bind == -1");
perror("bind()");
return -1;
}
if (listen (sfd, 5) == -1) {
handle_err ("usock_init", "listen == -1");
perror("listen()");
return -1;
}
*fd = sfd;
return 0;
}
int32_t usock_accept (int32_t fd, int32_t *pfd)
{
assert (pfd != NULL);
if (pfd == NULL) {
handle_err ("usock_accept", "pfd == NULL");
return -1;
}
struct sockaddr_un peer_addr;
memset (&peer_addr, 0, sizeof (struct sockaddr_un));
socklen_t peer_addr_size = 0;
*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (*pfd < 0) {
handle_err ("usock_accept", "accept < 0");
perror("listen()");
return -1;
}
return 0;
}
int32_t usock_close (int32_t fd)
{
int32_t ret;
ret = close (fd);
if (ret < 0) {
handle_err ("usock_close", "close ret < 0");
perror ("closing");
}
return ret;
}
int32_t usock_remove (const char *path)
{
return unlink (path);
}
int32_t main(int32_t argc, char * argv[])
{
int32_t tcpsockfd;
int32_t usockfd;
// check the number of args on command line
if(argc != 1)
{
fprintf (stderr, "USAGE: %s\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("Connection to the unix socket\n");
// 1. unix socket connection
int32_t ret = usock_connect (&usockfd, USOCK);
if (ret != 0) {
fprintf (stderr, "error: usock_connect\n");
exit(EXIT_FAILURE);
}
printf("Receiving the tcp socket\n");
// 2. receive the tcp socket
tcpsockfd = recvsockfd (usockfd);
printf("Sending 'hello world' to the tcp socket\n");
// 3. send a message to check the connection is effective
if (write(tcpsockfd, "hello world\n", strlen("hello world\n")) == -1) {
perror("write");
close(tcpsockfd);
exit(EXIT_FAILURE);
}
printf("Disconnection of both sockets\n");
// 4. close sockets
close(usockfd);
close(tcpsockfd);
return EXIT_SUCCESS;
}

View File

@ -1,322 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
#include <stdarg.h>
#define USOCK "./.socket"
#define handle_error(msg) \
do { log_error (msg); exit(EXIT_FAILURE); } while (0)
#define handle_err(fun,msg)\
do { log_error ("%s: file %s line %d %s", fun, __FILE__, __LINE__, msg); } while (0)
void log_format (const char* tag, const char* message, va_list args) {
time_t now;
time(&now);
char * date =ctime(&now);
date[strlen(date) - 1] = '\0';
printf("%s:%s: ", date, tag);
vprintf(message, args);
printf("\n");
}
void log_error (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("error", message, args);
va_end(args);
}
void log_info (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("info", message, args);
va_end(args);
}
void log_debug (const char* message, ...) {
va_list args;
va_start(args, message);
log_format("debug", message, args);
va_end(args);
}
int32_t build_socket (char *servername, char * serverport)
{
int32_t sockfd;
struct sockaddr_in6 server;
socklen_t addrlen;
// socket factory
if((sockfd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
perror("socket");
exit(EXIT_FAILURE);
}
// init remote addr structure and other params
server.sin6_family = AF_INET6;
server.sin6_port = htons(atoi(serverport));
addrlen = sizeof(struct sockaddr_in6);
// get addr from command line and convert it
if(inet_pton(AF_INET6, servername, &server.sin6_addr) != 1)
{
perror("inet_pton");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("Trying to connect to the remote host\n");
if(connect(sockfd, (struct sockaddr *) &server, addrlen) == -1)
{
perror("connect");
exit(EXIT_FAILURE);
}
return sockfd;
}
int32_t usock_connect (int32_t *fd, const char *path)
{
assert (fd != NULL);
assert (path != NULL);
if (fd == NULL) {
handle_err ("usock_connect", "fd == NULL");
return -1;
}
if (path == NULL) {
handle_err ("usock_connect", "path == NULL");
return -1;
}
int32_t sfd;
struct sockaddr_un my_addr;
socklen_t peer_addr_size;
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
handle_err ("usock_connect", "sfd == -1");
return -1;
}
// clear structure
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, path, strlen (path));
peer_addr_size = sizeof(struct sockaddr_un);
if(connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
handle_err ("usock_connect", "connect == -1");
perror("connect()");
exit(errno);
}
*fd = sfd;
return 0;
}
int32_t usock_init (int32_t *fd, const char *path)
{
assert (fd != NULL);
assert (path != NULL);
if (fd == NULL) {
handle_err ("usock_init", "fd == NULL");
return -1;
}
if (path == NULL) {
handle_err ("usock_init", "path == NULL");
return -1;
}
int32_t sfd;
struct sockaddr_un my_addr;
socklen_t peer_addr_size;
sfd = socket (AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
handle_err ("usock_init", "sfd == -1");
return -1;
}
// clear structure
memset(&my_addr, 0, sizeof(struct sockaddr_un));
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, path, strlen (path));
// TODO FIXME
// delete the unix socket if already created
peer_addr_size = sizeof(struct sockaddr_un);
if (bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1) {
handle_err ("usock_init", "bind == -1");
perror("bind()");
return -1;
}
if (listen (sfd, 5) == -1) {
handle_err ("usock_init", "listen == -1");
perror("listen()");
return -1;
}
*fd = sfd;
return 0;
}
int32_t usock_accept (int32_t fd, int32_t *pfd)
{
assert (pfd != NULL);
if (pfd == NULL) {
handle_err ("usock_accept", "pfd == NULL");
return -1;
}
struct sockaddr_un peer_addr;
memset (&peer_addr, 0, sizeof (struct sockaddr_un));
socklen_t peer_addr_size = 0;
*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (*pfd < 0) {
handle_err ("usock_accept", "accept < 0");
perror("listen()");
return -1;
}
return 0;
}
int32_t usock_close (int32_t fd)
{
int32_t ret;
ret = close (fd);
if (ret < 0) {
handle_err ("usock_close", "close ret < 0");
perror ("closing");
}
return ret;
}
int32_t usock_remove (const char *path)
{
return unlink (path);
}
int32_t build_unix_socket (char * path)
{
int32_t remotefd, localfd;
usock_init (&localfd, path);
usock_accept (localfd, &remotefd);
return remotefd;
}
static
void sendfd (int32_t socket, int32_t fd) // send fd by socket
{
struct ipc_messagehdr msg = { 0 };
char buf[CMSG_SPACE(sizeof(fd))];
memset(buf, '\0', sizeof(buf));
/* On Mac OS X, the struct iovec is needed, even if it points to minimal data */
struct iovec io = { .iov_base = "", .iov_len = 1 };
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
memmove(CMSG_DATA(cmsg), &fd, sizeof(fd));
msg.msg_controllen = cmsg->cmsg_len;
if (sendmsg(socket, &msg, 0) < 0)
handle_err("sendfd", "Failed to send message\n");
}
int32_t main(int32_t argc, char * argv[])
{
// check the number of args on command line
if(argc != 3)
{
fprintf (stderr, "USAGE: %s @server port_num\n", argv[0]);
exit(EXIT_FAILURE);
}
char *servername = argv[1];
char *serverport = argv[2];
printf("Connection to the tcp socket\n");
// 1. socket creation (tcp), connection to the server
int32_t sockfd = build_socket (servername, serverport);
printf("Sending 'coucou' to the tcp socket\n");
// send a message to check the connection is effective
if (write(sockfd, "coucou\n", strlen("coucou\n")) == -1) {
perror("write");
close(sockfd);
exit(EXIT_FAILURE);
}
printf ("Connection to the unix socket\n");
// 2. socket creation (unix)
int32_t usockfd = build_unix_socket (USOCK);
printf ("Passing the tcp socket to the unix socket\n");
// 3. tcp socket passing to the client
sendfd (usockfd, sockfd);
// send a message to check the connection is (still) effective
if (write(sockfd, "bye\n", strlen("bye\n")) == -1) {
perror("write");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("Disconnection\n");
// 4. close sockets
close(usockfd);
close(sockfd);
usock_remove (USOCK);
return EXIT_SUCCESS;
}

View File

@ -1,31 +0,0 @@
package=perfect-os-junk
version=0.0.1
CFLAGS="-O2 -Wall -Wextra -Wshadow -ansi -pedantic -std=c99 -D_XOPEN_SOURCE=500 -D_POSIX_C_SOURCE=200809L"
targets=(libposj)
type[libposj]=library
sources[libposj]="$(echo lib/*.c)"
target="pingpong/pingpong"
targets+=(${target})
sources[${target}]="$(echo pingpong/*.c)"
type[${target}]=binary
depends[${target}]="libposj.a"
ldflags[${target}]="libposj.a -lpthread"
target="pubsub/pubsub"
targets+=(${target})
sources[${target}]="$(ls pubsub/*.c | grep -v test-send)"
type[${target}]=binary
depends[${target}]="libposj.a"
ldflags[${target}]="libposj.a -lpthread"
target="pubsub/pubsub-test-send"
targets+=(${target})
sources[${target}]="pubsub/pubsub-test-send.c"
type[${target}]=binary
depends[${target}]="libposj.a"
ldflags[${target}]="libposj.a -lpthread"

View File

@ -1,50 +0,0 @@
#include "../lib/pubsubd.h"
#include <cbor.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PKT_CLOSE 0
#define PKT_MSG 1
#define PKT_ERROR 2
void usage (char **argv) {
printf ("usage: echo something | msg | %s\n", argv[0]);
}
int32_t main(int32_t argc, char * argv[])
{
if (argc == 2 && strcmp ("-h", argv[1]) == 0) {
usage (argv);
exit (1);
}
// read the message from the client
size_t mlen = 0;
uint8_t buf[BUFSIZ];
mlen = read (0, buf, BUFSIZ);
/* Assuming `buffer` contains `info.st_size` bytes of input data */
struct cbor_load_result result;
cbor_item_t * item = cbor_load (buf, mlen, &result);
/* Pretty-print the result */
cbor_describe(item, stdout);
fflush(stdout);
struct cbor_pair * pair = cbor_map_handle (item);
cbor_mutable_data *data = cbor_bytestring_handle (pair->value);
size_t datalen = cbor_bytestring_length (pair->value);
char *bstr = malloc (datalen +1);
memset (bstr, 0, datalen +1);
memcpy (bstr, data, datalen);
printf ("msg data (%ld bytes): %s\n", datalen, bstr);
/* Deallocate the result */
cbor_decref (&item);
free (bstr);
return EXIT_SUCCESS;
}

View File

@ -1,158 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* port we're listening on */
#define PORT 2020
int32_t main(int32_t argc, char *argv[])
{
/* master file descriptor list */
fd_set master;
/* temp file descriptor list for select() */
fd_set read_fds;
/* server address */
struct sockaddr_in serveraddr;
/* client address */
struct sockaddr_in clientaddr;
/* maximum file descriptor number */
int32_t fdmax;
/* listening socket descriptor */
int32_t listener;
/* newly accept()ed socket descriptor */
int32_t newfd;
/* buffer for client data */
char buf[1024];
int32_t nbytes;
/* for setsockopt() SO_REUSEADDR, below */
int32_t yes = 1;
int32_t addrlen;
int32_t i, j;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* get the listener */
if((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
exit(1);
}
printf("Server-socket() is OK...\n");
/*"address already in use" error message */
if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int32_t)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");
/* bind */
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
/* listen */
if(listen(listener, 10) == -1)
{
perror("Server-listen() error lol!");
exit(1);
}
printf("Server-listen() is OK...\n");
/* add the listener to the master set */
FD_SET(listener, &master);
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one*/
/* loop */
for(;;) {
/* copy it */
read_fds = master;
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("Server-select() error lol!");
exit(1);
}
printf("Server-select() is OK...\n");
/*run through the existing connections looking for data to be read*/
for(i = 0; i <= fdmax; i++) {
if(FD_ISSET(i, &read_fds)) {
/* we got one... */
if(i == listener) {
/* handle new connections */
addrlen = sizeof(clientaddr);
if((newfd = accept(listener, (struct sockaddr *)&clientaddr, &addrlen)) == -1)
{
perror("Server-accept() error lol!");
}
else
{
printf("Server-accept() is OK...\n");
FD_SET(newfd, &master); /* add to master set */
if(newfd > fdmax)
{ /* keep track of the maximum */
fdmax = newfd;
}
printf("%s: New connection from %s on socket %d\n"
, argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
}
}
else {
/* handle data from a client */
if((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) {
/* got error or connection closed by client */
if(nbytes == 0)
/* connection closed */
printf("%s: socket %d hung up\n", argv[0], i);
else
perror("recv() error lol!");
/* close it... */
close(i);
/* remove from master set */
FD_CLR(i, &master);
}
else {
/* we got some data from a client*/
for(j = 0; j <= fdmax; j++) {
/* send to everyone! */
if(FD_ISSET(j, &master)) {
/* except the listener and ourselves */
if(j != listener && j != i) {
if(send(j, buf, nbytes, 0) == -1)
perror("send() error lol!");
}
}
}
}
}
}
}
}
return 0;
}

35
man/libipc.7.md Normal file
View File

@ -0,0 +1,35 @@
---
title: libipc
header: libipc Manual
footer: libipc
date: 2018-11-20
section: 7
...
# NAME
libipc - Simple, easy-to-use IPC library
# SYNOPSIS
**`#include <ipc.h>`**
**`...`**
# DESCRIPTION
**libipc** is a library that provides interprocess communication medium between applications.
It provides both client and server code.
# USAGE
# NOTES
# SEE ALSO
# BUGS & LIMITATIONS
- Documentation is currently limited.
- Rerouting IPC connexions through other services (for example, through a network bridge service) is currently not possible.
- Errors management is currently limited, and precise errors cannot be distinguished.

View File

@ -1,31 +0,0 @@
# Service ping-pong
This service is a brain-dead application. It is only to a pedagogic end.
The purpose is only to communicate with an application once, the application
sends a message and the service answer with the same message.
# How it works
* **S**: service
* **A**: application
1. **S** creates the named pipe /tmp/pingpong, then listens
2. **S** opens the named pipes in & out
3. **A** talks with the test program *pingpong.sh*
4. **S** closes the test program named pipes
5. **S** removes the named pipe /tmp/pingpong after 10 served applications
# pingpong.sh
The script *pingpong.sh* lets you test the service.
Usage :
pingpong.sh [NB]
# NB is the number of exchanged messages
or
pingpong.sh clean
# it is to clean the /tmp/ipc/ directory

View File

@ -1,29 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread -lreadline
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c ../../core/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
test:
rm /tmp/ipc/pongd-0-0
./pongd.bin
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(OBJECTS) $@.c -o $@.bin $(LDFLAGS)
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin $(PARAMS)
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin

View File

@ -1,211 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdint.h>
#include "../../core/communication.h"
#include "../../core/error.h"
#define SERVICE_NAME "pongd"
#define MAX_MESSAGE_SIZE IPC_MAX_MESSAGE_SIZE
#define MESSAGE "salut ça va ?"
void interactive (char * service_name, char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (ipc_application_connection (env, &srv, service_name) < 0) {
handle_err ("main", "ipc_application_connection < 0");
exit (EXIT_FAILURE);
}
struct ipc_event event;
memset (&event, 0, sizeof (struct ipc_event));
struct ipc_services services;
memset (&services, 0, sizeof (struct ipc_services));
ipc_services_add (&services, &srv);
int ret = 0;
while (1) {
printf ("msg to send: ");
fflush (stdout);
ret = ipc_application_peek_event (&services, &event);
if (ret != 0) {
handle_error("ipc_application_peek_event != 0");
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_STDIN:
{
struct ipc_message *m = event.m;
if ( m->length == 0 || strncmp (m->payload, "exit", 4) == 0) {
ipc_message_empty (m);
free (m);
ipc_services_free (&services);
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}
char mtype_str[5];
memset(mtype_str, 0, 5);
printf ("message type: ");
fflush(stdout);
read(0, mtype_str, 5);
m->type = atoi(mtype_str);
memset(mtype_str, 0, 5);
if (ipc_application_write (&srv, m) < 0) {
handle_err("main", "application_write < 0");
exit (EXIT_FAILURE);
}
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
printf ("msg recv: %.*s", m->length, m->payload);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
printf ("server disconnected: quitting...\n");
// just remove srv from services, it's already closed
ipc_services_free (&services);
exit (EXIT_SUCCESS);
};
case IPC_EVENT_TYPE_NOT_SET:
case IPC_EVENT_TYPE_CONNECTION:
case IPC_EVENT_TYPE_ERROR:
default :
fprintf (stderr, "should not happen, event type %d\n", event.type);
}
}
}
void non_interactive (char msg_type, char *msg, char * service_name, char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (ipc_application_connection (env, &srv, service_name) < 0) {
handle_err ("main", "ipc_application_connection < 0");
exit (EXIT_FAILURE);
}
ipc_message_format (&m, msg_type, msg, strlen(msg) + 1);
// print_msg (&m);
if (ipc_application_write (&srv, &m) < 0) {
handle_err("main", "application_write < 0");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
if (ipc_application_read (&srv, &m) < 0) {
handle_err("main", "application_read < 0");
exit (EXIT_FAILURE);
}
if (m.length > 0) {
printf ("msg recv: %.*s\n", m.length, m.payload);
}
ipc_message_empty (&m);
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
}
// usage: ipc-debug [service-name]
int main (int argc, char *argv[], char *env[])
{
if (argc == 1) {
printf ("usage: %s [-n] [service_name [message-type [message]]]\n", argv[0]);
exit (EXIT_SUCCESS);
}
char service_name[100];
memset (service_name, 0, 100);
int asked_non_interactive = 0;
int current_param = 1;
if (argc >= 2) {
if (memcmp (argv[current_param], "-n", 2) == 0) {
// non interactive
asked_non_interactive = 1;
current_param++;
argc--;
}
}
if (argc != 1) {
ssize_t t = strlen(argv[current_param]) > 100 ? 100 : strlen(argv[current_param]);
memcpy(service_name, argv[current_param], t);
current_param++;
}
else { memcpy(service_name, SERVICE_NAME, strlen(SERVICE_NAME)); }
char mtype = 2;
if (argc > 2) {
mtype = atoi(argv[current_param]);
current_param++;
}
char *msg = malloc (MAX_MESSAGE_SIZE);
if (msg == NULL) {
handle_err("main", "not enough memory");
exit (EXIT_FAILURE);
}
memset(msg, 0, MAX_MESSAGE_SIZE);
if (argc > 3) { memcpy(msg, argv[current_param], strlen(argv[current_param])); }
else { memcpy(msg, MESSAGE, strlen(MESSAGE)); }
if (asked_non_interactive) {
non_interactive (mtype, msg, service_name, env);
free (msg);
}
else {
free (msg);
interactive (service_name, env);
}
return EXIT_SUCCESS;
}

View File

@ -1,138 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../../core/ipc.h"
#include "../../core/error.h"
#define MSG "coucou"
#define SERVICE_NAME "pongd"
void non_interactive (char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (ipc_application_connection (env, &srv, SERVICE_NAME) < 0) {
handle_err("main", "ipc_application_connection < 0");
exit (EXIT_FAILURE);
}
printf ("msg to send: %.*s\n", (int) strlen(MSG), MSG);
ipc_message_format_data (&m, MSG, strlen(MSG) +1);
// printf ("msg to send in the client: ");
// ipc_message_print (&m);
if (ipc_application_write (&srv, &m) < 0) {
handle_err("main", "application_write < 0");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
if (ipc_application_read (&srv, &m) < 0) {
handle_err("main", "application_read < 0");
exit (EXIT_FAILURE);
}
printf ("msg recv: %s\n", m.payload);
ipc_message_empty (&m);
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
}
void interactive (char *env[])
{
int ret = 0;
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (ipc_application_connection (env, &srv, SERVICE_NAME) < 0) {
handle_err ("main", "ipc_application_connection < 0");
exit (EXIT_FAILURE);
}
struct ipc_event event;
memset (&event, 0, sizeof (struct ipc_event));
struct ipc_services services;
memset (&services, 0, sizeof (struct ipc_services));
ipc_services_add (&services, &srv);
while (1) {
printf ("msg to send: ");
fflush (stdout);
ret = ipc_application_peek_event (&services, &event);
if (ret != 0) {
handle_error("ipc_application_peek_event != 0");
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_STDIN:
{
struct ipc_message *m = event.m;
if ( m->length == 0 || strncmp (m->payload, "exit", 4) == 0) {
ipc_message_empty (m);
free (m);
ipc_services_free (&services);
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}
if (ipc_application_write (&srv, m) < 0) {
handle_err("main", "application_write < 0");
exit (EXIT_FAILURE);
}
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
printf ("msg recv: %.*s", m->length, m->payload);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
case IPC_EVENT_TYPE_NOT_SET:
case IPC_EVENT_TYPE_CONNECTION:
case IPC_EVENT_TYPE_ERROR:
default :
fprintf (stderr, "should not happen, event type %d\n", event.type);
}
}
}
int main (int argc, char *argv[], char *env[])
{
argc = argc; // warnings
argv = argv; // warnings
if (argc == 1)
non_interactive (env);
else
interactive (env);
return EXIT_SUCCESS;
}

View File

@ -1,164 +0,0 @@
#include "../../core/ipc.h"
#include "../../core/error.h"
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define PONGD_SERVICE_NAME "pongd"
#define PONGD_PRINT_MESSAGES
int cpt = 0;
struct ipc_service *srv = 0;
struct ipc_clients *clients;
void main_loop ()
{
int ret = 0;
clients = malloc (sizeof (struct ipc_clients));
memset(clients, 0, sizeof(struct ipc_clients));
struct ipc_event event;
memset(&event, 0, sizeof (struct ipc_event));
event.type = IPC_EVENT_TYPE_NOT_SET;
while(1) {
// ipc_service_poll_event provides one event at a time
// warning: event->m is free'ed if not NULL
ret = ipc_service_poll_event (clients, srv, &event);
if (ret != 0) {
handle_error("ipc_service_poll_event != 0");
// the application will shut down, and close the service
if (ipc_server_close (srv) < 0) {
handle_error("ipc_server_close < 0");
}
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION:
{
cpt++;
#ifdef PONGD_PRINT_MESSAGES
printf ("connection: client fd %d, %d clients connected\n"
, ((struct ipc_client*) event.origin)->proc_fd, cpt);
#endif
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
cpt--;
#ifdef PONGD_PRINT_MESSAGES
printf ("disconnection: %d clients remaining\n", cpt);
#endif
// free the ipc_client structure
free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
#ifdef PONGD_PRINT_MESSAGES
if (m->length > 0) {
printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
}
#endif
if (ipc_server_write (event.origin, m) < 0) {
handle_err( "handle_new_msg", "server_write < 0");
}
};
break;
case IPC_EVENT_TYPE_ERROR:
{
fprintf (stderr, "a problem happened with client %d\n"
, ((struct ipc_client*) event.origin)->proc_fd);
};
break;
default :
{
fprintf (stderr, "there must be a problem, event not set\n");
};
}
}
// should never go there
exit (1);
}
void exit_program(int signal)
{
printf("Quitting, signal: %d\n", signal);
// free remaining clients
for (int i = 0; i < clients->size ; i++) {
struct ipc_client *cli = clients->clients[i];
// TODO: replace with specific ipc_client_empty function
if (cli != NULL) {
// ipc_client_empty (cli);
free (cli);
}
clients->clients[i] = NULL;
}
ipc_clients_free (clients);
free (clients);
// the application will shut down, and close the service
if (ipc_server_close (srv) < 0) {
handle_error("ipc_server_close < 0");
}
free (srv);
exit(EXIT_SUCCESS);
}
/*
* service ping-pong: send back everything sent by the clients
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main(int argc, char * argv[], char **env)
{
argc = argc; // warnings
argv = argv; // warnings
printf ("pid = %d\n", getpid ());
srv = malloc (sizeof (struct ipc_service));
if (srv == NULL) {
exit (1);
}
memset (srv, 0, sizeof (struct ipc_service));
srv->index = 0;
srv->version = 0;
// unlink("/tmp/ipc/pongd-0-0");
if (ipc_server_init (env, srv, PONGD_SERVICE_NAME) < 0) {
handle_error("ipc_server_init < 0");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv->spath);
printf("MAIN: server created\n" );
signal (SIGHUP, exit_program);
signal (SIGALRM, exit_program);
signal (SIGUSR1, exit_program);
signal (SIGUSR2, exit_program);
signal (SIGTERM, exit_program);
signal (SIGINT, exit_program);
// the service will loop until the end of time, or a signal
main_loop ();
// main_loop should not return
return EXIT_FAILURE;
}

View File

@ -1,106 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <stdint.h>
#include "../../core/communication.h"
#include "../../core/error.h"
#define SERVICE_NAME "pongd"
#define NUMBER_OF_MESSAGES 1000
#define MAX_MESSAGE_SIZE IPC_MAX_MESSAGE_SIZE
#define MESSAGE "salut ça va ?"
void non_interactive (char msg_type, char *msg, char * service_name, char *env[])
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
// index and version should be filled
srv.index = 0;
srv.version = 0;
// init service
if (ipc_application_connection (env, &srv, service_name) < 0) {
handle_err ("main", "ipc_application_connection < 0");
exit (EXIT_FAILURE);
}
for (int i = 0 ; i < NUMBER_OF_MESSAGES ; i++) {
ipc_message_format (&m, msg_type, msg, strlen(msg) + 1);
// print_msg (&m);
if (ipc_application_write (&srv, &m) < 0) {
handle_err("main", "application_write < 0");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
if (ipc_application_read (&srv, &m) < 0) {
handle_err("main", "application_read < 0");
exit (EXIT_FAILURE);
}
#ifdef WITH_PRINT_MESSAGES
if (m.length > 0) {
printf ("msg recv: %.*s\n", m.length, m.payload);
}
#endif
ipc_message_empty (&m);
}
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
}
// usage: ipc-debug [service-name]
int main (int argc, char *argv[], char *env[])
{
if (argc == 1) {
printf ("usage: %s service_name [message-type [message]]\n", argv[0]);
exit (EXIT_SUCCESS);
}
char service_name[100];
memset (service_name, 0, 100);
int current_param = 1;
if (argc != 1) {
ssize_t t = strlen(argv[current_param]) > 100 ? 100 : strlen(argv[current_param]);
memcpy(service_name, argv[current_param], t);
current_param++;
}
else { memcpy(service_name, SERVICE_NAME, strlen(SERVICE_NAME)); }
char mtype = 2;
if (argc > 2) {
mtype = atoi(argv[current_param]);
current_param++;
}
char *msg = malloc (MAX_MESSAGE_SIZE);
if (msg == NULL) {
handle_err("main", "not enough memory");
exit (EXIT_FAILURE);
}
memset(msg, 0, MAX_MESSAGE_SIZE);
if (argc > 3) { memcpy(msg, argv[current_param], strlen(argv[current_param])); }
else { memcpy(msg, MESSAGE, strlen(MESSAGE)); }
non_interactive (mtype, msg, service_name, env);
free (msg);
return EXIT_SUCCESS;
}

15
project.zsh Normal file
View File

@ -0,0 +1,15 @@
package=ipc
version=0.1.0
targets=(libipc src/ipc.h man/libipc.7)
type[libipc]=library
sources[libipc]="$(ls src/*.c)"
type[src/ipc.h]=header
type[man/libipc.7]=man
dist=(Makefile project.zsh src/error.h src/ipc.h src/event.h man/*.md)

View File

@ -1,25 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c ../../core/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin

View File

@ -1,171 +0,0 @@
#include "../../core/ipc.h"
#include "../lib/message.h"
#include "../lib/channels.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define PUBSUBD_SERVICE_NAME "pubsubd"
void usage (char **argv) {
printf ( "usage: %s [chan [pub]]\n", argv[0]);
}
void print_cmd (void) {
printf ("\033[32m>\033[00m ");
fflush (stdout);
}
void chan_sub (struct ipc_service *srv, char *chan)
{
struct pubsub_msg msg;
memset (&msg, 0, sizeof (struct pubsub_msg));
// meta data on the message
msg.type = PUBSUB_MSG_TYPE_SUB;
pubsub_message_set_chan (&msg, chan, strlen(chan));
pubsub_message_send (srv, &msg);
printf ("subscribed to %s\n", chan);
pubsub_message_empty (&msg);
}
void main_loop (char **env, int index, int version
, char *cmd, char *chan)
{
printf ("connection to pubsubd: index %d version %d "
"cmd %s chan %s\n"
, index, version, cmd, chan );
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
int ret = ipc_application_connection (env, &srv, PUBSUBD_SERVICE_NAME);
if (ret != 0) {
handle_err ("pubsub_connection", "application_connection != 0");
}
printf ("connected\n");
if (strncmp (cmd, "sub", 3) == 0) {
chan_sub (&srv, chan);
}
printf ("main_loop\n");
struct pubsub_msg msg;
memset (&msg, 0, sizeof (struct pubsub_msg));
// meta data on the message
msg.type = PUBSUB_MSG_TYPE_PUB;
pubsub_message_set_chan (&msg, chan, strlen(chan));
struct ipc_event event;
memset (&event, 0, sizeof (struct ipc_event));
struct ipc_services services;
memset (&services, 0, sizeof (struct ipc_services));
ipc_service_add (&services, &srv);
int should_continue = 1;
while (should_continue) {
print_cmd ();
ret = ipc_application_peek_event (&services, &event);
if (ret != 0) {
handle_error("ipc_application_peek_event != 0");
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_STDIN:
{
struct ipc_message *m = event.m;
if ( m->length == 0 || strncmp (m->payload, "exit", 4) == 0) {
ipc_message_empty (m);
free (m);
should_continue = 0;
break;
}
// get the curent payload, change it to be compatible with the application
// then send it
char *pointer_to_return = strchr (m->payload, '\n');
*pointer_to_return = '\0';
m->length--;
pubsub_message_set_chan (&msg, chan, strlen(chan));
pubsub_message_set_data (&msg, m->payload, m->length);
pubsub_message_send (&srv, &msg);
pubsub_message_empty (&msg);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
// print_hexa ("received msg hexa", (unsigned char *) m->payload, m->length);
pubsub_message_from_message (&msg, m);
printf ("\r\033[31m>\033[00m %.*s\n", (int) msg.datalen, msg.data);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
printf ("server disconnected: quitting...\n");
// just remove srv from services, it's already closed
ipc_services_free (&services);
exit (EXIT_SUCCESS);
};
break;
case IPC_EVENT_TYPE_NOT_SET:
case IPC_EVENT_TYPE_CONNECTION:
case IPC_EVENT_TYPE_ERROR:
default :
fprintf (stderr, "should not happen, event type %d\n", event.type);
}
}
// free everything
pubsub_message_empty (&msg);
printf ("disconnection...\n");
ipc_services_free (&services);
if (ipc_application_close (&srv) < 0) {
handle_err("main", "application_close < 0");
exit (EXIT_FAILURE);
}
}
int main(int argc, char **argv, char **env)
{
char *cmd = "sub";
char *chan = "chan1";
if (argc == 2 && strncmp("-h", argv[1], 2) == 0) {
usage (argv);
exit (0);
}
if (argc >= 2) {
chan = argv[1];
}
if (argc >= 3) {
cmd = argv[2];
}
int index = 0;
// don't care about the version
int version = 0;
main_loop (env, index, version, cmd, chan);
return EXIT_SUCCESS;
}

View File

@ -1,197 +0,0 @@
#include "../../core/ipc.h"
#include "../lib/message.h"
#include "../lib/channels.h"
#include <stdlib.h>
#include <sys/socket.h>
#include <signal.h>
#define PUBSUBD_SERVICE_NAME "pubsubd"
// to quit them properly if a signal occurs
struct ipc_service srv;
struct channels chans;
void pubsubd_send (const struct ipc_clients *clients, const struct pubsub_msg * pubsub_msg)
{
if (clients == NULL) {
fprintf (stderr, "pubsubd_send: clients == NULL");
return;
}
if (pubsub_msg == NULL) {
fprintf (stderr, "pubsubd_send: pubsub_msg == NULL");
return;
}
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
pubsub_message_to_message (pubsub_msg, &m);
int i;
for (i = 0; i < clients->size ; i++) {
ipc_server_write (clients->clients[i], &m);
}
ipc_message_empty (&m);
}
void pubsubd_main_loop (struct ipc_service *srv, struct channels *chans)
{
int i, ret = 0;
struct ipc_clients clients;
memset(&clients, 0, sizeof(struct ipc_clients));
struct ipc_clients proc_to_read;
memset(&proc_to_read, 0, sizeof(struct ipc_clients));
struct ipc_event event;
memset(&event, 0, sizeof (struct ipc_event));
event.type = IPC_EVENT_TYPE_NOT_SET;
int cpt = 0;
while(1) {
ret = ipc_service_poll_event (&clients, srv, &event);
if (ret != 0) {
handle_error("ipc_service_poll_event != 0");
// the application will shut down, and close the service
if (ipc_server_close (srv) < 0) {
handle_error("ipc_server_close < 0");
}
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION:
{
cpt++;
struct ipc_client *cli = event.origin;
printf ("connection of client %d: %d clients connected\n", cli->proc_fd, cpt);
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
cpt--;
struct ipc_client *cli = event.origin;
printf ("disconnection of client %d: %d clients remaining\n", cli->proc_fd, cpt);
pubsubd_channels_unsubscribe_everywhere (chans, cli);
// free the ipc_client structure
free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
// print_hexa ("received msg hexa", (unsigned char *) m->payload, m->length);
struct ipc_client *cli = event.origin;
struct pubsub_msg pm;
memset (&pm, 0, sizeof (struct pubsub_msg));
pubsub_message_from_message (&pm, m);
if (pm.type == PUBSUB_MSG_TYPE_SUB) {
printf ("client %d subscribing to %s\n"
, cli->proc_fd
, pm.chan);
pubsubd_channels_subscribe (chans
, pm.chan, cli);
}
if (pm.type == PUBSUB_MSG_TYPE_UNSUB) {
printf ("client %d unsubscribing to %s\n", cli->proc_fd, pm.chan);
pubsubd_channels_unsubscribe (chans, pm.chan, cli);
}
if (pm.type == PUBSUB_MSG_TYPE_PUB) {
// printf ("client %d: publishing to %s: %s\n", cli->proc_fd, pm.chan, pm.data);
printf ("client %d: ", cli->proc_fd);
pubsub_message_print (&pm);
struct channel *chan = pubsubd_channel_search (chans, pm.chan);
if (chan == NULL) {
handle_err ("handle_new_msg", "publish on nonexistent channel");
ipc_message_empty (m);
continue;
}
pubsubd_send (chan->subs, &pm);
}
pubsub_message_empty (&pm);
};
break;
case IPC_EVENT_TYPE_ERROR:
{
fprintf (stderr, "a problem happened with client %d\n"
, ((struct ipc_client*) event.origin)->proc_fd);
};
break;
default :
{
fprintf (stderr, "there must be a problem, event not set\n");
};
}
}
for (i = 0; i < clients.size; i++) {
if (ipc_server_close_client (clients.clients[i]) < 0) {
handle_error( "server_close_client < 0");
}
}
pubsubd_channels_del_all (chans);
}
void handle_signal (int signalnumber)
{
// the application will shut down, and remove the service named pipe
if (ipc_server_close (&srv) < 0) {
handle_error("ipc_server_close < 0");
}
pubsubd_channels_del_all (&chans);
fprintf (stderr, "received a signal %d\n", signalnumber);
exit (EXIT_SUCCESS);
}
int
main(int argc, char **argv, char **env)
{
argc = argc;
argv = argv;
// set the service
memset (&srv, 0, sizeof (struct ipc_service));
srv.index = 0;
srv.version = 0;
signal(SIGHUP, handle_signal);
signal(SIGINT, handle_signal);
signal(SIGQUIT, handle_signal);
// set the channels
memset (&chans, 0, sizeof (struct channels));
pubsubd_channels_init (&chans);
if (ipc_server_init (env, &srv, PUBSUBD_SERVICE_NAME) < 0) {
handle_error("ipc_server_init < 0");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv.spath);
printf("MAIN: server created\n" );
// the service will loop until the end of time, a specific message, a signal
pubsubd_main_loop (&srv, &chans);
// the application will shut down, and remove the service named pipe
if (ipc_server_close (&srv) < 0) {
handle_error("ipc_server_close < 0");
}
return EXIT_SUCCESS;
}

View File

@ -1,195 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../core/error.h"
#include "../../core/client.h"
#include "channels.h"
void pubsubd_channel_print (const struct channel *chan)
{
if (chan->chan == NULL) {
handle_err ("pubsubd_channel_print", "chan->chan == NULL");
}
printf ( "\033[32mchan %s\033[00m\n", chan->chan);
if (chan->subs == NULL) {
handle_err ("pubsubd_channel_print", "chan->subs == NULL");
}
else {
ipc_clients_print (chan->subs);
}
}
void pubsubd_channels_print (const struct channels *chans)
{
printf ("\033[36mmchannels\033[00m\n");
if (chans == NULL) {
handle_err ("pubsubd_channels_print", "chans == NULL");
return ;
}
struct channel *chan = NULL;
LIST_FOREACH(chan, chans, entries) {
pubsubd_channel_print (chan);
}
}
void pubsubd_channels_init (struct channels *chans) { LIST_INIT(chans); }
struct channel * pubsubd_channels_add (struct channels *chans, const char *chan)
{
if(chans == NULL || chan == NULL) {
handle_err ("pubsubd_channels_add", "chans == NULL or chan == NULL");
return NULL;
}
struct channel *n = malloc (sizeof (struct channel));
memset (n, 0, sizeof (struct channel));
pubsubd_channel_new (n, chan);
LIST_INSERT_HEAD(chans, n, entries);
return n;
}
void pubsubd_channels_del (struct channels *chans, struct channel *c)
{
struct channel *todel = pubsubd_channel_get (chans, c);
if(todel != NULL) {
pubsubd_channel_free (todel);
LIST_REMOVE(todel, entries);
free (todel);
todel = NULL;
}
}
void pubsubd_channels_del_all (struct channels *chans)
{
if (!chans)
return;
struct channel *c = NULL;
while (!LIST_EMPTY(chans)) {
c = LIST_FIRST(chans);
LIST_REMOVE(c, entries);
pubsubd_channel_free (c);
free (c);
c = NULL;
}
}
int pubsubd_channel_new (struct channel *c, const char * name)
{
if (c == NULL) {
return 1;
}
size_t nlen = (strlen (name) > BUFSIZ) ? BUFSIZ : strlen (name);
if (c->chan == NULL)
c->chan = malloc (nlen +1);
memset (c->chan, 0, nlen +1);
memcpy (c->chan, name, nlen);
c->chanlen = nlen;
c->subs = malloc (sizeof (struct ipc_clients));
memset (c->subs, 0, sizeof (struct ipc_clients));
return 0;
}
void pubsubd_channel_free (struct channel * c)
{
if (c == NULL)
return;
if (c->chan != NULL) {
free (c->chan);
c->chan = NULL;
}
if (c->subs != NULL) {
ipc_clients_free (c->subs);
free (c->subs);
}
}
struct channel * pubsubd_channel_search (struct channels *chans, char *chan)
{
struct channel * np = NULL;
LIST_FOREACH(np, chans, entries) {
// TODO debug
// printf ("pubsubd_channel_search: %s (%ld) vs %s (%ld)\n"
// , np->chan, np->chanlen, chan, strlen(chan));
if (np->chanlen == strlen (chan)
&& strncmp (np->chan, chan, np->chanlen) == 0) {
// printf ("pubsubd_channel_search: FOUND\n");
return np;
}
}
return NULL;
}
struct channel * pubsubd_channel_get (struct channels *chans, struct channel *c)
{
struct channel * np = NULL;
LIST_FOREACH(np, chans, entries) {
if (pubsubd_channel_eq (np, c))
return np;
}
return NULL;
}
int pubsubd_channel_eq (const struct channel *c1, const struct channel *c2)
{
return c1->chanlen == c2->chanlen &&
strncmp (c1->chan, c2->chan, c1->chanlen) == 0;
}
void pubsubd_channel_subscribe (const struct channel *c, struct ipc_client *p)
{
ipc_client_add (c->subs, p);
}
void pubsubd_channel_unsubscribe (const struct channel *c, struct ipc_client *p)
{
ipc_client_del (c->subs, p);
}
void pubsubd_channels_subscribe (struct channels *chans
, char *chname, struct ipc_client *p)
{
struct channel *chan = pubsubd_channel_search (chans, chname);
if (chan == NULL) {
printf ("chan %s non existent : creation\n", chname);
chan = pubsubd_channels_add (chans, chname);
}
pubsubd_channel_subscribe (chan, p);
}
void pubsubd_channels_unsubscribe (struct channels *chans
, char *chname, struct ipc_client *p)
{
struct channel *chan = pubsubd_channel_search (chans, chname);
if (chan == NULL) {
return;
}
pubsubd_channel_unsubscribe (chan, p);
}
void pubsubd_channels_unsubscribe_everywhere (struct channels *chans
, struct ipc_client *p)
{
struct channel * chan = NULL;
LIST_FOREACH(chan, chans, entries) {
pubsubd_channel_unsubscribe (chan, p);
}
}

View File

@ -1,45 +0,0 @@
#ifndef __CHANNELS_H__
#define __CHANNELS_H__
#include "../../core/ipc.h"
// head of the list
LIST_HEAD(channels, channel);
// element of the list
// channel : chan name + chan name length + a list of applications
struct channel {
char *chan;
size_t chanlen;
struct ipc_clients *subs;
LIST_ENTRY(channel) entries;
};
// simple channel
int pubsubd_channel_new (struct channel *c, const char *name);
struct channel * pubsubd_channel_get (struct channels *chans, struct channel *c);
void pubsubd_channel_free (struct channel *c);
int pubsubd_channel_eq (const struct channel *c1, const struct channel *c2);
void pubsubd_channel_print (const struct channel *c);
// list of channels
void pubsubd_channels_init (struct channels *chans);
void pubsubd_channels_print (const struct channels *chans);
struct channel * pubsubd_channels_add (struct channels *chans, const char *chan);
void pubsubd_channels_del (struct channels *chans, struct channel *c);
void pubsubd_channels_del_all (struct channels *chans);
struct channel * pubsubd_channel_search (struct channels *chans, char *chan);
// add and remove subscribers
void pubsubd_channel_subscribe (const struct channel *c, struct ipc_client *p);
void pubsubd_channel_unsubscribe (const struct channel *c, struct ipc_client *p);
void pubsubd_channels_subscribe (struct channels *chans
, char *chname, struct ipc_client *p);
void pubsubd_channels_unsubscribe (struct channels *chans
, char *chname, struct ipc_client *p);
void pubsubd_channels_unsubscribe_everywhere (struct channels *chans
, struct ipc_client *p);
#endif

View File

@ -1,164 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strndup, strncpy
#include "message.h"
void pubsub_message_set_data (struct pubsub_msg *pm, char *data, size_t len)
{
pm->datalen = len;
if (pm->data != NULL) {
free (pm->data);
}
pm->data = malloc (len + 1);
memset (pm->data, 0, len);
strncpy (pm->data, data, len);
pm->data[len] = '\0';
}
void pubsub_message_set_chan (struct pubsub_msg *pm, char *chan, size_t len)
{
pm->chanlen = len;
if (pm->chan != NULL) {
free (pm->chan);
}
pm->chan = malloc (len + 1);
memset (pm->chan, 0, len);
strncpy (pm->chan, chan, len);
pm->chan[len] = '\0';
}
void pubsub_message_from_message (struct pubsub_msg *pm, struct ipc_message *m)
{
size_t offset = 0;
pubsub_message_empty (pm); // just in case
pm->type = m->type;
// chan
memcpy (&pm->chanlen, m->payload + offset, sizeof (size_t));
if (pm->chanlen > BUFSIZ) {
handle_err ("pubsub_message_from_message", "chanlen > BUFSIZ");
return;
}
offset += sizeof (size_t);
if (pm->chanlen > 0) {
pubsub_message_set_chan (pm, m->payload + offset, pm->chanlen);
offset += pm->chanlen;
}
// data
memcpy (&pm->datalen, m->payload + offset, sizeof (size_t));
if (pm->datalen > BUFSIZ) {
handle_err ("pubsub_message_from_message", "chanlen > BUFSIZ");
return;
}
offset += sizeof (size_t);
if (pm->datalen > 0) {
pubsub_message_set_data (pm, m->payload + offset, pm->datalen);
offset += pm->datalen;
}
}
void pubsub_message_to_message (const struct pubsub_msg *msg, struct ipc_message *m)
{
if (msg == NULL) {
handle_err ("pubsub_message_to_message", "msg == NULL");
return;
}
if (m == NULL) {
handle_err ("pubsub_message_to_message", "data == NULL");
return;
}
ipc_message_empty (m); // just in case
size_t buflen = 2 * sizeof (size_t) + msg->chanlen + msg->datalen;
if (buflen > BUFSIZ) {
handle_err ("pubsub_message_serialize", "chanlen + datalen too high");
return;
}
char *buf = malloc (buflen);
memset (buf, 0, buflen);
size_t offset = 0;
m->type = msg->type;
// chan
memcpy (buf + offset, &msg->chanlen, sizeof (size_t));
offset += sizeof (size_t);
memcpy (buf + offset, msg->chan, msg->chanlen);
offset += msg->chanlen;
// data
memcpy (buf + offset, &msg->datalen, sizeof (size_t));
offset += sizeof (size_t);
memcpy (buf + offset, msg->data, msg->datalen);
offset += msg->datalen;
m->payload = buf;
m->length = buflen;
}
void pubsub_message_empty (struct pubsub_msg *msg)
{
if (msg == NULL) {
handle_err ("pubsub_message_empty", "msg == NULL");
return;
}
if (msg->chan != NULL) {
free (msg->chan);
msg->chan = NULL;
}
if (msg->data != NULL) {
free (msg->data);
msg->data = NULL;
}
}
void pubsub_message_print (const struct pubsub_msg *pm)
{
if (pm == NULL) {
handle_err ("pubsub_message_print", "pm == NULL");
return;
}
if (pm->chanlen > 0 && pm->datalen > 0) {
printf ("msg: type: %u, chan: %s (%lu bytes), data: %s (%lu bytes)\n"
, pm->type, pm->chan, pm->chanlen, pm->data, pm->datalen);
} else if (pm->chanlen > 0) {
printf ("msg: type: %u, chan: %s (%lu bytes), and no data\n"
, pm->type, pm->chan, pm->chanlen);
} else if (pm->datalen > 0) {
printf ("msg: type: %u, no chan, data: %s (%lu bytes)\n"
, pm->type, pm->data, pm->datalen);
}
}
int pubsub_message_send (struct ipc_service *srv, const struct pubsub_msg * pm)
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
pubsub_message_to_message (pm, &m);
ipc_application_write (srv, &m);
ipc_message_empty (&m);
return 0;
}
char * pubsub_action_to_str (enum subscriber_action action)
{
switch (action) {
case PUBSUB_PUB : return strdup (PUBSUB_SUBSCRIBER_ACTION_STR_PUB);
case PUBSUB_SUB : return strdup (PUBSUB_SUBSCRIBER_ACTION_STR_SUB);
default : return strdup ("undocumented action");
}
return NULL;
}

View File

@ -1,41 +0,0 @@
#ifndef __PUBSUB_MSG_H__
#define __PUBSUB_MSG_H__
#include "../../core/ipc.h"
#define PUBSUB_SUBSCRIBER_ACTION_STR_PUB "pub"
#define PUBSUB_SUBSCRIBER_ACTION_STR_SUB "sub"
enum subscriber_action {PUBSUB_PUB, PUBSUB_SUB};
#define PUBSUB_TYPE_MESSAGE 1
#define PUBSUB_TYPE_ERROR 2
#define PUBSUB_TYPE_DEBUG 4
#define PUBSUB_TYPE_INFO 5
enum pubsub_message_types {
PUBSUB_MSG_TYPE_SUB
, PUBSUB_MSG_TYPE_UNSUB
, PUBSUB_MSG_TYPE_PUB
};
struct pubsub_msg {
enum pubsub_message_types type; // message type : alert, notification, …
char *chan;
size_t chanlen;
char *data;
size_t datalen;
};
void pubsub_message_from_message (struct pubsub_msg *msg, struct ipc_message *m);
void pubsub_message_to_message (const struct pubsub_msg *msg, struct ipc_message *m);
void pubsub_message_set_chan (struct pubsub_msg *pm, char *chan, size_t len);
void pubsub_message_set_data (struct pubsub_msg *pm, char *data, size_t len);
void pubsub_message_empty (struct pubsub_msg *msg);
void pubsub_message_print (const struct pubsub_msg *msg);
int pubsub_message_send (struct ipc_service *srv, const struct pubsub_msg * m);
#endif

View File

@ -1,168 +0,0 @@
#if 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../core/error.h"
#include <pthread.h>
// WORKERS: one thread per client
void pubsubd_workers_init (struct workers *wrkrs) { LIST_INIT(wrkrs); }
struct worker * pubsubd_workers_add (struct workers *wrkrs, const struct worker *w)
{
if (wrkrs == NULL || w == NULL) {
printf ("pubsubd_workers_add: wrkrs == NULL or w == NULL");
return NULL;
}
struct worker *n = malloc (sizeof (struct worker));
memset (n, 0, sizeof (struct worker));
memcpy (n, w, sizeof (struct worker));
if (w->ale != NULL)
n->ale = pubsubd_subscriber_copy (w->ale);
LIST_INSERT_HEAD(wrkrs, n, entries);
return n;
}
void pubsubd_worker_del (struct workers *wrkrs, struct worker *w)
{
struct worker *todel = pubsubd_worker_get (wrkrs, w);
if(todel != NULL) {
LIST_REMOVE(todel, entries);
pubsubd_worker_free (todel);
free (todel);
todel = NULL;
}
}
// kill the threads
void pubsubd_workers_stop (struct workers *wrkrs)
{
if (!wrkrs)
return;
struct worker *w = NULL;
struct worker *wtmp = NULL;
LIST_FOREACH_SAFE(w, wrkrs, entries, wtmp) {
if (w->thr == NULL)
continue;
pthread_cancel (*w->thr);
void *ret = NULL;
pthread_join (*w->thr, &ret);
if (ret != NULL) {
free (ret);
}
free (w->thr);
w->thr = NULL;
}
}
void pubsubd_workers_del_all (struct workers *wrkrs)
{
if (!wrkrs)
return;
struct worker *w = NULL;
while (!LIST_EMPTY(wrkrs)) {
printf ("KILL THE WORKERS : %p\n", w);
w = LIST_FIRST(wrkrs);
LIST_REMOVE(w, entries);
pubsubd_worker_free (w);
free (w);
w = NULL;
}
}
void pubsubd_worker_free (struct worker * w)
{
if (w == NULL)
return;
pubsubd_subscriber_free (w->ale);
free (w->ale);
w->ale = NULL;
}
struct worker * pubsubd_worker_get (struct workers *wrkrs, struct worker *w)
{
struct worker * np = NULL;
LIST_FOREACH(np, wrkrs, entries) {
if (pubsubd_worker_eq (np, w))
return np;
}
return NULL;
}
int pubsubd_worker_eq (const struct worker *w1, const struct worker *w2)
{
return w1 == w2; // if it's the same pointer
}
// a thread for each connected client
void * pubsubd_worker_thread (void *params)
{
int s = 0;
s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0)
printf ("pthread_setcancelstate: %d\n", s);
struct worker *w = (struct worker *) params;
if (w == NULL) {
fprintf (stderr, "error pubsubd_worker_thread : params NULL\n");
return NULL;
}
struct channels *chans = w->chans;
struct channel *chan = w->chan;
struct subscriber *ale = w->ale;
// main loop
while (1) {
struct pubsub_msg m;
memset (&m, 0, sizeof (struct pubsub_msg));
pubsub_message_recv (ale->p, &m);
if (m.type == PUBSUB_TYPE_DISCONNECT) {
// printf ("client %d disconnecting...\n", ale->p->pid);
if ( 0 != pubsubd_subscriber_del (chan->alh, ale)) {
fprintf (stderr, "err : subscriber not registered\n");
}
break;
}
else {
struct channel *ch = pubsubd_channel_search (chans, chan->chan);
if (ch == NULL) {
printf ("CHAN NOT FOUND\n");
}
else {
printf ("what should be sent: ");
pubsub_message_print (&m);
printf ("send the message to:\t");
pubsubd_channel_print (ch);
pubsub_message_send (ch->alh, &m);
}
}
pubsub_message_free (&m);
}
pubsubd_subscriber_free (ale);
free (w->ale);
w->ale = NULL;
free (w->thr);
w->thr = NULL;
pubsubd_worker_del (w->my_workers, w);
pthread_exit (NULL);
}
#endif

View File

@ -1,32 +0,0 @@
#if 0
#ifndef __WORKERS_H__
#define __WORKERS_H__
// WORKERS: one thread per client
// head of the list
LIST_HEAD(workers, worker);
// element of the list
// worker : client to handle (threaded)
struct worker {
pthread_t *thr;
struct workers *my_workers;
struct channels *chans;
struct channel *chan;
struct subscriber *ale;
LIST_ENTRY(worker) entries;
};
void pubsubd_worker_free (struct worker * w);
struct worker * pubsubd_worker_get (struct workers *wrkrs, struct worker *w);
int pubsubd_worker_eq (const struct worker *w1, const struct worker *w2);
void pubsubd_workers_init (struct workers *wrkrs);
void * pubsubd_worker_thread (void *params);
struct worker * pubsubd_workers_add (struct workers *wrkrs, const struct worker *w);
void pubsubd_workers_del_all (struct workers *wrkrs);
void pubsubd_workers_stop (struct workers *wrkrs);
void pubsubd_worker_del (struct workers *wrkrs, struct worker *w);
#endif
#endif

View File

@ -1,25 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c ../../core/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin

View File

@ -1,152 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../lib/channels.h"
#include "../../core/error.h"
void fake_client (struct ipc_client *p
, unsigned int index, unsigned int version, int fake_fd)
{
p->version = version;
p->index = index;
p->proc_fd = fake_fd;
}
void phase1 ()
{
struct channel chan1;
memset (&chan1, 0, sizeof (struct channel));
pubsubd_channel_new (&chan1, "chan1");
struct channel chan2;
memset (&chan2, 0, sizeof (struct channel));
pubsubd_channel_new (&chan2, "chan2");
printf ("chan1:");
pubsubd_channel_print (&chan1);
printf ("chan2:");
pubsubd_channel_print (&chan2);
pubsubd_channel_free (&chan1);
pubsubd_channel_free (&chan2);
}
void phase2 ()
{
struct channel chan1;
memset (&chan1, 0, sizeof (struct channel));
pubsubd_channel_new (&chan1, "chan1");
struct channel chan2;
memset (&chan2, 0, sizeof (struct channel));
pubsubd_channel_new (&chan2, "chan1");
printf ("chan1:");
pubsubd_channel_print (&chan1);
printf ("chan2:");
pubsubd_channel_print (&chan2);
if (pubsubd_channel_eq (&chan1, &chan2)) {
printf ("chan1 == chan2\n");
}
else {
handle_err ("phase2", "pubsubd_channel_eq (&chan1, &chan2) == 0");
}
pubsubd_channel_free (&chan1);
pubsubd_channel_free (&chan2);
}
void phase3 ()
{
struct channels chans;
memset (&chans, 0, sizeof (struct channels));
pubsubd_channels_init (&chans);
struct channel * chan1 = pubsubd_channels_add (&chans, "chan1");
struct channel * chan2 = pubsubd_channels_add (&chans, "chan2");
pubsubd_channels_print (&chans);
pubsubd_channels_del (&chans, chan1);
pubsubd_channels_print (&chans);
pubsubd_channels_del (&chans, chan2);
pubsubd_channels_print (&chans);
}
void phase4 ()
{
struct channels chans;
memset (&chans, 0, sizeof (struct channels));
pubsubd_channels_init (&chans);
struct channel * chan1 = pubsubd_channels_add (&chans, "chan1");
struct channel * chan2 = pubsubd_channels_add (&chans, "chan2");
struct ipc_client proc1;
fake_client (&proc1, 0, 0, 1);
struct ipc_client proc2;
fake_client (&proc2, 0, 0, 2);
printf ("chan1: proc1, chan2: proc2\n");
pubsubd_channel_subscribe (chan1, &proc1);
pubsubd_channel_subscribe (chan2, &proc2);
pubsubd_channels_print (&chans);
pubsubd_channels_del_all (&chans);
printf ("channels removed\n");
pubsubd_channels_print (&chans);
}
void phase5 ()
{
struct channels chans;
memset (&chans, 0, sizeof (struct channels));
pubsubd_channels_init (&chans);
pubsubd_channels_add (&chans, "chan1");
pubsubd_channels_add (&chans, "chan2");
struct ipc_client proc1;
fake_client (&proc1, 0, 0, 1);
struct ipc_client proc2;
fake_client (&proc2, 0, 0, 2);
printf ("chan1 & 2 => proc1 and 2 added\n");
pubsubd_channels_subscribe (&chans, "chan1", &proc1);
pubsubd_channels_subscribe (&chans, "chan1", &proc2);
pubsubd_channels_subscribe (&chans, "chan2", &proc1);
pubsubd_channels_subscribe (&chans, "chan2", &proc2);
pubsubd_channels_print (&chans);
printf ("chan1 => proc1 removed\n");
pubsubd_channels_unsubscribe (&chans, "chan1", &proc1);
pubsubd_channels_print (&chans);
pubsubd_channels_del_all (&chans);
printf ("channels removed\n");
pubsubd_channels_print (&chans);
}
int main(int argc, char * argv[])
{
argc = argc;
argv = argv;
// phase1(); // new + print + free
// phase2(); // new + print + eq + free
// channels
// phase3(); // channels init + add + print + del
// phase4(); // channels del_all + channel subscribe
phase5(); // channels del_all + channels subscribe + unsubscribe
return EXIT_SUCCESS;
}

View File

@ -1,56 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../lib/message.h"
#include "../../core/error.h"
#include "../../core/utils.h"
#define CHAN "chan1"
#define DATA "hello chan1"
int main(int argc, char * argv[])
{
argc = argc;
argv = argv;
struct pubsub_msg msg;
memset (&msg, 0, sizeof (struct pubsub_msg));
msg.type = 8;
msg.chanlen = strlen (CHAN) + 1;
msg.chan = malloc (msg.chanlen);
memset (msg.chan, 0, msg.chanlen);
memcpy (msg.chan, CHAN, msg.chanlen);
msg.datalen = strlen (DATA) + 1;
msg.data = malloc (msg.datalen);
memset (msg.data, 0, msg.datalen);
memcpy (msg.data, DATA, msg.datalen);
printf ("msg 1: ");
pubsub_message_print (&msg);
char *buffer = NULL;
size_t len = 0;
pubsub_message_serialize (&msg, &buffer, &len);
mprint_hexa ("buffer msg 1", (unsigned char *) buffer, len);
struct pubsub_msg msg2;
memset (&msg2, 0, sizeof (struct pubsub_msg));
pubsub_message_unserialize (&msg2, buffer, len);
printf ("msg 2: ");
pubsub_message_print (&msg2);
pubsub_message_free (&msg);
pubsub_message_free (&msg2);
if (buffer != NULL)
free (buffer);
return EXIT_SUCCESS;
}

View File

@ -1,131 +0,0 @@
int main() { return 0; }
#if 0
#include "../lib/pubsubd.h"
#include <stdlib.h>
#include <pthread.h>
#define MYMESSAGE "coucou"
void
ohshit(int rvalue, const char* str) {
fprintf (stderr, "\033[31merr: %s\033[00m\n", str);
exit (rvalue);
}
void usage (char **argv)
{
printf ( "usage : %s pid index (pub|sub|both|quit) [chan]\n", argv[0]);
}
void sim_connection (int argc, char **argv, char **env, pid_t pid, int index, int version, char *cmd, char *chan)
{
printf ("Simulate connection : pid %d index %d version %d "
"cmd %s chan %s\n"
, pid, index, version, cmd, chan );
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
ipc_server_init (argc, argv, env, &srv, PUBSUB_SERVICE_NAME, NULL);
printf ("Writing on %s.\n", srv.spath);
struct ipc_client p;
memset (&p, 0, sizeof (struct ipc_client));
printf ("app creation\n");
if (application_create (&p, pid, index, version)) // called by the application
ohshit (1, "application_create");
printf ("connection\n");
// send a message to warn the service we want to do something
// line : pid index version action chan
pubsub_connection (&srv, &p, PUBSUB_PUB, chan);
struct pubsub_msg m;
memset (&m, 0, sizeof (struct pubsub_msg));
if (strcmp (cmd, "pub") == 0) {
// first message, "coucou"
m.type = PUBSUB_TYPE_MESSAGE;
m.chan = malloc (strlen (chan) + 1);
memset (m.chan, 0, strlen (chan) + 1);
m.chan[strlen (chan)] = '\0';
m.chanlen = strlen (chan);
m.data = malloc (strlen (MYMESSAGE) + 1);
memset (m.data, 0, strlen (MYMESSAGE) + 1);
strncpy ((char *) m.data, MYMESSAGE, strlen (MYMESSAGE) + 1);
m.datalen = strlen (MYMESSAGE);
printf ("send message\n");
pubsub_message_send (&p, &m);
}
else {
pubsub_message_recv (&p, &m);
pubsubd_message_print (&m);
}
// free everything
pubsubd_message_free (&m);
printf ("disconnection\n");
// disconnect from the server
pubsub_disconnect (&p);
printf ("destroying app\n");
// the application will shut down, and remove the application named pipes
if (application_destroy (&p))
ohshit (1, "application_destroy");
}
void sim_disconnection (int argc, char **argv, char **env, pid_t pid, int index, int version)
{
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
ipc_server_init (argc, argv, env, &srv, PUBSUB_SERVICE_NAME, NULL);
printf ("Disconnecting from %s.\n", srv.spath);
struct ipc_client p;
memset (&p, 0, sizeof (struct ipc_client));
// create the fake client
ipc_server_client_gen (&p, pid, index, version);
// send a message to disconnect
// line : pid index version action chan
pubsub_disconnect (&p);
}
int
main(int argc, char **argv, char **env)
{
if (argc < 3) {
usage (argv);
exit (1);
}
pid_t pid = 0;
pid = atol(argv[1]);
int index = 0;
index = atoi (argv[2]);
// don't care about the version
int version = COMMUNICATION_VERSION;
char * cmd = NULL;
cmd = argv[3];
if (strcmp(cmd, "quit") != 0) {
char *chan = NULL;
chan = argv[4];
sim_connection (argc, argv, env, pid, index, version, cmd, chan);
}
else {
sim_disconnection (argc, argv, env, pid, index, version);
}
return EXIT_SUCCESS;
}
#endif

View File

@ -1,63 +0,0 @@
int main() { return 0; }
#if 0
#include "../lib/pubsubd.h"
#include <stdlib.h>
#include <pthread.h>
#define MYMESSAGE "coucou"
#define MYCHAN "chan1"
void
ohshit(int rvalue, const char* str) {
fprintf (stderr, "\033[31merr: %s\033[00m\n", str);
exit (rvalue);
}
int
main(int argc, char **argv, char **env)
{
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
ipc_server_init (argc, argv, env, &srv, PUBSUB_SERVICE_NAME, NULL);
printf ("Writing on %s.\n", srv.spath);
struct ipc_client p;
memset (&p, 0, sizeof (struct ipc_client));
int index = 1;
pid_t pid = getpid();
if (application_create (&p, pid, index, COMMUNICATION_VERSION))
ohshit (1, "application_create");
// send a message to warn the service we want to do something
// line : pid index version action chan
pubsub_connection (&srv, &p, PUBSUB_PUB, MYCHAN);
struct pubsub_msg m;
memset (&m, 0, sizeof (struct pubsub_msg));
// first message, "coucou"
m.type = PUBSUB_TYPE_INFO;
m.chan = malloc (strlen (MYCHAN));
m.chanlen = strlen (MYCHAN);
m.data = malloc (strlen (MYMESSAGE));
m.datalen = strlen (MYMESSAGE);
pubsub_message_send (&p, &m);
// second message, to disconnect from the server
m.type = PUBSUB_TYPE_DISCONNECT;
pubsub_message_send (&p, &m);
// free everything
pubsubd_message_free (&m);
// the application will shut down, and remove the application named pipes
if (application_destroy (&p))
ohshit (1, "application_destroy");
return EXIT_SUCCESS;
}
#endif

View File

@ -1,25 +0,0 @@
CC=gcc
CFLAGS=-Wall -g -Wextra
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../lib/*.c ../../core/*.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin

View File

@ -1,25 +0,0 @@
# remoted
This service creates a path on the relevent remote location, going through anything network-related: TCP, UDP, HTTP, ...
# TODO
* authorizations
* code the -d option
### authorizations
The idea is to have a simple configuration file for authentication of remote connections, such as:
table dynusers # dynamic user table
clients = { "client123", alice.example.com, john@doe.com }
localclients = { pamuser1, <dynusers> }
level1services = { pongd, weather }
ifext = enp0s25
pass in on $ifext from any for all to local services $level1services
pass out on $ifext from local for $localclients to any services $level1services
block all

View File

@ -1,121 +0,0 @@
#include "../../core/communication.h"
#include "../../core/error.h"
#include "../lib/remoted.h"
#include "../lib/remotec.h"
#include "../lib/message.h"
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
/**
* remoted test application
*
* this application can:
* listen, given an URI (including a transport layer and eventually a port)
* connect to a remote service through a tunnel
* the remote service used for testing is pongd
*
* TODO: this test application is a work in progress
* currently, this application will:
* connect itself to the remoted service
* hang up the connection with the remoted service
*/
void usage (char **argv) {
printf ( "usage: %s uri service\n", argv[0]);
}
#if 0
void * listener (void *params)
{
int s = 0;
s = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0) {
handle_err ("listener", "pthread_setcancelstate != 0");
}
struct ipc_service *srv = NULL;
srv = (struct ipc_service *) params;
if (srv == NULL) {
handle_err ("listener", "no service passed");
return NULL;
}
// main loop
while (1) {
struct remoted_msg m;
memset (&m, 0, sizeof (struct remoted_msg));
remote_message_recv (srv, &m);
printf ("\r\033[31m>\033[00m %s\n", m.data);
print_cmd ();
remote_message_free (&m);
}
pthread_exit (NULL);
}
#endif
void main_loop (int argc, char **argv, char **env
, int index, int version, char *uri, char *service)
{
printf ("connection to remoted: index %d version %d uri %s service %s\n"
, index, version, uri, service);
(void) argc;
(void) argv;
(void) env;
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
remotec_connection (argc, argv, env, &srv);
log_debug ("remotec connected, entering main loop");
struct remoted_msg msg;
memset (&msg, 0, sizeof (struct remoted_msg));
#if 0
// msg loop
for (;;) {
char buf[BUFSIZ];
memset (buf, 0, BUFSIZ);
/* TODO */
msg.datalen = 5; // FIXME: take parameters into account
msg.data = malloc (msg.datalen);
memset (msg.data, 0, msg.datalen);
strncpy ((char *) msg.data, "salut", msg.datalen);
/* TODO */
remotec_message_send (&srv, &msg);
free (msg.data);
msg.data = NULL;
msg.datalen = 0;
}
// free everything
remote_message_free (&msg);
#endif
log_debug ("remotec disconnection...");
// disconnect from the server
remotec_disconnection (&srv);
}
int main(int argc, char **argv, char **env)
{
if (argc != 3) {
usage (argv);
exit (0);
}
int index = 0;
int version = 0;
main_loop (argc, argv, env, index, version, argv[1], argv[2]);
return EXIT_SUCCESS;
}

View File

@ -1,117 +0,0 @@
#include "../../core/communication.h"
#include "../../core/client.h"
#include "../../core/error.h"
#include "../lib/remoted.h"
#include <stdlib.h>
#include "../../core/logger.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
// to quit them properly if a signal occurs
struct ipc_service srv;
void handle_signal (int signalnumber)
{
// the application will shut down, and remove the service unix socket
if (ipc_server_close (&srv) < 0) {
handle_error("ipc_server_close < 0");
}
log_info ("remoted received a signal %d\n", signalnumber);
exit (EXIT_SUCCESS);
}
void usage ()
{
fprintf (stderr, "remoted [-d <unix-socket-dir>] [-h]\n");
}
/* TODO: handle command line arguments */
// cmdline: remoted -d <unix-socket-dir>
void remoted_cmd_args (int argc, char **argv, char **env
, struct remoted_ctx *ctx)
{
(void) env;
(void) ctx;
int c;
while ( (c = getopt(argc, argv, "hd:")) != -1) {
switch (c) {
case 'd':
ctx->unix_socket_dir = malloc (strlen (optarg) +1);
strncpy (ctx->unix_socket_dir, optarg, strlen (optarg));
log_debug ("remoted unix socket dir: %s", ctx->unix_socket_dir);
break;
case '?':
case 'h':
usage ();
exit (EXIT_FAILURE);
default:
log_debug ("remoted getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
log_debug ("remoted non-option ARGV-elements:");
while (optind < argc)
log_debug ("\t%s", argv[optind++]);
}
}
/* TODO: handle authorizations */
int remoted_auth_conf (struct remoted_ctx *ctx)
{
(void) ctx;
return 0;
}
int main(int argc, char **argv, char **env)
{
struct remoted_ctx ctx;
memset (&ctx, 0, sizeof (struct remoted_ctx));
memset (&srv, 0, sizeof (struct ipc_service));
srv.index = 0;
srv.version = 0;
signal(SIGHUP, handle_signal);
signal(SIGINT, handle_signal);
signal(SIGQUIT, handle_signal);
remoted_cmd_args (argc, argv, env, &ctx);
log_info ("remoted started");
// load configuration
if (remoted_auth_conf (&ctx)) {
log_error ("remoted cannot load configuration");
}
else
log_info ("remoted configuration loaded");
if (ipc_server_init (argc, argv, env, &srv, REMOTED_SERVICE_NAME) < 0) {
handle_error("server_init < 0");
}
log_info ("remoted listening on %s", srv.spath);
// TODO: here comes pledge (openbsd)
// the service will loop until the end of time, a specific message, a signal
remoted_main_loop (&srv, &ctx);
// the application will shut down, and remove the service unix socket
if (ipc_server_close (&srv) < 0) {
handle_error("server_close < 0");
}
log_info ("remoted ended");
remoted_free_ctx (&ctx);
return EXIT_SUCCESS;
}

View File

@ -1,109 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "message.h"
#include "../../core/error.h"
void remote_message_serialize (const struct remoted_msg *msg, char **data, size_t *len)
{
if (msg == NULL) {
handle_err ("remote remote_message_serialize", "msg == NULL");
return;
}
if (data == NULL) {
handle_err ("remote remote_message_serialize", "data == NULL");
return;
}
if (*data != NULL) {
handle_err ("remote remote_message_serialize", "*data != NULL");
return;
}
if (len == NULL) {
handle_err ("remote remote_message_serialize", "len == NULL");
return;
}
// buflen = remote msg type (1) + size_t (16) + data
size_t buflen = 1 + sizeof (size_t) + msg->datalen;
if (buflen > BUFSIZ) {
handle_err ("remote remote_message_serialize", "datalen too high");
return;
}
char *buf = malloc (buflen);
memset (buf, 0, buflen);
size_t offset = 0;
// msg type
buf[offset++] = msg->type;
// data
memcpy (buf + offset, &msg->datalen, sizeof (size_t));
offset += sizeof (size_t);
memcpy (buf + offset, msg->data, msg->datalen);
offset += msg->datalen;
*data = buf;
*len = buflen;
}
void remote_message_unserialize (struct remoted_msg *msg, const char *buf, size_t mlen)
{
if (msg == NULL) {
handle_err ("remote remote_message_unserialize", "msg == NULL");
return;
}
remote_message_free (msg);
if (mlen > BUFSIZ) {
handle_err ("remote remote_message_unserialize", "mlen > BUFSIZ");
return;
}
size_t offset = 0;
// msg type
msg->type = buf[offset++];
// data
memcpy (&msg->datalen, buf + offset, sizeof (size_t));
if (msg->datalen > BUFSIZ) {
handle_err ("remote remote_message_unserialize", "datalen > BUFSIZ");
return;
}
msg->data = malloc (msg->datalen);
memset (msg->data, 0, msg->datalen);
offset += sizeof (size_t);
memcpy (msg->data, buf + offset, msg->datalen);
offset += msg->datalen;
}
void remote_message_free (struct remoted_msg *msg)
{
if (msg == NULL) {
handle_err ("remote remote_message_free", "msg == NULL");
return;
}
if (msg->data) {
free (msg->data);
msg->data = NULL;
}
}
void remote_message_print (const struct remoted_msg *msg)
{
if (msg == NULL) {
handle_err ("remote remote_message_print", "msg == NULL");
return;
}
printf ("msg: type=%d data=%s\n", msg->type, msg->data);
}

View File

@ -1,20 +0,0 @@
#ifndef __REMOTE_MSG_H__
#define __REMOTE_MSG_H__
#define REMOTE_MSG_TYPE_CONNECT 1
#define REMOTE_MSG_TYPE_LISTEN 2
#define REMOTE_MSG_TYPE_PUB 3
struct remoted_msg {
unsigned char type; // message types = commands (connect, listen, ...)
char *data;
size_t datalen;
};
void remote_message_serialize (const struct remoted_msg *msg, char **data, size_t *len);
void remote_message_unserialize (struct remoted_msg *msg, const char *data, size_t len);
void remote_message_free (struct remoted_msg *msg);
void remote_message_print (const struct remoted_msg *msg);
#endif

View File

@ -1,74 +0,0 @@
#include "../../core/communication.h"
#include "../../core/error.h"
#include "message.h"
#include "remotec.h"
#include "remoted.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int remotec_connection (int argc, char **argv, char **env, struct ipc_service *srv)
{
int ret = ipc_application_connection (argc, argv, env
, srv, REMOTED_SERVICE_NAME, NULL, 0);
if (ret != 0) {
handle_err ("remote remotec_connection", "application_connection != 0");
}
return ret;
}
int remotec_disconnection (struct ipc_service *srv)
{
return ipc_application_close (srv);
}
int remotec_message_send (struct ipc_service *srv, const struct remoted_msg * m)
{
size_t msize = 0;
char * buf = NULL;
remote_message_serialize (m, &buf, &msize);
struct ipc_message m_data;
memset (&m_data, 0, sizeof (struct ipc_message));
// format the connection msg
if (ipc_message_format_data (&m_data, buf, msize) < 0) {
handle_err ("remotec_message_send", "ipc_message_format_data");
if (buf != NULL)
free (buf);
return -1;
}
ipc_application_write (srv, &m_data);
ipc_message_free (&m_data);
if (buf != NULL)
free(buf);
return 0;
}
int remotec_message_recv (struct ipc_service *srv, struct remoted_msg *m)
{
if (srv == NULL) {
handle_err ("remotec_message_recv", "srv == NULL");
return -1;
}
if (m == NULL) {
handle_err ("remotec_message_recv", "m == NULL");
return -1;
}
struct ipc_message m_recv;
memset (&m_recv, 0, sizeof (struct ipc_message));
ipc_application_read (srv, &m_recv);
remote_message_unserialize (m, m_recv.payload, m_recv.length);
ipc_message_free (&m_recv);
return 0;
}

View File

@ -1,16 +0,0 @@
#ifndef __REMOTEC_H__
#define __REMOTEC_H__
#include "../../core/client.h"
#include "../../core/message.h"
#include "remoted.h"
/* TODO */
int remotec_connection (int argc, char **argv, char **env, struct ipc_service *srv);
int remotec_disconnection (struct ipc_service *srv);
int remotec_message_send (struct ipc_service *srv, const struct remoted_msg *msg);
int remotec_message_recv (struct ipc_service *srv, struct remoted_msg *msg);
#endif

View File

@ -1,149 +0,0 @@
#include "../../core/communication.h"
#include "../../core/message.h"
#include "../../core/client.h"
#include "../../core/utils.h"
#include "../../core/error.h"
#include "../../core/logger.h"
#include "remoted.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
/**
* new connection, once accepted the client is added to the array_proc
* structure to be checked periodically for new messages
*/
void handle_new_connection (struct ipc_service *srv, struct ipc_clients *ap)
{
struct ipc_client *p = malloc(sizeof(struct ipc_client));
memset(p, 0, sizeof(struct ipc_client));
if (ipc_server_accept (srv, p) < 0) {
handle_error("ipc_server_accept < 0");
} else {
log_debug ("remoted, new connection", p->proc_fd);
}
if (ipc_client_add (ap, p) < 0) {
handle_error("ipc_client_add < 0");
}
}
void handle_new_msg (struct ipc_clients *ap, struct ipc_clients *proc_to_read)
{
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
int i;
for (i = 0; i < proc_to_read->size; i++) {
if (ipc_server_read (proc_to_read->clients[i], &m) < 0) {
handle_error("ipc_server_read < 0");
}
mprint_hexa ("msg received: ", (unsigned char *) m.payload, m.length);
// close the client then delete it from the client array
if (m.type == MSG_TYPE_CLOSE) {
struct ipc_client *p = proc_to_read->clients[i];
log_debug ("remoted, client %d disconnecting", p->proc_fd);
// close the connection to the client
if (ipc_server_close_client (p) < 0)
handle_error( "ipc_server_close_client < 0");
// remove the client from the clientes list
if (ipc_client_del (ap, p) < 0)
handle_error( "ipc_client_del < 0");
if (ipc_client_del (proc_to_read, p) < 0)
handle_err( "handle_new_msg", "ipc_client_del < 0");
ipc_message_free (&m);
// free client
free (p);
i--;
continue;
}
#if 0
struct pubsub_msg m_data;
memset (&m_data, 0, sizeof (struct pubsub_msg));
pubsub_message_unserialize (&m_data, m.payload, m.length);
if (m_data.type == PUBSUB_MSG_TYPE_SUB) {
printf ("client %d subscribing to %s\n"
, proc_to_read->clients[i]->proc_fd
, m_data.chan);
pubsubd_channels_subscribe (chans
, m_data.chan, proc_to_read->clients[i]);
}
if (m_data.type == PUBSUB_MSG_TYPE_UNSUB) {
printf ("client %d unsubscribing to %s\n"
, proc_to_read->clients[i]->proc_fd
, m_data.chan);
pubsubd_channels_unsubscribe (chans
, m_data.chan, proc_to_read->clients[i]);
}
if (m_data.type == PUBSUB_MSG_TYPE_PUB) {
printf ("client %d publishing to %s\n"
, proc_to_read->clients[i]->proc_fd
, m_data.chan);
struct channel *chan = pubsubd_channel_search (chans, m_data.chan);
if (chan == NULL) {
handle_err ("handle_new_msg", "publish on nonexistent channel");
ipc_message_free (&m);
return ;
}
pubsubd_send (chan->subs, &m_data);
}
pubsub_message_free (&m_data);
#endif
ipc_message_free (&m);
}
}
void remoted_main_loop (struct ipc_service *srv, struct remoted_ctx *ctx)
{
log_debug ("remoted entering main loop");
int i, ret = 0;
struct ipc_clients ap;
memset(&ap, 0, sizeof(struct ipc_clients));
struct ipc_clients proc_to_read;
memset(&proc_to_read, 0, sizeof(struct ipc_clients));
while(1) {
/* TODO: authorizations */
ret = ipc_server_select (&ap, srv, &proc_to_read);
if (ret == CONNECTION) {
handle_new_connection (srv, &ap);
} else if (ret == APPLICATION) {
handle_new_msg (&ap, &proc_to_read);
} else { // both new connection and new msg from at least one client
handle_new_connection (srv, &ap);
handle_new_msg (&ap, &proc_to_read);
}
ipc_clients_free (&proc_to_read);
}
for (i = 0; i < ap.size; i++) {
if (ipc_server_close_client (ap.clients[i]) < 0) {
handle_error( "ipc_server_close_client < 0");
}
}
}
void remoted_free_ctx (struct remoted_ctx *ctx)
{
if (ctx->unix_socket_dir != NULL)
free (ctx->unix_socket_dir), ctx->unix_socket_dir = NULL;
}

View File

@ -1,18 +0,0 @@
#ifndef __REMOTED_H__
#define __REMOTED_H__
#include "../../core/client.h"
#include "../../core/message.h"
#include "message.h"
#define REMOTED_SERVICE_NAME "remoted"
struct remoted_ctx {
char * unix_socket_dir;
/* TODO: authorizations */
};
void remoted_main_loop (struct ipc_service *srv, struct remoted_ctx *ctx);
void remoted_free_ctx (struct remoted_ctx *ctx);
#endif

View File

@ -1,29 +0,0 @@
CC=gcc
CFLAGS=-Wall -g
LDFLAGS= -pthread
CFILES=$(wildcard *.c) # CFILES => recompiles everything on a C file change
EXEC=$(basename $(wildcard *.c))
SOURCES=$(wildcard ../../lib/communication.c ../../lib/process.c)
OBJECTS=$(SOURCES:.c=.o)
TESTS=$(addsuffix .test, $(EXEC))
LCBOR=-lbor
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS) $(CFILES)
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJECTS) $@.c -o $@.bin
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(TESTS):
valgrind --show-leak-kinds=all --leak-check=full -v --track-origins=yes ./$(basename $@).bin
clean:
@-rm $(OBJECTS)
mrproper: clean
@-rm *.bin
cleantmp:
rm /tmp/ipc/*

View File

@ -1,799 +0,0 @@
#include "tcpd.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h> // mkfifo
#include <linux/limits.h>
#define PORT 6000
#define NBCLIENT 10
#define SERVICE_TCP "tcpd"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int init_connection(const info_request *req)
{
int yes = 1;
int sock = socket(AF_INET, SOCK_STREAM, 0);
//struct sockaddr_in sin = { 0 };
if(sock == -1)
{
perror("socket()");
exit(errno);
}
/*"address already in use" error message */
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");
if(bind(sock,(struct sockaddr *) &req->addr, sizeof(req->addr)) == -1)
{
perror("bind()");
exit(errno);
}
if(listen(sock, 10) == -1)
{
perror("listen()");
exit(errno);
}
return sock;
}
void write_message(int sock, const char *buffer, size_t size_buf)
{
if(send(sock, buffer, size_buf, 0) < 0)
{
perror("send()");
exit(errno);
}
}
int read_message(int sock, char *buffer)
{
return read(sock, buffer, BUFSIZ);
}
void endConnection(int sock) {
close(sock);
}
void printAddr(struct sockaddr_in *csin) {
printf("IP Addr : %s\n", inet_ntoa(csin->sin_addr));
printf("Port : %u\n", ntohs(csin->sin_port));
}
/*
* Chaque client correspond à un thread service
* Le 1er message du client indiquera le service voulu et sa version
* Etablir la connection avec le service
* Ecouter ensuite sur la socket client et socket unix pour traiter les messages
*/
void * service_thread(void * c_data) {
client_data *cda = (client_data*) c_data;
char *service;
int version;
int clientSock = cda->sfd;
int nbMessages = 0;
//buffer for message
size_t nbytes = 0;
char *buffer = malloc (BUFSIZ);
if (buffer == NULL) {
perror("malloc()");
return NULL;
}
memset(buffer, 0, BUFSIZ);
if (read_message(clientSock, buffer) == -1) {
perror("read_message()");
return NULL;
}else {
parseServiceVersion(buffer, &service, &version);
}
/* TODO : service correspond au service que le client veut utiliser
** il faut comparer service à un tableau qui contient les services
** disponibles
*/
//pid index version
char * piv = malloc(PATH_MAX);
memset(piv , 0, PATH_MAX);
if (piv == NULL) {
perror("malloc()");
}
makePivMessage(&piv, getpid(), cda->index, version);
struct ipc_service srv;
memset (&srv, 0, sizeof (struct ipc_service));
srv->index = 0;
srv->version = 0;
ipc_server_init (0, NULL, NULL, &srv, service, NULL);
if (application_server_connection(&srv, piv, strlen(piv)) == -1) {
handle_error("application_server_connection\n");
}
free(piv);
/*struct ipc_client p;
ipc_application_create(&p, getpid(), cda->index, version);
ipc_server_client_print(&p);*/
//sleep(1);
//printf("%s\n",p.path_proc );
/*if (proc_connection(&p) == -1){
handle_error("proc_connection");
}*/
//utilisation du select() pour surveiller la socket du client et fichier in
fd_set rdfs;
int max = clientSock > srv.service_fd ? clientSock : srv.service_fd;
printf("Waitting for new messages...\n" );
while(1) {
FD_ZERO(&rdfs);
//add client's socket
FD_SET(clientSock, &rdfs);
//add in file
FD_SET(srv.service_fd, &rdfs);
if(select(max + 1, &rdfs, NULL, NULL, NULL) == -1)
{
perror("select()");
exit(errno);
}
if (FD_ISSET(srv.service_fd, &rdfs)){
nbytes = file_read(srv.service_fd, &buffer);
if(nbytes < 0) {
perror("application_read()");
}
printf("message from file : %s\n", buffer );
write_message(clientSock, buffer, nbytes);
nbMessages--;
} else if (FD_ISSET(clientSock, &rdfs)) {
nbytes = read_message(clientSock, buffer);
if(nbytes > 0 && strncmp(buffer, "exit", 4) != 0) {
printf("Server : message (%ld bytes) : %s\n", nbytes, buffer);
if(file_write(srv.service_fd, buffer, nbytes) < 0) {
perror("file_write");
}
nbMessages++;
}
if (strncmp(buffer, "exit", 4) == 0 && nbMessages == 0){
//message end to server
if(file_write(srv.service_fd, "exit", 4) < 0) {
perror("file_write");
}
printf("------thread %d shutdown----------\n\n", cda->index );
break;
}
}
}
//close the files descriptors
close(srv.service_fd);
close(clientSock);
free(buffer);
//release the resources
pthread_detach(pthread_self());
return NULL;
}
void parseServiceVersion(char * buf, char ** service, int *version) {
char *token = NULL, *saveptr = NULL;
char *str = NULL;
int i = 0;
for (str = buf, i = 1; ; str = NULL, i++) {
token = strtok_r(str, " ", &saveptr);
if (token == NULL)
break;
if (i == 1) {
*service = token;
}
else if (i == 2) {
*version = strtoul(token, NULL, 10);
}
}
}
int fifo_create (char * path)
{
int ret;
if ((ret = mkfifo (path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
switch (errno) {
case EACCES :
printf ("file %s : EACCES\n", path);
return 1;
case EEXIST :
printf ("file %s : EEXIST\n", path);
break;
case ENAMETOOLONG :
printf ("file %s : ENAMETOOLONG\n", path);
return 2;
case ENOENT :
printf ("file %s : ENOENT\n", path);
return 3;
case ENOSPC :
printf ("file %s : ENOSPC\n", path);
return 4;
case ENOTDIR :
printf ("file %s : ENOTDIR\n", path);
return 5;
case EROFS :
printf ("file %s : EROFS\n", path);
return 6;
default :
printf ("err file %s unknown\n", path);
return 7;
}
}
return ret;
}
void inOutPathCreate(char ** pathname, int index, int version) {
snprintf(pathname[0] , PATH_MAX, "%s%d-%d-%d-in" , TMPDIR, getpid(), index, version);
snprintf(pathname[1] , PATH_MAX, "%s%d-%d-%d-out", TMPDIR, getpid(), index, version);
}
void makePivMessage (char ** piv, int pid, int index, int version) {
snprintf(*piv , PATH_MAX, "%d %d %d" , getpid(), index, version);
}
/*
* lancer le serveur, ecouter sur une l'adresse et port
* A chaque nouveau client lance un thread service
*/
void * ipc_server_thread(void * reqq) {
info_request *req = (info_request*) reqq;
//client
client_data tab_client[NBCLIENT];
pthread_t tab_service_threads[NBCLIENT];
int actual = 0;
int i;
int sock = init_connection(req);
fd_set rdfs;
printf("Waitting for new clients :\n" );
while(1) {
FD_ZERO(&rdfs);
/* add STDIN_FILENO */
FD_SET(STDIN_FILENO, &rdfs);
//add listener's socket
FD_SET(sock, &rdfs);
if(select(sock + 1, &rdfs, NULL, NULL, NULL) == -1)
{
perror("select()");
exit(errno);
}
/* something from standard input : i.e keyboard */
if(FD_ISSET(STDIN_FILENO, &rdfs))
{
/* stop client when type on keyboard */
for (i = 0; i < actual; i++) {
if (pthread_cancel(tab_service_threads[i]) != 0) {
printf("Aucun thread correspond \n");
}
}
printf("server shutdown\n");
break;
}
else if (FD_ISSET(sock, &rdfs)){
//New client
socklen_t sinsize = sizeof (struct sockaddr_in);
tab_client[actual].sfd = accept(sock, (struct sockaddr *)&tab_client[actual].c_addr, &sinsize);
if(tab_client[actual].sfd == -1)
{
perror("accept()");
close(sock);
exit(errno);
}
printf("New client :\n");
printAddr(&tab_client[actual].c_addr);
tab_client[actual].index = actual;
int ret = pthread_create( &tab_service_threads[actual], NULL, &service_thread, (void *) &tab_client[actual]);
if (ret) {
perror("pthread_create()");
endConnection(sock);
exit(errno);
} else {
printf("\n----------Creation of listen thread %d ------------\n", actual);
}
actual++;
}
}
for (i = 0; i < actual; i++) {
pthread_join(tab_service_threads[i], NULL);
}
printf("--------------server thread shutdown--------------- \n");
endConnection(sock);
return NULL;
}
/*
* user can send 2 types of request to server : listen or connect
* listen = server for a service such as pongd
* connect = connect to a server
*/
int ipc_server_get_new_request(char *buf, info_request *req) {
char *token = NULL, *saveptr = NULL;
char *str = NULL;
int i = 0;
//for a "connect" request
pid_t pid = 0;
int index = 0;
int version = 0;
for (str = buf, i = 1; ; str = NULL, i++) {
token = strtok_r(str, " ", &saveptr);
if (token == NULL)
break;
if (i == 1) {
if(strncmp("exit", token, 4) == 0 ) {
strncpy(req->request, token, 4);
free(str);
return 0;
}
req->request = token;
}
else if (i == 2){
req->addr.sin_addr.s_addr = inet_addr(token);
}
else if (i == 3) {
req->addr.sin_port = htons(strtoul(token, NULL, 10));
}
else if (i == 4 && (strcmp("connect", req->request)) == 0){
pid = strtoul(token, NULL, 10);
}
else if (i == 5 && (strcmp("connect", req->request)) == 0) {
index = strtoul(token, NULL, 10);
}
else if (i == 6 && (strcmp("connect", req->request)) == 0) {
version = strtoul(token, NULL, 10);
}
}
req->addr.sin_family = AF_INET;
if (strcmp("connect", req->request) == 0) {
ipc_server_client_gen (req->p, pid, index, version);
}
return 1;
}
/*
* client thread est lancé suite à une requete "connect"
* connecter à une adresse, port le 1er message indiquera le service et le version voulus
* Se mettre ensuite sur l'écoute de la socket serveur et le fichier client pour traiter les messages
*/
void * client_thread(void *reqq) {
info_request *req = (info_request*) reqq;
/* buffer for client data */
int nbytes;
char *buffer= malloc(BUFSIZ);
if (buffer == NULL)
{
handle_error("malloc");
}
memset(buffer, 0, BUFSIZ);;
int nbMessages = 0;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1)
{
perror("socket()");
exit(errno);
}
if(connect(sock,(struct sockaddr *) &req->addr, sizeof(struct sockaddr)) == -1)
{
perror("connect()");
exit(errno);
}
printf("Connected to server at :\n");
printAddr(&req->addr);
write_message(sock, "pongd 5", strlen("pongd 5"));
/*//init socket unix for server
int sfd;
struct sockaddr_un peer_addr;
socklen_t peer_addr_size;
sfd = set_listen_socket(req->p->path_proc);
if (sfd == -1){
handle_error("set_listen_socket");
}*/
/* master file descriptor list */
fd_set master;
/* temp file descriptor list for select() */
fd_set read_fds;
/* maximum file descriptor number */
int fdmax;
/* listening socket descriptor */
int listener = req->p->proc_fd;
/* newly accept()ed socket descriptor */
//int newfd;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* add the listener to the master set */
FD_SET(listener, &master);
FD_SET(sock, &master);
/* keep track of the biggest file descriptor */
fdmax = sock > listener ? sock : listener;
while(1) {
/* copy it */
read_fds = master;
if(select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select()");
exit(errno);
}
printf("select...OK\n");
// if(FD_ISSET(listener, &read_fds)) {
// /* handle new connections */
// peer_addr_size = sizeof(struct sockaddr_un);
// newfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
// if (newfd == -1) {
// handle_error("accept");
// }
// else
// {
// printf("Server-accept() is OK...\n");
// FD_SET(newfd, &master); /* add to master set */
// if(newfd > fdmax)
// { /* keep track of the maximum */
// fdmax = newfd;
// }
// req->p->proc_fd = newfd;
// }
// }
/*
* TODO:
* Que se passe-t-il si on reçoit un message du serveur avant l'app client?
* Ou ecrit-on le message ??
*/
/*else*/ if (FD_ISSET(sock, &read_fds)) {
int n = read_message(sock, buffer);
if(n > 0) {
printf("Client : message from server(%d bytes) : %s\n", n, buffer);
if(application_write(req->p, buffer, strlen(buffer)) < 0) {
perror("file_write");
}
nbMessages--;
} else if (n == 0){
//message end from server
printf("server down\n");
printf("------thread client shutdown----------\n");
break;
}
}else {
nbytes = ipc_application_read (req->p, &buffer);
printf("Client : message from app %d : %s\n",nbytes, buffer );
if ( nbytes == -1) {
handle_error("file_read");
} else if( nbytes == 0) {
/* close it... */
close(req->p->proc_fd);
/* remove from master set */
FD_CLR(req->p->proc_fd, &master);
break;
}else {
//printf("Client : size message %d \n",nbytes );
write_message(sock, buffer, nbytes);
if (strncmp(buffer, "exit", 4) != 0) {
nbMessages++;
}
}
}
}
printf("------thread client shutdown----------\n");
close(listener);
close(sock);
free(buffer);
//release the resources
pthread_detach(pthread_self());
return NULL;
}
void request_print (const info_request *req) {
printf("%s \n",req->request);
}
/*
*Surveiller le fichier tmp/ipc/service
*Accepter 2 types de requetes :
* listen : lancer un serveur, ecouter sur un port ie "listen 127.0.0.1 6000"
* connect : connecter à une adresse, port ie "connect 127.0.0.1 6000 ${pid} 1 1"
*/
void main_loop (struct ipc_service *srv) {
//request
info_request tab_req[NBCLIENT];
int ret;
int i;
//pid server
pthread_t pid_s;
//pid client
pthread_t tab_client[NBCLIENT];
int nbclient = 0;
//init socket unix for server
int sfd;
struct sockaddr_un peer_addr;
socklen_t peer_addr_size;
sfd = set_listen_socket(srv->spath);
if (sfd == -1){
handle_error("set_listen_socket");
}
/* master file descriptor list */
fd_set master;
/* temp file descriptor list for select() */
fd_set read_fds;
/* maximum file descriptor number */
int fdmax;
/* listening socket descriptor */
int listener = sfd;
/* newly accept()ed socket descriptor */
int newfd;
/* buffer for client data */
char *buf = malloc(BUFSIZ);
if (buf == NULL)
{
handle_error("malloc");
}
memset(buf, 0, BUFSIZ);
int nbytes;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&read_fds);
/* add the listener to the master set */
FD_SET(listener, &master);
//FD_SET(sfd, &master);
/* keep track of the biggest file descriptor */
fdmax = listener; /* so far, it's this one*/
for(;;) {
/* copy it */
read_fds = master;
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("Server-select() error lol!");
exit(1);
}
//printf("Server-select...OK\n");
for (i = 0; i <= fdmax; i++) {
if(FD_ISSET(i, &read_fds)) {
if(i == listener) {
/* handle new connections */
peer_addr_size = sizeof(struct sockaddr_un);
newfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);
if (newfd == -1) {
handle_error("accept");
}
else
{
printf("Server-accept() is OK...\n");
//FD_SET(newfd, &master); /* add to master set */
//if(newfd > fdmax)
//{ /* keep track of the maximum */
//fdmax = newfd;
//}
nbytes = file_read (newfd, &buf);
if ( nbytes == -1) {
handle_error("file_read");
} else if( nbytes == 0) {
/* close it... */
close(i);
/* remove from master set */
FD_CLR(i, &master);
}else {
buf[BUFSIZ - 1] = '\0';
printf ("msg received (%d) : %s\n", nbytes, buf);
if (strncmp ("exit", buf, 4) == 0) {
break;
}
tab_req[nbclient].p = malloc(sizeof(struct ipc_client));
// -1 : error, 0 = no new client, 1 = new client
ret = ipc_server_get_new_request (buf, &tab_req[nbclient]);
tab_req[nbclient].p->proc_fd = newfd;
if (ret == -1) {
perror("server_get_new_request()");
exit(1);
} else if (ret == 0) {
break;
}
request_print(&tab_req[nbclient]);
if (strcmp("listen", tab_req[nbclient].request) == 0) {
int ret = pthread_create( &pid_s, NULL, &server_thread, (void *) &tab_req[nbclient]);
if (ret) {
perror("pthread_create()");
exit(errno);
} else {
printf("\n----------Creation of server thread ------------\n");
}
nbclient++;
}else {
int ret = pthread_create( &tab_client[nbclient], NULL, &client_thread, (void *) &tab_req[nbclient]);
if (ret) {
perror("pthread_create()");
exit(errno);
} else {
printf("\n----------Creation of client thread ------------\n");
}
nbclient++;
}
}
}
} /*else {
nbytes = file_read (i, &buf);
if ( nbytes == -1) {
handle_error("file_read");
} else if( nbytes == 0) {*/
/* close it... */
//close(i);
/* remove from master set */
/*FD_CLR(i, &master);
}else {
buf[BUFSIZ - 1] = '\0';
printf ("msg received (%d) : %s\n", nbytes, buf);
if (strncmp ("exit_server", buf, 4) == 0) {
break;
}
tab_req[nbclient].p = malloc(sizeof(struct ipc_client));
// -1 : error, 0 = no new client, 1 = new client
ret = ipc_server_get_new_request (buf, &tab_req[nbclient]);
tab_req[nbclient].p->proc_fd = i;
if (ret == -1) {
perror("server_get_new_request()");
exit(1);
} else if (ret == 0) {
break;
}
request_print(&tab_req[nbclient]);
if (strcmp("listen", tab_req[nbclient].request) == 0) {
int ret = pthread_create( &pid_s, NULL, &server_thread, (void *) &tab_req[nbclient]);
if (ret) {
perror("pthread_create()");
exit(errno);
} else {
printf("\n----------Creation of server thread ------------\n");
}
nbclient++;
}else {
int ret = pthread_create( &tab_client[nbclient], NULL, &client_thread, (void *) &tab_req[nbclient]);
if (ret) {
perror("pthread_create()");
exit(errno);
} else {
printf("\n----------Creation of client thread ------------\n");
}
nbclient++;
}
}
}*/ //i == listener
} //if FDISSET
}//boucle for
if (strncmp ("exit", buf, 4) == 0) {
break;
}
}//boucle while
if (pthread_cancel(pid_s) != 0) {
printf("Aucun thread correspond \n");
}
pthread_join(pid_s, NULL);
/*for (i = 0; i < nbclient; i++) {
pthread_join(tab_client[i], NULL);
}*/
for (i = 0; i < nbclient; i++) {
free(tab_req[i].p);
}
free(buf);
close(sfd);
}
int main(int argc, char * argv[], char **env) {
struct ipc_service srv;
ipc_server_init (argc, argv, env, &srv, SERVICE_TCP, NULL);
printf ("Listening on %s.\n", srv.spath);
// creates the service named pipe, that listens to client applications
int ret;
if ((ret = ipc_server_create (&srv))) {
fprintf(stdout, "error service_create %d\n", ret);
exit (1);
}
printf("MAIN: server created\n" );
// the service will loop until the end of time, a specific message, a signal
main_loop (&srv);
// the application will shut down, and remove the service named pipe
if ((ret = ipc_server_close (&srv))) {
fprintf(stdout, "error service_close %d\n", ret);
exit (1);
}
return 0;
}

View File

@ -1,58 +0,0 @@
#ifndef __TCPDSERVER_H__
#define __TCPDSERVER_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "../../lib/communication.h"
typedef struct {
struct sockaddr_in c_addr;
int sfd;
int index;
} client_data;
//informations for server to listen at a address
typedef struct {
struct sockaddr_in addr;
char * request;
struct ipc_client *p;
} info_request;
int initConnection (const info_request *req);
void endConnection (int sock);
void printAddr (struct sockaddr_in *csin);
void write_message(int sock, const char *buffer, size_t size);
int read_message(int sock, char *buffer);
//2 threads for listen and send data
void * service_thread(void * pdata);
//parse the first message from client in service and version
void parseServiceVersion(char * buf, char ** service, int *version);
//create 2 pathnames such as : pid-index-version-in/out
void inOutPathCreate(char ** pathname, int index, int version);
//create a fifo file
int fifo_create (char * path);
//create first message for a service : pid index version
void makePivMessage(char ** piv, int pid, int index, int version);
void * ipc_server_thread(void *reqq);
void * client_thread(void *reqq);
int ipc_server_get_new_request(char *buf, info_request *req);
void request_print (const info_request *req);
void main_loop(struct ipc_service *srv);
#endif

View File

@ -1,11 +0,0 @@
#!/bin/dash
REP=/tmp/ipc/
SERVICE="tcpd"
# pid index version
echo "connect 127.0.0.1 6000 111111 1 1" | nc -U ${REP}${SERVICE}
sleep 1
echo "hello frero" | nc -U ${REP}111111-1-1

View File

@ -1,8 +0,0 @@
#!/bin/dash
REP=/tmp/ipc/
SERVICE="tcpd"
# pid index version
echo "exit" | nc -U ${REP}${SERVICE}

View File

@ -1,6 +0,0 @@
#!/bin/dash
REP=/tmp/ipc/
SERVICE="tcpd"
echo "listen 127.0.0.1 6000" | nc -U ${REP}${SERVICE}

View File

@ -1,16 +0,0 @@
#!/bin/dash
REP=/tmp/ipc/
SERVICE="tcpd"
NB=10
if [ $# -ne 0 ]
then
NB=$1
fi
for pid in `seq 1 ${NB}`
do
./tcpdtest.bin
done

View File

@ -1,66 +0,0 @@
#include "../../lib/communication.h"
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#define PONGD_SERVICE_NAME "pongd"
#define LISTEN_BACKLOG 50
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char * argv[]) {
char *server_message = malloc(BUFSIZ);
char *pidfile = malloc(BUFSIZ);
char *buffer = malloc(BUFSIZ);
snprintf(server_message, BUFSIZ, "%s %d 1 1", "connect 127.0.0.1 6000", getpid());
snprintf(pidfile, BUFSIZ, "%s%d-1-1", "/tmp/ipc/", getpid());
char *proc_message = "hello frero";
int sfd;
struct sockaddr_un my_addr;
socklen_t peer_addr_size;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1)
return -1;
memset(&my_addr, 0, sizeof(struct sockaddr_un));
// Clear structure
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, "/tmp/ipc/tcpd", sizeof(my_addr.sun_path) - 1);
peer_addr_size = sizeof(struct sockaddr_un);
if(connect(sfd,(struct sockaddr *) &my_addr, peer_addr_size) == -1)
{
perror("connect()");
exit(errno);
}
//printf("connected...\n");
file_write(sfd, ipc_server_message, strlen(server_message));
//printf("%s\n", proc_message);
//sleep(1);
file_write(sfd, proc_message, strlen(proc_message));
file_read(sfd, &buffer);
printf("%s\n", buffer);
//sleep(1);
file_write(sfd, "exit", 4);
close(sfd);
// //sleep(1);
// cfd = socket(AF_UNIX, SOCK_STREAM, 0);
// if (sfd == -1)
// return -1;
// strncpy(my_addr.sun_path, pidfile, sizeof(my_addr.sun_path) - 1);
// if(connect(cfd,(struct sockaddr *) &my_addr, peer_addr_size) == -1)
// {
// perror("connect()");
// exit(errno);
// }
// close(cfd);
return 0;
}