mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-19 12:06:15 +02:00
socket stuff
git-svn-id: svn://elaine/murooma/trunk@273 d8a302eb-03bc-478d-80e4-98257eca68ef
This commit is contained in:
parent
feabfee936
commit
3116ec0257
9 changed files with 266 additions and 98 deletions
|
@ -3,7 +3,7 @@ CC = /usr/bin/g++
|
||||||
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
||||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg
|
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg
|
||||||
|
|
||||||
OBJ = snapServer.o streamServer.o controlServer.o pcmEncoder.o oggEncoder.o serverConnection.o ../common/log.o ../common/socketConnection.o ../common/pcmChunk.o ../common/sampleFormat.o
|
OBJ = snapServer.o controlServer.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../common/pcmChunk.o ../common/sampleFormat.o
|
||||||
BIN = snapserver
|
BIN = snapserver
|
||||||
|
|
||||||
all: server
|
all: server
|
||||||
|
|
|
@ -9,7 +9,28 @@ ControlServer::ControlServer(unsigned short port) : port_(port), headerChunk(NUL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ControlServer::onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer)
|
|
||||||
|
|
||||||
|
void ControlServer::send(shared_ptr<BaseMessage> message)
|
||||||
|
{
|
||||||
|
for (std::set<shared_ptr<ServerSession>>::iterator it = sessions.begin(); it != sessions.end(); )
|
||||||
|
{
|
||||||
|
if (!(*it)->active())
|
||||||
|
{
|
||||||
|
cout << "Session inactive. Removing\n";
|
||||||
|
sessions.erase(it++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto s : sessions)
|
||||||
|
s->add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ControlServer::onMessageReceived(ServerSession* connection, const BaseMessage& baseMessage, char* buffer)
|
||||||
{
|
{
|
||||||
// cout << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," << baseMessage.received.usec << "\n";
|
// cout << "onMessageReceived: " << baseMessage.type << ", size: " << baseMessage.size << ", sent: " << baseMessage.sent.sec << "," << baseMessage.sent.usec << ", recv: " << baseMessage.received.sec << "," << baseMessage.received.usec << "\n";
|
||||||
if (baseMessage.type == message_type::requestmsg)
|
if (baseMessage.type == message_type::requestmsg)
|
||||||
|
@ -59,8 +80,8 @@ void ControlServer::acceptor()
|
||||||
setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
setsockopt(sock->native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||||
setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
setsockopt(sock->native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||||
cout << "ControlServer::NewConnection: " << sock->remote_endpoint().address().to_string() << "\n";
|
cout << "ControlServer::NewConnection: " << sock->remote_endpoint().address().to_string() << "\n";
|
||||||
ServerConnection* session = new ServerConnection(this, sock);
|
ServerSession* session = new ServerSession(this, sock);
|
||||||
sessions.insert(shared_ptr<ServerConnection>(session));
|
sessions.insert(shared_ptr<ServerSession>(session));
|
||||||
session->start();
|
session->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "serverConnection.h"
|
#include "serverSession.h"
|
||||||
#include "common/timeUtils.h"
|
#include "common/timeUtils.h"
|
||||||
#include "common/queue.h"
|
#include "common/queue.h"
|
||||||
#include "common/message.h"
|
#include "common/message.h"
|
||||||
|
@ -29,20 +29,43 @@ public:
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
virtual void onMessageReceived(SocketConnection* connection, const BaseMessage& baseMessage, char* buffer);
|
void send(shared_ptr<BaseMessage> message);
|
||||||
|
virtual void onMessageReceived(ServerSession* connection, const BaseMessage& baseMessage, char* buffer);
|
||||||
void setHeader(HeaderMessage* header);
|
void setHeader(HeaderMessage* header);
|
||||||
void setFormat(SampleFormat* format);
|
void setFormat(SampleFormat* format);
|
||||||
void setServerSettings(ServerSettings* settings);
|
void setServerSettings(ServerSettings* settings);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void acceptor();
|
void acceptor();
|
||||||
set<shared_ptr<ServerConnection>> sessions;
|
set<shared_ptr<ServerSession>> sessions;
|
||||||
boost::asio::io_service io_service_;
|
boost::asio::io_service io_service_;
|
||||||
unsigned short port_;
|
unsigned short port_;
|
||||||
HeaderMessage* headerChunk;
|
HeaderMessage* headerChunk;
|
||||||
SampleFormat* sampleFormat;
|
SampleFormat* sampleFormat;
|
||||||
ServerSettings* serverSettings;
|
ServerSettings* serverSettings;
|
||||||
thread* acceptThread;
|
thread* acceptThread;
|
||||||
|
Queue<shared_ptr<BaseMessage>> messages;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ServerException : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServerException(const std::string& what) : what_(what)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ServerException() throw()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* what() const throw()
|
||||||
|
{
|
||||||
|
return what_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string what_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
#include "serverConnection.h"
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
#include <mutex>
|
|
||||||
#include "common/log.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ServerConnection::ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket) : SocketConnection(_receiver)
|
|
||||||
{
|
|
||||||
socket = _socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ServerConnection::worker()
|
|
||||||
{
|
|
||||||
active_ = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
while (active_)
|
|
||||||
{
|
|
||||||
getNextMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl;
|
|
||||||
}
|
|
||||||
active_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
#ifndef SERVER_CONNECTION_H
|
|
||||||
#define SERVER_CONNECTION_H
|
|
||||||
|
|
||||||
#include "common/socketConnection.h"
|
|
||||||
|
|
||||||
|
|
||||||
using boost::asio::ip::tcp;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ServerConnection : public SocketConnection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ServerConnection(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void worker();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
142
server/serverSession.cpp
Normal file
142
server/serverSession.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#include "serverSession.h"
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ServerSession::ServerSession(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket) : messageReceiver(_receiver)
|
||||||
|
{
|
||||||
|
socket = _socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::start()
|
||||||
|
{
|
||||||
|
active_ = true;
|
||||||
|
readerThread = new thread(&ServerSession::reader, this);
|
||||||
|
writerThread = new thread(&ServerSession::writer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::socketRead(void* _to, size_t _bytes)
|
||||||
|
{
|
||||||
|
// std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
size_t toRead = _bytes;
|
||||||
|
size_t len = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// cout << "/";
|
||||||
|
// cout.flush();
|
||||||
|
boost::system::error_code error;
|
||||||
|
len += socket->read_some(boost::asio::buffer((char*)_to + len, toRead), error);
|
||||||
|
//cout << "len: " << len << ", error: " << error << endl;
|
||||||
|
toRead = _bytes - len;
|
||||||
|
// cout << "\\";
|
||||||
|
// cout.flush();
|
||||||
|
}
|
||||||
|
while (toRead > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::add(shared_ptr<BaseMessage> message)
|
||||||
|
{
|
||||||
|
if (!message)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (messages.size() > 100)// chunk->getDuration() > 10000)
|
||||||
|
messages.pop();
|
||||||
|
messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ServerSession::send(BaseMessage* message)
|
||||||
|
{
|
||||||
|
// std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
//cout << "send: " << message->type << ", size: " << message->getSize() << "\n";
|
||||||
|
if (!connected())
|
||||||
|
return false;
|
||||||
|
//cout << "send: " << message->type << ", size: " << message->getSize() << "\n";
|
||||||
|
boost::asio::streambuf streambuf;
|
||||||
|
std::ostream stream(&streambuf);
|
||||||
|
tv t;
|
||||||
|
message->sent = t;
|
||||||
|
message->serialize(stream);
|
||||||
|
boost::asio::write(*socket.get(), streambuf);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::getNextMessage()
|
||||||
|
{
|
||||||
|
cout << "getNextMessage\n";
|
||||||
|
BaseMessage baseMessage;
|
||||||
|
size_t baseMsgSize = baseMessage.getSize();
|
||||||
|
vector<char> buffer(baseMsgSize);
|
||||||
|
socketRead(&buffer[0], baseMsgSize);
|
||||||
|
baseMessage.deserialize(&buffer[0]);
|
||||||
|
cout << "getNextMessage: " << baseMessage.type << ", size: " << baseMessage.size << ", id: " << baseMessage.id << ", refers: " << baseMessage.refersTo << "\n";
|
||||||
|
if (baseMessage.size > buffer.size())
|
||||||
|
buffer.resize(baseMessage.size);
|
||||||
|
socketRead(&buffer[0], baseMessage.size);
|
||||||
|
tv t;
|
||||||
|
baseMessage.received = t;
|
||||||
|
|
||||||
|
if (messageReceiver != NULL)
|
||||||
|
messageReceiver->onMessageReceived(this, baseMessage, &buffer[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::reader()
|
||||||
|
{
|
||||||
|
active_ = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (active_)
|
||||||
|
{
|
||||||
|
getNextMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
cout << kLogNotice << "Exception: " << e.what() << ", trying to reconnect" << std::endl;
|
||||||
|
}
|
||||||
|
active_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ServerSession::writer()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boost::asio::streambuf streambuf;
|
||||||
|
std::ostream stream(&streambuf);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
shared_ptr<BaseMessage> message(messages.pop());
|
||||||
|
send(message.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception in thread: " << e.what() << "\n";
|
||||||
|
active_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
68
server/serverSession.h
Normal file
68
server/serverSession.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef SERVER_CONNECTION_H
|
||||||
|
#define SERVER_CONNECTION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <set>
|
||||||
|
#include "common/message.h"
|
||||||
|
#include "common/queue.h"
|
||||||
|
|
||||||
|
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
|
||||||
|
class ServerSession;
|
||||||
|
|
||||||
|
class MessageReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void onMessageReceived(ServerSession* connection, const BaseMessage& baseMessage, char* buffer) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ServerSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServerSession(MessageReceiver* _receiver, std::shared_ptr<tcp::socket> _socket);
|
||||||
|
void start();
|
||||||
|
bool send(BaseMessage* message);
|
||||||
|
void add(std::shared_ptr<BaseMessage> message);
|
||||||
|
virtual bool connected()
|
||||||
|
{
|
||||||
|
return (socket != 0);
|
||||||
|
// return (connected_ && socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool active()
|
||||||
|
{
|
||||||
|
return active_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void socketRead(void* _to, size_t _bytes);
|
||||||
|
void getNextMessage();
|
||||||
|
void reader();
|
||||||
|
void writer();
|
||||||
|
|
||||||
|
std::atomic<bool> active_;
|
||||||
|
std::thread* readerThread;
|
||||||
|
std::thread* writerThread;
|
||||||
|
std::shared_ptr<tcp::socket> socket;
|
||||||
|
MessageReceiver* messageReceiver;
|
||||||
|
Queue<std::shared_ptr<BaseMessage>> messages;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "../server/pcmEncoder.h"
|
#include "../server/pcmEncoder.h"
|
||||||
#include "../server/oggEncoder.h"
|
#include "../server/oggEncoder.h"
|
||||||
#include "common/message.h"
|
#include "common/message.h"
|
||||||
#include "streamServer.h"
|
|
||||||
#include "controlServer.h"
|
#include "controlServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,8 +87,8 @@ int main(int argc, char* argv[])
|
||||||
controlServer->setHeader(encoder->getHeader());
|
controlServer->setHeader(encoder->getHeader());
|
||||||
controlServer->start();
|
controlServer->start();
|
||||||
|
|
||||||
StreamServer* server = new StreamServer(port + 1);
|
// StreamServer* server = new StreamServer(port + 1);
|
||||||
server->start();
|
// server->start();
|
||||||
|
|
||||||
while (!g_terminated)
|
while (!g_terminated)
|
||||||
{
|
{
|
||||||
|
@ -116,7 +115,7 @@ int main(int argc, char* argv[])
|
||||||
chunk->timestamp.usec = tvChunk.tv_usec;
|
chunk->timestamp.usec = tvChunk.tv_usec;
|
||||||
double chunkDuration = encoder->encode(chunk.get());
|
double chunkDuration = encoder->encode(chunk.get());
|
||||||
if (chunkDuration > 0)
|
if (chunkDuration > 0)
|
||||||
server->send(chunk);
|
controlServer->send(chunk);
|
||||||
//cout << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
|
//cout << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
|
||||||
// addUs(tvChunk, 1000*chunk->getDuration());
|
// addUs(tvChunk, 1000*chunk->getDuration());
|
||||||
addUs(tvChunk, chunkDuration * 1000);
|
addUs(tvChunk, chunkDuration * 1000);
|
||||||
|
@ -140,7 +139,7 @@ int main(int argc, char* argv[])
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
server->stop();
|
// server->stop();
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,20 +22,6 @@ using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class StreamSession : public ServerConnection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StreamSession(socket_ptr sock);
|
|
||||||
void send(shared_ptr<BaseMessage> message);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void worker();
|
|
||||||
thread* senderThread;
|
|
||||||
Queue<shared_ptr<BaseMessage>> messages;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class StreamServer
|
class StreamServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -47,7 +33,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void acceptor();
|
void acceptor();
|
||||||
set<shared_ptr<StreamSession>> sessions;
|
set<shared_ptr<ServerSession>> sessions;
|
||||||
boost::asio::io_service io_service_;
|
boost::asio::io_service io_service_;
|
||||||
unsigned short port_;
|
unsigned short port_;
|
||||||
shared_ptr<HeaderMessage> headerChunk;
|
shared_ptr<HeaderMessage> headerChunk;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue