From f83b395168155d0421dbc093a37bd075dc51ed53 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Wed, 1 Aug 2012 20:30:37 +0200 Subject: Added socket class and made simple test app using fork. --- src/Makefile.am | 6 +- src/crosscomposer.cc | 49 ++++++++++--- src/socket.cc | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/socket.h | 62 ++++++++++++++++ 4 files changed, 307 insertions(+), 11 deletions(-) create mode 100644 src/socket.cc create mode 100644 src/socket.h diff --git a/src/Makefile.am b/src/Makefile.am index c544e46..db3a5b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,11 +8,13 @@ crosscomposer_CXXFLAGS = $(ALSA_CFLAGS) $(AO_CFLAGS) crosscomposer_SOURCES = \ crosscomposer.cc \ audioin.cc \ - audioout.cc + audioout.cc \ + socket.cc EXTRA_DIST = \ audioin.h \ - audioout.h + audioout.h \ + socket.h ################ # Test Section # diff --git a/src/crosscomposer.cc b/src/crosscomposer.cc index c8992ff..010aa92 100644 --- a/src/crosscomposer.cc +++ b/src/crosscomposer.cc @@ -27,22 +27,53 @@ */ #include +#include "socket.h" + #include "audioin.h" #include "audioout.h" +#define NUM_SAMPLES 940 + int main(int argc, char *argv[]) { - AudioIn in("default", "Capture", 44101, 1); - AudioOut out("default", 44101, 1); - sample_t samples[940]; - int i = 50; - while(i--) { - int sz = in.read(samples, sizeof(samples)); - out.write(samples, sz); - printf("."); fflush(stdout); + Socket s; + s.open("127.0.0.1", 10000); + + switch(fork()) { + case 0: + { + AudioIn in("default", "Capture", 44100, 1); + s.setSend(0); + + int i = 50; + while(i--) { + int sz = in.read(samples, NUM_SAMPLES); + for(size_t i = 0; i < NUM_SAMPLES; i++) { + samples[i] = ((sample_t)rand() / (float)RAND_MAX) * 10; + } + s.sendTo(samples, sz * sizeof(sample_t)); + printf("s"); fflush(stdout); + } + printf("S!\n"); + } + break; + + default: + { + s.setRecv(); + AudioOut out("default", 44100, 1); + + int i = 50; + while(i--) { + int sz = s.recvFrom(samples, sizeof(samples)); + out.write(samples, sz / sizeof(sample_t)); + printf("r%f", samples[0]); fflush(stdout); + } + printf("R!\n"); + } + break; } - printf("!\n"); return 0; } 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 +#include + +#ifdef WIN32 +#include +#include +typedef signed int ssize_t; +#else +#include +#include +#include +#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; +} + diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..313a87a --- /dev/null +++ b/src/socket.h @@ -0,0 +1,62 @@ +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * File: socket.h + * This file belongs to the Bifrost project. + * Socket wrapper class header file. + * Date: Wed Sep 2 09:02:38 CEST 2009 + * Author: Bent Bisballe Nyeng + * Copyright: 2009 + * Email: deva@aasimon.org + ****************************************************************************/ +#ifndef __BIFROST_SOCKET_H__ +#define __BIFROST_SOCKET_H__ + +#include +#include + +typedef unsigned short int port_t; + +#ifdef WIN32 +typedef SOCKET socket_t; +#define _throw(...) +#else +typedef int socket_t; +#define _throw(fmt...) throw(fmt) +#endif + +struct socket_private_t; + +class Socket { +public: + class BindException : public std::exception {}; + class MulticastTTLException : public std::exception {}; + class MulticastGroupJoinException : public std::exception {}; + class ReceiveException : public std::exception {}; + class SendException : public std::exception {}; + class WSAException : public std::exception {}; + class AddressParseException : public std::exception {}; + class OpenException : public std::exception {}; + + Socket() _throw(WSAException); + ~Socket(); + + void open(std::string address, port_t port) + _throw(AddressParseException, OpenException); + + void setSocketFiledescriptor(socket_t sock, std::string address, port_t port) + _throw(AddressParseException); + + void setSend(unsigned char ttl) + _throw(MulticastTTLException, MulticastGroupJoinException); + void setRecv() _throw(BindException); + + virtual size_t sendTo(void *data, size_t size) + _throw(SendException); + virtual size_t recvFrom(void *data, size_t size) + _throw(ReceiveException); + +private: + struct socket_private_t *prv; +}; + +#endif/*__BIFROST_SOCKET_H__*/ -- cgit v1.2.3