/* * Read data from the Telnet session to the raw input queue. */ static void telnet_read(ndesc_t *nd, telnet_t *tp) { int cc; if (!nq_full(tp->t_rawq)) { if (tp->t_flags & TF_URGENT) { if (at_mark(nd_fd(nd))) { tp->t_flags &= ~TF_URGENT; nd_enable(nd, ND_X); } } cc = nq_recv(tp->t_rawq, nd_fd(nd), &tp->t_rblen); if (cc == -1) { switch (errno) { case EWOULDBLOCK: case EINTR: case EPROTO: break; default: telnet_disconnect(tp); return; } } if (cc == 0) { telnet_disconnect(tp); return; } if ((tp->t_flags & TF_FLOWC) == 0) nd_enable(nd, ND_C); telnet_enabr(tp); if (!nq_full(tp->t_rawq)) return; } tp->t_flags |= TF_ENABR; nd_disable(nd, ND_R); }
/* * Accept a new Telnet connection. */ static void telnet_accept(void *vp) { ndesc_t *nd = vp; int addrlen, s; struct sockaddr_in addr; telnet_t *tp; void *ip; nd_enable(nd, ND_R); addrlen = sizeof (addr); s = accept(nd_fd(nd), (struct sockaddr *)&addr, &addrlen); if (s == -1) { switch (errno) { default: warning("telnet_accept: accept() errno = %d. ip: %s\n", errno, inet_ntoa(addr.sin_addr)); case EWOULDBLOCK: case EINTR: case EPROTO: return; } } enable_nbio(s); enable_oobinline(s); enable_nodelay(s); enable_lowdelay(s); enable_keepalive(s); set_rcvsize(s, TELNET_RCVBUF_SIZE); set_sndsize(s, TELNET_SNDBUF_SIZE); tp = telnet_alloc(); tp->t_nd = nd_attach(s, telnet_read, telnet_write, telnet_exception, NULL, telnet_shutdown, tp); ip = (void *)new_player(tp, &addr, addrlen); if (ip == NULL) { telnet_shutdown(tp->t_nd, tp); } else { telnet_attach(tp, ip); nd_enable(tp->t_nd, ND_R | ND_X); } }
static void udpsvc_process(udpsvc_t *svc) { int addrlen, cc; struct sockaddr_in addr; struct gdexception exception_frame; update_udp_av(); exception_frame.e_exception = exception; exception_frame.e_catch = 0; exception = &exception_frame; if (setjmp(exception_frame.e_context) == 0) { push_string(inet_ntoa(addr.sin_addr), STRING_MSTRING); push_string((char *)nq_rptr(svc->nq), STRING_MSTRING); (void)apply_master_ob(M_INCOMING_UDP, 2); } exception = exception->e_exception; addrlen = sizeof (addr); if (!read_datagram(svc)) { nd_enable(svc->nd, ND_R); svc->task = 0; return; } reschedule_task(svc->task); }
/* * Re-enable the output queue (if blocked). */ static void telnet_enabw(telnet_t *tp) { if (tp->t_flags & TF_ENABW) { tp->t_flags &= ~TF_ENABW; nd_enable(tp->t_nd, ND_W); } }
/* * Re-enable raw queue (if blocked). */ static void telnet_enabr(telnet_t *tp) { if (tp->t_flags & TF_ENABR) { tp->t_flags &= ~TF_ENABR; nd_enable(tp->t_nd, ND_R); } }
static void telnet_interactive(void *vp) { telnet_t *tp = vp; char *cp; if (!(tp->t_flags & TF_ATTACH)) { tp->task = NULL; telnet_shutdown(tp->t_nd, tp); return; } if (tp->t_flags & TF_DISCONNECT) { tp->t_flags &= ~TF_DISCONNECT; if (tp->t_ip) remove_interactive(tp->t_ip, 1); } if (!(tp->t_flags & TF_ATTACH)) { tp->task = NULL; telnet_shutdown(tp->t_nd, tp); return; } if (tp->t_flags & TF_OVFLOUTQ) { tp->task = NULL; return; } if (tp->t_flags & TF_INPUT) { tp->t_flags &= ~TF_INPUT; if (nq_full(tp->t_canq)) cp = ""; else cp = (char *)nq_rptr(tp->t_canq); interactive_input(tp->t_ip, cp); nq_init(tp->t_canq); } if (!(tp->t_flags & TF_ATTACH)) { tp->task = NULL; telnet_shutdown(tp->t_nd, tp); return; } tp->t_flags &= ~TF_GA; telnet_readbytes(tp->t_nd, tp); telnet_input(tp); if (!(tp->t_flags & TF_ATTACH)) { tp->task = NULL; telnet_shutdown(tp->t_nd, tp); return; } if (tp->t_flags & (TF_INPUT|TF_DISCONNECT)) { reschedule_task(tp->task); return; } tp->task = NULL; nd_enable(tp->t_nd, ND_R); }
/* * Disassociate a Telnet control block from an interactive object. */ void telnet_detach(telnet_t *tp) { if ((tp->t_flags & TF_ATTACH) == 0) return; tp->t_flags ^= TF_ATTACH; tp->t_ip = NULL; nd_enable(tp->t_nd, ND_C); }
/* * Write data from the output queue to the Telnet session. */ static void telnet_write(ndesc_t *nd, telnet_t *tp) { if (!nq_empty(tp->t_outq)) { if (nq_send(tp->t_outq, nd_fd(nd), &tp->t_sblen) == -1) { switch (errno) { case EWOULDBLOCK: case EINTR: case EPROTO: break; default: telnet_disconnect(tp); return; } } } if (tp->t_flags & TF_OVFLOUTQ) { if (nq_len(tp->t_outq) < TELNET_OUTQ_LOWAT) { tp->t_flags &= ~TF_OVFLOUTQ; nq_puts(tp->t_outq, (u_char *)"*** Truncated. ***\r\n"); } } if (tp->t_flags & TF_FLOWC) { if (nq_len(tp->t_outq) < TELNET_OUTQ_HIWAT) { tp->t_flags &= ~TF_FLOWC; nd_enable(nd, ND_C); } } if (!nq_empty(tp->t_outq)) return; nq_init(tp->t_outq); tp->t_flags |= TF_ENABW; nd_disable(nd, ND_W); }
/* * Initialize the UDP Manager. */ udpsvc_t * udpsvc_init(int port) { int s; struct sockaddr_in addr; struct udpsvc_t *svc; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) fatal("udp_init: socket() error = %d.\n", errno); enable_reuseaddr(s); memset(&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons((u_short)port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(s, (struct sockaddr *)&addr, sizeof (addr)) == -1) { if (errno == EADDRINUSE) { (void)fprintf(stderr, "UDP Socket already bound!\n"); debug_message("UDP Socket already bound!\n"); (void)close(s); return 0; } else { fatal("udp_init: bind() error = %d.\n", errno); } } enable_nbio(s); svc = xalloc(sizeof(*udpsvc)); svc->nq = nq_alloc(UDPSVC_RAWQ_SIZE); svc->nd = nd_attach(s, udpsvc_read, NULL, NULL, NULL, udpsvc_shutdown, svc); nd_enable(svc->nd, ND_R); return svc; }
/* * Initialize the Telnet server. */ void telnet_init(u_short port) { int s; struct sockaddr_in addr; ndesc_t *nd; s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == -1) fatal("telnet_init: socket() error = %d.\n", errno); enable_reuseaddr(s); memset(&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(s, (struct sockaddr *)&addr, sizeof (addr)) == -1) { if (errno == EADDRINUSE) { (void)fprintf(stderr, "Socket already bound!\n"); debug_message("Socket already bound!\n"); exit(errno); } else { fatal("telnet_init: bind() error = %d.\n", errno); } } if (listen(s, 5) == -1) fatal("telnet_init: listen() error = %d.\n", errno); enable_nbio(s); nd = nd_attach(s, telnet_ready, NULL, NULL, NULL, telnet_shutdown, NULL); nd_enable(nd, ND_R); }
/* * Re-enable the output queue (if blocked). */ static void telnet_enabw(telnet_t *tp) { nd_enable(tp->t_nd, ND_W); }