MFC: An off-by-one malloc size was corrupting the installer's memory,
[dragonfly.git] / contrib / bsdinstaller-1.1.6 / src / lib / libdfui / conn_tcp.c
blob960e17b3beeb80e0bdc2feeb9f37d9d5b70a8819
1 /*
3 * Copyright (c) 2004 Scott Ullrich <GeekGod@GeekGod.com>
4 * Portions Copyright (c) 2004 Chris Pressey <cpressey@catseye.mine.nu>
6 * Copyright (c) 2004 The DragonFly Project.
7 * All rights reserved.
9 * This code is derived from software contributed to The DragonFly Project
10 * by Scott Ullrich and Chris Pressey (see above for e-mail addresses).
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided with the
22 * distribution.
24 * 3. Neither the name of The DragonFly Project nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific, prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32 * COPYRIGHT HOLDERS, CONTRIBUTORS OR VOICES IN THE AUTHOR'S HEAD
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY
34 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
35 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
38 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
41 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
42 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
44 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
51 * conn_tcp.c
52 * $Id: conn_tcp.c,v 1.16 2005/02/06 19:53:19 cpressey Exp $
55 #include "system.h"
56 #ifdef HAS_TCP
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #include <sys/time.h>
61 #include <sys/errno.h>
62 #include <sys/types.h>
63 #include <sys/socket.h>
64 #include <netinet/in.h>
65 #include <arpa/inet.h>
67 #include <err.h>
68 #include <errno.h>
69 #include <stdarg.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <unistd.h>
75 #include <aura/buffer.h>
77 #define NEEDS_DFUI_STRUCTURE_DEFINITIONS
78 #include "dfui.h"
79 #undef NEEDS_DFUI_STRUCTURE_DEFINITIONS
80 #include "encoding.h"
81 #include "conn_tcp.h"
82 #include "dump.h"
84 /***** BACKEND ******/
86 /** High Level **/
89 * Connect to the frontend.
91 dfui_err_t
92 dfui_tcp_be_start(struct dfui_connection *c)
94 struct sockaddr_in servaddr;
95 int server_port;
96 int tru = 1;
98 server_port = atoi(c->rendezvous);
101 * Create the tcp socket
103 errno = 0;
104 if ((T_TCP(c)->listen_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
105 return(DFUI_FAILURE);
106 dfui_debug("LISTEN_SOCKET<<%d>>\n", T_TCP(c)->listen_sd);
108 if (setsockopt(T_TCP(c)->listen_sd, SOL_SOCKET, SO_REUSEADDR,
109 &tru, sizeof(tru)) == -1) {
110 return(DFUI_FAILURE);
113 bzero(&servaddr, sizeof(servaddr));
114 servaddr.sin_family = AF_INET;
115 servaddr.sin_port = htons(server_port);
116 switch(inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr)) {
117 case 0:
118 warnx("inet_pton(): address not parseable");
119 return(DFUI_FAILURE);
120 case 1:
121 break;
122 default:
123 warn("inet_pton()");
124 return(DFUI_FAILURE);
127 if (bind(T_TCP(c)->listen_sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {
128 warn("bind()");
129 return(DFUI_FAILURE);
131 dfui_debug("BOUND_ON<<%d>>\n", T_TCP(c)->listen_sd);
132 if (listen(T_TCP(c)->listen_sd, 0) == -1)
133 return(DFUI_FAILURE);
134 dfui_debug("LISTENING_ON<<%d>>\n", T_TCP(c)->listen_sd);
135 /* at this point we should be listening on the rendezvous port */
136 return(DFUI_SUCCESS);
140 * Tell the frontend that we're done and disconnect from it.
142 dfui_err_t
143 dfui_tcp_be_stop(struct dfui_connection *c)
145 if (dfui_tcp_be_ll_exchange(c, DFUI_BE_MSG_STOP, "")) {
146 close(T_TCP(c)->listen_sd);
147 close(T_TCP(c)->connected_sd);
148 fclose(T_TCP(c)->stream);
149 return(DFUI_SUCCESS);
150 } else
151 return(DFUI_FAILURE);
154 /** Low Level **/
157 * Exchange a message with the frontend. This involves two receive()/reply()
158 * cycles: one to provide our message, one to get a reply from the frontend.
160 * Note that this does not immediately send the message to the frontend -
161 * it can't, because we're a service and it's a client. What it does is
162 * keep the message handy and wait for a frontend request to come in. It
163 * then replies to that request with our message.
165 * The protocol looks something like the following, using the PRESENT and
166 * SUBMIT exchange as an example:
168 * frontend (client) | backend (service)
169 * ------------------+------------------
171 * [stage 1]
172 * READY --> ll_receive()
173 * <-- PRESENT(form) ll_reply()
175 * [stage 2]
176 * SUBMIT(form) --> ll_receive()
177 * <-- READY ll_reply()
179 * Each of those exchanges is a pair of calls, on our end, to
180 * dfui_tcp_be_ll_receive() and dfui_npipe_be_ll_reply().
182 * The set of messages that the client can pass us is determined by
183 * the conversation state:
185 * o In stage 1, only READY and ABORT are meaningful.
186 * o After a PRESENT, the messages SUBMIT and ABORT are meaningul
187 * in stage 2.
188 * o During a PROG_*, the messages CONTINUE, CANCEL, and ABORT
189 * are meaningful in stage 2.
191 * If the frontend sends us with READY in stage 2, we assume it has
192 * fallen out of sync, so we send the same initial reply again, going
193 * back to stage 1 as it were.
195 * After this call, the message is available in c->ebuf.
197 dfui_err_t
198 dfui_tcp_be_ll_exchange(struct dfui_connection *c, char msgtype, const char *msg)
200 char *fmsg;
203 * Construct our message to send.
206 fmsg = malloc(strlen(msg) + 2);
207 fmsg[0] = msgtype;
208 strcpy(fmsg + 1, msg);
211 * Get the frontend's message.
214 dfui_tcp_be_ll_receive(c);
217 * Frontend message should have been either READY or ABORT.
218 * If ABORT, we get out of here pronto.
221 if (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_ABORT) {
222 free(fmsg);
223 return(DFUI_FAILURE);
226 /* XXX if (!READY) ??? */
228 do {
229 dfui_tcp_be_ll_reply(c, fmsg);
232 * Here, the frontend has picked up our request and is
233 * processing it. We have to wait for the response.
236 dfui_tcp_be_ll_receive(c);
239 * Did we get READY from this?
240 * If so, loop!
243 } while (aura_buffer_buf(c->ebuf)[0] == DFUI_FE_MSG_READY);
245 fmsg[0] = DFUI_BE_MSG_READY;
246 fmsg[1] = '\0';
247 dfui_tcp_be_ll_reply(c, fmsg);
249 free(fmsg);
250 return(DFUI_SUCCESS);
254 * Receive a message from the frontend.
255 * This call is synchronous.
256 * After this call, the NUL-terminated message is available in
257 * c->ebuf.
259 dfui_err_t
260 dfui_tcp_be_ll_receive(struct dfui_connection *c)
262 int length;
263 char *buf;
265 top:
267 if (!T_TCP(c)->is_connected) {
268 dfui_debug("NOT_CONNECTED,ACCEPTING_ON<<%d>>\n", T_TCP(c)->listen_sd);
269 T_TCP(c)->connected_sd = accept(T_TCP(c)->listen_sd, NULL, NULL);
270 dfui_debug("ACCEPTED<<%d>>\n", T_TCP(c)->connected_sd);
271 T_TCP(c)->stream = fdopen(T_TCP(c)->connected_sd, "r+");
272 T_TCP(c)->is_connected = 1;
273 } else {
274 dfui_debug("ALREADY_CONNECTED<<>>\n");
277 dfui_debug("WAITING<<>>\n");
279 if (read_data(T_TCP(c)->stream, (char *)&length, sizeof(length)) == -1) {
280 dfui_debug("LOST_THEM<<>>\n");
281 fclose(T_TCP(c)->stream);
282 T_TCP(c)->is_connected = 0;
283 goto top;
286 buf = malloc(length + 1);
287 if (read_data(T_TCP(c)->stream, buf, length) == -1) {
288 dfui_debug("LOST_THEM<<>>\n");
289 fclose(T_TCP(c)->stream);
290 T_TCP(c)->is_connected = 0;
291 goto top;
294 aura_buffer_set(c->ebuf, buf, length);
295 free(buf);
297 dfui_debug("RECEIVED<<%s>>\n", aura_buffer_buf(c->ebuf));
299 return(DFUI_SUCCESS);
303 * Send a NUL-terminated reply to the frontend.
305 dfui_err_t
306 dfui_tcp_be_ll_reply(struct dfui_connection *c, const char *fmsg)
308 int length;
310 dfui_debug("SEND<<%s>>\n", fmsg);
311 length = strlen(fmsg);
312 write_data(T_TCP(c)->stream, (char *)&length, sizeof(length));
313 write_data(T_TCP(c)->stream, fmsg, length);
315 return(DFUI_SUCCESS);
318 /******** FRONTEND ********/
320 /** High Level **/
322 dfui_err_t
323 dfui_tcp_fe_connect(struct dfui_connection *c)
325 struct sockaddr_in servaddr;
326 int server_port;
327 int connected = 0;
329 server_port = atoi(c->rendezvous);
332 * Create the tcp socket
334 while (!connected) {
335 errno = 0;
336 if ((T_TCP(c)->connected_sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
337 return(DFUI_FAILURE);
340 dfui_debug("CLIENT_SOCKET<<%d>>\n", T_TCP(c)->connected_sd);
341 bzero(&servaddr, sizeof(servaddr));
342 servaddr.sin_family = AF_INET;
343 servaddr.sin_port = htons(server_port);
344 inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
346 if (connect(T_TCP(c)->connected_sd, (struct sockaddr *)&servaddr,
347 sizeof(servaddr)) == 0) {
348 dfui_debug("CONNECTED<<>>\n");
349 connected = 1;
350 } else {
351 dfui_debug("NO_CONNECT<<>>\n");
352 close(T_TCP(c)->connected_sd);
353 sleep(1);
357 /* at this point we should be connected */
359 T_TCP(c)->stream = fdopen(T_TCP(c)->connected_sd, "r+");
361 return(DFUI_SUCCESS);
364 dfui_err_t
365 dfui_tcp_fe_disconnect(struct dfui_connection *c)
367 close(T_TCP(c)->connected_sd);
368 return(DFUI_SUCCESS);
371 /** Low Level **/
374 * Ask for, and subsequently receieve, a message from the backend.
375 * msgtype should be one of the DFUI_FE_MSG_* constants.
376 * This call is synchronous.
377 * After this call, the null-terminated, encoded message is
378 * available in T_TCP(c)->buf.
380 dfui_err_t
381 dfui_tcp_fe_ll_request(struct dfui_connection *c, char msgtype, const char *msg)
383 char *fmsg, *buf;
384 int length, result;
387 * First, assert that the connection is open.
390 if (c == NULL || T_TCP(c)->connected_sd == -1)
391 return(DFUI_FAILURE);
394 * Construct a message.
397 fmsg = malloc(strlen(msg) + 2);
398 fmsg[0] = msgtype;
399 strcpy(fmsg + 1, msg);
400 dfui_debug("SEND<<%s>>\n", fmsg);
403 * Send a NUL-terminated message to the backend.
406 length = strlen(fmsg);
407 result = write_data(T_TCP(c)->stream, (char *)&length, sizeof(length));
408 dfui_debug("result<<%d>>\n", result);
409 result = write_data(T_TCP(c)->stream, (char *)fmsg, length);
410 dfui_debug("result<<%d>>\n", result);
413 * Receive a reply from the backend.
414 * If our message was a READY, this should be a message like PRESENT.
415 * Otherwise it should simply be a READY.
418 dfui_debug("WAITING<<>>\n");
419 result = read_data(T_TCP(c)->stream, (char *)&length, sizeof(length));
420 dfui_debug("result<<%d>>\n", result);
421 buf = malloc(length + 1);
422 result = read_data(T_TCP(c)->stream, buf, length);
423 dfui_debug("result<<%d>>\n", result);
424 aura_buffer_set(c->ebuf, buf, length);
425 free(buf);
427 dfui_debug("RECV<<%s>>\n", aura_buffer_buf(c->ebuf));
429 free(fmsg);
431 return(DFUI_SUCCESS);
435 read_data(FILE *f, char *buf, int n)
437 int bcount; /* counts bytes read */
438 int br; /* bytes read this pass */
440 bcount = 0;
441 br = 0;
442 while (bcount < n) {
443 if ((br = fread(buf, 1, n - bcount, f)) > 0) {
444 dfui_debug("READ_BYTES<<%d>>\n", br);
445 bcount += br;
446 buf += br;
447 } else if (br <= 0) {
448 dfui_debug("read_data_error<<%d>>\n", br);
449 return(-1);
452 return(bcount);
456 write_data(FILE *f, const char *buf, int n)
458 int bcount; /* counts bytes written */
459 int bw; /* bytes written this pass */
461 bcount = 0;
462 bw = 0;
463 while (bcount < n) {
464 if ((bw = fwrite(buf, 1, n - bcount, f)) > 0) {
465 dfui_debug("WROTE_BYTES<<%d>>\n", bw);
466 bcount += bw;
467 buf += bw;
468 } else if (bw <= 0) {
469 dfui_debug("write_data_error<<%d>>\n", bw);
470 return(-1);
473 return(bcount);
476 #endif /* HAS_TCP */