Programmation Système Cours 4 IPC: FIFO

Similar documents
Programmation Systèmes Cours 4 IPC: FIFO

Pipes and FIFOs. Woo-Yeong Jeong Computer Systems Laboratory Sungkyunkwan University

Programmation Systèmes Cours 8 Synchronization & File Locking

Contents. PA1 review and introduction to PA2. IPC (Inter-Process Communication) Exercise. I/O redirection Pipes FIFOs

IPC and Unix Special Files

Operating Systems. Lecture 07. System Calls, Input/Output and Error Redirection, Inter-process Communication in Unix/Linux

Contents. IPC (Inter-Process Communication) Representation of open files in kernel I/O redirection Anonymous Pipe Named Pipe (FIFO)

프로세스간통신 (Interprocess communication) i 숙명여대창병모

UNIX System Programming. Overview. 1. A UNIX System. 2. Processes (review) 2.1. Context. Pipes/FIFOs

Programmation Système Cours 5 Memory Mapping

Programmation Systèmes Cours 3 Interprocess Communication and Pipes

Programmation Système Cours 3 Interprocess Communication and Pipes

Topics. Unix Pipes (CSE 422S) In A Nutshell. Ken Wong Washington University. Pipe (Unnamed FIFO) in the Shell.

POSIX Shared Memory. Linux/UNIX IPC Programming. Outline. Michael Kerrisk, man7.org c 2017 November 2017

Outline. Relationship between file descriptors and open files

Outline. OS Interface to Devices. System Input/Output. CSCI 4061 Introduction to Operating Systems. System I/O and Files. Instructor: Abhishek Chandra

I/O OPERATIONS. UNIX Programming 2014 Fall by Euiseong Seo

Interprocess Communication. Originally multiple approaches Today more standard some differences between distributions still exist

I/O OPERATIONS. UNIX Programming 2014 Fall by Euiseong Seo

Operating Systems. Lecture 06. System Calls (Exec, Open, Read, Write) Inter-process Communication in Unix/Linux (PIPE), Use of PIPE on command line

Lecture 17. Log into Linux. Copy two subdirectories in /home/hwang/cs375/lecture17/ $ cp r /home/hwang/cs375/lecture17/*.

Process Management! Goals of this Lecture!

Hyo-bong Son Computer Systems Laboratory Sungkyunkwan University

Preview. Interprocess Communication with Pipe. Pipe from the Parent to the child Pipe from the child to the parent FIFO popen() with r Popen() with w

Files and the Filesystems. Linux Files

CSci 4061 Introduction to Operating Systems. File Systems: Basics

Interprocess Communication E. Im

UNIX System Calls. Sys Calls versus Library Func

Fall 2017 :: CSE 306. File Systems Basics. Nima Honarmand

CSI 402 Lecture 11 (Unix Discussion on Files continued) 11 1 / 19

Lecture 3. Introduction to Unix Systems Programming: Unix File I/O System Calls

CSci 4061 Introduction to Operating Systems. IPC: Basics, Pipes

Outline. CSCI 4730/6730 Systems Programming Refresher. What is a Pipe? Example: Shell Pipes. Programming with Pipes

CMSC 216 Introduction to Computer Systems Lecture 17 Process Control and System-Level I/O

CSci 4061 Introduction to Operating Systems. IPC: Basics, Pipes

CSci 4061 Introduction to Operating Systems. IPC: Basics, Pipes

Goals of this Lecture

NETWORK AND SYSTEM PROGRAMMING

I/O Management! Goals of this Lecture!

I/O Management! Goals of this Lecture!

CptS 360 (System Programming) Unit 6: Files and Directories

CS 33. Files Part 2. CS33 Intro to Computer Systems XXI 1 Copyright 2018 Thomas W. Doeppner. All rights reserved.

Systems Programming. COSC Software Tools. Systems Programming. High-Level vs. Low-Level. High-Level vs. Low-Level.

CSE 333 SECTION 3. POSIX I/O Functions

UNIT III- INTER PROCESS COMMUNICATIONS Part A

File Descriptors and Piping

Lecture files in /home/hwang/cs375/lecture05 on csserver.

Ricardo Rocha. Department of Computer Science Faculty of Sciences University of Porto

Processes COMPSCI 386

Design Overview of the FreeBSD Kernel. Organization of the Kernel. What Code is Machine Independent?

ECE 650 Systems Programming & Engineering. Spring 2018

Outline. Overview. Linux-specific, since kernel 2.6.0

Like select() and poll(), epoll can monitor multiple FDs epoll returns readiness information in similar manner to poll() Two main advantages:

Maria Hybinette, UGA. ! One easy way to communicate is to use files. ! File descriptors. 3 Maria Hybinette, UGA. ! Simple example: who sort

UNIX input and output

Inter-Process Communication

CSC209H Lecture 7. Dan Zingaro. February 25, 2015

CSE 410: Systems Programming

All the scoring jobs will be done by script

Unix File and I/O. Outline. Storing Information. File Systems. (USP Chapters 4 and 5) Instructor: Dr. Tongping Liu

Design Overview of the FreeBSD Kernel CIS 657

Files and Directories

Processes often need to communicate. CSCB09: Software Tools and Systems Programming. Solution: Pipes. Recall: I/O mechanisms in C

COP 4604 UNIX System Programming IPC. Dr. Sam Hsu Computer Science & Engineering Florida Atlantic University

Basic OS Progamming Abstrac2ons

INTRODUCTION TO THE UNIX FILE SYSTEM 1)

CSC209: Software tools. Unix files and directories permissions utilities/commands Shell programming quoting wild cards files

CSC209: Software tools. Unix files and directories permissions utilities/commands Shell programming quoting wild cards files. Compiler vs.

Chapter 1 - Introduction. September 8, 2016

Programmation Systèmes Cours 2 Process Management Basics

CS 201. Files and I/O. Gerson Robboy Portland State University

Basic OS Progamming Abstrac7ons

Preview. System Call. System Call. System Call. System Call. Library Functions 9/20/2018. System Call

INTER-PROCESS COMMUNICATION. UNIX Programming 2015 Fall by Euiseong Seo

CSE 410: Systems Programming

System Calls. Library Functions Vs. System Calls. Library Functions Vs. System Calls

File I/O. Dong-kun Shin Embedded Software Laboratory Sungkyunkwan University Embedded Software Lab.

Conduite de Projet Cours 4 The C build process

What Is Operating System? Operating Systems, System Calls, and Buffered I/O. Academic Computers in 1983 and Operating System

CS240: Programming in C

OS COMPONENTS OVERVIEW OF UNIX FILE I/O. CS124 Operating Systems Fall , Lecture 2

Advanced Unix/Linux System Program. Instructor: William W.Y. Hsu

UNIX Files. How UNIX Sees and Uses Files

Process Management 1

The bigger picture. File systems. User space operations. What s a file. A file system is the user space implementation of persistent storage.

CS240: Programming in C

Section 3: File I/O, JSON, Generics. Meghan Cowan

CS631 - Advanced Programming in the UNIX Environment Interprocess Communication I

CS 471 Operating Systems. Yue Cheng. George Mason University Fall 2017

Virtual File System. Don Porter CSE 306

Process Creation in UNIX

File I/O. Jin-Soo Kim Computer Systems Laboratory Sungkyunkwan University

Process Management! Goals of this Lecture!

All the scoring jobs will be done by script

How do we define pointers? Memory allocation. Syntax. Notes. Pointers to variables. Pointers to structures. Pointers to functions. Notes.

Chapter 3: Processes. Operating System Concepts 8 th Edition,

Lecture 21 Systems Programming in C

CSE 333 SECTION 3. POSIX I/O Functions

CSC 271 Software I: Utilities and Internals

Pipes. Pipes Implement a FIFO. Pipes (cont d) SWE 545. Pipes. A FIFO (First In, First Out) buffer is like a. Pipes are uni-directional

Transcription:

Programmation Système Cours 4 IPC: FIFO Stefano Zacchiroli zack@pps.univ-paris-diderot.fr Laboratoire PPS, Université Paris Diderot 2014 2015 URL http://upsilon.cc/zack/teaching/1415/progsyst/ Copyright 2011 2015 Stefano Zacchiroli License Creative Commons Attribution-ShareAlike 4.0 International License http://creativecommons.org/licenses/by-sa/4.0/deed.en_us Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 1 / 41

Outline 1 FIFOs 2 FIFO-based architectures Multiplying output streams Client-server FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 2 / 41

Outline 1 FIFOs 2 FIFO-based architectures Multiplying output streams Client-server FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 3 / 41

Pipes looking back Pros: 1 very simple data transfer model with implicit synchronization on read/write operations 2 use well-known and versatile handles: file descriptors 3 simple access control model: create before fork, all related processes can access 4 highly portable Cons: 1 can be used only by related processes 2 communication is kernel mediated and requires double copy For most applications, (2) is not a big deal. On the other hand, (1) makes impossible quite a number of architectures (e.g. client-server among unrelated processes). Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 4 / 41

On pipes restrictions Why can t pipe be used for communication across unrelated processes? 1 we can pass FDs around via UNIX domain sockets, but then we already have an IPC mechanism among unrelated processes... Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 5 / 41

On pipes restrictions Why can t pipe be used for communication across unrelated processes? 1 naming scheme pipes are anonymous they are requested to the kernel and accessed via FDs there is no (handy) way to reference them from the outside 1 2 access control all or nothing among related processes who see the FD... and all or nothing is too coarse-grained for unrelated processes 1 we can pass FDs around via UNIX domain sockets, but then we already have an IPC mechanism among unrelated processes... Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 5 / 41

Named pipes To overcome pipes limitations we need: a naming scheme that is valid between unrelated processes a fine-grained access control mechanism Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 6 / 41

Named pipes To overcome pipes limitations we need: a naming scheme that is valid between unrelated processes idea: let s use filesystem pathnames a fine-grained access control mechanism idea: let s use filesystem permission masks Let s use the filesystem! Design choice coherent with UNIX everything is a file mantra. Putting the pieces together we obtain FIFOs, AKA named pipes: conceptually similar to pipes, but exist on the filesystem and are accessed from it. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 6 / 41

FIFOs IPC characteristics data transfer, byte stream IPC facility that connect processes; the byte stream written to one end of the FIFO can be read from the other pathname identifiers are used to rendez-vous on FIFOs once opened, FIFOs are referenced by file descriptor handles accessible by unrelated processes filesystem-persistent; they disappear when unlinked (i.e. deleted ) from the containing directory highly portable: available on all known UNIX-es Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 7 / 41

FIFOs file system details FIFOs can be created in the shell using mkfifo(1) a FIFO is a special file (i.e. non regular) that exists on the file system S_ISFIFO() will return true on stat s s_mode field lseek will fail and set errno to ESPIPE (the same happen with pipes and sockets) permission masks can be decided upon creation and/or changed with chmod, as usual (thanks to uniformity) FIFOs can be used by programs as ordinary files open, read, write, unlink, etc.... as long as seeking is not needed Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 8 / 41

FIFOs file system details FIFOs can be created in the shell using mkfifo(1) a FIFO is a special file (i.e. non regular) that exists on the file system S_ISFIFO() will return true on stat s s_mode field lseek will fail and set errno to ESPIPE (the same happen with pipes and sockets) permission masks can be decided upon creation and/or changed with chmod, as usual (thanks to uniformity) FIFOs can be used by programs as ordinary files open, read, write, unlink, etc.... as long as seeking is not needed Demo Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 8 / 41

FIFO creation Given that open and creat only allow to create regular files, we need a different system call to create FIFOs. mkfifo (homonymous with the command line utility) allows to do so: #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode); Returns: 0 if OK, -1 on error mode has the same semantics of open/creat syscalls: it specifies the desired permission mask for the FIFO it will be bitwise AND-ed with the complement of current umask on most UNIX implementations, mkfifo is a wrapper around the more generic mknod, that allows to create all kinds of files mkfifo(path) = mknod(path, S_IFIFO, 0) the above is in fact the only portable use of mknod Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 9 / 41

FIFO example #include <errno. h> #include < f c n t l. h> #include <sys/ stat. h> #include <unistd. h> #include " helpers. h" #define BUFFSIZE 4096 #define FIFO_PATH " f i f o " int main ( void ) { int n, fd ; char buf [ BUFFSIZE ] ; i f ( mkfifo ( FIFO_PATH, S_IRUSR S_IWUSR ) < 0 && errno!= EEXIST ) err_sys ( " f i f o error " ) ; p r i n t f ( " opening %s... \ n", FIFO_PATH ) ; i f ( ( fd = open ( FIFO_PATH, O_RDONLY) ) < 0) err_sys ( "open error " ) ; p r i n t f ( " entering main loop... \ n" ) ; while ( ( n = read ( fd, buf, BUFFSIZE ) ) > 0) i f ( write ( STDOUT_FILENO, buf, n )!= n ) err_sys ( " write error " ) ; i f ( n < 0) err_sys ( " read error " ) ; exit ( EXIT_SUCCESS ) ; } // f i f o cat. c Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 10 / 41

FIFO example (cont.) Demo Notes: we create the FIFO only if needed, otherwise we reuse the existing one (filesystem persistence) open blocks until a writer arrives when the last writer terminates, the reader gets a EOF Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 10 / 41

FIFOs synchronization The most simple use case for FIFOs is synchronization between 2 processes: 1 reading from + 1 writing to the FIFO. FIFOs have an unusual open semantics built around it: a process opening a FIFO for reading (O_RDONLY) will block... note: usually read could block waiting for data, open could not a process opening a FIFO for writing (O_WRONLY) will block...... until another process opens the FIFO for the complementary action The kernel enforces 2-peer synchronization upon FIFO open. if the other end of the FIFO is already open (i.e. after synchronization between 2 processes has already happened), open will return immediately Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 11 / 41

FIFOs non-blocking behavior In those rare cases when you want to avoid blocking on FIFOs open, you can request non-blocking I/O with the O_NONBLOCK open flag. open with O_RDONLY will return immediately (opening read end) read-s on the FIFO before any connected writer will become available won t block, but rather return no data (coherently with the usual discipline of non-blocking I/O) open with O_WRONLY will return an ENXIO error until the read end of the FIFO has already been opened They behave differently because the consequences of writing to a FIFO with no readers are more severe (SIGPIPE). Table: FIFO open behavior type flags other end open other end closed reading immediate success blocks reading O_NONBLOCK immediate success immediate success writing immediate success blocks writing O_NONBLOCK immediate success fails (ENXIO) Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 12 / 41

FIFOs the O_RDWR trick On many UNIX-es (including Linux), opening a FIFO with the O_RDWR will never block. It will return successfully and mark both ends as open. used to open a FIFO for writing before a reader is available non portable, use with caution or prefer O_NONBLOCK all together Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 13 / 41

FIFOs multiple readers/writers Multiple readers/writer to FIFOs are common. The main intuition to keep in mind is that the kernel maintains a count of the number of connected readers/writers and will not complain until at least 1 reader and 1 writer exist. as it happens with pipes, writing to a FIFO with no connected readers will fail with EPIPE and also deliver a SIGPIPE signal to the writer reading to a FIFO with no connected writers will return an EOF to the reader (as we ve seen) The O_RDWR trick can be used to fool the count of connected readers/writers and ensure that both are above zero. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 14 / 41

O_RDWR trick example #include <errno. h> #include < f c n t l. h> #include <sys/ stat. h> #include <unistd. h> #include " helpers. h" #define BUFFSIZE 4096 #define FIFO_PATH " f i f o " int main ( void ) { int n, fd ; char buf [ BUFFSIZE ] ; i f ( mkfifo ( FIFO_PATH, S_IRUSR S_IWUSR ) < 0 && errno!= EEXIST ) err_sys ( " f i f o error " ) ; p r i n t f ( " opening %s... \ n", FIFO_PATH ) ; i f ( ( fd = open ( FIFO_PATH, O_RDWR) ) < 0) /* non portable! */ err_sys ( "open error " ) ; p r i n t f ( " entering main loop... \ n" ) ; while ( ( n = read ( fd, buf, BUFFSIZE ) ) > 0) i f ( write ( STDOUT_FILENO, buf, n )!= n ) err_sys ( " write error " ) ; i f ( n < 0) err_sys ( " read error " ) ; exit ( EXIT_SUCCESS ) ; } // f i f o cat t r i c k. c Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 15 / 41

O_RDWR trick example (cont.) Demo Notes: the only difference is in the O_RDWR flag open no longer blocks the program is now persistent: it will not die when the last writer disappear and can serve subsequent writers (what would happen if we connect multiple reader to the same pipe?) Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 15 / 41

Outline 1 FIFOs 2 FIFO-based architectures Multiplying output streams Client-server FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 16 / 41

Outline 1 FIFOs 2 FIFO-based architectures Multiplying output streams Client-server FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 17 / 41

Linear process combination Shell pipelines p 1... p n allow to create linear combinations where n processes (usually filters) cooperate using n 1 UNIX pipes (created by the shell). the input of each process is either STDIN or the output of the previous process in the pipeline the output of each process is either STDOUT or the output of the next process in the pipeline the output of each process is consumed exactly once Relying only on pipelines, we cannot process the output of a given process more than once (i.e. non-linearly) Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 18 / 41

Duplicating output streams with FIFOs Use case We want to process STDIN first with a filter prog1 and then process the result with two programs prog2 and prog3 without using temporary files. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 19 / 41

Duplicating output streams with FIFOs Use case We want to process STDIN first with a filter prog1 and then process the result with two programs prog2 and prog3 without using temporary files. We will use two tools: 1 tee(1) a cat replacement that also writes to a file mnemonic: tee as the letter T 2 FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 19 / 41

