/* * Copyright © 2013 Benjamin Franzke * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" uint32_t sock_get_ipv4_addr(int fd) { struct sockaddr_storage storage; struct sockaddr_in *own = (struct sockaddr_in *) &storage; socklen_t addrlen = sizeof(struct sockaddr_storage); assert(getsockname(fd, (struct sockaddr *) &storage, &addrlen) == 0); return own->sin_addr.s_addr; } static struct ifreq * sock_get_ifreq(int fd) { struct ifconf ifconf; static struct ifreq ifreqs[16]; struct sockaddr_in *sin; uint32_t own_ip; unsigned int i; own_ip = sock_get_ipv4_addr(fd); ifconf.ifc_len = sizeof ifreqs; ifconf.ifc_req = ifreqs; if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) { fprintf(stderr, "retrieving interfaces failed: %s\n", strerror(errno)); return NULL; } for (i = 0; i < ifconf.ifc_len/sizeof(ifreqs[0]); i++) { sin = (struct sockaddr_in *) &ifreqs[i].ifr_addr; if (sin->sin_addr.s_addr == own_ip) return &ifreqs[i]; } return NULL; } uint32_t sock_get_netmask(int fd) { struct ifreq *ifreq; ifreq = sock_get_ifreq(fd); if (ifreq == NULL) return 0; if (ioctl(fd, SIOCGIFNETMASK, ifreq) < 0) return 0; return ((struct sockaddr_in *) &ifreq->ifr_netmask)->sin_addr.s_addr; } uint8_t * sock_get_hwaddr(int fd) { struct ifreq *ifreq; ifreq = sock_get_ifreq(fd); if (ifreq == NULL) return NULL; if (ioctl(fd, SIOCGIFHWADDR, ifreq) < 0) return NULL; if (ifreq->ifr_hwaddr.sa_family != ARPHRD_ETHER) return NULL; return (uint8_t *) &ifreq->ifr_hwaddr.sa_data[0]; } uint32_t sock_get_peer_ipv4_addr(int fd) { struct sockaddr_storage storage; struct sockaddr_in *own = (struct sockaddr_in *) &storage; socklen_t addrlen = sizeof(struct sockaddr_storage); assert(getpeername(fd, (struct sockaddr *) &storage, &addrlen) == 0); return own->sin_addr.s_addr; } void set_ip(uint8_t *ipbuf, uint32_t ip) { ipbuf[0] = (ip & 0xFF); ipbuf[1] = (ip & 0xFF00) >> 8; ipbuf[2] = (ip & 0xFF0000) >> 16; ipbuf[3] = (ip & 0xFF000000) >> 24; } int bind_socket(int socktype, const char *host, const char *port) { struct addrinfo hints, *result, *rp; int reuseaddr = 1, s; int fd; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; hints.ai_socktype = socktype; printf("bind to host: %s, port: %s\n", host, port); s = getaddrinfo(host, port, &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) continue; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) == -1) continue; /*ip = ((struct sockaddr_in *)rp->ai_addr)->sin_addr.s_addr;*/ if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) break; close(fd); } freeaddrinfo(result); if (rp == NULL) { fprintf(stderr, "Failed to bind: %s\n", strerror(errno)); return -1; } if (socktype == SOCK_STREAM && listen(fd, 1) < 0) { fprintf(stderr, "Failed to listen: %s\n", strerror(errno)); close(fd); return -1; } return fd; } int connect_to_host(int socktype, const char *host, const char *port) { struct addrinfo hints, *result, *rp; int fd, s; memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; hints.ai_socktype = socktype; printf("connect to host: %s, port: %s\n", host, port); s = getaddrinfo(host, port, &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) continue; if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) break; close(fd); } freeaddrinfo(result); if (rp == NULL) { fprintf(stderr, "Failed to connect: %s\n", strerror(errno)); return -1; } return fd; } /* From systemd:src/shared/util.c */ ssize_t loop_read(int fd, void *buf, size_t nbytes, uint8_t do_poll) { uint8_t *p; ssize_t n = 0; assert(fd >= 0); assert(buf); p = buf; while (nbytes > 0) { ssize_t k; if ((k = read(fd, p, nbytes)) <= 0) { if (k < 0 && errno == EINTR) continue; if (k < 0 && errno == EAGAIN && do_poll) { struct pollfd pollfd; memset(&pollfd, 0, sizeof pollfd); pollfd.fd = fd; pollfd.events = POLLIN; if (poll(&pollfd, 1, -1) < 0) { if (errno == EINTR) continue; return n > 0 ? n : -errno; } if (pollfd.revents != POLLIN) return n > 0 ? n : -EIO; continue; } return n > 0 ? n : (k < 0 ? -errno : 0); } p += k; nbytes -= k; n += k; } return n; }