/* * (C) 2009 by Pablo Neira Ayuso * * 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 2 of the License, or * (at your option) any later version. */ #include "udp.h" #include #include #include #include #include #include #include #include #include struct udp_sock *udp_server_create(struct udp_conf *conf) { int yes = 1; struct udp_sock *m; socklen_t socklen = sizeof(int); m = calloc(sizeof(struct udp_sock), 1); if (m == NULL) return NULL; switch(conf->ipproto) { case AF_INET: m->addr.ipv4.sin_family = AF_INET; m->addr.ipv4.sin_port = htons(conf->port); m->addr.ipv4.sin_addr = conf->server.ipv4.inet_addr; m->sockaddr_len = sizeof(struct sockaddr_in); break; case AF_INET6: m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); m->addr.ipv6.sin6_addr = conf->server.ipv6.inet_addr6; m->addr.ipv6.sin6_scope_id = conf->server.ipv6.scope_id; m->sockaddr_len = sizeof(struct sockaddr_in6); break; } m->fd = socket(conf->ipproto, SOCK_DGRAM, 0); if (m->fd == -1) { free(m); return NULL; } if (setsockopt(m->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { close(m->fd); free(m); return NULL; } #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE 33 #endif if (conf->rcvbuf && setsockopt(m->fd, SOL_SOCKET, SO_RCVBUFFORCE, &conf->rcvbuf, sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { close(m->fd); free(m); return NULL; } } getsockopt(m->fd, SOL_SOCKET, SO_RCVBUF, &conf->rcvbuf, &socklen); if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) { close(m->fd); free(m); return NULL; } return m; } void udp_server_destroy(struct udp_sock *m) { close(m->fd); free(m); } struct udp_sock *udp_client_create(struct udp_conf *conf) { int ret = 0; struct udp_sock *m; socklen_t socklen = sizeof(int); m = calloc(sizeof(struct udp_sock), 1); if (m == NULL) return NULL; m->fd = socket(conf->ipproto, SOCK_DGRAM, 0); if (m->fd == -1) { free(m); return NULL; } if (setsockopt(m->fd, SOL_SOCKET, SO_NO_CHECK, &conf->checksum, sizeof(int)) == -1) { close(m->fd); free(m); return NULL; } #ifndef SO_SNDBUFFORCE #define SO_SNDBUFFORCE 32 #endif if (conf->sndbuf && setsockopt(m->fd, SOL_SOCKET, SO_SNDBUFFORCE, &conf->sndbuf, sizeof(int)) == -1) { /* not supported in linux kernel < 2.6.14 */ if (errno != ENOPROTOOPT) { close(m->fd); free(m); return NULL; } } getsockopt(m->fd, SOL_SOCKET, SO_SNDBUF, &conf->sndbuf, &socklen); switch(conf->ipproto) { case AF_INET: m->addr.ipv4.sin_family = AF_INET; m->addr.ipv4.sin_port = htons(conf->port); m->addr.ipv4.sin_addr = conf->client.inet_addr; m->sockaddr_len = sizeof(struct sockaddr_in); break; case AF_INET6: m->addr.ipv6.sin6_family = AF_INET6; m->addr.ipv6.sin6_port = htons(conf->port); memcpy(&m->addr.ipv6.sin6_addr, &conf->client.inet_addr6, sizeof(struct in6_addr)); m->sockaddr_len = sizeof(struct sockaddr_in6); break; default: ret = -1; break; } if (ret == -1) { close(m->fd); free(m); m = NULL; } return m; } void udp_client_destroy(struct udp_sock *m) { close(m->fd); free(m); } ssize_t udp_send(struct udp_sock *m, const void *data, int size) { ssize_t ret; ret = sendto(m->fd, data, size, 0, (struct sockaddr *) &m->addr, m->sockaddr_len); if (ret == -1) { m->stats.error++; return ret; } m->stats.bytes += ret; m->stats.messages++; return ret; } ssize_t udp_recv(struct udp_sock *m, void *data, int size) { ssize_t ret; socklen_t sin_size = sizeof(struct sockaddr_in); ret = recvfrom(m->fd, data, size, 0, (struct sockaddr *)&m->addr, &sin_size); if (ret == -1) { if (errno != EAGAIN) m->stats.error++; return ret; } m->stats.bytes += ret; m->stats.messages++; return ret; } int udp_get_fd(struct udp_sock *m) { return m->fd; } int udp_isset(struct udp_sock *m, fd_set *readfds) { return FD_ISSET(m->fd, readfds); } int udp_snprintf_stats(char *buf, size_t buflen, char *ifname, struct udp_stats *s, struct udp_stats *r) { size_t size; size = snprintf(buf, buflen, "UDP traffic (active device=%s):\n" "%20llu Bytes sent " "%20llu Bytes recv\n" "%20llu Pckts sent " "%20llu Pckts recv\n" "%20llu Error send " "%20llu Error recv\n\n", ifname, (unsigned long long)s->bytes, (unsigned long long)r->bytes, (unsigned long long)s->messages, (unsigned long long)r->messages, (unsigned long long)s->error, (unsigned long long)r->error); return size; } int udp_snprintf_stats2(char *buf, size_t buflen, const char *ifname, const char *status, int active, struct udp_stats *s, struct udp_stats *r) { size_t size; size = snprintf(buf, buflen, "UDP traffic device=%s status=%s role=%s:\n" "%20llu Bytes sent " "%20llu Bytes recv\n" "%20llu Pckts sent " "%20llu Pckts recv\n" "%20llu Error send " "%20llu Error recv\n\n", ifname, status, active ? "ACTIVE" : "BACKUP", (unsigned long long)s->bytes, (unsigned long long)r->bytes, (unsigned long long)s->messages, (unsigned long long)r->messages, (unsigned long long)s->error, (unsigned long long)r->error); return size; }