Skip to content

Commit

Permalink
sensible native error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
myeisha committed Jul 21, 2011
1 parent 9818bfc commit bec3ac4
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 82 deletions.
76 changes: 76 additions & 0 deletions src/Manos.IO/Manos.IO.Libev/Errors.cs
@@ -1,5 +1,7 @@
using System;
using Mono.Unix.Native;
using System.Net.Sockets;
using System.IO;

namespace Manos.IO.Libev
{
Expand All @@ -9,6 +11,80 @@ public static string ErrorToString (int errno)
{
return Syscall.strerror (NativeConvert.ToErrno (errno));
}

public static SocketError? ErrorToSocketError (int errno)
{
var err = NativeConvert.ToErrno (errno);
switch (err) {
case Errno.EAFNOSUPPORT:
return SocketError.AddressFamilyNotSupported;

case Errno.EMFILE:
case Errno.ENFILE:
return SocketError.TooManyOpenSockets;

case Errno.EPROTONOSUPPORT:
return SocketError.ProtocolNotSupported;

case Errno.EPROTOTYPE:
return SocketError.ProtocolType;

case Errno.EOPNOTSUPP:
return SocketError.OperationNotSupported;

case Errno.ENOTCONN:
return SocketError.NotConnected;

case Errno.EADDRINUSE:
return SocketError.AddressAlreadyInUse;

case Errno.EADDRNOTAVAIL:
return SocketError.AddressNotAvailable;

case Errno.EISCONN:
return SocketError.IsConnected;

case Errno.ECONNRESET:
return SocketError.ConnectionReset;

case Errno.ENETDOWN:
return SocketError.NetworkDown;

case Errno.EHOSTUNREACH:
return SocketError.HostUnreachable;

case Errno.ENETUNREACH:
return SocketError.NetworkUnreachable;

case Errno.EALREADY:
return SocketError.AlreadyInProgress;

case Errno.ECONNREFUSED:
return SocketError.ConnectionRefused;

case Errno.ETIMEDOUT:
return SocketError.TimedOut;

default:
return null;
}
}

public static IOException SocketStreamFailure (string text, int errno)
{
var err = ErrorToSocketError (errno);
if (err != null) {
return new IOException (text, new Manos.IO.SocketException (err.Value));
} else {
return new IOException (text, new InvalidOperationException (ErrorToString (errno)));
}
}

public static Manos.IO.SocketException SocketFailure (string text, int errno)
{
var err = ErrorToSocketError (errno);
return new Manos.IO.SocketException (text, err ?? SocketError.Fault);
}
}
}

6 changes: 3 additions & 3 deletions src/Manos.IO/Manos.IO.Libev/EventedStream.cs
Expand Up @@ -156,10 +156,9 @@ public override void Write (IEnumerable<TFragment> data)
base.Write (data);
ResumeWriting ();
}

public override void Close ()
protected override void Dispose(bool disposing)
{
base.Close ();
if (Handle != IntPtr.Zero) {
PauseReading ();
PauseWriting ();
Expand All @@ -179,6 +178,7 @@ public override void Close ()

Handle = IntPtr.Zero;
}
base.Dispose (disposing);
}

protected override void RaiseData (TFragment data)
Expand Down
20 changes: 15 additions & 5 deletions src/Manos.IO/Manos.IO.Libev/FileStream.cs
Expand Up @@ -47,14 +47,14 @@ class FileStream : FragmentStream<ByteBuffer>, IByteStream
public override bool CanSeek {
get { return true; }
}

public override void Close ()
protected override void Dispose (bool disposing)
{
if (Handle != IntPtr.Zero) {
Syscall.close (Handle.ToInt32 ());
Handle = IntPtr.Zero;
}
base.Close ();
base.Dispose (disposing);
}

public override void SeekBy (long delta)
Expand Down Expand Up @@ -85,6 +85,8 @@ public override void Write (IEnumerable<ByteBuffer> data)

public void Write (byte[] data)
{
CheckDisposed ();

Write (new ByteBuffer (data));
}

Expand All @@ -102,6 +104,8 @@ public override void ResumeReading ()

