]>
jfr.im git - solanum.git/blob - servlink/io.c
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)
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.
18 * $Id: io.c 3319 2007-03-29 20:03:06Z jilles $
23 #include <sys/types.h>
24 #include <sys/socket.h>
42 static int check_error(int, int, int);
58 #if defined( HAVE_LIBZ )
59 static unsigned char tmp_buf
[BUFLEN
];
60 static unsigned char tmp2_buf
[BUFLEN
];
63 static unsigned char ctrl_buf
[256] = "";
64 static unsigned int ctrl_len
= 0;
65 static unsigned int ctrl_ofs
= 0;
80 for (i
= 0; i
< 3; i
++)
83 FD_SET(fds
[i
].fd
, &rfds
);
85 FD_SET(fds
[i
].fd
, &wfds
);
88 /* we have <3 fds ever, so I don't think select is too painful */
89 ret
= select(nfds
, &rfds
, &wfds
, NULL
, NULL
);
93 check_error(ret
, IO_SELECT
, -1); /* exit on fatal errors */
97 /* call any callbacks */
98 for (i
= 2; i
>= 0; i
--)
100 if(FD_ISSET(fds
[i
].fd
, &rfds
) && fds
[i
].read_cb
)
101 (*fds
[i
].read_cb
) ();
102 if(FD_ISSET(fds
[i
].fd
, &wfds
) && fds
[i
].write_cb
)
103 (*fds
[i
].write_cb
) ();
110 send_data_blocking(int fd
, unsigned char *data
, int datalen
)
117 ret
= write(fd
, data
, datalen
);
127 ret
= check_error(ret
, IO_WRITE
, fd
);
132 /* sleep until we can write to the fd */
135 ret
= select(fd
+ 1, NULL
, &wfds
, NULL
, NULL
);
137 if(ret
> 0) /* break out so we can write */
140 if(ret
< 0) /* error ? */
141 check_error(ret
, IO_SELECT
, fd
); /* exit on fatal errors */
143 /* loop on non-fatal errors */
151 * used before CMD_INIT to pass contents of SendQ from ircd
152 * to servlink. This data must _not_ be encrypted/compressed.
155 process_sendq(struct ctrl_command
*cmd
)
157 send_data_blocking(REMOTE
.fd
, cmd
->data
, cmd
->datalen
);
163 * used before CMD_INIT to pass contents of RecvQ from ircd
164 * to servlink. This data must be decrypted/decopmressed before
165 * sending back to the ircd.
168 process_recvq(struct ctrl_command
*cmd
)
173 unsigned char *data
= cmd
->data
;
174 unsigned int datalen
= cmd
->datalen
;
179 if(datalen
> READLEN
)
180 send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)",
186 /* decompress data */
187 in_state
.zip_state
.z_stream
.next_in
= buf
;
188 in_state
.zip_state
.z_stream
.avail_in
= blen
;
189 in_state
.zip_state
.z_stream
.next_out
= tmp2_buf
;
190 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
193 while (in_state
.zip_state
.z_stream
.avail_in
)
195 if((ret
= inflate(&in_state
.zip_state
.z_stream
, Z_NO_FLUSH
)) != Z_OK
)
197 if(!strncmp("ERROR ", (char *)in_state
.zip_state
.z_stream
.next_in
, 6))
198 send_error("Received uncompressed ERROR");
200 send_error("Inflate failed: %s", zError(ret
));
202 blen
= BUFLEN
- in_state
.zip_state
.z_stream
.avail_out
;
204 if(in_state
.zip_state
.z_stream
.avail_in
)
206 send_data_blocking(LOCAL
.fd
, buf
, blen
);
208 in_state
.zip_state
.z_stream
.next_out
= buf
;
209 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
218 send_data_blocking(LOCAL
.fd
, buf
, blen
);
222 send_zipstats(struct ctrl_command
*unused
)
228 if(!in_state
.active
|| !out_state
.active
)
229 send_error("Error processing CMD_ZIPSTATS - link is not active!");
230 if(!in_state
.zip
|| !out_state
.zip
)
231 send_error("Error processing CMD_ZIPSTATS - link is not compressed!");
233 ctrl_buf
[i
++] = RPL_ZIPSTATS
;
237 len
= (u_int32_t
) in_state
.zip_state
.z_stream
.total_out
;
238 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
239 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
240 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
241 ctrl_buf
[i
++] = ((len
) & 0xFF);
243 len
= (u_int32_t
) in_state
.zip_state
.z_stream
.total_in
;
244 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
245 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
246 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
247 ctrl_buf
[i
++] = ((len
) & 0xFF);
249 len
= (u_int32_t
) out_state
.zip_state
.z_stream
.total_in
;
250 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
251 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
252 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
253 ctrl_buf
[i
++] = ((len
) & 0xFF);
255 len
= (u_int32_t
) out_state
.zip_state
.z_stream
.total_out
;
256 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
257 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
258 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
259 ctrl_buf
[i
++] = ((len
) & 0xFF);
261 in_state
.zip_state
.z_stream
.total_in
= 0;
262 in_state
.zip_state
.z_stream
.total_out
= 0;
263 out_state
.zip_state
.z_stream
.total_in
= 0;
264 out_state
.zip_state
.z_stream
.total_out
= 0;
266 ret
= check_error(write(CONTROL
.fd
, ctrl_buf
, i
), IO_WRITE
, CONTROL
.fd
);
269 /* write incomplete, register write cb */
270 CONTROL
.write_cb
= write_ctrl
;
271 /* deregister read_cb */
272 CONTROL
.read_cb
= NULL
;
278 send_error("can't send_zipstats -- no zlib support!");
283 * - we ran into some problem, make a last ditch effort to
284 * flush the control fd sendq, then (blocking) send an
285 * error message over the control fd.
288 send_error(const char *message
, ...)
291 static int sending_error
= 0;
292 struct linger linger_opt
= { 1, 30 }; /* wait 30 seconds */
296 exit(1); /* we did _try_ */
300 if(ctrl_len
) /* attempt to flush any data we have... */
302 send_data_blocking(CONTROL
.fd
, (ctrl_buf
+ ctrl_ofs
), ctrl_len
);
305 /* prepare the message, in in_buf, since we won't be using it again.. */
306 in_state
.buf
[0] = RPL_ERROR
;
310 va_start(args
, message
);
311 len
= vsprintf((char *) in_state
.buf
+ 3, message
, args
);
314 in_state
.buf
[3 + len
++] = '\0';
315 in_state
.buf
[1] = len
>> 8;
316 in_state
.buf
[2] = len
& 0xFF;
319 send_data_blocking(CONTROL
.fd
, in_state
.buf
, len
);
321 /* XXX - is this portable?
322 * this obviously will fail on a non socket.. */
323 setsockopt(CONTROL
.fd
, SOL_SOCKET
, SO_LINGER
, &linger_opt
, sizeof(struct linger
));
325 /* well, we've tried... */
326 exit(1); /* now abort */
330 * called when a command is waiting on the control pipe
336 unsigned char tmp
[2];
338 struct command_def
*cdef
;
339 static struct ctrl_command cmd
= { 0, 0, 0, 0, NULL
};
341 if(cmd
.command
== 0) /* we don't have a command yet */
348 /* read the command */
349 if(!(ret
= check_error(read(CONTROL
.fd
, tmp
, 1), IO_READ
, CONTROL
.fd
)))
352 cmd
.command
= tmp
[0];
355 for (cdef
= command_table
; cdef
->commandid
; cdef
++)
357 if((int)cdef
->commandid
== cmd
.command
)
363 send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd
.command
);
367 /* read datalen for commands including data */
368 if(cdef
->flags
& COMMAND_FLAG_DATA
)
370 if(cmd
.gotdatalen
< 2)
373 if(!(ret
= check_error(read(CONTROL
.fd
, len
,
374 (2 - cmd
.gotdatalen
)), IO_READ
, CONTROL
.fd
)))
377 if(cmd
.gotdatalen
== 0)
379 cmd
.datalen
= len
[0] << 8;
384 if(ret
&& (cmd
.gotdatalen
== 1))
386 cmd
.datalen
|= len
[0];
389 cmd
.data
= calloc(cmd
.datalen
, 1);
394 if(cmd
.readdata
< cmd
.datalen
) /* try to get any remaining data */
396 if(!(ret
= check_error(read(CONTROL
.fd
,
397 (cmd
.data
+ cmd
.readdata
),
398 cmd
.datalen
- cmd
.readdata
), IO_READ
, CONTROL
.fd
)))
402 if(cmd
.readdata
< cmd
.datalen
)
406 /* we now have the command and any data */
407 (*cdef
->handler
) (&cmd
);
421 if(!(ret
= check_error(write(CONTROL
.fd
, (ctrl_buf
+ ctrl_ofs
),
422 ctrl_len
), IO_WRITE
, CONTROL
.fd
)))
423 return; /* no data waiting */
429 /* write completed, de-register write cb */
430 CONTROL
.write_cb
= NULL
;
431 /* reregister read_cb */
432 CONTROL
.read_cb
= read_ctrl
;
443 unsigned char *buf
= out_state
.buf
;
446 assert(!out_state
.len
);
448 #if defined(HAVE_LIBZ)
449 if(out_state
.zip
|| out_state
.crypt
)
453 while ((ret
= check_error(read(LOCAL
.fd
, buf
, READLEN
), IO_READ
, LOCAL
.fd
)))
459 out_state
.zip_state
.z_stream
.next_in
= buf
;
460 out_state
.zip_state
.z_stream
.avail_in
= ret
;
463 out_state
.zip_state
.z_stream
.next_out
= buf
;
464 out_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
465 if(!(ret2
= deflate(&out_state
.zip_state
.z_stream
,
466 Z_PARTIAL_FLUSH
)) == Z_OK
)
467 send_error("error compressing outgoing data - deflate returned: %s",
470 if(!out_state
.zip_state
.z_stream
.avail_out
)
471 send_error("error compressing outgoing data - avail_out == 0");
472 if(out_state
.zip_state
.z_stream
.avail_in
)
473 send_error("error compressing outgoing data - avail_in != 0");
475 blen
= BUFLEN
- out_state
.zip_state
.z_stream
.avail_out
;
480 ret
= check_error(write(REMOTE
.fd
, out_state
.buf
, blen
), IO_WRITE
, REMOTE
.fd
);
483 /* write incomplete, register write cb */
484 REMOTE
.write_cb
= write_net
;
485 /* deregister read_cb */
486 LOCAL
.read_cb
= NULL
;
488 out_state
.len
= blen
- ret
;
491 #if defined(HAVE_LIBZ)
504 assert(out_state
.len
);
506 if(!(ret
= check_error(write(REMOTE
.fd
,
507 (out_state
.buf
+ out_state
.ofs
),
508 out_state
.len
), IO_WRITE
, REMOTE
.fd
)))
509 return; /* no data waiting */
511 out_state
.len
-= ret
;
515 /* write completed, de-register write cb */
516 REMOTE
.write_cb
= NULL
;
517 /* reregister read_cb */
518 LOCAL
.read_cb
= read_data
;
522 out_state
.ofs
+= ret
;
530 unsigned char *buf
= in_state
.buf
;
533 assert(!in_state
.len
);
535 #if defined(HAVE_LIBZ)
540 while ((ret
= check_error(read(REMOTE
.fd
, buf
, READLEN
), IO_READ
, REMOTE
.fd
)))
546 /* decompress data */
547 in_state
.zip_state
.z_stream
.next_in
= buf
;
548 in_state
.zip_state
.z_stream
.avail_in
= ret
;
549 in_state
.zip_state
.z_stream
.next_out
= in_state
.buf
;
550 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
552 while (in_state
.zip_state
.z_stream
.avail_in
)
554 if((ret2
= inflate(&in_state
.zip_state
.z_stream
,
555 Z_NO_FLUSH
)) != Z_OK
)
557 if(!strncmp("ERROR ", (char *)buf
, 6))
558 send_error("Received uncompressed ERROR");
559 send_error("Inflate failed: %s", zError(ret2
));
561 blen
= BUFLEN
- in_state
.zip_state
.z_stream
.avail_out
;
563 if(in_state
.zip_state
.z_stream
.avail_in
)
567 send_data_blocking(LOCAL
.fd
, in_state
.buf
, blen
);
571 in_state
.zip_state
.z_stream
.next_out
= in_state
.buf
;
572 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
577 return; /* that didn't generate any decompressed input.. */
581 ret
= check_error(write(LOCAL
.fd
, in_state
.buf
, blen
), IO_WRITE
, LOCAL
.fd
);
586 in_state
.len
= blen
- ret
;
587 /* write incomplete, register write cb */
588 LOCAL
.write_cb
= write_data
;
589 /* deregister read_cb */
590 REMOTE
.read_cb
= NULL
;
593 #if defined(HAVE_LIBZ)
605 assert(in_state
.len
);
607 if(!(ret
= check_error(write(LOCAL
.fd
,
608 (in_state
.buf
+ in_state
.ofs
),
609 in_state
.len
), IO_WRITE
, LOCAL
.fd
)))
616 /* write completed, de-register write cb */
617 LOCAL
.write_cb
= NULL
;
618 /* reregister read_cb */
619 REMOTE
.read_cb
= read_net
;
627 check_error(int ret
, int io
, int fd
)
629 if(ret
> 0) /* no error */
631 if(ret
== 0) /* EOF */
633 send_error("%s failed on %s: EOF", IO_TYPE(io
), FD_NAME(fd
));
634 exit(1); /* NOTREACHED */
642 #if EAGAIN != EWOULDBLOCK
650 /* non-fatal error, 0 bytes read */
655 send_error("%s failed on %s: %s", IO_TYPE(io
), FD_NAME(fd
), strerror(errno
));
656 exit(1); /* NOTREACHED */