From 92ffadf6e0e6f117bc493aa89dd1f29941fce489 Mon Sep 17 00:00:00 2001 From: Tom Lint Date: Tue, 22 Jul 2014 17:02:45 +0200 Subject: [PATCH] Fixed String operator[] signature Partially implemented Socket and SocketAsyncEventArgs --- include/System/Net/Sockets/Socket.h | 18 +- .../System/Net/Sockets/SocketAsyncEventArgs.h | 10 + include/System/String.h | 2 +- include/System/Threading/Interlocked.h | 18 +- src/libSystem/Socket.cpp | 265 +++++++++++++++++- src/libSystem/SocketAsyncEventArgs.cpp | 80 +++++- src/libmscorlib/String.cpp | 2 +- 7 files changed, 353 insertions(+), 42 deletions(-) diff --git a/include/System/Net/Sockets/Socket.h b/include/System/Net/Sockets/Socket.h index ab5f5d5..0683d81 100644 --- a/include/System/Net/Sockets/Socket.h +++ b/include/System/Net/Sockets/Socket.h @@ -29,13 +29,13 @@ namespace System { private: AddressFamily_t addressFamily; + /* true if we called Close_internal */ + bool closed; HANDLE handle; bool isConnected; ProtocolType_t protocolType; protected: - virtual ~Socket(); - void Dispose(bool disposing); public: @@ -43,6 +43,7 @@ namespace System int Available() const; bool Connected() const; HANDLE getHandle() const; + static bool OSSupportsIPv4(); ProtocolType_t getProtocolType() const; int ReceiveBufferSize; EndPoint* getRemoteEndPoint() const; @@ -50,20 +51,21 @@ namespace System short Ttl; Socket(AddressFamily_t addressFamily, SocketType_t socketType, ProtocolType_t protocolType); + virtual ~Socket(); - static void CancelConnectAsync(SocketAsyncEventArgs e); + static void CancelConnectAsync(SocketAsyncEventArgs * const e); void Close(); void Close(int timeOut); static bool ConnectAsync(SocketType_t socketType, ProtocolType_t protocolType, SocketAsyncEventArgs e); - bool ConnectAsync(SocketAsyncEventArgs e); + bool ConnectAsync(SocketAsyncEventArgs * const e); void Dispose(); void EndConnect(IAsyncResult * asyncResult); void EndDisconnect(IAsyncResult * asyncResult); static const Type& GetType(); - bool ReceiveAsync(SocketAsyncEventArgs e); - bool ReceiveFromAsync(SocketAsyncEventArgs e); - bool SendAsync(SocketAsyncEventArgs e); - bool SendToAsync(SocketAsyncEventArgs e); + bool ReceiveAsync(SocketAsyncEventArgs * const e); + bool ReceiveFromAsync(SocketAsyncEventArgs * const e); + bool SendAsync(SocketAsyncEventArgs * const e); + bool SendToAsync(SocketAsyncEventArgs * const e); void Shutdown(SocketShutdown_t how); }; } diff --git a/include/System/Net/Sockets/SocketAsyncEventArgs.h b/include/System/Net/Sockets/SocketAsyncEventArgs.h index 6d844bc..a7c95dd 100644 --- a/include/System/Net/Sockets/SocketAsyncEventArgs.h +++ b/include/System/Net/Sockets/SocketAsyncEventArgs.h @@ -23,8 +23,17 @@ namespace System class SocketAsyncEventArgs : public EventArgs, public IDisposable { private: + int count; + Socket* curSocket; + int inProgress; + bool isDisposed; + SocketAsyncOperation_t lastOperation; + int offset; friend class Socket; + void SetBufferInternal(byte buffer[], int offset, int count); + void SetLastOperation(SocketAsyncOperation_t op); + protected: virtual void Oncompleted(SocketAsyncEventArgs* e); virtual ~SocketAsyncEventArgs(); @@ -44,6 +53,7 @@ namespace System EventHandler Completed; SocketAsyncEventArgs(); + ~SocketAsyncEventArgs(); void Dispose(); static const Type& GetType(); diff --git a/include/System/String.h b/include/System/String.h index 1de95fa..4f14889 100644 --- a/include/System/String.h +++ b/include/System/String.h @@ -91,7 +91,7 @@ namespace System String operator+=(const String& right); String operator+=(const char* right); String operator+(const String& right) const; - const char operator [](const int index) const; + const char& operator[](const int index) const; }; inline const String operator +(const char * left, const String& right) diff --git a/include/System/Threading/Interlocked.h b/include/System/Threading/Interlocked.h index d763370..0086964 100644 --- a/include/System/Threading/Interlocked.h +++ b/include/System/Threading/Interlocked.h @@ -17,7 +17,7 @@ namespace System // The value to be added to the integer at location1. // Returns // The new value stored at location1. - static inline int Add(volatile long* const location1, const long value) + static inline int Add(volatile int* const location1, const int value) { long retval = value; __asm__("lock; xaddl %[retval], %[location1]" : [retval] "+r" (retval) : [location1] "m" (*location1) : "memory"); @@ -49,9 +49,9 @@ namespace System // The value that is compared to the value at location1. // Returns // The original value in location1. - static inline Int64 CompareExchange(volatile Int64* const Int64 location1, const Int64 value, const Int64 comparand) + static inline long long CompareExchange(volatile long long* const location1, const long long value, const long long comparand) { - Int64 retval = comparand; + long long retval = comparand; __asm__ ( @@ -87,21 +87,21 @@ namespace System // The variable whose value is to be decremented. // Returns // The decremented value. - static inline long Decrement(volatile long * const location) + static inline long Decrement(volatile int * const location) { return Add(location, -1) - 1; } // Sets a 32-bit signed integer to a specified value and returns the original value, as an atomic operation. // location1 - // The variable to set to the specified value. + // The variable to set to the specified value. // value - // The value to which the location1 parameter is set. + // The value to which the location1 parameter is set. // Returns // The original value of location1. - static inline long Exchange(volatile long* const location1, const long value) + static inline int Exchange(volatile int * const location1, const int value) { - long retval = value; + int retval = value; __asm__("xchgl %[retval], %[location1]" : [retval] "+r" (retval) : [location1] "m" (*location1) : "memory"); return retval; } @@ -125,7 +125,7 @@ namespace System // The variable whose value is to be incremented. // Returns // The incremented value. - static inline long Increment(volatile long * const location) + static inline int Increment(volatile int * const location) { return Add(location, 1) + 1; } diff --git a/src/libSystem/Socket.cpp b/src/libSystem/Socket.cpp index 6ac5ea3..5df2516 100644 --- a/src/libSystem/Socket.cpp +++ b/src/libSystem/Socket.cpp @@ -57,7 +57,7 @@ namespace System bool Socket::Connected() const { - // TODO: implement + return isConnected; } HANDLE Socket::getHandle() const @@ -67,11 +67,16 @@ namespace System ProtocolType_t Socket::getProtocolType() const { - // TODO: implement + return protocolType; + } + + EndPoint* Socket::getRemoteEndPoint() const + { + } Socket::Socket(AddressFamily_t addressFamily, SocketType_t socketType, ProtocolType_t protocolType) - : addressFamily(addressFamily) + : addressFamily(addressFamily), protocolType(protocolType) { // TODO: implement remainder } @@ -91,9 +96,17 @@ namespace System // TODO: implement } - bool Socket::ConnectAsync(SocketAsyncEventArgs e) + bool Socket::ConnectAsync(SocketAsyncEventArgs * const e) { - // TODO: implement + // NO check is made whether e != null in MS.NET (NRE is thrown in such case) + if (disposed && closed) + { + throw new ObjectDisposedException(GetType().ToString()); + } + + sassert(e->RemoteEndPoint != null, String::Format("remoteEP: %s", FrameworkResources::ArgumentNull_Generic)); + + return ConnectAsyncReal(e); } void Socket::Dispose() @@ -103,12 +116,55 @@ namespace System void Socket::EndConnect(IAsyncResult* asyncResult) { - // TODO: implement + sassert(!disposed || !closed, ""); + + sassert(asyncResult != null, String::Format("asyncResult: %s", FrameworkResources::ArgumentNull_Generic)); + + SocketAsyncResult * req = as(asyncResult); + + sassert(req != null, "Invalid IAsyncResult"); + + if (Interlocked::CompareExchange(&req.EndCalled, 1, 0) == 1) + { + throw InvalidAsyncOp("EndConnect"); + } + + if (!asyncResult->IsCompleted()) + { + asyncResult->AsyncWaitHandle.WaitOne(); + } + + req.CheckIfThrowDelayedException(); } void Socket::EndDisconnect(IAsyncResult* asyncResult) { - // TODO: implement + if (disposed && closed) + { + throw new ObjectDisposedException(GetType ().ToString ()); + } + + if (asyncResult == null) + { + throw new ArgumentNullException("asyncResult"); + } + + SocketAsyncResult * req = as(asyncResult); + + if (req == null) + throw new ArgumentException ("Invalid IAsyncResult", "asyncResult"); + + if (Interlocked::CompareExchange(&req.EndCalled, 1, 0) == 1) + { + throw InvalidAsyncOp("EndDisconnect"); + } + + if (!asyncResult->IsCompleted()) + { + asyncResult->AsyncWaitHandle.WaitOne(); + } + + req->CheckIfThrowDelayedException(); } const Type& Socket::GetType() @@ -116,29 +172,208 @@ namespace System return SocketTypeInfo; } - bool Socket::ReceiveAsync(SocketAsyncEventArgs e) + bool Socket::ReceiveAsync(SocketAsyncEventArgs * const e) { - // TODO: implement + // NO check is made whether e != null in MS.NET (NRE is thrown in such case) + if (disposed && closed) + { + throw new ObjectDisposedException(GetType ().ToString ()); + } + + // LAME SPEC: the ArgumentException is never thrown, instead an NRE is + // thrown when e.Buffer and e.BufferList are null (works fine when one is + // set to a valid object) + if (e->getBuffer() == null && e->BufferList == null) + { + throw new NullReferenceException ("Either e.Buffer or e.BufferList must be valid buffers."); + } + + e->curSocket = this; + SocketOperation op = (e->getBuffer() != null) ? SocketOperation::Receive : SocketOperation::ReceiveGeneric; + e->Worker.Init (this, e, op); + SocketAsyncResult res = e->Worker.result; + + if (e->getBuffer() != null) + { + res.Buffer = e->getBuffer(); + res.Offset = e->getOffset(); + res.Size = e->Count(); + } + else + { + res.Buffers = e->BufferList; + } + + res.SockFlags = e->SocketFlags; + int count; + + lock (readQ) + { + readQ.Enqueue(e->Worker); + count = readQ.Count; + } + + if (count == 1) + { + // Receive takes care of ReceiveGeneric + socket_pool_queue(Worker.Dispatcher, res); + } + + return true; } - bool Socket::ReceiveFromAsync(SocketAsyncEventArgs e) + bool Socket::ReceiveFromAsync(SocketAsyncEventArgs * const e) { - // TODO: implement + if (disposed && closed) + { + throw new ObjectDisposedException(GetType ().ToString ()); + } + + // We do not support recv into multiple buffers yet + if (e->getBufferList() != null) + { + throw new NotSupportedException("Mono doesn't support using BufferList at this point."); + } + + if (e->RemoteEndPoint == null) + { + throw new ArgumentNullException("remoteEP", "Value cannot be null."); + } + + e->curSocket = this; + e->Worker.Init(this, e, SocketOperation::ReceiveFrom); + SocketAsyncResult res = e->Worker.result; + res.Buffer = e->getBuffer(); + res.Offset = e->getOffset(); + res.Size = e->Count(); + res.EndPoint = e->RemoteEndPoint; + res.SockFlags = e->SocketFlags; + int count; + + lock (readQ) + { + readQ.Enqueue(e.Worker); + count = readQ.Count; + } + + if (count == 1) + { + socket_pool_queue (Worker.Dispatcher, res); + } + + return true; } - bool Socket::SendAsync(SocketAsyncEventArgs e) + bool Socket::SendAsync(SocketAsyncEventArgs * const e) { - // TODO: implement + // NO check is made whether e != null in MS.NET (NRE is thrown in such case) + if (disposed && closed) + { + throw new ObjectDisposedException (GetType ().ToString ()); + } + + if (e->getBuffer() == null && e->BufferList == null) + { + throw new NullReferenceException("Either e.Buffer or e.BufferList must be valid buffers."); + } + + e->curSocket = this; + SocketOperation op = (e->getBuffer() != null) ? SocketOperation::Send : SocketOperation::SendGeneric; + e->Worker.Init(this, e, op); + SocketAsyncResult res = e->Worker.result; + + if (e->getBuffer() != null) + { + res.Buffer = e->getBuffer(); + res.Offset = e->getOffset(); + res.Size = e->Count(); + } + else + { + res.Buffers = e->BufferList; + } + + res.SockFlags = e->SocketFlags; + int count; + + lock (writeQ) + { + writeQ.Enqueue(e.Worker); + count = writeQ.Count; + } + + if (count == 1) + { + // Send takes care of SendGeneric + socket_pool_queue(Worker.Dispatcher, res); + } + + return true; } - bool Socket::SendToAsync(SocketAsyncEventArgs e) + bool Socket::SendToAsync(SocketAsyncEventArgs * const e) { - // TODO: implement + // NO check is made whether e != null in MS.NET (NRE is thrown in such case) + if (disposed && closed) + { + throw new ObjectDisposedException (GetType().ToString()); + } + + if (e->BufferList != null) + { + throw new NotSupportedException ("Mono doesn't support using BufferList at this point."); + } + + if (e->RemoteEndPoint == null) + { + throw new ArgumentNullException("remoteEP", "Value cannot be null."); + } + + e->curSocket = this; + e->Worker.Init(this, e, SocketOperation::SendTo); + SocketAsyncResult res = e->Worker.result; + res.Buffer = e->getBuffer(); + res.Offset = e->getOffset(); + res.Size = e->Count; + res.SockFlags = e->SocketFlags; + res.EndPoint = e->RemoteEndPoint; + int count; + + lock (writeQ) + { + writeQ.Enqueue(e->Worker); + count = writeQ.Count; + } + + if (count == 1) + { + socket_pool_queue(Worker.Dispatcher, res); + } + + return true; } void Socket::Shutdown(SocketShutdown_t how) { + if (disposed && closed) + { + throw new ObjectDisposedException(GetType ().ToString ()); + } + + if (!isConnected) + { + throw new SocketException(10057); // Not connected + } + + int error; + // TODO: implement + Shutdown_internal(socket, how, out error); + + if (error != 0) + { + throw new SocketException(error); + } } } } diff --git a/src/libSystem/SocketAsyncEventArgs.cpp b/src/libSystem/SocketAsyncEventArgs.cpp index f85b9d7..99fd601 100644 --- a/src/libSystem/SocketAsyncEventArgs.cpp +++ b/src/libSystem/SocketAsyncEventArgs.cpp @@ -25,16 +25,21 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +#include #include #include +#include + +using namespace System::Threading; + namespace System { namespace Net { namespace Sockets { - const Type SocketAsyncEventArgsTypeInfo("SocketAsyncEventArgs", "SYstem::Net::Sockets::SocketAsyncEventArgs", TypeCode::Object); + const Type SocketAsyncEventArgsTypeInfo("SocketAsyncEventArgs", "System::Net::Sockets::SocketAsyncEventArgs", TypeCode::Object); byte * SocketAsyncEventArgs::getBuffer() const { @@ -48,36 +53,50 @@ namespace System Socket * SocketAsyncEventArgs::getConnectSocket() const { - // TODO: implement + switch (this->SocketError) + { + case SocketError::AccessDenied: + return null; + default: + return curSocket; + } } int SocketAsyncEventArgs::Count() const { - // TODO: implement + return count; } SocketAsyncOperation_t SocketAsyncEventArgs::getLastOperation() const { - // TODO: implement + return lastOperation; } int SocketAsyncEventArgs::getOffset() const { - // TODO: implement + return offset; } SocketAsyncEventArgs::SocketAsyncEventArgs() { + lastOperation = SocketAsyncOperation::None; + this->SocketError = SocketError::Success; + // TODO: implement } - SocketAsyncEventArgs::SocketAsyncEventArgs() + SocketAsyncEventArgs::~SocketAsyncEventArgs() { - // TODO: implement + if (!isDisposed) + { + // TODO: implement + } } void SocketAsyncEventArgs::Dispose() { + isDisposed = true; + // TODO: implement } @@ -86,10 +105,55 @@ namespace System return SocketAsyncEventArgsTypeInfo; } - void SocketAsyncEventArgs::Oncompleted(SocketAsyncEventArgs* e) + void SocketAsyncEventArgs::Oncompleted(SocketAsyncEventArgs * e) { + if (e == null) + { + return; + } + Completed(this, e); } + + void SocketAsyncEventArgs::SetBuffer(const int offset, const int count) + { + SetBufferInternal(getBuffer(), offset, count); + } + + void SocketAsyncEventArgs::SetBuffer(byte buffer[], const int offset, const int count) + { + SetBufferInternal(buffer, offset, count); + } + + void SocketAsyncEventArgs::SetBufferInternal(byte buffer[], int offset, int count) + { + if (buffer != null) + { + sassert(getBufferList() != null, "Buffer and BufferList properties cannot both be non-null."); + + int buflen = buffer.Length; + + sassert(offset >= 0 && offset < buflen, ""); + //throw new ArgumentOutOfRangeException("offset"); + + sassert(count >= 0 && count <= buflen - offset, ""); + //throw new ArgumentOutOfRangeException("count"); + + this->count = count; + this->offset = offset; + } + + Buffer = buffer; + } + + void SocketAsyncEventArgs::SetLastOperation(SocketAsyncOperation_t op) + { + sassert(!isDisposed, ""); + + sassert(Interlocked::Exchange(&inProgress, 1) == 0, ""); + + lastOperation = op; + } } } } diff --git a/src/libmscorlib/String.cpp b/src/libmscorlib/String.cpp index 176d0f7..d295c49 100644 --- a/src/libmscorlib/String.cpp +++ b/src/libmscorlib/String.cpp @@ -532,7 +532,7 @@ namespace System return result; } - const char String::operator [](const int index) const + const char& String::operator [](const int index) const { sassert(index > 0 && index < Length, "index out of range.");