diff --git a/src/tnc.c b/src/tnc.c index 1d82632..10886c5 100644 --- a/src/tnc.c +++ b/src/tnc.c @@ -49,6 +49,112 @@ struct _patty_kiss_tnc { offset_o; }; +static int init_sock(patty_kiss_tnc *tnc, patty_kiss_tnc_info *info) { + struct sockaddr_un addr; + + if (strlen(info->device) > sizeof(addr.sun_path)) { + errno = EOVERFLOW; + + goto error_overflow; + } + + if ((tnc->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + goto error_socket; + } + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, info->device, sizeof(addr.sun_path)-1); + + if (connect(tnc->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + goto error_connect; + } + + return 0; + +error_connect: + (void)close(tnc->fd); + +error_socket: +error_overflow: + return -1; +} + +static int init_termios(patty_kiss_tnc *tnc, patty_kiss_tnc_info *info) { + if (tcgetattr(tnc->fd, &tnc->attrs) < 0) { + goto error_tcgetattr; + } + + memcpy(&tnc->attrs_old, &tnc->attrs, sizeof(tnc->attrs_old)); + + cfmakeraw(&tnc->attrs); + + if (info->flags & PATTY_KISS_TNC_BAUD) { + cfsetspeed(&tnc->attrs, info->baud); + } + + if (info->flags & PATTY_KISS_TNC_FLOW) { + switch (info->flow) { + case PATTY_KISS_TNC_FLOW_NONE: + break; + + case PATTY_KISS_TNC_FLOW_CRTSCTS: + tnc->attrs.c_cflag |= CRTSCTS; + + break; + + case PATTY_KISS_TNC_FLOW_XONXOFF: + tnc->attrs.c_iflag |= IXON | IXOFF; + + break; + } + } + + if (tcflush(tnc->fd, TCIOFLUSH) < 0) { + goto error_tcflush; + } + + if (tcsetattr(tnc->fd, TCSANOW, &tnc->attrs) < 0) { + goto error_tcsetattr; + } + + return 0; + +error_tcsetattr: +error_tcflush: +error_tcgetattr: + return -1; +} + +static int init_device(patty_kiss_tnc *tnc, patty_kiss_tnc_info *info) { + struct stat st; + + if (strcmp(info->device, "/dev/ptmx") == 0) { + int ptysub; + + if (openpty(&tnc->fd, &ptysub, NULL, NULL, NULL) < 0) { + goto error; + } + } else if (stat(info->device, &st) < 0) { + goto error; + } else if ((st.st_mode & S_IFMT) == S_IFSOCK) { + if (init_sock(tnc, info) < 0) { + goto error; + } + } else { + if ((tnc->fd = open(info->device, O_RDWR | O_NOCTTY)) < 0) { + goto error; + } + } + + tnc->opts |= TNC_CLOSE_ON_DESTROY; + + return 0; + +error: + return -1; +} + patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { patty_kiss_tnc *tnc; @@ -61,90 +167,21 @@ patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { } if (info->flags & PATTY_KISS_TNC_DEVICE) { - struct stat st; - - if (strcmp(info->device, "/dev/ptmx") == 0) { - int ptysub; - - if (openpty(&tnc->fd, &ptysub, NULL, NULL, NULL) < 0) { - goto error_open; - } - } else if (stat(info->device, &st) < 0) { - goto error_stat; - } else if ((st.st_mode & S_IFMT) == S_IFSOCK) { - struct sockaddr_un addr; - - if (strlen(info->device) > sizeof(addr.sun_path)) { - errno = EOVERFLOW; - - goto error_overflow; - } - - if ((tnc->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - goto error_socket; - } - - memset(&addr, '\0', sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, info->device, sizeof(addr.sun_path)-1); - - if (connect(tnc->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - goto error_connect; - } - } else { - if ((tnc->fd = open(info->device, O_RDWR | O_NOCTTY)) < 0) { - goto error_open; - } + if (init_device(tnc, info) < 0) { + goto error_init_device; } - - tnc->opts |= TNC_CLOSE_ON_DESTROY; } else if (info->flags & PATTY_KISS_TNC_FD) { tnc->fd = info->fd; } else { errno = EINVAL; - goto error_no_fd; + goto error_invalid; } - if (isatty(tnc->fd) && ptsname(tnc->fd) == NULL) { - if (tcgetattr(tnc->fd, &tnc->attrs) < 0) { - goto error_tcgetattr; + if (isatty(tnc->fd)) { + if (init_termios(tnc, info) < 0) { + goto error_init_termios; } - - memcpy(&tnc->attrs_old, &tnc->attrs, sizeof(tnc->attrs_old)); - - cfmakeraw(&tnc->attrs); - - if (info->flags & PATTY_KISS_TNC_BAUD) { - cfsetspeed(&tnc->attrs, info->baud); - } - - if (info->flags & PATTY_KISS_TNC_FLOW) { - switch (info->flow) { - case PATTY_KISS_TNC_FLOW_NONE: - break; - - case PATTY_KISS_TNC_FLOW_CRTSCTS: - tnc->attrs.c_cflag |= CRTSCTS; - - break; - - case PATTY_KISS_TNC_FLOW_XONXOFF: - tnc->attrs.c_iflag |= IXON | IXOFF; - - break; - } - } - - if (tcflush(tnc->fd, TCIOFLUSH) < 0) { - goto error_tcflush; - } - - if (tcsetattr(tnc->fd, TCSANOW, &tnc->attrs) < 0) { - goto error_tcsetattr; - } - } else { - errno = 0; } memset(&tnc->stats, '\0', sizeof(tnc->stats)); @@ -160,19 +197,13 @@ patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { return tnc; -error_tcflush: -error_tcsetattr: -error_tcgetattr: -error_connect: +error_init_termios: if (info->flags & PATTY_KISS_TNC_DEVICE) { (void)close(tnc->fd); } -error_open: -error_no_fd: -error_socket: -error_overflow: -error_stat: +error_init_device: +error_invalid: free(tnc->buf); error_malloc_buf: