#include #include #include #include #include #include #include #include "tcp.h" int tcp_verbose; /* ------------------------------------------------------------------ */ static char *strfamily(int family) { switch (family) { case PF_INET6: return "ipv6"; case PF_INET: return "ipv4"; case PF_UNIX: return "unix"; } return "????"; } int tcp_connect(struct addrinfo *ai, char *addr, char *port, char *host, char *serv) { struct addrinfo *res,*e; struct addrinfo *lres, ask; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; char uhost[INET6_ADDRSTRLEN+1]; char userv[33]; int sock,rc,opt=1; /* lookup peer */ ai->ai_flags = AI_CANONNAME; if (0 != (rc = getaddrinfo(host, serv, ai, &res))) { if (tcp_verbose) fprintf(stderr,"getaddrinfo (peer): %s\n", gai_strerror(rc)); return -1; } for (e = res; e != NULL; e = e->ai_next) { if (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uhost,INET6_ADDRSTRLEN,userv,32, NI_NUMERICHOST | NI_NUMERICSERV)) { if (tcp_verbose) fprintf(stderr,"getnameinfo (peer): oops\n"); continue; } if (-1 == (sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol))) { if (tcp_verbose) fprintf(stderr,"socket (%s): %s\n", strfamily(e->ai_family),strerror(errno)); continue; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); if (NULL != addr || NULL != port) { /* bind local port */ memset(&ask,0,sizeof(ask)); ask.ai_flags = AI_PASSIVE; ask.ai_family = e->ai_family; ask.ai_socktype = e->ai_socktype; if (0 != (rc = getaddrinfo(addr, port, &ask, &lres))) { if (tcp_verbose) fprintf(stderr,"getaddrinfo (local): %s\n", gai_strerror(rc)); continue; } if (0 != getnameinfo((struct sockaddr*)lres->ai_addr, lres->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV)) { if (tcp_verbose) fprintf(stderr,"getnameinfo (local): oops\n"); continue; } if (-1 == bind(sock, lres->ai_addr, lres->ai_addrlen)) { if (tcp_verbose) fprintf(stderr,"%s [%s] %s bind: %s\n", strfamily(lres->ai_family),uaddr,uport, strerror(errno)); continue; } } /* connect to peer */ if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) { if (tcp_verbose) fprintf(stderr,"%s %s [%s] %s connect: %s\n", strfamily(e->ai_family),e->ai_canonname,uhost,userv, strerror(errno)); close(sock); continue; } if (tcp_verbose) fprintf(stderr,"%s %s [%s] %s open\n", strfamily(e->ai_family),e->ai_canonname,uhost,userv); fcntl(sock,F_SETFL,O_NONBLOCK); return sock; } return -1; } int tcp_listen(struct addrinfo *ai, char *addr, char *port) { struct addrinfo *res,*e; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten,rc,opt=1; /* lookup */ ai->ai_flags = AI_PASSIVE; if (0 != (rc = getaddrinfo(addr, port, ai, &res))) { if (tcp_verbose) fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rc)); exit(1); } /* create socket + bind */ for (e = res; e != NULL; e = e->ai_next) { getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); if (-1 == (slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol))) { if (tcp_verbose) fprintf(stderr,"socket (%s): %s\n", strfamily(e->ai_family),strerror(errno)); continue; } opt = 1; setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); if (-1 == bind(slisten, e->ai_addr, e->ai_addrlen)) { if (tcp_verbose) fprintf(stderr,"%s [%s] %s bind: %s\n", strfamily(e->ai_family),uaddr,uport, strerror(errno)); continue; } listen(slisten,1); break; } if (NULL == e) return -1; /* wait for a incoming connection */ if (tcp_verbose) fprintf(stderr,"listen on %s [%s] %s ...\n", strfamily(e->ai_family),uaddr,uport); fcntl(slisten,F_SETFL,O_NONBLOCK); return slisten; } int unix_connect(char *path) { struct sockaddr_un un; char *opts; int sock; if (-1 == (sock = socket(PF_UNIX, SOCK_STREAM, 0))) { perror("socket"); return -1; } opts = strchr(path,','); if (opts) { *opts = 0; opts++; } un.sun_family = AF_UNIX; snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); if (-1 == connect(sock, (struct sockaddr*) &un, sizeof(un))) { fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); return -1; } return sock; } int cdev_connect(char *path) { struct stat st; char *opts; int fd; opts = strchr(path,','); if (opts) { *opts = 0; opts++; } fd = open(path, O_RDWR); if (fd == -1) { fprintf(stderr, "open %s: %s\n", path, strerror(errno)); return -1; } fstat(fd, &st); if (!S_ISCHR(st.st_mode)) { fprintf(stderr, "not a character device: %s\n", path); close(fd); return -1; } return fd; } int pipe_connect(char *path) { struct stat st; char *opts; int fd; opts = strchr(path,','); if (opts) { *opts = 0; opts++; } fd = open(path, O_RDWR); if (fd == -1) { mkfifo(path, 0666); fd = open(path, O_RDWR); } if (fd == -1) { fprintf(stderr, "open %s: %s\n", path, strerror(errno)); return -1; } fstat(fd, &st); if (!S_ISFIFO(st.st_mode)) { fprintf(stderr, "not a pipe: %s\n", path); close(fd); return -1; } return fd; }