Duplicating output streams with FIFOs Use case We want to process STDIN first with a filter prog1 and then process the result with two programs prog2 and prog3 without using temporary files. We will use two tools: 1 tee(1) a cat replacement that also writes to a file mnemonic: tee as the letter T 2 FIFOs Figure: process arrangement Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 19 / 41

Duplicating output streams with FIFOs example $ mkfifo f i f o $ wc l < f i f o & $ l s l tee f i f o sort k5n <snip > $ Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 20 / 41

Duplicating output streams with FIFOs example $ mkfifo f i f o $ wc l < f i f o & $ l s l tee f i f o sort k5n <snip > $ will show the number of (non-hidden) files in the current working directory (thanks to wc -l), as well as the details of each of them presented in increasing size order (thanks to ls -l) Figure: process arrangement Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 20 / 41

Multiplying output streams with FIFOs can we generalize the scheme to multiply the output and process it n times? Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 21 / 41

Multiplying output streams with FIFOs intuition: each FIFO/tee block allows to add one extra branch in the pipeline we can scale up to n extra branches with n 1 FIFO/tee blocks Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 21 / 41

Outline 1 FIFOs 2 FIFO-based architectures Multiplying output streams Client-server FIFOs Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 22 / 41

Client-server FIFOs FIFOs can be used (with some care) to implement client-server architectures meant to run on a single machine e.g. daemons offering system services to local programs to find some, try find /var -type p (as root) In its simplest form, a FIFO-based client-server architecture works as follows: 0 a filesystem path pointing to a FIFO is agreed upon by server/clients and used as the well-known address of the service 1 the FIFO is either persistent (e.g. created at install-time) or created by the server at startup 2 the clients write requests to the FIFO 3 the server reads requests from the FIFO and handles them sequentially Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 23 / 41

