📄 dataxfer.c
字号:
/* EINTR means we were interrupted, just retry by returning. */ return; } if (errno == EAGAIN) { /* This was due to O_NONBLOCK, we need to shut off the reader and start the writer monitor. */ sel_set_fd_read_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_DISABLED); sel_set_fd_write_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_ENABLED); port->tcp_to_dev_state = PORT_WAITING_OUTPUT_CLEAR; } else { /* Some other bad error. */ syslog(LOG_ERR, "The dev write for port %s had error: %m", port->portname); shutdown_port(port, "dev write error"); } } else { port->dev_bytes_sent += write_count; port->tcp_to_dev_buf_count -= write_count; if (port->tcp_to_dev_buf_count != 0) { /* We didn't write all the data, shut off the reader and start the write monitor. */ port->tcp_to_dev_buf_start += write_count; sel_set_fd_read_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_DISABLED); sel_set_fd_write_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_ENABLED); port->tcp_to_dev_state = PORT_WAITING_OUTPUT_CLEAR; } } reset_timer(port);}/* The TCP port has room to write some data. This is only activated if a write fails to complete, it is deactivated as soon as writing is available again. */static voidhandle_tcp_fd_write(int fd, void *data){ port_info_t *port = (port_info_t *) data; telnet_data_t *td = &port->tn_data; int write_count; if (td->out_telnet_cmd_size > 0) { write_count = write(port->tcpfd, &(td->out_telnet_cmd[0]), td->out_telnet_cmd_size); if (write_count == -1) { if (errno == EINTR) { /* EINTR means we were interrupted, just retry by returning. */ return; } if (errno == EAGAIN) { /* This again was due to O_NONBLOCK, just ignore it. */ } else if (errno == EPIPE) { shutdown_port(port, "EPIPE"); } else { /* Some other bad error. */ syslog(LOG_ERR, "The tcp write for port %s had error: %m", port->portname); shutdown_port(port, "tcp write error"); } } else { int i, j; /* Copy the remaining data. */ for (j=0, i=write_count; i<td->out_telnet_cmd_size; i++, j++) td->out_telnet_cmd[j] = td->out_telnet_cmd[i]; td->out_telnet_cmd_size -= write_count; if (td->out_telnet_cmd_size != 0) /* If we have more telnet command data to send, don't send any real data. */ return; } } write_count = write(port->tcpfd, &(port->dev_to_tcp_buf[port->dev_to_tcp_buf_start]), port->dev_to_tcp_buf_count); if (write_count == -1) { if (errno == EINTR) { /* EINTR means we were interrupted, just retry by returning. */ return; } if (errno == EAGAIN) { /* This again was due to O_NONBLOCK, just ignore it. */ } else if (errno == EPIPE) { shutdown_port(port, "EPIPE"); } else { /* Some other bad error. */ syslog(LOG_ERR, "The tcp write for port %s had error: %m", port->portname); shutdown_port(port, "tcp write error"); } } else { port->tcp_bytes_sent += write_count; port->dev_to_tcp_buf_count -= write_count; if (port->dev_to_tcp_buf_count != 0) { /* We didn't write all the data, continue writing. */ port->dev_to_tcp_buf_start += write_count; } else { /* We are done writing, turn the reader back on. */ sel_set_fd_read_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_ENABLED); sel_set_fd_write_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_DISABLED); port->dev_to_tcp_state = PORT_WAITING_INPUT; } } reset_timer(port);}/* Handle an exception from the TCP port. */static voidhandle_tcp_fd_except(int fd, void *data){ port_info_t *port = (port_info_t *) data; syslog(LOG_ERR, "Select exception on port %s", port->portname); shutdown_port(port, "tcp fd exception");}static voidtelnet_cmd_handler(void *cb_data, unsigned char cmd){ port_info_t *port = cb_data; if (cmd == TN_BREAK) tcsendbreak(port->devfd, 0);}/* Called when the telnet code has output ready. */static voidtelnet_output_ready(void *cb_data){ port_info_t *port = cb_data; sel_set_fd_read_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_DISABLED); sel_set_fd_write_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_ENABLED);}/* Checks to see if some other port has the same device in use. */static intis_device_already_inuse(port_info_t *check_port){ port_info_t *port = ports; while (port != NULL) { if (port != check_port) { if ((strcmp(port->devname, check_port->devname) == 0) && (port->tcp_to_dev_state != PORT_UNCONNECTED)) { return 1; } } port = port->next; } return 0;}static voidadd_port_tcp_char(port_info_t *port, char c){ int pos = port->dev_to_tcp_buf_start + port->dev_to_tcp_buf_count; if (pos >= PORT_BUFSIZE) return; port->dev_to_tcp_buf[pos] = c; port->dev_to_tcp_buf_count++;}static intfrom_hex_digit(char c){ if ((c >= '0') && (c <= '9')) return c - '0'; if ((c >= 'A') && (c <= 'F')) return c = 'A' + 10; if ((c >= 'a') && (c <= 'f')) return c = 'a' + 10; return 0;}static voiddisplay_banner(port_info_t *port){ char val; char *s; char *t; if (!port->banner) return; s = port->banner; while (*s) { if (*s == '\\') { s++; if (!*s) return; switch (*s) { /* Standard "C" characters. */ case 'a': add_port_tcp_char(port, 7); break; case 'b': add_port_tcp_char(port, 8); break; case 'f': add_port_tcp_char(port, 12); break; case 'n': add_port_tcp_char(port, 10); break; case 'r': add_port_tcp_char(port, 13); break; case 't': add_port_tcp_char(port, 9); break; case 'v': add_port_tcp_char(port, 11); break; case '\\': add_port_tcp_char(port, '\\'); break; case '?': add_port_tcp_char(port, '?'); break; case '\'': add_port_tcp_char(port, '\''); break; case '"': add_port_tcp_char(port, '"'); break; case 'd': /* ser2net device name. */ for (t=port->devname; *t; t++) add_port_tcp_char(port, *t); break; case 'p': /* ser2net TCP port. */ for (t=port->portname; *t; t++) add_port_tcp_char(port, *t); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* Octal digit */ val = (*s) - '0'; s++; if (!*s) { add_port_tcp_char(port, val); return; } if (!isdigit(*s)) { continue; } val = (val * 8) + (*s) - '0'; s++; if (!*s) { add_port_tcp_char(port, val); return; } if (!isdigit(*s)) { continue; } val = (val * 8) + (*s) - '0'; break; case 'x': /* Hex digit */ s++; if (!*s) return; if (!isxdigit(*s)) continue; val = from_hex_digit(*s); s++; if (!*s) { add_port_tcp_char(port, val); return; } if (!isdigit(*s)) continue; val = (val * 16) + from_hex_digit(*s); break; default: add_port_tcp_char(port, *s); } } else add_port_tcp_char(port, *s); s++; }}/* A connection request has come in on a port. */static voidhandle_accept_port_read(int fd, void *data){ port_info_t *port = (port_info_t *) data; socklen_t len; char *err = NULL; int options; struct timeval then; if (port->tcp_to_dev_state != PORT_UNCONNECTED) { err = "Port already in use\n\r"; } else if (is_device_already_inuse(port)) { err = "Port's device already in use\n\r"; } if (err != NULL) { struct sockaddr_in dummy_sockaddr; socklen_t len = sizeof(dummy_sockaddr); int new_fd = accept(fd, (struct sockaddr *) &dummy_sockaddr, &len); if (new_fd != -1) { write(new_fd, err, strlen(err)); close(new_fd); } return; } len = sizeof(port->remote); port->tcpfd = accept(fd, (struct sockaddr *) &(port->remote), &len); if (port->tcpfd == -1) { syslog(LOG_ERR, "Could not accept on port %s: %m", port->portname); return; } if (fcntl(port->tcpfd, F_SETFL, O_NONBLOCK) == -1) { close(port->tcpfd); syslog(LOG_ERR, "Could not fcntl the tcp port %s: %m", port->portname); return; }#ifdef HAVE_TCPD_H { struct request_info req; request_init(&req, RQ_DAEMON, progname, RQ_FILE, port->tcpfd, NULL); fromhost(&req); if (!hosts_access(&req)) { char *err = "Access denied\n\r"; write(port->tcpfd, err, strlen(err)); close(port->tcpfd); return; } }#endif /* HAVE_TCPD_H */#ifdef USE_UUCP_LOCKING { int rv; rv = uucp_mk_lock(port->devname); if (rv > 0 ) { char *err; err = "Port already in use by another process\n\r"; write(port->tcpfd, err, strlen(err)); close(port->tcpfd); return; } else if (rv < 0) { char *err; err = "Error creating port lock file\n\r"; write(port->tcpfd, err, strlen(err)); close(port->tcpfd); return; } }#endif /* USE_UUCP_LOCKING */ /* Oct 05 2001 druzus: NOCTTY - don't make device control tty for our process */ options = O_NONBLOCK | O_NOCTTY; if (port->enabled == PORT_RAWLP) { options |= O_WRONLY; } else { options |= O_RDWR; } port->devfd = open(port->devname, options); if (port->devfd == -1) { close(port->tcpfd); syslog(LOG_ERR, "Could not open device %s for port %s: %m", port->devname, port->portname); return; } if (port->enabled != PORT_RAWLP && tcsetattr(port->devfd, TCSANOW, &(port->termctl)) == -1) { close(port->tcpfd); close(port->devfd); syslog(LOG_ERR, "Could not set up device %s for port %s: %m", port->devname, port->portname); return; } /* Turn of BREAK. */ if (ioctl(port->devfd, TIOCCBRK) == -1) { close(port->tcpfd); close(port->devfd); syslog(LOG_ERR, "Could not turn off break for device %s port %s: %m", port->devname, port->portname); return; } port->is_2217 = 0; port->break_set = 0; sel_set_fd_handlers(ser2net_sel, port->devfd, port, port->enabled == PORT_RAWLP ? NULL : handle_dev_fd_read, handle_dev_fd_write, handle_dev_fd_except); sel_set_fd_read_handler(ser2net_sel, port->devfd, ((port->enabled == PORT_RAWLP) ? SEL_FD_HANDLER_DISABLED : SEL_FD_HANDLER_ENABLED)); sel_set_fd_except_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_ENABLED); port->dev_to_tcp_state = PORT_WAITING_INPUT; sel_set_fd_handlers(ser2net_sel, port->tcpfd, port, handle_tcp_fd_read, handle_tcp_fd_write, handle_tcp_fd_except); sel_set_fd_read_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_ENABLED); sel_set_fd_except_handler(ser2net_sel, port->tcpfd, SEL_FD_HANDLER_ENABLED); port->tcp_to_dev_state = PORT_WAITING_INPUT; if (port->enabled == PORT_TELNET) { telnet_init(&port->tn_data, port, telnet_output_ready, telnet_cmd_handler, telnet_cmds, telnet_init_seq, sizeof(telnet_init_seq)); } else { sel_set_fd_read_handler(ser2net_sel, port->devfd, SEL_FD_HANDLER_ENABLED); } display_banner(port); gettimeofday(&then, NULL); then.tv_sec += 1; sel_start_timer(port->timer, &then); reset_timer(port);}/* Start monitoring for connections on a specific port. */static char *startup_port(port_info_t *port){ int optval = 1; port->acceptfd = socket(PF_INET, SOCK_STREAM, 0); if (port->acceptfd == -1) { return "Unable to create TCP socket"; } if (fcntl(port->acceptfd, F_SETFL, O_NONBLOCK) == -1) { close(port->acceptfd); return "Could not fcntl the accept port"; } if (setsockopt(port->acceptfd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(optval)) == -1) { close(port->acceptfd); return "Unable to set reuseaddress on socket"; } if (bind(port->acceptfd, (struct sockaddr *) &port->tcpport, sizeof(port->tcpport)) == -1) { close(port->acceptfd); return "Unable to bind TCP port"; } if (listen(port->acceptfd, 1) != 0) { close(port->acceptfd); return "Unable to listen to TCP port"; } sel_set_fd_handlers(ser2net_sel, port->acceptfd, port, handle_accept_port_read, NULL, NULL); sel_set_fd_read_handler(ser2net_sel, port->acceptfd, SEL_FD_HANDLER_ENABLED); return NULL;}char *change_port_state(port_info_t *port, int state){ char *rv = NULL; if (port->enabled == state) { return rv; } if (state == PORT_DISABLED) { if (port->acceptfd != -1) { sel_set_fd_read_handler(ser2net_sel, port->acceptfd, SEL_FD_HANDLER_DISABLED); sel_clear_fd_handlers(ser2net_sel, port->acceptfd); close(port->acceptfd); port->acceptfd = -1; } } else if (port->enabled == PORT_DISABLED) { rv = startup_port(port); } port->enabled = state; return rv;}static voidfree_port(port_info_t *port){ sel_free_timer(port->timer); change_port_state(port, PORT_DISABLED); if (port->portname != NULL) { free(port->portname); } if (port->devname != NULL) { free(port->devname); } if (port->new_config != NULL) { free_port(port->new_config); } free(port);}static voidshutdown_port(port_info_t *port, char *reason){ sel_stop_timer(port->timer); sel_clear_fd_handlers(ser2net_sel, port->devfd); sel_clear_fd_handlers(ser2net_sel, port->tcpfd); close(port->tcpfd); /* To avoid blocking on close if we have written bytes and are in flow-control, we flush the output queue. */ tcflush(port->devfd, TCOFLUSH); close(port->devfd);#ifdef USE_UUCP_LOCKING uucp_rm_lock(port->devname);#endif /* USE_UUCP_LOCKING */ port->tcp_to_dev_state = PORT_UNCONNECTED; port->tcp_to_dev_buf_start = 0; port->tcp_to_dev_buf_count = 0; port->tcp_bytes_received = 0; port->tcp_bytes_sent = 0; port->dev_to_tcp_state = PORT_UNCONNECTED; port->dev_to_tcp_buf_start = 0; port->dev_to_tcp_buf_count = 0; port->dev_bytes_received = 0; port->dev_bytes_sent = 0; /* If the port has been disabled, then delete it. Check this before the new config so the port will be deleted properly and not reconfigured on a reconfig. */ if (port->config_num == -1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -