Meaningful error msg, -logging +directory management, indentation.

more_to_read
Philippe PITTOLI 2020-01-01 12:11:34 +01:00
parent 534bd970a6
commit f4ef46aa6c
47 changed files with 3152 additions and 2045 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@
*.o
*.bin
*.dSYM
drop/

View File

@ -57,9 +57,9 @@ man/libipc.7.uninstall:
@echo ' RM > $(MANDIR)/man7/libipc.7'
$(Q)rm -f '$(DESTDIR)$(MANDIR)/man7/libipc.7'
libipc.so: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o
libipc.so: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
@echo ' LD > libipc.so'
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o
$(Q)$(CC) -o libipc.so -shared $(LDFLAGS) src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
libipc.so.install: libipc.so
@echo ' IN > $(LIBDIR)/libipc.so.0.4.0'
@ -86,9 +86,9 @@ libipc.so.uninstall:
@echo ' RM > $(LIBDIR)/libipc.so'
$(Q)rm -f '$(DESTDIR)$(LIBDIR)/libipc.so'
libipc.a: src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o
libipc.a: src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
@echo ' LD > libipc.a'
$(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/logger.o src/message.o src/network.o src/usocket.o src/utils.o
$(Q)$(AR) rc 'libipc.a' src/communication.o src/error.o src/fs.o src/message.o src/network.o src/print.o src/usocket.o src/utils.o
libipc.a.install: libipc.a
@echo ' IN > $(LIBDIR)/libipc.a'
@ -127,17 +127,17 @@ src/error.o.clean:
src/error.o.uninstall:
src/logger.o: src/logger.c src/logger.h src/ipc.h
@echo ' CC > src/logger.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/logger.c -fPIC -std=c11 -o src/logger.o
src/fs.o: src/fs.c src/utils.h src/fs.h
@echo ' CC > src/fs.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/fs.c -fPIC -std=c11 -o src/fs.o
src/logger.o.install:
src/fs.o.install:
src/logger.o.clean:
@echo ' RM > src/logger.o'
$(Q)rm -f src/logger.o
src/fs.o.clean:
@echo ' RM > src/fs.o'
$(Q)rm -f src/fs.o
src/logger.o.uninstall:
src/fs.o.uninstall:
src/message.o: src/message.c src/message.h src/usocket.h
@echo ' CC > src/message.o'
@ -163,7 +163,19 @@ src/network.o.clean:
src/network.o.uninstall:
src/usocket.o: src/usocket.c src/usocket.h src/utils.h
src/print.o: src/print.c src/ipc.h
@echo ' CC > src/print.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/print.c -fPIC -std=c11 -o src/print.o
src/print.o.install:
src/print.o.clean:
@echo ' RM > src/print.o'
$(Q)rm -f src/print.o
src/print.o.uninstall:
src/usocket.o: src/usocket.c src/usocket.h src/utils.h src/fs.h
@echo ' CC > src/usocket.o'
$(Q)$(CC) $(CFLAGS) -fPIC -std=c11 -c src/usocket.c -fPIC -std=c11 -o src/usocket.o
@ -209,16 +221,13 @@ $(DESTDIR)$(INCLUDEDIR):
$(DESTDIR)$(MANDIR):
@echo ' DIR > $(MANDIR)'
$(Q)mkdir -p $(DESTDIR)$(MANDIR)
install: libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/logger.o.install src/message.o.install src/network.o.install src/usocket.o.install src/utils.o.install
install: libipc.install src/ipc.h.install man/libipc.7.install libipc.so.install libipc.a.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install src/communication.o.install src/error.o.install src/fs.o.install src/message.o.install src/network.o.install src/print.o.install src/usocket.o.install src/utils.o.install
@:
uninstall: libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/logger.o.uninstall src/message.o.uninstall src/network.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall
uninstall: libipc.uninstall src/ipc.h.uninstall man/libipc.7.uninstall libipc.so.uninstall libipc.a.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall src/communication.o.uninstall src/error.o.uninstall src/fs.o.uninstall src/message.o.uninstall src/network.o.uninstall src/print.o.uninstall src/usocket.o.uninstall src/utils.o.uninstall
@:
test: all
@:
clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/logger.o.clean src/message.o.clean src/network.o.clean src/usocket.o.clean src/utils.o.clean
clean: libipc.clean src/ipc.h.clean man/libipc.7.clean libipc.so.clean libipc.a.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean src/communication.o.clean src/error.o.clean src/fs.o.clean src/message.o.clean src/network.o.clean src/print.o.clean src/usocket.o.clean src/utils.o.clean
distclean: clean
dist: dist-gz dist-xz dist-bz2
$(Q)rm -- $(PACKAGE)-$(VERSION)
@ -237,12 +246,13 @@ $(PACKAGE)-$(VERSION).tar.gz: distdir
$(PACKAGE)-$(VERSION)/man/libipc.7.scd \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/fs.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h
@ -257,12 +267,13 @@ $(PACKAGE)-$(VERSION).tar.xz: distdir
$(PACKAGE)-$(VERSION)/man/libipc.7.scd \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/fs.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h
@ -277,12 +288,13 @@ $(PACKAGE)-$(VERSION).tar.bz2: distdir
$(PACKAGE)-$(VERSION)/man/libipc.7.scd \
$(PACKAGE)-$(VERSION)/src/communication.c \
$(PACKAGE)-$(VERSION)/src/error.c \
$(PACKAGE)-$(VERSION)/src/logger.c \
$(PACKAGE)-$(VERSION)/src/fs.c \
$(PACKAGE)-$(VERSION)/src/message.c \
$(PACKAGE)-$(VERSION)/src/network.c \
$(PACKAGE)-$(VERSION)/src/print.c \
$(PACKAGE)-$(VERSION)/src/usocket.c \
$(PACKAGE)-$(VERSION)/src/utils.c \
$(PACKAGE)-$(VERSION)/src/logger.h \
$(PACKAGE)-$(VERSION)/src/fs.h \
$(PACKAGE)-$(VERSION)/src/message.h \
$(PACKAGE)-$(VERSION)/src/usocket.h \
$(PACKAGE)-$(VERSION)/src/utils.h

5
examples/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.[^ch]
!Makefile
!.zsh
!.gitignore
*.o

493
examples/Makefile Normal file
View File

@ -0,0 +1,493 @@
PACKAGE = 'ipc-examples'
VERSION = '0.5.0'
PREFIX := /usr/local
BINDIR := $(PREFIX)/bin
LIBDIR := $(PREFIX)/lib
SHAREDIR := $(PREFIX)/share
INCLUDEDIR := $(PREFIX)/include
MANDIR := $(SHAREDIR)/man
CC := cc
CXX := c++
LD := ${CC}
CFLAGS := -Wall -Wextra -g
LDFLAGS := -I../src -L../ ../src/ipc.h -lipc
Q := @
all: fs-function-tests fd-exchange-providing fd-exchange-receiving fs-experimentations pong pongd pongspam simple-tcp-client simple-tcpd test-ask-for-fd-to-networkd test-networkd-provide-fd wsserver
@:
fs-function-tests: fs-function-tests.o
@echo ' LD > fs-function-tests'
$(Q)$(CC) -o fs-function-tests fs-function-tests.o $(LDFLAGS)
fs-function-tests.install: fs-function-tests
@echo ' IN > $(BINDIR)/fs-function-tests'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 fs-function-tests $(DESTDIR)$(BINDIR)/fs-function-tests
fs-function-tests.clean: fs-function-tests.o.clean
@echo ' RM > fs-function-tests'
$(Q)rm -f fs-function-tests
fs-function-tests.uninstall:
@echo ' RM > $(BINDIR)/fs-function-tests'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/fs-function-tests'
fd-exchange-providing: fd-exchange-providing.o
@echo ' LD > fd-exchange-providing'
$(Q)$(CC) -o fd-exchange-providing fd-exchange-providing.o $(LDFLAGS)
fd-exchange-providing.install: fd-exchange-providing
@echo ' IN > $(BINDIR)/fd-exchange-providing'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 fd-exchange-providing $(DESTDIR)$(BINDIR)/fd-exchange-providing
fd-exchange-providing.clean: fd-exchange-providing.o.clean
@echo ' RM > fd-exchange-providing'
$(Q)rm -f fd-exchange-providing
fd-exchange-providing.uninstall:
@echo ' RM > $(BINDIR)/fd-exchange-providing'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/fd-exchange-providing'
fd-exchange-receiving: fd-exchange-receiving.o
@echo ' LD > fd-exchange-receiving'
$(Q)$(CC) -o fd-exchange-receiving fd-exchange-receiving.o $(LDFLAGS)
fd-exchange-receiving.install: fd-exchange-receiving
@echo ' IN > $(BINDIR)/fd-exchange-receiving'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 fd-exchange-receiving $(DESTDIR)$(BINDIR)/fd-exchange-receiving
fd-exchange-receiving.clean: fd-exchange-receiving.o.clean
@echo ' RM > fd-exchange-receiving'
$(Q)rm -f fd-exchange-receiving
fd-exchange-receiving.uninstall:
@echo ' RM > $(BINDIR)/fd-exchange-receiving'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/fd-exchange-receiving'
fs-experimentations: fs-experimentations.o
@echo ' LD > fs-experimentations'
$(Q)$(CC) -o fs-experimentations fs-experimentations.o $(LDFLAGS)
fs-experimentations.install: fs-experimentations
@echo ' IN > $(BINDIR)/fs-experimentations'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 fs-experimentations $(DESTDIR)$(BINDIR)/fs-experimentations
fs-experimentations.clean: fs-experimentations.o.clean
@echo ' RM > fs-experimentations'
$(Q)rm -f fs-experimentations
fs-experimentations.uninstall:
@echo ' RM > $(BINDIR)/fs-experimentations'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/fs-experimentations'
pong: pong.o
@echo ' LD > pong'
$(Q)$(CC) -o pong pong.o $(LDFLAGS)
pong.install: pong
@echo ' IN > $(BINDIR)/pong'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 pong $(DESTDIR)$(BINDIR)/pong
pong.clean: pong.o.clean
@echo ' RM > pong'
$(Q)rm -f pong
pong.uninstall:
@echo ' RM > $(BINDIR)/pong'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/pong'
pongd: pongd.o
@echo ' LD > pongd'
$(Q)$(CC) -o pongd pongd.o $(LDFLAGS)
pongd.install: pongd
@echo ' IN > $(BINDIR)/pongd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 pongd $(DESTDIR)$(BINDIR)/pongd
pongd.clean: pongd.o.clean
@echo ' RM > pongd'
$(Q)rm -f pongd
pongd.uninstall:
@echo ' RM > $(BINDIR)/pongd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/pongd'
pongspam: pongspam.o
@echo ' LD > pongspam'
$(Q)$(CC) -o pongspam pongspam.o $(LDFLAGS)
pongspam.install: pongspam
@echo ' IN > $(BINDIR)/pongspam'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 pongspam $(DESTDIR)$(BINDIR)/pongspam
pongspam.clean: pongspam.o.clean
@echo ' RM > pongspam'
$(Q)rm -f pongspam
pongspam.uninstall:
@echo ' RM > $(BINDIR)/pongspam'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/pongspam'
simple-tcp-client: simple-tcp-client.o
@echo ' LD > simple-tcp-client'
$(Q)$(CC) -o simple-tcp-client simple-tcp-client.o $(LDFLAGS)
simple-tcp-client.install: simple-tcp-client
@echo ' IN > $(BINDIR)/simple-tcp-client'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 simple-tcp-client $(DESTDIR)$(BINDIR)/simple-tcp-client
simple-tcp-client.clean: simple-tcp-client.o.clean
@echo ' RM > simple-tcp-client'
$(Q)rm -f simple-tcp-client
simple-tcp-client.uninstall:
@echo ' RM > $(BINDIR)/simple-tcp-client'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/simple-tcp-client'
simple-tcpd: simple-tcpd.o
@echo ' LD > simple-tcpd'
$(Q)$(CC) -o simple-tcpd simple-tcpd.o $(LDFLAGS)
simple-tcpd.install: simple-tcpd
@echo ' IN > $(BINDIR)/simple-tcpd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 simple-tcpd $(DESTDIR)$(BINDIR)/simple-tcpd
simple-tcpd.clean: simple-tcpd.o.clean
@echo ' RM > simple-tcpd'
$(Q)rm -f simple-tcpd
simple-tcpd.uninstall:
@echo ' RM > $(BINDIR)/simple-tcpd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/simple-tcpd'
test-ask-for-fd-to-networkd: test-ask-for-fd-to-networkd.o
@echo ' LD > test-ask-for-fd-to-networkd'
$(Q)$(CC) -o test-ask-for-fd-to-networkd test-ask-for-fd-to-networkd.o $(LDFLAGS)
test-ask-for-fd-to-networkd.install: test-ask-for-fd-to-networkd
@echo ' IN > $(BINDIR)/test-ask-for-fd-to-networkd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 test-ask-for-fd-to-networkd $(DESTDIR)$(BINDIR)/test-ask-for-fd-to-networkd
test-ask-for-fd-to-networkd.clean: test-ask-for-fd-to-networkd.o.clean
@echo ' RM > test-ask-for-fd-to-networkd'
$(Q)rm -f test-ask-for-fd-to-networkd
test-ask-for-fd-to-networkd.uninstall:
@echo ' RM > $(BINDIR)/test-ask-for-fd-to-networkd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/test-ask-for-fd-to-networkd'
test-networkd-provide-fd: test-networkd-provide-fd.o
@echo ' LD > test-networkd-provide-fd'
$(Q)$(CC) -o test-networkd-provide-fd test-networkd-provide-fd.o $(LDFLAGS)
test-networkd-provide-fd.install: test-networkd-provide-fd
@echo ' IN > $(BINDIR)/test-networkd-provide-fd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 test-networkd-provide-fd $(DESTDIR)$(BINDIR)/test-networkd-provide-fd
test-networkd-provide-fd.clean: test-networkd-provide-fd.o.clean
@echo ' RM > test-networkd-provide-fd'
$(Q)rm -f test-networkd-provide-fd
test-networkd-provide-fd.uninstall:
@echo ' RM > $(BINDIR)/test-networkd-provide-fd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/test-networkd-provide-fd'
wsserver: wsserver.o
@echo ' LD > wsserver'
$(Q)$(CC) -o wsserver wsserver.o $(LDFLAGS)
wsserver.install: wsserver
@echo ' IN > $(BINDIR)/wsserver'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 wsserver $(DESTDIR)$(BINDIR)/wsserver
wsserver.clean: wsserver.o.clean
@echo ' RM > wsserver'
$(Q)rm -f wsserver
wsserver.uninstall:
@echo ' RM > $(BINDIR)/wsserver'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/wsserver'
fs-function-tests.o: fs-function-tests.c ./../src/ipc.h ./../src/fs.h
@echo ' CC > fs-function-tests.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c fs-function-tests.c -std=c11 -o fs-function-tests.o
fs-function-tests.o.install:
fs-function-tests.o.clean:
@echo ' RM > fs-function-tests.o'
$(Q)rm -f fs-function-tests.o
fs-function-tests.o.uninstall:
fd-exchange-providing.o: fd-exchange-providing.c ./../src/ipc.h ./../src/usocket.h
@echo ' CC > fd-exchange-providing.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c fd-exchange-providing.c -std=c11 -o fd-exchange-providing.o
fd-exchange-providing.o.install:
fd-exchange-providing.o.clean:
@echo ' RM > fd-exchange-providing.o'
$(Q)rm -f fd-exchange-providing.o
fd-exchange-providing.o.uninstall:
fd-exchange-receiving.o: fd-exchange-receiving.c ./../src/ipc.h ./../src/usocket.h
@echo ' CC > fd-exchange-receiving.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c fd-exchange-receiving.c -std=c11 -o fd-exchange-receiving.o
fd-exchange-receiving.o.install:
fd-exchange-receiving.o.clean:
@echo ' RM > fd-exchange-receiving.o'
$(Q)rm -f fd-exchange-receiving.o
fd-exchange-receiving.o.uninstall:
fs-experimentations.o: fs-experimentations.c
@echo ' CC > fs-experimentations.o'
$(Q)$(CC) $(CFLAGS) -c fs-experimentations.c -o fs-experimentations.o
fs-experimentations.o.install:
fs-experimentations.o.clean:
@echo ' RM > fs-experimentations.o'
$(Q)rm -f fs-experimentations.o
fs-experimentations.o.uninstall:
pong.o: pong.c ./../src/ipc.h
@echo ' CC > pong.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c pong.c -std=c11 -o pong.o
pong.o.install:
pong.o.clean:
@echo ' RM > pong.o'
$(Q)rm -f pong.o
pong.o.uninstall:
pongd.o: pongd.c ./../src/ipc.h
@echo ' CC > pongd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c pongd.c -std=c11 -o pongd.o
pongd.o.install:
pongd.o.clean:
@echo ' RM > pongd.o'
$(Q)rm -f pongd.o
pongd.o.uninstall:
pongspam.o: pongspam.c ./../src/ipc.h
@echo ' CC > pongspam.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c pongspam.c -std=c11 -o pongspam.o
pongspam.o.install:
pongspam.o.clean:
@echo ' RM > pongspam.o'
$(Q)rm -f pongspam.o
pongspam.o.uninstall:
simple-tcp-client.o: simple-tcp-client.c ./../src/ipc.h ./../src/utils.h
@echo ' CC > simple-tcp-client.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c simple-tcp-client.c -std=c11 -o simple-tcp-client.o
simple-tcp-client.o.install:
simple-tcp-client.o.clean:
@echo ' RM > simple-tcp-client.o'
$(Q)rm -f simple-tcp-client.o
simple-tcp-client.o.uninstall:
simple-tcpd.o: simple-tcpd.c ./../src/ipc.h ./../src/utils.h
@echo ' CC > simple-tcpd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c simple-tcpd.c -std=c11 -o simple-tcpd.o
simple-tcpd.o.install:
simple-tcpd.o.clean:
@echo ' RM > simple-tcpd.o'
$(Q)rm -f simple-tcpd.o
simple-tcpd.o.uninstall:
test-ask-for-fd-to-networkd.o: test-ask-for-fd-to-networkd.c ./../src/ipc.h
@echo ' CC > test-ask-for-fd-to-networkd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c test-ask-for-fd-to-networkd.c -std=c11 -o test-ask-for-fd-to-networkd.o
test-ask-for-fd-to-networkd.o.install:
test-ask-for-fd-to-networkd.o.clean:
@echo ' RM > test-ask-for-fd-to-networkd.o'
$(Q)rm -f test-ask-for-fd-to-networkd.o
test-ask-for-fd-to-networkd.o.uninstall:
test-networkd-provide-fd.o: test-networkd-provide-fd.c ./../src/ipc.h
@echo ' CC > test-networkd-provide-fd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c test-networkd-provide-fd.c -std=c11 -o test-networkd-provide-fd.o
test-networkd-provide-fd.o.install:
test-networkd-provide-fd.o.clean:
@echo ' RM > test-networkd-provide-fd.o'
$(Q)rm -f test-networkd-provide-fd.o
test-networkd-provide-fd.o.uninstall:
wsserver.o: wsserver.c ./../src/ipc.h ./../src/utils.h
@echo ' CC > wsserver.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c wsserver.c -std=c11 -o wsserver.o
wsserver.o.install:
wsserver.o.clean:
@echo ' RM > wsserver.o'
$(Q)rm -f wsserver.o
wsserver.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: fs-function-tests.install fd-exchange-providing.install fd-exchange-receiving.install fs-experimentations.install pong.install pongd.install pongspam.install simple-tcp-client.install simple-tcpd.install test-ask-for-fd-to-networkd.install test-networkd-provide-fd.install wsserver.install fs-function-tests.o.install fd-exchange-providing.o.install fd-exchange-receiving.o.install fs-experimentations.o.install pong.o.install pongd.o.install pongspam.o.install simple-tcp-client.o.install simple-tcpd.o.install test-ask-for-fd-to-networkd.o.install test-networkd-provide-fd.o.install wsserver.o.install
@:
uninstall: fs-function-tests.uninstall fd-exchange-providing.uninstall fd-exchange-receiving.uninstall fs-experimentations.uninstall pong.uninstall pongd.uninstall pongspam.uninstall simple-tcp-client.uninstall simple-tcpd.uninstall test-ask-for-fd-to-networkd.uninstall test-networkd-provide-fd.uninstall wsserver.uninstall fs-function-tests.o.uninstall fd-exchange-providing.o.uninstall fd-exchange-receiving.o.uninstall fs-experimentations.o.uninstall pong.o.uninstall pongd.o.uninstall pongspam.o.uninstall simple-tcp-client.o.uninstall simple-tcpd.o.uninstall test-ask-for-fd-to-networkd.o.uninstall test-networkd-provide-fd.o.uninstall wsserver.o.uninstall
@:
clean: fs-function-tests.clean fd-exchange-providing.clean fd-exchange-receiving.clean fs-experimentations.clean pong.clean pongd.clean pongspam.clean simple-tcp-client.clean simple-tcpd.clean test-ask-for-fd-to-networkd.clean test-networkd-provide-fd.clean wsserver.clean fs-function-tests.o.clean fd-exchange-providing.o.clean fd-exchange-receiving.o.clean fs-experimentations.o.clean pong.o.clean pongd.o.clean pongspam.o.clean simple-tcp-client.o.clean simple-tcpd.o.clean test-ask-for-fd-to-networkd.o.clean test-networkd-provide-fd.o.clean wsserver.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)/test-networkd-provide-fd.c \
$(PACKAGE)-$(VERSION)/test-ask-for-fd-to-networkd.c \
$(PACKAGE)-$(VERSION)/fd-exchange-receiving.c \
$(PACKAGE)-$(VERSION)/fs-function-tests.c \
$(PACKAGE)-$(VERSION)/pongd.c \
$(PACKAGE)-$(VERSION)/wsserver.c \
$(PACKAGE)-$(VERSION)/pong.c \
$(PACKAGE)-$(VERSION)/fd-exchange-providing.c \
$(PACKAGE)-$(VERSION)/fs-experimentations.c \
$(PACKAGE)-$(VERSION)/pongspam.c \
$(PACKAGE)-$(VERSION)/simple-tcpd.c \
$(PACKAGE)-$(VERSION)/simple-tcp-client.c
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)/test-networkd-provide-fd.c \
$(PACKAGE)-$(VERSION)/test-ask-for-fd-to-networkd.c \
$(PACKAGE)-$(VERSION)/fd-exchange-receiving.c \
$(PACKAGE)-$(VERSION)/fs-function-tests.c \
$(PACKAGE)-$(VERSION)/pongd.c \
$(PACKAGE)-$(VERSION)/wsserver.c \
$(PACKAGE)-$(VERSION)/pong.c \
$(PACKAGE)-$(VERSION)/fd-exchange-providing.c \
$(PACKAGE)-$(VERSION)/fs-experimentations.c \
$(PACKAGE)-$(VERSION)/pongspam.c \
$(PACKAGE)-$(VERSION)/simple-tcpd.c \
$(PACKAGE)-$(VERSION)/simple-tcp-client.c
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)/test-networkd-provide-fd.c \
$(PACKAGE)-$(VERSION)/test-ask-for-fd-to-networkd.c \
$(PACKAGE)-$(VERSION)/fd-exchange-receiving.c \
$(PACKAGE)-$(VERSION)/fs-function-tests.c \
$(PACKAGE)-$(VERSION)/pongd.c \
$(PACKAGE)-$(VERSION)/wsserver.c \
$(PACKAGE)-$(VERSION)/pong.c \
$(PACKAGE)-$(VERSION)/fd-exchange-providing.c \
$(PACKAGE)-$(VERSION)/fs-experimentations.c \
$(PACKAGE)-$(VERSION)/pongspam.c \
$(PACKAGE)-$(VERSION)/simple-tcpd.c \
$(PACKAGE)-$(VERSION)/simple-tcp-client.c
help:
@echo ' :: ipc-examples-0.5.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 ' - CXX  ${CXX}'
@echo ' - LD  ${LD}'
@echo ' - CFLAGS  ${CFLAGS}'
@echo ' - CXXFLAGS  ${CXXFLAGS}'
@echo ' - LDFLAGS  ${LDFLAGS}'
@echo ' - PREFIX  ${PREFIX}'
@echo ' - BINDIR  ${BINDIR}'
@echo ' - LIBDIR  ${LIBDIR}'
@echo ' - SHAREDIR  ${SHAREDIR}'
@echo ' - INCLUDEDIR  ${INCLUDEDIR}'
@echo ' - MANDIR  ${MANDIR}'
@echo ''
@echo 'Project targets: '
@echo ' - fs-function-tests  binary'
@echo ' - fd-exchange-providing  binary'
@echo ' - fd-exchange-receiving  binary'
@echo ' - fs-experimentations  binary'
@echo ' - pong  binary'
@echo ' - pongd  binary'
@echo ' - pongspam  binary'
@echo ' - simple-tcp-client  binary'
@echo ' - simple-tcpd  binary'
@echo ' - test-ask-for-fd-to-networkd  binary'
@echo ' - test-networkd-provide-fd  binary'
@echo ' - wsserver  binary'
@echo ''
@echo 'Makefile options:'
@echo ' - gnu: false'
@echo ' - colors: true'
@echo ''
@echo 'Rebuild the Makefile with:'
@echo ' zsh ./build.zsh -c'
.PHONY: all clean distclean dist install uninstall help

View File

@ -1,14 +1,26 @@
# how to compile
./build.sh
make
# how to launch
export IPC_RUNDIR=/tmp
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../
If libipc is already installed and you have the rights to create unix sockets in the default directory (/run/ipc), just run the code:
./pongd
# in another terminal
In case you want to test the library and example programs:
# This is a directory anybody can write in
export IPC_RUNDIR=/tmp
# to test the library without installing it
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../
# finally, run the program, here a pong daemon
./pongd
# same thing in another terminal, to test the client
export IPC_RUNDIR=/tmp
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../
./pong

View File