Client-server FIFOs architecture APUE, Figure 15.22 Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 24 / 41

Client-server FIFOs atomic write Even with such a simple architecture, we need to worry about race conditions. For all requests of size greater than 1 byte, we need to worry about interleaving issues, since the FIFO is shared among the server and all its clients. the usual solution would be to do proper synchronization and ensure that only one client at a time write its request to the FIFO Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 25 / 41

Client-server FIFOs atomic write Even with such a simple architecture, we need to worry about race conditions. For all requests of size greater than 1 byte, we need to worry about interleaving issues, since the FIFO is shared among the server and all its clients. the usual solution would be to do proper synchronization and ensure that only one client at a time write its request to the FIFO luckily, UNIX kernels also offer a simpler solution: All write of size PIPE_BUF or less to pipes or FIFOs are guaranteed (by POSIX) to be atomic. if all write-s to the shared FIFO are smaller than PIPE_BUF, no interleaving can happen Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 25 / 41

How much is PIPE_BUF? The value is implementation-dependent, but with a guaranteed minimum of 512 bytes. #include <limits. h> #include <stdio. h> #include <stdlib. h> int main ( void ) { p r i n t f ( " PIPE_BUF : %d\n", PIPE_BUF ) ; exit ( EXIT_SUCCESS ) ; } $. / pipe buf PIPE_BUF : 4096 $ # on Linux x86, 64 b i t s It s more than enough for most control languages, but we need to use different IPC objects for actual atomic data transfer. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 26 / 41

