summaryrefslogtreecommitdiff
path: root/src/socket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/socket.cc')
-rw-r--r--src/socket.cc201
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;
+}
+