4
|
1 module dreactor.protocol.RawTcp;
|
|
2
|
|
3 import tango.io.Conduit;
|
|
4 import tango.io.selector.model.ISelector;
|
|
5 import tango.net.Socket;
|
|
6 import tango.util.collection.CircularSeq;
|
|
7 import tango.util.log.Log;
|
|
8 import tango.util.log.Config;
|
|
9
|
|
10 import dreactor.transport.AsyncSocketConduit;
|
|
11 import dreactor.core.SelectLoop;
|
|
12 import dreactor.core.ConnectionHandler;
|
|
13
|
|
14 /******************************************************************************
|
|
15
|
|
16 Basic TCP server or client routines for sending raw data.
|
|
17
|
|
18 ******************************************************************************/
|
|
19 class RawTCPListener
|
|
20 {
|
|
21 public
|
|
22 Logger log;
|
|
23 this(ConnectionHandler mgr, SelectLoop sel, IPv4Address addr)
|
|
24 {
|
|
25 manager = mgr;
|
|
26 mgr.events(Event.Read);
|
|
27 mgr.setOutgoingHandler(&Handlers.onSend);
|
|
28 mgr.setIncomingHandler(&Handlers.onReceive);
|
|
29 mgr.setConnectHandler(&accept);
|
|
30 mgr.listen(addr);
|
|
31
|
|
32 sel.addConnection(mgr);
|
|
33 select = sel;
|
|
34 log = Log.lookup("dreactor.protocol.RawTcpServer");
|
|
35 log.info("log initialized");
|
|
36 children = new CircularSeq!(ConnectionHandler);
|
|
37 }
|
|
38
|
|
39 int accept(Conduit cond, RegisterD reg)
|
|
40 {
|
|
41 AsyncSocketConduit newcond = new AsyncSocketConduit;
|
|
42 (cast(AsyncSocketConduit)cond).socket().accept(newcond.socket);
|
|
43 ConnectionHandler h = ConnectionHandler.New(newcond, manager);
|
|
44 h.events(Event.Read);
|
|
45 select.addConnection(h);
|
|
46 children.append(h);
|
|
47 log.info("accepted new connection");
|
|
48 return 0;
|
|
49 }
|
|
50
|
|
51 int broadcast(char[] outbuf)
|
|
52 {
|
|
53 foreach(ConnectionHandler h; children)
|
|
54 {
|
|
55 if (h.appendOutBuffer(outbuf))
|
|
56 {
|
|
57 h.addEvent(Event.Write);
|
|
58 select.addConnection(h);
|
|
59 }
|
|
60 }
|
|
61 return 0;
|
|
62 }
|
|
63
|
|
64 void close()
|
|
65 {
|
|
66
|
|
67 }
|
|
68
|
|
69 private
|
|
70 ConnectionHandler manager;
|
|
71 SelectLoop select;
|
|
72 CircularSeq!(ConnectionHandler) children;
|
|
73 }
|
|
74
|
|
75 class RawTCPClient
|
|
76 {
|
|
77 public
|
|
78 Logger log;
|
|
79 this(ConnectionHandler mgr, SelectLoop sel, Event evts = Event.Read)
|
|
80 {
|
|
81 manager = mgr;
|
|
82 manager.events(evts);
|
|
83 connected = false;
|
|
84 mgr.setOutgoingHandler(&Handlers.onSend);
|
|
85 mgr.setIncomingHandler(&Handlers.onReceive);
|
|
86 select = sel;
|
|
87 log = Log.lookup("dreactor.protocol.RawTcpClient");
|
|
88 }
|
|
89
|
|
90 int connect(IPv4Address addr)
|
|
91 {
|
|
92 (cast(AsyncSocketConduit) manager.transport()).connect(addr);
|
|
93 select.addConnection(manager);
|
|
94 connected = true;
|
|
95 log.info("connected to {}", addr);
|
|
96 return 0;
|
|
97 }
|
|
98
|
|
99 /**************************************************************************
|
|
100
|
|
101 send
|
|
102 User-called function to send data to the counterpart at the other
|
|
103 end of the connection. This sets up the connection manager to send
|
|
104 data as the socket becomes free.
|
|
105
|
|
106 **************************************************************************/
|
|
107 int send(char[] outbuf, IPv4Address addr = null)
|
|
108 {
|
|
109 log.info("sending buffer: {}", outbuf);
|
|
110 if (!connected)
|
|
111 {
|
|
112 log.info("not connected, connecting");
|
|
113 if (addr !is null)
|
|
114 {
|
|
115 if (0 > connect(addr))
|
|
116 {
|
|
117 log.error("unable to connect");
|
|
118 return -1;
|
|
119 }
|
|
120 }
|
|
121 }
|
|
122 if (manager.appendOutBuffer(outbuf))
|
|
123 {
|
|
124 manager.addEvent(Event.Write);
|
|
125 if (!select.addConnection(manager))
|
|
126 {
|
|
127 log.error("unable to register mgr");
|
|
128 }
|
|
129 }
|
|
130 return 0;
|
|
131 }
|
|
132
|
|
133 private
|
|
134 ConnectionHandler manager;
|
|
135 SelectLoop select;
|
|
136 bool connected;
|
|
137 }
|
|
138
|
|
139
|
|
140 /******************************************************************************
|
|
141
|
|
142 Default Event handlers common to both listener/clients
|
|
143
|
|
144 ******************************************************************************/
|
|
145 class Handlers
|
|
146 {
|
|
147 /**************************************************************************
|
|
148
|
|
149 onSend
|
|
150 OutgoingHandlerD
|
|
151 To be registered as the response to socket writable event.
|
|
152 Sends data, returns amount sent. Unregisters Handler for sending
|
|
153 if there is no more data left to send.
|
|
154
|
|
155 ***************************************************************************/
|
|
156 public static int onSend(ConnectionHandler h)
|
|
157 {
|
|
158 Logger log = Log.lookup("Handlers.onSend");
|
|
159
|
|
160 log.info("top of onSend");
|
|
161 char[] outbuf = h.nextBuffer();
|
|
162 if (outbuf !is null)
|
|
163 {
|
|
164 int sent = h.transport.write(outbuf);
|
|
165 if (sent > 0)
|
|
166 {
|
|
167 if (! h.addOffset(sent))
|
|
168 {
|
|
169 h.remEvent(Event.Write);
|
|
170 return REREGISTER;
|
|
171 }
|
|
172 }
|
|
173 else if (sent == AsyncSocketConduit.Eof)
|
|
174 {
|
|
175 log.error("Select said socket was writable, but sent 0 bytes");
|
|
176 }
|
|
177 else
|
|
178 {
|
|
179 log.error("Socket send return ERR");
|
|
180 }
|
|
181 return REMAIN;
|
|
182 }
|
|
183 else
|
|
184 {
|
|
185 h.remEvent(Event.Write);
|
|
186 return REREGISTER;
|
|
187 }
|
|
188 }
|
|
189 /**************************************************************************
|
|
190
|
|
191 receive
|
|
192 IncomingHandlerD
|
|
193 Default incoming data handler. Should be replaced with something useful.
|
|
194
|
|
195 **************************************************************************/
|
|
196 public static int onReceive(ConnectionHandler h)
|
|
197 {
|
|
198 Logger log = Log.lookup("Handlers.onReceive");
|
|
199
|
|
200 char inbuf[8192];
|
|
201 int amt;
|
|
202 if((amt = h.transport.read(inbuf)) > 0)
|
|
203 log.info("Received Buffer: {}", inbuf[0 .. amt]);
|
|
204 else
|
|
205 log.error("Received no data, err = {}", amt);
|
|
206
|
|
207 return REMAIN;
|
|
208 }
|
|
209 }
|