Messages within byte streams FIFOs offer a byte stream IPC facility, while client-server architectures often rely on separate messages. There are several ways to do message-oriented communication using byte streams: 1 terminate each message with a delimiter character pro: easy for the sender con: might need to escape the delimiter character con: forces receiver to scan the stream one char at a time delimiter char data data data TLPI, Figure 44-7 Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 27 / 41

Messages within byte streams (cont.) FIFOs offer a byte stream IPC facility, while client-server architectures often rely on separate messages. There are several ways to do message-oriented communication using byte streams: 2 prefix each message with a fixed-size header containing a length field pro: efficient (read the header first, then the rest) con: malformed messages (hence the need of CRC or equivalent) len bytes len data len data len data TLPI, Figure 44-7 Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 27 / 41

Messages within byte streams (cont.) FIFOs offer a byte stream IPC facility, while client-server architectures often rely on separate messages. There are several ways to do message-oriented communication using byte streams: 3 use fixed-length messages pro: very simple to program con: impose a maximum message size con: padding n bytes n bytes n bytes data data data TLPI, Figure 44-7 Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 27 / 41

Messages within byte streams (cont.) FIFOs offer a byte stream IPC facility, while client-server architectures often rely on separate messages. There are several ways to do message-oriented communication using byte streams: In the case of pipes and FIFOs, we additionally have PIPE_BUF as message size upper bound to avoid interleaving. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 27 / 41

Client-server FIFOs case study Example We want to implement a local server that, upon reading a reload command from a FIFO, will reread the /etc/motd file from disk and print it on stdout. using the architecture we have discussed...... and fixed-length messages Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 28 / 41

Client-server FIFOs case study (protocol) #include <errno. h> #include < f c n t l. h> #include <string. h> #include <sys/ stat. h> #include <unistd. h> #include " helpers. h" #define FIFO_PATH " f i f o " #define ACT_RELOAD 17 struct request { int action ; /* one of ACT_* macros */ } ; // common 1.h Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 29 / 41

Client-server FIFOs case study (server) #include "common 1.h" #define BUFFSIZE 4096 #define MOTD_PATH " / etc /motd" void print_motd ( void ) { int fd, n ; char buf [ BUFFSIZE ] ; i f ( ( fd = open (MOTD_PATH, O_RDONLY) ) < 0) err_sys ( "open error " ) ; while ( ( n = read ( fd, buf, BUFFSIZE ) ) > 0) i f ( write ( STDOUT_FILENO, buf, n )!= n ) err_sys ( " write error " ) ; close ( fd ) ; } Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 30 / 41

