Compare commits

...

37 Commits

Author SHA1 Message Date
Tristan B. Kildaire f780df7c56 Typo fix 2021-01-28 16:28:54 +02:00
Tristan B. Kildaire d6a62713a2 Encode sender's username in direct messages 2021-01-28 16:18:33 +02:00
Tristan B. Kildaire 1c9168a6b8 PROTOCOL UPDATE
Type: NotificationMessage
Sub-type: Channel

Channel changes from 1->0

Direct messages are meant to be 1
2021-01-28 15:39:35 +02:00
Tristan B. Kildaire 32b3ca7661 Added missing sub-type to "New message" notification type 2021-01-28 15:21:23 +02:00
Tristan B. Kildaire fe2aef4c41 Fixed compilation issues 2021-01-28 14:52:36 +02:00
Tristan B. Kildaire a00acaa35e Later work on multiple sessions 2021-01-28 11:14:37 +02:00
Tristan B. Kildaire c7a4cfbadd Added TODO 2021-01-27 22:26:56 +02:00
Tristan B. Kildaire e10cf7bc23 Upgraded 2021-01-27 21:30:38 +02:00
Tristan B. Kildaire 164eee4f3f Code cleanup 2020-12-22 00:54:28 +02:00
Tristan B. Kildaire dc6efc50b7 Print out config on startup 2020-12-20 23:48:52 +02:00
Tristan B. Kildaire ce05d226ba Removed uneeded configuration key 2020-12-20 23:03:01 +02:00
Tristan B. Kildaire d860170429 Removed unused constructor 2020-12-20 22:04:59 +02:00
Tristan B. Kildaire a83f55cc49 Removed unecessary config keys 2020-12-20 19:43:59 +02:00
Tristan B. Kildaire bee016f521 Parse new listener blocks 2020-12-20 19:36:53 +02:00
Tristan B. Kildaire eee69dcbac Code cleanup 2020-12-20 18:15:02 +02:00
Tristan B. Kildaire 0da2a73226 Added missing `bind()` call to DListener 2020-12-20 18:12:11 +02:00
Tristan B. Kildaire 917402e974 The dserver now starts all constructed listeners 2020-12-20 17:47:15 +02:00
Tristan B. Kildaire 9e3da7d09f Removed sockets from dserver.d, sockets are now per each DListener 2020-12-20 17:44:22 +02:00
Tristan B. Kildaire 40cb881816 Code cleanliness 2020-12-20 17:42:23 +02:00
Tristan B. Kildaire aec29f0fd1 Added method, `construcListeners()`, to instantiate listeners 2020-12-20 17:39:56 +02:00
Tristan B. Kildaire b9513bae96 Merge branch 'listeners' into multiple_listeners 2020-12-20 17:22:18 +02:00
Tristan B. Kildaire 04ee591936 Return all addresses requested to bind to 2020-12-20 17:20:46 +02:00
Tristan B. Kildaire 325b37c5da ya 2020-12-04 19:11:41 +02:00
Tristan B. Kildaire f1ab9271dd Use fixed tristanable 2020-12-04 19:09:36 +02:00
Tristan B. Kildaire 66be270b61 Use bformat 3.1.0 2020-12-04 19:07:33 +02:00
Tristan B. Kildaire 1826276262 New bformat fucks up 2020-12-04 18:52:21 +02:00
Tristan B. Kildaire f77a61d96a Upgraded to new bformat 2020-12-04 18:40:44 +02:00
Tristan B. Kildaire d1e1297a26 Handle error 2020-12-04 14:11:55 +02:00
Tristan B. Kildaire cc95b8e2e9 Add listener array to server 2020-11-03 10:56:58 +02:00
Tristan B. Kildaire 727d42fa67 Added debug print for the address the listener's socket is bound to 2020-11-03 10:41:32 +02:00
Tristan B. Kildaire 2badd2d302 Now accepts incoming connections, adds them to the global queue and starts the handler for the new connection 2020-11-03 10:39:56 +02:00
Tristan B. Kildaire 616d063516 Add server instance 2020-11-03 10:37:49 +02:00
Tristan B. Kildaire 878a59920b Fixed compilation errors 2020-11-03 10:36:28 +02:00
Tristan B. Kildaire 41d758c46a Added dlistener.d 2020-11-03 10:34:58 +02:00
Tristan B. Kildaire a246ef1d73 WIP: Plugin system 2020-11-03 10:25:44 +02:00
Tristan B. Kildaire 6a679613cc Removed uneeded variable 2020-10-30 19:46:07 +02:00
Tristan B. Kildaire 10da3b093d Using gogga for debug prints in dchannel 2020-10-30 19:27:19 +02:00
9 changed files with 278 additions and 82 deletions

View File

@ -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" : ""
}
}
}
}

View File

@ -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",

View File

@ -1,7 +1,7 @@
{
"fileVersion": 1,
"versions": {
"bformat": "1.0.8",
"bformat": "3.1.0",
"gogga": "0.0.2",
"tristanable": "0.0.33"
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;

73
source/dnetd/dlistener.d Normal file
View File

@ -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);
}
}
}

80
source/dnetd/dplugin.d Normal file
View File

@ -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;
}
}

View File

@ -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 */