1 /* 2 * Copyright (c)2004 Cat's Eye Technologies. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * Neither the name of Cat's Eye Technologies nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * conn_npipe.c 36 * $Id: conn_npipe.c,v 1.13 2005/02/06 19:53:19 cpressey Exp $ 37 */ 38 39 #include "system.h" 40 #ifdef HAS_NPIPE 41 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <sys/time.h> 45 #include <sys/errno.h> 46 47 #include <err.h> 48 #include <stdarg.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include <libaura/buffer.h> 55 #include <libaura/fspred.h> 56 57 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS 58 #include "dfui.h" 59 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS 60 #include "encoding.h" 61 #include "dump.h" 62 #include "conn_npipe.h" 63 64 /***** BACKEND ******/ 65 66 /** High Level **/ 67 68 /* 69 * Connect to the frontend. 70 */ 71 dfui_err_t 72 dfui_npipe_be_start(struct dfui_connection *c) 73 { 74 asprintf(&T_NPIPE(c)->out_pipename, "/tmp/dfui.%s.to_fe", c->rendezvous); 75 asprintf(&T_NPIPE(c)->in_pipename, "/tmp/dfui.%s.from_fe", c->rendezvous); 76 77 /* 78 * Create the named pipes. 79 */ 80 errno = 0; 81 if (mkfifo(T_NPIPE(c)->in_pipename, 0600) < 0) { 82 if (errno != EEXIST) { 83 warn("mkfifo (to_be)"); 84 return(DFUI_FAILURE); 85 } 86 } 87 errno = 0; 88 if (mkfifo(T_NPIPE(c)->out_pipename, 0600) < 0) { 89 if (errno != EEXIST) { 90 warn("mkfifo (to_fe)"); 91 return(DFUI_FAILURE); 92 } 93 } 94 dfui_debug("opening pipes...\n"); 95 if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) { 96 return(DFUI_FAILURE); 97 } 98 dfui_debug("opened to_fe pipe\n"); 99 setvbuf(T_NPIPE(c)->out, NULL, _IONBF, 0); 100 if ((T_NPIPE(c)->in = fopen(T_NPIPE(c)->in_pipename, "r")) == NULL) { 101 fclose(T_NPIPE(c)->out); 102 return(DFUI_FAILURE); 103 } 104 dfui_debug("opened to_be pipe\n"); 105 return(DFUI_SUCCESS); 106 } 107 108 /* 109 * Tell the frontend that we're done and disconnect from it. 110 */ 111 dfui_err_t 112 dfui_npipe_be_stop(struct dfui_connection *c) 113 { 114 if (dfui_npipe_be_ll_exchange(c, DFUI_BE_MSG_STOP, "")) { 115 fclose(T_NPIPE(c)->in); 116 fclose(T_NPIPE(c)->out); 117 return(DFUI_SUCCESS); 118 } else 119 return(DFUI_FAILURE); 120 } 121 122 /** Low Level **/ 123 124 /* 125 * Exchange a message with the frontend. This involves two receive()/reply() 126 * cycles: one to provide our message, one to get a reply from the frontend. 127 * 128 * Note that this does not immediately send the message to the frontend - 129 * it can't, because we're a service and it's a client. What it does is 130 * keep the message handy and wait for a frontend request to come in. It 131 * then replies to that request with our message. 132 * 133 * The protocol looks something like the following, using the PRESENT and 134 * SUBMIT exchange as an example: 135 * 136 * frontend (client) | backend (service) 137 * ------------------+------------------ 138 * 139 * [stage 1] 140 * READY --> ll_receive() 141 * <-- PRESENT(form) ll_reply() 142 * 143 * [stage 2] 144 * SUBMIT(form) --> ll_receive() 145 * <-- READY ll_reply() 146 * 147 * Each of those exchanges is a pair of calls, on our end, to 148 * dfui_npipe_be_ll_receive() and dfui_npipe_be_ll_reply(). 149 * 150 * The set of messages that the client can pass us is determined by 151 * the conversation state: 152 * 153 * o In stage 1, only READY and ABORT are meaningful. 154 * o After a PRESENT, the messages SUBMIT and ABORT are meaningul 155 * in stage 2. 156 * o During a PROG_*, the messages CONTINUE, CANCEL, and ABORT 157 * are meaningful in stage 2. 158 * 159 * If the frontend sends us with READY in stage 2, we assume it has 160 * fallen out of sync, so we send the same initial reply again, going 161 * back to stage 1 as it were. 162 * 163 * After this call, the message is available in c->ebuf. 164 */ 165 dfui_err_t 166 dfui_npipe_be_ll_exchange(struct dfui_connection *c, char msgtype, const char *msg) 167 { 168 char *fmsg; 169 170 /* 171 * Construct our message to send. 172 */ 173 174 fmsg = malloc(strlen(msg) + 2); 175 fmsg[0] = msgtype; 176 strcpy(fmsg + 1, msg); 177 178 /* 179 * Get the frontend's message. 180 */ 181 182 dfui_npipe_be_ll_receive(c); 183 184 /* 185 * Frontend message should have been either READY or ABORT. 186 * If ABORT, we get out of here pronto. 187 */ 188 189 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) { 190 free(fmsg); 191 return(DFUI_FAILURE); 192 } 193 194 /* XXX if (!READY) ??? */ 195 196 do { 197 dfui_npipe_be_ll_reply(c, fmsg); 198 199 /* 200 * Here, the frontend has picked up our request and is 201 * processing it. We have to wait for the response. 202 */ 203 204 dfui_npipe_be_ll_receive(c); 205 206 /* 207 * Did we get READY from this? 208 * If so, loop! 209 */ 210 211 } while (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_READY); 212 213 fmsg[0] = DFUI_BE_MSG_READY; 214 fmsg[1] = '\0'; 215 dfui_npipe_be_ll_reply(c, fmsg); 216 217 free(fmsg); 218 return(DFUI_SUCCESS); 219 } 220 221 /* 222 * Receive a message from the frontend. 223 * This call is synchronous. 224 * After this call, the NUL-terminated message is available in 225 * c->ebuf. 226 */ 227 dfui_err_t 228 dfui_npipe_be_ll_receive(struct dfui_connection *c) 229 { 230 int length; 231 char *buf; 232 233 dfui_debug("WAITING<<>>\n"); 234 235 fread(&length, 4, 1, T_NPIPE(c)->in); 236 237 dfui_debug("LENGTH<<%d>>\n", length); 238 239 buf = malloc(length + 1); 240 fread(buf, length, 1, T_NPIPE(c)->in); 241 aura_buffer_set(c->ebuf, buf, length); 242 free(buf); 243 244 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf)); 245 246 return(DFUI_SUCCESS); 247 } 248 249 /* 250 * Send a NUL-terminated reply to the frontend. 251 */ 252 dfui_err_t 253 dfui_npipe_be_ll_reply(struct dfui_connection *c, const char *fmsg) 254 { 255 int length; 256 257 dfui_debug("SEND<<%s>>\n", fmsg); 258 259 length = strlen(fmsg); 260 261 fwrite(&length, 4, 1, T_NPIPE(c)->out); 262 fwrite(fmsg, length, 1, T_NPIPE(c)->out); 263 264 return(DFUI_SUCCESS); 265 } 266 267 /******** FRONTEND ********/ 268 269 /** High Level **/ 270 271 dfui_err_t 272 dfui_npipe_fe_connect(struct dfui_connection *c) 273 { 274 asprintf(&T_NPIPE(c)->in_pipename, "/tmp/dfui.%s.to_fe", c->rendezvous); 275 asprintf(&T_NPIPE(c)->out_pipename, "/tmp/dfui.%s.from_fe", c->rendezvous); 276 277 dfui_debug("waiting for named pipes...\n"); 278 279 /* 280 * Wait for named pipes to be created. 281 */ 282 if (!is_named_pipe("%s", T_NPIPE(c)->in_pipename)) { 283 while (!is_named_pipe("%s", T_NPIPE(c)->in_pipename)) { 284 sleep(1); 285 } 286 sleep(1); 287 } 288 289 dfui_debug("opening inflow pipe...\n"); 290 291 if ((T_NPIPE(c)->in = fopen(T_NPIPE(c)->in_pipename, "r")) == NULL) { 292 return(DFUI_FAILURE); 293 } 294 295 dfui_debug("opening outflow pipe...\n"); 296 297 if ((T_NPIPE(c)->out = fopen(T_NPIPE(c)->out_pipename, "w")) == NULL) { 298 fclose(T_NPIPE(c)->in); 299 return(DFUI_FAILURE); 300 } 301 302 dfui_debug("making outflow pipe raw...\n"); 303 304 setvbuf(T_NPIPE(c)->out, NULL, _IONBF, 0); 305 return(DFUI_SUCCESS); 306 } 307 308 dfui_err_t 309 dfui_npipe_fe_disconnect(struct dfui_connection *c) 310 { 311 fclose(T_NPIPE(c)->in); 312 fclose(T_NPIPE(c)->out); 313 return(DFUI_SUCCESS); 314 } 315 316 /** Low Level **/ 317 318 /* 319 * Ask for, and subsequently receieve, a message from the backend. 320 * msgtype should be one of the DFUI_FE_MSG_* constants. 321 * This call is synchronous. 322 * After this call, the null-terminated, encoded message is 323 * available in T_NPIPE(c)->buf. 324 */ 325 dfui_err_t 326 dfui_npipe_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg) 327 { 328 char *fmsg, *buf; 329 int length; 330 331 /* 332 * First, assert that the connection is open. 333 */ 334 335 if (c == NULL || T_NPIPE(c)->in == NULL || T_NPIPE(c)->out == NULL) 336 return(DFUI_FAILURE); 337 338 /* 339 * Construct a message. 340 */ 341 342 fmsg = malloc(strlen(msg) + 2); 343 fmsg[0] = msgtype; 344 strcpy(fmsg + 1, msg); 345 346 dfui_debug("SEND<<%s>>\n", fmsg); 347 348 /* 349 * Send a NUL-terminated message to the backend. 350 */ 351 352 length = strlen(fmsg); 353 fwrite(&length, 4, 1, T_NPIPE(c)->out); 354 fwrite(fmsg, length, 1, T_NPIPE(c)->out); 355 356 /* 357 * Receive a reply from the backend. 358 * If our message was a READY, this should be a message like PRESENT. 359 * Otherwise it should simply be a READY. 360 */ 361 362 dfui_debug("WAITING<<>>\n"); 363 364 fread(&length, 4, 1, T_NPIPE(c)->in); 365 buf = malloc(length + 1); 366 fread(buf, length, 1, T_NPIPE(c)->in); 367 aura_buffer_set(c->ebuf, buf, length); 368 free(buf); 369 370 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf)); 371 372 free(fmsg); 373 374 return(DFUI_SUCCESS); 375 } 376 377 #endif /* HAS_NPIPE */ 378