versione di listings.
\const{INADDR\_ANY}, il cui valore, come visto anche negli esempi precedenti
è pari a zero, nell'esempio \figref{fig:net_serv_code} si è usata
un'assegnazione immediata del tipo:
-
-\begin{lstlisting}[stepnumber=0,frame=]{}
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
-\end{lstlisting}
+\includecodesnip{listati/serv_addr_sin_addr.c}
Si noti che si è usato \func{htonl} per assegnare il valore
\const{INADDR\_ANY}, benché essendo questo pari a zero il riordinamento sia
\const{in6addr\_any} (dichiarata come \direct{extern}, ed inizializzata dal
sistema al valore \const{IN6ADRR\_ANY\_INIT}) che permette di effettuare una
assegnazione del tipo:
-\begin{lstlisting}[stepnumber=0,frame=]{}
- serv_add.sin6_addr = in6addr_any; /* connect from anywhere */
-\end{lstlisting}
+\includecodesnip{listati/serv_addr_sin6_addr.c}
in maniera analoga si può utilizzare la variabile \const{in6addr\_loopback}
per indicare l'indirizzo di \textit{loopback}, che a sua volta viene
inizializzata staticamente a \const{IN6ADRR\_LOOPBACK\_INIT}.
\file{ElemDaytimeTCPCuncServ.c} è allegato nella directory dei sorgenti.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utililites */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-
-int main(int argc, char *argv[])
-{
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add, client;
- char buffer[MAXLINE];
- socklen_t len;
- time_t timeval;
- pid_t pid;
- int logging=0;
- ...
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
- <0 ) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd);
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- if (logging) {
- inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
- printf("Request from host %s, port %d\n", buffer,
- ntohs(client.sin_port));
- }
- close(conn_fd);
- exit(0);
- } else { /* parent */
- close(conn_fd);
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/ElemDaytimeTCPCuncServ.c}
+ \end{minipage}
+ \normalsize
\caption{Esempio di codice di un server concorrente elementare per il
servizio daytime.}
\label{fig:TCPel_serv_code}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
-};
- \end{lstlisting}
+ \includestruct{listati/pollfd.h}
\end{minipage}
\normalsize
- \caption{La struttura \struct{pollfd}, utilizzata per specificare le modalità
- di controllo di un file descriptor alla funzione \func{poll}.}
+ \caption{La struttura \structd{pollfd}, utilizzata per specificare le
+ modalità di controllo di un file descriptor alla funzione \func{poll}.}
\label{fig:file_pollfd}
\end{figure}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct aiocb
-{
- int aio_fildes; /* File descriptor. */
- off_t aio_offset; /* File offset */
- int aio_lio_opcode; /* Operation to be performed. */
- int aio_reqprio; /* Request priority offset. */
- volatile void *aio_buf; /* Location of buffer. */
- size_t aio_nbytes; /* Length of transfer. */
- struct sigevent aio_sigevent; /* Signal number and value. */
-};
- \end{lstlisting}
+ \includestruct{listati/aiocb.h}
\end{minipage}
\normalsize
- \caption{La struttura \struct{aiocb}, usata per il controllo dell'I/O
+ \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
asincrono.}
\label{fig:file_aiocb}
\end{figure}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sigevent
-{
- sigval_t sigev_value;
- int sigev_signo;
- int sigev_notify;
- void (*sigev_notify_function)(sigval_t);
- pthread_attr_t *sigev_notify_attributes;
-};
- \end{lstlisting}
+ \includestruct{listati/sigevent.h}
\end{minipage}
\normalsize
- \caption{La struttura \struct{sigevent}, usata per specificare le modalità di
- notifica degli eventi relativi alle operazioni di I/O asincrono.}
+ \caption{La struttura \structd{sigevent}, usata per specificare le modalità
+ di notifica degli eventi relativi alle operazioni di I/O asincrono.}
\label{fig:file_sigevent}
\end{figure}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct iovec {
- __ptr_t iov_base; /* Starting address */
- size_t iov_len; /* Length in bytes */
-};
- \end{lstlisting}
+ \includestruct{listati/iovec.h}
\end{minipage}
\normalsize
- \caption{La struttura \struct{iovec}, usata dalle operazioni di I/O
+ \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
vettorizzato.}
\label{fig:file_iovec}
\end{figure}
\begin{figure}[!bht]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct flock {
- short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
- short int l_whence; /* Where `l_start' is relative to (like `lseek').*/
- off_t l_start; /* Offset where the lock begins. */
- off_t l_len; /* Size of the locked area; zero means until EOF.*/
- pid_t l_pid; /* Process holding the lock. */
-};
- \end{lstlisting}
+ \includestruct{listati/flock.h}
\end{minipage}
\normalsize
- \caption{La struttura \struct{flock}, usata da \func{fcntl} per il file
+ \caption{La struttura \structd{flock}, usata da \func{fcntl} per il file
locking.}
\label{fig:struct_flock}
\end{figure}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- int type = F_UNLCK; /* lock type: default to unlock (invalid) */
- off_t start = 0; /* start of the locked region: default to 0 */
- off_t len = 0; /* length of the locked region: default to 0 */
- int fd, res, i; /* internal variables */
- int bsd = 0; /* semantic type: default to POSIX */
- int cmd = F_SETLK; /* lock command: default to non-blocking */
- struct flock lock; /* file lock structure */
- ...
- if ((argc - optind) != 1) { /* There must be remaing parameters */
- printf("Wrong number of arguments %d\n", argc - optind);
- usage();
- }
- if (type == F_UNLCK) { /* There must be a -w or -r option set */
- printf("You should set a read or a write lock\n");
- usage();
- }
- fd = open(argv[optind], O_RDWR); /* open the file to be locked */
- if (fd < 0) { /* on error exit */
- perror("Wrong filename");
- exit(1);
- }
- /* do lock */
- if (bsd) { /* if BSD locking */
- /* rewrite cmd for suitables flock operation values */
- if (cmd == F_SETLKW) { /* if no-blocking */
- cmd = LOCK_NB; /* set the value for flock operation */
- } else { /* else */
- cmd = 0; /* default is null */
- }
- if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
- if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
- res = flock(fd, cmd); /* esecute lock */
- } else { /* if POSIX locking */
- /* setting flock structure */
- lock.l_type = type; /* set type: read or write */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = start; /* set the start of the locked region */
- lock.l_len = len; /* set the length of the locked region */
- res = fcntl(fd, cmd, &lock); /* do lock */
- }
- /* check lock results */
- if (res) { /* on error exit */
- perror("Failed lock");
- exit(1);
- } else { /* else write message */
- printf("Lock acquired\n");
- }
- pause(); /* stop the process, use a signal to exit */
- return 0;
-}
- \end{lstlisting}
+ \includecodesample{listati/Flock.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del programma \file{Flock.c}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[], char *envp[])
-{
- ...
- /* create two pipes, pipein and pipeout, to handle communication */
- if ( (retval = pipe(pipein)) ) {
- WriteMess("input pipe creation error");
- exit(0);
- }
- if ( (retval = pipe(pipeout)) ) {
- WriteMess("output pipe creation error");
- exit(0);
- }
- /* First fork: use child to run barcode program */
- if ( (pid = fork()) == -1) { /* on error exit */
- WriteMess("child creation error");
- exit(0);
- }
- /* if child */
- if (pid == 0) {
- close(pipein[1]); /* close pipe write end */
- dup2(pipein[0], STDIN_FILENO); /* remap stdin to pipe read end */
- close(pipeout[0]);
- dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */
- execlp("barcode", "barcode", size, NULL);
- }
- close(pipein[0]); /* close input side of input pipe */
- write(pipein[1], argv[1], strlen(argv[1])); /* write parameter to pipe */
- close(pipein[1]); /* closing write end */
- waitpid(pid, NULL, 0); /* wait child completion */
- /* Second fork: use child to run ghostscript */
- if ( (pid = fork()) == -1) {
- WriteMess("child creation error");
- exit(0);
- }
- /* second child, convert PS to JPEG */
- if (pid == 0) {
- close(pipeout[1]); /* close write end */
- dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */
- /* send mime type */
- write(STDOUT_FILENO, content, strlen(content));
- execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
- }
- /* still parent */
- close(pipeout[1]);
- waitpid(pid, NULL, 0);
- exit(0);
-}
- \end{lstlisting}
+ \includecodesample{listati/BarCodePage.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del \textit{CGI}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[], char *envp[])
-{
- FILE *pipe[4];
- FILE *pipein;
- char *cmd_string[4]={
- "pnmtopng",
- "pnmmargin -white 10",
- "pnmcrop",
- "gs -sDEVICE=ppmraw -sOutputFile=- -sNOPAUSE -q - -c showpage -c quit"
- };
- char content[]="Content-type: image/png\n\n";
- int i;
- /* write mime-type to stdout */
- write(STDOUT_FILENO, content, strlen(content));
- /* execute chain of command */
- for (i=0; i<4; i++) {
- pipe[i] = popen(cmd_string[i], "w");
- dup2(fileno(pipe[i]), STDOUT_FILENO);
- }
- /* create barcode (in PS) */
- pipein = popen("barcode", "w");
- /* send barcode string to barcode program */
- write(fileno(pipein), argv[1], strlen(argv[1]));
- /* close all pipes (in reverse order) */
- for (i=4; i==0; i--) {
- pclose((pipe[i]));
- }
- exit(0);
-}
- \end{lstlisting}
+ \includecodesample{listati/BarCode.c}
\end{minipage}
\normalsize
\caption{Codice completo del \textit{CGI} \file{BarCode.c}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-char *fifoname = "/tmp/fortune.fifo";
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int i, n = 0;
- char *fortunefilename = "/usr/share/games/fortunes/linux";
- char **fortune;
- char line[80];
- int fifo_server, fifo_client;
- int nread;
- ...
- if (n==0) usage(); /* if no pool depth exit printing usage info */
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
- Signal(SIGINT, HandSIGTERM);
- Signal(SIGQUIT, HandSIGTERM);
- i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
- if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
- if (errno!=EEXIST) {
- perror("Cannot create well known fifo");
- exit(1);
- }
- }
- daemon(0, 0);
- /* open fifo two times to avoid EOF */
- fifo_server = open(fifoname, O_RDONLY);
- if (fifo_server < 0) {
- perror("Cannot open read only well known fifo");
- exit(1);
- }
- if (open(fifoname, O_WRONLY) < 0) {
- perror("Cannot open write only well known fifo");
- exit(1);
- }
- /* Main body: loop over requests */
- while (1) {
- nread = read(fifo_server, line, 79); /* read request */
- if (nread < 0) {
- perror("Read Error");
- exit(1);
- }
- line[nread] = 0; /* terminate fifo name string */
- n = random() % i; /* select random value */
- fifo_client = open(line, O_WRONLY); /* open client fifo */
- if (fifo_client < 0) {
- perror("Cannot open");
- exit(1);
- }
- nread = write(fifo_client, /* write phrase */
- fortune[n], strlen(fortune[n])+1);
- close(fifo_client); /* close client fifo */
- }
-}
- \end{lstlisting}
+ \includecodesample{listati/FortuneServer.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del server di \textit{fortunes}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int n = 0;
- char *fortunefilename = "/tmp/fortune.fifo";
- char line[80];
- int fifo_server, fifo_client;
- char fifoname[80];
- int nread;
- char buffer[PIPE_BUF];
- ...
- snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */
- if (mkfifo(fifoname, 0622)) { /* open client fifo */
- if (errno!=EEXIST) {
- perror("Cannot create well known fifo");
- exit(-1);
- }
- }
- fifo_server = open(fortunefilename, O_WRONLY); /* open server fifo */
- if (fifo_server < 0) {
- perror("Cannot open well known fifo");
- exit(-1);
- }
- nread = write(fifo_server, fifoname, strlen(fifoname)+1); /* write name */
- close(fifo_server); /* close server fifo */
- fifo_client = open(fifoname, O_RDONLY); /* open client fifo */
- if (fifo_client < 0) {
- perror("Cannot open well known fifo");
- exit(-1);
- }
- nread = read(fifo_client, buffer, sizeof(buffer)); /* read answer */
- printf("%s", buffer); /* print fortune */
- close(fifo_client); /* close client */
- close(fifo_server); /* close server */
- unlink(fifoname); /* remove client fifo */
-}
- \end{lstlisting}
+ \includecodesample{listati/FortuneClient.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del client di \textit{fortunes}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}%,frame=,indent=1cm ]{}
-struct ipc_perm
-{
- key_t key; /* Key. */
- uid_t uid; /* Owner's user ID. */
- gid_t gid; /* Owner's group ID. */
- uid_t cuid; /* Creator's user ID. */
- gid_t cgid; /* Creator's group ID. */
- unsigned short int mode; /* Read/write permission. */
- unsigned short int seq; /* Sequence number. */
-};
- \end{lstlisting}
+ \includestruct{listati/ipc_perm.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{ipc\_perm}, come definita in
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- ...
- switch (type) {
- case 'q': /* Message Queue */
- debug("Message Queue Try\n");
- for (i=0; i<n; i++) {
- id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- msgctl(id, IPC_RMID, NULL);
- }
- break;
- case 's': /* Semaphore */
- debug("Semaphore\n");
- for (i=0; i<n; i++) {
- id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- semctl(id, 0, IPC_RMID);
- }
- break;
- case 'm': /* Shared Memory */
- debug("Shared Memory\n");
- for (i=0; i<n; i++) {
- id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- shmctl(id, IPC_RMID, NULL);
- }
- break;
- default: /* should not reached */
- return -1;
- }
- return 0;
-}
- \end{lstlisting}
+ \includecodesample{listati/IPCTestId.c}
\end{minipage}
\normalsize
\caption{Sezione principale del programma di test per l'assegnazione degli
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct msqid_ds {
- struct ipc_perm msg_perm; /* structure for operation permission */
- time_t msg_stime; /* time of last msgsnd command */
- time_t msg_rtime; /* time of last msgrcv command */
- time_t msg_ctime; /* time of last change */
- msgqnum_t msg_qnum; /* number of messages currently on queue */
- msglen_t msg_qbytes; /* max number of bytes allowed on queue */
- pid_t msg_lspid; /* pid of last msgsnd() */
- pid_t msg_lrpid; /* pid of last msgrcv() */
- struct msg *msg_first; /* first message on queue, unused */
- struct msg *msg_last; /* last message in queue, unused */
- unsigned long int msg_cbytes; /* current number of bytes on queue */
-};
- \end{lstlisting}
+ \includestruct{listati/msqid_ds.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di
inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato
come illustrato in \secref{sec:ipc_sysv_access_control}, per quanto riguarda
gli altri campi invece:
-\begin{itemize}
+\begin{itemize*}
\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
sulla coda, viene inizializzato a 0.
\item i campi \var{msg\_lspid} e \var{msg\_lrpid}, che esprimono
\var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è
inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
e non devono essere utilizzati da programmi in user space).
-\end{itemize}
+\end{itemize*}
Una volta creata una coda di messaggi le operazioni di controllo vengono
effettuate con la funzione \funcd{msgctl}, che (come le analoghe \func{semctl}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
- struct msgbuf {
- long mtype; /* message type, must be > 0 */
- char mtext[LENGTH]; /* message data */
- };
- \end{lstlisting}
+ \includestruct{listati/msgbuf.h}
\end{minipage}
\normalsize
\caption{Schema della struttura \structd{msgbuf}, da utilizzare come
\begin{figure}[!bht]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int msgid; /* Message queue identifier */
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int i, n = 0;
- char **fortune; /* array of fortune message string */
- char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */
- struct msgbuf_read { /* message struct to read request from clients */
- long mtype; /* message type, must be 1 */
- long pid; /* message data, must be the pid of the client */
- } msg_read;
- struct msgbuf_write { /* message struct to write result to clients */
- long mtype; /* message type, will be the pid of the client*/
- char mtext[MSGMAX]; /* message data, will be the fortune */
- } msg_write;
- key_t key; /* Message queue key */
- int size; /* message size */
- ...
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
- Signal(SIGINT, HandSIGTERM);
- Signal(SIGQUIT, HandSIGTERM);
- if (n==0) usage(); /* if no pool depth exit printing usage info */
- i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
- /* Create the queue */
- key = ftok("./MQFortuneServer.c", 1);
- msgid = msgget(key, IPC_CREAT|0666);
- if (msgid < 0) {
- perror("Cannot create message queue");
- exit(1);
- }
- /* Main body: loop over requests */
- daemon(0, 0);
- while (1) {
- msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR);
- n = random() % i; /* select random value */
- strncpy(msg_write.mtext, fortune[n], MSGMAX);
- size = min(strlen(fortune[n])+1, MSGMAX);
- msg_write.mtype=msg_read.pid; /* use request pid as type */
- msgsnd(msgid, &msg_write, size, 0);
- }
-}
-/*
- * Signal Handler to manage termination
- */
-void HandSIGTERM(int signo) {
- msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
- exit(0);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/MQFortuneServer.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del server di \textit{fortunes}
\begin{figure}[!bht]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- ...
- key = ftok("./MQFortuneServer.c", 1);
- msgid = msgget(key, 0);
- if (msgid < 0) {
- perror("Cannot find message queue");
- exit(1);
- }
- /* Main body: do request and write result */
- msg_read.mtype = 1; /* type for request is always 1 */
- msg_read.pid = getpid(); /* use pid for communications */
- size = sizeof(msg_read.pid);
- msgsnd(msgid, &msg_read, size, 0); /* send request message */
- msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR);
- printf("%s", msg_write.mtext);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/MQFortuneClient.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del client di \textit{fortunes}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct semid_ds
-{
- struct ipc_perm sem_perm; /* operation permission struct */
- time_t sem_otime; /* last semop() time */
- time_t sem_ctime; /* last time changed by semctl() */
- unsigned long int sem_nsems; /* number of semaphores in set */
-};
- \end{lstlisting}
+ \includestruct{listati/semid_ds.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{semid\_ds}, associata a ciascun insieme di
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sem {
- short sempid; /* pid of last operation */
- ushort semval; /* current value */
- ushort semncnt; /* num procs awaiting increase in semval */
- ushort semzcnt; /* num procs awaiting semval = 0 */
-};
- \end{lstlisting}
+ \includestruct{listati/sem.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{sem}, che contiene i dati di un singolo
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-union semun {
- int val; /* value for SETVAL */
- struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* array for GETALL, SETALL */
- /* Linux specific part: */
- struct seminfo *__buf; /* buffer for IPC_INFO */
-};
- \end{lstlisting}
+ \includestruct{listati/semun.h}
\end{minipage}
\normalsize
\caption{La definizione dei possibili valori di una \direct{union}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sembuf
-{
- unsigned short int sem_num; /* semaphore number */
- short int sem_op; /* semaphore operation */
- short int sem_flg; /* operation flag */
-};
- \end{lstlisting}
+ \includestruct{listati/sembuf.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{sembuf}, usata per le operazioni sui
\begin{figure}[!bht]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* Function MutexCreate: create a mutex/semaphore */
-int MutexCreate(key_t ipc_key)
-{
- const union semun semunion={1}; /* semaphore union structure */
- int sem_id, ret;
- sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
- if (sem_id == -1) { /* if error return code */
- return sem_id;
- }
- ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
- if (ret == -1) {
- return ret;
- }
- return sem_id;
-}
-/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */
-int MutexFind(key_t ipc_key)
-{
- return semget(ipc_key,1,0);
-}
-/* Function MutexRead: read the current value of the mutex/semaphore */
-int MutexRead(int sem_id)
-{
- return semctl(sem_id, 0, GETVAL);
-}
-/* Define sembuf structures to lock and unlock the semaphore */
-struct sembuf sem_lock={ /* to lock semaphore */
- 0, /* semaphore number (only one so 0) */
- -1, /* operation (-1 to use resource) */
- SEM_UNDO}; /* flag (set for undo at exit) */
-struct sembuf sem_ulock={ /* to unlock semaphore */
- 0, /* semaphore number (only one so 0) */
- 1, /* operation (1 to release resource) */
- SEM_UNDO}; /* flag (in this case 0) */
-/* Function MutexLock: to lock a mutex/semaphore */
-int MutexLock(int sem_id)
-{
- return semop(sem_id, &sem_lock, 1);
-}
-/* Function MutexUnlock: to unlock a mutex/semaphore */
-int MutexUnlock(int sem_id)
-{
- return semop(sem_id, &sem_ulock, 1);
-}
-/* Function MutexRemove: remove a mutex/semaphore */
-int MutexRemove(int sem_id)
-{
- return semctl(sem_id, 0, IPC_RMID);
-}
- \end{lstlisting}
+ \includecodesample{listati/Mutex.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni che permettono di creare o recuperare
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct shmid_ds {
- struct ipc_perm shm_perm; /* operation perms */
- int shm_segsz; /* size of segment (bytes) */
- time_t shm_atime; /* last attach time */
- time_t shm_dtime; /* last detach time */
- time_t shm_ctime; /* last change time */
- unsigned short shm_cpid; /* pid of creator */
- unsigned short shm_lpid; /* pid of last operator */
- short shm_nattch; /* no. of current attaches */
-};
- \end{lstlisting}
+ \includestruct{listati/shmid_ds.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{shmid\_ds}, associata a ciascun segmento di
\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
-\begin{itemize*}
+\begin{itemize}
\item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene
inizializzato al valore di \param{size}.
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
creato il segmento, viene inizializzato al \acr{pid} del processo chiamante.
\item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati
al segmento viene inizializzato a zero.
-\end{itemize*}
+\end{itemize}
Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni
inoltre la regione di indirizzi usata per il segmento di memoria condivisa
viene tolta dallo spazio di indirizzi del processo.
-Come esempio di uso di queste funzioni vediamo come implementare una serie di
-funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
-più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
-\figref{fig:ipc_sysv_shm_func}.
-
\begin{figure}[!bht]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* Function ShmCreate Create a SysV shared memory segment */
-void * ShmCreate(key_t ipc_key, int shm_size, int perm, int fill)
-{
- void * shm_ptr;
- int shm_id; /* ID of the IPC shared memory segment */
- shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */
- if (shm_id < 0) {
- return NULL;
- }
- shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
- if (shm_ptr < 0) {
- return NULL;
- }
- memset((void *)shm_ptr, fill, shm_size); /* fill segment */
- return shm_ptr;
-}
-/* Function ShmFind: Find a SysV shared memory segment */
-void * ShmFind(key_t ipc_key, int shm_size)
-{
- void * shm_ptr;
- int shm_id; /* ID of the SysV shared memory segment */
- shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */
- if (shm_id < 0) {
- return NULL;
- }
- shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
- if (shm_ptr < 0) {
- return NULL;
- }
- return shm_ptr;
-}
-/* Function ShmRemove: Schedule removal for a SysV shared memory segment */
-int ShmRemove(key_t ipc_key, void * shm_ptr)
-{
- int shm_id; /* ID of the SysV shared memory segment */
- /* first detach segment */
- if (shmdt(shm_ptr) < 0) {
- return -1;
- }
- /* schedule segment removal */
- shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */
- if (shm_id < 0) {
- if (errno == EIDRM) return 0;
- return -1;
- }
- if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */
- if (errno == EIDRM) return 0;
- return -1;
- }
- return 0;
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/SharedMem.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni che permettono di creare, trovare e
\label{fig:ipc_sysv_shm_func}
\end{figure}
+Come esempio di uso di queste funzioni vediamo come implementare una serie di
+funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
+più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
+\figref{fig:ipc_sysv_shm_func}.
+
La prima funzione (\texttt{\small 3--16}) è \func{ShmCreate} che, data una
chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
stesso. La funzione comincia (\texttt{\small 6}) con il chiamare
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* global variables for shared memory segment */
-struct DirProp {
- int tot_size;
- int tot_files;
- int tot_regular;
- int tot_fifo;
- int tot_link;
- int tot_dir;
- int tot_block;
- int tot_char;
- int tot_sock;
-} *shmptr;
-key_t key;
-int mutex;
-/* main body */
-int main(int argc, char *argv[])
-{
- int i, pause = 10;
- ...
- if ((argc - optind) != 1) { /* There must be remaing parameters */
- printf("Wrong number of arguments %d\n", argc - optind);
- usage();
- }
- if (chdir(argv[1])) { /* chdir to be sure dir exist */
- perror("Cannot find directory to monitor");
- }
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
- Signal(SIGINT, HandSIGTERM);
- Signal(SIGQUIT, HandSIGTERM);
- key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
- shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */
- if (!shmptr) {
- perror("Cannot create shared memory");
- exit(1);
- }
- if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
- perror("Cannot create mutex");
- exit(1);
- }
- /* main loop, monitor directory properties each 10 sec */
- daemon(1, 0); /* demonize process, staying in monitored dir */
- while (1) {
- MutexLock(mutex); /* lock shared memory */
- memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
- DirScan(argv[1], ComputeValues); /* execute scan */
- MutexUnlock(mutex); /* unlock shared memory */
- sleep(pause); /* sleep until next watch */
- }
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/DirMonitor.c}
\end{minipage}
\normalsize
\caption{Codice della funzione principale del programma \file{DirMonitor.c}.}
di interfaccia già descritte in \secref{sec:ipc_sysv_sem}, anche un mutex, che
utilizzeremo per regolare l'accesso alla memoria condivisa.
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ComputeValues.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}
+
Completata l'inizializzazione e la creazione degli oggetti di
intercomunicazione il programma entra nel ciclo principale (\texttt{\small
40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
(\texttt{\small 47}) per il periodo di tempo specificato a riga di comando con
l'opzione \code{-p} con una \func{sleep}.
-
-\begin{figure}[!htb]
- \footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* Routine to compute directory properties inside DirScan */
-int ComputeValues(struct dirent * direntry)
-{
- struct stat data;
- stat(direntry->d_name, &data); /* get stat data */
- shmptr->tot_size += data.st_size;
- shmptr->tot_files++;
- if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
- if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
- if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
- if (S_ISDIR(data.st_mode)) shmptr->tot_dir++;
- if (S_ISBLK(data.st_mode)) shmptr->tot_block++;
- if (S_ISCHR(data.st_mode)) shmptr->tot_char++;
- if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++;
- return 0;
-}
-/* Signal Handler to manage termination */
-void HandSIGTERM(int signo) {
- MutexLock(mutex);
- ShmRemove(key, shmptr);
- MutexRemove(mutex);
- exit(0);
-}
- \end{lstlisting}
- \end{minipage}
- \normalsize
- \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.}
- \label{fig:ipc_dirmonitor_sub}
-\end{figure}
-
Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
descritta in dettaglio) in \secref{sec:file_dir_read}, che ci permette di
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- key_t key;
- ...
- /* create needed IPC objects */
- key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
- if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */
- perror("Cannot find shared memory");
- exit(1);
- }
- if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
- perror("Cannot find mutex");
- exit(1);
- }
- /* main loop */
- MutexLock(mutex); /* lock shared memory */
- printf("Ci sono %d file dati\n", shmptr->tot_regular);
- printf("Ci sono %d directory\n", shmptr->tot_dir);
- printf("Ci sono %d link\n", shmptr->tot_link);
- printf("Ci sono %d fifo\n", shmptr->tot_fifo);
- printf("Ci sono %d socket\n", shmptr->tot_sock);
- printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
- printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
- printf("Totale %d file, per %d byte\n",
- shmptr->tot_files, shmptr->tot_size);
- MutexUnlock(mutex); /* unlock shared memory */
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6 cm}
+ \includecodesample{listati/ReadMonitor.c}
\end{minipage}
\normalsize
\caption{Codice del programma client del monitor delle proprietà di una
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h> /* unix standard functions */
-/*
- * Function LockFile:
- */
-int LockFile(const char* path_name)
-{
- return open(path_name, O_EXCL|O_CREAT);
-}
-/*
- * Function UnlockFile:
- */
-int UnlockFile(const char* path_name)
-{
- return unlink(path_name);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/LockFile.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* Function CreateMutex: Create a mutex using file locking. */
-int CreateMutex(const char *path_name)
-{
- return open(path_name, O_EXCL|O_CREAT);
-}
-/* Function UnlockMutex: unlock a file. */
-int FindMutex(const char *path_name)
-{
- return open(path_name, O_RDWR);
-}
-/* Function LockMutex: lock mutex using file locking. */
-int LockMutex(int fd)
-{
- struct flock lock; /* file lock structure */
- /* set flock structure */
- lock.l_type = F_WRLCK; /* set type: read or write */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
- /* do locking */
- return fcntl(fd, F_SETLKW, &lock);
-}
-/* Function UnlockMutex: unlock a file. */
-int UnlockMutex(int fd)
-{
- struct flock lock; /* file lock structure */
- /* set flock structure */
- lock.l_type = F_UNLCK; /* set type: unlock */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
- /* do locking */
- return fcntl(fd, F_SETLK, &lock);
-}
-/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
-int RemoveMutex(const char *path_name)
-{
- return unlink(path_name);
-}
-/* Function ReadMutex: read a mutex status. */
-int ReadMutex(int fd)
-{
- int res;
- struct flock lock; /* file lock structure */
- /* set flock structure */
- lock.l_type = F_WRLCK; /* set type: unlock */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
- /* do locking */
- if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
- return res;
- }
- return lock.l_type;
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/MutexLocking.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni che permettono per la gestione dei
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct mq_attr {
- long mq_flags; /* message queue flags */
- long mq_maxmsg; /* maximum number of messages */
- long mq_msgsize; /* maximum message size */
- long mq_curmsgs; /* number of messages currently queued */
-};
- \end{lstlisting}
+ \includestruct{listati/mq_attr.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{mq\_attr}, contenente gli attributi di una
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/* Function CreateShm: Create a shared memory segment mapping it */
-void * CreateShm(char * shm_name, off_t shm_size, mode_t perm, int fill)
-{
- void * shm_ptr;
- int fd;
- int flag;
- /* first open the object, creating it if not existent */
- flag = O_CREAT|O_EXCL|O_RDWR;
- fd = shm_open(shm_name, flag, perm); /* get object file descriptor */
- if (fd < 0) {
- return NULL;
- }
- /* set the object size */
- if (ftruncate(fd, shm_size)) {
- return NULL;
- }
- /* map it in the process address space */
- shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
- if (shm_ptr == MAP_FAILED) {
- return NULL;
- }
- memset((void *) shm_ptr, fill, shm_size); /* fill segment */
- return shm_ptr;
-}
-/* Function FindShm: Find a POSIX shared memory segment */
-void * FindShm(char * shm_name, off_t shm_size)
-{
- void * shm_ptr;
- int fd; /* ID of the IPC shared memory segment */
- /* find shared memory ID */
- if ((fd = shm_open(shm_name, O_RDWR|O_EXCL, 0)) < 0) {
- return NULL;
- }
- /* take the pointer to it */
- shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
- if (shm_ptr == MAP_FAILED) {
- return NULL;
- }
- return shm_ptr;
-}
-/* Function RemoveShm: Remove a POSIX shared memory segment */
-int RemoveShm(char * shm_name)
-{
- return shm_unlink(shm_name);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/MemShared.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni di gestione dei segmenti di memoria
--- /dev/null
+int main(int argc, char *argv[], char *envp[])
+{
+ FILE *pipe[4];
+ FILE *pipein;
+ char *cmd_string[4]={
+ "pnmtopng",
+ "pnmmargin -white 10",
+ "pnmcrop",
+ "gs -sDEVICE=ppmraw -sOutputFile=- -sNOPAUSE -q - -c showpage -c quit"
+ };
+ char content[]="Content-type: image/png\n\n";
+ int i;
+ /* write mime-type to stdout */
+ write(STDOUT_FILENO, content, strlen(content));
+ /* execute chain of command */
+ for (i=0; i<4; i++) {
+ pipe[i] = popen(cmd_string[i], "w");
+ dup2(fileno(pipe[i]), STDOUT_FILENO);
+ }
+ /* create barcode (in PS) */
+ pipein = popen("barcode", "w");
+ /* send barcode string to barcode program */
+ write(fileno(pipein), argv[1], strlen(argv[1]));
+ /* close all pipes (in reverse order) */
+ for (i=4; i==0; i--) {
+ pclose((pipe[i]));
+ }
+ exit(0);
+}
--- /dev/null
+int main(int argc, char *argv[], char *envp[])
+{
+ ...
+ /* create two pipes, pipein and pipeout, to handle communication */
+ if ( (retval = pipe(pipein)) ) {
+ WriteMess("input pipe creation error");
+ exit(0);
+ }
+ if ( (retval = pipe(pipeout)) ) {
+ WriteMess("output pipe creation error");
+ exit(0);
+ }
+ /* First fork: use child to run barcode program */
+ if ( (pid = fork()) == -1) { /* on error exit */
+ WriteMess("child creation error");
+ exit(0);
+ }
+ /* if child */
+ if (pid == 0) {
+ close(pipein[1]); /* close pipe write end */
+ dup2(pipein[0], STDIN_FILENO); /* remap stdin to pipe read end */
+ close(pipeout[0]);
+ dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */
+ execlp("barcode", "barcode", size, NULL);
+ }
+ close(pipein[0]); /* close input side of input pipe */
+ write(pipein[1], argv[1], strlen(argv[1])); /* write parameter to pipe */
+ close(pipein[1]); /* closing write end */
+ waitpid(pid, NULL, 0); /* wait child completion */
+ /* Second fork: use child to run ghostscript */
+ if ( (pid = fork()) == -1) {
+ WriteMess("child creation error");
+ exit(0);
+ }
+ /* second child, convert PS to JPEG */
+ if (pid == 0) {
+ close(pipeout[1]); /* close write end */
+ dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */
+ /* send mime type */
+ write(STDOUT_FILENO, content, strlen(content));
+ execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
+ }
+ /* still parent */
+ close(pipeout[1]);
+ waitpid(pid, NULL, 0);
+ exit(0);
+}
--- /dev/null
+void ClientEcho(FILE * filein, int socket)
+{
+ char sendbuff[MAXLINE], recvbuff[MAXLINE];
+ int nread;
+ while (fgets(sendbuff, MAXLINE, filein) != NULL) {
+ FullWrite(socket, sendbuff, strlen(sendbuff));
+ nread = FullRead(socket, recvbuff, strlen(sendbuff));
+ recvbuff[nread] = 0;
+ fputs(recvbuff, stdout);
+ }
+ return;
+}
--- /dev/null
+/* Routine to compute directory properties inside DirScan */
+int ComputeValues(struct dirent * direntry)
+{
+ struct stat data;
+ stat(direntry->d_name, &data); /* get stat data */
+ shmptr->tot_size += data.st_size;
+ shmptr->tot_files++;
+ if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
+ if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
+ if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
+ if (S_ISDIR(data.st_mode)) shmptr->tot_dir++;
+ if (S_ISBLK(data.st_mode)) shmptr->tot_block++;
+ if (S_ISCHR(data.st_mode)) shmptr->tot_char++;
+ if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++;
+ return 0;
+}
+/* Signal Handler to manage termination */
+void HandSIGTERM(int signo) {
+ MutexLock(mutex);
+ ShmRemove(key, shmptr);
+ MutexRemove(mutex);
+ exit(0);
+}
--- /dev/null
+/* global variables for shared memory segment */
+struct DirProp {
+ int tot_size;
+ int tot_files;
+ int tot_regular;
+ int tot_fifo;
+ int tot_link;
+ int tot_dir;
+ int tot_block;
+ int tot_char;
+ int tot_sock;
+} *shmptr;
+key_t key;
+int mutex;
+/* main body */
+int main(int argc, char *argv[])
+{
+ int i, pause = 10;
+ ...
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ if (chdir(argv[1])) { /* chdir to be sure dir exist */
+ perror("Cannot find directory to monitor");
+ }
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */
+ if (!shmptr) {
+ perror("Cannot create shared memory");
+ exit(1);
+ }
+ if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
+ perror("Cannot create mutex");
+ exit(1);
+ }
+ /* main loop, monitor directory properties each 10 sec */
+ daemon(1, 0); /* demonize process, staying in monitored dir */
+ while (1) {
+ MutexLock(mutex); /* lock shared memory */
+ memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
+ DirScan(argv[1], ComputeValues); /* execute scan */
+ MutexUnlock(mutex); /* unlock shared memory */
+ sleep(pause); /* sleep until next watch */
+ }
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int sock_fd, i;
+ struct sockaddr_in serv_add;
+ ...
+ /* create socket */
+ if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ return -1;
+ }
+ /* initialize address */
+ memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(7); /* echo port is 7 */
+ /* build address using inet_pton */
+ if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
+ perror("Address creation error");
+ return -1;
+ }
+ /* extablish connection */
+ if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("Connection error");
+ return -1;
+ }
+ /* read daytime from server */
+ ClientEcho(stdin, sock_fd);
+ /* normal exit */
+ return 0;
+}
--- /dev/null
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utilities */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+
+int main(int argc, char *argv[])
+{
+ int sock_fd;
+ int i, nread;
+ struct sockaddr_in serv_add;
+ char buffer[MAXLINE];
+ ...
+ /* create socket */
+ if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ return -1;
+ }
+ /* initialize address */
+ memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime post is 13 */
+ /* build address using inet_pton */
+ if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
+ perror("Address creation error");
+ return -1;
+ }
+ /* extablish connection */
+ if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("Connection error");
+ return -1;
+ }
+ /* read daytime from server */
+ while ( (nread = read(sock_fd, buffer, MAXLINE)) > 0) {
+ buffer[nread]=0;
+ if (fputs(buffer, stdout) == EOF) { /* write daytime */
+ perror("fputs error");
+ return -1;
+ }
+ }
+ /* error on read */
+ if (nread < 0) {
+ perror("Read error");
+ return -1;
+ }
+ /* normal exit */
+ return 0;
+}
--- /dev/null
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utililites */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add, client;
+ char buffer[MAXLINE];
+ socklen_t len;
+ time_t timeval;
+ pid_t pid;
+ int logging=0;
+ ...
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
+ <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd);
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ if (logging) {
+ inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+ printf("Request from host %s, port %d\n", buffer,
+ ntohs(client.sin_port));
+ }
+ close(conn_fd);
+ exit(0);
+ } else { /* parent */
+ close(conn_fd);
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
--- /dev/null
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utilities */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+#include <time.h>
+#define MAXLINE 80
+#define BACKLOG 10
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add;
+ char buffer[MAXLINE];
+ time_t timeval;
+ ...
+ /* create socket */
+ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ exit(-1);
+ }
+ /* initialize address */
+ memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime port is 13 */
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
+ /* bind socket */
+ if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("bind error");
+ exit(-1);
+ }
+ /* listen on socket */
+ if (listen(list_fd, BACKLOG) < 0 ) {
+ perror("listen error");
+ exit(-1);
+ }
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ close(conn_fd);
+ }
+ /* normal exit */
+ exit(0);
+}
--- /dev/null
+/* Subroutines declaration */
+void ServEcho(int sockfd);
+/* Program beginning */
+int main(int argc, char *argv[])
+{
+ int list_fd, conn_fd;
+ pid_t pid;
+ struct sockaddr_in serv_add;
+ ...
+ /* create socket */
+ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ exit(-1);
+ }
+ /* initialize address */
+ memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime port is 13 */
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
+ /* bind socket */
+ if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("bind error");
+ exit(-1);
+ }
+ /* listen on socket */
+ if (listen(list_fd, BACKLOG) < 0 ) {
+ perror("listen error");
+ exit(-1);
+ }
+ /* handle echo to client */
+ while (1) {
+ /* accept connection */
+ if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd); /* close listening socket */
+ SockEcho(conn_fd); /* handle echo */
+ exit(0);
+ } else { /* parent */
+ close(conn_fd); /* close connected socket */
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+ int type = F_UNLCK; /* lock type: default to unlock (invalid) */
+ off_t start = 0; /* start of the locked region: default to 0 */
+ off_t len = 0; /* length of the locked region: default to 0 */
+ int fd, res, i; /* internal variables */
+ int bsd = 0; /* semantic type: default to POSIX */
+ int cmd = F_SETLK; /* lock command: default to non-blocking */
+ struct flock lock; /* file lock structure */
+ ...
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ if (type == F_UNLCK) { /* There must be a -w or -r option set */
+ printf("You should set a read or a write lock\n");
+ usage();
+ }
+ fd = open(argv[optind], O_RDWR); /* open the file to be locked */
+ if (fd < 0) { /* on error exit */
+ perror("Wrong filename");
+ exit(1);
+ }
+ /* do lock */
+ if (bsd) { /* if BSD locking */
+ /* rewrite cmd for suitables flock operation values */
+ if (cmd == F_SETLKW) { /* if no-blocking */
+ cmd = LOCK_NB; /* set the value for flock operation */
+ } else { /* else */
+ cmd = 0; /* default is null */
+ }
+ if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
+ if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
+ res = flock(fd, cmd); /* esecute lock */
+ } else { /* if POSIX locking */
+ /* setting flock structure */
+ lock.l_type = type; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = start; /* set the start of the locked region */
+ lock.l_len = len; /* set the length of the locked region */
+ res = fcntl(fd, cmd, &lock); /* do lock */
+ }
+ /* check lock results */
+ if (res) { /* on error exit */
+ perror("Failed lock");
+ exit(1);
+ } else { /* else write message */
+ printf("Lock acquired\n");
+ }
+ pause(); /* stop the process, use a signal to exit */
+ return 0;
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int n = 0;
+ char *fortunefilename = "/tmp/fortune.fifo";
+ char line[80];
+ int fifo_server, fifo_client;
+ char fifoname[80];
+ int nread;
+ char buffer[PIPE_BUF];
+ ...
+ snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */
+ if (mkfifo(fifoname, 0622)) { /* open client fifo */
+ if (errno!=EEXIST) {
+ perror("Cannot create well known fifo");
+ exit(-1);
+ }
+ }
+ fifo_server = open(fortunefilename, O_WRONLY); /* open server fifo */
+ if (fifo_server < 0) {
+ perror("Cannot open well known fifo");
+ exit(-1);
+ }
+ nread = write(fifo_server, fifoname, strlen(fifoname)+1); /* write name */
+ close(fifo_server); /* close server fifo */
+ fifo_client = open(fifoname, O_RDONLY); /* open client fifo */
+ if (fifo_client < 0) {
+ perror("Cannot open well known fifo");
+ exit(-1);
+ }
+ nread = read(fifo_client, buffer, sizeof(buffer)); /* read answer */
+ printf("%s", buffer); /* print fortune */
+ close(fifo_client); /* close client */
+ close(fifo_server); /* close server */
+ unlink(fifoname); /* remove client fifo */
+}
--- /dev/null
+char *fifoname = "/tmp/fortune.fifo";
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int i, n = 0;
+ char *fortunefilename = "/usr/share/games/fortunes/linux";
+ char **fortune;
+ char line[80];
+ int fifo_server, fifo_client;
+ int nread;
+ ...
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
+ if (errno!=EEXIST) {
+ perror("Cannot create well known fifo");
+ exit(1);
+ }
+ }
+ daemon(0, 0);
+ /* open fifo two times to avoid EOF */
+ fifo_server = open(fifoname, O_RDONLY);
+ if (fifo_server < 0) {
+ perror("Cannot open read only well known fifo");
+ exit(1);
+ }
+ if (open(fifoname, O_WRONLY) < 0) {
+ perror("Cannot open write only well known fifo");
+ exit(1);
+ }
+ /* Main body: loop over requests */
+ while (1) {
+ nread = read(fifo_server, line, 79); /* read request */
+ if (nread < 0) {
+ perror("Read Error");
+ exit(1);
+ }
+ line[nread] = 0; /* terminate fifo name string */
+ n = random() % i; /* select random value */
+ fifo_client = open(line, O_WRONLY); /* open client fifo */
+ if (fifo_client < 0) {
+ perror("Cannot open");
+ exit(1);
+ }
+ nread = write(fifo_client, /* write phrase */
+ fortune[n], strlen(fortune[n])+1);
+ close(fifo_client); /* close client fifo */
+ }
+}
--- /dev/null
+#include <unistd.h>
+
+ssize_t FullRead(int fd, void *buf, size_t count)
+{
+ size_t nleft;
+ ssize_t nread;
+
+ nleft = count;
+ while (nleft > 0) { /* repeat until no left */
+ if ( (nread = read(fd, buf, nleft)) < 0) {
+ if (errno == EINTR) { /* if interrupted by system call */
+ continue; /* repeat the loop */
+ } else {
+ return(nread); /* otherwise exit */
+ }
+ } else if (nread == 0) { /* EOF */
+ break; /* break loop here */
+ }
+ nleft -= nread; /* set left to read */
+ buf +=nread; /* set pointer */
+ }
+ return (count - nleft);
+}
--- /dev/null
+#include <unistd.h>
+
+ssize_t FullWrite(int fd, const void *buf, size_t count)
+{
+ size_t nleft;
+ ssize_t nwritten;
+
+ nleft = count;
+ while (nleft > 0) { /* repeat until no left */
+ if ( (nwritten = write(fd, buf, nleft)) < 0) {
+ if (errno == EINTR) { /* if interrupted by system call */
+ continue; /* repeat the loop */
+ } else {
+ return(nwritten); /* otherwise exit with error */
+ }
+ }
+ nleft -= nwritten; /* set left to write */
+ buf +=nwritten; /* set pointer */
+ }
+ return (count);
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+ ...
+ switch (type) {
+ case 'q': /* Message Queue */
+ debug("Message Queue Try\n");
+ for (i=0; i<n; i++) {
+ id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ msgctl(id, IPC_RMID, NULL);
+ }
+ break;
+ case 's': /* Semaphore */
+ debug("Semaphore\n");
+ for (i=0; i<n; i++) {
+ id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ semctl(id, 0, IPC_RMID);
+ }
+ break;
+ case 'm': /* Shared Memory */
+ debug("Shared Memory\n");
+ for (i=0; i<n; i++) {
+ id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ shmctl(id, IPC_RMID, NULL);
+ }
+ break;
+ default: /* should not reached */
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h> /* unix standard functions */
+/*
+ * Function LockFile:
+ */
+int LockFile(const char* path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/*
+ * Function UnlockFile:
+ */
+int UnlockFile(const char* path_name)
+{
+ return unlink(path_name);
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+ ...
+ key = ftok("./MQFortuneServer.c", 1);
+ msgid = msgget(key, 0);
+ if (msgid < 0) {
+ perror("Cannot find message queue");
+ exit(1);
+ }
+ /* Main body: do request and write result */
+ msg_read.mtype = 1; /* type for request is always 1 */
+ msg_read.pid = getpid(); /* use pid for communications */
+ size = sizeof(msg_read.pid);
+ msgsnd(msgid, &msg_read, size, 0); /* send request message */
+ msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR);
+ printf("%s", msg_write.mtext);
+}
--- /dev/null
+int msgid; /* Message queue identifier */
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int i, n = 0;
+ char **fortune; /* array of fortune message string */
+ char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */
+ struct msgbuf_read { /* message struct to read request from clients */
+ long mtype; /* message type, must be 1 */
+ long pid; /* message data, must be the pid of the client */
+ } msg_read;
+ struct msgbuf_write { /* message struct to write result to clients */
+ long mtype; /* message type, will be the pid of the client*/
+ char mtext[MSGMAX]; /* message data, will be the fortune */
+ } msg_write;
+ key_t key; /* Message queue key */
+ int size; /* message size */
+ ...
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ /* Create the queue */
+ key = ftok("./MQFortuneServer.c", 1);
+ msgid = msgget(key, IPC_CREAT|0666);
+ if (msgid < 0) {
+ perror("Cannot create message queue");
+ exit(1);
+ }
+ /* Main body: loop over requests */
+ daemon(0, 0);
+ while (1) {
+ msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR);
+ n = random() % i; /* select random value */
+ strncpy(msg_write.mtext, fortune[n], MSGMAX);
+ size = min(strlen(fortune[n])+1, MSGMAX);
+ msg_write.mtype=msg_read.pid; /* use request pid as type */
+ msgsnd(msgid, &msg_write, size, 0);
+ }
+}
+/*
+ * Signal Handler to manage termination
+ */
+void HandSIGTERM(int signo) {
+ msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
+ exit(0);
+}
--- /dev/null
+/* Function CreateShm: Create a shared memory segment mapping it */
+void * CreateShm(char * shm_name, off_t shm_size, mode_t perm, int fill)
+{
+ void * shm_ptr;
+ int fd;
+ int flag;
+ /* first open the object, creating it if not existent */
+ flag = O_CREAT|O_EXCL|O_RDWR;
+ fd = shm_open(shm_name, flag, perm); /* get object file descriptor */
+ if (fd < 0) {
+ return NULL;
+ }
+ /* set the object size */
+ if (ftruncate(fd, shm_size)) {
+ return NULL;
+ }
+ /* map it in the process address space */
+ shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if (shm_ptr == MAP_FAILED) {
+ return NULL;
+ }
+ memset((void *) shm_ptr, fill, shm_size); /* fill segment */
+ return shm_ptr;
+}
+/* Function FindShm: Find a POSIX shared memory segment */
+void * FindShm(char * shm_name, off_t shm_size)
+{
+ void * shm_ptr;
+ int fd; /* ID of the IPC shared memory segment */
+ /* find shared memory ID */
+ if ((fd = shm_open(shm_name, O_RDWR|O_EXCL, 0)) < 0) {
+ return NULL;
+ }
+ /* take the pointer to it */
+ shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if (shm_ptr == MAP_FAILED) {
+ return NULL;
+ }
+ return shm_ptr;
+}
+/* Function RemoveShm: Remove a POSIX shared memory segment */
+int RemoveShm(char * shm_name)
+{
+ return shm_unlink(shm_name);
+}
--- /dev/null
+/* Function MutexCreate: create a mutex/semaphore */
+int MutexCreate(key_t ipc_key)
+{
+ const union semun semunion={1}; /* semaphore union structure */
+ int sem_id, ret;
+ sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
+ if (sem_id == -1) { /* if error return code */
+ return sem_id;
+ }
+ ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
+ if (ret == -1) {
+ return ret;
+ }
+ return sem_id;
+}
+/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */
+int MutexFind(key_t ipc_key)
+{
+ return semget(ipc_key,1,0);
+}
+/* Function MutexRead: read the current value of the mutex/semaphore */
+int MutexRead(int sem_id)
+{
+ return semctl(sem_id, 0, GETVAL);
+}
+/* Define sembuf structures to lock and unlock the semaphore */
+struct sembuf sem_lock={ /* to lock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ -1, /* operation (-1 to use resource) */
+ SEM_UNDO}; /* flag (set for undo at exit) */
+struct sembuf sem_ulock={ /* to unlock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ 1, /* operation (1 to release resource) */
+ SEM_UNDO}; /* flag (in this case 0) */
+/* Function MutexLock: to lock a mutex/semaphore */
+int MutexLock(int sem_id)
+{
+ return semop(sem_id, &sem_lock, 1);
+}
+/* Function MutexUnlock: to unlock a mutex/semaphore */
+int MutexUnlock(int sem_id)
+{
+ return semop(sem_id, &sem_ulock, 1);
+}
+/* Function MutexRemove: remove a mutex/semaphore */
+int MutexRemove(int sem_id)
+{
+ return semctl(sem_id, 0, IPC_RMID);
+}
--- /dev/null
+/* Function CreateMutex: Create a mutex using file locking. */
+int CreateMutex(const char *path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/* Function UnlockMutex: unlock a file. */
+int FindMutex(const char *path_name)
+{
+ return open(path_name, O_RDWR);
+}
+/* Function LockMutex: lock mutex using file locking. */
+int LockMutex(int fd)
+{
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ return fcntl(fd, F_SETLKW, &lock);
+}
+/* Function UnlockMutex: unlock a file. */
+int UnlockMutex(int fd)
+{
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_UNLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ return fcntl(fd, F_SETLK, &lock);
+}
+/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
+int RemoveMutex(const char *path_name)
+{
+ return unlink(path_name);
+}
+/* Function ReadMutex: read a mutex status. */
+int ReadMutex(int fd)
+{
+ int res;
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
+ return res;
+ }
+ return lock.l_type;
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+ key_t key;
+ ...
+ /* create needed IPC objects */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */
+ perror("Cannot find shared memory");
+ exit(1);
+ }
+ if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
+ perror("Cannot find mutex");
+ exit(1);
+ }
+ /* main loop */
+ MutexLock(mutex); /* lock shared memory */
+ printf("Ci sono %d file dati\n", shmptr->tot_regular);
+ printf("Ci sono %d directory\n", shmptr->tot_dir);
+ printf("Ci sono %d link\n", shmptr->tot_link);
+ printf("Ci sono %d fifo\n", shmptr->tot_fifo);
+ printf("Ci sono %d socket\n", shmptr->tot_sock);
+ printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
+ printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
+ printf("Totale %d file, per %d byte\n",
+ shmptr->tot_files, shmptr->tot_size);
+ MutexUnlock(mutex); /* unlock shared memory */
+}
--- /dev/null
+void ServEcho(int sockfd) {
+ char buffer[MAXLINE];
+ int nread, nwrite;
+
+ /* main loop, reading 0 char means client close connection */
+ while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
+ nwrite = FullWrite(sockfd, buffer, nread);
+ }
+ return;
+}
--- /dev/null
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+
+int SetTermAttr(int fd, tcflag_t flag)
+{
+ struct termios values;
+ int res;
+ res = tcgetattr (desc, &values);
+ if (res) {
+ perror("Cannot get attributes");
+ return res;
+ }
+ values.c_lflag |= flag;
+ res = tcsetattr (desc, TCSANOW, &values);
+ if (res) {
+ perror("Cannot set attributes");
+ return res;
+ }
+ return 0;
+}
--- /dev/null
+/* Function ShmCreate Create a SysV shared memory segment */
+void * ShmCreate(key_t ipc_key, int shm_size, int perm, int fill)
+{
+ void * shm_ptr;
+ int shm_id; /* ID of the IPC shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */
+ if (shm_id < 0) {
+ return NULL;
+ }
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ if (shm_ptr < 0) {
+ return NULL;
+ }
+ memset((void *)shm_ptr, fill, shm_size); /* fill segment */
+ return shm_ptr;
+}
+/* Function ShmFind: Find a SysV shared memory segment */
+void * ShmFind(key_t ipc_key, int shm_size)
+{
+ void * shm_ptr;
+ int shm_id; /* ID of the SysV shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */
+ if (shm_id < 0) {
+ return NULL;
+ }
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ if (shm_ptr < 0) {
+ return NULL;
+ }
+ return shm_ptr;
+}
+/* Function ShmRemove: Schedule removal for a SysV shared memory segment */
+int ShmRemove(key_t ipc_key, void * shm_ptr)
+{
+ int shm_id; /* ID of the SysV shared memory segment */
+ /* first detach segment */
+ if (shmdt(shm_ptr) < 0) {
+ return -1;
+ }
+ /* schedule segment removal */
+ shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */
+ if (shm_id < 0) {
+ if (errno == EIDRM) return 0;
+ return -1;
+ }
+ if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */
+ if (errno == EIDRM) return 0;
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+int UnSetTermAttr(int fd, tcflag_t flag)
+{
+ struct termios values;
+ int res;
+ res = tcgetattr (desc, &values);
+ if (res) {
+ perror("Cannot get attributes");
+ return res;
+ }
+ values.c_lflag &= (~flag);
+ res = tcsetattr (desc, TCSANOW, &values);
+ if (res) {
+ perror("Cannot set attributes");
+ return res;
+ }
+ return 0;
+}
--- /dev/null
+struct aiocb
+{
+ int aio_fildes; /* File descriptor. */
+ off_t aio_offset; /* File offset */
+ int aio_lio_opcode; /* Operation to be performed. */
+ int aio_reqprio; /* Request priority offset. */
+ volatile void *aio_buf; /* Location of buffer. */
+ size_t aio_nbytes; /* Length of transfer. */
+ struct sigevent aio_sigevent; /* Signal number and value. */
+};
--- /dev/null
+struct flock {
+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ short int l_whence; /* Where `l_start' is relative to (like `lseek').*/
+ off_t l_start; /* Offset where the lock begins. */
+ off_t l_len; /* Size of the locked area; zero means until EOF.*/
+ pid_t l_pid; /* Process holding the lock. */
+};
--- /dev/null
+struct iovec {
+ __ptr_t iov_base; /* Starting address */
+ size_t iov_len; /* Length in bytes */
+};
--- /dev/null
+struct ipc_perm
+{
+ key_t key; /* Key. */
+ uid_t uid; /* Owner's user ID. */
+ gid_t gid; /* Owner's group ID. */
+ uid_t cuid; /* Creator's user ID. */
+ gid_t cgid; /* Creator's group ID. */
+ unsigned short int mode; /* Read/write permission. */
+ unsigned short int seq; /* Sequence number. */
+};
--- /dev/null
+struct mq_attr {
+ long mq_flags; /* message queue flags */
+ long mq_maxmsg; /* maximum number of messages */
+ long mq_msgsize; /* maximum message size */
+ long mq_curmsgs; /* number of messages currently queued */
+};
--- /dev/null
+struct msgbuf {
+ long mtype; /* message type, must be > 0 */
+ char mtext[LENGTH]; /* message data */
+};
--- /dev/null
+struct msqid_ds {
+ struct ipc_perm msg_perm; /* structure for operation permission */
+ time_t msg_stime; /* time of last msgsnd command */
+ time_t msg_rtime; /* time of last msgrcv command */
+ time_t msg_ctime; /* time of last change */
+ msgqnum_t msg_qnum; /* number of messages currently on queue */
+ msglen_t msg_qbytes; /* max number of bytes allowed on queue */
+ pid_t msg_lspid; /* pid of last msgsnd() */
+ pid_t msg_lrpid; /* pid of last msgrcv() */
+ struct msg *msg_first; /* first message on queue, unused */
+ struct msg *msg_last; /* last message in queue, unused */
+ unsigned long int msg_cbytes; /* current number of bytes on queue */
+};
--- /dev/null
+ c_oflag &= (~CRDLY);
+ c_oflag |= CR1;
--- /dev/null
+struct pollfd {
+ int fd; /* file descriptor */
+ short events; /* requested events */
+ short revents; /* returned events */
+};
--- /dev/null
+struct sem {
+ short sempid; /* pid of last operation */
+ ushort semval; /* current value */
+ ushort semncnt; /* num procs awaiting increase in semval */
+ ushort semzcnt; /* num procs awaiting semval = 0 */
+};
--- /dev/null
+struct sembuf
+{
+ unsigned short int sem_num; /* semaphore number */
+ short int sem_op; /* semaphore operation */
+ short int sem_flg; /* operation flag */
+};
--- /dev/null
+struct semid_ds
+{
+ struct ipc_perm sem_perm; /* operation permission struct */
+ time_t sem_otime; /* last semop() time */
+ time_t sem_ctime; /* last time changed by semctl() */
+ unsigned long int sem_nsems; /* number of semaphores in set */
+};
--- /dev/null
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short *array; /* array for GETALL, SETALL */
+ /* Linux specific part: */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
--- /dev/null
+ serv_add.sin6_addr = in6addr_any;
--- /dev/null
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY);
--- /dev/null
+struct shmid_ds {
+ struct ipc_perm shm_perm; /* operation perms */
+ int shm_segsz; /* size of segment (bytes) */
+ time_t shm_atime; /* last attach time */
+ time_t shm_dtime; /* last detach time */
+ time_t shm_ctime; /* last change time */
+ unsigned short shm_cpid; /* pid of creator */
+ unsigned short shm_lpid; /* pid of last operator */
+ short shm_nattch; /* no. of current attaches */
+};
--- /dev/null
+ ...
+ /* install SIGCHLD handler */
+ Signal(SIGCHLD, sigchld_hand); /* establish handler */
+ /* create socket */
+ ...
--- /dev/null
+struct sigevent
+{
+ sigval_t sigev_value;
+ int sigev_signo;
+ int sigev_notify;
+ void (*sigev_notify_function)(sigval_t);
+ pthread_attr_t *sigev_notify_attributes;
+};
--- /dev/null
+struct sockaddr {
+ sa_family_t sa_family; /* address family: AF_xxx */
+ char sa_data[14]; /* address (protocol-specific) */
+};
--- /dev/null
+struct sockaddr_atalk {
+ sa_family_t sat_family; /* address family */
+ uint8_t sat_port; /* port */
+ struct at_addr sat_addr; /* net/node */
+};
+struct at_addr {
+ uint16_t s_net;
+ uint8_t s_node;
+};
--- /dev/null
+struct sockaddr_in {
+ sa_family_t sin_family; /* address family: AF_INET */
+ in_port_t sin_port; /* port in network byte order */
+ struct in_addr sin_addr; /* internet address */
+};
+/* Internet address. */
+struct in_addr {
+ in_addr_t s_addr; /* address in network byte order */
+};
--- /dev/null
+struct sockaddr_in6 {
+ uint16_t sin6_family; /* AF_INET6 */
+ in_port_t sin6_port; /* port number */
+ uint32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ uint32_t sin6_scope_id; /* Scope id (new in 2.4) */
+};
+struct in6_addr {
+ uint8_t s6_addr[16]; /* IPv6 address */
+};
--- /dev/null
+struct sockaddr_ll {
+ unsigned short sll_family; /* Always AF_PACKET */
+ unsigned short sll_protocol; /* Physical layer protocol */
+ int sll_ifindex; /* Interface number */
+ unsigned short sll_hatype; /* Header type */
+ unsigned char sll_pkttype; /* Packet type */
+ unsigned char sll_halen; /* Length of address */
+ unsigned char sll_addr[8]; /* Physical layer address */
+};
--- /dev/null
+#define UNIX_PATH_MAX 108
+struct sockaddr_un {
+ sa_family_t sun_family; /* AF_UNIX */
+ char sun_path[UNIX_PATH_MAX]; /* pathname */
+};
--- /dev/null
+struct termios {
+ tcflag_t c_iflag; /* input modes */
+ tcflag_t c_oflag; /* output modes */
+ tcflag_t c_cflag; /* control modes */
+ tcflag_t c_lflag; /* local modes */
+ cc_t c_cc[NCCS]; /* control characters */
+ cc_t c_line; /* line discipline */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
--- /dev/null
+ value.c_cc[VEOL2] = '\n';
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct termios {
- tcflag_t c_iflag; /* input modes */
- tcflag_t c_oflag; /* output modes */
- tcflag_t c_cflag; /* control modes */
- tcflag_t c_lflag; /* local modes */
- cc_t c_cc[NCCS]; /* control characters */
- cc_t c_line; /* line discipline */
- speed_t c_ispeed; /* input speed */
- speed_t c_ospeed; /* output speed */
-;
- \end{lstlisting}
+ \includestruct{listati/termios.h}
\end{minipage}
\normalsize
\caption{La struttura \structd{termios}, che identifica le proprietà di un
spiegazione corrispondente) sono numerici e non per bit, per cui possono
sovrapporsi fra di loro. Occorrerà perciò utilizzare un codice del tipo:
-\begin{lstlisting}[stepnumber=0,frame=]{}
- c_oflag &= (~CRDLY);
- c_oflag |= CR1;
-\end{lstlisting}
+\includecodesnip{listati/oflag.c}
\noindent che prima cancella i bit della maschera in questione e poi setta il
valore.
associate è riportato in \tabref{tab:sess_termios_cc}, usando quelle
definizioni diventa possibile assegnare un nuovo carattere di controllo con un
codice del tipo:
-\begin{lstlisting}[stepnumber=0,frame=]{}
- value.c_cc[VEOL2] = '\n';
-\end{lstlisting}
+\includecodesnip{listati/value_c_cc.c}
La maggior parte di questi caratteri (tutti tranne \const{VTIME} e
\const{VMIN}) hanno effetto solo quando il terminale viene utilizzato in modo
chiamata a \func{tcgetattr} che essi siano stati eseguiti tutti quanti.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <unistd.h>
-#include <termios.h>
-#include <errno.h>
-
-int SetTermAttr(int fd, tcflag_t flag)
-{
- struct termios values;
- int res;
- res = tcgetattr (desc, &values);
- if (res) {
- perror("Cannot get attributes");
- return res;
- }
- values.c_lflag |= flag;
- res = tcsetattr (desc, TCSANOW, &values);
- if (res) {
- perror("Cannot set attributes");
- return res;
- }
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/SetTermAttr.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della funzione \func{SetTermAttr} che permette di
impostare uno dei flag di controllo locale del terminale.}
\label{fig:term_set_attr}
o uscendo normalmente.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-int UnSetTermAttr(int fd, tcflag_t flag)
-{
- struct termios values;
- int res;
- res = tcgetattr (desc, &values);
- if (res) {
- perror("Cannot get attributes");
- return res;
- }
- values.c_lflag &= (~flag);
- res = tcsetattr (desc, TCSANOW, &values);
- if (res) {
- perror("Cannot set attributes");
- return res;
- }
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/UnSetTermAttr.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della funzione \func{UnSetTermAttr} che permette di
rimuovere uno dei flag di controllo locale del terminale.}
\label{fig:term_unset_attr}
\end{figure}
La seconda funzione, \func{UnSetTermAttr}, è assolutamente identica alla
-prima, solo che in questo caso (in \texttt{\small 15}) si rimuovono i bit
+prima, solo che in questo caso, in (\texttt{\small 15}), si rimuovono i bit
specificati dall'argomento \param{flag} usando un AND binario del valore
negato.
-%% signal.tex
+a%% signal.tex
%%
%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
messaggi POSIX (vedi \secref{sec:ipc_posix_mq}); pertanto devono essere
inviati esplicitamente.
-Inoltre per poter usufruire della capacità di restituire dei dati i relativi
-gestori devono essere installati con \func{sigaction} specificando la modalità
-\const{SA\_SIGINFO} che permette di utilizzare la forma estesa
-\var{sa\_sigaction} (vedi \secref{sec:sig_sigaction}). In questo modo tutti i
-segnali real-time possono restituire al gestore una serie di informazioni
-aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui definizione
-abbiamo già visto in \figref{fig:sig_siginfo_t}, nella trattazione dei gestori
-in forma estesa.
+Inoltre, per poter usufruire della capacità di restituire dei dati, i relativi
+gestori devono essere installati con \func{sigaction}, specificando per
+\var{sa\_flags} la modalità \const{SA\_SIGINFO} che permette di utilizzare la
+forma estesa \var{sa\_sigaction} (vedi \secref{sec:sig_sigaction}). In questo
+modo tutti i segnali real-time possono restituire al gestore una serie di
+informazioni aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui
+definizione abbiamo già visto in \figref{fig:sig_siginfo_t}, nella trattazione
+dei gestori in forma estesa.
In particolare i campi utilizzati dai segnali real-time sono \var{si\_pid} e
\var{si\_uid} in cui vengono memorizzati rispettivamente il \acr{pid} e
nel precedente esempio esaminato in \secref{sec:TCPel_cunc_serv}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-/* Subroutines declaration */
-void ServEcho(int sockfd);
-/* Program beginning */
-int main(int argc, char *argv[])
-{
- int list_fd, conn_fd;
- pid_t pid;
- struct sockaddr_in serv_add;
- ...
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* handle echo to client */
- while (1) {
- /* accept connection */
- if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd); /* close listening socket */
- SockEcho(conn_fd); /* handle echo */
- exit(0);
- } else { /* parent */
- close(conn_fd); /* close connected socket */
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ElemEchoTCPServer.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della funzione \code{main} della prima versione del server
per il servizio \texttt{echo}.}
\label{fig:TCPsimpl_serv_code}
\func{write}.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void ServEcho(int sockfd) {
- char buffer[MAXLINE];
- int nread, nwrite;
-
- /* main loop, reading 0 char means client close connection */
- while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
- nwrite = FullWrite(sockfd, buffer, nread);
- }
- return;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ServEcho.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione della funzione \code{ServEcho} per la
gestione del servizio \texttt{echo}.}
\label{fig:TCPsimpl_server_elem_sub}
\texttt{daytime} (vedi \secref{sec:net_cli_sample}) ma, come per il server, lo
si è diviso in due parti, inserendo la parte relativa alle operazioni
specifiche previste per il protocollo \texttt{echo} in una funzione a parte.
+
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int sock_fd, i;
- struct sockaddr_in serv_add;
- ...
- /* create socket */
- if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- return -1;
- }
- /* initialize address */
- memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(7); /* echo port is 7 */
- /* build address using inet_pton */
- if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
- perror("Address creation error");
- return -1;
- }
- /* extablish connection */
- if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("Connection error");
- return -1;
- }
- /* read daytime from server */
- ClientEcho(stdin, sock_fd);
- /* normal exit */
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6 cm}
+ \includecodesample{listati/EchoServerWrong.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione del client \texttt{echo}.}
\label{fig:TCPsimpl_client_elem}
\end{figure}
ricevuto in risposta dal server.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-void ClientEcho(FILE * filein, int socket)
-{
- char sendbuff[MAXLINE], recvbuff[MAXLINE];
- int nread;
- while (fgets(sendbuff, MAXLINE, filein) != NULL) {
- FullWrite(socket, sendbuff, strlen(sendbuff));
- nread = FullRead(socket, recvbuff, strlen(sendbuff));
- recvbuff[nread] = 0;
- fputs(recvbuff, stdout);
- }
- return;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/ClientEcho.c}
+ \end{minipage}
+ \normalsize
\caption{Codice della prima versione della funzione \texttt{ClientEcho} per
la gestione del servizio \texttt{echo}.}
\label{fig:TCPsimpl_client_echo_sub}
\figref{fig:sig_Signal_code}, per installare il semplice gestore che
riceve i segnali dei processi figli terminati già visto in
\figref{fig:sig_sigchld_handl}; aggiungendo il seguente codice:
-\begin{lstlisting}{}
- ...
- /* install SIGCHLD handler */
- Signal(SIGCHLD, sigchld_hand); /* establish handler */
- /* create socket */
- ...
-\end{lstlisting}
-
+\includecodesnip{listati/sigchildhand.c}
\noindent
all'esempio illustrato in \figref{fig:TCPsimpl_serv_code}, e linkando il tutto
alla funzione \code{sigchld\_hand}, si risolverà completamente il problema
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sockaddr {
- sa_family_t sa_family; /* address family: AF_xxx */
- char sa_data[14]; /* address (protocol-specific) */
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr.h}
\end{minipage}
\caption{La struttura generica degli indirizzi dei socket
\structd{sockaddr}.}
\begin{figure}[!htb]
\footnotesize\centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sockaddr_in {
- sa_family_t sin_family; /* address family: AF_INET */
- in_port_t sin_port; /* port in network byte order */
- struct in_addr sin_addr; /* internet address */
-};
-/* Internet address. */
-struct in_addr {
- in_addr_t s_addr; /* address in network byte order */
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr_in.h}
\end{minipage}
\caption{La struttura degli indirizzi dei socket internet (IPv4)
\structd{sockaddr\_in}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sockaddr_in6 {
- uint16_t sin6_family; /* AF_INET6 */
- in_port_t sin6_port; /* port number */
- uint32_t sin6_flowinfo; /* IPv6 flow information */
- struct in6_addr sin6_addr; /* IPv6 address */
- uint32_t sin6_scope_id; /* Scope id (new in 2.4) */
-};
-struct in6_addr {
- uint8_t s6_addr[16]; /* IPv6 address */
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr_in6.h}
\end{minipage}
\caption{La struttura degli indirizzi dei socket IPv6
\structd{sockaddr\_in6}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-#define UNIX_PATH_MAX 108
-struct sockaddr_un {
- sa_family_t sun_family; /* AF_UNIX */
- char sun_path[UNIX_PATH_MAX]; /* pathname */
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr_un.h}
\end{minipage}
\caption{La struttura degli indirizzi dei socket locali (detti anche
\textit{unix domain}) \structd{sockaddr\_un} definita in \file{sys/un.h}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sockaddr_atalk {
- sa_family_t sat_family; /* address family */
- uint8_t sat_port; /* port */
- struct at_addr sat_addr; /* net/node */
-};
-struct at_addr {
- uint16_t s_net;
- uint8_t s_node;
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr_atalk.h}
\end{minipage}
\caption{La struttura degli indirizzi dei socket AppleTalk
\structd{sockaddr\_atalk}.}
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \begin{lstlisting}[stepnumber=0]{}
-struct sockaddr_ll {
- unsigned short sll_family; /* Always AF_PACKET */
- unsigned short sll_protocol; /* Physical layer protocol */
- int sll_ifindex; /* Interface number */
- unsigned short sll_hatype; /* Header type */
- unsigned char sll_pkttype; /* Packet type */
- unsigned char sll_halen; /* Length of address */
- unsigned char sll_addr[8]; /* Physical layer address */
-};
- \end{lstlisting}
+ \includestruct{listati/sockaddr_ll.h}
\end{minipage}
\caption{La struttura \structd{sockaddr\_ll} degli indirizzi dei
\textit{packet socket}.}
\secref{sec:ipc_pipes}).
\begin{figure}[htb]
- \centering
- \footnotesize
- \begin{lstlisting}{}
-#include <unistd.h>
-
-ssize_t FullRead(int fd, void *buf, size_t count)
-{
- size_t nleft;
- ssize_t nread;
-
- nleft = count;
- while (nleft > 0) { /* repeat until no left */
- if ( (nread = read(fd, buf, nleft)) < 0) {
- if (errno == EINTR) { /* if interrupted by system call */
- continue; /* repeat the loop */
- } else {
- return(nread); /* otherwise exit */
- }
- } else if (nread == 0) { /* EOF */
- break; /* break loop here */
- }
- nleft -= nread; /* set left to read */
- buf +=nread; /* set pointer */
- }
- return (count - nleft);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/FullRead.c}
+ \end{minipage}
+ \normalsize
\caption{Funzione \func{FullRead}, legge esattamente \var{count} byte da un
file descriptor, iterando opportunamente le letture.}
\label{fig:sock_FullRead_code}
\begin{figure}[htb]
\centering
- \footnotesize
- \begin{lstlisting}{}
-#include <unistd.h>
-
-ssize_t FullWrite(int fd, const void *buf, size_t count)
-{
- size_t nleft;
- ssize_t nwritten;
-
- nleft = count;
- while (nleft > 0) { /* repeat until no left */
- if ( (nwritten = write(fd, buf, nleft)) < 0) {
- if (errno == EINTR) { /* if interrupted by system call */
- continue; /* repeat the loop */
- } else {
- return(nwritten); /* otherwise exit with error */
- }
- }
- nleft -= nwritten; /* set left to write */
- buf +=nwritten; /* set pointer */
- }
- return (count);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/FullWrite.c}
+ \end{minipage}
+ \normalsize
\caption{Funzione \func{FullWrite}, scrive \var{count} byte su un socket.}
\label{fig:sock_FullWrite_code}
\end{figure}
richiesta.
\begin{figure}[!htb]
- \footnotesize
- \begin{lstlisting}{}
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utilities */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-
-int main(int argc, char *argv[])
-{
- int sock_fd;
- int i, nread;
- struct sockaddr_in serv_add;
- char buffer[MAXLINE];
- ...
- /* create socket */
- if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- return -1;
- }
- /* initialize address */
- memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime post is 13 */
- /* build address using inet_pton */
- if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
- perror("Address creation error");
- return -1;
- }
- /* extablish connection */
- if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("Connection error");
- return -1;
- }
- /* read daytime from server */
- while ( (nread = read(sock_fd, buffer, MAXLINE)) > 0) {
- buffer[nread]=0;
- if (fputs(buffer, stdout) == EOF) { /* write daytime */
- perror("fputs error");
- return -1;
- }
- }
- /* error on read */
- if (nread < 0) {
- perror("Read error");
- return -1;
- }
- /* normal exit */
- return 0;
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/ElemDaytimeTCPClient.c}
+ \end{minipage}
+ \normalsize
\caption{Esempio di codice di un client elementare per il servizio daytime.}
\label{fig:net_cli_code}
\end{figure}
directory \file{sources}.
\begin{figure}[!htbp]
- \footnotesize
- \begin{lstlisting}{}
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utilities */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-#define MAXLINE 80
-#define BACKLOG 10
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add;
- char buffer[MAXLINE];
- time_t timeval;
- ...
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
- perror("accept error");
- exit(-1);
- }
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- close(conn_fd);
- }
- /* normal exit */
- exit(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/ElemDaytimeTCPServer.c}
+ \end{minipage}
+ \normalsize
\caption{Esempio di codice di un semplice server per il servizio daytime.}
\label{fig:net_serv_code}
\end{figure}