@ -1,23 +0,0 @@
#!/bin/sh
nontapmsg() {
echo $*
}
if [ $# -eq 0 ] ; then
SRC="*.c"
else
SRC="$*"
fi
for i in $SRC
do
BIN=$(echo ${i} | sed "s/.c$/.bin/")
if [ ! -f ${BIN} ] || [ $(stat -c "%X" ${BIN}) -lt $(stat -c "%X" ${i}) ]
then
nontapmsg "compiling ${BIN}"
# gcc $BIN.c ./lib/*.o -o $BIN -I../src -I ./lib/ -L../ -L./lib/ -lipc -Wall -g -Wextra
gcc -Wall -g -Wextra "${i}" -o "${BIN}" -I../src -L../ ../src/ipc.h -lipc
touch "${BIN}"
fi
done

View File

@ -12,7 +12,7 @@
// This program opens a file then provide it to another running program.
// see examples/fd-exchange-receiving.c
int main(int argc, char * argv[])
int main (int argc, char *argv[])
{
if (argc != 2) {
fprintf (stderr, "usage: %s file", argv[0]);
@ -24,8 +24,8 @@ int main(int argc, char * argv[])
T_PERROR_R (((fd = open (argv[1], O_CREAT | O_RDWR)) < 0), "cannot open the file", EXIT_FAILURE);
TIPC_P_Q (usock_connect (&sock, "SOCKET_FD_EXCHANGE_TEST"), "trying to connect to the unix socket", EXIT_FAILURE);
TIPC_P_Q (ipc_provide_fd (sock, fd), "cannot send the file descriptor", EXIT_FAILURE);
TEST_IPC_Q (usock_connect (&sock, "SOCKET_FD_EXCHANGE_TEST"), EXIT_FAILURE);
TEST_IPC_Q (ipc_provide_fd (sock, fd), EXIT_FAILURE);
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}

View File

@ -13,7 +13,7 @@
// This program receives an open file descriptor from another running program.
// see examples/fd-exchange-providing.c
int main(int argc, char * argv[])
int main (int argc, char *argv[])
{
if (argc != 1) {
fprintf (stderr, "usage: %s", argv[0]);
@ -24,14 +24,14 @@ int main(int argc, char * argv[])
int usockclient = 0;
int fd = 0;
TIPC_P_Q (usock_init (&usock, "SOCKET_FD_EXCHANGE_TEST"), "trying to connect to the unix socket", EXIT_FAILURE);
TIPC_P_Q (usock_accept (usock, &usockclient), "cannot accept a client from the unix socket", EXIT_FAILURE);
TIPC_P_Q (ipc_receive_fd (usockclient, &fd), "cannot receive the file descriptor", EXIT_FAILURE);
TEST_IPC_Q (usock_init (&usock, "SOCKET_FD_EXCHANGE_TEST"), EXIT_FAILURE);
TEST_IPC_Q (usock_accept (usock, &usockclient), EXIT_FAILURE);
TEST_IPC_Q (ipc_receive_fd (usockclient, &fd), EXIT_FAILURE);
T_PERROR_R ((write (fd, "coucou\n", 7) < 0), "cannot write a message in the file", EXIT_FAILURE);
T_PERROR_R ((close (fd) < 0), "cannot close the file descriptor", EXIT_FAILURE);
T_PERROR_R ((close (fd) < 0) , "cannot close the file descriptor" , EXIT_FAILURE);
TIPC_P_Q (usock_close (usock), "cannot close the unix socket", EXIT_FAILURE);
TEST_IPC_Q (usock_close (usock), EXIT_FAILURE);
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,153 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <limits.h> /* PATH_MAX */
#include <sys/stat.h> /* mkdir(2) */
#include <sys/types.h>
#include <errno.h>
void print_content (const char *dirname)
{
DIR *dir;
struct dirent *entry;
dir = opendir (dirname);
if (dir == NULL)
return;
printf ("%s :\n", dirname);
while ((entry = readdir (dir)) != NULL) {
printf (" %s\n", entry->d_name);
}
printf ("\n");
closedir (dir);
}
int mkdir_p (const char *path)
{
int dir_rights = 01750;
// notes:
// S_ISGID
// files and sub-directories are automatically in the same group of the root directory
// S_ISVTX = "sticky bit"
// files created in this dir can only be removed by the owner or the directory owner
// so in /tmp even people with writing rights cannot remove other's content
char _path[BUFSIZ];
const size_t len = strlen (path);
char *p;
errno = 0;
/* copy the string so it becomes mutable */
if (len > sizeof (_path) - 1) {
errno = ENAMETOOLONG;
return -1;
}
strcpy (_path, path);
/* loop over the string, each time we have a slash we can mkdir */
for (p = _path + 1; *p; p++) {
if (*p == '/') {
/* Temporarily truncate */
*p = '\0';
if (mkdir (_path, dir_rights) != 0) {
if (errno != EEXIST)
return -1;
}
*p = '/';
}
}
if (mkdir (_path, dir_rights) != 0) {
if (errno != EEXIST)
return -1;
}
return 0;
}
void rights (struct stat *status)
{
printf (status->st_mode & S_IRUSR ? "r" : "-");
printf (status->st_mode & S_IWUSR ? "w" : "-");
printf (status->st_mode & S_IXUSR ? "x" : "-");
printf (status->st_mode & S_IRGRP ? "r" : "-");
printf (status->st_mode & S_IWGRP ? "w" : "-");
printf (status->st_mode & S_IXGRP ? "x" : "-");
printf (status->st_mode & S_IROTH ? "r" : "-");
printf (status->st_mode & S_IWOTH ? "w" : "-");
printf (status->st_mode & S_IXOTH ? "x" : "-");
printf ("\n");
}
void print_status (struct stat *status)
{
if (S_ISBLK (status->st_mode))
printf ("block ");
else if (S_ISBLK (status->st_mode))
printf ("ISBLK ");
else if (S_ISCHR (status->st_mode))
printf ("ISCHR ");
else if (S_ISDIR (status->st_mode))
printf ("ISDIR ");
else if (S_ISFIFO (status->st_mode))
printf ("ISFIFO ");
else if (S_ISLNK (status->st_mode))
printf ("ISLNK ");
else if (S_ISREG (status->st_mode))
printf ("ISREG ");
else if (S_ISSOCK (status->st_mode))
printf ("ISSOCK ");
else
printf ("CANNOT SEE THE FILE TYPE :(\n");
rights (status);
}
int test_with_stat (char *filename, struct stat *status)
{
int ret = stat (filename, status);
if (ret < 0) {
printf ("file not found or non accessible\n");
return 1;
}
return 0;
}
int main (int argc, char *argv[], char *env[])
{
env = env;
if (argc <= 1) {
printf ("usage: %s directory\n", argv[0]);
return 0;
}
struct stat status;
memset (&status, 0, sizeof (struct stat));
if (test_with_stat (argv[1], &status)) {
printf ("This is neither a directory nor a file, creating directory\n");
int ret = mkdir_p (argv[1]);
if (ret < 0) {
printf ("There is an error: cannot create the directory %s\n", argv[1]);
exit (1);
} else {
printf ("Directory %s created\n", argv[1]);
}
print_content (argv[1]);
} else {
print_status (&status);
}
return 0;
}

View File

@ -0,0 +1,29 @@
#include "../src/fs.h"
void print_usage (char *progname)
{
printf ("usage: %s path\n", progname);
}
int main (int argc, char **argv)
{
if (argc == 1) {
print_usage (argv[0]);
exit (0);
}
if (strncmp (argv[1], "-h", 2) == 0) {
print_usage (argv[0]);
exit (0);
}
printf ("directory_setup_ (\"%s\")\n", argv[1]);
struct ipc_error ret = directory_setup_ (argv[1]);
if (ret.error_code != 0) {
fprintf (stderr, "an error occured: %s\n", ret.error_message);
exit (1);
}
return 0;
}

View File

@ -9,16 +9,17 @@
#define SERVICE_NAME "pong"
#define PRINTERR(ret,msg) {\
const char * err = ipc_errors_get (ret);\
const char * err = ipc_errors_get (ret.error_code);\
fprintf(stderr, "error while %s: %s\n", msg, err);\
}
void chomp (char *str, ssize_t len) {
if (str[len -1] == '\n') {
str[len -1] = '\0';
void chomp (char *str, ssize_t len)
{
if (str[len - 1] == '\n') {
str[len - 1] = '\0';
}
if (str[len -2] == '\n') {
str[len -2] = '\0';
if (str[len - 2] == '\n') {
str[len - 2] = '\0';
}
}
@ -26,123 +27,133 @@ struct ipc_connection_info *srv;
void non_interactive (char *env[])
{
SECURE_DECLARATION (struct ipc_message, m);
SECURE_DECLARATION (struct ipc_message, m);
// init service
TIPC_P_Q (ipc_connection (env, srv, SERVICE_NAME), "application connection", EXIT_FAILURE);
TIPC_P_Q (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen(MSG) +1), "message format data", EXIT_FAILURE);
// init service
TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen (MSG) + 1), EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG);
TIPC_P_Q (ipc_write (srv, &m), "application write", EXIT_FAILURE);
ipc_message_empty (&m);
TIPC_P_Q (ipc_read (srv, &m), "application read", EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG);
TEST_IPC_QUIT_ON_ERROR (ipc_write (srv, &m), EXIT_FAILURE);
ipc_message_empty (&m);
TEST_IPC_QUIT_ON_ERROR (ipc_read (srv, &m), EXIT_FAILURE);
printf ("msg recv (type: %u): %s\n", m.user_type, m.payload);
ipc_message_empty (&m);
printf ("msg recv (type: %u): %s\n", m.user_type, m.payload);
ipc_message_empty (&m);
TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE);
TEST_IPC_QUIT_ON_ERROR (ipc_close (srv), EXIT_FAILURE);
}
void interactive (char *env[])
{
// init service
TIPC_P_Q (ipc_connection (env, srv, SERVICE_NAME), "application connection", EXIT_FAILURE);
// init service
TEST_IPC_QUIT_ON_ERROR (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_add_fd (&services, 0); // add STDIN
ipc_connections_print (&services);
while (1) {
printf ("msg to send: ");
fflush (stdout);
long timer = 10;
TIPC_P_Q (ipc_wait_event (&services, NULL, &event), "wait event", EXIT_FAILURE);
while (1) {
printf ("msg to send: ");
fflush (stdout);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// structure not read, should read the message here
ssize_t len;
char buf[4096];
memset(buf, 0, 4096);
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// structure not read, should read the message here
ssize_t len;
char buf[4096];
memset (buf, 0, 4096);
len = read (event.origin->fd, buf, 4096);
len = read (event.origin->fd, buf, 4096);
buf[len -1] = '\0';
chomp (buf, len);
buf[len - 1] = '\0';
chomp (buf, len);
#if 0
printf ("\n");
printf ("message to send: %.*s\n", (int) len, buf);
printf ("\n");
printf ("message to send: %.*s\n", (int)len, buf);
#endif
// in case we want to quit the program
if ( len == 0
|| strncmp (buf, "quit", 4) == 0
|| strncmp (buf, "exit", 4) == 0) {
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE);
ipc_connections_free (&services);
exit (EXIT_SUCCESS);
struct ipc_error ret = ipc_close (srv);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s", ret.error_message);
exit (EXIT_FAILURE);
}
// send the message read on STDIN
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message), , );
ipc_connections_free (&services);
TIPC_P_Q (ipc_message_format_data (m, 42, buf, len), "message format", EXIT_FAILURE);
#if 0
printf ("\n");
printf ("right before sending a message\n");
#endif
TIPC_P_Q (ipc_write (srv, m), "ipc_write", EXIT_FAILURE);
#if 0
printf ("right after sending a message\n");
#endif
ipc_message_empty (m);
free (m);
exit (EXIT_SUCCESS);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
printf ("\rmsg recv: %.*s\n", 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);
// send the message read on STDIN
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION (m, sizeof (struct ipc_message),, return; );
struct ipc_error ret = ipc_message_format_data (m, 42, buf, len);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s", ret.error_message);
exit (EXIT_FAILURE);
}
#if 0
printf ("\n");
printf ("right before sending a message\n");
#endif
ret = ipc_write (srv, m);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s", ret.error_message);
exit (EXIT_FAILURE);
}
#if 0
printf ("right after sending a message\n");
#endif
ipc_message_empty (m);
free (m);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
printf ("\rmsg recv: %.*s\n", 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
argc = argc; // warnings
argv = argv; // warnings
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
memset (srv, 0, sizeof (struct ipc_connection_info));
if (argc == 1)
non_interactive (env);
else
interactive (env);
// index and version should be filled
srv->index = 0;
srv->version = 0;
return EXIT_SUCCESS;
if (argc == 1)
non_interactive (env);
else
interactive (env);
return EXIT_SUCCESS;
}

View File

@ -9,8 +9,7 @@
#define PONGD_VERBOSE
#define PRINTERR(ret,msg) {\
const char * err = ipc_errors_get (ret);\
fprintf(stderr, "error while %s: %s\n", msg, err);\
fprintf(stderr, "error while %s: %s\n", msg, ret.error_message);\
}
int cpt = 0;
@ -18,105 +17,95 @@ int cpt = 0;
struct ipc_connection_info *srv = NULL;
struct ipc_connection_infos *clients = NULL;
void main_loop ()
{
enum ipc_errors ret = 0;
long timer = 10;
SECURE_DECLARATION (struct ipc_error, ret);
clients = malloc (sizeof (struct ipc_connection_infos));
memset(clients, 0, sizeof(struct ipc_connection_infos));
memset (clients, 0, sizeof (struct ipc_connection_infos));
struct ipc_event event;
memset(&event, 0, sizeof (struct ipc_event));
SECURE_DECLARATION (struct ipc_event, event);
event.type = IPC_EVENT_TYPE_NOT_SET;
while(1) {
while (1) {
// ipc_service_poll_event provides one event at a time
// warning: event->m is free'ed if not NULL
// printf ("before wait event\n"); // TODO remove
ret = ipc_wait_event (clients, srv, &event);
// printf ("after wait event\n"); // TODO remove
if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) {
PRINTERR(ret,"service poll event");
// the application will shut down, and close the service
ret = ipc_server_close (srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server close");
}
exit (EXIT_FAILURE);
}
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (clients, srv, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION:
{
cpt++;
case IPC_EVENT_TYPE_CONNECTION:
{
cpt++;
#ifdef PONGD_VERBOSE
printf ("connection: %d clients connected, new client is %d\n"
, cpt, (event.origin)->fd);
printf ("connection: %d clients connected, new client is %d\n", cpt, (event.origin)->fd);
#endif
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
cpt--;
};
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
cpt--;
#ifdef PONGD_VERBOSE
printf ("disconnection: %d clients remaining\n", cpt);
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;
// free the ipc_client structure
free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
#ifdef PONGD_VERBOSE
if (m->length > 0) {
printf ("message received (type %d, user type %d, size %u bytes): %.*s\n"
, m->type, m->user_type, m->length, m->length, m->payload);
}
else {
printf ("message with a 0-byte size :(\n");
}
if (m->length > 0) {
printf ("message received (type %d, user type %d, size %u bytes): %.*s\n",
m->type, m->user_type, m->length, m->length, m->payload);
} else {
printf ("message with a 0-byte size :(\n");
}
#endif
ret = ipc_write (event.origin, m);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server write");
}
printf ("message sent\n");
};
break;
case IPC_EVENT_TYPE_ERROR:
{
cpt--;
fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd);
fprintf (stderr, ", %d clients remaining\n", cpt);
ret = ipc_write (event.origin, m);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server write");
}
printf ("message sent\n");
};
break;
case IPC_EVENT_TYPE_TIMER:{
printf ("timer\n");
// free the ipc_client structure
free (event.origin);
};
break;
default :
{
fprintf (stderr, "there must be a problem, event not set\n");
};
timer = 10;
};
break;
case IPC_EVENT_TYPE_ERROR:
{
cpt--;
fprintf (stderr, "a problem happened with client %d (now disconnected)", (event.origin)->fd);
fprintf (stderr, ", %d clients remaining\n", cpt);
// free the ipc_client structure
free (event.origin);
};
break;
default:
{
fprintf (stderr, "there must be a problem, event not set\n");
};
}
}
}
// should never go there
exit (EXIT_FAILURE);
}
void exit_program(int signal)
void exit_program (int signal)
{
printf("Quitting, signal: %d\n", signal);
printf ("Quitting, signal: %d\n", signal);
// free remaining clients
for (size_t i = 0; i < clients->size ; i++) {
for (size_t i = 0; i < clients->size; i++) {
struct ipc_connection_info *cli = clients->cinfos[i];
if (cli != NULL) {
free (cli);
@ -127,15 +116,14 @@ void exit_program(int signal)
ipc_connections_free (clients);
free (clients);
// the application will shut down, and close the service
enum ipc_errors ret = ipc_server_close (srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server close");
}
// the application will shut down, and close the service
struct ipc_error ret = ipc_server_close (srv);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server close");
}
free (srv);
exit(EXIT_SUCCESS);
exit (EXIT_SUCCESS);
}
/*
@ -143,10 +131,10 @@ void exit_program(int signal)
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main(int argc, char * argv[], char **env)
int main (int argc, char *argv[], char **env)
{
argc = argc; // warnings
argv = argv; // warnings
argc = argc; // warnings
argv = argv; // warnings
printf ("pid = %d\n", getpid ());
@ -154,21 +142,21 @@ int main(int argc, char * argv[], char **env)
if (srv == NULL) {
exit (EXIT_FAILURE);
}
memset (srv, 0, sizeof (struct ipc_connection_info));
srv->type = '\0';
srv->index = 0;
srv->version = 0;
srv->fd = 0;
srv->spath = NULL;
memset (srv, 0, sizeof (struct ipc_connection_info));
srv->type = '\0';
srv->index = 0;
srv->version = 0;
srv->fd = 0;
srv->spath = NULL;
enum ipc_errors ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server init");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv->spath);
struct ipc_error ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR (ret, "server init");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv->spath);
printf("MAIN: server created\n" );
printf ("MAIN: server created\n");
signal (SIGHUP, exit_program);
signal (SIGALRM, exit_program);
@ -177,9 +165,9 @@ int main(int argc, char * argv[], char **env)
signal (SIGTERM, exit_program);
signal (SIGINT, exit_program);
// the service will loop until the end of time, or a signal
main_loop ();
// the service will loop until the end of time, or a signal
main_loop ();
// main_loop should not return
return EXIT_FAILURE;
return EXIT_FAILURE;
}

162
examples/pongspam.c Normal file
View File

@ -0,0 +1,162 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../src/ipc.h"
#define MSG "coucou"
#define SERVICE_NAME "pong"
#define PRINTERR(ret,msg) {\
const char * err = ipc_errors_get (ret);\
fprintf(stderr, "error while %s: %s\n", msg, err);\
}
void chomp (char *str, ssize_t len)
{
if (str[len - 1] == '\n') {
str[len - 1] = '\0';
}
if (str[len - 2] == '\n') {
str[len - 2] = '\0';
}
}
struct ipc_connection_info *srv;
void non_interactive (char *env[])
{
SECURE_DECLARATION (struct ipc_message, m);
// init service
TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_message_format_data (&m, 42, MSG, (ssize_t) strlen (MSG) + 1), EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen (MSG) + 1, (int)strlen (MSG), MSG);
TEST_IPC_Q (ipc_write (srv, &m), EXIT_FAILURE);
ipc_message_empty (&m);
TEST_IPC_Q (ipc_read (srv, &m), EXIT_FAILURE);
printf ("msg recv (type: %u): %s\n", m.user_type, m.payload);
ipc_message_empty (&m);
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
}
void interactive (char *env[])
{
// init service
TEST_IPC_Q (ipc_connection (env, srv, SERVICE_NAME), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_connections_print (&services);
long timer = 10;
while (1) {
printf ("msg to send: ");
fflush (stdout);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER:{
printf ("time up!\n");
timer = 10;
};
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// structure not read, should read the message here
ssize_t len;
char buf[4096];
memset (buf, 0, 4096);
len = read (event.origin->fd, buf, 4096);
buf[len - 1] = '\0';
chomp (buf, len);
#if 0
printf ("\n");
printf ("message to send: %.*s\n", (int)len, buf);
#endif
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
ipc_connections_free (&services);
exit (EXIT_SUCCESS);
}
// send the message read on STDIN
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION (m, sizeof (struct ipc_message),,);
for (size_t i = 0; i < 5; i++) {
memset (buf, 0, 4096);
snprintf (buf, 4096, "%lu", i);
len = strlen (buf);
printf ("message %lu, buffer %.*s\n", i, (int)len, buf);
TEST_IPC_Q (ipc_message_format_data (m, 42, buf, len), EXIT_FAILURE);
printf ("message from structure: %.*s\n", m->length, m->payload);
#if 0
printf ("\n");
printf ("right before sending a message\n");
#endif
TEST_IPC_Q (ipc_write (srv, m), EXIT_FAILURE);
#if 0
printf ("right after sending a message\n");
#endif
ipc_message_empty (m);
// sleep (1);
}
free (m);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
printf ("\rmsg recv: %.*s\n", 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
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));
// index and version should be filled
srv->index = 0;
srv->version = 0;
if (argc == 1)
non_interactive (env);
else
interactive (env);
return EXIT_SUCCESS;
}

30
examples/project.zsh Normal file
View File

@ -0,0 +1,30 @@
package=ipc-examples
version=0.5.0
CFLAGS="-Wall -Wextra -g"
LDFLAGS="-I../src -L../ ../src/ipc.h -lipc"
targets=(
fs-function-tests
fd-exchange-providing
fd-exchange-receiving
fs-experimentations
pong
pongd
pongspam
simple-tcp-client
simple-tcpd
test-ask-for-fd-to-networkd
test-networkd-provide-fd
wsserver
)
for i in $targets ; do
type[$i]=binary
sources[$i]="$i.c"
cflags[$i]="-std=c11"
done
dist=(Makefile project.zsh *.c)

View File

@ -9,7 +9,6 @@
#include <unistd.h>
#include <arpa/inet.h>
#include "../src/ipc.h"
#include "../src/utils.h"
@ -22,58 +21,57 @@
* 1 B | 4 B | 1 B | ]
*/
int connection(char *ipstr, int port)
int connection (char *ipstr, int port)
{
int sockfd;
SECURE_DECLARATION (struct sockaddr_in, server);
socklen_t addrlen;
// socket factory
T_PERROR_Q (((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1), "socket creation", EXIT_FAILURE);
T_PERROR_Q (((sockfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1), "socket creation", EXIT_FAILURE);
// init remote addr structure and other params
server.sin_family = AF_INET;
server.sin_port = htons(port);
addrlen = sizeof(struct sockaddr_in);
server.sin_port = htons (port);
addrlen = sizeof (struct sockaddr_in);
// get addr from command line and convert it
T_PERROR_Q ((inet_pton(AF_INET, ipstr, &server.sin_addr) <= 0), "inet_pton", EXIT_FAILURE);
T_PERROR_Q ((inet_pton (AF_INET, ipstr, &server.sin_addr) <= 0), "inet_pton", EXIT_FAILURE);
printf("Trying to connect to the remote host\n");
printf ("Trying to connect to the remote host\n");
T_PERROR_Q ((connect(sockfd, (struct sockaddr *) &server, addrlen) == -1), "connection", EXIT_FAILURE);
T_PERROR_Q ((connect (sockfd, (struct sockaddr *)&server, addrlen) == -1), "connection", EXIT_FAILURE);
printf("Connection OK\n");
printf ("Connection OK\n");
return sockfd;
}
void send_receive (int sockfd) {
void send_receive (int sockfd)
{
SECURE_BUFFER_DECLARATION (unsigned char, buf, BUFSIZ);
int paylen;
// first, send service name "pong"
// send string
T_PERROR_Q ((send(sockfd, "pong", 4, 0) == -1), "sending a message", EXIT_FAILURE);
T_PERROR_Q ((send (sockfd, "pong", 4, 0) == -1), "sending a message", EXIT_FAILURE);
printf ("message 'pong' sent\n");
T_PERROR_Q (((paylen = recv(sockfd, buf, BUFSIZ, 0)) <= 0), "cannot connect to networkd", EXIT_FAILURE);
T_PERROR_Q (((paylen = recv (sockfd, buf, BUFSIZ, 0)) <= 0), "cannot connect to networkd", EXIT_FAILURE);
print_hexa ("should be 'OK'", buf, paylen);
memset (buf, 0, BUFSIZ);
// 2 | 6 | 0 | "coucou"
// 1 B | 4 B | 1 | 6 B
ipc_message_raw_serialize ((char *) buf, MSG_TYPE_DATA, 42, "coucou", 6);
ipc_message_raw_serialize ((char *)buf, MSG_TYPE_DATA, 42, "coucou", 6);
print_hexa ("WAITING 10 seconds then message to send", buf, 12);
// sleep (1);
T_PERROR_Q ((send(sockfd, buf, 12, 0) == -1), "sending a message", EXIT_FAILURE);
T_PERROR_Q ((send (sockfd, buf, 12, 0) == -1), "sending a message", EXIT_FAILURE);
printf ("message 'coucou' sent\n");
memset (buf, 0, BUFSIZ);
// receiving a message
T_PERROR_Q ( ((paylen = recv (sockfd, buf, BUFSIZ, 0)) < 0), "receiving a message", EXIT_FAILURE);
T_PERROR_Q (((paylen = recv (sockfd, buf, BUFSIZ, 0)) < 0), "receiving a message", EXIT_FAILURE);
if (paylen == 0) {
fprintf (stderr, "error: disconnection from the server\n");
@ -81,27 +79,15 @@ void send_receive (int sockfd) {
}
print_hexa ("RECEIVED MESSAGE", buf, paylen);
#if 0
// send string
if(sendto(sockfd, , ), 0) == -1)
{
perror("sendto");
close(sockfd);
exit(EXIT_FAILURE);
}
#endif
}
int main(int argc, char * argv[])
int main (int argc, char *argv[])
{
char *ipstr = "127.0.0.1";
int port = 9000;
if (argc == 2) {
port = atoi (argv[1]);
}
else if (argc == 3) {
} else if (argc == 3) {
ipstr = argv[1];
port = atoi (argv[2]);
}
@ -110,11 +96,10 @@ int main(int argc, char * argv[])
send_receive (sockfd);
printf("Disconnection\n");
printf ("Disconnection\n");
// close the socket
close(sockfd);
close (sockfd);
return EXIT_SUCCESS;
}

View File

@ -1,4 +1,5 @@
#include "../src/ipc.h"
// #include "../src/log.h"
#include "../src/utils.h"
#include <signal.h>
@ -7,14 +8,15 @@
#include <sys/un.h>
#include <unistd.h>
#define CLOG_DEBUG(a, ...) LOG_DEBUG (""); LOG_DEBUG("\033[36m" a "\033[00m", #__VA_ARGS__); LOG_DEBUG ("")
#define CLOG_DEBUG(a, ...) LOG_DEBUG (""); LOG_DEBUG("\033[36m" a "\033[00m", #__VA_ARGS__); LOG_DEBUG ("")
void chomp (char *str, size_t len) {
if (str[len -1] == '\n') {
str[len -1] = '\0';
void chomp (char *str, size_t len)
{
if (str[len - 1] == '\n') {
str[len - 1] = '\0';
}
if (str[len -2] == '\n') {
str[len -2] = '\0';
if (str[len - 2] == '\n') {
str[len - 2] = '\0';
}
}
@ -50,18 +52,14 @@ void chomp (char *str, size_t len) {
#define SERVICE_NAME "simpletcp"
struct networkd * ctx;
struct networkd *ctx;
void handle_disconnection (int fd)
{
// disconnection
LOG_DEBUG ("CLOSE CONNECTION %d", fd);
int delfd;
delfd = ipc_switching_del (ctx->TCP_TO_IPC, fd);
if (delfd >= 0) {
LOG_DEBUG ("CLOSE RELATED CONNECTION %d", delfd);
close (delfd);
ipc_del_fd (ctx->clients, delfd);
}
@ -69,40 +67,38 @@ void handle_disconnection (int fd)
close (fd);
ipc_del_fd (ctx->clients, fd);
printf ("\n\n");
// printf ("TCP_TO_IPC\n");
ipc_switching_print (ctx->TCP_TO_IPC);
printf ("\n\n");
}
void tcp_connection (char **env, int fd)
{
SECURE_BUFFER_DECLARATION(char, buf, BUFSIZ);
SECURE_BUFFER_DECLARATION (char, buf, BUFSIZ);
ssize_t len = recv (fd, buf, BUFSIZ, 0);
if (len <= 0) {
handle_disconnection (fd);
return ;
return;
}
buf[len] = '\0';
// XXX: for testing purposes
chomp (buf, len);
LOG_DEBUG ("SHOULD CONNECT TO %s", buf);
// TODO: tests
T_PERROR_Q ( (send (fd, "OK", 2, 0) <= 0), "sending a message", EXIT_FAILURE);
T_PERROR_Q ((send (fd, "OK", 2, 0) <= 0), "sending a message", EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_connection_info, tcp_to_ipc_ci);
TIPC_F_Q (ipc_connection (env, &tcp_to_ipc_ci, buf), ("cannot connect to the service [%s]", buf), EXIT_FAILURE);
struct ipc_error ret = ipc_connection (env, &tcp_to_ipc_ci, buf);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s\n", ret.error_message);
exit (EXIT_FAILURE);
}
ipc_switching_add (ctx->TCP_TO_IPC, fd, tcp_to_ipc_ci.fd);
ipc_add_fd (ctx->clients, tcp_to_ipc_ci.fd);
LOG_DEBUG ("CONNECTION TO SERVICE client %d -> %d", fd, tcp_to_ipc_ci.fd);
}
int accept_new_client (int serverfd)
@ -111,7 +107,9 @@ int accept_new_client (int serverfd)
socklen_t addrlen = 0;
int sock_fd_client;
T_PERROR_Q (((sock_fd_client = accept(serverfd, (struct sockaddr *) &client, &addrlen)) == -1), "accept new client", EXIT_FAILURE);
T_PERROR_Q (((sock_fd_client =
accept (serverfd, (struct sockaddr *)&client, &addrlen)) == -1), "accept new client",
EXIT_FAILURE);
// adding a client
ipc_add_fd (ctx->clients, sock_fd_client);
@ -121,121 +119,129 @@ int accept_new_client (int serverfd)
void main_loop (int argc, char **argv, char **env)
{
argc = argc; // FIXME: useless
argc = argc; // FIXME: useless
int serverfd;
SECURE_DECLARATION (struct sockaddr_in, my_addr);
socklen_t addrlen;
// socket factory
T_PERROR_R (((serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1), "socket", );
if ((serverfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
perror ("socket");
return;
}
int yes = 1;
T_PERROR_R ((setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1), "setsockopt", );
if (setsockopt (serverfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int)) == -1) {
perror ("setsockopt");
return;
}
// init local addr structure and other params
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(atoi(argv[1]));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons (atoi (argv[1]));
my_addr.sin_addr.s_addr = INADDR_ANY;
addrlen = sizeof(struct sockaddr_in);
addrlen = sizeof (struct sockaddr_in);
// bind addr structure with socket
T_PERROR_R ((bind(serverfd, (struct sockaddr *) &my_addr, addrlen) == -1), "bind", );
if (bind (serverfd, (struct sockaddr *)&my_addr, addrlen) == -1) {
perror ("bind");
return;
}
// set the socket in passive mode (only used for accept())
// and set the list size for pending connection
T_PERROR_R ((listen(serverfd, 5) == -1), "listen", );
if (listen (serverfd, 5) == -1) {
perror ("listen");
return;
}
printf("Waiting for incomming connection\n");
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->clients, sizeof (struct ipc_connection_infos), , EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->clients, sizeof (struct ipc_connection_infos),, EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
printf ("adding serverfd to ctx->clients\n");
ipc_add_fd (ctx->clients, serverfd);
while(1) {
while (1) {
// ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL
TIPC_T_P_I_R (
/* function to test */ ipc_wait_event_networkd (ctx->clients, ctx->srv, &event, ctx->TCP_TO_IPC)
, /* error condition */ ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT
, /* to say on error */ "wait event"
, /* to do on error */ LOG_ERROR ("\033[31m error happened\033[00m"); TIPC_P (ipc_server_close (ctx->srv), "server close")
, /* return function */ return );
long timer = 10;
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event_networkd (ctx->clients, ctx->srv, &event, ctx->TCP_TO_IPC, &timer)
, EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_SWITCH:
{
printf ("switch happened\n");
}
break;
case IPC_EVENT_TYPE_TIMER:{
printf ("timed out!\n");
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// NEW CLIENT
if (event.origin->fd == serverfd) {
int sock_fd_client = accept_new_client (serverfd);
ctx->cpt++;
printf ("TCP connection: %d clients connected\n", ctx->cpt);
printf ("new TCP client has the fd %d\n", sock_fd_client);
}
// CLIENT IS TALKING
else {
tcp_connection (env, event.origin->fd);
}
}
break;
timer = 10;
}
break;
case IPC_EVENT_TYPE_SWITCH:{
printf ("switch happened\n");
}
break;
case IPC_EVENT_TYPE_CONNECTION:
{
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// NEW CLIENT
if (event.origin->fd == serverfd) {
int sock_fd_client = accept_new_client (serverfd);
ctx->cpt++;
printf ("connection: %d clients connected\n", ctx->cpt);
printf ("new client has the fd %d\n", (event.origin)->fd);
};
break;
printf ("TCP connection: %d clients connected\n", ctx->cpt);
printf ("new TCP client has the fd %d\n", sock_fd_client);
}
// CLIENT IS TALKING
else {
tcp_connection (env, event.origin->fd);
}
}
break;
case IPC_EVENT_TYPE_DISCONNECTION:
{
ctx->cpt--;
printf ("disconnection: %d clients remaining\n", ctx->cpt);
case IPC_EVENT_TYPE_CONNECTION:
{
ctx->cpt++;
printf ("connection: %d clients connected\n", ctx->cpt);
printf ("new client has the fd %d\n", (event.origin)->fd);
};
break;
// free the ipc_client structure
// if (event.origin != NULL)
// free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
if (m->length > 0) {
printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
}
case IPC_EVENT_TYPE_DISCONNECTION:
{
ctx->cpt--;
printf ("disconnection: %d clients remaining\n", ctx->cpt);
TIPC_P (ipc_write (event.origin, m), "server write");
};
break;
case IPC_EVENT_TYPE_ERROR:
fprintf (stderr, "a problem happened with client %d\n", (event.origin)->fd);
break;
default :
fprintf (stderr, "there must be a problem, event not set\n");
// free the ipc_client structure
// if (event.origin != NULL)
// free (event.origin);
};
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
if (m->length > 0) {
printf ("message received (type %d): %.*s\n", m->type, m->length, m->payload);
}
TEST_IPC_P (ipc_write (event.origin, m), "server write");
};
break;
case IPC_EVENT_TYPE_ERROR:
fprintf (stderr, "a problem happened with client %d\n", (event.origin)->fd);
break;
default:
fprintf (stderr, "there must be a problem, event not set\n");
}
}
}
// should never go there
exit (EXIT_FAILURE);
}
void exit_program(int signal)
void exit_program (int signal)
{
printf("Quitting, signal: %d\n", signal);
printf ("Quitting, signal: %d\n", signal);
// free remaining clients
for (size_t i = 0; i < ctx->clients->size ; i++) {
for (size_t i = 0; i < ctx->clients->size; i++) {
struct ipc_connection_info *cli = ctx->clients->cinfos[i];
if (cli != NULL) {
free (cli);
@ -245,8 +251,8 @@ void exit_program(int signal)
ipc_connections_free (ctx->clients);
// the application will shut down, and close the service
TIPC_P (ipc_server_close (ctx->srv), "server close");
// the application will shut down, and close the service
TEST_IPC_P (ipc_server_close (ctx->srv), "server close");
// free, free everything!
free (ctx->clients);
@ -255,7 +261,7 @@ void exit_program(int signal)
free (ctx->TCP_TO_IPC);
free (ctx);
exit(EXIT_SUCCESS);
exit (EXIT_SUCCESS);
}
/*
@ -263,37 +269,40 @@ void exit_program(int signal)
* stop the program on SIG{TERM,INT,ALRM,USR{1,2},HUP} signals
*/
int main(int argc, char * argv[], char **env)
int main (int argc, char *argv[], char **env)
{
// check the number of args on command line
if(argc != 2)
{
printf("USAGE: %s port_num\n", argv[0]);
exit(EXIT_FAILURE);
if (argc != 2) {
printf ("USAGE: %s port_num\n", argv[0]);
exit (EXIT_FAILURE);
}
printf ("pid = %d\n", getpid ());
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx, sizeof (struct networkd), , EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC, sizeof(struct ipc_switchings), , EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC->collection, sizeof(struct ipc_switching), , EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->srv, sizeof (struct ipc_connection_info), , EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx, sizeof (struct networkd) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC, sizeof (struct ipc_switchings) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->TCP_TO_IPC->collection, sizeof (struct ipc_switching) ,, EXIT_FAILURE);
SECURE_BUFFER_HEAP_ALLOCATION_Q (ctx->srv, sizeof (struct ipc_connection_info),, EXIT_FAILURE);
TIPC_P_R (ipc_server_init (env, ctx->srv, SERVICE_NAME), "server init", EXIT_FAILURE);
printf ("Listening on [%s].\n", ctx->srv->spath);
struct ipc_error ret = ipc_server_init (env, ctx->srv, SERVICE_NAME);
if (ret.error_code != IPC_ERROR_NONE) {
fprintf (stderr, "%s\n", ret.error_message);
return EXIT_FAILURE;
}
printf ("Listening on [%s].\n", ctx->srv->spath);
printf("MAIN: server created\n" );
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);
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 (argc, argv, env);
// the service will loop until the end of time, or a signal
main_loop (argc, argv, env);
// main_loop should not return
return EXIT_FAILURE;
return EXIT_FAILURE;
}

View File

@ -4,15 +4,12 @@
#include "../src/ipc.h"
#define DEFAULT_IPC_NETWORK "IPC_NETWORK=\"pong local:lolwat\""
int main(int argc, char * argv[])
int main (int argc, char *argv[])
{
(void)argc;
(void)argv;
(void) argc;
(void) argv;
enum ipc_errors ret;
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_connection_info, srv);
if (argc != 2) {
@ -22,25 +19,17 @@ int main(int argc, char * argv[])
char *service_name = argv[1];
// ask for a local service "pong"
// inform the network service that it's now named "lolwat"
char *ipc_network = getenv("IPC_NETWORK");
if (ipc_network == NULL) {
ipc_network = DEFAULT_IPC_NETWORK;
}
ret = ipc_contact_networkd (&srv, service_name);
ret = ipc_contact_networkd (&srv, service_name, ipc_network);
printf ("ret = %d\n", ret.error_code);
printf ("ret = %d\n", ret);
if (ret == 0 && srv.fd != 0) {
if (ret.error_code == IPC_ERROR_NONE && srv.fd != 0) {
printf ("Success\n");
}
else {
} else {
printf ("Ow. :(\n");
}
usock_close (srv.fd);
return EXIT_SUCCESS;
return EXIT_SUCCESS;
}

View File

@ -4,38 +4,35 @@
#include "../src/ipc.h"
int main(int argc, char * argv[], char *env[])
int main (int argc, char *argv[], char *env[])
{
(void)argc;
(void)argv;
(void) argc;
(void) argv;
enum ipc_errors ret;
SECURE_DECLARATION (struct ipc_error, ret);
SECURE_DECLARATION (struct ipc_connection_info, srv);
SECURE_DECLARATION (struct ipc_connection_info, client);
SECURE_DECLARATION (struct ipc_connection_info, contacted_service);
// service start
TIPC_P_RR (ipc_server_init (env, &srv, "network"), "Networkd cannot be initialized");
TEST_IPC_Q (ipc_server_init (env, &srv, "network"), EXIT_FAILURE);
printf ("service initialized, waiting for a client\n");
// accept a new client
TIPC_P_RR (ipc_accept (&srv, &client), "cannot accept the client during handle_new_connection");
TEST_IPC_Q (ipc_accept (&srv, &client), EXIT_FAILURE);
// TODO: read a message to know the requested service
SECURE_DECLARATION (struct ipc_message, msg);
ret = ipc_read (&client, &msg);
TEST_IPC_Q (ipc_read (&client, &msg), EXIT_FAILURE);
printf ("received message: %s\n", msg.payload);
/** TODO: contact the service */
printf ("WARNING: currently this program only ask for pong service %d\n", ret);
TIPC_P_RR (ipc_connection (env, &contacted_service, "pong"), "cannot connect to the requested service");
printf ("WARNING: currently this program only ask for pong service %d\n", ret.error_code);
TEST_IPC_Q (ipc_connection (env, &contacted_service, "pong"), EXIT_FAILURE);
ipc_provide_fd (client.fd, contacted_service.fd);
TIPC_P_RR (ipc_server_close (&srv), "Networkd cannot be stopped!!");
return EXIT_SUCCESS;
TEST_IPC_Q (ipc_server_close (&srv), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -1,16 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../src/ipc.h"
int main(void)
{
SECURE_BUFFER_DECLARATION (char, buffer, BUFSIZ);
log_get_logfile_name (buffer, BUFSIZ);
printf ("log: %s\n", buffer);
return EXIT_SUCCESS;
}

View File

@ -9,12 +9,13 @@
#define WEBSOCKETD_BULLSHIT
void chomp (char *str, ssize_t len) {
if (str[len -1] == '\n') {
str[len -1] = '\0';
void chomp (char *str, ssize_t len)
{
if (str[len - 1] == '\n') {
str[len - 1] = '\0';
}
if (str[len -2] == '\n') {
str[len -2] = '\0';
if (str[len - 2] == '\n') {
str[len - 2] = '\0';
}
}
@ -22,88 +23,91 @@ struct ipc_connection_info *srv;
void interactive (char *env[])
{
long timer = 10;
SECURE_BUFFER_DECLARATION (char, service_name, 100);
char *sn = getenv("PATH_TRANSLATED");
char *sn = getenv ("PATH_TRANSLATED");
if (sn != NULL) {
memcpy (service_name, sn, strlen(sn));
}
else {
memcpy (service_name, sn, strlen (sn));
} else {
fprintf (stderr, "cannot see PATH_TRANSLATED variable\n");
exit (EXIT_FAILURE);
}
// init service
TIPC_P_Q (ipc_connection (env, srv, service_name), "application connection", EXIT_FAILURE);
// init service
TEST_IPC_Q (ipc_connection (env, srv, service_name), EXIT_FAILURE);
SECURE_DECLARATION (struct ipc_event, event);
SECURE_DECLARATION (struct ipc_connection_infos, services);
ipc_add (&services, srv);
ipc_add_fd (&services, 0); // add STDIN
ipc_add_fd (&services, 0); // add STDIN
while (1) {
TIPC_P_Q (ipc_wait_event (&services, NULL, &event), "wait event", EXIT_FAILURE);
while (1) {
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// structure not read, should read the message here
SECURE_BUFFER_DECLARATION (char, buf, 4096);
ssize_t len;
case IPC_EVENT_TYPE_TIMER:{
fprintf (stderr, "time up!\n");
timer = 10;
};
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
// structure not read, should read the message here
SECURE_BUFFER_DECLARATION (char, buf, 4096);
ssize_t len;
len = read (event.origin->fd, buf, 4096);
len = read (event.origin->fd, buf, 4096);
// in case we want to quit the program
if ( len == 0
|| strncmp (buf, "quit", 4) == 0
|| strncmp (buf, "exit", 4) == 0) {
// in case we want to quit the program
if (len == 0 || strncmp (buf, "quit", 4) == 0 || strncmp (buf, "exit", 4) == 0) {
TIPC_P_Q (ipc_close (srv), "application close", EXIT_FAILURE);
TEST_IPC_Q (ipc_close (srv), EXIT_FAILURE);
ipc_connections_free (&services);
ipc_connections_free (&services);
exit (EXIT_SUCCESS);
}
// send the message read on STDIN
ssize_t len_sent = write (srv->fd, buf, len);
if (len_sent != len) {
fprintf (stderr, "cannot send the message %lu-byte message, sent %lu bytes"
, len, len_sent);
exit (EXIT_FAILURE);
}
exit (EXIT_SUCCESS);
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
SECURE_BUFFER_DECLARATION (char, buf, 4096);
uint32_t size;
size = ipc_message_raw_serialize (buf, m->type, m->user_type, m->payload, m->length);
// send the message read on STDIN
ssize_t len_sent = write (srv->fd, buf, len);
if (len_sent != len) {
fprintf (stderr, "cannot send the message %lu-byte message, sent %lu bytes",
len, len_sent);
exit (EXIT_FAILURE);
}
}
break;
case IPC_EVENT_TYPE_MESSAGE:
{
struct ipc_message *m = event.m;
SECURE_BUFFER_DECLARATION (char, buf, 4096);
uint32_t size;
size = ipc_message_raw_serialize (buf, m->type, m->user_type, m->payload, m->length);
write (1, buf, size);
write (1, buf, size);
#ifdef WEBSOCKETD_BULLSHIT
printf ("\n");
printf ("\n");
#endif
fflush (stdout);
};
break;
ERROR_CASE (IPC_EVENT_TYPE_DISCONNECTION, "main loop", "disconnection: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_NOT_SET , "main loop", "not set: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_CONNECTION , "main loop", "connection: should not happen");
// ERROR_CASE (IPC_EVENT_TYPE_ERROR , "main loop", "error");
default :
fprintf (stderr, "event type error: should not happen, event type %d\n", event.type);
fflush (stdout);
};
break;
ERROR_CASE (IPC_EVENT_TYPE_DISCONNECTION, "main loop", "disconnection: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_NOT_SET , "main loop", "not set: should not happen");
ERROR_CASE (IPC_EVENT_TYPE_CONNECTION , "main loop", "connection: should not happen");
// ERROR_CASE (IPC_EVENT_TYPE_ERROR , "main loop", "error");
default:
fprintf (stderr, "event type error: should not happen, event type %d\n", event.type);
}
}
}
}
int main (int argc, char *argv[], char *env[])
{
argc = argc; // warnings
argv = argv; // warnings
argc = argc; // warnings
argv = argv; // warnings
srv = malloc (sizeof (struct ipc_connection_info));
memset (srv, 0, sizeof (struct ipc_connection_info));

1
man/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.[0-9]

View File

@ -1,111 +0,0 @@
.TH COMMUNICATION.H 3 2016-12-20 "" "Linux Programmer's Manual"
.SH NAME
communication.h \- all functions explained
.SH SYNOPSIS
.nf
.B #include <communication.h>
.sp
.BI "int32_t ipc_server_init (int32_t "argc ", char **" argv ", char **" env ", struct ipc_service *" srv "
.BI " , const char *" service_name );
.BI "int32_t ipc_server_accept (struct ipc_service *" srv ", struct ipc_client *" p );
.sp
.BI "int32_t ipc_server_read (const struct ipc_client *" p ", struct ipc_message *" message );
.BI "int32_t ipc_server_write (const struct ipc_client *" p ", const struct ipc_message *" message );
.sp
.BI "int32_t ipc_server_close (struct ipc_service *" srv );
.BI "int32_t ipc_server_close_client (struct ipc_client *" p );
.BI "int32_t ipc_server_select (struct ipc_clients *" fds ", struct ipc_service *" srv ", struct ipc_clients *" readfds );
.BI "int32_t ipc_application_connection (int32_t " argc ", char **" argv ", char **" env ", struct ipc_service *" srv
.BI " , const char *" service_name "
.BI " , const char *" connection_buffer ", size_t " bufsize );
.sp
.BI "int32_t ipc_application_read (const struct ipc_service *" srv ", struct ipc_message *" message );
.BI "int32_t ipc_application_write (const struct ipc_service *" srv ", const struct ipc_message *" message );
.sp
.BI "int32_t ipc_application_close (struct ipc_service *" srv );
.fi
.SH DESCRIPTION
The
.BR ipc_server_init ()
function let the service declare itself, create a new unix socket and listen.
.I argc
,
.IR *argv
and
.IR *env
should be passed to the function in order to automatically change the behavior of the program without the application being modified.
.I *srv
is the pointer to the \fBstruct ipc_service\fR that should be filled (index and version parameters).
The \fBserver_init()\fR function will fill the rest of the elements of this structure, such as the unix socket path and the unix socket file descriptor in order to be able to receive new connections.
.PP
The
.BR ipc_server_accept ()
function accepts new connections.
.IR p
parameter is the client client that will be provided after the connection.
.PP
The
.BR ipc_server_read ()
and
.BR ipc_server_write ()
functions take respectively a message to read from, and a message to write to a client.
.PP
The
.BR ipc_server_close_client ()
and
.BR ipc_server_close ()
functions terminate respectively a client (closing its unix socket) and the service (closing and removing its named unix socket).
.PP
The
.BR ipc_server_select ()
takes three arguments,
.IR *ap
an array of clientes you want to listen on,
.IR *srv
the service which receives new connections and
.IR *ap_read
an array of clientes which have sent a message we need to read.
.PP
The
.BR ipc_application_connection ()
function takes
.I argc
,
.IR *argv
and
.IR *env
in argument for latter use.
It takes
.IR *srv
the pointer to the \fBstruct ipc_service\fR that should be filled (index and version parameters) and
will fill the rest of the elements of this structure, such as the unix socket path and the unix socket file descriptor of the service in order to be able to talk to it.
The function also takes
.IR *service_name
to deduce the pipe's name of the service.
Finally, the function takes
.IR *connection_buffer
and
.IR bufsize
arguments to send a buffer in the first message value for the connection, which is useful when the service needs configuration.
The function finally connects itself to the service.
\fBIn a near future, this function will be completed to invoke transparently the remote service\fR.
.PP
The
.BR ipc_application_read ()
and
.BR ipc_application_write ()
functions take respectively a message to read from, and a message to write to the service.
.PP
The
.BR ipc_application_close ()
function finally ends the communication to the service.
.SH RETURN VALUE
Most of the functions return an integer less than zero if there is an error.
.PP
For
.BR ipc_server_select()
if there is a new connection, the function will return \fBCONNECTION\fR, if there is one or more clientes talking the function will return \fBAPPLICATION\fR and finally if there are both a new connection and a client talking the function will return \fBCON_APP\fR.

View File

@ -2,7 +2,7 @@
#include <unistd.h>
#include <stdio.h>
#include <errno.h> // error numbers
#include <errno.h> // error numbers
#include <stdlib.h>
#include <string.h>
@ -10,304 +10,293 @@
#include "ipc.h"
#include "utils.h"
// FOR THE PURPOSE OF SOME EXPERIMENT
#include <sys/types.h>
#include <sys/socket.h>
// print structures
#include "message.h"
enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version)
struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version)
{
T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH);
T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME);
T_R ((path == NULL), IPC_ERROR_SERVICE_PATH__NO_PATH);
T_R ((sname == NULL), IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME);
memset (path, 0, PATH_MAX);
memset (path, 0, PATH_MAX);
char * rundir = getenv ("IPC_RUNDIR");
if (rundir == NULL)
rundir = RUNDIR;
char *rundir = getenv ("IPC_RUNDIR");
if (rundir == NULL)
rundir = RUNDIR;
snprintf (path, PATH_MAX-1, "%s/%s-%d-%d", rundir, sname, index, version);
snprintf (path, PATH_MAX - 1, "%s/%s-%d-%d", rundir, sname, index, version);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
static int32_t get_max_fd (struct ipc_connection_infos *cinfos)
{
size_t i;
int32_t max = 0;
size_t i;
int32_t max = 0;
for (i = 0; i < cinfos->size; i++ ) {
if (cinfos->cinfos[i]->fd > max) {
max = cinfos->cinfos[i]->fd;
}
}
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i]->fd > max) {
max = cinfos->cinfos[i]->fd;
}
}
return max;
return max;
}
enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname)
struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname)
{
T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM);
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
T_R ((env == NULL), IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM);
T_R ((sname == NULL), IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM);
#if 0
// For server init, no need for networkd evaluation
// TODO: loop over environment variables
// any IPC_NETWORK_* should be shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK_AUDIO="tor://some.example.com/"
for (size_t i = 0 ; env[i] != NULL ; i++) {
// TODO: loop over environment variables
// any IPC_NETWORK_* should be shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK_AUDIO="tor://some.example.com/"
for (size_t i = 0; env[i] != NULL; i++) {
// TODO: check for every IPC_NETWORK_* environment variable
}
#endif
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TIPC_P_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
// gets the service path
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
size_t s = strlen (buf);
SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s+1, , IPC_ERROR_SERVER_INIT__MALLOC);
memcpy (srv->spath, buf, s);
srv->spath[s] = '\0'; // to be sure
TIPC_F_RR (usock_init (&srv->fd, srv->spath), ("cannot init server %s", srv->spath) );
return IPC_ERROR_NONE;
}
enum ipc_errors ipc_write_fd (int fd, const struct ipc_message *m);
// when networkd is not working properly (or do not retrieve the service): srv->fd = 0
enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
{
T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM);
T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
char *networkvar = getenv("IPC_NETWORK");
if (networkvar == NULL) {
srv->fd = 0;
return IPC_ERROR_NONE;
// gets the service path
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
// TODO: is there another, more interesting way to do this?
// currently, IPC_NETWORK is shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong"
size_t s = strlen (buf);
SECURE_BUFFER_HEAP_ALLOCATION_R (srv->spath, s + 1,, IPC_ERROR_SERVER_INIT__MALLOC);
memcpy (srv->spath, buf, s);
srv->spath[s] = '\0'; // to be sure
TEST_IPC_RETURN_ON_ERROR (usock_init (&srv->fd, srv->spath));
IPC_RETURN_NO_ERROR;
}
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m);
// when networkd is not working properly (or do not retrieve the service): srv->fd = 0
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname)
{
T_R ((srv == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM);
T_R ((sname == NULL), IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM);
char *networkvar = getenv ("IPC_NETWORK");
if (networkvar == NULL) {
srv->fd = 0;
IPC_RETURN_NO_ERROR;
}
// TODO: is there another, more interesting way to do this?
// currently, IPC_NETWORK is shared with the network service
// in order to route requests over any chosen protocol stack
// ex: IPC_NETWORK="audio tor://some.example.com/audio ;pong tls://pong.example.com/pong"
// printf ("IPC_NETWORK: %s\n", networkvar);
SECURE_BUFFER_DECLARATION (char, columnthensname, BUFSIZ);
columnthensname[0] = ';';
memcpy (columnthensname +1, sname, strlen(sname));
memcpy (columnthensname + 1, sname, strlen (sname));
if (strncmp (networkvar, sname, strlen(sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
if (strncmp (networkvar, sname, strlen (sname)) != 0 && strstr (networkvar, columnthensname) == NULL) {
// printf ("sname %s not found\n", sname);
srv->fd = 0;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// printf ("(;)sname %s found\n", sname);
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TIPC_P_RR (service_path (buf, "network", 0, 0), "cannot get network service path");
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, "network", 0, 0), "cannot get network service path");
int networkdfd = 0;
TIPC_F_R (usock_connect (&networkdfd, buf), ("cannot initiates a connection [%s]", buf)
, IPC_ERROR_CONTACT_NETWORKD__NETWORKD);
TEST_IPC_RETURN_ON_ERROR (usock_connect (&networkdfd, buf));
SECURE_DECLARATION (struct ipc_message, msg);
msg.type = MSG_TYPE_NETWORK_LOOKUP;
msg.user_type = MSG_TYPE_NETWORK_LOOKUP;
SECURE_BUFFER_DECLARATION (char, content, BUFSIZ);
SECURE_BUFFER_DECLARATION (char, content, BUFSIZ);
snprintf (content, BUFSIZ, "%s;%s", sname, networkvar);
msg.length = strlen (content);
msg.payload = content;
TIPC_P_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
TEST_IPC_RR (ipc_write_fd (networkdfd, &msg), "cannot send a message to networkd");
enum ipc_errors ret = ipc_receive_fd (networkdfd, &srv->fd);
if (ret == IPC_ERROR_NONE) {
struct ipc_error ret = ipc_receive_fd (networkdfd, &srv->fd);
if (ret.error_code == IPC_ERROR_NONE) {
usock_close (networkdfd);
}
return ret;
}
enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname)
struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname)
{
T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER);
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
T_R ((env == NULL), IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_CONNECTION__NO_SERVER);
T_R ((sname == NULL), IPC_ERROR_CONNECTION__NO_SERVICE_NAME);
TIPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection");
TEST_IPC_P (ipc_contact_networkd (srv, sname), "error during networkd connection");
// if networkd did not initiate the connection
if (srv->fd <= 0) {
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TIPC_P_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
TIPC_F_RR (usock_connect (&srv->fd, buf), ("cannot initiates a connection [%s]", buf));
}
// gets the service path
SECURE_BUFFER_DECLARATION (char, buf, PATH_MAX);
TEST_IPC_RR (service_path (buf, sname, srv->index, srv->version), "cannot get server path");
TEST_IPC_RETURN_ON_ERROR (usock_connect (&srv->fd, buf));
}
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_server_close (struct ipc_connection_info *srv)
struct ipc_error ipc_server_close (struct ipc_connection_info *srv)
{
usock_close (srv->fd);
enum ipc_errors ret = usock_remove (srv->spath);
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
return ret;
usock_close (srv->fd);
struct ipc_error ret = usock_remove (srv->spath);
if (srv->spath != NULL) {
free (srv->spath);
srv->spath = NULL;
}
return ret;
}
enum ipc_errors ipc_close (struct ipc_connection_info *p)
struct ipc_error ipc_close (struct ipc_connection_info *p)
{
return usock_close (p->fd);
return usock_close (p->fd);
}
enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p)
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p)
{
T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM);
T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM);
T_R ((srv == NULL), IPC_ERROR_ACCEPT__NO_SERVICE_PARAM);
T_R ((p == NULL), IPC_ERROR_ACCEPT__NO_CLIENT_PARAM);
TIPC_P_R (usock_accept (srv->fd, &p->fd), "cannot accept fd", IPC_ERROR_ACCEPT);
p->type = IPC_CONNECTION_TYPE_IPC;
TEST_IPC_RR (usock_accept (srv->fd, &p->fd), "cannot accept IPC connection");
p->type = IPC_CONNECTION_TYPE_IPC;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// receive then format in an ipc_message structure
enum ipc_errors ipc_read (const struct ipc_connection_info *p, struct ipc_message *m)
struct ipc_error ipc_read (const struct ipc_connection_info *p, struct ipc_message *m)
{
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
T_R ((m == NULL), IPC_ERROR_READ__NO_MESSAGE_PARAM);
char *buf = NULL;
size_t msize = IPC_MAX_MESSAGE_SIZE;
char *buf = NULL;
size_t msize = IPC_MAX_MESSAGE_SIZE;
// on error or closed recipient, the buffer already freed
TIPC_NP_RR (usock_recv (p->fd, &buf, &msize));
TIPC_I_RR (ipc_message_format_read (m, buf, msize), if (buf != NULL) free (buf));
TEST_IPC_RETURN_ON_ERROR (usock_recv (p->fd, &buf, &msize));
TEST_IPC_RETURN_ON_ERROR_FREE (ipc_message_format_read (m, buf, msize), buf);
free (buf);
return IPC_ERROR_NONE; // propagates ipc_message_format return
IPC_RETURN_NO_ERROR; // propagates ipc_message_format return
}
enum ipc_errors ipc_write_fd (int fd, const struct ipc_message *m)
struct ipc_error ipc_write_fd (int fd, const struct ipc_message *m)
{
T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM);
T_R ((m == NULL), IPC_ERROR_WRITE__NO_MESSAGE_PARAM);
char *buf = NULL;
size_t msize = 0;
ipc_message_format_write (m, &buf, &msize);
char *buf = NULL;
size_t msize = 0;
ipc_message_format_write (m, &buf, &msize);
size_t nbytes_sent = 0;
TIPC_I_RR (usock_send (fd, buf, msize, &nbytes_sent), if (buf != NULL) free (buf));
size_t nbytes_sent = 0;
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (fd, buf, msize, &nbytes_sent), buf);
if (buf != NULL) {
free (buf);
}
if (buf != NULL) {
free (buf);
}
// what was sent != what should have been sent
T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA);
// what was sent != what should have been sent
T_R ((nbytes_sent != msize), IPC_ERROR_WRITE__NOT_ENOUGH_DATA);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m)
struct ipc_error ipc_write (const struct ipc_connection_info *p, const struct ipc_message *m)
{
return ipc_write_fd (p->fd, m);
}
enum ipc_errors handle_new_connection (struct ipc_connection_info *cinfo
, struct ipc_connection_infos *cinfos
, struct ipc_connection_info **new_client)
struct ipc_error handle_new_connection (struct ipc_connection_info *cinfo, struct ipc_connection_infos *cinfos
, struct ipc_connection_info **new_client)
{
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM);
T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
T_R ((cinfo == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM);
T_R ((cinfos == NULL), IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM);
SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof(struct ipc_connection_info), , IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
SECURE_BUFFER_HEAP_ALLOCATION_R (*new_client, sizeof (struct ipc_connection_info),,
IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC);
TIPC_P_RR (ipc_accept (cinfo, *new_client), "cannot accept the client during handle_new_connection");
TIPC_P_RR (ipc_add (cinfos, *new_client), "cannot add the new accepted client");
TEST_IPC_RR (ipc_accept (cinfo, *new_client), "cannot accept the client during handle_new_connection");
TEST_IPC_RR (ipc_add (cinfos, *new_client), "cannot add the new accepted client");
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// new connection from a client
enum ipc_errors handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos, struct ipc_connection_info *cinfo)
struct ipc_error handle_connection (struct ipc_event *event, struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo)
{
// connection
struct ipc_connection_info *new_client = NULL;
// connection
struct ipc_connection_info *new_client = NULL;
TIPC_P_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client");
TEST_IPC_RR (handle_new_connection (cinfo, cinfos, &new_client), "cannot add new client");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
return IPC_ERROR_NONE;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_CONNECTION, NULL, new_client);
IPC_RETURN_NO_ERROR;
}
// new message
enum ipc_errors handle_message (struct ipc_event *event
, struct ipc_connection_infos *cinfos
, struct ipc_connection_info *pc
, struct ipc_switchings *switchdb)
struct ipc_error handle_message (struct ipc_event *event, struct ipc_connection_infos *cinfos
, struct ipc_connection_info *pc, struct ipc_switchings *switchdb)
{
// if the socket is associated to another one for networkd
// read and write automatically and provide a new IPC_EVENT_TYPE indicating the switch
if (switchdb != NULL) {
if (switchdb != NULL) {
int talkingfd = pc->fd;
int correspondingfd = ipc_switching_get (switchdb, talkingfd);
if (correspondingfd != -1) {
char *buf = NULL;
size_t msize = 0;
TIPC_T_P_I_R (
/* function to test */ usock_recv (talkingfd, &buf, &msize)
, /* error condition */ ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT
, /* to say on error */ "error while receiving message from client"
, /* to do on error */ if (buf != NULL) free (buf) ;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc)
, /* return function */ return (ret));
TEST_IPC_T_P_I_R (
/* function to test */ usock_recv (talkingfd, &buf, &msize)
, /* error condition */ ret.error_code != IPC_ERROR_NONE
&& ret.error_code != IPC_ERROR_CLOSED_RECIPIENT
, /* to do on error */ if (buf != NULL) free (buf);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc)
, /* return function */ return (ret)) ;
/** TODO: there is a message, send it to the corresponding fd **/
if (msize > 0) {
size_t nbytes_sent = 0;
TIPC_I_RR (usock_send (correspondingfd, buf, msize, &nbytes_sent), if (buf != NULL) free (buf));
TEST_IPC_RETURN_ON_ERROR_FREE (usock_send (correspondingfd, buf, msize, &nbytes_sent), buf);
if (nbytes_sent != msize) {
LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd);
// LOG_ERROR ("wrote not enough data from %d to fd %d", talkingfd, correspondingfd);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
return IPC_ERROR_NONE; // FIXME: return something else, maybe?
IPC_RETURN_NO_ERROR; // FIXME: return something else, maybe?
}
LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd);
// LOG_DEBUG ("received a message on fd %d => switch to fd %d", talkingfd, correspondingfd);
if (buf != NULL)
free (buf);
// everything is OK: inform networkd of a successful transfer
IPC_EVENT_SET (event, IPC_EVENT_TYPE_SWITCH, NULL, pc);
return IPC_ERROR_NONE;
}
else if (msize == 0) {
IPC_RETURN_NO_ERROR;
} else if (msize == 0) {
int delfd;
delfd = ipc_switching_del (switchdb, talkingfd);
@ -319,107 +308,104 @@ enum ipc_errors handle_message (struct ipc_event *event
close (talkingfd);
ipc_del_fd (cinfos, talkingfd);
#if 0
if (delfd >= 0) {
LOG_DEBUG ("disconnection of %d (and related fd %d)", talkingfd, delfd);
}
else {
} else {
LOG_DEBUG ("disconnection of %d", talkingfd);
}
#endif
IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
return IPC_ERROR_CLOSED_RECIPIENT;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}
}
}
// no treatment of the socket if external socket
if (pc->type == IPC_CONNECTION_TYPE_EXTERNAL) {
IPC_EVENT_SET (event, IPC_EVENT_TYPE_EXTRA_SOCKET, NULL, pc);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
SECURE_DECLARATION (struct ipc_error, ret);
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof (struct ipc_message),, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY);
// current talking client
ret = ipc_read (pc, m);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
struct ipc_error rvalue = ret; // store the final return value
ipc_message_empty (m);
free (m);
// if there is a problem, just remove the client
TEST_IPC_P (ipc_close (pc), "cannot close a connection in handle_message");
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message");
IPC_EVENT_SET (event, IPC_EVENT_TYPE_ERROR, NULL, pc);
return rvalue;
}
// disconnection: close the client then delete it from cinfos
if (ret.error_code == IPC_ERROR_CLOSED_RECIPIENT) {
TEST_IPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message");
TEST_IPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message");
ipc_message_empty (m);
free (m);
IPC_EVENT_SET (event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
// warning: do not forget to free the ipc_client structure
IPC_RETURN_NO_ERROR;
}
// listen to what they have to say (disconnection or message)
// then add a client to `event`, the ipc_event structure
enum ipc_errors ret;
struct ipc_message *m = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (m, sizeof(struct ipc_message), , IPC_ERROR_NOT_ENOUGH_MEMORY);
// current talking client
ret = ipc_read (pc, m);
if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) {
enum ipc_errors rvalue = ret; // store the final return value
ipc_message_empty (m);
free (m);
// if there is a problem, just remove the client
TIPC_P (ipc_close (pc), "cannot close a connection in handle_message");
TIPC_P (ipc_del (cinfos, pc), "cannot delete a connection in handle_message");
IPC_EVENT_SET(event, IPC_EVENT_TYPE_ERROR, NULL, pc);
return rvalue;
}
// disconnection: close the client then delete it from cinfos
if (ret == IPC_ERROR_CLOSED_RECIPIENT) {
TIPC_P (ipc_close (pc), "cannot close a connection on closed recipient in handle_message");
TIPC_P (ipc_del (cinfos, pc), "cannot delete a connection on closed recipient in handle_message");
ipc_message_empty (m);
free (m);
IPC_EVENT_SET(event, IPC_EVENT_TYPE_DISCONNECTION, NULL, pc);
// warning: do not forget to free the ipc_client structure
return IPC_ERROR_NONE;
}
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc);
return IPC_ERROR_NONE;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_MESSAGE, m, pc);
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event
, struct ipc_switchings *switchdb
, long *timer /** TODO: timers */)
struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event, struct ipc_switchings *switchdb
, long *timer)
{
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
T_R ((cinfos == NULL), IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM);
T_R ((event == NULL), IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM);
IPC_EVENT_CLEAN(event);
IPC_EVENT_CLEAN (event);
size_t i, j;
/* master file descriptor list */
fd_set master;
fd_set readf;
size_t i, j;
/* master file descriptor list */
fd_set master;
fd_set readf;
/* clear the master and temp sets */
FD_ZERO(&master);
FD_ZERO(&readf);
/* clear the master and temp sets */
FD_ZERO (&master);
FD_ZERO (&readf);
/* maximum file descriptor number */
/* keep track of the biggest file descriptor */
int32_t fdmax = get_max_fd (cinfos);
/* maximum file descriptor number */
/* keep track of the biggest file descriptor */
int32_t fdmax = get_max_fd (cinfos);
/* listening socket descriptor */
int32_t listener;
if (cinfo != NULL) {
listener = cinfo->fd;
/* listening socket descriptor */
int32_t listener;
if (cinfo != NULL) {
listener = cinfo->fd;
/* add the listener to the master set */
FD_SET(listener, &master);
/* add the listener to the master set */
FD_SET (listener, &master);
// if listener is max fd
if (fdmax < listener)
fdmax = listener;
}
/* if listener is max fd */
if (fdmax < listener)
fdmax = listener;
}
for (i=0; i < cinfos->size; i++) {
FD_SET(cinfos->cinfos[i]->fd, &master);
}
for (i = 0; i < cinfos->size; i++) {
FD_SET (cinfos->cinfos[i]->fd, &master);
}
readf = master;
readf = master;
struct timeval *ptimeout = NULL;
SECURE_DECLARATION (struct timeval, timeout);
@ -429,205 +415,171 @@ enum ipc_errors ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
ptimeout = &timeout;
}
T_PERROR_R ((select(fdmax+1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT);
T_PERROR_RIPC ((select (fdmax + 1, &readf, NULL, NULL, ptimeout) == -1), "select", IPC_ERROR_WAIT_EVENT__SELECT);
if (ptimeout != NULL) {
*timer = timeout.tv_sec;
if (*timer == 0) {
IPC_EVENT_SET(event, IPC_EVENT_TYPE_TIMER, NULL, NULL);
return IPC_ERROR_NONE;
IPC_EVENT_SET (event, IPC_EVENT_TYPE_TIMER, NULL, NULL);
IPC_RETURN_NO_ERROR;
}
}
for (i = 0; i <= (size_t) fdmax; i++) {
if (FD_ISSET(i, &readf)) {
if (cinfo != NULL && i == (size_t) listener) {
return handle_connection (event, cinfos, cinfo);
} else {
for(j = 0; j < cinfos->size; j++) {
if(i == (size_t) cinfos->cinfos[j]->fd ) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
}
}
}
}
}
for (i = 0; i <= (size_t) fdmax; i++) {
if (FD_ISSET (i, &readf)) {
if (cinfo != NULL && i == (size_t) listener) {
return handle_connection (event, cinfos, cinfo);
} else {
for (j = 0; j < cinfos->size; j++) {
if (i == (size_t) cinfos->cinfos[j]->fd) {
return handle_message (event, cinfos, cinfos->cinfos[j], switchdb);
}
}
}
}
}
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_wait_event (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event
, long *timer)
struct ipc_error ipc_wait_event (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event, long *timer)
{
return ipc_wait_event_networkd (cinfos, cinfo, event, NULL, timer);
}
// store and remove only pointers on allocated structures
enum ipc_errors ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
struct ipc_error ipc_add (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
{
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
T_R ((cinfos == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENTS);
T_R ((p == NULL), IPC_ERROR_ADD__NO_PARAM_CLIENT);
cinfos->size++;
if (cinfos->size == 1 && cinfos->cinfos == NULL) {
// first allocation
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof(struct ipc_connection_info), , IPC_ERROR_ADD__MALLOC);
}
else {
cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size);
}
cinfos->size++;
if (cinfos->size == 1 && cinfos->cinfos == NULL) {
// first allocation
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfos->cinfos, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD__MALLOC);
} else {
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
}
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_ADD__EMPTY_LIST);
cinfos->cinfos[cinfos->size - 1] = p;
return IPC_ERROR_NONE;
cinfos->cinfos[cinfos->size - 1] = p;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
struct ipc_error ipc_del (struct ipc_connection_infos *cinfos, struct ipc_connection_info *p)
{
T_R ((cinfos == NULL), IPC_ERROR_DEL__NO_CLIENTS_PARAM);
T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST);
T_R ((p == NULL), IPC_ERROR_DEL__NO_CLIENT_PARAM);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL__EMPTY_LIST);
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i] == p) {
// TODO: possible memory leak if the ipc_connection_info is not free'ed
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size-1];
cinfos->size--;
if (cinfos->size == 0) {
ipc_connections_free (cinfos);
}
else {
cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size);
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i] == p) {
// TODO: possible memory leak if the ipc_connection_info is not free'ed
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size - 1];
cinfos->size--;
if (cinfos->size == 0) {
ipc_connections_free (cinfos);
} else {
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
if (cinfos->cinfos == NULL) {
return IPC_ERROR_DEL__EMPTIED_LIST;
}
}
if (cinfos->cinfos == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL__EMPTIED_LIST);
}
}
return IPC_ERROR_NONE;
}
}
IPC_RETURN_NO_ERROR;
}
}
return IPC_ERROR_DEL__CANNOT_FIND_CLIENT;
IPC_RETURN_ERROR (IPC_ERROR_DEL__CANNOT_FIND_CLIENT);
}
void ipc_connections_close (struct ipc_connection_infos *cinfos)
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size ; i++) {
ipc_close (cinfos->cinfos[i]);
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
ipc_close (cinfos->cinfos[i]);
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
}
void ipc_connections_free (struct ipc_connection_infos *cinfos)
void ipc_connections_free (struct ipc_connection_infos *cinfos)
{
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size ; i++) {
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
}
struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p)
{
T_R ((p == NULL), NULL);
struct ipc_connection_info * copy = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (copy, sizeof(struct ipc_connection_info), , NULL);
memcpy (copy, p, sizeof (struct ipc_connection_info));
return copy;
}
int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc_connection_info *p2)
{
return (p1->type == p2->type && p1->version == p2->version && p1->index == p2->index && p1->fd == p2->fd);
if (cinfos->cinfos != NULL) {
for (size_t i = 0; i < cinfos->size; i++) {
free (cinfos->cinfos[i]);
}
free (cinfos->cinfos);
cinfos->cinfos = NULL;
}
cinfos->size = 0;
}
// create the client service structure
enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version, int fd, char type)
struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version
, int fd, char type)
{
T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO);
T_R ((cinfo == NULL), IPC_ERROR_CONNECTION_GEN__NO_CINFO);
cinfo->type = type;
cinfo->version = version;
cinfo->index = index;
cinfo->fd = fd;
cinfo->type = type;
cinfo->version = version;
cinfo->index = index;
cinfo->fd = fd;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// add an arbitrary file descriptor to read
enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd)
struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd)
{
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
T_R ((cinfos == NULL), IPC_ERROR_ADD_FD__NO_PARAM_CINFOS);
struct ipc_connection_info *cinfo = NULL;
struct ipc_connection_info *cinfo = NULL;
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof(struct ipc_connection_info), , IPC_ERROR_NOT_ENOUGH_MEMORY);
SECURE_BUFFER_HEAP_ALLOCATION_R (cinfo, sizeof (struct ipc_connection_info),,
IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY);
ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL);
ipc_connection_gen (cinfo, 0, 0, fd, IPC_CONNECTION_TYPE_EXTERNAL);
return ipc_add (cinfos, cinfo);
return ipc_add (cinfos, cinfo);
}
// remove a connection from its file descriptor
enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd)
struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd)
{
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
T_R ((cinfos == NULL), IPC_ERROR_DEL_FD__NO_PARAM_CINFOS);
T_R ((cinfos->cinfos == NULL), IPC_ERROR_DEL_FD__EMPTY_LIST);
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i]->fd == fd) {
free (cinfos->cinfos[i]);
cinfos->size--;
if (cinfos->size == 0) {
// free cinfos->cinfos
ipc_connections_free (cinfos);
}
else {
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
cinfos->cinfos = realloc(cinfos->cinfos, sizeof(struct ipc_connection_info) * cinfos->size);
size_t i;
for (i = 0; i < cinfos->size; i++) {
if (cinfos->cinfos[i]->fd == fd) {
free (cinfos->cinfos[i]);
cinfos->size--;
if (cinfos->size == 0) {
// free cinfos->cinfos
ipc_connections_free (cinfos);
} else {
cinfos->cinfos[i] = cinfos->cinfos[cinfos->size];
cinfos->cinfos = realloc (cinfos->cinfos, sizeof (struct ipc_connection_info) * cinfos->size);
if (cinfos->cinfos == NULL) {
return IPC_ERROR_DEL_FD__EMPTIED_LIST;
}
}
if (cinfos->cinfos == NULL) {
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__EMPTIED_LIST);
}
}
return IPC_ERROR_NONE;
}
}
IPC_RETURN_NO_ERROR;
}
}
return IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT;
}
void ipc_connection_print (struct ipc_connection_info *cinfo)
{
T_R ((cinfo == NULL), );
LOG_DEBUG ("fd %d: index %d, version %d, type %c, path %s"
, cinfo->fd, cinfo->index, cinfo->version, cinfo->type
, (cinfo->spath == NULL) ? "-" : cinfo->spath);
}
void ipc_connections_print (struct ipc_connection_infos *cinfos)
{
for (size_t i = 0; i < cinfos->size; i++) {
ipc_connection_print(cinfos->cinfos[i]);
}
IPC_RETURN_ERROR (IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT);
}

