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 22629 2006-05-23 17:47:03Z androsyn $
23 #include <sys/types.h>
24 #include <sys/socket.h>
43 static int check_error(int, int, int);
59 #if defined( HAVE_LIBZ )
60 static unsigned char tmp_buf
[BUFLEN
];
61 static unsigned char tmp2_buf
[BUFLEN
];
64 static unsigned char ctrl_buf
[256] = "";
65 static unsigned int ctrl_len
= 0;
66 static unsigned int ctrl_ofs
= 0;
81 for (i
= 0; i
< 3; i
++)
84 FD_SET(fds
[i
].fd
, &rfds
);
86 FD_SET(fds
[i
].fd
, &wfds
);
89 /* we have <3 fds ever, so I don't think select is too painful */
90 ret
= select(nfds
, &rfds
, &wfds
, NULL
, NULL
);
94 check_error(ret
, IO_SELECT
, -1); /* exit on fatal errors */
98 /* call any callbacks */
99 for (i
= 0; i
< 3; i
++)
101 if(FD_ISSET(fds
[i
].fd
, &rfds
) && fds
[i
].read_cb
)
102 (*fds
[i
].read_cb
) ();
103 if(FD_ISSET(fds
[i
].fd
, &wfds
) && fds
[i
].write_cb
)
104 (*fds
[i
].write_cb
) ();
111 send_data_blocking(int fd
, unsigned char *data
, int datalen
)
118 ret
= write(fd
, data
, datalen
);
128 ret
= check_error(ret
, IO_WRITE
, fd
);
133 /* sleep until we can write to the fd */
136 ret
= select(fd
+ 1, NULL
, &wfds
, NULL
, NULL
);
138 if(ret
> 0) /* break out so we can write */
141 if(ret
< 0) /* error ? */
142 check_error(ret
, IO_SELECT
, fd
); /* exit on fatal errors */
144 /* loop on non-fatal errors */
152 * used before CMD_INIT to pass contents of SendQ from ircd
153 * to servlink. This data must _not_ be encrypted/compressed.
156 process_sendq(struct ctrl_command
*cmd
)
158 send_data_blocking(REMOTE
.fd
, cmd
->data
, cmd
->datalen
);
164 * used before CMD_INIT to pass contents of RecvQ from ircd
165 * to servlink. This data must be decrypted/decopmressed before
166 * sending back to the ircd.
169 process_recvq(struct ctrl_command
*cmd
)
174 unsigned char *data
= cmd
->data
;
175 unsigned int datalen
= cmd
->datalen
;
180 if(datalen
> READLEN
)
181 send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)",
187 /* decompress data */
188 in_state
.zip_state
.z_stream
.next_in
= buf
;
189 in_state
.zip_state
.z_stream
.avail_in
= blen
;
190 in_state
.zip_state
.z_stream
.next_out
= tmp2_buf
;
191 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
194 while (in_state
.zip_state
.z_stream
.avail_in
)
196 if((ret
= inflate(&in_state
.zip_state
.z_stream
, Z_NO_FLUSH
)) != Z_OK
)
198 if(!strncmp("ERROR ", (char *)in_state
.zip_state
.z_stream
.next_in
, 6))
199 send_error("Received uncompressed ERROR");
201 send_error("Inflate failed: %s", zError(ret
));
203 blen
= BUFLEN
- in_state
.zip_state
.z_stream
.avail_out
;
205 if(in_state
.zip_state
.z_stream
.avail_in
)
207 send_data_blocking(LOCAL
.fd
, buf
, blen
);
209 in_state
.zip_state
.z_stream
.next_out
= buf
;
210 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
219 send_data_blocking(LOCAL
.fd
, buf
, blen
);
223 send_zipstats(struct ctrl_command
*unused
)
229 if(!in_state
.active
|| !out_state
.active
)
230 send_error("Error processing CMD_ZIPSTATS - link is not active!");
231 if(!in_state
.zip
|| !out_state
.zip
)
232 send_error("Error processing CMD_ZIPSTATS - link is not compressed!");
234 ctrl_buf
[i
++] = RPL_ZIPSTATS
;
238 len
= (uint32_t) in_state
.zip_state
.z_stream
.total_out
;
239 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
240 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
241 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
242 ctrl_buf
[i
++] = ((len
) & 0xFF);
244 len
= (uint32_t) in_state
.zip_state
.z_stream
.total_in
;
245 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
246 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
247 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
248 ctrl_buf
[i
++] = ((len
) & 0xFF);
250 len
= (uint32_t) out_state
.zip_state
.z_stream
.total_in
;
251 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
252 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
253 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
254 ctrl_buf
[i
++] = ((len
) & 0xFF);
256 len
= (uint32_t) out_state
.zip_state
.z_stream
.total_out
;
257 ctrl_buf
[i
++] = ((len
>> 24) & 0xFF);
258 ctrl_buf
[i
++] = ((len
>> 16) & 0xFF);
259 ctrl_buf
[i
++] = ((len
>> 8) & 0xFF);
260 ctrl_buf
[i
++] = ((len
) & 0xFF);
262 in_state
.zip_state
.z_stream
.total_in
= 0;
263 in_state
.zip_state
.z_stream
.total_out
= 0;
264 out_state
.zip_state
.z_stream
.total_in
= 0;
265 out_state
.zip_state
.z_stream
.total_out
= 0;
267 ret
= check_error(write(CONTROL
.fd
, ctrl_buf
, i
), IO_WRITE
, CONTROL
.fd
);
270 /* write incomplete, register write cb */
271 CONTROL
.write_cb
= write_ctrl
;
272 /* deregister read_cb */
273 CONTROL
.read_cb
= NULL
;
279 send_error("can't send_zipstats -- no zlib support!");
284 * - we ran into some problem, make a last ditch effort to
285 * flush the control fd sendq, then (blocking) send an
286 * error message over the control fd.
289 send_error(const char *message
, ...)
292 static int sending_error
= 0;
293 struct linger linger_opt
= { 1, 30 }; /* wait 30 seconds */
297 exit(1); /* we did _try_ */
301 if(ctrl_len
) /* attempt to flush any data we have... */
303 send_data_blocking(CONTROL
.fd
, (ctrl_buf
+ ctrl_ofs
), ctrl_len
);
306 /* prepare the message, in in_buf, since we won't be using it again.. */
307 in_state
.buf
[0] = RPL_ERROR
;
311 va_start(args
, message
);
312 len
= vsprintf((char *) in_state
.buf
+ 3, message
, args
);
315 in_state
.buf
[3 + len
++] = '\0';
316 in_state
.buf
[1] = len
>> 8;
317 in_state
.buf
[2] = len
& 0xFF;
320 send_data_blocking(CONTROL
.fd
, in_state
.buf
, len
);
322 /* XXX - is this portable?
323 * this obviously will fail on a non socket.. */
324 setsockopt(CONTROL
.fd
, SOL_SOCKET
, SO_LINGER
, &linger_opt
, sizeof(struct linger
));
326 /* well, we've tried... */
327 exit(1); /* now abort */
331 * called when a command is waiting on the control pipe
337 unsigned char tmp
[2];
339 struct command_def
*cdef
;
340 static struct ctrl_command cmd
= { 0, 0, 0, 0, NULL
};
342 if(cmd
.command
== 0) /* we don't have a command yet */
349 /* read the command */
350 if(!(ret
= check_error(read(CONTROL
.fd
, tmp
, 1), IO_READ
, CONTROL
.fd
)))
353 cmd
.command
= tmp
[0];
356 for (cdef
= command_table
; cdef
->commandid
; cdef
++)
358 if((int)cdef
->commandid
== cmd
.command
)
364 send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd
.command
);
368 /* read datalen for commands including data */
369 if(cdef
->flags
& COMMAND_FLAG_DATA
)
371 if(cmd
.gotdatalen
< 2)
374 if(!(ret
= check_error(read(CONTROL
.fd
, len
,
375 (2 - cmd
.gotdatalen
)), IO_READ
, CONTROL
.fd
)))
378 if(cmd
.gotdatalen
== 0)
380 cmd
.datalen
= len
[0] << 8;
385 if(ret
&& (cmd
.gotdatalen
== 1))
387 cmd
.datalen
|= len
[0];
390 cmd
.data
= calloc(cmd
.datalen
, 1);
395 if(cmd
.readdata
< cmd
.datalen
) /* try to get any remaining data */
397 if(!(ret
= check_error(read(CONTROL
.fd
,
398 (cmd
.data
+ cmd
.readdata
),
399 cmd
.datalen
- cmd
.readdata
), IO_READ
, CONTROL
.fd
)))
403 if(cmd
.readdata
< cmd
.datalen
)
407 /* we now have the command and any data */
408 (*cdef
->handler
) (&cmd
);
422 if(!(ret
= check_error(write(CONTROL
.fd
, (ctrl_buf
+ ctrl_ofs
),
423 ctrl_len
), IO_WRITE
, CONTROL
.fd
)))
424 return; /* no data waiting */
430 /* write completed, de-register write cb */
431 CONTROL
.write_cb
= NULL
;
432 /* reregister read_cb */
433 CONTROL
.read_cb
= read_ctrl
;
444 unsigned char *buf
= out_state
.buf
;
447 assert(!out_state
.len
);
449 #if defined(HAVE_LIBZ)
450 if(out_state
.zip
|| out_state
.crypt
)
454 while ((ret
= check_error(read(LOCAL
.fd
, buf
, READLEN
), IO_READ
, LOCAL
.fd
)))
460 out_state
.zip_state
.z_stream
.next_in
= buf
;
461 out_state
.zip_state
.z_stream
.avail_in
= ret
;
464 out_state
.zip_state
.z_stream
.next_out
= buf
;
465 out_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
466 if(!(ret2
= deflate(&out_state
.zip_state
.z_stream
,
467 Z_PARTIAL_FLUSH
)) == Z_OK
)
468 send_error("error compressing outgoing data - deflate returned: %s",
471 if(!out_state
.zip_state
.z_stream
.avail_out
)
472 send_error("error compressing outgoing data - avail_out == 0");
473 if(out_state
.zip_state
.z_stream
.avail_in
)
474 send_error("error compressing outgoing data - avail_in != 0");
476 blen
= BUFLEN
- out_state
.zip_state
.z_stream
.avail_out
;
481 ret
= check_error(write(REMOTE
.fd
, out_state
.buf
, blen
), IO_WRITE
, REMOTE
.fd
);
484 /* write incomplete, register write cb */
485 REMOTE
.write_cb
= write_net
;
486 /* deregister read_cb */
487 LOCAL
.read_cb
= NULL
;
489 out_state
.len
= blen
- ret
;
492 #if defined(HAVE_LIBZ)
505 assert(out_state
.len
);
507 if(!(ret
= check_error(write(REMOTE
.fd
,
508 (out_state
.buf
+ out_state
.ofs
),
509 out_state
.len
), IO_WRITE
, REMOTE
.fd
)))
510 return; /* no data waiting */
512 out_state
.len
-= ret
;
516 /* write completed, de-register write cb */
517 REMOTE
.write_cb
= NULL
;
518 /* reregister read_cb */
519 LOCAL
.read_cb
= read_data
;
523 out_state
.ofs
+= ret
;
531 unsigned char *buf
= in_state
.buf
;
534 assert(!in_state
.len
);
536 #if defined(HAVE_LIBZ)
541 while ((ret
= check_error(read(REMOTE
.fd
, buf
, READLEN
), IO_READ
, REMOTE
.fd
)))
547 /* decompress data */
548 in_state
.zip_state
.z_stream
.next_in
= buf
;
549 in_state
.zip_state
.z_stream
.avail_in
= ret
;
550 in_state
.zip_state
.z_stream
.next_out
= in_state
.buf
;
551 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
553 while (in_state
.zip_state
.z_stream
.avail_in
)
555 if((ret2
= inflate(&in_state
.zip_state
.z_stream
,
556 Z_NO_FLUSH
)) != Z_OK
)
558 if(!strncmp("ERROR ", (char *)buf
, 6))
559 send_error("Received uncompressed ERROR");
560 send_error("Inflate failed: %s", zError(ret2
));
562 blen
= BUFLEN
- in_state
.zip_state
.z_stream
.avail_out
;
564 if(in_state
.zip_state
.z_stream
.avail_in
)
568 send_data_blocking(LOCAL
.fd
, in_state
.buf
, blen
);
572 in_state
.zip_state
.z_stream
.next_out
= in_state
.buf
;
573 in_state
.zip_state
.z_stream
.avail_out
= BUFLEN
;
578 return; /* that didn't generate any decompressed input.. */
582 ret
= check_error(write(LOCAL
.fd
, in_state
.buf
, blen
), IO_WRITE
, LOCAL
.fd
);
587 in_state
.len
= blen
- ret
;
588 /* write incomplete, register write cb */
589 LOCAL
.write_cb
= write_data
;
590 /* deregister read_cb */
591 REMOTE
.read_cb
= NULL
;
594 #if defined(HAVE_LIBZ)
606 assert(in_state
.len
);
608 if(!(ret
= check_error(write(LOCAL
.fd
,
609 (in_state
.buf
+ in_state
.ofs
),
610 in_state
.len
), IO_WRITE
, LOCAL
.fd
)))
617 /* write completed, de-register write cb */
618 LOCAL
.write_cb
= NULL
;
619 /* reregister read_cb */
620 REMOTE
.read_cb
= read_net
;
628 check_error(int ret
, int io
, int fd
)
630 if(ret
> 0) /* no error */
632 if(ret
== 0) /* EOF */
634 send_error("%s failed on %s: EOF", IO_TYPE(io
), FD_NAME(fd
));
635 exit(1); /* NOTREACHED */
643 #if EAGAIN != EWOULDBLOCK
651 /* non-fatal error, 0 bytes read */
656 send_error("%s failed on %s: %s", IO_TYPE(io
), FD_NAME(fd
), strerror(errno
));
657 exit(1); /* NOTREACHED */