Client-server FIFOs case study (server) (cont.) int main ( void ) { int fd ; struct request req ; i f ( mkfifo ( FIFO_PATH, S_IRUSR S_IWUSR ) < 0 && errno!= EEXIST ) err_sys ( " f i f o error " ) ; i f ( ( fd = open ( FIFO_PATH, O_RDWR) ) < 0) err_sys ( "open error " ) ; print_motd ( ) ; for ( ; ; ) { i f ( read ( fd, &req, sizeof ( struct request ) )!= sizeof ( struct request ) ) continue ; /* partial read or error */ switch ( req. action ) { case ACT_RELOAD: p r i n t f ( " **** reload ****\n" ) ; print_motd ( ) ; break ; default : p r i n t f ( " **** i n v a l i d request ****\n" ) ; break ; } } exit ( EXIT_SUCCESS ) ; } // server 1.c Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 30 / 41

Client-server FIFOs case study (client) #include "common 1.h" int main ( void ) { int fd ; struct request req ; i f ( ( fd = open ( FIFO_PATH, O_WRONLY) ) < 0) err_sys ( "open error " ) ; req. action = ACT_RELOAD; i f ( write ( fd, &req, sizeof ( struct request ) )!= sizeof ( struct request ) ) err_sys ( " write error " ) ; exit ( EXIT_SUCCESS ) ; } // client 1.c Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 31 / 41

Client-server FIFOs case study Demo Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 32 / 41

Client-server FIFOs exercise Exercise Add to the protocol a new action (e.g., ACT_EXIT) that clients can send to the server to ask it to voluntarily terminate. Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 33 / 41

Client-server FIFOs request-response The previous architecture is not suitable for client-server request-response architectures where the server, in response to incoming request, has both to act and reply to the client. why? Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 34 / 41

Client-server FIFOs request-response The previous architecture is not suitable for client-server request-response architectures where the server, in response to incoming request, has both to act and reply to the client. The problem: we cannot send replies trough the shared FIFO, because we don t know which of the client will read the message. We need a context where to correlate responses with the corresponding requests. Note: PIPE_BUF guarantees are unrelated from this. To do so we can: use the shared FIFO for incoming requests only use client-specific FIFOs (one per client) to send back responses Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 34 / 41