View File

@ -3,125 +3,135 @@
#define NTAB(t) ((int) (sizeof (t) / sizeof (t)[0]))
struct ipc_errors_verbose {
enum ipc_errors error_code;
char * explanation_string;
enum ipc_error_code error_code;
char *explanation_string;
};
static struct ipc_errors_verbose ipc_errors_verbose [] = {
static struct ipc_errors_verbose ipc_errors_verbose[] = {
/* general errors */
{ IPC_ERROR_NONE, "no error" }
, { IPC_ERROR_NOT_ENOUGH_MEMORY, "not enough memory" }
, { IPC_ERROR_CLOSED_RECIPIENT, "closed recipient" }
{IPC_ERROR_NONE, "no error"}
, {IPC_ERROR_CLOSED_RECIPIENT, "closed recipient"}
, { IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param" }
, { IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM, "ipc_server_init: no service param" }
, { IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param" }
, { IPC_ERROR_SERVER_INIT__MALLOC, "ipc_server_init: error on malloc function" }
, {IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT,
"ipc_server_init: no directory for ipc and cannot to create it"}
, {IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR, "ipc_server_init: non writable directory for ipc"}
, { IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter" }
, { IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter" }
, { IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param" }
, { IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function" }
, {IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM, "ipc_server_init: no environment param"}
, {IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM , "ipc_server_init: no service param"}
, {IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM, "ipc_server_init: no server name param"}
, {IPC_ERROR_SERVER_INIT__MALLOC , "ipc_server_init: error on malloc function"}
, { IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo" }
, {IPC_ERROR_CONNECTION__NO_SERVER, "ipc_connection: no server parameter"}
, {IPC_ERROR_CONNECTION__NO_SERVICE_NAME, "ipc_connection: no service name parameter"}
, {IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM, "ipc_connection: no environment param"}
, {IPC_ERROR_USOCK_CONNECT__CONNECT, "ipc_connection: error on the connect function"}
, { IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param" }
, { IPC_ERROR_ACCEPT__NO_CLIENT_PARAM, "ipc_accept: no client param" }
, { IPC_ERROR_ACCEPT, "ipc_accept: error on accept function" }
, {IPC_ERROR_CONNECTION_GEN__NO_CINFO, "ipc_connection_gen: no cinfo"}
, { IPC_ERROR_RECEIVE_FD__RECVMSG, "ipc_receive_fd: recvmsg function" }
, { IPC_ERROR_RECEIVE_FD__NO_PARAM_FD, "ipc_receive_fd: no fd param" }
, { IPC_ERROR_PROVIDE_FD__SENDMSG, "ipc_provide_fd: sendmsg function" }
, {IPC_ERROR_ACCEPT__NO_SERVICE_PARAM, "ipc_accept: no service param"}
, {IPC_ERROR_ACCEPT__NO_CLIENT_PARAM , "ipc_accept: no client param"}
, { IPC_ERROR_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param" }
, { IPC_ERROR_WRITE__NOT_ENOUGH_DATA, "ipc_write: no enough data sent" }
, { IPC_ERROR_READ__NO_MESSAGE_PARAM, "ipc_read: no message param" }
, {IPC_ERROR_RECEIVE_FD__RECVMSG , "ipc_receive_fd: recvmsg function"}
, {IPC_ERROR_RECEIVE_FD__NO_PARAM_FD, "ipc_receive_fd: no fd param"}
, {IPC_ERROR_PROVIDE_FD__SENDMSG , "ipc_provide_fd: sendmsg function"}
, { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM, "ipc_handle_new_connection: no cinfo param" }
, { IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param" }
, {IPC_ERROR_WRITE__NO_MESSAGE_PARAM, "ipc_write: no message param"}
, {IPC_ERROR_WRITE__NOT_ENOUGH_DATA , "ipc_write: no enough data sent"}
, {IPC_ERROR_READ__NO_MESSAGE_PARAM , "ipc_read: no message param"}
, { IPC_ERROR_WAIT_EVENT__SELECT, "ipc_wait_event: error on the select function" }
, { IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param" }
, { IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM, "ipc_wait_event: no event param" }
, {IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY , "handle_message: not enough memory"}
, {IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM , "ipc_handle_new_connection: no cinfo param"}
, {IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM, "ipc_handle_new_connection: no cinfos param"}
, { IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM, "ipc_contact_networkd: no service name param"}
, { IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM, "ipc_contact_networkd: no server param"}
, { IPC_ERROR_CONTACT_NETWORKD__NETWORKD, "ipc_contact_networkd: cannot retrieve fd"}
, {IPC_ERROR_WAIT_EVENT__SELECT , "ipc_wait_event: error on the select function"}
, {IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM, "ipc_wait_event: no clients param"}
, {IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM , "ipc_wait_event: no event param"}
, { IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function" }
, {IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM, "ipc_contact_networkd: no service name param"}
, {IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM , "ipc_contact_networkd: no server param"}
, { IPC_ERROR_ADD__MALLOC, "ipc_add: first memory allocation failed" }
, { IPC_ERROR_ADD__EMPTY_LIST, "ipc_add: empty list: realloc failed" }
, { IPC_ERROR_ADD__NO_PARAM_CLIENTS, "ipc_add: no param client list" }
, { IPC_ERROR_ADD__NO_PARAM_CLIENT, "ipc_add: no param client" }
, {IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC, "ipc_handle_new_connection: error on malloc function"}
, { IPC_ERROR_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param" }
, { IPC_ERROR_ADD_FD__EMPTY_LIST, "ipc_add_fd: empty list after realloc (memory problem)" }
, {IPC_ERROR_ADD__MALLOC , "ipc_add: first memory allocation failed"}
, {IPC_ERROR_ADD__EMPTY_LIST , "ipc_add: empty list: realloc failed"}
, {IPC_ERROR_ADD__NO_PARAM_CLIENTS , "ipc_add: no param client list"}
, {IPC_ERROR_ADD__NO_PARAM_CLIENT , "ipc_add: no param client"}
, {IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY, "ipc_add_fd: not enough memory"}
, { IPC_ERROR_DEL_FD__NO_PARAM_CINFOS, "ipc_del_fd: no cinfos param" }
, { IPC_ERROR_DEL_FD__EMPTIED_LIST, "ipc_del_fd: empty list after realloc (memory problem)" }
, { IPC_ERROR_DEL_FD__EMPTY_LIST, "ipc_del_fd: empty list" }
, { IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user" }
, {IPC_ERROR_ADD_FD__NO_PARAM_CINFOS, "ipc_add_fd: no cinfos param"}
, { IPC_ERROR_DEL__EMPTY_LIST, "ipc_del: empty list" }
, { IPC_ERROR_DEL__EMPTIED_LIST, "ipc_del: cannot realloc" }
, { IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_del: cannot find client" }
, { IPC_ERROR_DEL__NO_CLIENTS_PARAM, "ipc_del: no clients param" }
, { IPC_ERROR_DEL__NO_CLIENT_PARAM, "ipc_del: no client param" }
, {IPC_ERROR_DEL_FD__NO_PARAM_CINFOS , "ipc_del_fd: no cinfos param"}
, {IPC_ERROR_DEL_FD__EMPTIED_LIST , "ipc_del_fd: empty list after realloc (memory problem)"}
, {IPC_ERROR_DEL_FD__EMPTY_LIST , "ipc_del_fd: empty list"}
, {IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT, "ipc_del_fd: cannot find user"}
, {IPC_ERROR_DEL__EMPTY_LIST , "ipc_del: empty list"}
, {IPC_ERROR_DEL__EMPTIED_LIST , "ipc_del: cannot realloc"}
, {IPC_ERROR_DEL__CANNOT_FIND_CLIENT, "ipc_del: cannot find client"}
, {IPC_ERROR_DEL__NO_CLIENTS_PARAM , "ipc_del: no clients param"}
, {IPC_ERROR_DEL__NO_CLIENT_PARAM , "ipc_del: no client param"}
/* unix socket */
, {IPC_ERROR_USOCK_SEND, "usock_send: cannot send message"}
, { IPC_ERROR_USOCK_SEND, "usock_send: cannot send message" }
, {IPC_ERROR_USOCK_CONNECT__SOCKET , "usock_connect: error on socket function"}
, {IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor"}
, {IPC_ERROR_USOCK_CONNECT__EMPTY_PATH , "usock_connect: empty path"}
, { IPC_ERROR_USOCK_CONNECT__SOCKET, "usock_connect: error on socket function" }
, { IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR, "usock_connect: wrong file descriptor" }
, { IPC_ERROR_USOCK_CONNECT__EMPTY_PATH, "usock_connect: empty path" }
, {IPC_ERROR_USOCK_CLOSE, "usock_close: close function"}
, { IPC_ERROR_USOCK_CLOSE, "usock_close: close function" }
, {IPC_ERROR_USOCK_REMOVE__UNLINK , "usock_remove: unlink function"}
, {IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found"}
, { IPC_ERROR_USOCK_REMOVE__UNLINK, "usock_remove: unlink function" }
, { IPC_ERROR_USOCK_REMOVE__NO_FILE, "usock_remove: file not found" }
, {IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor"}
, {IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor"}
, {IPC_ERROR_USOCK_INIT__EMPTY_PATH , "usock_init: empty path"}
, {IPC_ERROR_USOCK_INIT__BIND , "usock_init: error on bind function"}
, {IPC_ERROR_USOCK_INIT__LISTEN , "usock_init: error on listen function"}
, { IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR, "usock_init: no file descriptor" }
, { IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR, "usock_init: wrong file descriptor" }
, { IPC_ERROR_USOCK_INIT__EMPTY_PATH, "usock_init: empty path" }
, { IPC_ERROR_USOCK_INIT__BIND, "usock_init: error on bind function" }
, { IPC_ERROR_USOCK_INIT__LISTEN, "usock_init: error on listen function" }
, {IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor"}
, {IPC_ERROR_USOCK_ACCEPT , "ipc_usock_accept: error on accept function"}
, { IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR, "ipc_usock_accept: no path file descriptor" }
, { IPC_ERROR_USOCK_ACCEPT, "ipc_usock_accept: error on accept function" }
, {IPC_ERROR_USOCK_RECV__NO_BUFFER , "ipc_usock_recv: no buffer in usock_recv"}
, {IPC_ERROR_USOCK_RECV__NO_LENGTH , "ipc_usock_recv: no length in usock_recv"}
, {IPC_ERROR_USOCK_RECV , "ipc_usock_recv: cannot receive message in usock_recv"}
, {IPC_ERROR_USOCK_RECV__UNRECOGNIZED_ERROR, "ipc_usock_recv: unrecognized error during recv(2)"}
, {IPC_ERROR_USOCK_RECV__MESSAGE_SIZE , "ipc_usock_recv: message length > maximum allowed"}
, {IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION , "ipc_usock_recv: heap allocation failed"}
, { IPC_ERROR_USOCK_RECV__NO_BUFFER, "ipc_usock_recv: no buffer in usock_recv" }
, { IPC_ERROR_USOCK_RECV__NO_LENGTH, "ipc_usock_recv: no length in usock_recv" }
, { IPC_ERROR_USOCK_RECV, "ipc_usock_recv: cannot receive message in usock_recv" }
, { IPC_ERROR_USOCK_RECV__MESSAGE_SIZE, "ipc_usock_recv: message length > maximum allowed" }
, {IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH, "ipc_message_write: message is longer than accepted"}
, {IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM , "ipc_message_format: no message param"}
, {IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS , "ipc_message_format: inconsistent params"}
, {IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE , "ipc_message_format: length param > maximum allowed"}
, {IPC_ERROR_MESSAGE_FORMAT__HEAP_ALLOCATION , "ipc_message_format: heap allocation failed"}
, {IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message"}
, {IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size"}
, {IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer"}
/* message function errors */
, {IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message"}
, {IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER , "ipc_message_format_read: empty buffer"}
, {IPC_ERROR_MESSAGE_FORMAT_READ__PARAM_MESSAGE_SIZE,
"ipc_message_format_read: said buffer size (in parameter) > maximum allowed"}
, {IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE, "ipc_message_format: read message size is not correct"}
, {IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_TOO_LONG , "ipc_message_format: read message size > maximum allowed"}
, { IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH, "ipc_message_write: message is longer than accepted" }
, {IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list"}
, { IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM, "ipc_message_format: no message param" }
, { IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS, "ipc_message_format: inconsistent params" }
, { IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE, "ipc_message_format: length param > maximum allowed" }
, { IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE, "ipc_message_format: read message size > maximum allowed" }
, {IPC_ERROR_SERVICE_PATH__NO_PATH , "ipc_service_path: no path"}
, {IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME, "ipc_service_path: no service name"}
, { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE, "ipc_message_format_write: empty message" }
, { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE, "ipc_message_format_write: empty message size" }
, { IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER, "ipc_message_format_write: empty buffer" }
, {IPC_ERROR_MKDIR__CANNOT_CREATE_DIR, "mkdir_p_: cannot create a directory"}
, {IPC_ERROR_MKDIR__NAME_TOO_LONG , "mkdir_p_: path parameter has a too long name"}
, { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE, "ipc_message_format_read: empty message" }
, { IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER, "ipc_message_format_read: empty buffer" }
, { IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE, "ipc_message_format_read: message size > maximum allowed" }
, {IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY, "directory_setup_: path cannot be created"}
, { IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST, "ipc_message_empty: empty message list" }
, {IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE, "directory_setup_: directory not writable"}
, {IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM , "directory_setup_: no path param"}
};
const char * ipc_errors_get (enum ipc_errors e)
const char *ipc_errors_get (enum ipc_error_code e)
{
for (int i = 0 ; i < NTAB(ipc_errors_verbose) ; i++) {
for (int i = 0; i < NTAB (ipc_errors_verbose); i++) {
if (ipc_errors_verbose[i].error_code == e) {
return ipc_errors_verbose[i].explanation_string;
}

141
src/fs.c Normal file
View File

@ -0,0 +1,141 @@
#include <strings.h>
#include <assert.h>
// error_message_format
#include "utils.h"
#include "fs.h"
/**
Private functions finish with an underscore
*/
int exists_ (const char *path, struct stat *status)
{
assert (status != NULL);
return stat (path, status) == 0;
}
int is_directory_ (struct stat *status)
{
assert (status != NULL);
return S_ISDIR (status->st_mode);
}
int is_writable_ (struct stat *status)
{
assert (status != NULL);
// what is my effective uid?
uid_t uid = geteuid ();
gid_t gid = getegid ();
if (status->st_uid == uid) {
// does the user can write?
return (status->st_mode & S_IWUSR) != 0;
}
if (status->st_gid == gid) {
// does the group can write?
return (status->st_mode & S_IWGRP) != 0;
}
return (status->st_mode & S_IWOTH) != 0;
}
/** avoiding name clashes */
int dirname_ (const char *path, char *dname)
{
assert (dname != NULL);
char *last_slash = rindex (path, '/');
int pathlen = last_slash - path;
snprintf (dname, pathlen + 1, "%s", path);
return 0;
}
struct ipc_error mkdir_p_ (const char *path)
{
int dir_rights = 01750;
// notes:
// S_ISGID
// files and sub-directories are automatically in the same group of the root directory
// S_ISVTX = "sticky bit"
// files created in this dir can only be removed by the owner or the directory owner
// so in /tmp even people with writing rights cannot remove other's content
SECURE_BUFFER_DECLARATION (char, _path, BUFSIZ);
const size_t len = strlen (path);
char *p;
errno = 0;
/* copy the string so it becomes mutable */
if (len > sizeof (_path) - 1) {
errno = ENAMETOOLONG;
IPC_RETURN_ERROR (IPC_ERROR_MKDIR__NAME_TOO_LONG);
}
strcpy (_path, path);
/* loop over the string, each time we have a slash we can mkdir */
for (p = _path + 1; *p; p++) {
if (*p == '/') {
/**
truncate the path to conserve the path we want to create only
*/
*p = '\0';
if (mkdir (_path, dir_rights) != 0) {
if (errno != EEXIST)
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_MKDIR__CANNOT_CREATE_DIR
, "mkdir_p_: cannot create the directory %s", _path);
}
*p = '/';
}
}
if (mkdir (_path, dir_rights) != 0) {
// actually, in our code this error shouldn't be possible
// since it already has been tested
if (errno != EEXIST)
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_MKDIR__CANNOT_CREATE_DIR
, "mkdir: cannot create the directory %s", _path);
}
IPC_RETURN_NO_ERROR;
}
/** Paramater is the path of the file we want to create
* A trailing slash '/' is required if the full path is itself a directory we need to create.
*/
struct ipc_error directory_setup_ (const char *path)
{
T_R ((path == NULL), IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM);
SECURE_BUFFER_DECLARATION (char, dir, BUFSIZ);
dirname_ (path, dir);
SECURE_DECLARATION (struct stat, status);
/** If the directory doesn't exists, yet */
if (!exists_ (dir, &status)) {
/** create the whole path */
return mkdir_p_ (dir);
}
/** The path exists, is it a directory? */
if (!is_directory_ (&status)) {
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY
, "directory_setup_: path %s is not a directory", dir);
}
/** The path exists and it is a directory. Do we have the rights to write in it? */
if (!is_writable_ (&status)) {
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE
, "directory_setup_: directory %s is not writable", dir);
}
IPC_RETURN_NO_ERROR;
}

18
src/fs.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __FS_H__
#define __FS_H__
#include "ipc.h"
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
struct ipc_error mkdir_p_ (const char *path);
struct ipc_error directory_setup_ (const char *dir);
int exists_ (const char *path, struct stat *status);
int is_directory_ (struct stat *status);
int is_writable_ (struct stat *status);
int dirname_ (const char *path, char *dname);
#endif

609
src/ipc.h
View File

@ -6,7 +6,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h> // error numbers
#include <errno.h> // error numbers
#include <time.h>
/***
@ -15,13 +15,13 @@
#define RUNDIR "/run/ipc/"
#define PATH_MAX 4096
#define IPC_HEADER_SIZE 6
#define IPC_HEADER_SIZE 6
#define IPC_MAX_MESSAGE_SIZE 8000000-IPC_HEADER_SIZE
#define IPC_VERSION 4
#if ! defined(IPC_WITHOUT_ERRORS) && ! defined(IPC_WITH_ERRORS)
#define IPC_WITH_ERRORS 2
#define IPC_WITH_ERRORS 2
#endif
#define IPC_WITH_UNIX_SOCKETS
@ -29,80 +29,6 @@
#include "usocket.h"
#endif
/***
* grooming macros
**/
#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t));
#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size);
#define SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr,r) { p = malloc (len); if (p == NULL) { instr; r; } ; memset(p, 0, len); }
#define SECURE_BUFFER_HEAP_ALLOCATION_R(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, return r )
#define SECURE_BUFFER_HEAP_ALLOCATION_Q(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, exit(r))
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
// print error string
#define PRINT_ERR(code) const char *estr = ipc_errors_get (code); LOG_ERROR ("%s", estr);
#define PRINT_ERR_STR(code,err) { const char *estr = ipc_errors_get (code); LOG_ERROR ("%s - %s", err, estr); }
#else
#define PRINT_ERR(code)
#define PRINT_ERR_STR(code,err)
#endif
// Test macros, requiring the variable `enum ipc_errors ret`
// one macro to rule them all!
// 1. function to test
// 2. Test IPC error based (test itself)
// 3. Print error (then ipc-error message)
// 4. Instructions to exec on failure
// 5. Return something
#define TIPC_T_P_I_R(f, t, err, instr, r) { enum ipc_errors ret = f;\
if (t) {\
PRINT_ERR_STR(ret, err); \
instr;\
r;\
} }
// P = print somehting with LOG_ERROR
// NP = no LOG_ERROR print
// R = return r param
// RR = return "ret" variable
// RV = return void
// Q = quit
// I = additionnal instructions before returning on error
#define TIPC_P_I_R(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, return r)
#define TIPC_P_I_Q(f, t, err, instr, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, instr, quit(r))
#define TIPC_P_Q(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, exit(r))
#define TIPC_P_R(f, err,r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, return r)
#define TIPC_P_RR(f, err) TIPC_P_R(f,err,ret)
#define TIPC_F_RR(f, format) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return ret)
#define TIPC_F_Q(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, exit(r))
#define TIPC_F_R(f, format, r) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", LOG_ERROR format ;, return r)
#define TIPC_P_RV(f, err) TIPC_P_R(f,err,;)
#define TIPC_P(f, err) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, err, ;, ;)
#define TIPC_T_I_P_Q(f,t,instr,err,r) TIPC_T_P_I_R(f, t, err, instr, exit(r))
#define TIPC_T_I_RR(f,t,instr) TIPC_T_P_I_R(f, t, "", instr, return ret)
#define TIPC_I_RR(f,instr) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", instr, return ret)
#define TIPC_RR(f) TIPC_T_P_I_R(f, ret != IPC_ERROR_NONE, "", ;, return ret)
#define TIPC_NP_RR(f) { enum ipc_errors ret = f; if (ret != IPC_ERROR_NONE) { return ret; } }
// Tests macros, do not require `enum ipc_errors ret` variable
// test => return error code
#define T_R(t,r) if t { return r; }
// test => perror, formatted message then return (for system functions)
#define T_PERROR_F_R(t,m,fmt,r) if t { perror(m); LOG_ERROR fmt; return r; }
// test => perror then return (for system functions)
#define T_PERROR_R(t,m,r) if t { perror(m); return r; }
// test => perror then exit (for system functions)
#define T_PERROR_Q(t,m,r) if t { perror(m); exit(r); }
// Switch cases macros
// print on error
#define ERROR_CASE(e,f,m) case e : { LOG_ERROR ("function %s: %s", f, m); } break;
/***
* structures and enumerations
**/
@ -114,154 +40,177 @@ enum msg_types {
, MSG_TYPE_NETWORK_LOOKUP = 3
} message_types;
/**
* Event types.
* In the main event loop, servers and clients can receive connections,
* disconnections, errors or messages from their pairs. They also can
* set a timer so the loop will allow a periodic routine (sending ping
* messages for websockets, for instance).
*
**
*
* A few other events can occur.
*
* Extra socket
* The main loop waiting for an event can be used as an unique entry
* point for socket management. libipc users can register sockets via
* ipc_add_fd allowing them to trigger an event, so events unrelated
* to libipc are managed the same way.
* Switch
* libipc can be used to create protocol-related programs, such as a
* websocket proxy allowing libipc services to be accessible online.
* To help those programs (with TCP-complient sockets), two sockets
* can be bound together, each message coming from one end will be
* automatically transfered to the other socket and a Switch event
* will be triggered.
* Look Up
* When a client establishes a connection to a service, it asks the
* ipc daemon (ipcd) to locate the service and establish a connection
* to it. This is a lookup.
*/
enum ipc_event_type {
IPC_EVENT_TYPE_NOT_SET = 0
, IPC_EVENT_TYPE_ERROR = 1
, IPC_EVENT_TYPE_EXTRA_SOCKET = 2
, IPC_EVENT_TYPE_SWITCH = 3
, IPC_EVENT_TYPE_CONNECTION = 4
, IPC_EVENT_TYPE_DISCONNECTION = 5
, IPC_EVENT_TYPE_MESSAGE = 6
, IPC_EVENT_TYPE_LOOKUP = 7
, IPC_EVENT_TYPE_TIMER = 8
IPC_EVENT_TYPE_NOT_SET = 0
, IPC_EVENT_TYPE_ERROR = 1
, IPC_EVENT_TYPE_EXTRA_SOCKET = 2
, IPC_EVENT_TYPE_SWITCH = 3
, IPC_EVENT_TYPE_CONNECTION = 4
, IPC_EVENT_TYPE_DISCONNECTION = 5
, IPC_EVENT_TYPE_MESSAGE = 6
, IPC_EVENT_TYPE_LOOKUP = 7
, IPC_EVENT_TYPE_TIMER = 8
};
enum ipc_errors {
/* general errors */
/**
* Error codes.
* libipc tend to use unique error codes in the whole library, allowing easier debugging.
*/
enum ipc_error_code {
IPC_ERROR_NONE = 0
, IPC_ERROR_NOT_ENOUGH_MEMORY = 1
, IPC_ERROR_CLOSED_RECIPIENT = 2
, IPC_ERROR_SERVICE_PATH__NO_PATH = 3
, IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME = 4
, IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM = 5
, IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM = 6
, IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 7
, IPC_ERROR_SERVER_INIT__MALLOC = 8
, IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 9
, IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 10
, IPC_ERROR_READ__NO_MESSAGE_PARAM = 11
, IPC_ERROR_CONNECTION__NO_SERVER = 12
, IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 13
, IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 14
, IPC_ERROR_CONNECTION_GEN__NO_CINFO = 15
, IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 16
, IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 17
, IPC_ERROR_ACCEPT = 18
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 19
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM = 20
, IPC_ERROR_WAIT_EVENT__SELECT = 21
, IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM = 22
, IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM = 23
, IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC = 24
, IPC_ERROR_ADD__EMPTY_LIST = 25
, IPC_ERROR_ADD__NO_PARAM_CLIENTS = 26
, IPC_ERROR_ADD__NO_PARAM_CLIENT = 27
, IPC_ERROR_ADD__MALLOC = 28
, IPC_ERROR_ADD_FD__NO_PARAM_CINFOS = 29
, IPC_ERROR_ADD_FD__EMPTY_LIST = 30
, IPC_ERROR_DEL_FD__NO_PARAM_CINFOS = 31
, IPC_ERROR_DEL_FD__EMPTIED_LIST = 32
, IPC_ERROR_DEL_FD__EMPTY_LIST = 33
, IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 34
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 35
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 36
, IPC_ERROR_CONTACT_NETWORKD__NETWORKD = 37
, IPC_ERROR_SERVER_INIT__NON_WRITABLE_DIR = 1
, IPC_ERROR_SERVER_INIT__NO_DIR_CANNOT_CREATE_IT = 2
, IPC_ERROR_HANDLE_MESSAGE__NOT_ENOUGH_MEMORY = 3
, IPC_ERROR_CLOSED_RECIPIENT = 4
, IPC_ERROR_SERVICE_PATH__NO_PATH = 5
, IPC_ERROR_SERVICE_PATH__NO_SERVICE_NAME = 6
, IPC_ERROR_SERVER_INIT__NO_ENVIRONMENT_PARAM = 7
, IPC_ERROR_SERVER_INIT__NO_SERVICE_PARAM = 8
, IPC_ERROR_SERVER_INIT__NO_SERVER_NAME_PARAM = 9
, IPC_ERROR_SERVER_INIT__MALLOC = 10
, IPC_ERROR_WRITE__NO_MESSAGE_PARAM = 11
, IPC_ERROR_WRITE__NOT_ENOUGH_DATA = 12
, IPC_ERROR_READ__NO_MESSAGE_PARAM = 13
, IPC_ERROR_CONNECTION__NO_SERVER = 14
, IPC_ERROR_CONNECTION__NO_SERVICE_NAME = 15
, IPC_ERROR_CONNECTION__NO_ENVIRONMENT_PARAM = 16
, IPC_ERROR_CONNECTION_GEN__NO_CINFO = 17
, IPC_ERROR_ACCEPT__NO_SERVICE_PARAM = 18
, IPC_ERROR_ACCEPT__NO_CLIENT_PARAM = 19
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFO_PARAM = 20
, IPC_ERROR_HANDLE_NEW_CONNECTION__NO_CINFOS_PARAM = 21
, IPC_ERROR_WAIT_EVENT__SELECT = 22
, IPC_ERROR_WAIT_EVENT__NO_CLIENTS_PARAM = 23
, IPC_ERROR_WAIT_EVENT__NO_EVENT_PARAM = 24
, IPC_ERROR_HANDLE_NEW_CONNECTION__MALLOC = 25
, IPC_ERROR_ADD__EMPTY_LIST = 26
, IPC_ERROR_ADD__NO_PARAM_CLIENTS = 27
, IPC_ERROR_ADD__NO_PARAM_CLIENT = 28
, IPC_ERROR_ADD__MALLOC = 29
, IPC_ERROR_ADD_FD__NO_PARAM_CINFOS = 30
, IPC_ERROR_ADD_FD__NOT_ENOUGH_MEMORY = 31
, IPC_ERROR_DEL_FD__NO_PARAM_CINFOS = 32
, IPC_ERROR_DEL_FD__EMPTIED_LIST = 33
, IPC_ERROR_DEL_FD__EMPTY_LIST = 34
, IPC_ERROR_DEL_FD__CANNOT_FIND_CLIENT = 35
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVICE_NAME_PARAM = 36
, IPC_ERROR_CONTACT_NETWORKD__NO_SERVER_PARAM = 37
, IPC_ERROR_DEL__EMPTY_LIST = 38
, IPC_ERROR_DEL__EMPTIED_LIST = 39
, IPC_ERROR_DEL__CANNOT_FIND_CLIENT = 40
, IPC_ERROR_DEL__NO_CLIENTS_PARAM = 41
, IPC_ERROR_DEL__NO_CLIENT_PARAM = 42
/* unix socket */
, IPC_ERROR_USOCK_SEND = 1
, IPC_ERROR_USOCK_CONNECT__SOCKET = 43
, IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR = 44
, IPC_ERROR_USOCK_CONNECT__EMPTY_PATH = 45
, IPC_ERROR_USOCK_CONNECT__CONNECT = 46
, IPC_ERROR_USOCK_CLOSE = 47
, IPC_ERROR_USOCK_REMOVE__UNLINK = 48
, IPC_ERROR_USOCK_REMOVE__NO_FILE = 49
, IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR = 50
, IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR = 51
, IPC_ERROR_USOCK_INIT__EMPTY_PATH = 52
, IPC_ERROR_USOCK_INIT__BIND = 53
, IPC_ERROR_USOCK_INIT__LISTEN = 54
, IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR = 55
, IPC_ERROR_USOCK_ACCEPT = 56
, IPC_ERROR_USOCK_RECV__NO_BUFFER = 57
, IPC_ERROR_USOCK_RECV__NO_LENGTH = 58
, IPC_ERROR_USOCK_RECV = 59
, IPC_ERROR_USOCK_RECV__MESSAGE_SIZE = 60
, IPC_ERROR_RECEIVE_FD__NO_PARAM_FD = 61
, IPC_ERROR_RECEIVE_FD__RECVMSG = 62
, IPC_ERROR_PROVIDE_FD__SENDMSG = 63
/* message function errors */
, IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH = 64
, IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE = 65
, IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM = 66
, IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS = 67
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE = 68
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE = 69
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER = 70
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE = 71
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER = 72
, IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE = 73
, IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE = 74
, IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST = 75
, IPC_ERROR_USOCK_SEND = 43
, IPC_ERROR_USOCK_CONNECT__SOCKET = 44
, IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR = 45
, IPC_ERROR_USOCK_CONNECT__EMPTY_PATH = 46
, IPC_ERROR_USOCK_CONNECT__CONNECT = 47
, IPC_ERROR_USOCK_CLOSE = 48
, IPC_ERROR_USOCK_REMOVE__UNLINK = 49
, IPC_ERROR_USOCK_REMOVE__NO_FILE = 50
, IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR = 51
, IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR = 52
, IPC_ERROR_USOCK_INIT__EMPTY_PATH = 53
, IPC_ERROR_USOCK_INIT__BIND = 54
, IPC_ERROR_USOCK_INIT__LISTEN = 55
, IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR = 56
, IPC_ERROR_USOCK_ACCEPT = 57
, IPC_ERROR_USOCK_RECV__NO_BUFFER = 58
, IPC_ERROR_USOCK_RECV__NO_LENGTH = 59
, IPC_ERROR_USOCK_RECV = 60
, IPC_ERROR_USOCK_RECV__UNRECOGNIZED_ERROR = 61
, IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION = 62
, IPC_ERROR_USOCK_RECV__MESSAGE_SIZE = 63
, IPC_ERROR_RECEIVE_FD__NO_PARAM_FD = 64
, IPC_ERROR_RECEIVE_FD__RECVMSG = 65
, IPC_ERROR_PROVIDE_FD__SENDMSG = 66
, IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH = 67
, IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE = 68
, IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM = 69
, IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS = 70
, IPC_ERROR_MESSAGE_FORMAT__HEAP_ALLOCATION = 71
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE = 72
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE = 73
, IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER = 74
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE = 75
, IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER = 76
, IPC_ERROR_MESSAGE_FORMAT_READ__PARAM_MESSAGE_SIZE = 77
, IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE = 78
, IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_TOO_LONG = 79
, IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST = 80
, IPC_ERROR_MKDIR__CANNOT_CREATE_DIR = 81
, IPC_ERROR_MKDIR__NAME_TOO_LONG = 82
, IPC_ERROR_DIR_SETUP__NOT_A_DIRECTORY = 83
, IPC_ERROR_DIR_SETUP__DIRECTORY_NOT_WRITABLE = 84
, IPC_ERROR_DIRECTORY_SETUP__PATH_PARAM = 85
};
struct ipc_error {
enum ipc_error_code error_code;
char error_message[BUFSIZ];
};
// get explanation about an error
// This only returns the generic error based on its code.
// Library's users have a more meaningful insight on the error
// with the error_message string in the ipc_error structure.
const char *ipc_errors_get (enum ipc_error_code e);
struct ipc_connection_info {
uint32_t version;
uint32_t index;
int32_t fd;
char type; // server, client, arbitrary fd
char *spath; // max size: PATH_MAX
uint32_t version;
uint32_t index;
int32_t fd;
char type; // server, client, arbitrary fd
char *spath; // max size: PATH_MAX
};
struct ipc_connection_infos {
struct ipc_connection_info ** cinfos;
struct ipc_connection_info **cinfos;
size_t size;
};
struct ipc_message {
char type;
char user_type;
uint32_t length;
char *payload;
char type;
char user_type;
uint32_t length;
char *payload;
};
struct ipc_event {
enum ipc_event_type type;
struct ipc_connection_info *origin;
void* m; // message pointer
void *m; // message pointer
};
/***
* logging macros
**/
#ifdef IPC_WITH_ERRORS
#include "logger.h"
// XXX: ##__VA_ARGS__ is a GNU extension to avoid requiring more arguments
#define LOG_ERROR(format, ...) log_error ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ )
#define LOG_INFO(format, ...) log_info ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ )
#else
#define LOG_ERROR(format, ...)
#define LOG_INFO(format, ...)
#endif
#if IPC_WITH_ERRORS > 2
#define LOG_DEBUG(format, ...) log_debug ( __FILE__ ":%d:" format, __LINE__, ##__VA_ARGS__ )
#else
#define LOG_DEBUG(format, ...)
#endif
/***
* ipc event macros
**/
@ -273,7 +222,7 @@ struct ipc_event {
};
enum ipc_connection_types {
IPC_CONNECTION_TYPE_IPC = 0
IPC_CONNECTION_TYPE_IPC = 0
, IPC_CONNECTION_TYPE_EXTERNAL = 1
};
@ -286,87 +235,70 @@ enum ipc_connection_types {
}\
};
/***
* logging functions
**/
void log_error (const char* message, ...);
void log_info (const char* message, ...);
void log_debug (const char* message, ...);
/**
* main public functions
**/
enum ipc_errors ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname);
enum ipc_errors ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname);
struct ipc_error ipc_server_init (char **env, struct ipc_connection_info *srv, const char *sname);
struct ipc_error ipc_connection (char **env, struct ipc_connection_info *srv, const char *sname);
enum ipc_errors ipc_server_close (struct ipc_connection_info *srv);
enum ipc_errors ipc_close (struct ipc_connection_info *p);
struct ipc_error ipc_server_close (struct ipc_connection_info *srv);
struct ipc_error ipc_close (struct ipc_connection_info *p);
enum ipc_errors ipc_read (const struct ipc_connection_info *, struct ipc_message *m);
enum ipc_errors ipc_write (const struct ipc_connection_info *, const struct ipc_message *m);
struct ipc_error ipc_read (const struct ipc_connection_info *, struct ipc_message *m);
struct ipc_error ipc_write (const struct ipc_connection_info *, const struct ipc_message *m);
enum ipc_errors ipc_wait_event (struct ipc_connection_infos *clients
, struct ipc_connection_info *srv
, struct ipc_event *event
, long *timer);
struct ipc_error ipc_wait_event (struct ipc_connection_infos *clients
, struct ipc_connection_info *srv
, struct ipc_event *event, long *timer);
// store and remove only pointers on allocated structures
enum ipc_errors ipc_add (struct ipc_connection_infos *, struct ipc_connection_info *);
enum ipc_errors ipc_del (struct ipc_connection_infos *, struct ipc_connection_info *);
struct ipc_error ipc_add (struct ipc_connection_infos *, struct ipc_connection_info *);
struct ipc_error ipc_del (struct ipc_connection_infos *, struct ipc_connection_info *);
// add an arbitrary file descriptor to read
enum ipc_errors ipc_add_fd (struct ipc_connection_infos *cinfos, int fd);
enum ipc_errors ipc_del_fd (struct ipc_connection_infos *cinfos, int fd);
struct ipc_error ipc_add_fd (struct ipc_connection_infos *cinfos, int fd);
struct ipc_error ipc_del_fd (struct ipc_connection_infos *cinfos, int fd);
void ipc_connections_free (struct ipc_connection_infos *);
void ipc_connections_free (struct ipc_connection_infos *);
struct ipc_connection_info * ipc_connection_copy (const struct ipc_connection_info *p);
int8_t ipc_connection_eq (const struct ipc_connection_info *p1, const struct ipc_connection_info *p2);
// create the client service structure
enum ipc_errors ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version, int fd, char type);
void ipc_connection_print (struct ipc_connection_info *cinfo);
void ipc_connections_print (struct ipc_connection_infos *cinfos);
void ipc_connections_close (struct ipc_connection_infos *cinfos);
// get explanation about an error
const char * ipc_errors_get (enum ipc_errors e);
struct ipc_error ipc_connection_gen (struct ipc_connection_info *cinfo
, uint32_t index, uint32_t version
, int fd, char type);
void ipc_connections_close (struct ipc_connection_infos *cinfos);
/***
* message functions
**/
uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size);
uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char *message, uint32_t message_size);
// used to create msg structure from buffer
enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize);
struct ipc_error ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize);
// used to create buffer from msg structure
enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize);
struct ipc_error ipc_message_format_write (const struct ipc_message *m, char **buf, size_t * msize);
enum ipc_errors ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length);
enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length);
enum ipc_errors ipc_message_format_server_close (struct ipc_message *m);
enum ipc_errors ipc_message_empty (struct ipc_message *m);
struct ipc_error ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length);
struct ipc_error ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length);
struct ipc_error ipc_message_format_server_close (struct ipc_message *m);
struct ipc_error ipc_message_empty (struct ipc_message *m);
// Switch cases macros
// print on error
#define ERROR_CASE(e,f,m) case e : { fprintf (stderr, "function %s: %s", f, m); } break;
/***
* non public functions
**/
void ipc_connection_print (struct ipc_connection_info *cinfo);
void ipc_connections_print (struct ipc_connection_infos *cinfos);
enum ipc_errors ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p);
enum ipc_errors ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname);
enum ipc_errors service_path (char *path, const char *sname, int32_t index, int32_t version);
char * log_get_logfile_dir (char *buf, size_t size);
void log_get_logfile_name (char *buf, size_t size);
struct ipc_error ipc_accept (struct ipc_connection_info *srv, struct ipc_connection_info *p);
struct ipc_error ipc_contact_networkd (struct ipc_connection_info *srv, const char *sname);
struct ipc_error service_path (char *path, const char *sname, int32_t index, int32_t version);
/***
* networkd enumerations, structures and functions
@ -386,24 +318,185 @@ struct networkd {
int cpt;
struct ipc_connection_info *srv;
struct ipc_connection_infos *clients;
struct ipc_switchings * TCP_TO_IPC;
struct ipc_switchings *TCP_TO_IPC;
};
enum ipc_errors ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // NULL for clients
, struct ipc_event *event
, struct ipc_switchings *switchdb
, long *timer);
struct ipc_error ipc_wait_event_networkd (struct ipc_connection_infos *cinfos
, struct ipc_connection_info *cinfo // cinfo is NULL for clients
, struct ipc_event *event, struct ipc_switchings *switchdb, long *timer);
void ipc_switching_add (struct ipc_switchings *is, int orig, int dest);
int ipc_switching_del (struct ipc_switchings *is, int fd);
int ipc_switching_get (struct ipc_switchings *is, int fd);
void ipc_switching_free (struct ipc_switchings *is);
void ipc_switching_print (struct ipc_switchings *is);
struct ipc_error ipc_receive_fd (int sock, int *fd);
struct ipc_error ipc_provide_fd (int sock, int fd);
enum ipc_errors ipc_receive_fd (int sock, int *fd);
enum ipc_errors ipc_provide_fd (int sock, int fd);
/***
* grooming macros
**/
#define SECURE_DECLARATION(t,v) t v; memset(&v,0,sizeof(t));
#define SECURE_BUFFER_DECLARATION(type,name,size) type name[size]; memset(&name, 0, sizeof(type) * size);
#define SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr,r)\
{ p = malloc (len); if (p == NULL) { instr; r; } ; memset(p, 0, len); }
#define SECURE_BUFFER_HEAP_ALLOCATION_R(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, IPC_RETURN_ERROR(r); )
#define SECURE_BUFFER_HEAP_ALLOCATION_R_NULL(p,len,instr) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, return NULL; )
#define SECURE_BUFFER_HEAP_ALLOCATION_Q(p,len,instr,r) SECURE_BUFFER_HEAP_ALLOCATION(p,len,instr, exit(r))
// Test macros, requiring the variable `enum ipc_error_code ret`
// one macro to rule them all!
// 1. function to test
// 2. Test IPC error based (test itself)
// 3. Instructions to exec on failure
// 4. Return something
#define TEST_IPC_T_P_I_R(function_to_test, test, instr, r) \
{\
struct ipc_error ret = function_to_test;\
if (test) {\
instr;\
r;\
}\
}
// R = return r param
// RR = return "ret" variable
// RV = return void
// Q = quit
// I = additionnal instructions before returning on error
#define TEST_IPC_T_I_P_Q(f,t,instr,err,r) TEST_IPC_T_P_I_R(f, t, instr, exit(r))
#define TEST_IPC_T_I_RR(f,t,instr) TEST_IPC_T_P_I_R(f, t, instr, return ret)
#define TEST_IPC_I_RR(f,instr) TEST_IPC_T_P_I_R(f, ret.error_code != IPC_ERROR_NONE, instr, return ret)
// Tests macros, do not require `enum ipc_error_code ret` variable
// test => return error code
#define T_R(t,r) if t { IPC_RETURN_ERROR(r); }
#define T_R_NULL(t) if t { return NULL; }
#define T_R_NOTHING(t) if t { return ; }
// test => perror then return (for system functions)
#define T_PERROR_R(t,m,r) if t { perror(m); return (r); }
// test => perror then exit (for system functions)
#define T_PERROR_Q(t,m,r) if t { perror(m); exit(r); }
#define T_PERROR_RIPC(t,m,r) if t { perror(m); IPC_RETURN_ERROR(r); }
#define TEST_IPC_QUIT_ON_ERROR(function_to_test,ec) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
fprintf(stderr, "%s\n", ret.error_message);\
exit(ec);\
}\
}
#define TEST_IPC_RETURN_ON_ERROR_FREE(function_to_test, buffer_to_free) {\
struct ipc_error ret = function_to_test; \
if (ret.error_code != IPC_ERROR_NONE) {\
if (buffer_to_free != NULL) {\
free(buffer_to_free); \
}\
return ret;\
}\
}
#define TEST_IPC_RETURN_ON_ERROR(function_to_test) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
return ret;\
}\
}
#define TEST_IPC_RETURN_ON_ERROR_FREE(function_to_test, buffer_to_free) {\
struct ipc_error ret = function_to_test; \
if (ret.error_code != IPC_ERROR_NONE) {\
if (buffer_to_free != NULL) {\
free(buffer_to_free); \
}\
return ret;\
}\
}
// formatted version of TEST_IPC_RR
#define TEST_IPC_RR_F(function_to_test, format, ...) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) { \
error_message_format (ret.error_message + strlen(ret.error_message) \
, "blocking error" \
, ":" __FILE__ ":" format \
, ##__VA_ARGS__ ); \
return ret;\
}\
}
// TODO: ret already contains error message, append the error_message
// TODO: currently, error message is not what it should be
#define TEST_IPC_RR(function_to_test, err_message) \
TEST_IPC_RR_F(function_to_test, "%s", err_message)
// same as TEST_IPC_RR but do not return
#define TEST_IPC_P(function_to_test, err_message) {\
struct ipc_error ret = function_to_test;\
if (ret.error_code != IPC_ERROR_NONE) {\
error_message_format (ret.error_message + strlen(ret.error_message) \
, "non blocking error" \
, ":" __FILE__ "%s:%s" \
, err_message );\
}\
}
#define IPC_RETURN_NO_ERROR { \
SECURE_DECLARATION (struct ipc_error, ret); \
ret.error_code = IPC_ERROR_NONE; \
return ret; \
}
#define IPC_FILL_DEFAULT_ERROR_MESSAGE(error_message_ptr,error_code) { \
const char *estr = ipc_errors_get (error_code); \
snprintf(error_message_ptr, BUFSIZ, "%s", estr); \
}
#define IPC_RETURN_ERROR(ec_) \
SECURE_DECLARATION(struct ipc_error, ret);\
IPC_FILL_DEFAULT_ERROR_MESSAGE(ret.error_message, ec_);\
ret.error_code = ec_;\
return ret;
#define IPC_RETURN_ERROR_FORMAT(v,format,...) { \
SECURE_DECLARATION (struct ipc_error, ret); \
ret.error_code = v; \
error_message_format (ret.error_message \
, "blocking error" \
, format \
, ##__VA_ARGS__ ); \
return ret; \
}
#define TEST_IPC_Q(f,e) {\
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE) { \
fprintf(stderr, "%s", ret.error_message); \
exit(e); \
} \
}
#define TEST_IPC_WAIT_EVENT_RR(f, r) { \
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE && \
ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { \
return ret; \
} \
}
#define TEST_IPC_WAIT_EVENT_Q(f, r) { \
struct ipc_error ret = f; \
if (ret.error_code != IPC_ERROR_NONE && \
ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) { \
exit(r); \
} \
}
#endif

