[socket] Reduce handle manipulations in native (#5378)
[mono.git] / mcs / class / System / System.Net.Sockets / Socket.cs
index 4d5d7b418496bad939a53f2b25840d4031ebb150..4a889e4dd2709692107c9acee71d19ca0b670551 100644 (file)
@@ -901,12 +901,11 @@ namespace System.Net.Sockets
                                SocketAsyncResult ares;
 
                                if (!GetCheckedIPs (e, out addresses)) {
-                                       e.socket_async_result.EndPoint = e.RemoteEndPoint;
+                                       //NOTE: DualMode may cause Socket's RemoteEndpoint to differ in AddressFamily from the
+                                       // SocketAsyncEventArgs, but the SocketAsyncEventArgs itself is not changed
                                        ares = (SocketAsyncResult) BeginConnect (e.RemoteEndPoint, ConnectAsyncCallback, e);
                                } else {
-                                       DnsEndPoint dep = (e.RemoteEndPoint as DnsEndPoint);
-                                       e.socket_async_result.Addresses = addresses;
-                                       e.socket_async_result.Port = dep.Port;
+                                       DnsEndPoint dep = (DnsEndPoint)e.RemoteEndPoint;
                                        ares = (SocketAsyncResult) BeginConnect (addresses, dep.Port, ConnectAsyncCallback, e);
                                }
 
@@ -977,60 +976,7 @@ namespace System.Net.Sockets
                                EndPoint = remoteEP,
                        };
 
-                       // Bug #75154: Connect() should not succeed for .Any addresses.
-                       if (remoteEP is IPEndPoint) {
-                               IPEndPoint ep = (IPEndPoint) remoteEP;
-                               if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
-                                       sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
-                                       return sockares;
-                               }
-                               
-                               remoteEP = RemapIPEndPoint (ep);
-                       }
-
-                       int error = 0;
-
-                       if (connect_in_progress) {
-                               // This could happen when multiple IPs are used
-                               // Calling connect() again will reset the connection attempt and cause
-                               // an error. Better to just close the socket and move on.
-                               connect_in_progress = false;
-                               m_Handle.Dispose ();
-                               m_Handle = new SafeSocketHandle (Socket_internal (addressFamily, socketType, protocolType, out error), true);
-                               if (error != 0)
-                                       throw new SocketException (error);
-                       }
-
-                       bool blk = is_blocking;
-                       if (blk)
-                               Blocking = false;
-                       Connect_internal (m_Handle, remoteEP.Serialize (), out error, false);
-                       if (blk)
-                               Blocking = true;
-
-                       if (error == 0) {
-                               // succeeded synch
-                               is_connected = true;
-                               is_bound = true;
-                               sockares.Complete (true);
-                               return sockares;
-                       }
-
-                       if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
-                               // error synch
-                               is_connected = false;
-                               is_bound = false;
-                               sockares.Complete (new SocketException (error), true);
-                               return sockares;
-                       }
-
-                       // continue asynch
-                       is_connected = false;
-                       is_bound = false;
-                       connect_in_progress = true;
-
-                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
-
+                       BeginSConnect (sockares);
                        return sockares;
                }
 
@@ -1056,39 +1002,85 @@ namespace System.Net.Sockets
 
                        is_connected = false;
 
-                       return BeginMConnect (sockares);
+                       BeginMConnect (sockares);
+                       return sockares;
                }
 
-               internal IAsyncResult BeginMConnect (SocketAsyncResult sockares)
+               static void BeginMConnect (SocketAsyncResult sockares)
                {
-                       SocketAsyncResult ares = null;
                        Exception exc = null;
-                       AsyncCallback callback;
 
                        for (int i = sockares.CurrentAddress; i < sockares.Addresses.Length; i++) {
                                try {
                                        sockares.CurrentAddress++;
+                                       sockares.EndPoint = new IPEndPoint (sockares.Addresses [i], sockares.Port);
 
-                                       ares = (SocketAsyncResult) BeginConnect (new IPEndPoint (sockares.Addresses [i], sockares.Port), null, sockares);
-                                       if (ares.IsCompleted && ares.CompletedSynchronously) {
-                                               ares.CheckIfThrowDelayedException ();
-
-                                               callback = ares.AsyncCallback;
-                                               if (callback != null)
-                                                       ThreadPool.UnsafeQueueUserWorkItem (_ => callback (ares), null);
-                                       }
-
-                                       break;
+                                       BeginSConnect (sockares);
+                                       return;
                                } catch (Exception e) {
                                        exc = e;
-                                       ares = null;
                                }
                        }
 
-                       if (ares == null)
-                               throw exc;
+                       throw exc;
+               }
 
