/* * Copyright 2002 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Niels Provos. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include struct io_filter *multi; #define DIEMESSAGE "DEAD.\n" #define ENTERMESSAGE "ENTER.\n" #define NAMEMESSAGE "Enter name: " int filter_append(void *arg, struct io_filter *filter, struct io_buffer *buf, int flags) { struct io_buffer *mybuf = &filter->io_buf; char *name = arg; int len; if (buf->ready == 0 && !(flags & IOFLAG_FLUSH)) return (IOFILT_NEEDMORE); if (flags & IOFLAG_FLUSH) len = strlen(name) + strlen(DIEMESSAGE); else len = buf->ready + strlen(name); if (io_buffer_extend(mybuf, len + 1) == -1) return (IOFILT_ERROR); if (flags & IOFLAG_FLUSH) { strcpy(mybuf->data, name); memcpy(mybuf->data + strlen(name), DIEMESSAGE, strlen(DIEMESSAGE)); } else { strcpy(mybuf->data, name); memcpy(mybuf->data + strlen(name), buf->data, buf->ready); } mybuf->ready = mybuf->off = len; return (IOFILT_DONE); } int filter_filter(void *arg, struct io_filter *filter, struct io_buffer *buf, int flags) { char *name = arg; struct io_buffer *mybuf = &filter->io_buf; if (buf->ready >= strlen(name) && !strncmp(buf->data, name, strlen(name))) { mybuf->ready = 0; return (IOFILT_NEEDMORE); } if (io_buffer_append(mybuf, buf) == -1) return (IOFILT_ERROR); mybuf->ready = mybuf->off; return (IOFILT_DONE); } int filter_response(void *arg, struct io_filter *filter, struct io_buffer *buf, int flags) { struct io_duplex *dplx = arg; struct io_filter *first, *second; int len; char prompt[32]; char enter[128]; len = sizeof(prompt) - 4; if (buf->ready - 1 < len) len = buf->ready - 1; while (len > 0) { if (buf->data[len] != '\r' && buf->data[len] != '\n') { len++; break; } len--; } if (len == 0) return (IOFILT_ERROR); prompt[0] = '<'; memcpy(prompt + 1, buf->data, len); strcpy(prompt + len + 1, "> "); first = io_new_filter(filter_append, strdup(prompt)); second = io_new_filter(filter_filter, strdup(prompt)); io_attach(dplx->io_src, first); io_attach(first, multi); io_attach(multi, second); io_attach(second, dplx->io_dst); io_terminate((struct io_obj *)filter, IORES_END); snprintf(enter, sizeof(enter), "%sENTER.\n", prompt); io_data_write((struct io_obj *)multi, enter, strlen(enter)); return (IOFILT_NEEDMORE); } int client_new(int fd) { struct io_duplex *dplx; struct io_filter *filt; if ((dplx = io_new_socket(fd)) == NULL) { close (fd); return (-1); } io_data_write(dplx->io_dst, NAMEMESSAGE, strlen(NAMEMESSAGE)); filt = io_new_filter(filter_response, dplx); io_attach(dplx->io_src, filt); return (0); } int filter_printfd(void *arg, struct io_filter *filter, struct io_buffer *buf, int flags) { struct io_buffer *mybuf = &filter->io_buf; int newfd; if (io_buffer_extend(mybuf, 256) == -1) return (IOFILT_ERROR); if (buf->ready < sizeof (int)) return (IOFILT_NEEDMORE); newfd = *(int *)buf->data; snprintf(mybuf->data, 256, "New connection on fd %d\n", newfd); mybuf->ready = mybuf->off = strlen(mybuf->data); client_new(newfd); return (IOFILT_DONE); } int filter_multiplex(void *arg, struct io_filter *filter, struct io_buffer *buf, int flags) { struct io_buffer *mybuf = &filter->io_buf; if (io_buffer_append(mybuf, buf) == -1) return (IOFILT_ERROR); mybuf->ready = mybuf->off; return (IOFILT_DONE); } int main(int argc, char **argv) { struct io_obj *src, *dst; struct io_filter *filt, *dummy; event_init(); dst = io_new_sink(fileno(stdout)); multi = io_new_filter(filter_multiplex, NULL); dummy = io_new_filter(NULL, NULL); /* The multiplexer has to be a persistent object, it * must not die when one of its sources dies */ io_attach(dummy, multi); /* Print out all chatter */ io_attach(multi, dst); src = io_new_listener("0.0.0.0", 8080); filt = io_new_filter(filter_printfd, NULL); io_attach(src, filt); /* Print out new connections */ io_attach(filt, dst); event_dispatch(); exit(0); }