Client-server request-response FIFOs architecture Client A (PID=6514) Client B (PID=6523) Request (PID +length) Request (PID +length) Client A FIFO / tmp/ seqnum_cl. 6514 Server FIFO / tmp/ seqnum_sv Client B FIFO / tmp/ seqnum_cl. 6523 Response (seq. #) Response (seq. #) Server TLPI, Figure 44-6 Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 35 / 41

Client-server request-response FIFOs naming For the architecture to work, clients and server must agree on the pathname of each client-specific FIFO. Common solutions are: the client tells the server where he should send the response, by including the pathname in the request clients and server agrees on a naming scheme based on some client identifier, and the client sends the identifier as part of the request e.g. we say that client-specific FIFOs will be named /var/run/my-server/client-%d.fifo where %d is the client PID 2 2 we are ignoring security issues here... Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 36 / 41

Request-response FIFOs example Example We want to implement a server that allocates unique sequential identifiers to clients. the server hold a global integer counter the client connect to the server to request a new unique identifier in the sequence the server send back the next integer in the sequence and update the global counter We will use a client-server request-response FIFO architecture: client server requests are sent via a shared FIFO server client responses are sent via client-specific FIFOs server client rendez-vous happens via a PID-based naming scheme Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 37 / 41

Request-response FIFOs example (protocol) #include <errno. h> #include < f c n t l. h> #include <signal. h> #include <string. h> #include <sys/ stat. h> #include <unistd. h> #include " helpers. h" #define SRV_FIFO "seqnum srv " #define CLI_FIFO_TPL "seqnum c l i.% ld " #define CLI_FIFO_LEN ( sizeof ( CLI_FIFO_TPL ) + 20) struct request { /* Request ( c l i e n t > server ) */ pid_t pid ; /* PID of c l i e n t */ } ; struct response { /* Response ( server > c l i e n t ) */ int seqno ; /* Sequence number */ } ; /* fifo_seqnum. h based on TLPI s fifo_seqnum. h Copyright (C) Michael Kerrisk, 2010. License : GNU AGPL */ Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 38 / 41

Request-response FIFOs example (server) #include " fifo_seqnum. h" int main ( void ) { int srv_fd, c l i _ f d ; char c l i _ f i f o [ CLI_FIFO_LEN ] ; struct request req ; struct response res ; int seqno = 0; i f ( mkfifo ( SRV_FIFO, S_IRUSR S_IWUSR S_IWGRP ) < 0 && errno!= EEXIST ) err_sys ( " mkfifo error " ) ; i f ( ( srv_fd = open ( SRV_FIFO, O_RDWR) ) < 0) err_sys ( "open error " ) ; i f ( signal ( SIGPIPE, SIG_IGN ) == SIG_ERR ) err_sys ( " signal " ) ; for ( ; ; ) { /* main request /response loop */ i f ( read ( srv_fd, &req, sizeof ( struct request ) )!= sizeof ( struct request ) ) continue ; Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 39 / 41

Request-response FIFOs example (server) (cont.) snprintf ( c l i _ f i f o, CLI_FIFO_LEN, CLI_FIFO_TPL, ( long ) req. pid ) ; i f ( ( c l i _ f d = open ( c l i _ f i f o, O_WRONLY) ) < 0) { err_msg ( "open error ( c l i e n t FIFO ) " ) ; continue ; } res. seqno = seqno ; i f ( write ( c l i _ f d, &res, sizeof ( struct response ) )!= sizeof ( struct response ) ) err_msg ( " write error ( c l i e n t FIFO ) " ) ; i f ( close ( c l i _ f d ) == 1) err_msg ( " close " ) ; } } seqno++; /* fifo_seqnum_server. c based on TLPI s fifo_seqnum_server. c Copyright (C) Michael Kerrisk, 2010. License : GNU AGPL */ Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 39 / 41

Request-response FIFOs example (client) #include " fifo_seqnum. h" static char c l i _ f i f o [ CLI_FIFO_LEN ] ; void remove_fifo ( void ) { unlink ( c l i _ f i f o ) ; } int main ( void ) { int srv_fd, c l i _ f d ; struct request req ; struct response resp ; snprintf ( c l i _ f i f o, CLI_FIFO_LEN, CLI_FIFO_TPL, ( long ) getpid ( ) ) ; i f ( mkfifo ( c l i _ f i f o, S_IRUSR S_IWUSR S_IWGRP ) == 1 && errno!= EEXIST ) err_sys ( " mkfifo error " ) ; i f ( atexit ( remove_fifo )!= 0) err_sys ( " atexit error " ) ; Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 40 / 41

Request-response FIFOs example (client) (cont.) req. pid = getpid ( ) ; i f ( ( srv_fd = open ( SRV_FIFO, O_WRONLY) ) < 0) err_sys ( "open error ( server FIFO ) " ) ; i f ( write ( srv_fd, &req, sizeof ( struct request ) )!= sizeof ( struct request ) ) err_sys ( " write error " ) ; i f ( ( c l i _ f d = open ( c l i _ f i f o, O_RDONLY) ) < 0) err_sys ( "open error ( c l i e n t FIFO ) " ) ; i f ( read ( c l i _ f d, &resp, sizeof ( struct response ) )!= sizeof ( struct response ) ) err_sys ( " read error " ) ; } p r i n t f ( "%d\n", resp. seqno ) ; exit ( EXIT_SUCCESS ) ; /* fifo_seqnum_client. c based on TLPI s fifo_seqnum_client. c Copyright ( C) Michael Kerrisk, 2010. License : GNU AGPL */ Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 40 / 41

Request-response FIFOs example Demo Stefano Zacchiroli (Paris Diderot) IPC: FIFO 2014 2015 41 / 41