View File

@ -1,112 +0,0 @@
#include "logger.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ipc.h"
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(_GNU_SOURCE)
#else
extern char *__progname;
#endif
char * log_get_logfile_dir (char *buf, size_t size)
{
char * datadir = getenv ("XDG_DATA_HOME");
if (datadir == NULL) {
datadir = getenv ("HOME");
if (datadir == NULL) {
return buf + snprintf (buf, size, "./ipc/");
}
else {
return buf + snprintf (buf, size, "%s/.local/share/ipc/", datadir);
}
}
return buf + snprintf (buf, size, "%s/ipc/", datadir);
}
void log_get_logfile_name (char *buf, size_t size) {
char *logfile = getenv ("IPC_LOGFILE");
if (logfile == NULL) {
char *buf_after_dir;
buf_after_dir = log_get_logfile_dir (buf, size);
pid_t pid = getpid();
#if defined(__APPLE__) || defined(__FreeBSD__)
const char * appname = getprogname();
#elif defined(_GNU_SOURCE)
const char * appname = program_invocation_name;
#elif defined(__linux__)
const char * appname = __progname;
#else
#error "cannot know the application name for this environment"
#endif
snprintf (buf_after_dir, size - (buf_after_dir - buf), "%s-%d.log", appname, pid);
return;
}
snprintf (buf, size, "%s", logfile);
}
void log_format (const char* tag, const char* message, va_list args) {
time_t now;
time(&now);
struct tm *t = localtime (&now);
SECURE_BUFFER_DECLARATION (char, date, 200);
snprintf (date, 200, "%d-%02d-%02d_%02d-%02d-%02d"
, t->tm_year+1900, t->tm_mon +1, t->tm_mday
, t->tm_hour, t->tm_min, t->tm_sec);
SECURE_BUFFER_DECLARATION (char, logfile, BUFSIZ);
log_get_logfile_name (logfile, BUFSIZ);
FILE * logfd = fopen (logfile, "a");
if (logfd == NULL) {
fprintf (stderr, "something gone horribly wrong: cannot open logfile: %s\n", logfile);
return;
}
fprintf (logfd, "%s:%s:", date, tag);
vfprintf(logfd, message, args);
fprintf (logfd, "\n");
fflush (logfd);
fclose (logfd);
}
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);
}