-                       return sockares;
+               static void BeginSConnect (SocketAsyncResult sockares)
+               {
+                       EndPoint remoteEP = sockares.EndPoint;
+                       // Bug #75154: Connect() should not succeed for .Any addresses.
+                       if (remoteEP is IPEndPoint) {
+                               IPEndPoint ep = (IPEndPoint) remoteEP;
+                               if (ep.Address.Equals (IPAddress.Any) || ep.Address.Equals (IPAddress.IPv6Any)) {
+                                       sockares.Complete (new SocketException ((int) SocketError.AddressNotAvailable), true);
+                                       return;
+                               }
+
+                               sockares.EndPoint = remoteEP = sockares.socket.RemapIPEndPoint (ep);
+                       }
+
+                       int error = 0;
+
+                       if (sockares.socket.connect_in_progress) {
+                               // This could happen when multiple IPs are used
+                               // Calling connect() again will reset the connection attempt and cause
+                               // an error. Better to just close the socket and move on.
+                               sockares.socket.connect_in_progress = false;
+                               sockares.socket.m_Handle.Dispose ();
+                               sockares.socket.m_Handle = new SafeSocketHandle (sockares.socket.Socket_internal (sockares.socket.addressFamily, sockares.socket.socketType, sockares.socket.protocolType, out error), true);
+                               if (error != 0)
+                                       throw new SocketException (error);
+                       }
+
+                       bool blk = sockares.socket.is_blocking;
+                       if (blk)
+                               sockares.socket.Blocking = false;
+                       Connect_internal (sockares.socket.m_Handle, remoteEP.Serialize (), out error, false);
+                       if (blk)
+                               sockares.socket.Blocking = true;
+
+                       if (error == 0) {
+                               // succeeded synch
+                               sockares.socket.is_connected = true;
+                               sockares.socket.is_bound = true;
+                               sockares.Complete (true);
+                               return;
+                       }
+
+                       if (error != (int) SocketError.InProgress && error != (int) SocketError.WouldBlock) {
+                               // error synch
+                               sockares.socket.is_connected = false;
+                               sockares.socket.is_bound = false;
+                               sockares.Complete (new SocketException (error), true);
+                               return;
+                       }
+
+                       // continue asynch
+                       sockares.socket.is_connected = false;
+                       sockares.socket.is_bound = false;
+                       sockares.socket.connect_in_progress = true;
+
+                       IOSelector.Add (sockares.Handle, new IOSelectorJob (IOOperation.Write, BeginConnectCallback, sockares));
                }
 
                static IOAsyncCallback BeginConnectCallback = new IOAsyncCallback (ares => {
@@ -1099,18 +1091,11 @@ namespace System.Net.Sockets
                                return;
                        }
 
-                       SocketAsyncResult mconnect = sockares.AsyncState as SocketAsyncResult;
-                       bool is_mconnect = mconnect != null && mconnect.Addresses != null;
-
                        try {
-                               EndPoint ep = sockares.EndPoint;
-                               int error_code = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
+                               int error = (int) sockares.socket.GetSocketOption (SocketOptionLevel.Socket, SocketOptionName.Error);
 
-                               if (error_code == 0) {
-                                       if (is_mconnect)
-                                               sockares = mconnect;
-
-                                       sockares.socket.seed_endpoint = ep;
+                               if (error == 0) {
+                                       sockares.socket.seed_endpoint = sockares.EndPoint;
                                        sockares.socket.is_connected = true;
                                        sockares.socket.is_bound = true;
                                        sockares.socket.connect_in_progress = false;
@@ -1119,26 +1104,21 @@ namespace System.Net.Sockets
                                        return;
                                }
 
-                               if (!is_mconnect) {
+                               if (sockares.Addresses == null) {
                                        sockares.socket.connect_in_progress = false;
-                                       sockares.Complete (new SocketException (error_code));
+                                       sockares.Complete (new SocketException (error));
                                        return;
                                }
 
-                               if (mconnect.CurrentAddress >= mconnect.Addresses.Length) {
-                                       mconnect.Complete (new SocketException (error_code));
+                               if (sockares.CurrentAddress >= sockares.Addresses.Length) {
+                                       sockares.Complete (new SocketException (error));
                                        return;
                                }
 
-                               mconnect.socket.BeginMConnect (mconnect);
+                               BeginMConnect (sockares);
                        } catch (Exception e) {
                                sockares.socket.connect_in_progress = false;
-
-                               if (is_mconnect)
-                                       sockares = mconnect;
-
                                sockares.Complete (e);
-                               return;
                        }
                });
 
@@ -1310,7 +1290,12 @@ namespace System.Net.Sockets
                        ThrowIfBufferOutOfRange (buffer, offset, size);
 
                        int nativeError;
-                       int ret = Receive_internal (m_Handle, buffer, offset, size, socketFlags, out nativeError, is_blocking);
+                       int ret;
+                       unsafe {
+                               fixed (byte* pbuffer = buffer) {
+                                       ret = Receive_internal (m_Handle, &pbuffer[offset], size, socketFlags, out nativeError, is_blocking);
+                               }
+                       }
 
                        errorCode = (SocketError) nativeError;
                        if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
@@ -1335,25 +1320,27 @@ namespace System.Net.Sockets
                        int nativeError;
                        int ret;
 
-                       /* Only example I can find of sending a byte array reference directly into an internal
-                        * call is in System.Runtime.Remoting/System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs,
-                        * so taking a lead from that... */
-                       WSABUF[] bufarray = new WSABUF[numsegments];
                        GCHandle[] gch = new GCHandle[numsegments];
+                       try {
+                               unsafe {
+                                       fixed (WSABUF* bufarray = new WSABUF[numsegments]) {
+                                               for (int i = 0; i < numsegments; i++) {
+                                                       ArraySegment<byte> segment = buffers[i];
 
-                       for (int i = 0; i < numsegments; i++) {
-                               ArraySegment<byte> segment = buffers[i];
+                                                       if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
+                                                               throw new ArgumentOutOfRangeException ("segment");
 
-                               if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
-                                       throw new ArgumentOutOfRangeException ("segment");
+                                                       try {} finally {
+                                                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+                                                       }
 
-                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
-                               bufarray[i].len = segment.Count;
-                               bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
-                       }
+                                                       bufarray[i].len = segment.Count;
+                                                       bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+                                               }
 
-                       try {
-                               ret = Receive_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
+                                               ret = Receive_internal (m_Handle, bufarray, numsegments, socketFlags, out nativeError, is_blocking);
+                                       }
+                               }
                        } finally {
                                for (int i = 0; i < numsegments; i++) {
                                        if (gch[i].IsAllocated)
@@ -1442,7 +1429,11 @@ namespace System.Net.Sockets
                        int total = 0;
 
                        try {
-                               total = Receive_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
+                               unsafe {
+                                       fixed (byte* pbuffer = sockares.Buffer) {
+                                               total = Receive_internal (sockares.socket.m_Handle, &pbuffer[sockares.Offset], sockares.Size, sockares.SockFlags, out sockares.error, sockares.socket.is_blocking);
+                                       }
+                               }
                        } catch (Exception e) {
                                sockares.Complete (e);
                                return;
@@ -1508,31 +1499,31 @@ namespace System.Net.Sockets
                        return sockares.Total;
                }
 
-               static int Receive_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
+               static unsafe int Receive_internal (SafeSocketHandle safeHandle, WSABUF* bufarray, int count, SocketFlags flags, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
+                               return Receive_internal (safeHandle.DangerousGetHandle (), bufarray, count, flags, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern static int Receive_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
+               extern static unsafe int Receive_internal (IntPtr sock, WSABUF* bufarray, int count, SocketFlags flags, out int error, bool blocking);
 
-               static int Receive_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking)
+               static unsafe int Receive_internal (SafeSocketHandle safeHandle, byte* buffer, int count, SocketFlags flags, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return Receive_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, out error, blocking);
+                               return Receive_internal (safeHandle.DangerousGetHandle (), buffer, count, flags, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static int Receive_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, out int error, bool blocking);
+               extern static unsafe int Receive_internal(IntPtr sock, byte* buffer, int count, SocketFlags flags, out int error, bool blocking);
 
 #endregion
 
@@ -1561,7 +1552,12 @@ namespace System.Net.Sockets
                        SocketAddress sockaddr = remoteEP.Serialize();
 
                        int nativeError;
-                       int cnt = ReceiveFrom_internal (m_Handle, buffer, offset, size, socketFlags, ref sockaddr, out nativeError, is_blocking);
+                       int cnt;
+                       unsafe {
+                               fixed (byte* pbuffer = buffer) {
+                                       cnt = ReceiveFrom_internal (m_Handle, &pbuffer[offset], size, socketFlags, ref sockaddr, out nativeError, is_blocking);
+                               }
+                       }
 
                        errorCode = (SocketError) nativeError;
                        if (errorCode != SocketError.Success) {
@@ -1692,18 +1688,18 @@ namespace System.Net.Sockets
 
 
 
-               static int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
+               static unsafe int ReceiveFrom_internal (SafeSocketHandle safeHandle, byte* buffer, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, ref sockaddr, out error, blocking);
+                               return ReceiveFrom_internal (safeHandle.DangerousGetHandle (), buffer, count, flags, ref sockaddr, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static int ReceiveFrom_internal(IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
+               extern static unsafe int ReceiveFrom_internal(IntPtr sock, byte* buffer, int count, SocketFlags flags, ref SocketAddress sockaddr, out int error, bool blocking);
 
 #endregion
 
@@ -1777,8 +1773,12 @@ namespace System.Net.Sockets
                        int nativeError;
                        int sent = 0;
                        do {
-                               sent += Send_internal (
-m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_blocking);
+                               unsafe {
+                                       fixed (byte *pbuffer = buffer) {
+                                               sent += Send_internal (m_Handle, &pbuffer[offset + sent], size - sent, socketFlags, out nativeError, is_blocking);
+                                       }
+                               }
+
                                errorCode = (SocketError)nativeError;
                                if (errorCode != SocketError.Success && errorCode != SocketError.WouldBlock && errorCode != SocketError.InProgress) {
                                        is_connected = false;
@@ -1806,28 +1806,32 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                        int nativeError;
                        int ret;
 
-                       WSABUF[] bufarray = new WSABUF[numsegments];
                        GCHandle[] gch = new GCHandle[numsegments];
+                       try {
+                               unsafe {
+                                       fixed (WSABUF* bufarray = new WSABUF[numsegments]) {
+                                               for(int i = 0; i < numsegments; i++) {
+                                                       ArraySegment<byte> segment = buffers[i];
 
-                       for(int i = 0; i < numsegments; i++) {
-                               ArraySegment<byte> segment = buffers[i];
+                                                       if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
+                                                               throw new ArgumentOutOfRangeException ("segment");
 
-                               if (segment.Offset < 0 || segment.Count < 0 || segment.Count > segment.Array.Length - segment.Offset)
-                                       throw new ArgumentOutOfRangeException ("segment");
+                                                       try {} finally {
+                                                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
+                                                       }
 
-                               gch[i] = GCHandle.Alloc (segment.Array, GCHandleType.Pinned);
-                               bufarray[i].len = segment.Count;
-                               bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
-                       }
+                                                       bufarray[i].len = segment.Count;
+                                                       bufarray[i].buf = Marshal.UnsafeAddrOfPinnedArrayElement (segment.Array, segment.Offset);
+                                               }
 
-                       try {
-                               ret = Send_internal (m_Handle, bufarray, socketFlags, out nativeError, is_blocking);
-                       } finally {
-                               for(int i = 0; i < numsegments; i++) {
-                                       if (gch[i].IsAllocated) {
-                                               gch[i].Free ();
+                                               ret = Send_internal (m_Handle, bufarray, numsegments, socketFlags, out nativeError, is_blocking);
                                        }
                                }
+                       } finally {
+                               for (int i = 0; i < numsegments; i++) {
+                                       if (gch[i].IsAllocated)
+                                               gch[i].Free();
+                               }
                        }
 
                        errorCode = (SocketError)nativeError;
@@ -1910,7 +1914,11 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                        int total = 0;
 
                        try {
-                               total = Socket.Send_internal (sockares.socket.m_Handle, sockares.Buffer, sockares.Offset, sockares.Size, sockares.SockFlags, out sockares.error, false);
+                               unsafe {
+                                       fixed (byte *pbuffer = sockares.Buffer) {
+                                               total = Socket.Send_internal (sockares.socket.m_Handle, &pbuffer[sockares.Offset], sockares.Size, sockares.SockFlags, out sockares.error, false);
+                                       }
+                               }
                        } catch (Exception e) {
                                sockares.Complete (e);
                                return;
@@ -1998,31 +2006,31 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                        return sockares.Total;
                }
 
-               static int Send_internal (SafeSocketHandle safeHandle, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking)
+               static unsafe int Send_internal (SafeSocketHandle safeHandle, WSABUF* bufarray, int count, SocketFlags flags, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return Send_internal (safeHandle.DangerousGetHandle (), bufarray, flags, out error, blocking);
+                               return Send_internal (safeHandle.DangerousGetHandle (), bufarray, count, flags, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               extern static int Send_internal (IntPtr sock, WSABUF[] bufarray, SocketFlags flags, out int error, bool blocking);
+               extern static unsafe int Send_internal (IntPtr sock, WSABUF* bufarray, int count, SocketFlags flags, out int error, bool blocking);
 
-               static int Send_internal (SafeSocketHandle safeHandle, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking)
+               static unsafe int Send_internal (SafeSocketHandle safeHandle, byte* buffer, int count, SocketFlags flags, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return Send_internal (safeHandle.DangerousGetHandle (), buf, offset, count, flags, out error, blocking);
+                               return Send_internal (safeHandle.DangerousGetHandle (), buffer, count, flags, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static int Send_internal(IntPtr sock, byte[] buf, int offset, int count, SocketFlags flags, out int error, bool blocking);
+               extern static unsafe int Send_internal(IntPtr sock, byte* buffer, int count, SocketFlags flags, out int error, bool blocking);
 
 #endregion
 
@@ -2038,7 +2046,12 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                                throw new ArgumentNullException("remoteEP");
 
                        int error;
-                       int ret = SendTo_internal (m_Handle, buffer, offset, size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
+                       int ret;
+                       unsafe {
+                               fixed (byte *pbuffer = buffer) {
+                                       ret = SendTo_internal (m_Handle, &pbuffer[offset], size, socketFlags, remoteEP.Serialize (), out error, is_blocking);
+                               }
+                       }
 
                        SocketError err = (SocketError) error;
                        if (err != 0) {
@@ -2154,18 +2167,18 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                        return sockares.Total;
                }
 
-               static int SendTo_internal (SafeSocketHandle safeHandle, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
+               static unsafe int SendTo_internal (SafeSocketHandle safeHandle, byte* buffer, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking)
                {
                        try {
                                safeHandle.RegisterForBlockingSyscall ();
-                               return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, offset, count, flags, sa, out error, blocking);
+                               return SendTo_internal (safeHandle.DangerousGetHandle (), buffer, count, flags, sa, out error, blocking);
                        } finally {
                                safeHandle.UnRegisterForBlockingSyscall ();
                        }
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern static int SendTo_internal (IntPtr sock, byte[] buffer, int offset, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
+               extern static unsafe int SendTo_internal (IntPtr sock, byte* buffer, int count, SocketFlags flags, SocketAddress sa, out int error, bool blocking);
 
 #endregion
 
@@ -2285,6 +2298,9 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
 
 #region DuplicateAndClose
 
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               static extern bool Duplicate_internal(IntPtr handle, int targetProcessId, out IntPtr duplicateHandle, out MonoIOError error);
+
                [MonoLimitation ("We do not support passing sockets across processes, we merely allow this API to pass the socket across AppDomains")]
                public SocketInformation DuplicateAndClose (int targetProcessId)
                {
@@ -2295,9 +2311,8 @@ m_Handle, buffer, offset + sent, size - sent, socketFlags, out nativeError, is_b
                                (is_blocking       ? 0 : SocketInformationOptions.NonBlocking) |
                                (useOverlappedIO ? SocketInformationOptions.UseOnlyOverlappedIO : 0);
 
-                       MonoIOError error;
                        IntPtr duplicateHandle;
-                       if (!MonoIO.DuplicateHandle (System.Diagnostics.Process.GetCurrentProcess ().Handle, Handle, new IntPtr (targetProcessId), out duplicateHandle, 0, 0, 0x00000002 /* DUPLICATE_SAME_ACCESS */, out error))
+                       if (!Duplicate_internal (Handle, targetProcessId, out duplicateHandle, out MonoIOError error))
                                throw MonoIO.GetException (error);
 
                        si.ProtocolInformation = Mono.DataConverter.Pack ("iiiil", (int)addressFamily, (int)socketType, (int)protocolType, is_bound ? 1 : 0, (long)duplicateHandle);