/*************************************************************************** * Copyright (C) 04/2006 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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. * * * * 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, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "socket.h" #include "logging.h" Socket::Socket() { if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) LogSystem::log(LOG_CRIT, "Socket: socket()"); strcpy(devname, "any"); memset(&addr, 0, sizeof(addr)); } Socket::~Socket() { close(fd); } bool Socket::checkDeviceFlags(const char* name) { struct ifreq ifr; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) { LogSystem::log(LOG_WARN, "Socket: ioctl(SIOCGIFFLAGS) %s", name); return false; } if (!(ifr.ifr_flags & IFF_UP) || (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) return false; return true; } bool Socket::bindToDevice(const char* name) { struct ifreq ifr; strncpy(devname, name, sizeof(devname)); strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFADDR, &ifr) != 0) { LogSystem::log(LOG_WARN, "Socket: ioctl(SIOCGIFADDR) %s", devname); return false; } memcpy(&addr, &ifr.ifr_addr, sizeof(addr)); if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, devname, sizeof(devname)) < 0) { LogSystem::log(LOG_NOTICE, "Socket: setsockopt(SO_BINDTODEVICE) %s", devname); // no failure! //return false; } return true; } bool Socket::bindToAddress(struct sockaddr_in* tmp) { int i = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { LogSystem::log(LOG_NOTICE, "Socket: setsockopt(SO_REUSEADDR) %s", devname); return false; } memcpy(&addr, tmp, sizeof(addr)); if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { LogSystem::log(LOG_WARN, "Socket: bind(%s:%d)", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); return false; } return true; } bool Socket::setBroadcast(int flag) { if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag))) { LogSystem::log(LOG_WARN, "Socket: setsockopt(SO_BROADCAST) %s", devname); return false; } return true; } Socket* Socket::createSocket(struct sockaddr_in* addr) { Socket* sock = new Socket(); if (!sock->bindToAddress(addr)) { delete sock; return NULL; } sock->setBroadcast(1); return sock; } Socket* Socket::createSocket(const char* name, int port) { Socket* sock = new Socket(); if (!sock->checkDeviceFlags(name)) { delete sock; return NULL; } if (!sock->bindToDevice(name)) { delete sock; return NULL; } sock->addr.sin_port = htons(port); if (!sock->bindToAddress(&sock->addr)) { delete sock; return NULL; } sock->setBroadcast(1); return sock; } int Socket::show(char* buf, int size) { return snprintf(buf, size, "%s (%s:%d) ", devname, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } int Socket::getRecvSize() { int retval; if (ioctl(fd, FIONREAD, &retval) == -1) { LogSystem::log(LOG_ERROR, "Socket::getRecvSize()"); return 0; } return retval; } int Socket::getFD() { return fd; } int Socket::sendto(NetPkt* pkt, struct sockaddr_in* dst) { if (!dst) dst = &pkt->addr; if (::sendto(fd, pkt->data, pkt->size, 0, (struct sockaddr *)dst, sizeof(*dst)) < 0) LogSystem::log(LOG_WARN, "Socket::sendto()"); return 0; } NetPkt* Socket::recv() { fd_set fdsel; FD_ZERO(&fdsel); FD_SET(fd, &fdsel); select(FD_SETSIZE, &fdsel, NULL, NULL, NULL); NetPkt* pkt = new NetPkt(this->getRecvSize()); socklen_t i = sizeof(pkt->addr); pkt->size = ::recvfrom(fd, (void*)pkt->data, pkt->alloc, 0, (struct sockaddr *)&pkt->addr, &i); return pkt; }