View File

@ -1,9 +0,0 @@
#ifndef __IPC_LOGGER_H__
#define __IPC_LOGGER_H__
#include <stdarg.h>
// print log, format: date:tag: message
void log_format (const char* tag, const char* message, va_list args);
#endif

View File

@ -11,7 +11,7 @@
// #define IPC_WITH_ERRORS 3
uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char * message, uint32_t message_size)
uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, char *message, uint32_t message_size)
{
uint32_t msize = 6 + message_size;
buffer[0] = type;
@ -28,132 +28,120 @@ uint32_t ipc_message_raw_serialize (char *buffer, char type, char user_type, cha
return msize;
}
void ipc_message_print (const struct ipc_message *m)
struct ipc_error ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize)
{
if (m == NULL) return;
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
LOG_INFO ("msg: type %d len %d\n", m->type, m->length);
#endif
}
enum ipc_errors ipc_message_format_read (struct ipc_message *m, const char *buf, size_t msize)
{
T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE);
T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER);
T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_SIZE);
T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_MESSAGE);
T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_READ__EMPTY_BUFFER);
T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__PARAM_MESSAGE_SIZE);
// message format:
// Type (1 B) | Length (4 B) | UserType (1 B) | Payload (Length B)
m->type = buf[0];
m->type = buf[0];
uint32_t unformated_size = 0;
memcpy (&unformated_size, buf+1, sizeof(uint32_t));
memcpy (&unformated_size, buf + 1, sizeof (uint32_t));
m->length = ntohl (unformated_size);
m->user_type = buf[1 + sizeof m->length];
T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE);
T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_READ__MESSAGE_TOO_LONG);
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
LOG_INFO ("receiving msg: type %d, paylen %u, total %lu", m->type, m->length, msize);
LOG_INFO ("receiving msg: type %d, paylen %u, total %lu", m->type, m->length, msize);
#endif
T_R ((m->length != msize - IPC_HEADER_SIZE && m->length != 0)
, IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE);
T_R ((m->length != msize - IPC_HEADER_SIZE && m->length != 0)
, IPC_ERROR_MESSAGE_FORMAT_READ__READ_MESSAGE_SIZE);
if (m->payload != NULL) {
free (m->payload);
if (m->payload != NULL) {
free (m->payload);
m->payload = NULL;
}
if (m->length > 0) {
m->payload = malloc (m->length);
memcpy (m->payload, buf+IPC_HEADER_SIZE, m->length);
}
else {
m->payload = malloc (1);
if (m->length > 0) {
m->payload = malloc (m->length);
memcpy (m->payload, buf + IPC_HEADER_SIZE, m->length);
} else {
m->payload = malloc (1);
}
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_message_format_write (const struct ipc_message *m, char **buf, size_t *msize)
struct ipc_error ipc_message_format_write (const struct ipc_message *m, char **buf, size_t * msize)
{
T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE);
T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER);
T_R ((msize == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE);
T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH);
T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MESSAGE);
T_R ((buf == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_BUFFER);
T_R ((msize == NULL), IPC_ERROR_MESSAGE_FORMAT_WRITE__EMPTY_MSIZE);
T_R ((m->length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT_WRITE__MESSAGE_LENGTH);
if (*buf == NULL) {
*buf = malloc (IPC_HEADER_SIZE + m->length);
if (*buf == NULL) {
*buf = malloc (IPC_HEADER_SIZE + m->length);
memset (*buf, 0, IPC_HEADER_SIZE + m->length);
}
}
char *buffer = *buf;
uint32_t net_paylen = htonl(m->length);
char *buffer = *buf;
uint32_t net_paylen = htonl (m->length);
buffer[0] = m->type;
memcpy (buffer + 1, &net_paylen, sizeof(uint32_t));
buffer[1 + sizeof m->length] = m->user_type;
buffer[0] = m->type;
memcpy (buffer + 1, &net_paylen, sizeof (uint32_t));
buffer[1 + sizeof m->length] = m->user_type;
if (m->payload != NULL && m->length > 0) {
memcpy (buffer + IPC_HEADER_SIZE, m->payload, m->length);
}
*msize = IPC_HEADER_SIZE + m->length;
*msize = IPC_HEADER_SIZE + m->length;
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
LOG_INFO ("sending msg: type %u, paylen %u, msize %lu", m->type, m->length, *msize);
#endif
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// MSG FORMAT
enum ipc_errors ipc_message_format (struct ipc_message *m
, char type, char utype, const char *payload, size_t length)
struct ipc_error ipc_message_format (struct ipc_message *m, char type, char utype, const char *payload, size_t length)
{
T_R ((m == NULL), IPC_ERROR_MESSAGE_FORMAT__NO_MESSAGE_PARAM);
T_R ((length > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_MESSAGE_FORMAT__MESSAGE_SIZE);
T_R (((length == 0 && payload != NULL) || (length > 0 && payload == NULL))
, IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS);
, IPC_ERROR_MESSAGE_FORMAT__INCONSISTENT_PARAMS);
m->type = type;
m->user_type = utype;
m->length = (uint32_t) length;
m->type = type;
m->user_type = utype;
m->length = (uint32_t) length;
if (payload != NULL) {
if (payload != NULL) {
if (m->payload != NULL) {
free (m->payload);
}
SECURE_BUFFER_HEAP_ALLOCATION_R (m->payload, length, , IPC_ERROR_NOT_ENOUGH_MEMORY);
SECURE_BUFFER_HEAP_ALLOCATION_R (m->payload, length,, IPC_ERROR_MESSAGE_FORMAT__HEAP_ALLOCATION);
}
if (payload != NULL) {
memcpy (m->payload, payload, length);
}
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length)
struct ipc_error ipc_message_format_data (struct ipc_message *m, char utype, const char *payload, size_t length)
{
return ipc_message_format (m, MSG_TYPE_DATA, utype, payload, length);
return ipc_message_format (m, MSG_TYPE_DATA, utype, payload, length);
}
enum ipc_errors ipc_message_format_server_close (struct ipc_message *m)
struct ipc_error ipc_message_format_server_close (struct ipc_message *m)
{
return ipc_message_format (m, MSG_TYPE_SERVER_CLOSE, 0, NULL, 0);
return ipc_message_format (m, MSG_TYPE_SERVER_CLOSE, 0, NULL, 0);
}
enum ipc_errors ipc_message_empty (struct ipc_message *m)
struct ipc_error ipc_message_empty (struct ipc_message *m)
{
T_R ((m == NULL), IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST);
T_R ((m == NULL), IPC_ERROR_MESSAGE_EMPTY__EMPTY_MESSAGE_LIST);
if (m->payload != NULL) {
free (m->payload);
if (m->payload != NULL) {
free (m->payload);
m->payload = NULL;
}
m->length = 0;
m->length = 0;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}

View File

@ -28,119 +28,116 @@
* get a networkd working with this
*/
enum ipc_errors ipc_receive_fd (int sock, int *fd)
struct ipc_error ipc_receive_fd (int sock, int *fd)
{
T_R ((fd == NULL), IPC_ERROR_RECEIVE_FD__NO_PARAM_FD);
*fd = -1;
SECURE_DECLARATION (struct msghdr, msg);
SECURE_BUFFER_DECLARATION (char, c_buffer, 256);
SECURE_BUFFER_DECLARATION (char, c_buffer, 256);
/* 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;
/* 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;
msg.msg_control = c_buffer;
msg.msg_controllen = sizeof(c_buffer);
msg.msg_control = c_buffer;
msg.msg_controllen = sizeof (c_buffer);
T_PERROR_R ((recvmsg(sock, &msg, 0) <= 0), "recvmsg", IPC_ERROR_RECEIVE_FD__RECVMSG);
T_PERROR_RIPC ((recvmsg (sock, &msg, 0) <= 0), "recvmsg", IPC_ERROR_RECEIVE_FD__RECVMSG);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
memmove(fd, CMSG_DATA(cmsg), sizeof(*fd));
memmove (fd, CMSG_DATA (cmsg), sizeof (*fd));
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors ipc_provide_fd (int sock, int fd)
struct ipc_error ipc_provide_fd (int sock, int fd)
{
SECURE_DECLARATION (struct msghdr, msg);
SECURE_BUFFER_DECLARATION (char, buf, CMSG_SPACE(sizeof(fd)));
SECURE_DECLARATION (struct msghdr, msg);
SECURE_BUFFER_DECLARATION (char, buf, CMSG_SPACE (sizeof (fd)));
/* On Mac OS X, the struct iovec is needed, even if it points to minimal data */
struct iovec io = { .iov_base = "", .iov_len = 1 };
/* 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);
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));
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));
memmove (CMSG_DATA (cmsg), &fd, sizeof (fd));
msg.msg_controllen = cmsg->cmsg_len;
msg.msg_controllen = cmsg->cmsg_len;
T_PERROR_R ((sendmsg(sock, &msg, 0) < 0), "sendmsg", IPC_ERROR_PROVIDE_FD__SENDMSG);
T_PERROR_RIPC ((sendmsg (sock, &msg, 0) < 0), "sendmsg", IPC_ERROR_PROVIDE_FD__SENDMSG);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
void ipc_switching_add (struct ipc_switchings *is, int orig, int dest)
{
is->collection = realloc(is->collection, sizeof(struct ipc_switching) * (is->size+1));
if (is->collection == NULL) {
LOG_ERROR ("error realloc");
exit (EXIT_FAILURE);
}
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * (is->size + 1));
if (is->collection == NULL) {
fprintf (stderr, __FILE__ " error realloc line %d", __LINE__);
exit (EXIT_FAILURE);
}
is->size++;
is->size++;
is->collection[is->size-1].orig = orig;
is->collection[is->size-1].dest = dest;
is->collection[is->size - 1].orig = orig;
is->collection[is->size - 1].dest = dest;
}
int ipc_switching_del (struct ipc_switchings *is, int fd)
{
for (size_t i = 0; i < is->size; i++) {
if (is->collection[i].orig == fd || is->collection[i].dest == fd) {
int ret;
for (size_t i = 0; i < is->size; i++) {
if (is->collection[i].orig == fd || is->collection[i].dest == fd) {
int ret;
if (fd == is->collection[i].orig) {
ret = is->collection[i].dest;
}
else {
ret = is->collection[i].orig;
}
if (fd == is->collection[i].orig) {
ret = is->collection[i].dest;
} else {
ret = is->collection[i].orig;
}
is->collection[i].orig = is->collection[is->size-1].orig;
is->collection[i].dest = is->collection[is->size-1].dest;
is->collection[i].orig = is->collection[is->size - 1].orig;
is->collection[i].dest = is->collection[is->size - 1].dest;
size_t s = (is->size - 1) > 0 ? (is->size - 1) : 1;
size_t s = (is->size - 1) > 0 ? (is->size - 1) : 1;
is->collection = realloc(is->collection, sizeof(struct ipc_switching) * s);
if (is->collection == NULL) {
LOG_ERROR ("error realloc");
exit (EXIT_FAILURE);
}
is->collection = realloc (is->collection, sizeof (struct ipc_switching) * s);
if (is->collection == NULL) {
/** TODO: not sure we want this behavior */
fprintf (stderr, __FILE__ " error realloc line %d", __LINE__);
exit (EXIT_FAILURE);
}
is->size--;
return ret;
}
}
is->size--;
return ret;
}
}
return -1;
return -1;
}
int ipc_switching_get (struct ipc_switchings *is, int fd)
{
for (size_t i = 0; i < is->size; i++) {
if (is->collection[i].orig == fd) {
return is->collection[i].dest;
}
else if (is->collection[i].dest == fd) {
return is->collection[i].orig;
}
}
for (size_t i = 0; i < is->size; i++) {
if (is->collection[i].orig == fd) {
return is->collection[i].dest;
} else if (is->collection[i].dest == fd) {
return is->collection[i].orig;
}
}
return -1;
return -1;
}
void ipc_switching_free (struct ipc_switchings *is)
@ -154,10 +151,3 @@ void ipc_switching_free (struct ipc_switchings *is)
}
is->size = 0;
}
void ipc_switching_print (struct ipc_switchings *is)
{
for (size_t i = 0; i < is->size; i++) {
LOG_DEBUG ("client %d - %d", is->collection[i].orig, is->collection[i].dest);
}
}

