2020-09-23 09:37:18 +02:00
|
|
|
/**
|
|
|
|
* DServer
|
|
|
|
*
|
|
|
|
* Represents a server instance.
|
|
|
|
*
|
|
|
|
* Holds a list of DConnections,
|
|
|
|
* configuration parameters and
|
|
|
|
* more.
|
|
|
|
*/
|
|
|
|
|
|
|
|
module dnetd.dserver;
|
|
|
|
|
|
|
|
import core.thread : Thread;
|
2020-09-23 21:49:56 +02:00
|
|
|
import std.socket : Address, Socket, AddressFamily, SocketType, ProtocolType;
|
2020-09-23 09:37:18 +02:00
|
|
|
import dnetd.dconnection;
|
2020-09-23 18:52:11 +02:00
|
|
|
import dnetd.dchannel;
|
|
|
|
import std.string : cmp;
|
|
|
|
import core.sync.mutex : Mutex;
|
2020-09-25 12:53:34 +02:00
|
|
|
import std.stdio;
|
2020-09-28 11:42:14 +02:00
|
|
|
import std.conv : to;
|
2020-09-23 09:37:18 +02:00
|
|
|
|
|
|
|
public class DServer : Thread
|
|
|
|
{
|
|
|
|
/* The server's socket to bind, listen and accept connections from */
|
|
|
|
private Socket serverSocket;
|
|
|
|
|
|
|
|
/* Bind address */
|
|
|
|
private Address sockAddress;
|
|
|
|
|
|
|
|
|
2020-09-23 11:20:09 +02:00
|
|
|
/**
|
|
|
|
* Connection queue
|
|
|
|
*/
|
2020-09-23 09:37:18 +02:00
|
|
|
private DConnection[] connectionQueue;
|
2020-09-27 18:31:34 +02:00
|
|
|
private Mutex connectionLock;
|
2020-09-23 18:52:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Channels
|
|
|
|
*/
|
|
|
|
private DChannel[] channels;
|
|
|
|
private Mutex channelLock;
|
2020-09-23 09:37:18 +02:00
|
|
|
|
|
|
|
this(Address sockAddress)
|
|
|
|
{
|
|
|
|
/* Set the function to be called on thread start */
|
|
|
|
super(&dequeueLoop);
|
|
|
|
|
|
|
|
/* Set the listening address */
|
|
|
|
this.sockAddress = sockAddress;
|
|
|
|
|
|
|
|
/* Initialize the server */
|
|
|
|
init();
|
|
|
|
|
|
|
|
/* Start the server */
|
|
|
|
startServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void init()
|
|
|
|
{
|
|
|
|
/* Setup socket */
|
|
|
|
initNetwork();
|
|
|
|
|
|
|
|
/* Setup queues */
|
|
|
|
initQueues();
|
2020-09-23 18:52:11 +02:00
|
|
|
|
|
|
|
/* Setup locks */
|
|
|
|
initLocks();
|
2020-09-23 09:37:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates the socket, binds it
|
|
|
|
* to the given address
|
|
|
|
*/
|
|
|
|
private void initNetwork()
|
|
|
|
{
|
|
|
|
/* Create the socket */
|
2020-09-23 21:49:56 +02:00
|
|
|
serverSocket = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
|
2020-09-23 09:37:18 +02:00
|
|
|
|
|
|
|
/* Bind the socket to the given address */
|
|
|
|
serverSocket.bind(sockAddress);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates all needed queues
|
|
|
|
* and their mutexes
|
|
|
|
*/
|
|
|
|
private void initQueues()
|
|
|
|
{
|
|
|
|
/* TODO: Implement me */
|
|
|
|
}
|
2020-09-23 18:52:11 +02:00
|
|
|
|
|
|
|
private void initLocks()
|
|
|
|
{
|
2020-09-27 18:31:34 +02:00
|
|
|
/* Initialize the connection lock */
|
|
|
|
connectionLock = new Mutex();
|
|
|
|
|
|
|
|
/* Initialize the channel lock */
|
2020-09-23 18:52:11 +02:00
|
|
|
channelLock = new Mutex();
|
|
|
|
}
|
2020-09-23 09:37:18 +02:00
|
|
|
|
|
|
|
private void startServer()
|
|
|
|
{
|
|
|
|
/* Start the connection dequeue thread */
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void dequeueLoop()
|
|
|
|
{
|
|
|
|
/* Start accepting-and-enqueuing connections */
|
|
|
|
serverSocket.listen(0); /* TODO: Linux be lile, hehahahhahahah who gives one - I give zero */
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
/* Dequeue a connection */
|
|
|
|
Socket socket = serverSocket.accept();
|
|
|
|
|
|
|
|
/* Spawn a connection handler */
|
2020-09-23 18:52:11 +02:00
|
|
|
DConnection connection = new DConnection(this, socket);
|
2020-09-23 09:37:18 +02:00
|
|
|
|
|
|
|
/* Add to the connection queue */
|
2020-09-28 11:56:59 +02:00
|
|
|
addConnection(connection);
|
2020-09-23 09:37:18 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-23 18:52:11 +02:00
|
|
|
|
|
|
|
public void addChannel(DConnection causer, DChannel channel)
|
|
|
|
{
|
|
|
|
/* Lock the channels list */
|
2020-09-28 19:23:04 +02:00
|
|
|
// channelLock.lock();
|
2020-09-23 18:52:11 +02:00
|
|
|
|
|
|
|
channels ~= channel;
|
|
|
|
|
|
|
|
/* TODO: Use causer */
|
|
|
|
|
|
|
|
/* Unlock the channels list */
|
2020-09-28 19:23:04 +02:00
|
|
|
// channelLock.unlock();
|
2020-09-23 18:52:11 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 11:56:59 +02:00
|
|
|
public void addConnection(DConnection connection)
|
|
|
|
{
|
|
|
|
/* Lock the connections list */
|
|
|
|
connectionLock.lock();
|
|
|
|
|
|
|
|
/* Add to the connection queue */
|
|
|
|
connectionQueue ~= connection;
|
2020-09-28 12:50:40 +02:00
|
|
|
writeln("Added connection to queue "~to!(string)(connection));
|
2020-09-28 11:56:59 +02:00
|
|
|
|
|
|
|
/* Unlock the connections list */
|
|
|
|
connectionLock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO Remove connection */
|
2020-09-28 12:50:40 +02:00
|
|
|
public void removeConnection(DConnection connection)
|
2020-09-28 11:56:59 +02:00
|
|
|
{
|
2020-09-28 12:50:40 +02:00
|
|
|
/* Lock the connections list */
|
|
|
|
connectionLock.lock();
|
|
|
|
|
|
|
|
/* The new connection queue */
|
|
|
|
DConnection[] connectionQueueNew;
|
|
|
|
|
|
|
|
foreach(DConnection currentConnection; connectionQueue)
|
|
|
|
{
|
|
|
|
if(!(currentConnection is connection))
|
|
|
|
{
|
|
|
|
connectionQueueNew ~= currentConnection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set this as the new queue */
|
|
|
|
connectionQueue = connectionQueueNew;
|
|
|
|
|
2020-09-28 12:54:05 +02:00
|
|
|
writeln("Removed connection from queue "~to!(string)(connection));
|
2020-09-28 12:50:40 +02:00
|
|
|
|
|
|
|
/* Unlock the connections list */
|
|
|
|
connectionLock.unlock();
|
2020-09-28 11:56:59 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 19:23:04 +02:00
|
|
|
/* TODO: neew method */
|
|
|
|
public DChannel getChannel(DConnection causer, string channelName)
|
|
|
|
{
|
|
|
|
DChannel channel = null;
|
|
|
|
|
|
|
|
channelLock.lock();
|
|
|
|
|
|
|
|
|
|
|
|
foreach(DChannel currentChannel; channels)
|
|
|
|
{
|
|
|
|
if(cmp(currentChannel.getName(), channelName) == 0)
|
|
|
|
{
|
|
|
|
channel = currentChannel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(channel)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
channel = new DChannel(channelName);
|
|
|
|
|
|
|
|
this.addChannel(causer, channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
channelLock.unlock();
|
|
|
|
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-09-23 18:52:11 +02:00
|
|
|
public DChannel getChannelByName(string channelName)
|
|
|
|
{
|
2020-09-25 10:21:58 +02:00
|
|
|
/* The channel */
|
|
|
|
DChannel channel = null;
|
|
|
|
|
2020-09-23 18:52:11 +02:00
|
|
|
/* Lock the channels list */
|
|
|
|
channelLock.lock();
|
|
|
|
|
|
|
|
foreach(DChannel currentChannel; channels)
|
|
|
|
{
|
|
|
|
if(cmp(currentChannel.getName(), channelName) == 0)
|
|
|
|
{
|
2020-09-25 10:21:58 +02:00
|
|
|
channel = currentChannel;
|
|
|
|
break;
|
2020-09-23 18:52:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unlock the channels list */
|
|
|
|
channelLock.unlock();
|
|
|
|
|
2020-09-25 10:21:58 +02:00
|
|
|
return channel;
|
2020-09-23 18:52:11 +02:00
|
|
|
}
|
2020-09-24 12:32:00 +02:00
|
|
|
|
2020-09-27 18:31:34 +02:00
|
|
|
/**
|
|
|
|
* Returns the DConnection with the matching
|
|
|
|
* username, null if not found
|
|
|
|
*/
|
|
|
|
public DConnection findUser(string username)
|
|
|
|
{
|
|
|
|
/* Get all the current connections */
|
|
|
|
DConnection[] connections = getConnections();
|
|
|
|
|
|
|
|
/* Find the user with the matching user name */
|
|
|
|
foreach(DConnection connection; connections)
|
|
|
|
{
|
|
|
|
/* The connection must be a user (not unspec or server) */
|
|
|
|
if(connection.getConnectionType() == DConnection.ConnectionType.CLIENT)
|
|
|
|
{
|
|
|
|
/* Match the username */
|
|
|
|
if(cmp(connection.getUsername(), username) == 0)
|
|
|
|
{
|
|
|
|
return connection;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public DConnection[] getConnections()
|
|
|
|
{
|
|
|
|
/* The current connections list */
|
|
|
|
DConnection[] currentConnections;
|
|
|
|
|
|
|
|
/* Lock the connections list */
|
|
|
|
connectionLock.lock();
|
|
|
|
|
|
|
|
currentConnections = connectionQueue;
|
|
|
|
|
|
|
|
/* Unlock the connections list */
|
|
|
|
connectionLock.unlock();
|
|
|
|
|
|
|
|
return currentConnections;
|
|
|
|
}
|
|
|
|
|
2020-09-24 12:32:00 +02:00
|
|
|
public DChannel[] getChannels()
|
|
|
|
{
|
2020-09-26 15:05:52 +02:00
|
|
|
/* The current channels list */
|
|
|
|
DChannel[] currentChannels;
|
|
|
|
|
|
|
|
/* Lock the channels list */
|
|
|
|
channelLock.lock();
|
|
|
|
|
|
|
|
currentChannels = channels;
|
|
|
|
|
|
|
|
/* Unlock the channels list */
|
|
|
|
channelLock.unlock();
|
|
|
|
|
|
|
|
return currentChannels;
|
2020-09-24 12:32:00 +02:00
|
|
|
}
|
2020-09-23 09:37:18 +02:00
|
|
|
}
|