You've already forked linux-packaging-mono
Imported Upstream version 4.2.0.179
Former-commit-id: 4610231f55806d2a05ed69e5ff3faa7336cc1479
This commit is contained in:
committed by
Jo Shields
parent
aa7da660d6
commit
c042cd0c52
118
mcs/class/System/System.Net.Sockets/SafeSocketHandle.cs
Normal file
118
mcs/class/System/System.Net.Sockets/SafeSocketHandle.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// System.Net.Sockets.SafeSocketHandle
|
||||
//
|
||||
// Authors:
|
||||
// Marcos Henrich <marcos.henrich@xamarin.com>
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace System.Net.Sockets {
|
||||
|
||||
sealed class SafeSocketHandle : SafeHandleZeroOrMinusOneIsInvalid {
|
||||
|
||||
List<Thread> blocking_threads;
|
||||
|
||||
const int SOCKET_CLOSED = 10004;
|
||||
|
||||
const int ABORT_RETRIES = 10;
|
||||
static bool THROW_ON_ABORT_RETRIES = Environment.GetEnvironmentVariable("MONO_TESTS_IN_PROGRESS") == "yes";
|
||||
|
||||
public SafeSocketHandle (IntPtr preexistingHandle, bool ownsHandle) : base (ownsHandle)
|
||||
{
|
||||
SetHandle (preexistingHandle);
|
||||
}
|
||||
|
||||
// This is just for marshalling
|
||||
internal SafeSocketHandle () : base (true)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool ReleaseHandle ()
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
Socket.Blocking_internal (handle, false, out error);
|
||||
|
||||
if (blocking_threads != null) {
|
||||
int abort_attempts = 0;
|
||||
while (blocking_threads.Count > 0) {
|
||||
if (abort_attempts++ >= ABORT_RETRIES) {
|
||||
if (THROW_ON_ABORT_RETRIES)
|
||||
throw new Exception ("Could not abort registered blocking threads before closing socket.");
|
||||
|
||||
// Attempts to close the socket safely failed.
|
||||
// We give up, and close the socket with pending blocking system calls.
|
||||
// This should not occur, nonetheless if it does this avoids an endless loop.
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method can be called by the DangerousRelease inside RegisterForBlockingSyscall
|
||||
* When this happens blocking_threads contains the current thread.
|
||||
* We can safely close the socket and throw SocketException in RegisterForBlockingSyscall
|
||||
* before the blocking system call.
|
||||
*/
|
||||
lock (blocking_threads) {
|
||||
if (blocking_threads.Count == 1 && blocking_threads[0] == Thread.CurrentThread)
|
||||
break;
|
||||
}
|
||||
|
||||
AbortRegisteredThreads ();
|
||||
// Sleep so other threads can resume
|
||||
Thread.Sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
Socket.Close_internal (handle, out error);
|
||||
|
||||
return error == 0;
|
||||
}
|
||||
|
||||
public void RegisterForBlockingSyscall ()
|
||||
{
|
||||
if (blocking_threads == null)
|
||||
Interlocked.CompareExchange (ref blocking_threads, new List<Thread> (), null);
|
||||
|
||||
bool release = false;
|
||||
try {
|
||||
DangerousAddRef (ref release);
|
||||
} finally {
|
||||
/* We must use a finally block here to make this atomic. */
|
||||
lock (blocking_threads) {
|
||||
blocking_threads.Add (Thread.CurrentThread);
|
||||
}
|
||||
if (release)
|
||||
DangerousRelease ();
|
||||
|
||||
// Handle can be closed by DangerousRelease
|
||||
if (IsClosed)
|
||||
throw new SocketException (SOCKET_CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
/* This must be called from a finally block! */
|
||||
public void UnRegisterForBlockingSyscall ()
|
||||
{
|
||||
//If this NRE, we're in deep problems because Register Must have
|
||||
lock (blocking_threads) {
|
||||
blocking_threads.Remove (Thread.CurrentThread);
|
||||
}
|
||||
}
|
||||
|
||||
void AbortRegisteredThreads () {
|
||||
if (blocking_threads == null)
|
||||
return;
|
||||
|
||||
lock (blocking_threads) {
|
||||
foreach (var t in blocking_threads)
|
||||
Socket.cancel_blocking_socket_operation (t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
32
mcs/class/System/System.Net.Sockets/SocketAsyncCallback.cs
Normal file
32
mcs/class/System/System.Net.Sockets/SocketAsyncCallback.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
// System.Net.Sockets.SocketAsyncCallback.cs
|
||||
//
|
||||
// Authors:
|
||||
// Ludovic Henry <ludovic@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.com)
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
internal delegate void SocketAsyncCallback (SocketAsyncResult sar);
|
||||
}
|
@@ -40,7 +40,7 @@ namespace System.Net.Sockets
|
||||
{
|
||||
bool disposed;
|
||||
int in_progress;
|
||||
internal Socket.Worker Worker;
|
||||
internal SocketAsyncWorker Worker;
|
||||
EndPoint remote_ep;
|
||||
public Exception ConnectByNameError { get; internal set; }
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace System.Net.Sockets
|
||||
|
||||
public SocketAsyncEventArgs ()
|
||||
{
|
||||
Worker = new Socket.Worker (this);
|
||||
Worker = new SocketAsyncWorker (this);
|
||||
AcceptSocket = null;
|
||||
Buffer = null;
|
||||
BufferList = null;
|
||||
@@ -208,33 +208,42 @@ namespace System.Net.Sockets
|
||||
static void DispatcherCB (IAsyncResult ares)
|
||||
{
|
||||
SocketAsyncEventArgs args = (SocketAsyncEventArgs) ares.AsyncState;
|
||||
|
||||
if (Interlocked.Exchange (ref args.in_progress, 0) != 1)
|
||||
throw new InvalidOperationException ("No operation in progress");
|
||||
SocketAsyncOperation op = args.LastOperation;
|
||||
// Notes;
|
||||
// -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
|
||||
// -SendPackets and ReceiveMessageFrom are not implemented yet
|
||||
if (op == SocketAsyncOperation.Receive)
|
||||
args.ReceiveCallback (ares);
|
||||
else if (op == SocketAsyncOperation.Send)
|
||||
args.SendCallback (ares);
|
||||
else if (op == SocketAsyncOperation.ReceiveFrom)
|
||||
args.ReceiveFromCallback (ares);
|
||||
else if (op == SocketAsyncOperation.SendTo)
|
||||
args.SendToCallback (ares);
|
||||
else if (op == SocketAsyncOperation.Accept)
|
||||
args.AcceptCallback (ares);
|
||||
else if (op == SocketAsyncOperation.Disconnect)
|
||||
args.DisconnectCallback (ares);
|
||||
else if (op == SocketAsyncOperation.Connect)
|
||||
args.ConnectCallback (ares);
|
||||
/*
|
||||
else if (op == Socket.SocketOperation.ReceiveMessageFrom)
|
||||
else if (op == Socket.SocketOperation.SendPackets)
|
||||
*/
|
||||
else
|
||||
throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
|
||||
|
||||
/* Notes;
|
||||
* -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
|
||||
* -SendPackets and ReceiveMessageFrom are not implemented yet */
|
||||
switch (args.LastOperation) {
|
||||
case SocketAsyncOperation.Receive:
|
||||
args.ReceiveCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.Send:
|
||||
args.SendCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.ReceiveFrom:
|
||||
args.ReceiveFromCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.SendTo:
|
||||
args.SendToCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.Accept:
|
||||
args.AcceptCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.Disconnect:
|
||||
args.DisconnectCallback (ares);
|
||||
break;
|
||||
case SocketAsyncOperation.Connect:
|
||||
args.ConnectCallback (ares);
|
||||
break;
|
||||
/*
|
||||
case SocketOperation.ReceiveMessageFrom:
|
||||
case SocketOperation.SendPackets:
|
||||
*/
|
||||
default:
|
||||
throw new NotImplementedException (String.Format ("Operation {0} is not implemented", args.LastOperation));
|
||||
}
|
||||
}
|
||||
|
||||
internal void ReceiveCallback (IAsyncResult ares)
|
||||
@@ -286,7 +295,7 @@ namespace System.Net.Sockets
|
||||
SocketError = SocketError.OperationAborted;
|
||||
} finally {
|
||||
if (AcceptSocket == null)
|
||||
AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, (IntPtr)(-1));
|
||||
AcceptSocket = new Socket (curSocket.AddressFamily, curSocket.SocketType, curSocket.ProtocolType, null);
|
||||
OnCompleted (this);
|
||||
}
|
||||
}
|
||||
|
318
mcs/class/System/System.Net.Sockets/SocketAsyncResult.cs
Normal file
318
mcs/class/System/System.Net.Sockets/SocketAsyncResult.cs
Normal file
@@ -0,0 +1,318 @@
|
||||
// System.Net.Sockets.SocketAsyncResult.cs
|
||||
//
|
||||
// Authors:
|
||||
// Ludovic Henry <ludovic@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.com)
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
internal sealed class SocketAsyncResult: IAsyncResult, IThreadPoolWorkItem
|
||||
{
|
||||
/* Same structure in the runtime. Keep this in sync with
|
||||
* MonoSocketAsyncResult in metadata/socket-io.h and
|
||||
* ProcessAsyncReader in System.Diagnostics/Process.cs. */
|
||||
|
||||
public Socket socket;
|
||||
IntPtr handle;
|
||||
object state;
|
||||
AsyncCallback callback; // used from the runtime
|
||||
WaitHandle wait_handle;
|
||||
|
||||
Exception delayed_exception;
|
||||
|
||||
public EndPoint EndPoint; // Connect,ReceiveFrom,SendTo
|
||||
public byte [] Buffer; // Receive,ReceiveFrom,Send,SendTo
|
||||
public int Offset; // Receive,ReceiveFrom,Send,SendTo
|
||||
public int Size; // Receive,ReceiveFrom,Send,SendTo
|
||||
public SocketFlags SockFlags; // Receive,ReceiveFrom,Send,SendTo
|
||||
public Socket AcceptSocket; // AcceptReceive
|
||||
public IPAddress[] Addresses; // Connect
|
||||
public int Port; // Connect
|
||||
public IList<ArraySegment<byte>> Buffers; // Receive, Send
|
||||
public bool ReuseSocket; // Disconnect
|
||||
|
||||
// Return values
|
||||
Socket accept_socket;
|
||||
int total;
|
||||
|
||||
bool completed_synchronously;
|
||||
bool completed;
|
||||
bool is_blocking;
|
||||
internal int error;
|
||||
public SocketOperation operation;
|
||||
AsyncResult async_result;
|
||||
public int EndCalled;
|
||||
|
||||
/* These fields are not in MonoSocketAsyncResult */
|
||||
public SocketAsyncWorker Worker;
|
||||
public int CurrentAddress; // Connect
|
||||
|
||||
public SocketAsyncResult ()
|
||||
{
|
||||
}
|
||||
|
||||
public SocketAsyncResult (Socket socket, object state, AsyncCallback callback, SocketOperation operation)
|
||||
{
|
||||
Init (socket, state, callback, operation, new SocketAsyncWorker (this));
|
||||
}
|
||||
|
||||
public object AsyncState {
|
||||
get {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
public WaitHandle AsyncWaitHandle {
|
||||
get {
|
||||
lock (this) {
|
||||
if (wait_handle == null)
|
||||
wait_handle = new ManualResetEvent (completed);
|
||||
}
|
||||
|
||||
return wait_handle;
|
||||
}
|
||||
set {
|
||||
wait_handle = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CompletedSynchronously {
|
||||
get {
|
||||
return completed_synchronously;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCompleted {
|
||||
get {
|
||||
return completed;
|
||||
}
|
||||
set {
|
||||
completed = value;
|
||||
lock (this) {
|
||||
if (wait_handle != null && value)
|
||||
((ManualResetEvent) wait_handle).Set ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Socket Socket {
|
||||
get {
|
||||
return accept_socket;
|
||||
}
|
||||
}
|
||||
|
||||
public int Total {
|
||||
get { return total; }
|
||||
set { total = value; }
|
||||
}
|
||||
|
||||
public SocketError ErrorCode {
|
||||
get {
|
||||
SocketException ex = delayed_exception as SocketException;
|
||||
if (ex != null)
|
||||
return ex.SocketErrorCode;
|
||||
|
||||
if (error != 0)
|
||||
return (SocketError) error;
|
||||
|
||||
return SocketError.Success;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init (Socket socket, object state, AsyncCallback callback, SocketOperation operation, SocketAsyncWorker worker)
|
||||
{
|
||||
this.socket = socket;
|
||||
this.is_blocking = socket != null ? socket.is_blocking : true;
|
||||
this.handle = socket != null ? socket.Handle : IntPtr.Zero;
|
||||
this.state = state;
|
||||
this.callback = callback;
|
||||
this.operation = operation;
|
||||
|
||||
if (wait_handle != null)
|
||||
((ManualResetEvent) wait_handle).Reset ();
|
||||
|
||||
delayed_exception = null;
|
||||
|
||||
EndPoint = null;
|
||||
Buffer = null;
|
||||
Offset = 0;
|
||||
Size = 0;
|
||||
SockFlags = SocketFlags.None;
|
||||
AcceptSocket = null;
|
||||
Addresses = null;
|
||||
Port = 0;
|
||||
Buffers = null;
|
||||
ReuseSocket = false;
|
||||
accept_socket = null;
|
||||
total = 0;
|
||||
|
||||
completed_synchronously = false;
|
||||
completed = false;
|
||||
is_blocking = false;
|
||||
error = 0;
|
||||
async_result = null;
|
||||
EndCalled = 0;
|
||||
Worker = worker;
|
||||
}
|
||||
|
||||
public void DoMConnectCallback ()
|
||||
{
|
||||
if (callback == null)
|
||||
return;
|
||||
ThreadPool.UnsafeQueueUserWorkItem (_ => callback (this), null);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Init (null, null, null, 0, Worker);
|
||||
if (wait_handle != null) {
|
||||
wait_handle.Close ();
|
||||
wait_handle = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckIfThrowDelayedException ()
|
||||
{
|
||||
if (delayed_exception != null) {
|
||||
socket.is_connected = false;
|
||||
throw delayed_exception;
|
||||
}
|
||||
|
||||
if (error != 0) {
|
||||
socket.is_connected = false;
|
||||
throw new SocketException (error);
|
||||
}
|
||||
}
|
||||
|
||||
void CompleteDisposed (object unused)
|
||||
{
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete ()
|
||||
{
|
||||
if (operation != SocketOperation.Receive && socket.is_disposed)
|
||||
delayed_exception = new ObjectDisposedException (socket.GetType ().ToString ());
|
||||
|
||||
IsCompleted = true;
|
||||
|
||||
Queue<SocketAsyncWorker> queue = null;
|
||||
switch (operation) {
|
||||
case SocketOperation.Receive:
|
||||
case SocketOperation.ReceiveFrom:
|
||||
case SocketOperation.ReceiveGeneric:
|
||||
case SocketOperation.Accept:
|
||||
queue = socket.readQ;
|
||||
break;
|
||||
case SocketOperation.Send:
|
||||
case SocketOperation.SendTo:
|
||||
case SocketOperation.SendGeneric:
|
||||
queue = socket.writeQ;
|
||||
break;
|
||||
}
|
||||
|
||||
if (queue != null) {
|
||||
lock (queue) {
|
||||
/* queue.Count will only be 0 if the socket is closed while receive/send/accept
|
||||
* operation(s) are pending and at least one call to this method is waiting
|
||||
* on the lock while another one calls CompleteAllOnDispose() */
|
||||
if (queue.Count > 0)
|
||||
queue.Dequeue (); /* remove ourselves */
|
||||
if (queue.Count > 0) {
|
||||
if (!socket.is_disposed) {
|
||||
Socket.socket_pool_queue (SocketAsyncWorker.Dispatcher, (queue.Peek ()).result);
|
||||
} else {
|
||||
/* CompleteAllOnDispose */
|
||||
SocketAsyncWorker [] workers = queue.ToArray ();
|
||||
for (int i = 0; i < workers.Length; i++)
|
||||
ThreadPool.UnsafeQueueUserWorkItem (workers [i].result.CompleteDisposed, null);
|
||||
queue.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IMPORTANT: 'callback', if any is scheduled from unmanaged code
|
||||
}
|
||||
|
||||
public void Complete (bool synch)
|
||||
{
|
||||
this.completed_synchronously = synch;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete (int total)
|
||||
{
|
||||
this.total = total;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete (Exception e, bool synch)
|
||||
{
|
||||
this.completed_synchronously = synch;
|
||||
this.delayed_exception = e;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete (Exception e)
|
||||
{
|
||||
this.delayed_exception = e;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete (Socket s)
|
||||
{
|
||||
this.accept_socket = s;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
public void Complete (Socket s, int total)
|
||||
{
|
||||
this.accept_socket = s;
|
||||
this.total = total;
|
||||
Complete ();
|
||||
}
|
||||
|
||||
void IThreadPoolWorkItem.ExecuteWorkItem()
|
||||
{
|
||||
async_result.Invoke ();
|
||||
|
||||
if (completed && callback != null) {
|
||||
ThreadPool.UnsafeQueueCustomWorkItem (new AsyncResult (state => callback ((IAsyncResult) state), this, false), false);
|
||||
}
|
||||
}
|
||||
|
||||
void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
397
mcs/class/System/System.Net.Sockets/SocketAsyncWorker.cs
Normal file
397
mcs/class/System/System.Net.Sockets/SocketAsyncWorker.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
// System.Net.Sockets.SocketAsyncWorker.cs
|
||||
//
|
||||
// Authors:
|
||||
// Ludovic Henry <ludovic@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.com)
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
internal sealed class SocketAsyncWorker
|
||||
{
|
||||
public SocketAsyncResult result;
|
||||
SocketAsyncEventArgs args;
|
||||
|
||||
public SocketAsyncWorker (SocketAsyncEventArgs args)
|
||||
{
|
||||
this.args = args;
|
||||
result = new SocketAsyncResult ();
|
||||
result.Worker = this;
|
||||
}
|
||||
|
||||
public SocketAsyncWorker (SocketAsyncResult ares)
|
||||
{
|
||||
this.result = ares;
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
if (result != null) {
|
||||
result.Dispose ();
|
||||
result = null;
|
||||
args = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static SocketAsyncCallback Dispatcher = new SocketAsyncCallback (DispatcherCB);
|
||||
|
||||
static void DispatcherCB (SocketAsyncResult sar)
|
||||
{
|
||||
/* SendPackets and ReceiveMessageFrom are not implemented yet */
|
||||
switch (sar.operation) {
|
||||
case SocketOperation.Receive:
|
||||
case SocketOperation.ReceiveGeneric:
|
||||
case SocketOperation.RecvJustCallback:
|
||||
sar.Worker.Receive ();
|
||||
break;
|
||||
case SocketOperation.Send:
|
||||
case SocketOperation.SendGeneric:
|
||||
case SocketOperation.SendJustCallback:
|
||||
sar.Worker.Send ();
|
||||
break;
|
||||
case SocketOperation.ReceiveFrom:
|
||||
sar.Worker.ReceiveFrom ();
|
||||
break;
|
||||
case SocketOperation.SendTo:
|
||||
sar.Worker.SendTo ();
|
||||
break;
|
||||
case SocketOperation.Connect:
|
||||
sar.Worker.Connect ();
|
||||
break;
|
||||
case SocketOperation.Accept:
|
||||
sar.Worker.Accept ();
|
||||
break;
|
||||
case SocketOperation.AcceptReceive:
|
||||
sar.Worker.AcceptReceive ();
|
||||
break;
|
||||
case SocketOperation.Disconnect:
|
||||
sar.Worker.Disconnect ();
|
||||
break;
|
||||
// case SocketOperation.ReceiveMessageFrom
|
||||
// sar.Worker.ReceiveMessageFrom ()
|
||||
// break;
|
||||
// case SocketOperation.SendPackets:
|
||||
// sar.Worker.SendPackets ();
|
||||
// break;
|
||||
default:
|
||||
throw new NotImplementedException (String.Format ("Operation {0} is not implemented", sar.operation));
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called when reusing a SocketAsyncEventArgs */
|
||||
public void Init (Socket sock, SocketAsyncEventArgs args, SocketOperation op)
|
||||
{
|
||||
result.Init (sock, args, SocketAsyncEventArgs.Dispatcher, op, this);
|
||||
|
||||
SocketAsyncOperation async_op;
|
||||
|
||||
// Notes;
|
||||
// -SocketOperation.AcceptReceive not used in SocketAsyncEventArgs
|
||||
// -SendPackets and ReceiveMessageFrom are not implemented yet
|
||||
switch (op) {
|
||||
case SocketOperation.Connect:
|
||||
async_op = SocketAsyncOperation.Connect;
|
||||
break;
|
||||
case SocketOperation.Accept:
|
||||
async_op = SocketAsyncOperation.Accept;
|
||||
break;
|
||||
case SocketOperation.Disconnect:
|
||||
async_op = SocketAsyncOperation.Disconnect;
|
||||
break;
|
||||
case SocketOperation.Receive:
|
||||
case SocketOperation.ReceiveGeneric:
|
||||
async_op = SocketAsyncOperation.Receive;
|
||||
break;
|
||||
case SocketOperation.ReceiveFrom:
|
||||
async_op = SocketAsyncOperation.ReceiveFrom;
|
||||
break;
|
||||
// case SocketOperation.ReceiveMessageFrom:
|
||||
// async_op = SocketAsyncOperation.ReceiveMessageFrom;
|
||||
// break;
|
||||
case SocketOperation.Send:
|
||||
case SocketOperation.SendGeneric:
|
||||
async_op = SocketAsyncOperation.Send;
|
||||
break;
|
||||
// case SocketOperation.SendPackets:
|
||||
// async_op = SocketAsyncOperation.SendPackets;
|
||||
// break;
|
||||
case SocketOperation.SendTo:
|
||||
async_op = SocketAsyncOperation.SendTo;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException (String.Format ("Operation {0} is not implemented", op));
|
||||
}
|
||||
|
||||
args.SetLastOperation (async_op);
|
||||
args.SocketError = SocketError.Success;
|
||||
args.BytesTransferred = 0;
|
||||
}
|
||||
|
||||
public void Accept ()
|
||||
{
|
||||
Socket acc_socket = null;
|
||||
try {
|
||||
if (args != null && args.AcceptSocket != null) {
|
||||
result.socket.Accept (args.AcceptSocket);
|
||||
acc_socket = args.AcceptSocket;
|
||||
} else {
|
||||
acc_socket = result.socket.Accept ();
|
||||
if (args != null)
|
||||
args.AcceptSocket = acc_socket;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
result.Complete (acc_socket);
|
||||
}
|
||||
|
||||
/* only used in 2.0 profile and newer, but
|
||||
* leave in older profiles to keep interface
|
||||
* to runtime consistent
|
||||
*/
|
||||
public void AcceptReceive ()
|
||||
{
|
||||
Socket acc_socket = null;
|
||||
try {
|
||||
if (result.AcceptSocket == null) {
|
||||
acc_socket = result.socket.Accept ();
|
||||
} else {
|
||||
acc_socket = result.AcceptSocket;
|
||||
result.socket.Accept (acc_socket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
/* It seems the MS runtime
|
||||
* special-cases 0-length requested
|
||||
* receive data. See bug 464201.
|
||||
*/
|
||||
int total = 0;
|
||||
if (result.Size > 0) {
|
||||
try {
|
||||
SocketError error;
|
||||
total = acc_socket.Receive_nochecks (result.Buffer, result.Offset, result.Size, result.SockFlags, out error);
|
||||
if (error != 0) {
|
||||
result.Complete (new SocketException ((int) error));
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
result.Complete (acc_socket, total);
|
||||
}
|
||||
|
||||
public void Connect ()
|
||||
{
|
||||
if (result.EndPoint == null) {
|
||||
result.Complete (new SocketException ((int)SocketError.AddressNotAvailable));
|
||||
return;
|
||||
}
|
||||
|
||||
SocketAsyncResult mconnect = result.AsyncState as SocketAsyncResult;
|
||||
bool is_mconnect = (mconnect != null && mconnect.Addresses != null);
|
||||
try {
|
||||
int error_code;
|
||||
EndPoint ep = result.EndPoint;
|
||||
error_code = (int) result.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
|
||||
if (error_code == 0) {
|
||||
if (is_mconnect)
|
||||
result = mconnect;
|
||||
result.socket.seed_endpoint = ep;
|
||||
result.socket.is_connected = true;
|
||||
result.socket.is_bound = true;
|
||||
result.socket.connect_in_progress = false;
|
||||
result.error = 0;
|
||||
result.Complete ();
|
||||
if (is_mconnect)
|
||||
result.DoMConnectCallback ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_mconnect) {
|
||||
result.socket.connect_in_progress = false;
|
||||
result.Complete (new SocketException (error_code));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
|
||||
mconnect.Complete (new SocketException (error_code));
|
||||
if (is_mconnect)
|
||||
mconnect.DoMConnectCallback ();
|
||||
return;
|
||||
}
|
||||
mconnect.socket.BeginMConnect (mconnect);
|
||||
} catch (Exception e) {
|
||||
result.socket.connect_in_progress = false;
|
||||
if (is_mconnect)
|
||||
result = mconnect;
|
||||
result.Complete (e);
|
||||
if (is_mconnect)
|
||||
result.DoMConnectCallback ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Also only used in 2.0 profile and newer */
|
||||
public void Disconnect ()
|
||||
{
|
||||
try {
|
||||
if (args != null)
|
||||
result.ReuseSocket = args.DisconnectReuseSocket;
|
||||
result.socket.Disconnect (result.ReuseSocket);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
result.Complete ();
|
||||
}
|
||||
|
||||
public void Receive ()
|
||||
{
|
||||
if (result.operation == SocketOperation.ReceiveGeneric) {
|
||||
ReceiveGeneric ();
|
||||
return;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
try {
|
||||
total = Socket.Receive_internal (result.socket.safe_handle, result.Buffer, result.Offset, result.Size, result.SockFlags, out result.error);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
result.Complete (total);
|
||||
}
|
||||
|
||||
public void ReceiveFrom ()
|
||||
{
|
||||
int total = 0;
|
||||
try {
|
||||
total = result.socket.ReceiveFrom_nochecks (result.Buffer, result.Offset, result.Size, result.SockFlags, ref result.EndPoint);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
result.Complete (total);
|
||||
}
|
||||
|
||||
public void ReceiveGeneric ()
|
||||
{
|
||||
int total = 0;
|
||||
try {
|
||||
total = result.socket.Receive (result.Buffers, result.SockFlags);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
result.Complete (total);
|
||||
}
|
||||
|
||||
int send_so_far;
|
||||
|
||||
void UpdateSendValues (int last_sent)
|
||||
{
|
||||
if (result.error == 0) {
|
||||
send_so_far += last_sent;
|
||||
result.Offset += last_sent;
|
||||
result.Size -= last_sent;
|
||||
}
|
||||
}
|
||||
|
||||
public void Send ()
|
||||
{
|
||||
if (result.operation == SocketOperation.SendGeneric) {
|
||||
SendGeneric ();
|
||||
return;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
try {
|
||||
total = Socket.Send_internal (result.socket.safe_handle, result.Buffer, result.Offset, result.Size, result.SockFlags, out result.error);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.error == 0) {
|
||||
UpdateSendValues (total);
|
||||
if (result.socket.is_disposed) {
|
||||
result.Complete (total);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.Size > 0) {
|
||||
Socket.socket_pool_queue (SocketAsyncWorker.Dispatcher, result);
|
||||
return; // Have to finish writing everything. See bug #74475.
|
||||
}
|
||||
result.Total = send_so_far;
|
||||
send_so_far = 0;
|
||||
}
|
||||
result.Complete (total);
|
||||
}
|
||||
|
||||
public void SendTo ()
|
||||
{
|
||||
int total = 0;
|
||||
try {
|
||||
total = result.socket.SendTo_nochecks (result.Buffer, result.Offset, result.Size, result.SockFlags, result.EndPoint);
|
||||
|
||||
UpdateSendValues (total);
|
||||
if (result.Size > 0) {
|
||||
Socket.socket_pool_queue (SocketAsyncWorker.Dispatcher, result);
|
||||
return; // Have to finish writing everything. See bug #74475.
|
||||
}
|
||||
result.Total = send_so_far;
|
||||
send_so_far = 0;
|
||||
} catch (Exception e) {
|
||||
send_so_far = 0;
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
|
||||
result.Complete ();
|
||||
}
|
||||
|
||||
public void SendGeneric ()
|
||||
{
|
||||
int total = 0;
|
||||
try {
|
||||
total = result.socket.Send (result.Buffers, result.SockFlags);
|
||||
} catch (Exception e) {
|
||||
result.Complete (e);
|
||||
return;
|
||||
}
|
||||
result.Complete (total);
|
||||
}
|
||||
}
|
||||
}
|
48
mcs/class/System/System.Net.Sockets/SocketOperation.cs
Normal file
48
mcs/class/System/System.Net.Sockets/SocketOperation.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// System.Net.Sockets.SocketOperation.cs
|
||||
//
|
||||
// Authors:
|
||||
// Ludovic Henry <ludovic@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2015 Xamarin, Inc. (https://www.xamarin.com)
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
namespace System.Net.Sockets
|
||||
{
|
||||
// Used by the runtime
|
||||
internal enum SocketOperation {
|
||||
Accept,
|
||||
Connect,
|
||||
Receive,
|
||||
ReceiveFrom,
|
||||
Send,
|
||||
SendTo,
|
||||
RecvJustCallback,
|
||||
SendJustCallback,
|
||||
UsedInProcess,
|
||||
UsedInConsole2,
|
||||
Disconnect,
|
||||
AcceptReceive,
|
||||
ReceiveGeneric,
|
||||
SendGeneric
|
||||
}
|
||||
}
|
@@ -1,207 +0,0 @@
|
||||
// SocketOptionName.cs
|
||||
//
|
||||
// This code was automatically generated from
|
||||
// ECMA CLI XML Library Specification.
|
||||
// Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
|
||||
// Created: Wed, 5 Sep 2001 06:33:02 UTC
|
||||
// Source file: AllTypes.xml
|
||||
// URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
|
||||
//
|
||||
// (C) 2001 Ximian, Inc. http://www.ximian.com
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
|
||||
namespace System.Net.Sockets {
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public enum SocketOptionName {
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Debug = 1,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
AcceptConnection = 2,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ReuseAddress = 4,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
KeepAlive = 8,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
DontRoute = 16,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Broadcast = 32,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
UseLoopback = 64,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Linger = 128,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
OutOfBandInline = 256,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
DontLinger = -129,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ExclusiveAddressUse = -5,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
SendBuffer = 4097,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ReceiveBuffer = 4098,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
SendLowWater = 4099,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ReceiveLowWater = 4100,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
SendTimeout = 4101,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ReceiveTimeout = 4102,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Error = 4103,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Type = 4104,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
MaxConnections = 2147483647,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
IPOptions = 1,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
HeaderIncluded = 2,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
TypeOfService = 3,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
IpTimeToLive = 4,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
MulticastInterface = 9,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
MulticastTimeToLive = 10,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
MulticastLoopback = 11,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
AddMembership = 12,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
DropMembership = 13,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
DontFragment = 14,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
AddSourceMembership = 15,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
DropSourceMembership = 16,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
BlockSource = 17,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
UnblockSource = 18,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
PacketInformation = 19,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
NoDelay = 1,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
BsdUrgent = 2,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
Expedited = 2,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
NoChecksum = 1,
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
ChecksumCoverage = 20,
|
||||
|
||||
HopLimit = 21,
|
||||
UpdateAcceptContext = 28683,
|
||||
UpdateConnectContext = 28688,
|
||||
|
||||
} // SocketOptionName
|
||||
|
||||
} // System.Net.Sockets
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user