diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2012-08-01 20:30:37 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2012-08-01 20:30:37 +0200 |
commit | f83b395168155d0421dbc093a37bd075dc51ed53 (patch) | |
tree | 5e0c2324e09961a0f3736b623b701803f339f7de /src/socket.cc | |
parent | 91bc7bcdb590e05ceb975be66da4a19e2a649157 (diff) |
Added socket class and made simple test app using fork.
Diffstat (limited to 'src/socket.cc')
-rw-r--r-- | src/socket.cc | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/socket.cc b/src/socket.cc new file mode 100644 index 0000000..b5a93c8 --- /dev/null +++ b/src/socket.cc @@ -0,0 +1,201 @@ +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * File: socket.cc + * This file belongs to the Bifrost project. + * Socket wrapper class implementation. + * Date: Wed Sep 2 09:02:38 CEST 2009 + * Author: Bent Bisballe Nyeng + * Copyright: 2009 + * Email: deva@aasimon.org + ****************************************************************************/ +#include "socket.h" + +#include <stdlib.h> +#include <errno.h> + +#ifdef WIN32 +#include <ws2tcpip.h> +#include <WinSock2.h> +typedef signed int ssize_t; +#else +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#endif + +#define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a)) + +struct socket_private_t { + bool close_socket; + socket_t sock; + struct sockaddr_in name; + struct ip_mreq mreq; +}; + +static void leave_group(socket_t sock, struct ip_mreq mreq) +{ + int ret; + + ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, + (const char*)&mreq, sizeof(mreq)); + if (ret < 0) { + /* + fprintf(stderr, "Failed to leave multicast group."); + perror(""); + */ + } +} + + +#ifdef WIN32 +static void wsastartup() +{ + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + + int ret = WSAStartup(wVersionRequested, &wsaData); + if(ret != 0) throw Socket::WSAException(); +} +#endif + +Socket::Socket() + _throw(WSAException) +{ + prv = new struct socket_private_t(); + +#ifdef WIN32 + wsastartup(); +#endif + + prv->close_socket = false; +} + +Socket::~Socket() +{ + if(prv->close_socket) { + if (ADDR_IS_MULTICAST(prv->name.sin_addr.s_addr)) { + leave_group(prv->sock, prv->mreq); + } + +#ifdef WIN32 + closesocket(prv->sock); + WSACleanup(); +#else + close(prv->sock); +#endif + } + + if(prv) delete prv; +} + +void Socket::open(std::string address, port_t port) + _throw(AddressParseException, OpenException) +{ + prv->name.sin_family = AF_INET; + prv->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(prv->sock < 0) throw OpenException(); + + prv->name.sin_port = htons(port); + +#ifdef WIN32 + prv->name.sin_addr.S_un.S_addr = inet_addr(address.c_str()); + if(INADDR_NONE == prv->name.sin_addr.S_un.S_addr) throw AddressParseException(); +#else + prv->name.sin_addr.s_addr = inet_addr(address.c_str()); + if(INADDR_NONE == prv->name.sin_addr.s_addr) throw AddressParseException(); +#endif + + prv->close_socket = true; +} + +void Socket::setSocketFiledescriptor(socket_t sock, std::string address, port_t port) + _throw(AddressParseException) +{ + prv->name.sin_family = AF_INET; + prv->sock = sock; + if(prv->sock < 0) throw OpenException(); + + prv->name.sin_port = htons(port); + +#ifdef WIN32 + prv->name.sin_addr.S_un.S_addr = inet_addr(address.c_str()); + if(INADDR_NONE == prv->name.sin_addr.S_un.S_addr) throw AddressParseException(); +#else + prv->name.sin_addr.s_addr = inet_addr(address.c_str()); + if(INADDR_NONE == prv->name.sin_addr.s_addr) throw AddressParseException(); +#endif + + prv->close_socket = false; +} + +void Socket::setSend(unsigned char ttl) + _throw(MulticastTTLException, MulticastGroupJoinException) +{ + int ret; + if (ADDR_IS_MULTICAST(prv->name.sin_addr.s_addr)) { + ret = setsockopt(prv->sock, IPPROTO_IP, IP_MULTICAST_TTL, + (const char*)&ttl, sizeof(ttl)); + if (ret < 0) throw MulticastTTLException(); + + prv->mreq.imr_multiaddr.s_addr = prv->name.sin_addr.s_addr; + prv->mreq.imr_interface.s_addr = htonl(INADDR_ANY); + ret = setsockopt(prv->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (const char*)&prv->mreq, sizeof(prv->mreq)); + if (ret < 0) throw MulticastGroupJoinException(); + } +} + +void Socket::setRecv() + _throw(BindException) +{ +#ifdef WIN32 + if(bind(prv->sock, (SOCKADDR*)&prv->name, sizeof(prv->name)) < 0) { + + // int err = WSAGetLastError(); + + if(prv->close_socket) closesocket(prv->sock); + + throw BindException(); + } +#else + if(bind(prv->sock, (struct sockaddr *)&prv->name, sizeof(prv->name)) < 0) { + + if(prv->close_socket) close(prv->sock); + + if(ADDR_IS_MULTICAST(prv->name.sin_addr.s_addr)) { + leave_group(prv->sock, prv->mreq); + } + throw BindException(); + } +#endif +} + +size_t Socket::sendTo(void *data, size_t size) + _throw(SendException) +{ + ssize_t ret = sendto(prv->sock, (const char*) data, size, 0, + (struct sockaddr *)&prv->name, sizeof(struct sockaddr_in)); + if(ret == -1 || (size_t)ret != size) throw SendException(); + return ret; +} + +size_t Socket::recvFrom(void *data, size_t size) + _throw(ReceiveException) +{ + ssize_t ret; +#ifdef WIN32 + // unsigned long int pending; +#endif + + // do { + ret = recv(prv->sock, (char*) data, size, 0); + if(ret == -1) throw ReceiveException(); +#ifdef WIN32 + // ioctlsocket(prv->sock, FIONREAD, &pending); + // } while(pending > 0); +#else + // } while(recv(prv->sock, (char*) data, size, MSG_PEEK | MSG_DONTWAIT) > 0); +#endif + return ret; +} + |