36
src/print.c Normal file
View File

@ -0,0 +1,36 @@
#include "ipc.h"
void ipc_connection_print (struct ipc_connection_info *cinfo)
{
T_R_NOTHING ((cinfo == NULL));
#if 0
LOG_DEBUG ("fd %d: index %d, version %d, type %c, path %s"
, cinfo->fd , cinfo->index, cinfo->version, cinfo->type
, (cinfo->spath == NULL) ? "-" : cinfo->spath);
#endif
}
void ipc_connections_print (struct ipc_connection_infos *cinfos)
{
for (size_t i = 0; i < cinfos->size; i++) {
ipc_connection_print (cinfos->cinfos[i]);
}
}
void ipc_message_print (const struct ipc_message *m)
{
if (m == NULL)
return;
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
LOG_INFO ("msg: type %d len %d\n", m->type, m->length);
#endif
}
void ipc_switching_print (struct ipc_switchings *is)
{
for (size_t i = 0; i < is->size; i++) {
printf ("client %d - %d", is->collection[i].orig, is->collection[i].dest);
}
}

View File

@ -1,171 +0,0 @@
/* $OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues and XOR simple queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* An XOR simple queue is used in the same way as a regular simple queue.
* The difference is that the head structure also includes a "cookie" that
* is XOR'd with the queue pointer (first, last or next) to generate the
* real pointer value.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods.
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#endif /* _SYS_QUEUE_H_ */

