Zoadian

D-Networking-API

Jun 19th, 2012
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 7.11 KB | None | 0 0
  1. /**
  2.  * A Very Simple Socket Wrapper.
  3.  * It splits a TCP-Stream into 'Messages'
  4.  * which are ubyte[] with a specific length.
  5.  * each message currently has an overhead of 9byte.
  6.  *
  7.  * TODO: add checks for isAlive
  8.  */
  9. module net;
  10.  
  11. import std.socket;
  12. import std.conv;
  13. import std.stdio;
  14.     import std.range;
  15.     import std.traits;
  16.     import std.typecons;
  17.     import std.typetuple;
  18. import std.variant;
  19.     import std.algorithm;
  20. import std.md5;
  21.  
  22. ubyte[16u] uniqueId(T)() {
  23.     ubyte[16u] digest;
  24.     sum(digest, T.mangleof);
  25.     return digest;
  26. }
  27.  
  28. class Server {
  29. private:
  30.     TcpSocket _socket;
  31.     Connection[] _connections;
  32.    
  33. public:
  34.     this(ushort port) {
  35.         writeln("start server");
  36.         this._socket = new TcpSocket();
  37.         writeln("bind server");
  38.         this._socket.bind(new InternetAddress(port));
  39.         writeln("listen server");
  40.         this._socket.listen(1);
  41.         writeln("setblcking server");
  42.         this._socket.blocking = false;
  43.         writeln("alive server");
  44.         assert(this._socket.isAlive);
  45.     }
  46.    
  47.     ~this() {
  48.         this.close();
  49.     }
  50.    
  51.     void close() {
  52.         assert(this._socket.isAlive);
  53.         this._socket.shutdown(SocketShutdown.BOTH);
  54.         this._socket.close();
  55.     }
  56.    
  57.     @property Connection[] connections() {
  58.         return this._connections;
  59.     }
  60.    
  61.     void update() {
  62.         assert(this._socket.isAlive);
  63.         try {
  64.             Socket socket = this._socket.accept();
  65.             if(socket is null || !socket.isAlive)
  66.                 return;
  67.             auto con = new Connection();
  68.             this._connections ~= con;
  69.             con._socket = socket;
  70.             writeln("new socket");
  71.         } catch(SocketAcceptException e) {
  72.             //writeln("socket accept error");
  73.         }
  74.     }
  75. }
  76.  
  77. class Connection {
  78.     alias ubyte[] Message;
  79.     Socket _socket;
  80.     ubyte[] _buffer;
  81.    
  82.     string[] _localMap;
  83.     string[] _remoteMap;
  84.    
  85. public:
  86.     static Connection connect(Address addr) {
  87.         auto con = new Connection();
  88.         con._socket = new TcpSocket(addr);
  89.         assert(con._socket.isAlive);
  90.         con._socket.blocking = false;        
  91.         return con;
  92.     }
  93.    
  94.     ~this() {
  95.         this.close();
  96.     }
  97.    
  98.     void close() {
  99.         assert(this._socket.isAlive);
  100.         this._socket.shutdown(SocketShutdown.BOTH);
  101.         this._socket.close();
  102.     }
  103.    
  104.     alias ulong MangleLenType;
  105.    
  106.     enum MsgType : ubyte {
  107.         PublishType,
  108.         SendMsg
  109.     }
  110.    
  111. public:
  112.     final void send(T)(T msg) {
  113.         assert(this._socket.isAlive);
  114.         auto pos = this._localMap.countUntil(T.mangleof);
  115.         if(pos == -1) {
  116.             //publish type first
  117.             this._localMap ~= T.mangleof;
  118.             MangleLenType mangleLen = T.mangleof.length;
  119.             this._socket.send(
  120.                 MsgType.PublishType ~
  121.                 *cast(ubyte[MangleLenType.sizeof]*)&mangleLen ~
  122.                 cast(ubyte[])T.mangleof
  123.             );
  124.             pos = this._localMap.length-1;
  125.             debug {                
  126.                 writeln(
  127.                 "sent: ",MsgType.PublishType ~
  128.                 *cast(ubyte[MangleLenType.sizeof]*)&mangleLen ~
  129.                 cast(ubyte[])T.mangleof
  130.                 );
  131.             }
  132.         }
  133.        
  134.         //send msg
  135.         uint msgLen = msg.length;
  136.         this._socket.send(
  137.             MsgType.SendMsg ~
  138.             *cast(ubyte[uint.sizeof]*)&pos ~
  139.             *cast(ubyte[uint.sizeof]*)&msgLen ~
  140.             cast(ubyte[])msg
  141.         );
  142.     }
  143.    
  144.     final void receive(T...)(scope T vals ) {
  145.         assert(this._socket.isAlive);  
  146.         static assert(T.length, "receive needs at least one function.");
  147.         alias TypeTuple!(T) Ops;
  148.         alias vals[0 .. $] ops;
  149.        
  150.         //get all bytes from socket and store in this._buffer
  151.         assert(this._socket.isAlive);
  152.         ubyte[1024] buf;
  153.         ptrdiff_t len;
  154.         while((len = this._socket.receive(buf)) > 0) {
  155.             this._buffer ~= buf[0..len];
  156.         }
  157.        
  158.         //enough buffer to decode a MsgType?
  159.         if(this._buffer.length < MsgType.sizeof)
  160.             return;
  161.        
  162.         MsgType msgType = *cast(MsgType*)this._buffer[0 .. MsgType.sizeof].ptr;
  163.         final switch(msgType) {
  164.         case MsgType.PublishType:
  165.             //enough buffer to decode mangleLen?
  166.             if(this._buffer.length < MsgType.sizeof + MangleLenType.sizeof)
  167.                 return;
  168.            
  169.             MangleLenType mangleLen = *cast(MangleLenType*)this._buffer[MsgType.sizeof .. MsgType.sizeof + MangleLenType.sizeof].ptr;
  170.            
  171.             //enough buffer to decode mangle?
  172.             if(this._buffer.length < MsgType.sizeof + MangleLenType.sizeof + cast(size_t)mangleLen)
  173.                 return;
  174.            
  175.             string mangle = cast(string)this._buffer[MsgType.sizeof + MangleLenType.sizeof .. MsgType.sizeof + MangleLenType.sizeof + cast(size_t)mangleLen];
  176.            
  177.             this._remoteMap ~= mangle;
  178.             this._buffer = this._buffer[MsgType.sizeof + MangleLenType.sizeof + cast(size_t)mangleLen .. $];          
  179.            
  180.             break;
  181.         case MsgType.SendMsg:
  182.             //enough buffer to decode typeID
  183.             if(this._buffer.length < MsgType.sizeof + uint.sizeof)
  184.                 return;
  185.            
  186.             uint pos = *cast(uint*)this._buffer[MsgType.sizeof .. MsgType.sizeof + uint.sizeof].ptr;
  187.             assert(pos < this._remoteMap.length, "could not find mangleof in _remoteMap."); //TODO: add that check in release?!
  188.        
  189.             string mangle = this._remoteMap[pos];
  190.            
  191.             foreach( i, t; Ops ) {
  192.                 alias ParameterTypeTuple!(t) Args;
  193.                 auto op = ops[i];
  194.                
  195.                 static if( Args.length == 1 ) {
  196.                     if(Args[0].mangleof == mangle) {
  197.                        
  198.                         //enough buffer to decode msgLen?
  199.                         if(this._buffer.length < MsgType.sizeof + uint.sizeof + uint.sizeof)
  200.                             return;
  201.                        
  202.                         uint msgLen = *cast(uint*)this._buffer[MsgType.sizeof + uint.sizeof .. MsgType.sizeof + uint.sizeof + uint.sizeof].ptr;
  203.                        
  204.                         //enough buffer to decode msg?
  205.                         if(this._buffer.length < MsgType.sizeof + uint.sizeof + uint.sizeof + msgLen)
  206.                             return;
  207.                        
  208.                         auto msg = *cast(Args[0]*)this._buffer[MsgType.sizeof + uint.sizeof + uint.sizeof .. MsgType.sizeof + uint.sizeof + uint.sizeof + msgLen].ptr;
  209.                         this._buffer = this._buffer[MsgType.sizeof + uint.sizeof + uint.sizeof + msgLen .. $];
  210.                        
  211.                         op(msg);
  212.                     }
  213.                 }
  214.                 else
  215.                     static assert(false, "Only one Parameter supported in receive functions.");
  216.             }                
  217.            
  218.             break;
  219.         }
  220.     }
  221. }
Advertisement
Add Comment
Please, Sign In to add comment