00001 /* 00002 SMI - POSIX messages 00003 AUP2, Sec. 7.07.2 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 "smi_mq.h" 00023 #ifdef COMPILES_POSIX_MESSAGE_PASSING 00024 #include <mqueue.h> 00025 #endif 00026 00027 #ifndef COMPILES_POSIX_MESSAGE_PASSING 00028 00029 typedef int mqd_t; 00030 struct mq_attr { 00031 long mq_flags; 00032 long mq_maxmsg; 00033 long mq_msgsize; 00034 long mq_curmsgs; 00035 }; 00036 00037 static int missing_function(const char *s, ...) 00038 { 00039 errno = ENOSYS; 00040 return -1; 00041 } 00042 00043 #define mq_open (mqd_t)missing_function 00044 #define mq_close(a) missing_function(NULL) 00045 #define mq_unlink missing_function 00046 #define mq_send(a, b, c, d) missing_function(NULL) 00047 #define mq_receive(a, b, c, d) missing_function(NULL) 00048 00049 #endif 00050 /*[top]*/ 00051 #define MAX_CLIENTS 20 00052 00053 typedef struct { 00054 SMIENTITY sq_entity; /* entity */ 00055 mqd_t sq_mqd_server; /* server message-queue descriptor */ 00056 char sq_name[SERVER_NAME_MAX]; /* server name */ 00057 struct client_info { /* Client uses only sq_clients[0] */ 00058 mqd_t cl_mqd; /* client message-queue descriptor */ 00059 pid_t cl_pid; /* client process ID */ 00060 } sq_clients[MAX_CLIENTS]; 00061 struct client_id sq_client; /* client ID */ 00062 size_t sq_msgsize; /* msg size */ 00063 struct smi_msg *sq_msg; /* msg buffer */ 00064 } SMIQ_MQ; 00065 /*[make_mq_name]*/ 00066 static void make_mq_name_server(const SMIQ_MQ *p, char *mqname, 00067 size_t mqname_max) 00068 { 00069 snprintf(mqname, mqname_max, "/smimq-s%s", p->sq_name); 00070 } 00071 00072 static void make_mq_name_client(pid_t pid, char *mqname, 00073 size_t mqname_max) 00074 { 00075 snprintf(mqname, mqname_max, "/smimq-c%d", pid); 00076 } 00077 /*[get_client_mqd]*/ 00078 static mqd_t get_client_mqd(SMIQ_MQ *p, pid_t pid) 00079 { 00080 int i, avail = -1; 00081 char mqname[SERVER_NAME_MAX + 100]; 00082 00083 for (i = 0; i < MAX_CLIENTS; i++) { 00084 if (p->sq_clients[i].cl_pid == pid) 00085 return p->sq_clients[i].cl_mqd; 00086 if (avail == -1 && p->sq_clients[i].cl_pid == 0) 00087 avail = i; 00088 } 00089 errno = ECONNREFUSED; 00090 ec_neg1( avail ) 00091 p->sq_clients[avail].cl_pid = pid; 00092 make_mq_name_client(pid, mqname, sizeof(mqname)); 00093 ec_neg1( p->sq_clients[avail].cl_mqd = mq_open(mqname, O_WRONLY) ) 00094 return p->sq_clients[avail].cl_mqd; 00095 00096 EC_CLEANUP_BGN 00097 return (mqd_t)-1; 00098 EC_CLEANUP_END 00099 } 00100 /*[smi_open_mq]*/ 00101 static pid_t my_pid; 00102 00103 SMIQ *smi_open_mq(const char *name, SMIENTITY entity, size_t msgsize) 00104 { 00105 SMIQ_MQ *p = NULL; 00106 char mqname[SERVER_NAME_MAX + 100]; 00107 struct mq_attr attr = {0}; 00108 00109 my_pid = getpid(); 00110 ec_null( p = calloc(1, sizeof(SMIQ_MQ)) ) 00111 p->sq_msgsize = msgsize + offsetof(struct smi_msg, smi_data); 00112 ec_null( p->sq_msg = calloc(1, p->sq_msgsize) ) 00113 p->sq_entity = entity; 00114 p->sq_mqd_server = p->sq_clients[0].cl_mqd = (mqd_t)-1; 00115 if (strlen(name) >= SERVER_NAME_MAX) { 00116 errno = ENAMETOOLONG; 00117 EC_FAIL 00118 } 00119 strcpy(p->sq_name, name); 00120 make_mq_name_server(p, mqname, sizeof(mqname)); 00121 attr.mq_maxmsg = 100; 00122 attr.mq_msgsize = p->sq_msgsize; 00123 if (p->sq_entity == SMI_SERVER) { 00124 (void)mq_unlink(mqname); 00125 ec_cmp( errno, ENOSYS ) 00126 ec_neg1( p->sq_mqd_server = mq_open(mqname, O_RDONLY | O_CREAT, 00127 PERM_FILE, &attr) ) 00128 } 00129 else { 00130 ec_neg1( p->sq_mqd_server = mq_open(mqname, O_WRONLY) ) 00131 make_mq_name_client(my_pid, mqname, sizeof(mqname)); 00132 ec_neg1( p->sq_clients[0].cl_mqd = mq_open(mqname, 00133 O_RDONLY | O_CREAT, PERM_FILE, &attr) ) 00134 } 00135 return (SMIQ *)p; 00136 00137 EC_CLEANUP_BGN 00138 if (p != NULL) 00139 (void)smi_close_mq((SMIQ *)p); 00140 return NULL; 00141 EC_CLEANUP_END 00142 } 00143 /*[smi_close_mq]*/ 00144 bool smi_close_mq(SMIQ *sqp) 00145 { 00146 SMIQ_MQ *p = (SMIQ_MQ *)sqp; 00147 char msgname[SERVER_NAME_MAX + 100]; 00148 00149 if (p->sq_entity == SMI_SERVER) { 00150 make_mq_name_server(p, msgname, sizeof(msgname)); 00151 (void)mq_close(p->sq_mqd_server); 00152 (void)mq_unlink(msgname); 00153 } 00154 else { 00155 make_mq_name_client(my_pid, msgname, sizeof(msgname)); 00156 (void)mq_close(p->sq_mqd_server); 00157 (void)mq_unlink(msgname); 00158 } 00159 free(p->sq_msg); 00160 free(p); 00161 return true; 00162 } 00163 /*[smi_send_getaddr_mq]*/ 00164 bool smi_send_getaddr_mq(SMIQ *sqp, struct client_id *client, 00165 void **addr) 00166 { 00167 SMIQ_MQ *p = (SMIQ_MQ *)sqp; 00168 00169 if (p->sq_entity == SMI_SERVER) 00170 p->sq_client = *client; 00171 *addr = p->sq_msg; 00172 return true; 00173 } 00174 00175 bool smi_send_release_mq(SMIQ *sqp) 00176 { 00177 SMIQ_MQ *p = (SMIQ_MQ *)sqp; 00178 mqd_t mqd_receiver; 00179 00180 if (p->sq_entity == SMI_SERVER) 00181 ec_neg1( mqd_receiver = get_client_mqd(p, p->sq_client.c_id1) ) 00182 else { 00183 mqd_receiver = p->sq_mqd_server; 00184 p->sq_msg->smi_client.c_id1 = my_pid; 00185 } 00186 ec_neg1( mq_send(mqd_receiver, (const char *)p->sq_msg, 00187 p->sq_msgsize, 0) ) 00188 return true; 00189 00190 EC_CLEANUP_BGN 00191 return false; 00192 EC_CLEANUP_END 00193 } 00194 /*[smi_receive_getaddr_mq]*/ 00195 bool smi_receive_getaddr_mq(SMIQ *sqp, void **addr) 00196 { 00197 SMIQ_MQ *p = (SMIQ_MQ *)sqp; 00198 mqd_t mqd_receiver; 00199 ssize_t nrcv; 00200 00201 if (p->sq_entity == SMI_SERVER) 00202 mqd_receiver = p->sq_mqd_server; 00203 else 00204 mqd_receiver = p->sq_clients[0].cl_mqd; 00205 ec_neg1( nrcv = mq_receive(mqd_receiver, (char *)p->sq_msg, 00206 p->sq_msgsize, NULL) ) 00207 *addr = p->sq_msg; 00208 return true; 00209 00210 EC_CLEANUP_BGN 00211 return false; 00212 EC_CLEANUP_END 00213 } 00214 00215 bool smi_receive_release_mq(SMIQ *sqp) 00216 { 00217 return true; 00218 } 00219 /*[]*/ 00220