View File

@ -15,40 +15,39 @@
#include "usocket.h"
#include "utils.h"
// exists_, basename_, is_directory_, have_rights_
#include "fs.h"
// #define IPC_DEBUG 3
/**
* TODO: non blocking read
*/
enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent)
struct ipc_error usock_send (const int32_t fd, const char *buf, size_t len, size_t * sent)
{
ssize_t ret = 0;
ret = send (fd, buf, len, MSG_NOSIGNAL);
T_R ((ret <= 0), IPC_ERROR_USOCK_SEND);
ssize_t ret = 0;
ret = send (fd, buf, len, MSG_NOSIGNAL);
T_R ((ret <= 0), IPC_ERROR_USOCK_SEND);
*sent = ret;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
// *len is changed to the total message size read (header + payload)
enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len)
struct ipc_error usock_recv (const int32_t fd, char **buf, size_t * len)
{
T_R ((buf == NULL), IPC_ERROR_USOCK_RECV__NO_BUFFER);
T_R ((len == NULL), IPC_ERROR_USOCK_RECV__NO_LENGTH);
T_R ((buf == NULL), IPC_ERROR_USOCK_RECV__NO_BUFFER);
T_R ((len == NULL), IPC_ERROR_USOCK_RECV__NO_LENGTH);
int32_t ret_recv = 0;
int32_t ret_recv = 0;
if (*len == 0)
*len = IPC_MAX_MESSAGE_SIZE;
if (*buf == NULL) {
// do not allocate too much memory
if (*len > IPC_MAX_MESSAGE_SIZE) {
LOG_ERROR ("usock_recv: len > IPC_MAX_MESSAGE_SIZE");
*len = IPC_MAX_MESSAGE_SIZE;
if (*buf == NULL) {
// do not allocate too much memory
if (*len > IPC_MAX_MESSAGE_SIZE) {
*len = IPC_MAX_MESSAGE_SIZE;
}
SECURE_BUFFER_HEAP_ALLOCATION (*buf,*len + IPC_HEADER_SIZE, , return (IPC_ERROR_NOT_ENOUGH_MEMORY));
}
SECURE_BUFFER_HEAP_ALLOCATION (*buf, *len + IPC_HEADER_SIZE,,
IPC_RETURN_ERROR (IPC_ERROR_USOCK_RECV__HEAP_ALLOCATION));
}
uint32_t msize = 0;
uint32_t msize_read = 0;
@ -57,8 +56,8 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len)
ret_recv = recv (fd, *buf, *len, 0);
#ifdef IPC_DEBUG
if (ret_recv > 0) {
print_hexa ("msg recv", (uint8_t *)*buf, ret_recv);
fflush(stdout);
print_hexa ("msg recv", (uint8_t *) * buf, ret_recv);
fflush (stdout);
}
#endif
@ -70,14 +69,13 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len)
if (msize >= IPC_MAX_MESSAGE_SIZE) {
#ifdef IPC_DEBUG
print_hexa ("msg recv", (uint8_t *)*buf, ret_recv);
fflush(stdout);
print_hexa ("msg recv", (uint8_t *) * buf, ret_recv);
fflush (stdout);
#endif
}
T_R ((msize > IPC_MAX_MESSAGE_SIZE), IPC_ERROR_USOCK_RECV__MESSAGE_SIZE);
msize_read += ret_recv - IPC_HEADER_SIZE;
}
else if (ret_recv < 0) {
} else if (ret_recv < 0) {
if (*buf != NULL) {
free (*buf);
*buf = NULL;
@ -115,19 +113,17 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len)
// any data were available; see signal(7).
ERROR_CASE (EINTR, "usock_recv", "unsupported error");
default:
LOG_ERROR ("usock_recv: unsupported error");
default:
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_USOCK_RECV__UNRECOGNIZED_ERROR
, "%s"
, "usock_recv: unrecognized error after recv(2)");
}
LOG_ERROR ("usock_recv: recv < 0");
return IPC_ERROR_USOCK_RECV;
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_USOCK_RECV
, "%s"
, "usock_recv: recv < 0, is the message size malformed?");
}
#if 0
#if defined(IPC_WITH_ERRORS) && IPC_WITH_ERRORS > 2
LOG_ERROR ("fragmentation: message size read %u, should read %u", msize_read, msize);
#endif
#endif
} while (msize > msize_read);
*len = msize + IPC_HEADER_SIZE;
@ -139,93 +135,96 @@ enum ipc_errors usock_recv (const int32_t fd, char **buf, size_t *len)
*buf = NULL;
}
*len = 0;
return IPC_ERROR_CLOSED_RECIPIENT;
IPC_RETURN_ERROR (IPC_ERROR_CLOSED_RECIPIENT);
}
// print_hexa ("msg recv", (uint8_t *)*buf, *len);
// fflush(stdout);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors usock_connect (int32_t *fd, const char *path)
struct ipc_error usock_connect (int32_t * fd, const char *path)
{
T_R ((fd == NULL), IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR);
T_R ((path == NULL), IPC_ERROR_USOCK_CONNECT__EMPTY_PATH);
T_R ((fd == NULL), IPC_ERROR_USOCK_CONNECT__WRONG_FILE_DESCRIPTOR);
T_R ((path == NULL), IPC_ERROR_USOCK_CONNECT__EMPTY_PATH);
SECURE_DECLARATION (struct sockaddr_un, my_addr);
my_addr.sun_family = AF_UNIX;
SECURE_DECLARATION (struct sockaddr_un, my_addr);
my_addr.sun_family = AF_UNIX;
int32_t sfd;
socklen_t peer_addr_size = sizeof(struct sockaddr_un);
int32_t sfd;
socklen_t peer_addr_size = sizeof (struct sockaddr_un);
T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_SEQPACKET, 0)) == -1), "socket", IPC_ERROR_USOCK_CONNECT__SOCKET);
strncpy(my_addr.sun_path, path, (strlen (path) < PATH_MAX) ? strlen(path) : PATH_MAX);
T_PERROR_RIPC (((sfd = socket (AF_UNIX, SOCK_SEQPACKET, 0)) == -1), "socket", IPC_ERROR_USOCK_CONNECT__SOCKET);
strncpy (my_addr.sun_path, path, (strlen (path) < PATH_MAX) ? strlen (path) : PATH_MAX);
/** TODO: massive series of tests */
T_PERROR_F_R (
/** test */ (connect(sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1)
, /** perror */ "connect"
, /** log error */ ("unix socket connection to the path %s not possible", path)
, /** return value */ IPC_ERROR_USOCK_CONNECT__CONNECT);
TEST_IPC_RETURN_ON_ERROR(directory_setup_ (path));
*fd = sfd;
if (connect (sfd, (struct sockaddr *)&my_addr, peer_addr_size) == -1) {
IPC_RETURN_ERROR_FORMAT (IPC_ERROR_USOCK_CONNECT__CONNECT
, "unix socket connection to the path %s not possible", path);
}
return IPC_ERROR_NONE;
*fd = sfd;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors usock_init (int32_t *fd, const char *path)
struct ipc_error usock_init (int32_t * fd, const char *path)
{
T_R ((fd == NULL), IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR);
T_R ((path == NULL), IPC_ERROR_USOCK_INIT__EMPTY_PATH);
T_R ((fd == NULL), IPC_ERROR_USOCK_INIT__EMPTY_FILE_DESCRIPTOR);
T_R ((path == NULL), IPC_ERROR_USOCK_INIT__EMPTY_PATH);
SECURE_DECLARATION (struct sockaddr_un, my_addr);
my_addr.sun_family = AF_UNIX;
strncpy(my_addr.sun_path, path, strlen (path));
SECURE_DECLARATION (struct sockaddr_un, my_addr);
my_addr.sun_family = AF_UNIX;
strncpy (my_addr.sun_path, path, strlen (path));
int32_t sfd;
socklen_t peer_addr_size;
int32_t sfd;
socklen_t peer_addr_size;
T_PERROR_R (((sfd = socket (AF_UNIX, SOCK_SEQPACKET, 0)) == -1), "socket", IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR);
TEST_IPC_RETURN_ON_ERROR(directory_setup_ (path));
T_PERROR_RIPC (((sfd = socket (AF_UNIX, SOCK_SEQPACKET, 0)) == -1)
, "socket", IPC_ERROR_USOCK_INIT__WRONG_FILE_DESCRIPTOR);
// delete the unix socket if already created
// ignore otherwise
usock_remove (path);
peer_addr_size = sizeof(struct sockaddr_un);
peer_addr_size = sizeof (struct sockaddr_un);
T_PERROR_R ((bind (sfd, (struct sockaddr *) &my_addr, peer_addr_size) == -1), "bind", IPC_ERROR_USOCK_INIT__BIND);
T_PERROR_R ((listen (sfd, LISTEN_BACKLOG) == -1), "listen", IPC_ERROR_USOCK_INIT__LISTEN);
T_PERROR_RIPC ((bind (sfd, (struct sockaddr *)&my_addr, peer_addr_size) == -1)
, "bind", IPC_ERROR_USOCK_INIT__BIND);
T_PERROR_RIPC ((listen (sfd, LISTEN_BACKLOG) == -1), "listen", IPC_ERROR_USOCK_INIT__LISTEN);
*fd = sfd;
*fd = sfd;
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors usock_accept (int32_t fd, int32_t *pfd)
struct ipc_error usock_accept (int32_t fd, int32_t * pfd)
{
T_R ((pfd == NULL), IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR);
T_R ((pfd == NULL), IPC_ERROR_USOCK_ACCEPT__PATH_FILE_DESCRIPTOR);
SECURE_DECLARATION (struct sockaddr_un, peer_addr);
socklen_t peer_addr_size = 0;
SECURE_DECLARATION (struct sockaddr_un, peer_addr);
socklen_t peer_addr_size = 0;
T_PERROR_R (((*pfd = accept (fd, (struct sockaddr *) &peer_addr, &peer_addr_size)) < 0), "accept", IPC_ERROR_USOCK_ACCEPT);
T_PERROR_RIPC (((*pfd = accept (fd, (struct sockaddr *)&peer_addr, &peer_addr_size)) < 0)
, "accept", IPC_ERROR_USOCK_ACCEPT);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}
enum ipc_errors usock_close (int32_t fd)
struct ipc_error usock_close (int32_t fd)
{
T_PERROR_R ((close (fd) < 0), "close", IPC_ERROR_USOCK_CLOSE);
return IPC_ERROR_NONE;
T_PERROR_RIPC ((close (fd) < 0), "close", IPC_ERROR_USOCK_CLOSE);
IPC_RETURN_NO_ERROR;
}
enum ipc_errors usock_remove (const char *path)
struct ipc_error usock_remove (const char *path)
{
SECURE_DECLARATION(struct stat, file_state);
SECURE_DECLARATION (struct stat, file_state);
// if file exists, remove it
T_R ((stat (path, &file_state) != 0), IPC_ERROR_USOCK_REMOVE__NO_FILE);
T_R ((unlink (path) != 0), IPC_ERROR_USOCK_REMOVE__UNLINK);
return IPC_ERROR_NONE;
IPC_RETURN_NO_ERROR;
}

View File

@ -7,23 +7,23 @@
// input: len = max buf size
// output: *sent = nb received bytes
enum ipc_errors usock_send (const int32_t fd, const char *buf, size_t len, size_t *sent);
struct ipc_error usock_send (const int32_t fd, const char *buf, size_t len, size_t * sent);
// allocation of *len bytes on *buf == NULL
//
// output: *len = nb sent bytes
enum ipc_errors usock_recv (int32_t fd, char **buf, size_t *len);
struct ipc_error usock_recv (int32_t fd, char **buf, size_t * len);
enum ipc_errors usock_close (int32_t fd);
struct ipc_error usock_close (int32_t fd);
// same as connect(2)
enum ipc_errors usock_connect (int32_t *fd, const char *path);
struct ipc_error usock_connect (int32_t * fd, const char *path);
enum ipc_errors usock_init (int32_t *fd, const char *path);
struct ipc_error usock_init (int32_t * fd, const char *path);
enum ipc_errors usock_accept (int32_t fd, int32_t *pfd);
struct ipc_error usock_accept (int32_t fd, int32_t * pfd);
// same as unlink(2)
enum ipc_errors usock_remove (const char *path);
struct ipc_error usock_remove (const char *path);
#endif

View File

@ -1,36 +1,66 @@
#include "utils.h"
#include "ipc.h"
#include <time.h>
#include <sys/types.h>
#include <stdarg.h>
void print_hexa (const char *prefix, uint8_t *payload, size_t size)
void error_message_format (char *formatted_message, const char *tag, const char *message, ...)
{
if (payload == NULL)
return ;
va_list args;
time_t now;
time (&now);
struct tm *t = localtime (&now);
SECURE_BUFFER_DECLARATION (char, date, 200);
snprintf (date, 200, "%d-%02d-%02d_%02d-%02d-%02d"
, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday
, t->tm_hour, t->tm_min, t->tm_sec);
size_t written = 0;
written = snprintf (formatted_message, BUFSIZ, "%s:%s:", date, tag);
va_start (args, message);
written += vsprintf (formatted_message + written, message, args);
va_end (args);
snprintf (formatted_message + written, BUFSIZ, "\n");
}
void print_hexa (const char *prefix, uint8_t * payload, size_t size)
{
if (payload == NULL)
return;
SECURE_BUFFER_DECLARATION (char, buffer, BUFSIZ);
char *cur = buffer, * const end = buffer + sizeof buffer;
char *cur = buffer, *const end = buffer + sizeof buffer;
size_t i;
size_t i;
size_t linenum = 0;
for(i = 0; i < size; i++) {
for (i = 0; i < size; i++) {
if (i == 0) {
cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size);
linenum ++;
}
else if(! (i % 16)) {
LOG_DEBUG ("%s", buffer);
cur += snprintf (cur, end - cur
, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) "
, linenum + 1, (size / 16) + 1, prefix, size);
linenum++;
} else if (!(i % 16)) {
printf ("%s", buffer);
memset (buffer, 0, BUFSIZ);
cur = buffer;
cur += snprintf(cur, end-cur, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) ", linenum +1, (size / 16) +1, prefix, size);
linenum ++;
cur += snprintf (cur, end - cur
, "\033[32m[%2ld/%2ld]\033[00m \033[36m%s\033[00m (%ld) "
, linenum + 1, (size / 16) + 1, prefix, size);
linenum++;
} else if (!(i % 4)) {
cur += snprintf (cur, end - cur, " ");
}
else if (! (i % 4)) {
cur += snprintf(cur, end-cur, " ");
}
cur += snprintf(cur, end-cur, "%2x ", payload[i]);
}
cur += snprintf (cur, end - cur, "%2x ", payload[i]);
}
if ((i % 16)) {
LOG_DEBUG ("%s", buffer);
printf ("%s", buffer);
}
}

View File

@ -7,6 +7,7 @@
#include <stdint.h>
void print_hexa (const char *prefix, uint8_t *payload, size_t size);
void error_message_format (char *formatted_message, const char *tag, const char *message, ...);
void print_hexa (const char *prefix, uint8_t * payload, size_t size);
#endif

439
tests/Makefile Normal file
View File

