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.
21 #include <sys/types.h>
22 #include <sys/socket.h>
40 static int check_error(int, int, int);
56 #if defined( HAVE_LIBZ )
57 static unsigned char tmp_buf
[BUFLEN
];
58 static unsigned char tmp2_buf
[BUFLEN
];
61 static unsigned char ctrl_buf
[256] = "";
62 static unsigned int ctrl_len
= 0;
63 static unsigned int ctrl_ofs
= 0;
78 for (i
= 0; i
< 3; i
++)
81 FD_SET(fds
[i
].fd
, &rfds
);
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
);
91 check_error(ret
, IO_SELECT
, -1); /* exit on fatal errors */
95 /* call any callbacks */
96 for (i
= 0; i
< 3; i
++)
98 if(FD_ISSET(fds
[i
].fd
, &rfds
) && fds
[i
].read_cb
)
100 if(FD_ISSET(fds
[i
].fd
, &wfds
) && fds
[i
].write_cb
)
101 (*fds
[i
].write_cb
) ();
108 send_data_blocking(int fd
, unsigned char *data
, int datalen
)
115 ret
= write(fd
, data
, datalen
);
125 ret
= check_error(ret
, IO_WRITE
, fd
);
130 /* sleep until we can write to the fd */
133 ret
= select(fd
+ 1, NULL
, &wfds
, NULL
, NULL
);
135 if(ret
> 0) /* break out so we can write */
138 if(ret
< 0) /* error ? */
139 check_error(ret
, IO_SELECT
, fd
); /* exit on fatal errors */
141 /* loop on non-fatal errors */
149 * used before CMD_INIT to pass contents of SendQ from ircd
150 * to servlink. This data must _not_ be encrypted/compressed.
153 process_sendq(struct ctrl_command
*cmd
)
155 send_data_blocking(REMOTE
.fd
, cmd
->data
, cmd
->datalen
);
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.
166 process_recvq(struct ctrl_command
*cmd
)
171 unsigned char *data
= cmd
->data
;
172 unsigned int datalen
= cmd
->datalen
;
177 if(datalen
> READLEN
)
178 send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)",
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
;
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");
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
);
206 in_state
.zip_state
.z_stream
.next_out
= buf
;
207 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
216 send_data_blocking(LOCAL
.fd
, buf
, blen
);
220 send_zipstats(struct ctrl_command
*unused
)
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
;
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
);
267 /* write incomplete, register write cb */
268 CONTROL
.write_cb
= write_ctrl
;
269 /* deregister read_cb */
270 CONTROL
.read_cb
= NULL
;
276 send_error("can't send_zipstats -- no zlib support!");
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.
286 send_error(const char *message
, ...)
289 static int sending_error
= 0;
290 struct linger linger_opt
= { 1, 30 }; /* wait 30 seconds */
294 exit(1); /* we did _try_ */
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
;
308 va_start(args
, message
);
309 len
= vsprintf((char *) in_state
.buf
+ 3, message
, args
);
312 in_state
.buf
[3 + len
++] = '\0';
313 in_state
.buf
[1] = len
>> 8;
314 in_state
.buf
[2] = len
& 0xFF;
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 */
328 * called when a command is waiting on the control pipe
334 unsigned char tmp
[2];
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 */
346 /* read the command */
347 if(!(ret
= check_error(read(CONTROL
.fd
, tmp
, 1), IO_READ
, CONTROL
.fd
)))
350 cmd
.command
= tmp
[0];
353 for (cdef
= command_table
; cdef
->commandid
; cdef
++)
355 if((int)cdef
->commandid
== cmd
.command
)
361 send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd
.command
);
365 /* read datalen for commands including data */
366 if(cdef
->flags
& COMMAND_FLAG_DATA
)
368 if(cmd
.gotdatalen
< 2)
371 if(!(ret
= check_error(read(CONTROL
.fd
, len
,
372 (2 - cmd
.gotdatalen
)), IO_READ
, CONTROL
.fd
)))
375 if(cmd
.gotdatalen
== 0)
377 cmd
.datalen
= len
[0] << 8;
382 if(ret
&& (cmd
.gotdatalen
== 1))
384 cmd
.datalen
|= len
[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
)))
400 if(cmd
.readdata
< cmd
.datalen
)
404 /* we now have the command and any data */
405 (*cdef
->handler
) (&cmd
);
419 if(!(ret
= check_error(write(CONTROL
.fd
, (ctrl_buf
+ ctrl_ofs
),
420 ctrl_len
), IO_WRITE
, CONTROL
.fd
)))
421 return; /* no data waiting */
427 /* write completed, de-register write cb */
428 CONTROL
.write_cb
= NULL
;
429 /* reregister read_cb */
430 CONTROL
.read_cb
= read_ctrl
;
441 unsigned char *buf
= out_state
.buf
;
444 assert(!out_state
.len
);
446 #if defined(HAVE_LIBZ)
447 if(out_state
.zip
|| out_state
.crypt
)
451 while ((ret
= check_error(read(LOCAL
.fd
, buf
, READLEN
), IO_READ
, LOCAL
.fd
)))
457 out_state
.zip_state
.z_stream
.next_in
= buf
;
458 out_state
.zip_state
.z_stream
.avail_in
= ret
;
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",
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
;
478 ret
= check_error(write(REMOTE
.fd
, out_state
.buf
, blen
), IO_WRITE
, REMOTE
.fd
);
481 /* write incomplete, register write cb */
482 REMOTE
.write_cb
= write_net
;
483 /* deregister read_cb */
484 LOCAL
.read_cb
= NULL
;
486 out_state
.len
= blen
- ret
;
489 #if defined(HAVE_LIBZ)
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
;
513 /* write completed, de-register write cb */
514 REMOTE
.write_cb
= NULL
;
515 /* reregister read_cb */
516 LOCAL
.read_cb
= read_data
;
520 out_state
.ofs
+= ret
;
528 unsigned char *buf
= in_state
.buf
;
531 assert(!in_state
.len
);
533 #if defined(HAVE_LIBZ)
538 while ((ret
= check_error(read(REMOTE
.fd
, buf
, READLEN
), IO_READ
, REMOTE
.fd
)))
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
)
565 send_data_blocking(LOCAL
.fd
, in_state
.buf
, blen
);
569 in_state
.zip_state
.z_stream
.next_out
= in_state
.buf
;
570 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
575 return; /* that didn't generate any decompressed input.. */
579 ret
= check_error(write(LOCAL
.fd
, in_state
.buf
, blen
), IO_WRITE
, LOCAL
.fd
);
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
;
591 #if defined(HAVE_LIBZ)
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
)))
614 /* write completed, de-register write cb */
615 LOCAL
.write_cb
= NULL
;
616 /* reregister read_cb */
617 REMOTE
.read_cb
= read_net
;
625 check_error(int ret
, int io
, int fd
)
627 if(ret
> 0) /* no error */
629 if(ret
== 0) /* EOF */
631 send_error("%s failed on %s: EOF", IO_TYPE(io
), FD_NAME(fd
));
632 exit(1); /* NOTREACHED */
640 #if EAGAIN != EWOULDBLOCK
648 /* non-fatal error, 0 bytes read */
653 send_error("%s failed on %s: %s", IO_TYPE(io
), FD_NAME(fd
), strerror(errno
));
654 exit(1); /* NOTREACHED */