/******************************************************************************* * BSocket.cc BSocket Classes * T.Barnaby, BEAM Ltd, 1/4/05 ******************************************************************************* */ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #include <net/if.h> #include "BSocket.h" #if HAVE_GETIFADDRS #include <ifaddrs.h> #endif #ifndef IP_MTU #define IP_MTU 14 #endif BSocketAddress::BSocketAddress(){ olen = 0; oaddress = 0; } BSocketAddress::BSocketAddress(const BSocketAddress& add){ olen = 0; oaddress = 0; set(add.oaddress, add.olen); } BSocketAddress::BSocketAddress(SockAddr* address, int len){ olen = 0; oaddress = 0; set(address, len); } BSocketAddress::~BSocketAddress(){ free(oaddress); oaddress = 0; olen = 0;; } BError BSocketAddress::set(SockAddr* address, int len){ BError err; if(olen != len){ olen = len; if(oaddress) free(oaddress); oaddress = (SockAddr*)malloc(olen); } memcpy(oaddress, address, olen); return err; } const BSocketAddress::SockAddr* BSocketAddress::raw() const { return oaddress; } int BSocketAddress::len() const{ return olen; } BSocketAddress& BSocketAddress::operator=(const BSocketAddress& add){ if(this != &add){ free(oaddress); olen = add.olen; oaddress = (SockAddr*)malloc(olen); memcpy(oaddress, add.oaddress, olen); } return *this; } int BSocketAddress::operator==(const BSocketAddress& add) const { return !memcmp(oaddress, add.oaddress, olen); } int BSocketAddress::operator!=(const BSocketAddress& add) const { return ! (*this == add); } BError BSocketAddressINET::set(BString hostName, uint32_t port){ BError err; struct hostent* host; SockAddrIP add; /* Clear out address structure */ memset(&add, 0, sizeof(add)); add.sin_family = AF_INET; add.sin_port = htons(port); if(hostName.len()){ if((host = gethostbyname(hostName)) && host->h_addr_list[0]){ memcpy(&(add.sin_addr.s_addr), host->h_addr_list[0], sizeof(add.sin_addr.s_addr)); } else { err.set(-h_errno, hstrerror(h_errno)); } } if(!err) err = BSocketAddress::set((SockAddr*)&add, sizeof(add)); return err; } BError BSocketAddressINET::set(uint32_t address, uint32_t port){ BError err; SockAddrIP add; /* Clear out address structure */ memset(&add, 0, sizeof(add)); add.sin_family = AF_INET; add.sin_port = htons(port); add.sin_addr.s_addr = htonl(address); err = BSocketAddress::set((SockAddr*)&add, sizeof(add)); return err; } BError BSocketAddressINET::set(BString hostName, BString service, BString type){ BError err; struct servent* ser; if(ser = getservbyname(service.retStr(), type.retStr())){ err = set(hostName, htons(ser->s_port)); } else { err.set(ErrorMisc, "Getservbyname error"); } return err; } void BSocketAddressINET::setPort(uint32_t port){ SockAddrIP add; /* Clear out address structure */ memset(&add, 0, sizeof(add)); if(len()) memcpy(&add, raw(), sizeof(add)); add.sin_port = htons(port); BSocketAddress::set((SockAddr*)&add, sizeof(add)); } uint32_t BSocketAddressINET::address(){ uint32_t ret = 0; if(len()){ ret = ntohl(((SockAddrIP*)raw())->sin_addr.s_addr); } return ret; } uint32_t BSocketAddressINET::port(){ uint32_t ret = 0; if(len()){ ret = ntohs(((SockAddrIP*)raw())->sin_port); } return ret; } BString BSocketAddressINET::getString(){ BString ret; char buf[32]; SockAddrIP* add = (SockAddrIP*)raw(); buf[0] = '\0'; if(len()){ inet_ntop(add->sin_family, &add->sin_addr, buf, sizeof(buf)); ret = BString(buf) + ":" + ntohs(add->sin_port); } return ret; } // Some usefull functions BString BSocketAddressINET::getHostName(){ char s[256]; gethostname(s, sizeof(s)); s[sizeof(s) - 1] = '\0'; return s; } BList<uint32_t> BSocketAddressINET::getIpAddresses(){ struct hostent* host; int n; BList<uint32_t> l; if(host = gethostbyname(getHostName())){ for(n = 0; host->h_addr_list[n]; n++){ l.append(ntohl(*((int*)host->h_addr_list[n]))); } } return l; } BList<BString> BSocketAddressINET::getIpAddressList(){ BList<BString> l; char buf[256] = ""; struct hostent* host; int n; if(host = gethostbyname(getHostName())){ for(n = 0; host->h_addr_list[n]; n++){ if(inet_ntop(AF_INET, host->h_addr_list[n], buf, sizeof(buf))){ l.append(buf); } } } return l; } BList<BString> BSocketAddressINET::getIpAddressListAll(){ BList<BString> l; char buf[256] = ""; #if HAVE_GETIFADDRS struct ifaddrs* addrs = NULL; struct ifaddrs* addr = NULL; struct sockaddr_in* ia; if(getifaddrs(&addrs) == 0){ for(addr = addrs; addr; addr = addr->ifa_next){ if(addr->ifa_addr && (addr->ifa_addr->sa_family == PF_INET)){ ia = (struct sockaddr_in*)addr->ifa_addr; if(inet_ntop(AF_INET, &ia->sin_addr, buf, sizeof(buf))){ l.append(buf); } } } } #else struct hostent* host; int n; if(host = gethostbyname(getHostName())){ for(n = 0; host->h_addr_list[n]; n++){ if(inet_ntop(AF_INET, host->h_addr_list[n], buf, sizeof(buf))){ l.append(buf); } } } #endif return l; } /******************************************************************************* * BSocket class ******************************************************************************* */ BSocket::BSocket(){ osocket = -1; } BSocket::BSocket(int fd){ osocket = fd; } BSocket::BSocket(int domain, int type, int protocol){ init(domain, type, protocol); if(osocket < 0) fprintf(stderr, "BSocket::BSocket: Socket creation error: %s\n", strerror(errno)); } BSocket::BSocket(NType type){ init(type); if(osocket < 0) fprintf(stderr, "BSocket::BSocket: Socket creation error: %s\n", strerror(errno)); } BSocket::~BSocket(){ if(osocket >= 0) ::close(osocket); osocket = -1; } BError BSocket::init(int domain, int type, int protocol){ BError err; osocket = socket(domain, type, protocol); if(osocket < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::init(NType type){ BError err; switch(type){ case STREAM: osocket = socket(AF_INET, SOCK_STREAM, 0); break; case DGRAM: osocket = socket(AF_INET, SOCK_DGRAM, 0); break; } if(osocket < 0) err.set(-errno, strerror(errno)); return err; } void BSocket::setFd(int fd){ osocket = fd; } int BSocket::getFd(){ return osocket; } BError BSocket::bind(const BSocketAddress& address){ BError err; if(::bind(osocket, address, address.len()) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::connect(const BSocketAddress& address){ BError err; if(::connect(osocket, address, address.len()) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::shutdown(int how){ BError err; if(::shutdown(osocket, how) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::close(){ BError err; if(osocket >= 0) ::close(osocket); osocket = -1; return err; } BError BSocket::listen(int backlog){ BError err; if(::listen(osocket, 5) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::accept(int& fd){ BError err; int f; if((f = ::accept(osocket, 0, 0)) < 0){ err.set(-errno, strerror(errno)); } else { fd = f; } return err; } BError BSocket::accept(int& fd, BSocketAddress& address){ BError err; BSocketAddress::SockAddr add; socklen_t len = sizeof(add); int f; if((f = ::accept(osocket, &add, &len)) < 0){ err.set(-errno, strerror(errno)); } else { fd = f; address.set(&add, len); } return err; } BError BSocket::send(const void* buf, BSize nbytes, BSize& nbytesSent, int flags){ BError err; int r; if((r = ::send(osocket, buf, nbytes, flags)) < 0){ err.set(-errno, strerror(errno)); } else { nbytesSent = r; } return err; } BError BSocket::sendTo(const BSocketAddress& address, const void* buf, BSize nbytes, BSize& nbytesSent, int flags){ BError err; int r; if((r = ::sendto(osocket, buf, nbytes, flags, address, address.len())) < 0){ err.set(-errno, strerror(errno)); } else { nbytesSent = r; } return err; } BError BSocket::recv(void* buf, BSize maxbytes, BSize& nbytesRecv, int flags){ BError err; int r; if((r = ::recv(osocket, buf, maxbytes, flags)) < 0){ err.set(-errno, strerror(errno)); } else { if(r == 0) err.set(-EPIPE, "Connection Closed by Peer"); nbytesRecv = r; } return err; } BError BSocket::recvWithTimeout(void* buf, BSize maxbytes, BSize& nbytesRecv, int timeout, int flags){ BError err; int r; fd_set set; struct timeval t; if(timeout >= 0){ t.tv_sec = 0; t.tv_usec = timeout; FD_ZERO(&set); FD_SET(osocket, &set); r = select(osocket + 1, &set, 0, 0, &t); if(r == 0) return err.set(-ETIMEDOUT, "Connection timed out"); } return recv(buf, maxbytes, nbytesRecv, flags); } BError BSocket::recvFrom(BSocketAddress& address, void* buf, BSize maxbytes, BSize& nbytesRecv, int flags){ BError err; int r; BSocketAddress::SockAddr add; socklen_t len = sizeof(add); if((r = ::recvfrom(osocket, buf, maxbytes, flags, &add, &len)) < 0){ err.set(-errno, strerror(errno)); } else { address.set(&add, len); nbytesRecv = r; } return err; } BError BSocket::recvFromWithTimeout(BSocketAddress& address, void* buf, BSize maxbytes, BSize& nbytesRecv, int timeout, int flags){ BError err; int r; fd_set set; struct timeval t; if(timeout >= 0){ t.tv_sec = 0; t.tv_usec = timeout; FD_ZERO(&set); FD_SET(osocket, &set); r = select(osocket + 1, &set, 0, 0, &t); if(r == 0) return err.set(-ETIMEDOUT, "Connection timed out"); } return recvFrom(address, buf, maxbytes, nbytesRecv, flags); } BError BSocket::setSockOpt(int level, int optname, void* optval, unsigned int optlen){ BError err; if(setsockopt(osocket, level, optname, optval, optlen) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::getSockOpt(int level, int optname, void* optval, unsigned int* optlen){ BError err; if(getsockopt(osocket, level, optname, optval, optlen) < 0) err.set(-errno, strerror(errno)); return err; } BError BSocket::setReuseAddress(int on){ return setSockOpt(SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); } BError BSocket::setBroadCast(int on){ return setSockOpt(SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); } BError BSocket::setPriority(Priority priority){ unsigned int level; switch(priority){ case PriorityLow: level = 2; break; case PriorityNormal: level = 0; break; case PriorityHigh: level = 6; break; default: level = 0; break; } return setSockOpt(SOL_SOCKET, SO_PRIORITY, &level, sizeof(level)); } BError BSocket::getMTU(uint32_t& mtu){ socklen_t mtulen = sizeof(mtu); return getSockOpt(SOL_IP, IP_MTU, &mtu, &mtulen); } BError BSocket::getAddress(BSocketAddress& address){ BError err; BSocketAddress::SockAddr add; socklen_t len = sizeof(add); if(getsockname(osocket, &add, &len) < 0){ err.set(-errno, strerror(errno)); } else { address.set(&add, len); } return err; }