/*************************************************************************** * Copyright (C) 2005 by Jeff Ferr * * root@sat * * * * 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 "Stdafx.h" #include "jrawsocket.h" #include "jsocketexception.h" #include "jsockettimeoutexception.h" #include "jioexception.h" namespace jsocket { int RawSocket::_used_port = 1024; RawSocket::RawSocket(std::string device_, bool promisc_, int timeout_, int rbuf_, int wbuf_): jsocket::Connection(JCT_RAW) { jcommon::Object::SetClassName("jsocket::RawSocket"); _device = device_; _promisc = promisc_; _address = NULL; _is = NULL; _os = NULL; _is_closed = true; _timeout = timeout_; CreateSocket(); BindSocket(); InitStream(rbuf_, wbuf_); _sent_bytes = 0; _receive_bytes = 0; } RawSocket::~RawSocket() { ioctl(_fd, SIOCSIFFLAGS, &(_ifr)); try { Close(); } catch (...) { } } /** Private */ void RawSocket::CreateSocket() { #ifdef _WIN32 if ((_fd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET) { throw SocketException("Socket creation exception"); } #else if ((_fd = ::socket(PF_PACKET, SOCK_RAW, (_promisc == true)?ETH_P_ALL:ETH_P_IP)) < 0) { throw SocketException("Socket creation exception"); } _is_closed = false; struct ifreq ifr; memset(&_ifr, 0, sizeof(_ifr)); strncpy(_ifr.ifr_name, _device.c_str(), sizeof(_ifr.ifr_name)); if (ioctl(_fd, SIOCGIFFLAGS, &_ifr)<0) { throw SocketException("Cannot access network interface flags"); } if (_promisc) { ifr.ifr_flags |= IFF_PROMISC; } else { ifr.ifr_flags &= ~IFF_PROMISC; } if (ioctl(_fd, SIOCSIFFLAGS, &_ifr) < 0) { throw SocketException("Cannot put network interface in promiscuous mode"); } if (ioctl(_fd, SIOCGIFINDEX, &_ifr) < 0) { throw SocketException("Cannot access network interface index"); } _index_device = _ifr.ifr_ifindex; if (_index_device < 0) { throw SocketException("Network interface do not exists"); } #endif } void RawSocket::BindSocket() { struct sockaddr_ll sock_ether; memset(&sock_ether, 0, sizeof(sock_ether)); sock_ether.sll_family = AF_PACKET; sock_ether.sll_protocol = htons((_promisc == true)?ETH_P_ALL:ETH_P_IP); sock_ether.sll_ifindex = _index_device; sock_ether.sll_pkttype = (_promisc == true)?PACKET_OTHERHOST:PACKET_HOST; if (bind(_fd, (struct sockaddr *)(&sock_ether), sizeof(sock_ether)) < 0) { throw SocketException("Socket bind exception"); } } void RawSocket::InitStream(int rbuf_, int wbuf_) { _is = new SocketInputStream((Connection *)this, &_is_closed, (struct sockaddr *)&_server_sock, rbuf_); _os = new SocketOutputStream((Connection *)this, &_is_closed, (struct sockaddr *)&_server_sock, wbuf_); } /** End */ jsocket_t RawSocket::GetHandler() { return _fd; } jio::InputStream * RawSocket::GetInputStream() { return (jio::InputStream *)_is; } jio::OutputStream * RawSocket::GetOutputStream() { return (jio::OutputStream *)_os; } int RawSocket::Receive(char *data_, int size_, int time_) { if (_is_closed == true) { throw SocketException("Connection closed exception"); } #ifdef _WIN32 return RawSocket::Receive(data_, size_); #else struct pollfd ufds[1]; ufds[0].fd = _fd; ufds[0].events = POLLIN | POLLRDBAND; int rv = poll(ufds, 1, time_); if (rv == -1) { throw SocketException("Invalid receive parameters exception"); } else if (rv == 0) { throw SocketTimeoutException("Socket read timeout exception"); } else { if ((ufds[0].revents & POLLIN) || (ufds[0].revents & POLLRDBAND)) { return RawSocket::Receive(data_, size_); } } #endif return -1; } int RawSocket::Receive(char *data_, int size_, bool block_) { if (_is_closed == true) { throw SocketException("Connection closed exception"); } int n; #ifdef _WIN32 /* n = ::recvfrom(_fd, data_, size_, 0, (struct sockaddr *)&_server_sock, &length); if (n == SOCKET_ERROR) { if (WSAGetLastError() == WSAETIMEDOUT) { throw SocketTimeoutException("Socket receive timeout exception"); } else { throw jio::IOException("Socket read exception"); } } else if (n == 0) { throw jio::IOException("Peer shutdown exception"); } */ #else // n = ::recvfrom(_fd, data_, size_, 0, (struct sockaddr *)&_lsock, (socklen_t *)&length); n = ::read(_fd, data_, size_); if (n < 0) { if (errno == EAGAIN) { if (block_ == true) { throw SocketTimeoutException("Socket receive timeout exception"); } else { // INFO:: non-blocking socket, no data read n = 0; } } else { throw jio::IOException("Socket read exception"); } } else if (n == 0) { Close(); throw jio::IOException("Peer shutdown exception"); } #endif _receive_bytes += n; return n; } int RawSocket::Send(const char *data_, int size_, int time_) { if (_is_closed == true) { throw SocketException("Connection closed exception"); } #ifdef _WIN32 return RawSocket::Send(data_, size_); #else struct pollfd ufds[1]; ufds[0].fd = _fd; ufds[0].events = POLLOUT | POLLWRBAND; int rv = poll(ufds, 1, time_); if (rv == -1) { throw SocketException("Invalid send parameters exception"); } else if (rv == 0) { throw SocketTimeoutException("Socket send timeout exception"); } else { if ((ufds[0].revents & POLLOUT) || (ufds[0].revents & POLLWRBAND)) { return RawSocket::Send(data_, size_); } } #endif return -1; } int RawSocket::Send(const char *data_, int size_, bool block_) { if (_is_closed == true) { throw SocketException("Connection closed exception"); } int n; #ifdef _WIN32 n = ::sendto(_fd, data_, size_, 0, (struct sockaddr *)&_server_sock, sizeof(_server_sock)); #else n = ::write(_fd, data_, size_); #endif #ifdef _WIN32 if (n == SOCKET_ERROR) { if (WSAGetLastError() == WSAECONNABORTED) { throw SocketTimeoutException("Socket send timeout exception"); } else { throw SocketTimeoutException("Socket send exception"); } } #else if (n < 0) { if (errno == EAGAIN) { if (block_ == true) { throw SocketTimeoutException("Socket send timeout exception"); } else { // INFO:: non-blocking socket, no data read n = 0; } } else if (errno == EPIPE || errno == ECONNRESET) { Close(); throw SocketException("Broken pipe exception"); } else { throw SocketTimeoutException("Socket send exception"); } } #endif _sent_bytes += n; return n; } void RawSocket::Close() { if (_is_closed == true) { return; } #ifdef _WIN32 if (closesocket(_fd) < 0) { #else if (close(_fd) != 0) { #endif throw SocketException("Unknown close exception"); } _is_closed = true; } InetAddress * RawSocket::GetInetAddress() { return _address; } int RawSocket::GetLocalPort() { return ntohs(_lsock.sin_port); } int RawSocket::GetPort() { return ntohs(_server_sock.sin_port); } int64_t RawSocket::GetSentBytes() { return _sent_bytes + _os->GetSentBytes(); } int64_t RawSocket::GetReadedBytes() { return _receive_bytes + _is->GetReadedBytes(); } SocketOptions * RawSocket::GetSocketOptions() { return new SocketOptions(_fd, JCT_RAW); } unsigned short RawSocket::Checksum(unsigned short *addr, int len) { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *) w; sum += answer; } sum = (sum >> 16) + (sum & 0xF0F0); sum += (sum >> 16); answer = ~sum; return(answer); } std::string RawSocket::what() { char port[20]; sprintf(port, "%u", GetPort()); return GetInetAddress()->GetHostName() + ":" + port; } }