@ -0,0 +1,439 @@
PACKAGE = 'ipc-tests'
VERSION = '0.5.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 := -Wall -Wextra -g
LDFLAGS := -I../src -L../ ../src/ipc.h -lipc
Q := @
all: func_01_connection_establishment func_01_connection_establishmentd func_02_pong func_02_pongd func_03_multiple-communications-client func_03_multiple-communications-server func_04_empty_message unit_01_service-path unit_02_usock-remove unit_03_connection-add-remove
@:
func_01_connection_establishment: func_01_connection_establishment.o
@echo ' LD > func_01_connection_establishment'
$(Q)$(CC) -o func_01_connection_establishment func_01_connection_establishment.o $(LDFLAGS)
func_01_connection_establishment.install: func_01_connection_establishment
@echo ' IN > $(BINDIR)/func_01_connection_establishment'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_01_connection_establishment $(DESTDIR)$(BINDIR)/func_01_connection_establishment
func_01_connection_establishment.clean: func_01_connection_establishment.o.clean
@echo ' RM > func_01_connection_establishment'
$(Q)rm -f func_01_connection_establishment
func_01_connection_establishment.uninstall:
@echo ' RM > $(BINDIR)/func_01_connection_establishment'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_01_connection_establishment'
func_01_connection_establishmentd: func_01_connection_establishmentd.o
@echo ' LD > func_01_connection_establishmentd'
$(Q)$(CC) -o func_01_connection_establishmentd func_01_connection_establishmentd.o $(LDFLAGS)
func_01_connection_establishmentd.install: func_01_connection_establishmentd
@echo ' IN > $(BINDIR)/func_01_connection_establishmentd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_01_connection_establishmentd $(DESTDIR)$(BINDIR)/func_01_connection_establishmentd
func_01_connection_establishmentd.clean: func_01_connection_establishmentd.o.clean
@echo ' RM > func_01_connection_establishmentd'
$(Q)rm -f func_01_connection_establishmentd
func_01_connection_establishmentd.uninstall:
@echo ' RM > $(BINDIR)/func_01_connection_establishmentd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_01_connection_establishmentd'
func_02_pong: func_02_pong.o
@echo ' LD > func_02_pong'
$(Q)$(CC) -o func_02_pong func_02_pong.o $(LDFLAGS)
func_02_pong.install: func_02_pong
@echo ' IN > $(BINDIR)/func_02_pong'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_02_pong $(DESTDIR)$(BINDIR)/func_02_pong
func_02_pong.clean: func_02_pong.o.clean
@echo ' RM > func_02_pong'
$(Q)rm -f func_02_pong
func_02_pong.uninstall:
@echo ' RM > $(BINDIR)/func_02_pong'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_02_pong'
func_02_pongd: func_02_pongd.o
@echo ' LD > func_02_pongd'
$(Q)$(CC) -o func_02_pongd func_02_pongd.o $(LDFLAGS)
func_02_pongd.install: func_02_pongd
@echo ' IN > $(BINDIR)/func_02_pongd'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_02_pongd $(DESTDIR)$(BINDIR)/func_02_pongd
func_02_pongd.clean: func_02_pongd.o.clean
@echo ' RM > func_02_pongd'
$(Q)rm -f func_02_pongd
func_02_pongd.uninstall:
@echo ' RM > $(BINDIR)/func_02_pongd'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_02_pongd'
func_03_multiple-communications-client: func_03_multiple-communications-client.o
@echo ' LD > func_03_multiple-communications-client'
$(Q)$(CC) -o func_03_multiple-communications-client func_03_multiple-communications-client.o $(LDFLAGS)
func_03_multiple-communications-client.install: func_03_multiple-communications-client
@echo ' IN > $(BINDIR)/func_03_multiple-communications-client'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_03_multiple-communications-client $(DESTDIR)$(BINDIR)/func_03_multiple-communications-client
func_03_multiple-communications-client.clean: func_03_multiple-communications-client.o.clean
@echo ' RM > func_03_multiple-communications-client'
$(Q)rm -f func_03_multiple-communications-client
func_03_multiple-communications-client.uninstall:
@echo ' RM > $(BINDIR)/func_03_multiple-communications-client'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_03_multiple-communications-client'
func_03_multiple-communications-server: func_03_multiple-communications-server.o
@echo ' LD > func_03_multiple-communications-server'
$(Q)$(CC) -o func_03_multiple-communications-server func_03_multiple-communications-server.o $(LDFLAGS)
func_03_multiple-communications-server.install: func_03_multiple-communications-server
@echo ' IN > $(BINDIR)/func_03_multiple-communications-server'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_03_multiple-communications-server $(DESTDIR)$(BINDIR)/func_03_multiple-communications-server
func_03_multiple-communications-server.clean: func_03_multiple-communications-server.o.clean
@echo ' RM > func_03_multiple-communications-server'
$(Q)rm -f func_03_multiple-communications-server
func_03_multiple-communications-server.uninstall:
@echo ' RM > $(BINDIR)/func_03_multiple-communications-server'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_03_multiple-communications-server'
func_04_empty_message: func_04_empty_message.o
@echo ' LD > func_04_empty_message'
$(Q)$(CC) -o func_04_empty_message func_04_empty_message.o $(LDFLAGS)
func_04_empty_message.install: func_04_empty_message
@echo ' IN > $(BINDIR)/func_04_empty_message'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 func_04_empty_message $(DESTDIR)$(BINDIR)/func_04_empty_message
func_04_empty_message.clean: func_04_empty_message.o.clean
@echo ' RM > func_04_empty_message'
$(Q)rm -f func_04_empty_message
func_04_empty_message.uninstall:
@echo ' RM > $(BINDIR)/func_04_empty_message'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/func_04_empty_message'
unit_01_service-path: unit_01_service-path.o
@echo ' LD > unit_01_service-path'
$(Q)$(CC) -o unit_01_service-path unit_01_service-path.o $(LDFLAGS)
unit_01_service-path.install: unit_01_service-path
@echo ' IN > $(BINDIR)/unit_01_service-path'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 unit_01_service-path $(DESTDIR)$(BINDIR)/unit_01_service-path
unit_01_service-path.clean: unit_01_service-path.o.clean
@echo ' RM > unit_01_service-path'
$(Q)rm -f unit_01_service-path
unit_01_service-path.uninstall:
@echo ' RM > $(BINDIR)/unit_01_service-path'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/unit_01_service-path'
unit_02_usock-remove: unit_02_usock-remove.o
@echo ' LD > unit_02_usock-remove'
$(Q)$(CC) -o unit_02_usock-remove unit_02_usock-remove.o $(LDFLAGS)
unit_02_usock-remove.install: unit_02_usock-remove
@echo ' IN > $(BINDIR)/unit_02_usock-remove'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 unit_02_usock-remove $(DESTDIR)$(BINDIR)/unit_02_usock-remove
unit_02_usock-remove.clean: unit_02_usock-remove.o.clean
@echo ' RM > unit_02_usock-remove'
$(Q)rm -f unit_02_usock-remove
unit_02_usock-remove.uninstall:
@echo ' RM > $(BINDIR)/unit_02_usock-remove'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/unit_02_usock-remove'
unit_03_connection-add-remove: unit_03_connection-add-remove.o
@echo ' LD > unit_03_connection-add-remove'
$(Q)$(CC) -o unit_03_connection-add-remove unit_03_connection-add-remove.o $(LDFLAGS)
unit_03_connection-add-remove.install: unit_03_connection-add-remove
@echo ' IN > $(BINDIR)/unit_03_connection-add-remove'
$(Q)mkdir -p '$(DESTDIR)$(BINDIR)'
$(Q)install -m0755 unit_03_connection-add-remove $(DESTDIR)$(BINDIR)/unit_03_connection-add-remove
unit_03_connection-add-remove.clean: unit_03_connection-add-remove.o.clean
@echo ' RM > unit_03_connection-add-remove'
$(Q)rm -f unit_03_connection-add-remove
unit_03_connection-add-remove.uninstall:
@echo ' RM > $(BINDIR)/unit_03_connection-add-remove'
$(Q)rm -f '$(DESTDIR)$(BINDIR)/unit_03_connection-add-remove'
func_01_connection_establishment.o: func_01_connection_establishment.c ./../src/ipc.h
@echo ' CC > func_01_connection_establishment.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_01_connection_establishment.c -std=c11 -o func_01_connection_establishment.o
func_01_connection_establishment.o.install:
func_01_connection_establishment.o.clean:
@echo ' RM > func_01_connection_establishment.o'
$(Q)rm -f func_01_connection_establishment.o
func_01_connection_establishment.o.uninstall:
func_01_connection_establishmentd.o: func_01_connection_establishmentd.c ./../src/ipc.h
@echo ' CC > func_01_connection_establishmentd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_01_connection_establishmentd.c -std=c11 -o func_01_connection_establishmentd.o
func_01_connection_establishmentd.o.install:
func_01_connection_establishmentd.o.clean:
@echo ' RM > func_01_connection_establishmentd.o'
$(Q)rm -f func_01_connection_establishmentd.o
func_01_connection_establishmentd.o.uninstall:
func_02_pong.o: func_02_pong.c ./../src/ipc.h
@echo ' CC > func_02_pong.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_02_pong.c -std=c11 -o func_02_pong.o
func_02_pong.o.install:
func_02_pong.o.clean:
@echo ' RM > func_02_pong.o'
$(Q)rm -f func_02_pong.o
func_02_pong.o.uninstall:
func_02_pongd.o: func_02_pongd.c ./../src/ipc.h
@echo ' CC > func_02_pongd.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_02_pongd.c -std=c11 -o func_02_pongd.o
func_02_pongd.o.install:
func_02_pongd.o.clean:
@echo ' RM > func_02_pongd.o'
$(Q)rm -f func_02_pongd.o
func_02_pongd.o.uninstall:
func_03_multiple-communications-client.o: func_03_multiple-communications-client.c ./../src/ipc.h
@echo ' CC > func_03_multiple-communications-client.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_03_multiple-communications-client.c -std=c11 -o func_03_multiple-communications-client.o
func_03_multiple-communications-client.o.install:
func_03_multiple-communications-client.o.clean:
@echo ' RM > func_03_multiple-communications-client.o'
$(Q)rm -f func_03_multiple-communications-client.o
func_03_multiple-communications-client.o.uninstall:
func_03_multiple-communications-server.o: func_03_multiple-communications-server.c ./../src/ipc.h
@echo ' CC > func_03_multiple-communications-server.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_03_multiple-communications-server.c -std=c11 -o func_03_multiple-communications-server.o
func_03_multiple-communications-server.o.install:
func_03_multiple-communications-server.o.clean:
@echo ' RM > func_03_multiple-communications-server.o'
$(Q)rm -f func_03_multiple-communications-server.o
func_03_multiple-communications-server.o.uninstall:
func_04_empty_message.o: func_04_empty_message.c ./../src/ipc.h
@echo ' CC > func_04_empty_message.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c func_04_empty_message.c -std=c11 -o func_04_empty_message.o
func_04_empty_message.o.install:
func_04_empty_message.o.clean:
@echo ' RM > func_04_empty_message.o'
$(Q)rm -f func_04_empty_message.o
func_04_empty_message.o.uninstall:
unit_01_service-path.o: unit_01_service-path.c ./../src/ipc.h
@echo ' CC > unit_01_service-path.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c unit_01_service-path.c -std=c11 -o unit_01_service-path.o
unit_01_service-path.o.install:
unit_01_service-path.o.clean:
@echo ' RM > unit_01_service-path.o'
$(Q)rm -f unit_01_service-path.o
unit_01_service-path.o.uninstall:
unit_02_usock-remove.o: unit_02_usock-remove.c ./../src/ipc.h ./../src/usocket.h
@echo ' CC > unit_02_usock-remove.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c unit_02_usock-remove.c -std=c11 -o unit_02_usock-remove.o
unit_02_usock-remove.o.install:
unit_02_usock-remove.o.clean:
@echo ' RM > unit_02_usock-remove.o'
$(Q)rm -f unit_02_usock-remove.o
unit_02_usock-remove.o.uninstall:
unit_03_connection-add-remove.o: unit_03_connection-add-remove.c ./../src/ipc.h
@echo ' CC > unit_03_connection-add-remove.o'
$(Q)$(CC) $(CFLAGS) -std=c11 -c unit_03_connection-add-remove.c -std=c11 -o unit_03_connection-add-remove.o
unit_03_connection-add-remove.o.install:
unit_03_connection-add-remove.o.clean:
@echo ' RM > unit_03_connection-add-remove.o'
$(Q)rm -f unit_03_connection-add-remove.o
unit_03_connection-add-remove.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 func_01_connection_establishment.install func_01_connection_establishmentd.install func_02_pong.install func_02_pongd.install func_03_multiple-communications-client.install func_03_multiple-communications-server.install func_04_empty_message.install unit_01_service-path.install unit_02_usock-remove.install unit_03_connection-add-remove.install func_01_connection_establishment.o.install func_01_connection_establishmentd.o.install func_02_pong.o.install func_02_pongd.o.install func_03_multiple-communications-client.o.install func_03_multiple-communications-server.o.install func_04_empty_message.o.install unit_01_service-path.o.install unit_02_usock-remove.o.install unit_03_connection-add-remove.o.install
@:
subdirs.install:
uninstall: subdirs.uninstall func_01_connection_establishment.uninstall func_01_connection_establishmentd.uninstall func_02_pong.uninstall func_02_pongd.uninstall func_03_multiple-communications-client.uninstall func_03_multiple-communications-server.uninstall func_04_empty_message.uninstall unit_01_service-path.uninstall unit_02_usock-remove.uninstall unit_03_connection-add-remove.uninstall func_01_connection_establishment.o.uninstall func_01_connection_establishmentd.o.uninstall func_02_pong.o.uninstall func_02_pongd.o.uninstall func_03_multiple-communications-client.o.uninstall func_03_multiple-communications-server.o.uninstall func_04_empty_message.o.uninstall unit_01_service-path.o.uninstall unit_02_usock-remove.o.uninstall unit_03_connection-add-remove.o.uninstall
@:
subdirs.uninstall:
test: all subdirs subdirs.test
@:
subdirs.test:
clean: func_01_connection_establishment.clean func_01_connection_establishmentd.clean func_02_pong.clean func_02_pongd.clean func_03_multiple-communications-client.clean func_03_multiple-communications-server.clean func_04_empty_message.clean unit_01_service-path.clean unit_02_usock-remove.clean unit_03_connection-add-remove.clean func_01_connection_establishment.o.clean func_01_connection_establishmentd.o.clean func_02_pong.o.clean func_02_pongd.o.clean func_03_multiple-communications-client.o.clean func_03_multiple-communications-server.o.clean func_04_empty_message.o.clean unit_01_service-path.o.clean unit_02_usock-remove.o.clean unit_03_connection-add-remove.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)/unit_01_service-path.c \
$(PACKAGE)-$(VERSION)/func_02_pong.c \
$(PACKAGE)-$(VERSION)/func_02_pongd.c \
$(PACKAGE)-$(VERSION)/func_04_empty_message.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishment.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-server.c \
$(PACKAGE)-$(VERSION)/unit_03_connection-add-remove.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-client.c \
$(PACKAGE)-$(VERSION)/unit_02_usock-remove.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishmentd.c
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)/unit_01_service-path.c \
$(PACKAGE)-$(VERSION)/func_02_pong.c \
$(PACKAGE)-$(VERSION)/func_02_pongd.c \
$(PACKAGE)-$(VERSION)/func_04_empty_message.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishment.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-server.c \
$(PACKAGE)-$(VERSION)/unit_03_connection-add-remove.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-client.c \
$(PACKAGE)-$(VERSION)/unit_02_usock-remove.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishmentd.c
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)/unit_01_service-path.c \
$(PACKAGE)-$(VERSION)/func_02_pong.c \
$(PACKAGE)-$(VERSION)/func_02_pongd.c \
$(PACKAGE)-$(VERSION)/func_04_empty_message.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishment.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-server.c \
$(PACKAGE)-$(VERSION)/unit_03_connection-add-remove.c \
$(PACKAGE)-$(VERSION)/func_03_multiple-communications-client.c \
$(PACKAGE)-$(VERSION)/unit_02_usock-remove.c \
$(PACKAGE)-$(VERSION)/func_01_connection_establishmentd.c
help:
@echo ' :: ipc-tests-0.5.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 ' - func_01_connection_establishment binary'
@echo ' - func_01_connection_establishmentd binary'
@echo ' - func_02_pong  binary'
@echo ' - func_02_pongd  binary'
@echo ' - func_03_multiple-communications-client binary'
@echo ' - func_03_multiple-communications-server binary'
@echo ' - func_04_empty_message binary'
@echo ' - unit_01_service-path binary'
@echo ' - unit_02_usock-remove binary'
@echo ' - unit_03_connection-add-remove binary'
@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

@ -8,22 +8,26 @@
int main(int argc, char * argv[], char **env)
{
enum ipc_errors ret;
argc = (int) argc;
argv = (char **) argv;
SECURE_DECLARATION(struct ipc_error, ret);
SECURE_DECLARATION(struct ipc_connection_info,service);
SECURE_DECLARATION(struct ipc_event, event);
ret = ipc_connection (env, &service, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
if (ret.error_code != IPC_ERROR_NONE) {
return EXIT_FAILURE;
}
// ret = ipc_wait_event (services, struct ipc_event *event);
// if (ret != IPC_ERROR_NONE) {
// long timer = 10;
// ret = ipc_wait_event (services, struct ipc_event *event, &timer);
// if (ret.error_code != IPC_ERROR_NONE) {
// return EXIT_FAILURE;
// }
ret = ipc_close (&service);
if (ret != IPC_ERROR_NONE) {
if (ret.error_code != IPC_ERROR_NONE) {
return EXIT_FAILURE;
}

View File

@ -8,24 +8,31 @@
int main(int argc, char * argv[], char **env)
{
enum ipc_errors ret;
argc = (int) argc;
argv = (char **) argv;
SECURE_DECLARATION(struct ipc_connection_info,srv);
long timer = 10;
printf ("func 01 - server init...\n");
ret = ipc_server_init (env, &srv, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
return EXIT_FAILURE;
}
TEST_IPC_Q(ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE);
printf ("func 01 - server init ok\n");
SECURE_DECLARATION(struct ipc_connection_infos, clients);
SECURE_DECLARATION(struct ipc_event,event);
printf ("func 01 - service polling...\n");
// listen only for a single client
ret = ipc_wait_event (&clients, &srv, &event);
TEST_IPC_Q(ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER : {
fprintf(stderr, "time up!\n");
timer = 10;
};
break;
case IPC_EVENT_TYPE_CONNECTION :
{
printf ("ok - connection establishment\n");
@ -44,13 +51,9 @@ int main(int argc, char * argv[], char **env)
printf ("func 01 - closing clients...\n");
ipc_connections_free (&clients);
printf ("func 01 - closing server...\n");
ret = ipc_server_close(&srv);
if (ret != IPC_ERROR_NONE)
{
const char * error_explanation = ipc_errors_get (ret);
printf ("ipc_server_close: %s\n", error_explanation);
}
TEST_IPC_Q(ipc_server_close(&srv), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -9,59 +9,32 @@
#define SERVICE_NAME "pong"
#define PRINTERR(ret,msg) {\
const char * err = ipc_errors_get (ret);\
const char * err = ipc_errors_get (ret.error_code);\
fprintf(stderr, "error while %s: %s\n", msg, err);\
}
void non_interactive (char *env[])
{
enum ipc_errors ret;
struct ipc_message m;
memset (&m, 0, sizeof (struct ipc_message));
SECURE_DECLARATION(struct ipc_connection_info, srv);
// init service
ret = ipc_connection (env, &srv, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application connection");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE);
printf ("msg to send (%ld): %.*s\n", (ssize_t) strlen(MSG) +1, (int) strlen(MSG), MSG);
ret = ipc_message_format_data (&m, /* type */ 'a', MSG, (ssize_t) strlen(MSG) +1);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "message format data");
exit (EXIT_FAILURE);
}
// printf ("msg to send in the client: ");
// ipc_message_print (&m);
ret = ipc_write (&srv, &m);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application write");
exit (EXIT_FAILURE);
}
ipc_message_empty (&m);
ret = ipc_read (&srv, &m);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application read");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_message_format_data (&m, /* type */ 'a', MSG, (ssize_t) strlen(MSG) +1), EXIT_FAILURE);
TEST_IPC_Q(ipc_write (&srv, &m), EXIT_FAILURE);
TEST_IPC_Q(ipc_read (&srv, &m), EXIT_FAILURE);
printf ("msg recv: %s\n", m.payload);
ipc_message_empty (&m);
ret = ipc_close (&srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application close");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE);
}
void interactive (char *env[])
{
enum ipc_errors ret;
SECURE_DECLARATION(struct ipc_connection_info, srv);
// index and version should be filled
@ -69,28 +42,27 @@ void interactive (char *env[])
srv.version = 0;
// init service
ret = ipc_connection (env, &srv, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application connection");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_connection (env, &srv, SERVICE_NAME), EXIT_FAILURE);
SECURE_DECLARATION(struct ipc_event, event);
SECURE_DECLARATION(struct ipc_connection_infos, services);
ipc_add (&services, &srv);
TEST_IPC_Q(ipc_add (&services, &srv), EXIT_FAILURE);
long timer = 10;
while (1) {
printf ("msg to send: ");
fflush (stdout);
ret = ipc_wait_event (&services, NULL, &event);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application peek event");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_wait_event (&services, NULL, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER: {
printf("time up!\n");
timer = 10;
};
break;
case IPC_EVENT_TYPE_EXTRA_SOCKET:
{
struct ipc_message *m = event.m;
@ -101,20 +73,12 @@ void interactive (char *env[])
ipc_connections_free (&services);
ret = ipc_close (&srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application close");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_close (&srv), EXIT_FAILURE);
exit (EXIT_SUCCESS);
}
ret = ipc_write (&srv, m);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret, "application write");
exit (EXIT_FAILURE);
}
TEST_IPC_Q(ipc_write (&srv, m), EXIT_FAILURE);
}
break;
case IPC_EVENT_TYPE_MESSAGE:

View File

@ -8,7 +8,7 @@
#define PONGD_SERVICE_NAME "pong"
#define PRINTERR(ret,msg) {\
const char * err = ipc_errors_get (ret);\
const char * err = ipc_errors_get (ret.error_code);\
fprintf(stderr, "error while %s: %s\n", msg, err);\
}
@ -20,31 +20,34 @@ struct ipc_connection_infos *clients;
void main_loop ()
{
enum ipc_errors ret = 0;
SECURE_DECLARATION(struct ipc_error, ret);
clients = malloc (sizeof (struct ipc_connection_infos));
memset(clients, 0, sizeof(struct ipc_connection_infos));
SECURE_DECLARATION(struct ipc_event,event);
long timer = 10;
while(1) {
// ipc_wait_event provides one event at a time
// warning: event->m is free'ed if not NULL
ret = ipc_wait_event (clients, srv, &event);
if (ret != IPC_ERROR_NONE && ret != IPC_ERROR_CLOSED_RECIPIENT) {
ret = ipc_wait_event (clients, srv, &event, &timer);
if (ret.error_code != IPC_ERROR_NONE && ret.error_code != IPC_ERROR_CLOSED_RECIPIENT) {
PRINTERR(ret,"service poll event");
// the application will shut down, and close the service
ret = ipc_server_close (srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server close");
}
TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE);
exit (EXIT_FAILURE);
}
switch (event.type) {
case IPC_EVENT_TYPE_CONNECTION:
{
case IPC_EVENT_TYPE_TIMER: {
fprintf(stderr, "time up!\n");
timer = 10;
};
break;
case IPC_EVENT_TYPE_CONNECTION: {
cpt++;
printf ("connection: %d clients connected\n", cpt);
printf ("new client has the fd %d\n", ((struct ipc_connection_info*) event.origin)->fd);
@ -67,7 +70,7 @@ void main_loop ()
}
ret = ipc_write (event.origin, m);
if (ret != IPC_ERROR_NONE) {
if (ret.error_code != IPC_ERROR_NONE) {
PRINTERR(ret,"server write");
}
};
@ -95,7 +98,7 @@ void exit_program(int signal)
printf("Quitting, signal: %d\n", signal);
// free remaining clients
for (int i = 0; i < clients->size ; i++) {
for (size_t i = 0; i < clients->size ; i++) {
struct ipc_connection_info *cli = clients->cinfos[i];
if (cli != NULL) {
free (cli);
@ -108,10 +111,7 @@ void exit_program(int signal)
// the application will shut down, and close the service
enum ipc_errors ret = ipc_server_close (srv);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server close");
}
TEST_IPC_Q(ipc_server_close (srv), EXIT_FAILURE);
free (srv);
exit(EXIT_SUCCESS);
@ -137,13 +137,8 @@ int main(int argc, char * argv[], char **env)
srv->index = 0;
srv->version = 0;
// unlink("/tmp/ipc/pongd-0-0");
TEST_IPC_Q(ipc_server_init (env, srv, PONGD_SERVICE_NAME), EXIT_FAILURE);
enum ipc_errors ret = ipc_server_init (env, srv, PONGD_SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
PRINTERR(ret,"server init");
return EXIT_FAILURE;
}
printf ("Listening on %s.\n", srv->spath);
printf("MAIN: server created\n" );

View File

@ -7,24 +7,6 @@
#define SERVICE_NAME "pong"
#define SECURE_MALLOC(p, s, wat) p = malloc (s); if (p == NULL) { wat; }
void connection (char **env, struct ipc_connection_info *ci)
{
enum ipc_errors ret = ipc_connection (env, ci, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
fprintf (stderr, "cannot connect to the server\n");
exit(EXIT_FAILURE);
}
}
void closing (struct ipc_connection_info *ci)
{
enum ipc_errors ret = ipc_close (ci);
if (ret != IPC_ERROR_NONE) {
fprintf (stderr, "cannot close server\n");
exit(EXIT_FAILURE);
}
}
// test the behavior of the server when the client never read its messages
void send_message (struct ipc_connection_info *ci)
@ -48,9 +30,11 @@ void read_message (struct ipc_connection_info *ci)
SECURE_DECLARATION(struct ipc_event, event);
SECURE_DECLARATION(struct ipc_connection_infos, clients);
ipc_add (&clients, ci);
long timer = 10;
ipc_wait_event (&clients, NULL, &event);
TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE);
ipc_wait_event (&clients, NULL, &event, &timer);
switch (event.type) {
case IPC_EVENT_TYPE_MESSAGE : {
@ -72,7 +56,7 @@ void read_message (struct ipc_connection_info *ci)
#else
SECURE_DECLARATION (struct ipc_message, m);
ipc_read (ci, &m);
TEST_IPC_Q(ipc_read (ci, &m), EXIT_FAILURE);
printf ("received message: %*.s\n", m.length, m.payload);
free (m.payload);
#endif
@ -80,18 +64,25 @@ void read_message (struct ipc_connection_info *ci)
int main(int argc, char * argv[], char **env)
{
argc = argc;
argv = argv;
SECURE_DECLARATION(struct ipc_connection_info,srv1);
SECURE_DECLARATION(struct ipc_connection_info,srv2);
SECURE_DECLARATION(struct ipc_event, event);
connection (env, &srv1);
connection (env, &srv2);
TEST_IPC_Q (ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE);
TEST_IPC_Q (ipc_connection (env, &srv2, SERVICE_NAME), EXIT_FAILURE);
send_message (&srv1);
read_message (&srv1);
closing (&srv1);
TEST_IPC_Q (ipc_close (&srv1), EXIT_FAILURE);
send_message (&srv2);
read_message (&srv2);
closing (&srv2);
TEST_IPC_Q (ipc_close (&srv2), EXIT_FAILURE);
return EXIT_SUCCESS;
}

View File

@ -9,14 +9,14 @@
int main_loop(int argc, char * argv[], char **env)
{
enum ipc_errors ret;
argc = argc;
argv = argv;
SECURE_DECLARATION (struct ipc_connection_info, srv);
long timer = 10;
printf ("func 03 - server init...\n");
ret = ipc_server_init (env, &srv, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
exit(EXIT_FAILURE);
}
TEST_IPC_Q (ipc_server_init (env, &srv, SERVICE_NAME), EXIT_FAILURE);
printf ("func 03 - server init ok\n");
SECURE_DECLARATION (struct ipc_connection_infos, clients);
@ -25,9 +25,14 @@ int main_loop(int argc, char * argv[], char **env)
printf ("func 01 - service polling...\n");
// listen only for a single client
while (1) {
ret = ipc_wait_event (&clients, &srv, &event);
TEST_IPC_WAIT_EVENT_Q (ipc_wait_event (&clients, &srv, &event, &timer), EXIT_FAILURE);
switch (event.type) {
case IPC_EVENT_TYPE_TIMER : {
fprintf (stderr, "time up!");
timer = 10;
}
break;
case IPC_EVENT_TYPE_CONNECTION : {
printf ("connection establishment: %d \n", event.origin->fd);
}
@ -54,12 +59,7 @@ int main_loop(int argc, char * argv[], char **env)
printf ("func 03 - closing clients...\n");
ipc_connections_free (&clients);
printf ("func 03 - closing server...\n");
ret = ipc_server_close(&srv);
if (ret != IPC_ERROR_NONE)
{
const char * error_explanation = ipc_errors_get (ret);
printf ("ipc_server_close: %s\n", error_explanation);
}
TEST_IPC_Q (ipc_server_close(&srv), EXIT_FAILURE);
return 0;
}

View File

@ -7,24 +7,6 @@
#define SERVICE_NAME "pong"
#define SECURE_MALLOC(p, s, wat) p = malloc (s); if (p == NULL) { wat; }
void connection (char **env, struct ipc_connection_info *ci)
{
enum ipc_errors ret = ipc_connection (env, ci, SERVICE_NAME);
if (ret != IPC_ERROR_NONE) {
fprintf (stderr, "cannot connect to the server\n");
exit(EXIT_FAILURE);
}
}
void closing (struct ipc_connection_info *ci)
{
enum ipc_errors ret = ipc_close (ci);
if (ret != IPC_ERROR_NONE) {
fprintf (stderr, "cannot close server\n");
exit(EXIT_FAILURE);
}
}
// test the behavior of the server when the client never read its messages
void send_message (struct ipc_connection_info *ci)
@ -61,12 +43,17 @@ void read_message (struct ipc_connection_info *ci)
int main(int argc, char * argv[], char **env)
{
argc = argc;
argv = argv;
SECURE_DECLARATION(struct ipc_connection_info,srv1);
connection (env, &srv1);
TEST_IPC_Q(ipc_connection (env, &srv1, SERVICE_NAME), EXIT_FAILURE);
send_message (&srv1);
read_message (&srv1);
closing (&srv1);
TEST_IPC_Q(ipc_close (&srv1), EXIT_FAILURE);
return EXIT_SUCCESS;
}

28
tests/project.zsh Normal file
View File

@ -0,0 +1,28 @@
package=ipc-tests
version=0.5.0
CFLAGS="-Wall -Wextra -g"
LDFLAGS="-I../src -L../ ../src/ipc.h -lipc"
targets=(
func_01_connection_establishment
func_01_connection_establishmentd
func_02_pong
func_02_pongd
func_03_multiple-communications-client
func_03_multiple-communications-server
func_04_empty_message
unit_01_service-path
unit_02_usock-remove
unit_03_connection-add-remove
)
for i in $targets ; do
type[$i]=binary
sources[$i]="$i.c"
cflags[$i]="-std=c11"
done
dist=(Makefile project.zsh *.c)

View File

@ -19,8 +19,7 @@ int main(int argc, char * argv[])
return EXIT_FAILURE;
}
enum ipc_errors ret = usock_remove (ftr);
if (ret == IPC_ERROR_NONE)
return 0;
return 1;
TEST_IPC_Q (usock_remove (ftr), EXIT_FAILURE);
return EXIT_SUCCESS;
}