public override void ResumeReading (long forBytes)
{
CheckDisposed ();

if (!canRead)
throw new InvalidOperationException ();
if (forBytes < 0) {
Expand All @@ -117,6 +121,8 @@ public override void ResumeReading (long forBytes)

public override void ResumeWriting ()
{
CheckDisposed ();

if (!canWrite)
throw new InvalidOperationException ();

Expand All @@ -128,11 +134,15 @@ public override void ResumeWriting ()

public override void PauseReading ()
{
CheckDisposed ();

readEnabled = false;
}

public override void PauseWriting ()
{
CheckDisposed ();

writeEnabled = false;
}

Expand All @@ -150,7 +160,7 @@ void OnReadDone (int result, byte[] buffer, int error)
{
if (result < 0) {
PauseReading ();
RaiseError (new Exception (string.Format ("Error '{0}' reading from file '{1}'", error, Handle.ToInt32 ())));
RaiseError (new IOException (string.Format ("Error reading from file: {0}", Errors.ErrorToString (error))));
} else if (result > 0) {
position += result;
byte [] newBuffer = new byte [result];
Expand Down Expand Up @@ -193,7 +203,7 @@ protected override WriteResult WriteSingleFragment (ByteBuffer buffer)
void OnWriteDone (int result, int error)
{
if (result < 0) {
throw new Exception (string.Format ("Error '{0}' writing to file '{1}'", error, Handle.ToInt32 ()));
RaiseError (new IOException (string.Format ("Error writing to file: {0}", Errors.ErrorToString (error))));
}
HandleWrite ();
}
Expand Down
41 changes: 30 additions & 11 deletions src/Manos.IO/Manos.IO.Libev/IPSocket.cs
Expand Up @@ -16,7 +16,7 @@ protected IPSocket (Context context, AddressFamily addressFamily, ProtocolFamily
int err;
fd = SocketFunctions.manos_socket_create ((int) addressFamily, (int) protocolFamily, out err);
if (fd < 0) {
throw new Exception ();
throw Errors.SocketFailure ("Could not create socket", err);
}
}

Expand All @@ -28,12 +28,14 @@ protected IPSocket (Context context, AddressFamily addressFamily, int fd)

public override IPEndPoint LocalEndpoint {
get {
CheckDisposed ();

if (localname == null) {
int err;
ManosIPEndpoint ep;
err = SocketFunctions.manos_socket_localname_ip (fd, out ep, out err);
var result = SocketFunctions.manos_socket_localname_ip (fd, out ep, out err);
if (err != 0) {
throw new Exception ();
throw Errors.SocketFailure ("Could not get local address", err);
}
localname = ep;
}
Expand All @@ -43,12 +45,14 @@ protected IPSocket (Context context, AddressFamily addressFamily, int fd)

public override IPEndPoint RemoteEndpoint {
get {
CheckDisposed ();

if (peername == null) {
int err;
ManosIPEndpoint ep;
err = SocketFunctions.manos_socket_peername_ip (fd, out ep, out err);
var result = SocketFunctions.manos_socket_peername_ip (fd, out ep, out err);
if (err != 0) {
throw new Exception ();
throw Errors.SocketFailure ("Could not get remote address", err);
}
peername = ep;
}
Expand All @@ -62,21 +66,36 @@ protected IPSocket (Context context, AddressFamily addressFamily, int fd)

public override void Bind (IPEndPoint endpoint)
{
CheckDisposed ();

if (endpoint == null)
throw new ArgumentNullException ("endpoint");

int err;
ManosIPEndpoint ep = endpoint;
err = SocketFunctions.manos_socket_bind_ip (fd, ref ep, out err);
var result = SocketFunctions.manos_socket_bind_ip (fd, ref ep, out err);
if (err != 0) {
throw new Exception ();
throw Errors.SocketFailure ("Could not bind to address", err);
} else {
localname = endpoint;
}
IsBound = true;
}

protected void CheckDisposed ()
{
if (fd == 0)
throw new ObjectDisposedException (GetType ().ToString ());
}

public override void Close ()
protected override void Dispose (bool disposing)
{
int err;
SocketFunctions.manos_socket_close (fd, out err);
base.Close ();
if (fd != 0) {
int err;
SocketFunctions.manos_socket_close (fd, out err);
fd = 0;
}
base.Dispose (disposing);
}
}
}
Expand Down

0 comments on commit bec3ac4

Please sign in to comment.