mirror of https://github.com/deavminet/dnetd.git
Compare commits
37 Commits
Author | SHA1 | Date |
---|---|---|
Tristan B. Kildaire | f780df7c56 | |
Tristan B. Kildaire | d6a62713a2 | |
Tristan B. Kildaire | 1c9168a6b8 | |
Tristan B. Kildaire | 32b3ca7661 | |
Tristan B. Kildaire | fe2aef4c41 | |
Tristan B. Kildaire | a00acaa35e | |
Tristan B. Kildaire | c7a4cfbadd | |
Tristan B. Kildaire | e10cf7bc23 | |
Tristan B. Kildaire | 164eee4f3f | |
Tristan B. Kildaire | dc6efc50b7 | |
Tristan B. Kildaire | ce05d226ba | |
Tristan B. Kildaire | d860170429 | |
Tristan B. Kildaire | a83f55cc49 | |
Tristan B. Kildaire | bee016f521 | |
Tristan B. Kildaire | eee69dcbac | |
Tristan B. Kildaire | 0da2a73226 | |
Tristan B. Kildaire | 917402e974 | |
Tristan B. Kildaire | 9e3da7d09f | |
Tristan B. Kildaire | 40cb881816 | |
Tristan B. Kildaire | aec29f0fd1 | |
Tristan B. Kildaire | b9513bae96 | |
Tristan B. Kildaire | 04ee591936 | |
Tristan B. Kildaire | 325b37c5da | |
Tristan B. Kildaire | f1ab9271dd | |
Tristan B. Kildaire | 66be270b61 | |
Tristan B. Kildaire | 1826276262 | |
Tristan B. Kildaire | f77a61d96a | |
Tristan B. Kildaire | d1e1297a26 | |
Tristan B. Kildaire | cc95b8e2e9 | |
Tristan B. Kildaire | 727d42fa67 | |
Tristan B. Kildaire | 2badd2d302 | |
Tristan B. Kildaire | 616d063516 | |
Tristan B. Kildaire | 878a59920b | |
Tristan B. Kildaire | 41d758c46a | |
Tristan B. Kildaire | a246ef1d73 | |
Tristan B. Kildaire | 6a679613cc | |
Tristan B. Kildaire | 10da3b093d |
14
config.json
14
config.json
|
@ -1,7 +1,15 @@
|
|||
{
|
||||
"general" : {
|
||||
"addresses" : ["0.0.0.0"],
|
||||
"port" : "7777",
|
||||
"binds" : [
|
||||
{
|
||||
"address" : "0.0.0.0",
|
||||
"port" : "7777"
|
||||
},
|
||||
{
|
||||
"address" : "::",
|
||||
"port" : "7778"
|
||||
},
|
||||
],
|
||||
"network" : "aBasedIRCNetwork",
|
||||
"name" : "MyBrandSpankingNewIRCServer",
|
||||
"motd" : "Welcome to my generic dnet chat server!"
|
||||
|
@ -14,4 +22,4 @@
|
|||
"port" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
5
dub.json
5
dub.json
|
@ -4,8 +4,9 @@
|
|||
],
|
||||
"copyright": "Copyright © 2020, Tristan B. Kildaire",
|
||||
"dependencies": {
|
||||
"gogga": "~>0.0.2",
|
||||
"tristanable": "~>0.0.33"
|
||||
"bformat": "~>3.1.0",
|
||||
"gogga": "0.0.2",
|
||||
"tristanable": "2.2.0"
|
||||
},
|
||||
"description": "dnet server",
|
||||
"license": "AGPLv3",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"fileVersion": 1,
|
||||
"versions": {
|
||||
"bformat": "1.0.8",
|
||||
"bformat": "3.1.0",
|
||||
"gogga": "0.0.2",
|
||||
"tristanable": "0.0.33"
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import dnetd.dconnection : DConnection;
|
|||
import core.sync.mutex : Mutex;
|
||||
import std.conv : to;
|
||||
import std.stdio : writeln;
|
||||
import gogga;
|
||||
|
||||
public class DChannel
|
||||
{
|
||||
|
@ -49,9 +50,9 @@ public class DChannel
|
|||
broadcastJoin(client);
|
||||
|
||||
/* Lock the members list */
|
||||
writeln("join: mutex lock (about to call)");
|
||||
gprintln("join: mutex lock (about to call)");
|
||||
memberLock.lock();
|
||||
writeln("join: mutex lock (completed)");
|
||||
gprintln("join: mutex lock (completed)");
|
||||
|
||||
/**
|
||||
* Don't allow the user to join a channel he
|
||||
|
@ -81,9 +82,9 @@ public class DChannel
|
|||
}
|
||||
|
||||
/* Unlock the members list */
|
||||
writeln("join: mutex unlock (about to call)");
|
||||
gprintln("join: mutex unlock (about to call)");
|
||||
memberLock.unlock();
|
||||
writeln("join: mutex unlock (completed)");
|
||||
gprintln("join: mutex unlock (completed)");
|
||||
|
||||
return isPresent;
|
||||
}
|
||||
|
@ -271,7 +272,7 @@ public class DChannel
|
|||
*/
|
||||
|
||||
/* Set mode to channel message */
|
||||
msg ~= [cast(byte)1];
|
||||
msg ~= [cast(byte)0];
|
||||
|
||||
/* Encode the [usernameLength, username] */
|
||||
msg ~= [(cast(byte)sender.getUsername().length)];
|
||||
|
@ -291,16 +292,16 @@ public class DChannel
|
|||
if(!(member is sender))
|
||||
{
|
||||
/* Send the message */
|
||||
writeln("Delivering message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'...");
|
||||
gprintln("Delivering message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'...");
|
||||
status = member.writeSocket(0, msg);
|
||||
|
||||
if(status)
|
||||
{
|
||||
writeln("Delivered message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'!");
|
||||
gprintln("Delivered message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'!");
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln("Failed to deliver message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'!");
|
||||
gprintln("Failed to deliver message '"~message~"' for channel '"~name~"' to user '"~member.getUsername()~"'!", DebugType.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ module dnetd.dconfig;
|
|||
import std.json;
|
||||
import std.conv;
|
||||
import std.socket : Address, parseAddress;
|
||||
import gogga;
|
||||
|
||||
public final class DConfig
|
||||
{
|
||||
|
@ -69,9 +70,8 @@ public final class DConfig
|
|||
|
||||
public final class DGeneralConfig
|
||||
{
|
||||
|
||||
/* Addresses to bind sockets to */
|
||||
private string[] addresses;
|
||||
private Address[] addresses;
|
||||
private ushort port;
|
||||
|
||||
/* Server information */
|
||||
|
@ -79,26 +79,26 @@ public final class DGeneralConfig
|
|||
private string name;
|
||||
private string motd;
|
||||
|
||||
private this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static DGeneralConfig getConfig(JSONValue generalBlock)
|
||||
{
|
||||
/* The generated general config */
|
||||
DGeneralConfig config = new DGeneralConfig();
|
||||
gprintln("Reading config:\n"~generalBlock.toPrettyString());
|
||||
|
||||
try
|
||||
{
|
||||
/* Set the addresses */
|
||||
foreach(JSONValue address; generalBlock["addresses"].array())
|
||||
/* Set the addresses to bind to */
|
||||
foreach(JSONValue bindBlock; generalBlock["binds"].array())
|
||||
{
|
||||
config.addresses ~= [address.str()];
|
||||
/* Get the address */
|
||||
string address = bindBlock["address"].str();
|
||||
|
||||
/* Get the port */
|
||||
ushort port = to!(ushort)(bindBlock["port"].str());
|
||||
|
||||
/* Add the address and port tuple to the list of addresses to bind to */
|
||||
config.addresses ~= parseAddress(address, port);
|
||||
}
|
||||
|
||||
/* Set the ports */
|
||||
config.port = to!(ushort)(generalBlock["port"].str());
|
||||
|
||||
/* Set the network name */
|
||||
config.network = generalBlock["network"].str();
|
||||
|
@ -116,7 +116,6 @@ public final class DGeneralConfig
|
|||
config = null;
|
||||
}
|
||||
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -125,10 +124,9 @@ public final class DGeneralConfig
|
|||
return motd;
|
||||
}
|
||||
|
||||
public Address getAddress()
|
||||
public Address[] getAddresses()
|
||||
{
|
||||
/* TODO: Add multi address support later */
|
||||
return parseAddress(addresses[0], port);
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,9 +92,6 @@ public class DConnection : Thread
|
|||
* Mutex to provide safe access to the status message
|
||||
*/
|
||||
private Mutex statusMessageLock;
|
||||
|
||||
/* Reserved tag for push notifications */
|
||||
private long notificationTag = 0;
|
||||
|
||||
this(DServer server, Socket socket)
|
||||
{
|
||||
|
@ -113,7 +110,7 @@ public class DConnection : Thread
|
|||
/* Initialize locks */
|
||||
initLocks();
|
||||
|
||||
/* Initialize status */
|
||||
/* Initialize status (TODO: Remove, we use props now) */
|
||||
currentStatus = "available,Hey there I'm using DNET!";
|
||||
|
||||
/* Start the connection handler */
|
||||
|
@ -847,11 +844,30 @@ public class DConnection : Thread
|
|||
*/
|
||||
private bool authenticate(string username, string password)
|
||||
{
|
||||
/* TODO: Check username and password */
|
||||
/* TODO: Multi-client/session support */
|
||||
|
||||
/* TODO: Implement me */
|
||||
this.username = username;
|
||||
|
||||
/* TODO (Sessions): Generate a session ID for this connection */
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private uint generateSessionID()
|
||||
{
|
||||
/* TODO: Basically find a number that isn't taken by matching usernames */
|
||||
return 1;
|
||||
}
|
||||
|
||||
private uint getMySessionID()
|
||||
{
|
||||
/* TODO: */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get member count
|
||||
*
|
||||
|
@ -901,15 +917,24 @@ public class DConnection : Thread
|
|||
/* The protocol data to send */
|
||||
byte[] protocolData;
|
||||
|
||||
/* Set the sub-type (ntype=0) */
|
||||
/* Set the sub-type (ntype=0 / channel/directmessage) */
|
||||
protocolData ~= [0];
|
||||
|
||||
/* Encode the sender's length */
|
||||
/* Set to user message (direct message, sub-sub-type) */
|
||||
protocolData ~= [1];
|
||||
|
||||
/* Encode the recipients's length */
|
||||
protocolData ~= [cast(byte)username.length];
|
||||
|
||||
/* Encode the username */
|
||||
protocolData ~= cast(byte[])username;
|
||||
|
||||
/* Encode the sender's length */
|
||||
protocolData ~= [cast(byte)this.username.length];
|
||||
|
||||
/* Encode the sender */
|
||||
protocolData ~= cast(byte[])this.username;
|
||||
|
||||
/* Encode the message */
|
||||
protocolData ~= cast(byte[])message;
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
module dnetd.dlistener;
|
||||
|
||||
import std.socket;
|
||||
import dnetd.dserver;
|
||||
import core.thread;
|
||||
import dnetd.dconnection;
|
||||
import gogga;
|
||||
import std.conv : to;
|
||||
|
||||
public final class DListener : Thread
|
||||
{
|
||||
/* Associated server */
|
||||
private DServer server;
|
||||
|
||||
/* The socket */
|
||||
private Socket serverSocket;
|
||||
|
||||
/**
|
||||
* Creates new listener with the associated server
|
||||
* and listens on the given address
|
||||
*/
|
||||
this(DServer server, AddressInfo addressInfo)
|
||||
{
|
||||
super(&dequeueLoop);
|
||||
|
||||
/* Set the server */
|
||||
this.server = server;
|
||||
|
||||
// /* Get the Address */
|
||||
Address address = addressInfo.address;
|
||||
|
||||
|
||||
|
||||
gprintln("DListener: Hello there I am a new listener "~to!(string)(addressInfo));
|
||||
|
||||
|
||||
|
||||
/* TODO: Check AF_FAMILY (can only be INET,INET6,UNIX) */
|
||||
/* TODO: Check SocketType (can only be STREAM) */
|
||||
/* TODO: Check Protocol, can only be RAW (assuming UNIX) or TCP */
|
||||
/* address.addressFamily, addressInfo.type, addressInfo.protocol */
|
||||
|
||||
/* Create the Socket and bind it */
|
||||
serverSocket = new Socket(addressInfo);
|
||||
serverSocket.bind(address);
|
||||
gprintln("New listener started with address "~to!(string)(addressInfo));
|
||||
|
||||
/* Start the connection dequeue thread */
|
||||
//start();
|
||||
}
|
||||
|
||||
private void dequeueLoop()
|
||||
{
|
||||
gprintln("Starting dequeue loop...");
|
||||
|
||||
/* Start accepting-and-enqueuing connections */
|
||||
serverSocket.listen(0); /* TODO: Linux be lile, hehahahhahahah who gives one - I give zero */
|
||||
|
||||
while(true)
|
||||
{
|
||||
/* Dequeue a connection */
|
||||
gprintln("Awaiting a connection...");
|
||||
Socket socket = serverSocket.accept();
|
||||
gprintln("Dequeued a socket");
|
||||
|
||||
/* Spawn a connection handler */
|
||||
DConnection connection = new DConnection(server, socket);
|
||||
|
||||
/* Add to the connection queue */
|
||||
server.addConnection(connection);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* dplugin
|
||||
*
|
||||
* Represents a dplugin
|
||||
*
|
||||
* On initialization it connects over a UNIX domain socket
|
||||
* to the server and then the plugin can be used whenver it
|
||||
* needs to be (send and receive)
|
||||
*/
|
||||
|
||||
module dnetd.dplugin;
|
||||
|
||||
import dnetd.dserver;
|
||||
import std.socket;
|
||||
import bmessage;
|
||||
|
||||
public final class DPlugin
|
||||
{
|
||||
/* The associated server */
|
||||
private DServer server;
|
||||
|
||||
/* The UNIX domaion socket path */
|
||||
private string unixDomainSocketPath;
|
||||
|
||||
/**
|
||||
* Constructs a new DPugin associated with the
|
||||
* given server and with the intent to connect
|
||||
* to the UNIX domain socket at the path given
|
||||
*/
|
||||
this(DServer server, string unixDomainSocketPath)
|
||||
{
|
||||
this.server = server;
|
||||
this.unixDomainSocketPath = unixDomainSocketPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new session to the plugin server
|
||||
* then sends the data, awaits a reply, then
|
||||
* closes the session (connection)
|
||||
*/
|
||||
public byte[] sendPlugin(byte[] data)
|
||||
{
|
||||
/* The response */
|
||||
byte[] response;
|
||||
|
||||
/* The status */
|
||||
bool status;
|
||||
|
||||
/* Open a connection to the plugin server */
|
||||
Socket socket = new Socket(AddressFamily.UNIX, SocketType.STREAM, ProtocolType.RAW);
|
||||
socket.connect(new UnixAddress(unixDomainSocketPath));
|
||||
|
||||
/* Send the data */
|
||||
/* TODO: Error handling */
|
||||
status = sendMessage(socket, data);
|
||||
|
||||
/* Encode the status in the reply */
|
||||
response ~= [status];
|
||||
|
||||
/* If the send succeeded */
|
||||
if(status)
|
||||
{
|
||||
/* Get the reply */
|
||||
/* TODO: Error handling */
|
||||
byte[] reply;
|
||||
receiveMessage(socket, reply);
|
||||
|
||||
/* Close the connetion to the plugin server */
|
||||
socket.close();
|
||||
|
||||
/* Encode the response */
|
||||
response ~= reply;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -20,17 +20,11 @@ import std.stdio;
|
|||
import std.conv : to;
|
||||
import dnetd.dconfig;
|
||||
import dnetd.dlink;
|
||||
import dnetd.dlistener;
|
||||
import gogga;
|
||||
|
||||
public class DServer : Thread
|
||||
{
|
||||
/* The server's socket to bind, listen and accept connections from */
|
||||
private Socket serverSocket;
|
||||
|
||||
/* Bind address */
|
||||
private Address sockAddress;
|
||||
|
||||
|
||||
/* Server configuration */
|
||||
private DConfig config;
|
||||
|
||||
|
@ -51,17 +45,22 @@ public class DServer : Thread
|
|||
*/
|
||||
private DMeyer meyerSS;
|
||||
|
||||
/**
|
||||
* The listeners attached to this server
|
||||
*/
|
||||
private DListener[] listeners;
|
||||
|
||||
/* TODO: Implement new constructor */
|
||||
this(DConfig config)
|
||||
{
|
||||
/* Set the function to be called on thread start */
|
||||
super(&dequeueLoop);
|
||||
super(&startListeners);
|
||||
|
||||
/* Set the server's config */
|
||||
this.config = config;
|
||||
|
||||
/* Set the listening address */
|
||||
this.sockAddress = config.getGeneral().getAddress();
|
||||
/* Construct the listeners */
|
||||
initListeners(config.getGeneral().getAddresses());
|
||||
|
||||
/* Initialize the server */
|
||||
init();
|
||||
|
@ -70,6 +69,51 @@ public class DServer : Thread
|
|||
startServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of Address(es) this will construct all
|
||||
* the corresponding listsners (DListener) and append them
|
||||
* to the array
|
||||
*/
|
||||
private void initListeners(Address[] listenAddresses)
|
||||
{
|
||||
gprintln("Constructing "~to!(string)(listenAddresses.length)~" listsners...");
|
||||
|
||||
foreach(Address listenAddress; listenAddresses)
|
||||
{
|
||||
gprintln("Constructing listener for address '"~to!(string)(listenAddress)~"'");
|
||||
|
||||
import std.socket : AddressInfo;
|
||||
AddressInfo addrInfo;
|
||||
|
||||
/* Set the address (and port) to the current one along with address family */
|
||||
addrInfo.address = listenAddress;
|
||||
addrInfo.family = listenAddress.addressFamily;
|
||||
|
||||
/* Set standard (it will always be TCP and in stream access mode) */
|
||||
addrInfo.protocol = ProtocolType.TCP;
|
||||
addrInfo.type = SocketType.STREAM;
|
||||
|
||||
/* Construct the listener */
|
||||
listeners ~= new DListener(this, addrInfo);
|
||||
gprintln("Listener for '"~to!(string)(listenAddress)~"' constructed");
|
||||
}
|
||||
|
||||
gprintln("Listener construction complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all the listeners
|
||||
*/
|
||||
private void startListeners()
|
||||
{
|
||||
foreach(DListener listener; listeners)
|
||||
{
|
||||
/* Start the listener */
|
||||
gprintln("Starting listener "~to!(string)(listener)~"...");
|
||||
listener.start();
|
||||
}
|
||||
}
|
||||
|
||||
public DConfig getConfig()
|
||||
{
|
||||
return config;
|
||||
|
@ -77,9 +121,6 @@ public class DServer : Thread
|
|||
|
||||
private void init()
|
||||
{
|
||||
/* Setup socket */
|
||||
initNetwork();
|
||||
|
||||
/* Setup queues */
|
||||
initQueues();
|
||||
|
||||
|
@ -87,19 +128,6 @@ public class DServer : Thread
|
|||
initLocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the socket, binds it
|
||||
* to the given address
|
||||
*/
|
||||
private void initNetwork()
|
||||
{
|
||||
/* Create the socket */
|
||||
serverSocket = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
|
||||
|
||||
/* Bind the socket to the given address */
|
||||
serverSocket.bind(sockAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates all needed queues
|
||||
* and their mutexes
|
||||
|
@ -128,28 +156,10 @@ public class DServer : Thread
|
|||
/* Initialize the Meyer linking sub-system */
|
||||
meyerSS = new DMeyer(this);
|
||||
|
||||
/* Start the connection dequeue thread */
|
||||
/* Start the listener starter */
|
||||
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 */
|
||||
DConnection connection = new DConnection(this, socket);
|
||||
|
||||
/* Add to the connection queue */
|
||||
addConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
public void addChannel(DConnection causer, DChannel channel)
|
||||
{
|
||||
/* Lock the channels list */
|
||||
|
|
Loading…
Reference in New Issue