A few minor error handling improvements for unusual situations.
[versaplex.git] / wvdotnet / wvsockstream.cs
blob9e2182acb7c750005c54ae3561f300c7b01b9c5c
1 using System;
2 using System.Collections.Generic;
3 using System.Net;
4 using System.Net.Sockets;
5 using Mono.Unix;
6 using Wv;
8 namespace Wv
10 public class WvSockStream : WvStream
12 Socket _sock = null;
13 protected Socket sock {
14 get {
15 return _sock;
17 set {
18 _sock = value;
19 if (_sock != null)
20 _sock.Blocking = false;
24 public override bool ok {
25 get { return (sock != null) && base.ok; }
28 public WvSockStream(Socket sock)
30 this.sock = sock;
33 public override EndPoint localaddr {
34 get {
35 if (!ok)
36 return null;
37 return sock.LocalEndPoint;
41 public override EndPoint remoteaddr {
42 get {
43 if (!ok)
44 return null;
45 return sock.RemoteEndPoint;
49 public override int read(WvBytes b)
51 if (!ok)
52 return 0;
54 try
56 int ret = sock.Receive(b.bytes, b.start, b.len, 0);
57 if (ret <= 0) // EOF
59 nowrite();
60 noread();
61 return 0;
63 else
64 return ret;
66 catch (SocketException e)
68 if (e.ErrorCode == 10004) // EINTR is normal when non-blocking
69 return 0;
70 else if (e.ErrorCode == 10035) // EWOULDBLOCK too
71 return 0;
72 else
74 err = e;
75 // err = new Exception(wv.fmt("Error code {0}\n", e.ErrorCode));
77 return 0;
81 public override int write(WvBytes b)
83 if (!ok)
84 return 0;
86 try
88 int ret = sock.Send(b.bytes, b.start, b.len, 0);
89 if (ret < 0) // Unexpected error
91 err = new Exception(wv.fmt("Write error #{0}", ret));
92 return 0;
94 else
95 return ret;
97 catch (SocketException e)
99 if (e.ErrorCode == 10004) // EINTR is normal when non-blocking
100 return 0;
101 else if (e.ErrorCode == 10035) // EWOULDBLOCK too
102 return 0;
103 else
105 err = e;
106 // err = new Exception(wv.fmt("Error code {0}\n", e.ErrorCode));
108 return 0;
112 public override event Action onreadable {
113 add { base.onreadable += value;
114 if (ok) ev.onreadable(sock, do_readable); }
115 remove { base.onreadable -= value;
116 if (!can_onreadable) ev.onreadable(sock, null); }
119 public override event Action onwritable {
120 add { base.onwritable += value;
121 if (ok) ev.onwritable(sock, do_writable); }
122 remove { base.onwritable -= value;
123 if (!can_onwritable) ev.onwritable(sock, null); }
126 void tryshutdown(SocketShutdown sd)
130 sock.Shutdown(sd);
132 catch (SocketException)
134 // ignore
138 public override bool wait(int msec_timeout,
139 bool readable, bool writable)
141 foreach (int remain in wv.until(msec_timeout))
143 if (!ok)
144 return false;
145 if (!readable && !writable)
146 wv.sleep(remain);
147 else
149 var rlist = new List<Socket>();
150 var wlist = new List<Socket>();
151 if (readable)
152 rlist.Add(sock);
153 if (writable)
154 wlist.Add(sock);
155 Socket.Select(rlist, wlist, null, remain * 1000);
157 if (rlist.Count > 0 || wlist.Count > 0)
158 return true;
162 return false;
165 public override void noread()
167 base.noread();
168 if (sock != null)
169 tryshutdown(SocketShutdown.Receive);
170 ev.onreadable(sock, null);
173 public override void nowrite()
175 base.nowrite();
176 if (sock != null)
177 tryshutdown(SocketShutdown.Send);
178 ev.onwritable(sock, null);
181 public override void close()
183 base.close();
184 if (sock != null)
186 try {
187 ev.onreadable(sock, null);
188 ev.onwritable(sock, null);
189 tryshutdown(SocketShutdown.Both);
190 sock.Close();
191 ((IDisposable)sock).Dispose();
193 finally {
194 sock = null;
200 public class WvTcp : WvSockStream
202 public WvTcp(string remote, ushort port) : base(null)
204 // FIXME: do DNS lookups asynchronously?
207 IPHostEntry ipe = Dns.GetHostEntry(remote);
208 IPEndPoint ipep = new IPEndPoint(ipe.AddressList[0], port);
209 Socket sock = new Socket(AddressFamily.InterNetwork,
210 SocketType.Stream,
211 ProtocolType.Tcp);
212 sock.Connect(ipep);
213 this.sock = sock;
215 catch (Exception e)
217 err = e;
222 public class WvUnix : WvSockStream
224 public WvUnix(string path) : base(null)
226 EndPoint ep;
228 if (path.StartsWith("@"))
229 ep = new AbstractUnixEndPoint(path.Substring(1));
230 else
231 ep = new UnixEndPoint(path);
233 Socket sock = new Socket(AddressFamily.Unix,
234 SocketType.Stream, 0);
235 sock.Connect(ep);
236 this.sock = sock;