©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

c7/smi_fifo.c

Go to the documentation of this file.
00001 /*
00002     SMI - FIFOs
00003     AUP2, Sec. 7.03.3
00004 
00005     Copyright 2003 by Marc J. Rochkind. All rights reserved.
00006     May be copied only for purposes and under conditions described
00007     on the Web page www.basepath.com/aup/copyright.htm.
00008 
00009     The Example Files are provided "as is," without any warranty;
00010     without even the implied warranty of merchantability or fitness
00011     for a particular purpose. The author and his publisher are not
00012     responsible for any damages, direct or incidental, resulting
00013     from the use or non-use of these Example Files.
00014 
00015     The Example Files may contain defects, and some contain deliberate
00016     coding mistakes that were included for educational reasons.
00017     You are responsible for determining if and how the Example Files
00018     are to be used.
00019 
00020 */
00021 #include "defs.h"
00022 #include "../c4/setblock.h"
00023 #include "smi_fifo.h"
00024 
00025 /* See comment in smi_receive_fifo about poor handling of too many clients. */
00026 /*
00027     client uses only sq_clients[0] and sq_clients[1] and doesn't use
00028     sq_fd_server_w
00029 */
00030 /*[SMIQ_FIFO]*/
00031 #define MAX_CLIENTS 20
00032 
00033 typedef struct {
00034     SMIENTITY sq_entity;            /* entity */
00035     int sq_fd_server;               /* server read and ... */
00036     int sq_fd_server_w;             /* ... write file descriptors */
00037     char sq_name[SERVER_NAME_MAX];  /* server name */
00038     struct {
00039         int cl_fd;                  /* client file descriptor */
00040         pid_t cl_pid;               /* client process ID */
00041     } sq_clients[MAX_CLIENTS];
00042     struct client_id sq_client;     /* client ID */
00043     size_t sq_msgsize;              /* msg size */
00044     struct smi_msg *sq_msg;         /* msg buffer */
00045 } SMIQ_FIFO;
00046 /*[clients_bgn]*/
00047 static void clients_bgn(SMIQ_FIFO *p)
00048 {
00049     int i;
00050 
00051     for (i = 0; i < MAX_CLIENTS; i++)
00052         p->sq_clients[i].cl_fd = -1;
00053 }
00054 /*[clients_find]*/
00055 static int clients_find(SMIQ_FIFO *p, pid_t pid)
00056 {
00057     int i, avail = -1;
00058 
00059     for (i = 0; i < MAX_CLIENTS; i++) {
00060         if (p->sq_clients[i].cl_pid == pid)
00061             return i;
00062         if (p->sq_clients[i].cl_fd == -1 && avail == -1)
00063             avail = i;
00064     }
00065     if (avail != -1)
00066         p->sq_clients[avail].cl_pid = pid;
00067     return avail;
00068 }
00069 /*[clients_close_all]*/
00070 static void clients_close_all(SMIQ_FIFO *p)
00071 {
00072     int i;
00073 
00074     for (i = 0; i < MAX_CLIENTS; i++)
00075         if (p->sq_clients[i].cl_fd != -1) {
00076             (void)close(p->sq_clients[i].cl_fd);
00077             p->sq_clients[i].cl_fd = -1;
00078         }
00079 }
00080 /*[clients_end]*/
00081 static void clients_end(SMIQ_FIFO *p)
00082 {
00083     clients_close_all(p);
00084 }
00085 /*[make_fifo_name_]*/
00086 static void make_fifo_name_server(const SMIQ_FIFO *p, char *fifoname,
00087   size_t fifoname_max)
00088 {
00089     snprintf(fifoname, fifoname_max, "/tmp/smififo-%s", p->sq_name);
00090 }
00091 
00092 static void make_fifo_name_client(pid_t pid, char *fifoname,
00093   size_t fifoname_max)
00094 {
00095     snprintf(fifoname, fifoname_max, "/tmp/smififo%ld", (long)pid);
00096 }
00097 /*[]*/
00098 /*
00099     Instead of freeing allocated structure on error, another idea is to build local structure and allocate only at end, copying local structure to allocated one.
00100 */
00101 /*[smi_open_fifo]*/
00102 SMIQ *smi_open_fifo(const char *name, SMIENTITY entity, size_t msgsize)
00103 {
00104     SMIQ_FIFO *p = NULL;
00105     char fifoname[SERVER_NAME_MAX + 50];
00106 
00107     ec_null( p = calloc(1, sizeof(SMIQ_FIFO)) )
00108     p->sq_msgsize = msgsize + offsetof(struct smi_msg, smi_data);
00109     ec_null( p->sq_msg = calloc(1, p->sq_msgsize) )
00110     p->sq_entity = entity;
00111     if (strlen(name) >= SERVER_NAME_MAX) {
00112         errno = ENAMETOOLONG;
00113         EC_FAIL
00114     }
00115     strcpy(p->sq_name, name);
00116     make_fifo_name_server(p, fifoname, sizeof(fifoname));
00117     if (p->sq_entity == SMI_SERVER) {
00118         clients_bgn(p);
00119         if (mkfifo(fifoname, PERM_FILE) == -1 && errno != EEXIST)
00120             EC_FAIL
00121         ec_neg1( p->sq_fd_server = open(fifoname, O_RDONLY) )
00122         ec_neg1( p->sq_fd_server_w = open(fifoname, O_WRONLY) )
00123     }
00124     else {
00125         ec_neg1( p->sq_fd_server = open(fifoname, O_WRONLY) )
00126         make_fifo_name_client(getpid(), fifoname, sizeof(fifoname));
00127         (void)unlink(fifoname);
00128         ec_neg1( mkfifo(fifoname, PERM_FILE) )
00129         ec_neg1( p->sq_clients[0].cl_fd =
00130           open(fifoname, O_RDONLY | O_NONBLOCK) )
00131         ec_false( setblock(p->sq_clients[0].cl_fd, true) )
00132         ec_neg1( p->sq_clients[1].cl_fd = open(fifoname, O_WRONLY) )
00133     }
00134     return (SMIQ *)p;
00135 
00136 EC_CLEANUP_BGN
00137     if (p != NULL) {
00138         free(p->sq_msg);
00139         free(p);
00140     }
00141     return NULL;
00142 EC_CLEANUP_END
00143 }
00144 /*[smi_close_fifo]*/
00145 bool smi_close_fifo(SMIQ *sqp)
00146 {
00147     SMIQ_FIFO *p = (SMIQ_FIFO *)sqp;
00148 
00149     clients_end(p);
00150     (void)close(p->sq_fd_server);
00151     /*
00152         Leaving server FIFO around allows future sq_clients to be started before server.
00153     */
00154     if (p->sq_entity == SMI_CLIENT) {
00155         char fifoname[SERVER_NAME_MAX + 50];
00156 
00157         make_fifo_name_client(getpid(), fifoname, sizeof(fifoname));
00158         (void)unlink(fifoname);
00159     }
00160     else
00161         (void)close(p->sq_fd_server_w);
00162     free(p->sq_msg);
00163     free(p);
00164     return true;
00165 }
00166 /*[]*/
00167 /* Assumes whole message can be sent at once. */
00168 /*[smi_send_getaddr_fifo]*/
00169 bool smi_send_getaddr_fifo(SMIQ *sqp, struct client_id *client,
00170   void **addr)
00171 {
00172     SMIQ_FIFO *p = (SMIQ_FIFO *)sqp;
00173 
00174     if (p->sq_entity == SMI_SERVER)
00175         p->sq_client = *client;
00176     *addr = p->sq_msg;
00177     return true;
00178 }
00179 /*[smi_send_release_fifo]*/
00180 bool smi_send_release_fifo(SMIQ *sqp)
00181 {
00182     SMIQ_FIFO *p = (SMIQ_FIFO *)sqp;
00183     ssize_t nwrite;
00184 
00185     if (p->sq_entity == SMI_SERVER) {
00186         int nclient = clients_find(p, p->sq_client.c_id1);
00187         if (nclient == -1 || p->sq_clients[nclient].cl_fd == -1) {
00188             errno = EADDRNOTAVAIL;
00189             EC_FAIL
00190         }
00191         ec_neg1( nwrite = write(p->sq_clients[nclient].cl_fd, p->sq_msg,
00192           p->sq_msgsize) )
00193     }
00194     else {
00195         p->sq_msg->smi_client.c_id1 = (long)getpid();
00196         ec_neg1( nwrite = write(p->sq_fd_server, p->sq_msg,
00197           p->sq_msgsize) )
00198     }
00199     return true;
00200 
00201 EC_CLEANUP_BGN
00202     return false;
00203 EC_CLEANUP_END
00204 }
00205 /*[smi_receive_getaddr_fifo]*/
00206 bool smi_receive_getaddr_fifo(SMIQ *sqp, void **addr)
00207 {
00208     SMIQ_FIFO *p = (SMIQ_FIFO *)sqp;
00209     ssize_t nread;
00210 
00211     if (p->sq_entity == SMI_SERVER) {
00212         int nclient;
00213         char fifoname[SERVER_NAME_MAX + 50];
00214 
00215         while (true) {
00216             ec_neg1( nread = read(p->sq_fd_server, p->sq_msg,
00217               p->sq_msgsize) )
00218             if (nread == 0) {
00219                 errno = ENETDOWN;
00220                 EC_FAIL
00221             }
00222             if (nread < offsetof(struct smi_msg, smi_data)) {
00223                 errno = E2BIG;
00224                 EC_FAIL
00225             }
00226             if ((nclient = clients_find(p,
00227               (pid_t)p->sq_msg->smi_client.c_id1)) == -1) {
00228                 continue; /* client not notified */
00229             }
00230             if (p->sq_clients[nclient].cl_fd == -1) {
00231                 make_fifo_name_client((pid_t)p->sq_msg->smi_client.c_id1,
00232                   fifoname, sizeof(fifoname));
00233                 ec_neg1( p->sq_clients[nclient].cl_fd =
00234                   open(fifoname, O_WRONLY) )
00235             }
00236             break;
00237         }
00238     }
00239     else
00240         ec_neg1( nread = read(p->sq_clients[0].cl_fd, p->sq_msg,
00241           p->sq_msgsize) )
00242     *addr = p->sq_msg;
00243     return true;
00244 
00245 EC_CLEANUP_BGN
00246     return false;
00247 EC_CLEANUP_END
00248 }
00249 /*[smi_receive_release_fifo]*/
00250 bool smi_receive_release_fifo(SMIQ *sqp)
00251 {
00252     return true;
00253 }
00254 /*[]*/

Generated on Fri Apr 23 10:56:59 2004 for AUP2 Example Source by doxygen 1.3.1