Clean a bit - to be continued...
[seven-1.x.git] / servlink / io.c
blobd3560e5db4a1b38e2c960112af497212c5a19355
1 /************************************************************************
2 * IRC - Internet Relay Chat, servlink/io.c
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 1, or (at your option)
7 * any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "setup.h"
21 #include <sys/types.h>
22 #include <sys/socket.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <unistd.h>
32 #ifdef HAVE_LIBZ
33 #include <zlib.h>
34 #endif
36 #include "servlink.h"
37 #include "io.h"
38 #include "control.h"
40 static int check_error(int, int, int);
42 static const char *
43 fd_name(int fd)
45 if(fd == CONTROL.fd)
46 return "control";
47 if(fd == LOCAL.fd)
48 return "data";
49 if(fd == REMOTE.fd)
50 return "network";
52 /* uh oh... */
53 return "unknown";
56 #if defined( HAVE_LIBZ )
57 static unsigned char tmp_buf[BUFLEN];
58 static unsigned char tmp2_buf[BUFLEN];
59 #endif
61 static unsigned char ctrl_buf[256] = "";
62 static unsigned int ctrl_len = 0;
63 static unsigned int ctrl_ofs = 0;
65 void
66 io_loop(int nfds)
68 fd_set rfds;
69 fd_set wfds;
70 int i, ret;
72 /* loop forever */
73 for (;;)
75 FD_ZERO(&rfds);
76 FD_ZERO(&wfds);
78 for (i = 0; i < 3; i++)
80 if(fds[i].read_cb)
81 FD_SET(fds[i].fd, &rfds);
82 if(fds[i].write_cb)
83 FD_SET(fds[i].fd, &wfds);
86 /* we have <3 fds ever, so I don't think select is too painful */
87 ret = select(nfds, &rfds, &wfds, NULL, NULL);
89 if(ret < 0)
91 check_error(ret, IO_SELECT, -1); /* exit on fatal errors */
93 else if(ret > 0)
95 /* call any callbacks */
96 for (i = 0; i < 3; i++)
98 if(FD_ISSET(fds[i].fd, &rfds) && fds[i].read_cb)
99 (*fds[i].read_cb) ();
100 if(FD_ISSET(fds[i].fd, &wfds) && fds[i].write_cb)
101 (*fds[i].write_cb) ();
107 void
108 send_data_blocking(int fd, unsigned char *data, int datalen)
110 int ret;
111 fd_set wfds;
113 while (1)
115 ret = write(fd, data, datalen);
117 if(ret == datalen)
118 return;
119 else if(ret > 0)
121 data += ret;
122 datalen -= ret;
125 ret = check_error(ret, IO_WRITE, fd);
127 FD_ZERO(&wfds);
128 FD_SET(fd, &wfds);
130 /* sleep until we can write to the fd */
131 while (1)
133 ret = select(fd + 1, NULL, &wfds, NULL, NULL);
135 if(ret > 0) /* break out so we can write */
136 break;
138 if(ret < 0) /* error ? */
139 check_error(ret, IO_SELECT, fd); /* exit on fatal errors */
141 /* loop on non-fatal errors */
147 * process_sendq:
149 * used before CMD_INIT to pass contents of SendQ from ircd
150 * to servlink. This data must _not_ be encrypted/compressed.
152 void
153 process_sendq(struct ctrl_command *cmd)
155 send_data_blocking(REMOTE.fd, cmd->data, cmd->datalen);
159 * process_recvq:
161 * used before CMD_INIT to pass contents of RecvQ from ircd
162 * to servlink. This data must be decrypted/decopmressed before
163 * sending back to the ircd.
165 void
166 process_recvq(struct ctrl_command *cmd)
168 int ret;
169 unsigned char *buf;
170 int blen;
171 unsigned char *data = cmd->data;
172 unsigned int datalen = cmd->datalen;
174 buf = data;
175 blen = datalen;
176 ret = -1;
177 if(datalen > READLEN)
178 send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)",
179 datalen, READLEN);
181 #ifdef HAVE_LIBZ
182 if(in_state.zip)
184 /* decompress data */
185 in_state.zip_state.z_stream.next_in = buf;
186 in_state.zip_state.z_stream.avail_in = blen;
187 in_state.zip_state.z_stream.next_out = tmp2_buf;
188 in_state.zip_state.z_stream.avail_out = BUFLEN;
190 buf = tmp2_buf;
191 while (in_state.zip_state.z_stream.avail_in)
193 if((ret = inflate(&in_state.zip_state.z_stream, Z_NO_FLUSH)) != Z_OK)
195 if(!strncmp("ERROR ", (char *)in_state.zip_state.z_stream.next_in, 6))
196 send_error("Received uncompressed ERROR");
197 else
198 send_error("Inflate failed: %s", zError(ret));
200 blen = BUFLEN - in_state.zip_state.z_stream.avail_out;
202 if(in_state.zip_state.z_stream.avail_in)
204 send_data_blocking(LOCAL.fd, buf, blen);
205 blen = 0;
206 in_state.zip_state.z_stream.next_out = buf;
207 in_state.zip_state.z_stream.avail_out = BUFLEN;
211 if(!blen)
212 return;
214 #endif
216 send_data_blocking(LOCAL.fd, buf, blen);
219 void
220 send_zipstats(struct ctrl_command *unused)
222 #ifdef HAVE_LIBZ
223 int i = 0;
224 int ret;
225 u_int32_t len;
226 if(!in_state.active || !out_state.active)
227 send_error("Error processing CMD_ZIPSTATS - link is not active!");
228 if(!in_state.zip || !out_state.zip)
229 send_error("Error processing CMD_ZIPSTATS - link is not compressed!");
231 ctrl_buf[i++] = RPL_ZIPSTATS;
232 ctrl_buf[i++] = 0;
233 ctrl_buf[i++] = 16;
235 len = (u_int32_t) in_state.zip_state.z_stream.total_out;
236 ctrl_buf[i++] = ((len >> 24) & 0xFF);
237 ctrl_buf[i++] = ((len >> 16) & 0xFF);
238 ctrl_buf[i++] = ((len >> 8) & 0xFF);
239 ctrl_buf[i++] = ((len) & 0xFF);
241 len = (u_int32_t) in_state.zip_state.z_stream.total_in;
242 ctrl_buf[i++] = ((len >> 24) & 0xFF);
243 ctrl_buf[i++] = ((len >> 16) & 0xFF);
244 ctrl_buf[i++] = ((len >> 8) & 0xFF);
245 ctrl_buf[i++] = ((len) & 0xFF);
247 len = (u_int32_t) out_state.zip_state.z_stream.total_in;
248 ctrl_buf[i++] = ((len >> 24) & 0xFF);
249 ctrl_buf[i++] = ((len >> 16) & 0xFF);
250 ctrl_buf[i++] = ((len >> 8) & 0xFF);
251 ctrl_buf[i++] = ((len) & 0xFF);
253 len = (u_int32_t) out_state.zip_state.z_stream.total_out;
254 ctrl_buf[i++] = ((len >> 24) & 0xFF);
255 ctrl_buf[i++] = ((len >> 16) & 0xFF);
256 ctrl_buf[i++] = ((len >> 8) & 0xFF);
257 ctrl_buf[i++] = ((len) & 0xFF);
259 in_state.zip_state.z_stream.total_in = 0;
260 in_state.zip_state.z_stream.total_out = 0;
261 out_state.zip_state.z_stream.total_in = 0;
262 out_state.zip_state.z_stream.total_out = 0;
264 ret = check_error(write(CONTROL.fd, ctrl_buf, i), IO_WRITE, CONTROL.fd);
265 if(ret < i)
267 /* write incomplete, register write cb */
268 CONTROL.write_cb = write_ctrl;
269 /* deregister read_cb */
270 CONTROL.read_cb = NULL;
271 ctrl_ofs = ret;
272 ctrl_len = i - ret;
273 return;
275 #else
276 send_error("can't send_zipstats -- no zlib support!");
277 #endif
280 /* send_error
281 * - we ran into some problem, make a last ditch effort to
282 * flush the control fd sendq, then (blocking) send an
283 * error message over the control fd.
285 void
286 send_error(const char *message, ...)
288 va_list args;
289 static int sending_error = 0;
290 struct linger linger_opt = { 1, 30 }; /* wait 30 seconds */
291 int len;
293 if(sending_error)
294 exit(1); /* we did _try_ */
296 sending_error = 1;
298 if(ctrl_len) /* attempt to flush any data we have... */
300 send_data_blocking(CONTROL.fd, (ctrl_buf + ctrl_ofs), ctrl_len);
303 /* prepare the message, in in_buf, since we won't be using it again.. */
304 in_state.buf[0] = RPL_ERROR;
305 in_state.buf[1] = 0;
306 in_state.buf[2] = 0;
308 va_start(args, message);
309 len = vsprintf((char *) in_state.buf + 3, message, args);
310 va_end(args);
312 in_state.buf[3 + len++] = '\0';
313 in_state.buf[1] = len >> 8;
314 in_state.buf[2] = len & 0xFF;
315 len += 3;
317 send_data_blocking(CONTROL.fd, in_state.buf, len);
319 /* XXX - is this portable?
320 * this obviously will fail on a non socket.. */
321 setsockopt(CONTROL.fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(struct linger));
323 /* well, we've tried... */
324 exit(1); /* now abort */
327 /* read_ctrl
328 * called when a command is waiting on the control pipe
330 void
331 read_ctrl(void)
333 int ret;
334 unsigned char tmp[2];
335 unsigned char *len;
336 struct command_def *cdef;
337 static struct ctrl_command cmd = { 0, 0, 0, 0, NULL };
339 if(cmd.command == 0) /* we don't have a command yet */
341 cmd.gotdatalen = 0;
342 cmd.datalen = 0;
343 cmd.readdata = 0;
344 cmd.data = NULL;
346 /* read the command */
347 if(!(ret = check_error(read(CONTROL.fd, tmp, 1), IO_READ, CONTROL.fd)))
348 return;
350 cmd.command = tmp[0];
353 for (cdef = command_table; cdef->commandid; cdef++)
355 if((int)cdef->commandid == cmd.command)
356 break;
359 if(!cdef->commandid)
361 send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd.command);
362 /* NOTREACHED */
365 /* read datalen for commands including data */
366 if(cdef->flags & COMMAND_FLAG_DATA)
368 if(cmd.gotdatalen < 2)
370 len = tmp;
371 if(!(ret = check_error(read(CONTROL.fd, len,
372 (2 - cmd.gotdatalen)), IO_READ, CONTROL.fd)))
373 return;
375 if(cmd.gotdatalen == 0)
377 cmd.datalen = len[0] << 8;
378 cmd.gotdatalen++;
379 ret--;
380 len++;
382 if(ret && (cmd.gotdatalen == 1))
384 cmd.datalen |= len[0];
385 cmd.gotdatalen++;
386 if(cmd.datalen > 0)
387 cmd.data = calloc(cmd.datalen, 1);
392 if(cmd.readdata < cmd.datalen) /* try to get any remaining data */
394 if(!(ret = check_error(read(CONTROL.fd,
395 (cmd.data + cmd.readdata),
396 cmd.datalen - cmd.readdata), IO_READ, CONTROL.fd)))
397 return;
399 cmd.readdata += ret;
400 if(cmd.readdata < cmd.datalen)
401 return;
404 /* we now have the command and any data */
405 (*cdef->handler) (&cmd);
407 if(cmd.datalen > 0)
408 free(cmd.data);
409 cmd.command = 0;
412 void
413 write_ctrl(void)
415 int ret;
417 assert(ctrl_len);
419 if(!(ret = check_error(write(CONTROL.fd, (ctrl_buf + ctrl_ofs),
420 ctrl_len), IO_WRITE, CONTROL.fd)))
421 return; /* no data waiting */
423 ctrl_len -= ret;
425 if(!ctrl_len)
427 /* write completed, de-register write cb */
428 CONTROL.write_cb = NULL;
429 /* reregister read_cb */
430 CONTROL.read_cb = read_ctrl;
431 ctrl_ofs = 0;
433 else
434 ctrl_ofs += ret;
437 void
438 read_data(void)
440 int ret, ret2;
441 unsigned char *buf = out_state.buf;
442 int blen;
443 ret2 = -1;
444 assert(!out_state.len);
446 #if defined(HAVE_LIBZ)
447 if(out_state.zip || out_state.crypt)
448 buf = tmp_buf;
449 #endif
451 while ((ret = check_error(read(LOCAL.fd, buf, READLEN), IO_READ, LOCAL.fd)))
453 blen = ret;
454 #ifdef HAVE_LIBZ
455 if(out_state.zip)
457 out_state.zip_state.z_stream.next_in = buf;
458 out_state.zip_state.z_stream.avail_in = ret;
460 buf = out_state.buf;
461 out_state.zip_state.z_stream.next_out = buf;
462 out_state.zip_state.z_stream.avail_out = BUFLEN;
463 if(!(ret2 = deflate(&out_state.zip_state.z_stream,
464 Z_PARTIAL_FLUSH)) == Z_OK)
465 send_error("error compressing outgoing data - deflate returned: %s",
466 zError(ret2));
468 if(!out_state.zip_state.z_stream.avail_out)
469 send_error("error compressing outgoing data - avail_out == 0");
470 if(out_state.zip_state.z_stream.avail_in)
471 send_error("error compressing outgoing data - avail_in != 0");
473 blen = BUFLEN - out_state.zip_state.z_stream.avail_out;
475 #endif
478 ret = check_error(write(REMOTE.fd, out_state.buf, blen), IO_WRITE, REMOTE.fd);
479 if(ret < blen)
481 /* write incomplete, register write cb */
482 REMOTE.write_cb = write_net;
483 /* deregister read_cb */
484 LOCAL.read_cb = NULL;
485 out_state.ofs = ret;
486 out_state.len = blen - ret;
487 return;
489 #if defined(HAVE_LIBZ)
490 if(out_state.zip)
491 buf = tmp_buf;
492 #endif
497 void
498 write_net(void)
500 int ret;
502 assert(out_state.len);
504 if(!(ret = check_error(write(REMOTE.fd,
505 (out_state.buf + out_state.ofs),
506 out_state.len), IO_WRITE, REMOTE.fd)))
507 return; /* no data waiting */
509 out_state.len -= ret;
511 if(!out_state.len)
513 /* write completed, de-register write cb */
514 REMOTE.write_cb = NULL;
515 /* reregister read_cb */
516 LOCAL.read_cb = read_data;
517 out_state.ofs = 0;
519 else
520 out_state.ofs += ret;
523 void
524 read_net(void)
526 int ret;
527 int ret2;
528 unsigned char *buf = in_state.buf;
529 int blen;
530 ret2 = -1;
531 assert(!in_state.len);
533 #if defined(HAVE_LIBZ)
534 if(in_state.zip)
535 buf = tmp_buf;
536 #endif
538 while ((ret = check_error(read(REMOTE.fd, buf, READLEN), IO_READ, REMOTE.fd)))
540 blen = ret;
541 #ifdef HAVE_LIBZ
542 if(in_state.zip)
544 /* decompress data */
545 in_state.zip_state.z_stream.next_in = buf;
546 in_state.zip_state.z_stream.avail_in = ret;
547 in_state.zip_state.z_stream.next_out = in_state.buf;
548 in_state.zip_state.z_stream.avail_out = BUFLEN;
550 while (in_state.zip_state.z_stream.avail_in)
552 if((ret2 = inflate(&in_state.zip_state.z_stream,
553 Z_NO_FLUSH)) != Z_OK)
555 if(!strncmp("ERROR ", (char *)buf, 6))
556 send_error("Received uncompressed ERROR");
557 send_error("Inflate failed: %s", zError(ret2));
559 blen = BUFLEN - in_state.zip_state.z_stream.avail_out;
561 if(in_state.zip_state.z_stream.avail_in)
563 if(blen)
565 send_data_blocking(LOCAL.fd, in_state.buf, blen);
566 blen = 0;
569 in_state.zip_state.z_stream.next_out = in_state.buf;
570 in_state.zip_state.z_stream.avail_out = BUFLEN;
574 if(!blen)
575 return; /* that didn't generate any decompressed input.. */
577 #endif
579 ret = check_error(write(LOCAL.fd, in_state.buf, blen), IO_WRITE, LOCAL.fd);
581 if(ret < blen)
583 in_state.ofs = ret;
584 in_state.len = blen - ret;
585 /* write incomplete, register write cb */
586 LOCAL.write_cb = write_data;
587 /* deregister read_cb */
588 REMOTE.read_cb = NULL;
589 return;
591 #if defined(HAVE_LIBZ)
592 if(in_state.zip)
593 buf = tmp_buf;
594 #endif
598 void
599 write_data(void)
601 int ret;
603 assert(in_state.len);
605 if(!(ret = check_error(write(LOCAL.fd,
606 (in_state.buf + in_state.ofs),
607 in_state.len), IO_WRITE, LOCAL.fd)))
608 return;
610 in_state.len -= ret;
612 if(!in_state.len)
614 /* write completed, de-register write cb */
615 LOCAL.write_cb = NULL;
616 /* reregister read_cb */
617 REMOTE.read_cb = read_net;
618 in_state.ofs = 0;
620 else
621 in_state.ofs += ret;
625 check_error(int ret, int io, int fd)
627 if(ret > 0) /* no error */
628 return ret;
629 if(ret == 0) /* EOF */
631 send_error("%s failed on %s: EOF", IO_TYPE(io), FD_NAME(fd));
632 exit(1); /* NOTREACHED */
635 /* ret == -1.. */
636 switch (errno)
638 case EINPROGRESS:
639 case EWOULDBLOCK:
640 #if EAGAIN != EWOULDBLOCK
641 case EAGAIN:
642 #endif
643 case EALREADY:
644 case EINTR:
645 #ifdef ERESTART
646 case ERESTART:
647 #endif
648 /* non-fatal error, 0 bytes read */
649 return 0;
652 /* fatal error */
653 send_error("%s failed on %s: %s", IO_TYPE(io), FD_NAME(fd), strerror(errno));
654 exit(1); /* NOTREACHED */