summaryrefslogtreecommitdiff
path: root/mcs/class/System
diff options
context:
space:
mode:
authorJo Shields <directhex@apebox.org>2014-02-19 22:12:43 +0000
committerJo Shields <directhex@apebox.org>2014-02-19 22:12:43 +0000
commit9972bf87b4f27d9c8f358ef8414ac1ab957a2f0f (patch)
tree5bb230c1d698659115f918e243c1d4b0aa4c7f51 /mcs/class/System
parentd0a215f5626219ff7927f576588a777e5331c7be (diff)
downloadmono-upstream/3.2.8+dfsg.tar.gz
Imported Upstream version 3.2.8+dfsgupstream/3.2.8+dfsg
Diffstat (limited to 'mcs/class/System')
-rwxr-xr-xmcs/class/System/Documentation/en/System.Net/IPAddress.xml15
-rw-r--r--mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs17
-rw-r--r--mcs/class/System/System.CodeDom.Compiler/TempFileCollection.cs45
-rw-r--r--mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs44
-rw-r--r--mcs/class/System/System.Collections.Concurrent/ConcurrentBag.cs10
-rw-r--r--mcs/class/System/System.ComponentModel/BindingList.cs2
-rw-r--r--mcs/class/System/System.ComponentModel/Component.cs2
-rw-r--r--mcs/class/System/System.Configuration/SettingValueElement.cs75
-rw-r--r--mcs/class/System/System.Diagnostics/Process.cs39
-rw-r--r--mcs/class/System/System.IO.Compression/CompressionLevel.cs2
-rw-r--r--mcs/class/System/System.Net.NetworkInformation/NetworkChange.cs319
-rw-r--r--mcs/class/System/System.Net.Sockets/NetworkStream.cs8
-rw-r--r--mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs330
-rw-r--r--mcs/class/System/System.Net.WebSockets/ClientWebSocketOptions.cs45
-rw-r--r--mcs/class/System/System.Net.WebSockets/WebSocketException.cs38
-rw-r--r--mcs/class/System/System.Net.WebSockets/WebSocketMessageType.cs6
-rw-r--r--mcs/class/System/System.Net.WebSockets/WebSocketReceiveResult.cs10
-rw-r--r--mcs/class/System/System.Net/HttpWebRequest.cs41
-rw-r--r--mcs/class/System/System.Net/HttpWebResponse.cs3
-rw-r--r--mcs/class/System/System.Net/IPAddress.cs10
-rw-r--r--mcs/class/System/System.Net/MacProxy.cs86
-rw-r--r--mcs/class/System/System.Net/ServicePointManager.cs5
-rw-r--r--mcs/class/System/System.Net/TransportContext.cs2
-rw-r--r--mcs/class/System/System.Net/WebConnection.cs27
-rw-r--r--mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs67
-rw-r--r--mcs/class/System/System.Timers/Timer.cs8
-rw-r--r--mcs/class/System/System.Windows.Input/ICommand.cs8
-rw-r--r--mcs/class/System/System_test.dll.sources1
-rw-r--r--mcs/class/System/Test/Microsoft.CSharp/CSharpCodeProviderTest.cs43
-rw-r--r--mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs55
-rw-r--r--mcs/class/System/Test/System.Collections.Concurrent/ConcurrentBagTests.cs44
-rw-r--r--mcs/class/System/Test/System.ComponentModel/BindingListTest.cs10
-rwxr-xr-x[-rw-r--r--]mcs/class/System/Test/System.Net.Sockets/SocketTest.cs48
-rw-r--r--mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs23
-rw-r--r--mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs242
-rw-r--r--mcs/class/System/Test/System.Net/IPAddressTest.cs9
-rw-r--r--mcs/class/System/mobile_System.dll.sources98
37 files changed, 1537 insertions, 300 deletions
diff --git a/mcs/class/System/Documentation/en/System.Net/IPAddress.xml b/mcs/class/System/Documentation/en/System.Net/IPAddress.xml
index f2caec0386..e428def11c 100755
--- a/mcs/class/System/Documentation/en/System.Net/IPAddress.xml
+++ b/mcs/class/System/Documentation/en/System.Net/IPAddress.xml
@@ -541,6 +541,21 @@ in network-byte-order.</para>
<remarks>To be added.</remarks>
</Docs>
</Member>
+ <Member MemberName="IsIPv6Teredo">
+ <MemberSignature Language="C#" Value="public bool IsIPv6Teredo { get; }" />
+ <MemberType>Property</MemberType>
+ <AssemblyInfo>
+ <AssemblyVersion>4.0.0.0</AssemblyVersion>
+ </AssemblyInfo>
+ <ReturnValue>
+ <ReturnType>System.Boolean</ReturnType>
+ </ReturnValue>
+ <Docs>
+ <summary>To be added.</summary>
+ <value>To be added.</value>
+ <remarks>To be added.</remarks>
+ </Docs>
+ </Member>
<Member MemberName="IsLoopback">
<MemberSignature Language="ILASM" Value=".method public hidebysig static bool IsLoopback(class System.Net.IPAddress address)" />
<MemberSignature Language="C#" Value="public static bool IsLoopback (System.Net.IPAddress addr);" />
diff --git a/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs b/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs
index 26039bdd79..62b41de358 100644
--- a/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs
+++ b/mcs/class/System/Microsoft.CSharp/CSharpCodeCompiler.cs
@@ -395,6 +395,20 @@ namespace Mono.CSharp
args.AppendFormat("\"{0}\" ",source);
return args.ToString();
}
+
+ // Keep in sync with mcs/class/Microsoft.Build.Utilities/Microsoft.Build.Utilities/ToolTask.cs
+ const string ErrorRegexPattern = @"
+ ^
+ (\s*(?<file>[^\(]+) # filename (optional)
+ (\((?<line>\d*)(,(?<column>\d*[\+]*))?\))? # line+column (optional)
+ :\s+)?
+ (?<level>\w+) # error|warning
+ \s+
+ (?<number>[^:]*\d) # CS1234
+ :
+ \s*
+ (?<message>.*)$";
+
private static CompilerError CreateErrorFromString(string error_string)
{
if (error_string.StartsWith ("BETA"))
@@ -404,8 +418,7 @@ namespace Mono.CSharp
return null;
CompilerError error=new CompilerError();
- Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)(:)?\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",
- RegexOptions.Compiled | RegexOptions.ExplicitCapture);
+ Regex reg = new Regex (ErrorRegexPattern, RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace);
Match match=reg.Match(error_string);
if (!match.Success) {
// We had some sort of runtime crash
diff --git a/mcs/class/System/System.CodeDom.Compiler/TempFileCollection.cs b/mcs/class/System/System.CodeDom.Compiler/TempFileCollection.cs
index da056d1533..80c30eece7 100644
--- a/mcs/class/System/System.CodeDom.Compiler/TempFileCollection.cs
+++ b/mcs/class/System/System.CodeDom.Compiler/TempFileCollection.cs
@@ -73,33 +73,36 @@ namespace System.CodeDom.Compiler {
// note: this property *cannot* change TempDir property
string temp = tempdir;
- if (temp.Length == 0)
- temp = GetOwnTempDir ();
+ if (temp.Length == 0) {
+ if (ownTempDir != null) {
+ temp = ownTempDir;
+ Directory.CreateDirectory (temp);
+ } else {
+ temp = CreateOwnTempDir ();
+ }
+ }
// Create a temporary file at the target directory. This ensures
// that the generated file name is unique.
- FileStream f = null;
- do {
+ int test_counter = 1000;
+ while (true) {
int num = rnd.Next ();
num++;
basepath = Path.Combine (temp, num.ToString("x"));
string path = basepath + ".tmp";
try {
- f = new FileStream (path, FileMode.CreateNew);
- }
- catch (System.IO.IOException) {
- f = null;
- continue;
- }
- catch {
- // avoid endless loop
+ using (var f = new FileStream (path, FileMode.CreateNew)) {
+ break;
+ }
+ } catch (IOException) {
+ if (test_counter-- > 0)
+ continue;
+
throw;
}
- } while (f == null);
-
- f.Close ();
-
+ }
+
// and you must have discovery access to the combined path
// note: the cache behaviour is tested in the CAS tests
if (SecurityManager.SecurityEnabled) {
@@ -110,12 +113,9 @@ namespace System.CodeDom.Compiler {
return(basepath);
}
}
-
- string GetOwnTempDir ()
- {
- if (ownTempDir != null)
- return ownTempDir;
+ string CreateOwnTempDir ()
+ {
// this call ensure the Environment permissions check
string basedir = Path.GetTempPath ();
@@ -245,9 +245,8 @@ namespace System.CodeDom.Compiler {
File.Delete (tmpFile);
basepath = null;
}
- if (allDeleted && ownTempDir != null) {
+ if (allDeleted && ownTempDir != null && filenames.Length > 0) {
Directory.Delete (ownTempDir, true);
- ownTempDir = null;
}
}
diff --git a/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs b/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs
index 26dc84a078..cc7e04ecdd 100644
--- a/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs
+++ b/mcs/class/System/System.Collections.Concurrent/BlockingCollection.cs
@@ -370,13 +370,19 @@ namespace System.Collections.Concurrent
{
item = default (T);
CheckArray (collections);
- int index = 0;
- foreach (var coll in collections) {
- try {
- item = coll.Take ();
- return index;
- } catch {}
- index++;
+ WaitHandle[] wait_table = null;
+ while (true) {
+ int index = 0;
+ for (int i = 0; i < collections.Length; ++i) {
+ if (collections [i].TryTake (out item))
+ return i;
+ }
+ if (wait_table == null) {
+ wait_table = new WaitHandle [collections.Length];
+ for (int i = 0; i < collections.Length; ++i)
+ wait_table [i] = collections [i].mreRemove.WaitHandle;
+ }
+ WaitHandle.WaitAny (wait_table);
}
return -1;
}
@@ -385,14 +391,24 @@ namespace System.Collections.Concurrent
{
item = default (T);
CheckArray (collections);
- int index = 0;
- foreach (var coll in collections) {
- try {
- item = coll.Take (cancellationToken);
- return index;
- } catch {}
- index++;
+ WaitHandle[] wait_table = null;
+ while (true) {
+ int index = 0;
+ for (int i = 0; i < collections.Length; ++i) {
+ if (collections [i].TryTake (out item))
+ return i;
+ }
+ cancellationToken.ThrowIfCancellationRequested ();
+ if (wait_table == null) {
+ wait_table = new WaitHandle [collections.Length + 1];
+ for (int i = 0; i < collections.Length; ++i)
+ wait_table [i] = collections [i].mreRemove.WaitHandle;
+ wait_table [collections.Length] = cancellationToken.WaitHandle;
+ }
+ WaitHandle.WaitAny (wait_table);
+ cancellationToken.ThrowIfCancellationRequested ();
}
+
return -1;
}
diff --git a/mcs/class/System/System.Collections.Concurrent/ConcurrentBag.cs b/mcs/class/System/System.Collections.Concurrent/ConcurrentBag.cs
index 5b4cbfcf1a..cd063347c6 100644
--- a/mcs/class/System/System.Collections.Concurrent/ConcurrentBag.cs
+++ b/mcs/class/System/System.Collections.Concurrent/ConcurrentBag.cs
@@ -65,6 +65,7 @@ namespace System.Collections.Concurrent
int index;
CyclicDeque<T> bag = GetBag (out index);
bag.PushBottom (item);
+ staging.TryAdd (index, bag);
AddHint (index);
Interlocked.Increment (ref count);
}
@@ -88,6 +89,7 @@ namespace System.Collections.Concurrent
if (bag == null || bag.PopBottom (out result) != PopResult.Succeed) {
var self = bag;
+ ret = false;
foreach (var other in staging) {
// Try to retrieve something based on a hint
ret = TryGetHint (out hintIndex) && (bag = container[hintIndex]).PopTop (out result) == PopResult.Succeed;
@@ -129,6 +131,7 @@ namespace System.Collections.Concurrent
if (bag == null || !bag.PeekBottom (out result)) {
var self = bag;
+ ret = false;
foreach (var other in staging) {
// Try to retrieve something based on a hint
ret = TryGetHint (out hintIndex) && container[hintIndex].PeekTop (out result);
@@ -264,10 +267,7 @@ namespace System.Collections.Concurrent
if (container.TryGetValue (index, out value))
return value;
- var bag = createBag ? container.GetOrAdd (index, new CyclicDeque<T> ()) : null;
- if (bag != null)
- staging.TryAdd (index, bag);
- return bag;
+ return createBag ? container.GetOrAdd (index, new CyclicDeque<T> ()) : null;
}
void TidyBag (int index, CyclicDeque<T> bag)
@@ -279,4 +279,4 @@ namespace System.Collections.Concurrent
}
}
}
-#endif \ No newline at end of file
+#endif
diff --git a/mcs/class/System/System.ComponentModel/BindingList.cs b/mcs/class/System/System.ComponentModel/BindingList.cs
index b64d655efe..b4c0ce8b69 100644
--- a/mcs/class/System/System.ComponentModel/BindingList.cs
+++ b/mcs/class/System/System.ComponentModel/BindingList.cs
@@ -242,7 +242,7 @@ namespace System.ComponentModel {
if (raise_list_changed_events)
OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, index));
- if (type_raises_item_changed_events)
+ if (item != null && type_raises_item_changed_events)
(item as INotifyPropertyChanged).PropertyChanged += Item_PropertyChanged;
}
diff --git a/mcs/class/System/System.ComponentModel/Component.cs b/mcs/class/System/System.ComponentModel/Component.cs
index 5c61d72eef..1095161648 100644
--- a/mcs/class/System/System.ComponentModel/Component.cs
+++ b/mcs/class/System/System.ComponentModel/Component.cs
@@ -44,7 +44,7 @@ namespace System.ComponentModel {
private EventHandlerList event_handlers;
private ISite mySite;
- private object disposedEvent = new object ();
+ static readonly object disposedEvent = new object ();
public Component ()
{
diff --git a/mcs/class/System/System.Configuration/SettingValueElement.cs b/mcs/class/System/System.Configuration/SettingValueElement.cs
index bf618659ce..4c336dd005 100644
--- a/mcs/class/System/System.Configuration/SettingValueElement.cs
+++ b/mcs/class/System/System.Configuration/SettingValueElement.cs
@@ -27,6 +27,7 @@
//
using System;
+using System.Reflection;
#if (XML_DEP)
using System.Xml;
#endif
@@ -112,7 +113,79 @@ namespace System.Configuration
#if (CONFIGURATION_DEP)
protected override void Unmerge (ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode saveMode)
{
- throw new NotImplementedException ();
+ if (parentElement != null && sourceElement.GetType() != parentElement.GetType())
+ throw new ConfigurationErrorsException ("Can't unmerge two elements of different type");
+
+ bool isMinimalOrModified = saveMode == ConfigurationSaveMode.Minimal ||
+ saveMode == ConfigurationSaveMode.Modified;
+
+ foreach (PropertyInformation prop in sourceElement.ElementInformation.Properties)
+ {
+ if (prop.ValueOrigin == PropertyValueOrigin.Default)
+ continue;
+
+ PropertyInformation unmergedProp = ElementInformation.Properties [prop.Name];
+
+ object sourceValue = prop.Value;
+ if (parentElement == null || !HasValue (parentElement, prop.Name)) {
+ unmergedProp.Value = sourceValue;
+ continue;
+ }
+
+ if (sourceValue == null)
+ continue;
+
+ object parentValue = GetItem (parentElement, prop.Name);
+ if (!PropertyIsElement (prop)) {
+ if (!object.Equals (sourceValue, parentValue) ||
+ (saveMode == ConfigurationSaveMode.Full) ||
+ (saveMode == ConfigurationSaveMode.Modified && prop.ValueOrigin == PropertyValueOrigin.SetHere))
+ unmergedProp.Value = sourceValue;
+ continue;
+ }
+
+ var sourceElem = (ConfigurationElement) sourceValue;
+ if (isMinimalOrModified && !ElementIsModified (sourceElem))
+ continue;
+ if (parentValue == null) {
+ unmergedProp.Value = sourceValue;
+ continue;
+ }
+
+ var parentElem = (ConfigurationElement) parentValue;
+ ConfigurationElement copy = (ConfigurationElement) unmergedProp.Value;
+ ElementUnmerge (copy, sourceElem, parentElem, saveMode);
+ }
+ }
+
+ bool HasValue (ConfigurationElement element, string propName)
+ {
+ PropertyInformation info = element.ElementInformation.Properties [propName];
+ return info != null && info.ValueOrigin != PropertyValueOrigin.Default;
+ }
+
+ object GetItem (ConfigurationElement element, string property)
+ {
+ PropertyInformation pi = ElementInformation.Properties [property];
+ if (pi == null)
+ throw new InvalidOperationException ("Property '" + property + "' not found in configuration element");
+
+ return pi.Value;
+ }
+
+ bool PropertyIsElement (PropertyInformation prop)
+ {
+ return (typeof(ConfigurationElement).IsAssignableFrom (prop.Type));
+ }
+
+ bool ElementIsModified (ConfigurationElement element)
+ {
+ return (bool) element.GetType ().GetMethod ("IsModified", BindingFlags.NonPublic | BindingFlags.Instance).Invoke (element, new object [0]);
+ }
+
+ void ElementUnmerge (ConfigurationElement target, ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode saveMode)
+ {
+ target.GetType ().GetMethod ("Unmerge", BindingFlags.NonPublic | BindingFlags.Instance).Invoke (target, new object [] {sourceElement, parentElement, saveMode});
}
#endif
}
diff --git a/mcs/class/System/System.Diagnostics/Process.cs b/mcs/class/System/System.Diagnostics/Process.cs
index e08d79e0f1..7a63ce0377 100644
--- a/mcs/class/System/System.Diagnostics/Process.cs
+++ b/mcs/class/System/System.Diagnostics/Process.cs
@@ -918,8 +918,7 @@ namespace System.Diagnostics {
IntPtr stderr,
ref ProcInfo proc_info);
- private static bool Start_shell (ProcessStartInfo startInfo,
- Process process)
+ private static bool Start_shell (ProcessStartInfo startInfo, Process process)
{
ProcInfo proc_info=new ProcInfo();
bool ret;
@@ -948,9 +947,7 @@ namespace System.Diagnostics {
process.process_handle = proc_info.process_handle;
process.pid = proc_info.pid;
-
process.StartExitCallbackIfNeeded ();
-
return(ret);
}
@@ -1182,9 +1179,9 @@ namespace System.Diagnostics {
if (startInfo == null)
throw new ArgumentNullException ("startInfo");
- Process process=new Process();
+ Process process = new Process();
process.StartInfo = startInfo;
- if (Start_common(startInfo, process))
+ if (Start_common(startInfo, process) && process.process_handle != IntPtr.Zero)
return process;
return null;
}
@@ -1566,6 +1563,21 @@ namespace System.Diagnostics {
async_output.Close ();
if (async_error != null)
async_error.Close ();
+
+ if (input_stream != null) {
+ input_stream.Close();
+ input_stream = null;
+ }
+
+ if (output_stream != null) {
+ output_stream.Close();
+ output_stream = null;
+ }
+
+ if (error_stream != null) {
+ error_stream.Close();
+ error_stream = null;
+ }
}
}
@@ -1576,21 +1588,6 @@ namespace System.Diagnostics {
Process_free_internal(process_handle);
process_handle=IntPtr.Zero;
}
-
- if (input_stream != null) {
- input_stream.Close();
- input_stream = null;
- }
-
- if (output_stream != null) {
- output_stream.Close();
- output_stream = null;
- }
-
- if (error_stream != null) {
- error_stream.Close();
- error_stream = null;
- }
}
}
base.Dispose (disposing);
diff --git a/mcs/class/System/System.IO.Compression/CompressionLevel.cs b/mcs/class/System/System.IO.Compression/CompressionLevel.cs
index 7ea3a7a49f..2242c19cf5 100644
--- a/mcs/class/System/System.IO.Compression/CompressionLevel.cs
+++ b/mcs/class/System/System.IO.Compression/CompressionLevel.cs
@@ -27,7 +27,7 @@
#if NET_4_5
namespace System.IO.Compression {
public enum CompressionLevel {
- Optional,
+ Optimal,
Fastest,
NoCompression
}
diff --git a/mcs/class/System/System.Net.NetworkInformation/NetworkChange.cs b/mcs/class/System/System.Net.NetworkInformation/NetworkChange.cs
index c60954c949..de9754e951 100644
--- a/mcs/class/System/System.Net.NetworkInformation/NetworkChange.cs
+++ b/mcs/class/System/System.Net.NetworkInformation/NetworkChange.cs
@@ -2,8 +2,8 @@
// System.Net.NetworkInformation.NetworkChange
//
// Authors:
-// Gonzalo Paniagua Javier (gonzalo@novell.com)
-// Aaron Bockover (abock@xamarin.com)
+// Gonzalo Paniagua Javier (LinuxNetworkChange) (gonzalo@novell.com)
+// Aaron Bockover (MacNetworkChange) (abock@xamarin.com)
//
// Copyright (c) 2006,2011 Novell, Inc. (http://www.novell.com)
// Copyright (c) 2013 Xamarin, Inc. (http://www.xamarin.com)
@@ -15,10 +15,10 @@
// 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
@@ -28,137 +28,298 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
+#if NETWORK_CHANGE_STANDALONE
+namespace NetworkInformation {
+
+ public class NetworkAvailabilityEventArgs : EventArgs
+ {
+ public bool IsAvailable { get; set; }
+
+ public NetworkAvailabilityEventArgs (bool available)
+ {
+ IsAvailable = available;
+ }
+ }
+
+ public delegate void NetworkAddressChangedEventHandler (object sender, EventArgs args);
+ public delegate void NetworkAvailabilityChangedEventHandler (object sender, NetworkAvailabilityEventArgs args);
+#else
namespace System.Net.NetworkInformation {
- internal interface INetworkChange {
+#endif
+
+ internal interface INetworkChange : IDisposable {
event NetworkAddressChangedEventHandler NetworkAddressChanged;
event NetworkAvailabilityChangedEventHandler NetworkAvailabilityChanged;
+ bool HasRegisteredEvents { get; }
}
public sealed class NetworkChange {
static INetworkChange networkChange;
- static NetworkChange ()
+ public static event NetworkAddressChangedEventHandler NetworkAddressChanged {
+ add {
+ lock (typeof (INetworkChange)) {
+ MaybeCreate ();
+ if (networkChange != null)
+ networkChange.NetworkAddressChanged += value;
+ }
+ }
+
+ remove {
+ lock (typeof (INetworkChange)) {
+ if (networkChange != null) {
+ networkChange.NetworkAddressChanged -= value;
+ MaybeDispose ();
+ }
+ }
+ }
+ }
+
+ public static event NetworkAvailabilityChangedEventHandler NetworkAvailabilityChanged {
+ add {
+ lock (typeof (INetworkChange)) {
+ MaybeCreate ();
+ if (networkChange != null)
+ networkChange.NetworkAvailabilityChanged += value;
+ }
+ }
+
+ remove {
+ lock (typeof (INetworkChange)) {
+ if (networkChange != null) {
+ networkChange.NetworkAvailabilityChanged -= value;
+ MaybeDispose ();
+ }
+ }
+ }
+ }
+
+ static void MaybeCreate ()
{
- if (MacNetworkChange.IsEnabled) {
+ if (networkChange != null)
+ return;
+
+ try {
networkChange = new MacNetworkChange ();
- } else {
+ } catch {
+#if !NETWORK_CHANGE_STANDALONE
networkChange = new LinuxNetworkChange ();
+#endif
}
}
- public static event NetworkAddressChangedEventHandler NetworkAddressChanged {
- add { networkChange.NetworkAddressChanged += value; }
- remove { networkChange.NetworkAddressChanged -= value; }
+ static void MaybeDispose ()
+ {
+ if (networkChange != null && networkChange.HasRegisteredEvents) {
+ networkChange.Dispose ();
+ networkChange = null;
+ }
}
+ }
- public static event NetworkAvailabilityChangedEventHandler NetworkAvailabilityChanged {
- add { networkChange.NetworkAvailabilityChanged += value; }
- remove { networkChange.NetworkAvailabilityChanged -= value; }
+ internal sealed class MacNetworkChange : INetworkChange
+ {
+ const string DL_LIB = "/usr/lib/libSystem.dylib";
+ const string CORE_SERVICES_LIB = "/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration";
+ const string CORE_FOUNDATION_LIB = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
+
+ [UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)]
+ delegate void SCNetworkReachabilityCallback (IntPtr target, NetworkReachabilityFlags flags, IntPtr info);
+
+ [DllImport (DL_LIB)]
+ static extern IntPtr dlopen (string path, int mode);
+
+ [DllImport (DL_LIB)]
+ static extern IntPtr dlsym (IntPtr handle, string symbol);
+
+ [DllImport (DL_LIB)]
+ static extern int dlclose (IntPtr handle);
+
+ [DllImport (CORE_FOUNDATION_LIB)]
+ static extern void CFRelease (IntPtr handle);
+
+ [DllImport (CORE_FOUNDATION_LIB)]
+ static extern IntPtr CFRunLoopGetMain ();
+
+ [DllImport (CORE_SERVICES_LIB)]
+ static extern IntPtr SCNetworkReachabilityCreateWithAddress (IntPtr allocator, ref sockaddr_in sockaddr);
+
+ [DllImport (CORE_SERVICES_LIB)]
+ static extern bool SCNetworkReachabilityGetFlags (IntPtr reachability, out NetworkReachabilityFlags flags);
+
+ [DllImport (CORE_SERVICES_LIB)]
+ static extern bool SCNetworkReachabilitySetCallback (IntPtr reachability, SCNetworkReachabilityCallback callback, ref SCNetworkReachabilityContext context);
+
+ [DllImport (CORE_SERVICES_LIB)]
+ static extern bool SCNetworkReachabilityScheduleWithRunLoop (IntPtr reachability, IntPtr runLoop, IntPtr runLoopMode);
+
+ [DllImport (CORE_SERVICES_LIB)]
+ static extern bool SCNetworkReachabilityUnscheduleFromRunLoop (IntPtr reachability, IntPtr runLoop, IntPtr runLoopMode);
+
+ [StructLayout (LayoutKind.Explicit, Size = 28)]
+ struct sockaddr_in {
+ [FieldOffset (0)] public byte sin_len;
+ [FieldOffset (1)] public byte sin_family;
+
+ public static sockaddr_in Create ()
+ {
+ return new sockaddr_in {
+ sin_len = 28,
+ sin_family = 2 // AF_INET
+ };
+ }
}
- }
- internal sealed class MacNetworkChange : INetworkChange {
- public static bool IsEnabled {
- get { return mono_sc_reachability_enabled () != 0; }
+ [StructLayout (LayoutKind.Sequential)]
+ struct SCNetworkReachabilityContext {
+ public IntPtr version;
+ public IntPtr info;
+ public IntPtr retain;
+ public IntPtr release;
+ public IntPtr copyDescription;
+ }
+
+ [Flags]
+ enum NetworkReachabilityFlags {
+ None = 0,
+ TransientConnection = 1 << 0,
+ Reachable = 1 << 1,
+ ConnectionRequired = 1 << 2,
+ ConnectionOnTraffic = 1 << 3,
+ InterventionRequired = 1 << 4,
+ ConnectionOnDemand = 1 << 5,
+ IsLocalAddress = 1 << 16,
+ IsDirect = 1 << 17,
+ IsWWAN = 1 << 18,
+ ConnectionAutomatic = ConnectionOnTraffic
}
+ IntPtr handle;
+ IntPtr runLoopMode;
+ SCNetworkReachabilityCallback callback;
+ bool scheduledWithRunLoop;
+ NetworkReachabilityFlags flags;
+
event NetworkAddressChangedEventHandler networkAddressChanged;
event NetworkAvailabilityChangedEventHandler networkAvailabilityChanged;
public event NetworkAddressChangedEventHandler NetworkAddressChanged {
add {
- if (value != null) {
- MaybeInitialize ();
- networkAddressChanged += value;
- value (null, EventArgs.Empty);
- }
+ value (null, EventArgs.Empty);
+ networkAddressChanged += value;
}
- remove {
- networkAddressChanged -= value;
- MaybeDispose ();
- }
+ remove { networkAddressChanged -= value; }
}
public event NetworkAvailabilityChangedEventHandler NetworkAvailabilityChanged {
add {
- if (value != null) {
- MaybeInitialize ();
- networkAvailabilityChanged += value;
- var available = handle != IntPtr.Zero && mono_sc_reachability_is_available (handle) != 0;
- value (null, new NetworkAvailabilityEventArgs (available));
- }
+ value (null, new NetworkAvailabilityEventArgs (IsAvailable));
+ networkAvailabilityChanged += value;
}
- remove {
- networkAvailabilityChanged -= value;
- MaybeDispose ();
+ remove { networkAvailabilityChanged -= value; }
+ }
+
+ bool IsAvailable {
+ get {
+ return (flags & NetworkReachabilityFlags.Reachable) != 0 &&
+ (flags & NetworkReachabilityFlags.ConnectionRequired) == 0;
}
}
- IntPtr handle;
- MonoSCReachabilityCallback callback;
+ public bool HasRegisteredEvents {
+ get { return networkAddressChanged != null || networkAvailabilityChanged != null; }
+ }
- void Callback (int available)
+ public MacNetworkChange ()
{
- var addressChanged = networkAddressChanged;
- if (addressChanged != null) {
- addressChanged (null, EventArgs.Empty);
- }
+ var sockaddr = sockaddr_in.Create ();
+ handle = SCNetworkReachabilityCreateWithAddress (IntPtr.Zero, ref sockaddr);
+ if (handle == IntPtr.Zero)
+ throw new Exception ("SCNetworkReachabilityCreateWithAddress returned NULL");
- var availabilityChanged = networkAvailabilityChanged;
- if (availabilityChanged != null) {
- availabilityChanged (null, new NetworkAvailabilityEventArgs (available != 0));
- }
+ callback = new SCNetworkReachabilityCallback (HandleCallback);
+ var info = new SCNetworkReachabilityContext {
+ info = GCHandle.ToIntPtr (GCHandle.Alloc (this))
+ };
+
+ SCNetworkReachabilitySetCallback (handle, callback, ref info);
+
+ scheduledWithRunLoop =
+ LoadRunLoopMode () &&
+ SCNetworkReachabilityScheduleWithRunLoop (handle, CFRunLoopGetMain (), runLoopMode);
+
+ SCNetworkReachabilityGetFlags (handle, out flags);
}
- void MaybeInitialize ()
+ bool LoadRunLoopMode ()
{
- lock (this) {
- if (handle == IntPtr.Zero) {
- callback = new MonoSCReachabilityCallback (Callback);
- handle = mono_sc_reachability_new (callback);
+ var cfLibHandle = dlopen (CORE_FOUNDATION_LIB, 0);
+ if (cfLibHandle == IntPtr.Zero)
+ return false;
+
+ try {
+ runLoopMode = dlsym (cfLibHandle, "kCFRunLoopDefaultMode");
+ if (runLoopMode != IntPtr.Zero) {
+ runLoopMode = Marshal.ReadIntPtr (runLoopMode);
+ return runLoopMode != IntPtr.Zero;
}
+ } finally {
+ dlclose (cfLibHandle);
}
+
+ return false;
}
- void MaybeDispose ()
+ public void Dispose ()
{
lock (this) {
- var addressChanged = networkAddressChanged;
- var availabilityChanged = networkAvailabilityChanged;
- if (handle != IntPtr.Zero && addressChanged == null && availabilityChanged == null) {
- mono_sc_reachability_free (handle);
- handle = IntPtr.Zero;
- }
+ if (handle == IntPtr.Zero)
+ return;
+
+ if (scheduledWithRunLoop)
+ SCNetworkReachabilityUnscheduleFromRunLoop (handle, CFRunLoopGetMain (), runLoopMode);
+
+ CFRelease (handle);
+ handle = IntPtr.Zero;
+ callback = null;
+ flags = NetworkReachabilityFlags.None;
+ scheduledWithRunLoop = false;
}
}
-#if MONOTOUCH || MONODROID
- const string LIBNAME = "__Internal";
-#else
- const string LIBNAME = "MonoPosixHelper";
+#if MONOTOUCH
+ [MonoTouch.MonoPInvokeCallback (typeof (SCNetworkReachabilityCallback))]
#endif
+ static void HandleCallback (IntPtr reachability, NetworkReachabilityFlags flags, IntPtr info)
+ {
+ if (info == IntPtr.Zero)
+ return;
- delegate void MonoSCReachabilityCallback (int available);
-
- [DllImport (LIBNAME)]
- static extern int mono_sc_reachability_enabled ();
+ var instance = GCHandle.FromIntPtr (info).Target as MacNetworkChange;
+ if (instance == null || instance.flags == flags)
+ return;
- [DllImport (LIBNAME)]
- static extern IntPtr mono_sc_reachability_new (MonoSCReachabilityCallback callback);
+ instance.flags = flags;
- [DllImport (LIBNAME)]
- static extern void mono_sc_reachability_free (IntPtr handle);
+ var addressChanged = instance.networkAddressChanged;
+ if (addressChanged != null)
+ addressChanged (null, EventArgs.Empty);
- [DllImport (LIBNAME)]
- static extern int mono_sc_reachability_is_available (IntPtr handle);
+ var availabilityChanged = instance.networkAvailabilityChanged;
+ if (availabilityChanged != null)
+ availabilityChanged (null, new NetworkAvailabilityEventArgs (instance.IsAvailable));
+ }
}
+#if !NETWORK_CHANGE_STANDALONE
+
internal sealed class LinuxNetworkChange : INetworkChange {
[Flags]
enum EventType {
@@ -185,6 +346,14 @@ namespace System.Net.NetworkInformation {
remove { Unregister (value); }
}
+ public bool HasRegisteredEvents {
+ get { return AddressChanged != null || AvailabilityChanged != null; }
+ }
+
+ public void Dispose ()
+ {
+ }
+
//internal Socket (AddressFamily family, SocketType type, ProtocolType proto, IntPtr sock)
bool EnsureSocket ()
@@ -321,5 +490,7 @@ namespace System.Net.NetworkInformation {
[DllImport (LIBNAME, CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr CloseNLSocket (IntPtr sock);
}
-}
+#endif
+
+}
diff --git a/mcs/class/System/System.Net.Sockets/NetworkStream.cs b/mcs/class/System/System.Net.Sockets/NetworkStream.cs
index 65126ca24f..f358c4dbbc 100644
--- a/mcs/class/System/System.Net.Sockets/NetworkStream.cs
+++ b/mcs/class/System/System.Net.Sockets/NetworkStream.cs
@@ -51,8 +51,8 @@ namespace System.Net.Sockets
{
}
- public NetworkStream (Socket socket, bool owns_socket)
- : this (socket, FileAccess.ReadWrite, owns_socket)
+ public NetworkStream (Socket socket, bool ownsSocket)
+ : this (socket, FileAccess.ReadWrite, ownsSocket)
{
}
@@ -61,7 +61,7 @@ namespace System.Net.Sockets
{
}
- public NetworkStream (Socket socket, FileAccess access, bool owns_socket)
+ public NetworkStream (Socket socket, FileAccess access, bool ownsSocket)
{
if (socket == null)
throw new ArgumentNullException ("socket is null");
@@ -73,7 +73,7 @@ namespace System.Net.Sockets
throw new IOException ("Operation not allowed on a non-blocking socket.");
this.socket = socket;
- this.owns_socket = owns_socket;
+ this.owns_socket = ownsSocket;
this.access = access;
readable = CanRead;
diff --git a/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs b/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs
index f04cb3c054..3778c74053 100644
--- a/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs
+++ b/mcs/class/System/System.Net.WebSockets/ClientWebSocket.cs
@@ -1,10 +1,12 @@
//
// ClientWebSocket.cs
//
-// Author:
-// Martin Baulig <martin.baulig@xamarin.com>
+// Authors:
+// Jérémie Laval <jeremie dot laval at xamarin dot com>
//
-// Copyright (c) 2013 Xamarin Inc. (http://www.xamarin.com)
+// Copyright 2013 Xamarin Inc (http://www.xamarin.com).
+//
+// Lightly inspired from WebSocket4Net distributed under the Apache License 2.0
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -27,71 +29,327 @@
#if NET_4_5
using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Security.Principal;
+using System.Security.Cryptography.X509Certificates;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using System.Globalization;
+using System.Text;
+using System.Security.Cryptography;
namespace System.Net.WebSockets
{
- [MonoTODO]
- public class ClientWebSocket : WebSocket
+ public class ClientWebSocket : WebSocket, IDisposable
{
- public ClientWebSocketOptions Options {
- get { throw new NotImplementedException (); }
+ const string Magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ const string VersionTag = "13";
+
+ ClientWebSocketOptions options;
+ WebSocketState state;
+ string subProtocol;
+
+ HttpWebRequest req;
+ WebConnection connection;
+ Socket underlyingSocket;
+
+ Random random = new Random ();
+
+ const int HeaderMaxLength = 14;
+ byte[] headerBuffer;
+ byte[] sendBuffer;
+
+ public ClientWebSocket ()
+ {
+ options = new ClientWebSocketOptions ();
+ state = WebSocketState.None;
+ headerBuffer = new byte[HeaderMaxLength];
}
- public Task ConnectAsync (Uri uri, CancellationToken cancellationToken)
+ public override void Dispose ()
{
- throw new NotImplementedException ();
+ if (connection != null)
+ connection.Close (false);
}
- #region implemented abstract members of WebSocket
+ [MonoTODO]
public override void Abort ()
{
throw new NotImplementedException ();
}
- public override Task CloseAsync (WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
+
+ public ClientWebSocketOptions Options {
+ get {
+ return options;
+ }
+ }
+
+ public override WebSocketState State {
+ get {
+ return state;
+ }
+ }
+
+ public override WebSocketCloseStatus? CloseStatus {
+ get {
+ if (state != WebSocketState.Closed)
+ return (WebSocketCloseStatus?)null;
+ return WebSocketCloseStatus.Empty;
+ }
+ }
+
+ public override string CloseStatusDescription {
+ get {
+ return null;
+ }
+ }
+
+ public override string SubProtocol {
+ get {
+ return subProtocol;
+ }
+ }
+
+ public async Task ConnectAsync (Uri uri, CancellationToken cancellationToken)
{
- throw new NotImplementedException ();
+ state = WebSocketState.Connecting;
+ var httpUri = new UriBuilder (uri);
+ if (uri.Scheme == "wss")
+ httpUri.Scheme = "https";
+ else
+ httpUri.Scheme = "http";
+ req = (HttpWebRequest)WebRequest.Create (httpUri.Uri);
+ req.ReuseConnection = true;
+ if (options.Cookies != null)
+ req.CookieContainer = options.Cookies;
+
+ if (options.CustomRequestHeaders.Count > 0) {
+ foreach (var header in options.CustomRequestHeaders)
+ req.Headers[header.Key] = header.Value;
+ }
+
+ var secKey = Convert.ToBase64String (Encoding.ASCII.GetBytes (Guid.NewGuid ().ToString ().Substring (0, 16)));
+ string expectedAccept = Convert.ToBase64String (SHA1.Create ().ComputeHash (Encoding.ASCII.GetBytes (secKey + Magic)));
+
+ req.Headers["Upgrade"] = "WebSocket";
+ req.Headers["Sec-WebSocket-Version"] = VersionTag;
+ req.Headers["Sec-WebSocket-Key"] = secKey;
+ req.Headers["Sec-WebSocket-Origin"] = uri.Host;
+ if (options.SubProtocols.Count > 0)
+ req.Headers["Sec-WebSocket-Protocol"] = string.Join (",", options.SubProtocols);
+
+ if (options.Credentials != null)
+ req.Credentials = options.Credentials;
+ if (options.ClientCertificates != null)
+ req.ClientCertificates = options.ClientCertificates;
+ if (options.Proxy != null)
+ req.Proxy = options.Proxy;
+ req.UseDefaultCredentials = options.UseDefaultCredentials;
+ req.Connection = "Upgrade";
+
+ HttpWebResponse resp = null;
+ try {
+ resp = (HttpWebResponse)(await req.GetResponseAsync ().ConfigureAwait (false));
+ } catch (Exception e) {
+ throw new WebSocketException (WebSocketError.Success, e);
+ }
+
+ connection = req.StoredConnection;
+ underlyingSocket = connection.socket;
+
+ if (resp.StatusCode != HttpStatusCode.SwitchingProtocols)
+ throw new WebSocketException ("The server returned status code '" + (int)resp.StatusCode + "' when status code '101' was expected");
+ if (!string.Equals (resp.Headers["Upgrade"], "WebSocket", StringComparison.OrdinalIgnoreCase)
+ || !string.Equals (resp.Headers["Connection"], "Upgrade", StringComparison.OrdinalIgnoreCase)
+ || !string.Equals (resp.Headers["Sec-WebSocket-Accept"], expectedAccept))
+ throw new WebSocketException ("HTTP header error during handshake");
+ if (resp.Headers["Sec-WebSocket-Protocol"] != null) {
+ if (!options.SubProtocols.Contains (resp.Headers["Sec-WebSocket-Protocol"]))
+ throw new WebSocketException (WebSocketError.UnsupportedProtocol);
+ subProtocol = resp.Headers["Sec-WebSocket-Protocol"];
+ }
+
+ state = WebSocketState.Open;
}
- public override Task CloseOutputAsync (WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
+
+ public override Task SendAsync (ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
- throw new NotImplementedException ();
+ EnsureWebSocketConnected ();
+ ValidateArraySegment (buffer);
+ if (connection == null)
+ throw new WebSocketException (WebSocketError.Faulted);
+ var count = Math.Max (options.SendBufferSize, buffer.Count) + HeaderMaxLength;
+ if (sendBuffer == null || sendBuffer.Length != count)
+ sendBuffer = new byte[count];
+ return Task.Run (() => {
+ EnsureWebSocketState (WebSocketState.Open, WebSocketState.CloseReceived);
+ var maskOffset = WriteHeader (messageType, buffer, endOfMessage);
+
+ if (buffer.Count > 0)
+ MaskData (buffer, maskOffset);
+ //underlyingSocket.Send (headerBuffer, 0, maskOffset + 4, SocketFlags.None);
+ var headerLength = maskOffset + 4;
+ Array.Copy (headerBuffer, sendBuffer, headerLength);
+ underlyingSocket.Send (sendBuffer, 0, buffer.Count + headerLength, SocketFlags.None);
+ });
}
+
public override Task<WebSocketReceiveResult> ReceiveAsync (ArraySegment<byte> buffer, CancellationToken cancellationToken)
{
- throw new NotImplementedException ();
+ EnsureWebSocketConnected ();
+ ValidateArraySegment (buffer);
+ return Task.Run (() => {
+ EnsureWebSocketState (WebSocketState.Open, WebSocketState.CloseSent);
+ // First read the two first bytes to know what we are doing next
+ connection.Read (req, headerBuffer, 0, 2);
+ var isLast = (headerBuffer[0] >> 7) > 0;
+ var isMasked = (headerBuffer[1] >> 7) > 0;
+ int mask = 0;
+ var type = (WebSocketMessageType)(headerBuffer[0] & 0xF);
+ long length = headerBuffer[1] & 0x7F;
+ int offset = 0;
+ if (length == 126) {
+ offset = 2;
+ connection.Read (req, headerBuffer, 2, offset);
+ length = (headerBuffer[2] << 8) | headerBuffer[3];
+ } else if (length == 127) {
+ offset = 8;
+ connection.Read (req, headerBuffer, 2, offset);
+ length = 0;
+ for (int i = 2; i <= 9; i++)
+ length = (length << 8) | headerBuffer[i];
+ }
+
+ if (isMasked) {
+ connection.Read (req, headerBuffer, 2 + offset, 4);
+ for (int i = 0; i < 4; i++) {
+ var pos = i + offset + 2;
+ mask = (mask << 8) | headerBuffer[pos];
+ }
+ }
+
+ if (type == WebSocketMessageType.Close) {
+ state = WebSocketState.Closed;
+ var tmpBuffer = new byte[length];
+ connection.Read (req, tmpBuffer, 0, tmpBuffer.Length);
+ var closeStatus = (WebSocketCloseStatus)(tmpBuffer[0] << 8 | tmpBuffer[1]);
+ var closeDesc = tmpBuffer.Length > 2 ? Encoding.UTF8.GetString (tmpBuffer, 2, tmpBuffer.Length - 2) : string.Empty;
+ return new WebSocketReceiveResult ((int)length, type, isLast, closeStatus, closeDesc);
+ } else {
+ var readLength = (int)(buffer.Count < length ? buffer.Count : length);
+ connection.Read (req, buffer.Array, buffer.Offset, readLength);
+
+ return new WebSocketReceiveResult ((int)length, type, isLast);
+ }
+ });
}
- public override Task SendAsync (ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
+
+ // The damn difference between those two methods is that CloseAsync will wait for server acknowledgement before completing
+ // while CloseOutputAsync will send the close packet and simply complete.
+
+ public async override Task CloseAsync (WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
{
- throw new NotImplementedException ();
+ EnsureWebSocketConnected ();
+ await SendCloseFrame (closeStatus, statusDescription, cancellationToken).ConfigureAwait (false);
+ state = WebSocketState.CloseSent;
+ // TODO: figure what's exceptions are thrown if the server returns something faulty here
+ await ReceiveAsync (new ArraySegment<byte> (new byte[0]), cancellationToken).ConfigureAwait (false);
+ state = WebSocketState.Closed;
}
- public override void Dispose ()
+
+ public async override Task CloseOutputAsync (WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
{
- throw new NotImplementedException ();
+ EnsureWebSocketConnected ();
+ await SendCloseFrame (closeStatus, statusDescription, cancellationToken).ConfigureAwait (false);
+ state = WebSocketState.CloseSent;
}
- public override WebSocketCloseStatus? CloseStatus {
- get {
- throw new NotImplementedException ();
- }
+
+ async Task SendCloseFrame (WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
+ {
+ var statusDescBuffer = string.IsNullOrEmpty (statusDescription) ? new byte[2] : new byte[2 + Encoding.UTF8.GetByteCount (statusDescription)];
+ statusDescBuffer[0] = (byte)(((ushort)closeStatus) >> 8);
+ statusDescBuffer[1] = (byte)(((ushort)closeStatus) & 0xFF);
+ if (!string.IsNullOrEmpty (statusDescription))
+ Encoding.UTF8.GetBytes (statusDescription, 0, statusDescription.Length, statusDescBuffer, 2);
+ await SendAsync (new ArraySegment<byte> (statusDescBuffer), WebSocketMessageType.Close, true, cancellationToken).ConfigureAwait (false);
}
- public override string CloseStatusDescription {
- get {
- throw new NotImplementedException ();
+
+ int WriteHeader (WebSocketMessageType type, ArraySegment<byte> buffer, bool endOfMessage)
+ {
+ var opCode = (byte)type;
+ var length = buffer.Count;
+
+ headerBuffer[0] = (byte)(opCode | (endOfMessage ? 0 : 0x80));
+ if (length < 126) {
+ headerBuffer[1] = (byte)length;
+ } else if (length <= ushort.MaxValue) {
+ headerBuffer[1] = (byte)126;
+ headerBuffer[2] = (byte)(length / 256);
+ headerBuffer[3] = (byte)(length % 256);
+ } else {
+ headerBuffer[1] = (byte)127;
+
+ int left = length;
+ int unit = 256;
+
+ for (int i = 9; i > 1; i--) {
+ headerBuffer[i] = (byte)(left % unit);
+ left = left / unit;
+ }
}
+
+ var l = Math.Max (0, headerBuffer[1] - 125);
+ var maskOffset = 2 + l * l * 2;
+ GenerateMask (headerBuffer, maskOffset);
+
+ // Since we are client only, we always mask the payload
+ headerBuffer[1] |= 0x80;
+
+ return maskOffset;
}
- public override WebSocketState State {
- get {
- throw new NotImplementedException ();
- }
+
+ void GenerateMask (byte[] mask, int offset)
+ {
+ mask[offset + 0] = (byte)random.Next (0, 255);
+ mask[offset + 1] = (byte)random.Next (0, 255);
+ mask[offset + 2] = (byte)random.Next (0, 255);
+ mask[offset + 3] = (byte)random.Next (0, 255);
}
- public override string SubProtocol {
- get {
- throw new NotImplementedException ();
- }
+
+ void MaskData (ArraySegment<byte> buffer, int maskOffset)
+ {
+ var sendBufferOffset = maskOffset + 4;
+ for (var i = 0; i < buffer.Count; i++)
+ sendBuffer[i + sendBufferOffset] = (byte)(buffer.Array[buffer.Offset + i] ^ headerBuffer[maskOffset + (i % 4)]);
+ }
+
+ void EnsureWebSocketConnected ()
+ {
+ if (state < WebSocketState.Open)
+ throw new InvalidOperationException ("The WebSocket is not connected");
+ }
+
+ void EnsureWebSocketState (params WebSocketState[] validStates)
+ {
+ foreach (var validState in validStates)
+ if (state == validState)
+ return;
+ throw new WebSocketException ("The WebSocket is in an invalid state ('" + state + "') for this operation. Valid states are: " + string.Join (", ", validStates));
+ }
+
+ void ValidateArraySegment (ArraySegment<byte> segment)
+ {
+ if (segment.Array == null)
+ throw new ArgumentNullException ("buffer.Array");
+ if (segment.Offset < 0)
+ throw new ArgumentOutOfRangeException ("buffer.Offset");
+ if (segment.Offset + segment.Count > segment.Array.Length)
+ throw new ArgumentOutOfRangeException ("buffer.Count");
}
- #endregion
}
}
#endif
-
diff --git a/mcs/class/System/System.Net.WebSockets/ClientWebSocketOptions.cs b/mcs/class/System/System.Net.WebSockets/ClientWebSocketOptions.cs
index a1d617cbad..586752d7f6 100644
--- a/mcs/class/System/System.Net.WebSockets/ClientWebSocketOptions.cs
+++ b/mcs/class/System/System.Net.WebSockets/ClientWebSocketOptions.cs
@@ -33,11 +33,15 @@ using System.Net;
using System.Security.Principal;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.CompilerServices;
+using System.Collections.Generic;
namespace System.Net.WebSockets
{
public sealed class ClientWebSocketOptions
{
+ List<string> subprotocols = new List<string> ();
+ Dictionary<string, string> customRequestHeaders = new Dictionary<string, string> ();
+
public X509CertificateCollection ClientCertificates { get; set; }
public CookieContainer Cookies { get; set; }
@@ -50,28 +54,53 @@ namespace System.Net.WebSockets
public bool UseDefaultCredentials { get; set; }
- [MonoTODO]
+ internal IList<string> SubProtocols {
+ get {
+ return subprotocols.AsReadOnly ();
+ }
+ }
+
+ internal Dictionary<string, string> CustomRequestHeaders {
+ get {
+ return customRequestHeaders;
+ }
+ }
+
+ internal int ReceiveBufferSize {
+ get;
+ private set;
+ }
+
+ internal ArraySegment<byte> CustomReceiveBuffer {
+ get;
+ private set;
+ }
+
+ internal int SendBufferSize {
+ get;
+ private set;
+ }
+
public void AddSubProtocol (string subProtocol)
{
- throw new NotImplementedException ();
+ subprotocols.Add (subProtocol);
}
- [MonoTODO]
public void SetBuffer (int receiveBufferSize, int sendBufferSize)
{
- throw new NotImplementedException ();
+ SetBuffer (receiveBufferSize, sendBufferSize, new ArraySegment<byte> ());
}
- [MonoTODO]
public void SetBuffer (int receiveBufferSize, int sendBufferSize, ArraySegment<byte> buffer)
{
- throw new NotImplementedException ();
+ ReceiveBufferSize = receiveBufferSize;
+ SendBufferSize = sendBufferSize;
+ CustomReceiveBuffer = buffer;
}
- [MonoTODO]
public void SetRequestHeader (string headerName, string headerValue)
{
- throw new NotImplementedException ();
+ customRequestHeaders[headerName] = headerValue;
}
}
}
diff --git a/mcs/class/System/System.Net.WebSockets/WebSocketException.cs b/mcs/class/System/System.Net.WebSockets/WebSocketException.cs
index b4980174f6..e617ab38b0 100644
--- a/mcs/class/System/System.Net.WebSockets/WebSocketException.cs
+++ b/mcs/class/System/System.Net.WebSockets/WebSocketException.cs
@@ -36,72 +36,68 @@ namespace System.Net.WebSockets
{
public sealed class WebSocketException : Win32Exception
{
- public WebSocketException ()
+ const string DefaultMessage = "Generic WebSocket exception";
+
+ public WebSocketException () : this (WebSocketError.Success, -1, DefaultMessage, null)
{
}
- public WebSocketException (int nativeError) : base (nativeError)
+ public WebSocketException (int nativeError) : this (WebSocketError.Success, nativeError, DefaultMessage, null)
{
}
- public WebSocketException (string message) : base (message)
+ public WebSocketException (string message) : this (WebSocketError.Success, -1, message, null)
{
}
- public WebSocketException (WebSocketError error)
+ public WebSocketException (WebSocketError error) : this (error, -1, DefaultMessage, null)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (int nativeError, Exception innerException)
+ public WebSocketException (int nativeError, Exception innerException) : this (WebSocketError.Success, nativeError, DefaultMessage, innerException)
{
}
- public WebSocketException (int nativeError, string message) : base (nativeError, message)
+ public WebSocketException (int nativeError, string message) : this (WebSocketError.Success, nativeError, message, null)
{
}
- public WebSocketException (string message, Exception innerException) : base (message, innerException)
+ public WebSocketException (string message, Exception innerException) : this (WebSocketError.Success, -1, message, innerException)
{
}
- public WebSocketException (WebSocketError error, Exception innerException)
+ public WebSocketException (WebSocketError error, Exception innerException) : this (error, -1, DefaultMessage, innerException)
{
- WebSocketErrorCode = error;
+
}
- public WebSocketException (WebSocketError error, int nativeError) : base (nativeError)
+ public WebSocketException (WebSocketError error, int nativeError) : this (error, nativeError, DefaultMessage, null)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (WebSocketError error, string message) : base (message)
+ public WebSocketException (WebSocketError error, string message) : this (error, -1, message, null)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (WebSocketError error, int nativeError, Exception innerException) : base (nativeError)
+ public WebSocketException (WebSocketError error, int nativeError, Exception innerException) : this (error, nativeError, DefaultMessage, innerException)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (WebSocketError error, int nativeError, string message) : base (nativeError, message)
+ public WebSocketException (WebSocketError error, int nativeError, string message) : this (error, nativeError, message, null)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (WebSocketError error, string message, Exception innerException)
+ public WebSocketException (WebSocketError error, string message, Exception innerException) : this (error, -1, message, innerException)
{
- WebSocketErrorCode = error;
}
- public WebSocketException (WebSocketError error, int nativeError, string message, Exception innerException) : base (nativeError, message)
+ public WebSocketException (WebSocketError error, int nativeError, string message, Exception innerException) : base (message, innerException)
{
WebSocketErrorCode = error;
}
diff --git a/mcs/class/System/System.Net.WebSockets/WebSocketMessageType.cs b/mcs/class/System/System.Net.WebSockets/WebSocketMessageType.cs
index 18e2d9ecbe..50cbc003c0 100644
--- a/mcs/class/System/System.Net.WebSockets/WebSocketMessageType.cs
+++ b/mcs/class/System/System.Net.WebSockets/WebSocketMessageType.cs
@@ -35,9 +35,9 @@ namespace System.Net.WebSockets
{
public enum WebSocketMessageType
{
- Text,
- Binary,
- Close
+ Text = 1,
+ Binary = 2,
+ Close = 8
}
}
diff --git a/mcs/class/System/System.Net.WebSockets/WebSocketReceiveResult.cs b/mcs/class/System/System.Net.WebSockets/WebSocketReceiveResult.cs
index e237344e46..af97ebcdca 100644
--- a/mcs/class/System/System.Net.WebSockets/WebSocketReceiveResult.cs
+++ b/mcs/class/System/System.Net.WebSockets/WebSocketReceiveResult.cs
@@ -36,20 +36,22 @@ namespace System.Net.WebSockets
{
public class WebSocketReceiveResult
{
- [MonoTODO]
public WebSocketReceiveResult (int count, WebSocketMessageType messageType, bool endOfMessage)
+ : this (count, messageType, endOfMessage, null, null)
{
- throw new NotImplementedException ();
}
- [MonoTODO]
public WebSocketReceiveResult (int count,
WebSocketMessageType messageType,
bool endOfMessage,
WebSocketCloseStatus? closeStatus,
string closeStatusDescription)
{
- throw new NotImplementedException ();
+ MessageType = messageType;
+ CloseStatus = closeStatus;
+ CloseStatusDescription = closeStatusDescription;
+ Count = count;
+ EndOfMessage = endOfMessage;
}
public WebSocketCloseStatus? CloseStatus {
diff --git a/mcs/class/System/System.Net/HttpWebRequest.cs b/mcs/class/System/System.Net/HttpWebRequest.cs
index 84d59f6802..1cdffff533 100644
--- a/mcs/class/System/System.Net/HttpWebRequest.cs
+++ b/mcs/class/System/System.Net/HttpWebRequest.cs
@@ -36,6 +36,7 @@ using System.Collections;
using System.Configuration;
using System.Globalization;
using System.IO;
+using System.Net;
using System.Net.Cache;
using System.Net.Sockets;
using System.Runtime.Remoting.Messaging;
@@ -950,6 +951,14 @@ namespace System.Net
return result.Response;
}
+
+#if NET_3_5
+ public Stream EndGetRequestStream (IAsyncResult asyncResult, out TransportContext transportContext)
+ {
+ transportContext = null;
+ return EndGetRequestStream (asyncResult);
+ }
+#endif
public override WebResponse GetResponse()
{
@@ -1071,29 +1080,19 @@ namespace System.Net
redirects++;
Exception e = null;
string uriString = null;
-
switch (code) {
case HttpStatusCode.Ambiguous: // 300
e = new WebException ("Ambiguous redirect.");
break;
case HttpStatusCode.MovedPermanently: // 301
case HttpStatusCode.Redirect: // 302
- case HttpStatusCode.TemporaryRedirect: // 307
- /* MS follows the redirect for POST too
- if (method != "GET" && method != "HEAD") // 10.3
- return false;
- */
-
- contentLength = -1;
- bodyBufferLength = 0;
- bodyBuffer = null;
- if (code != HttpStatusCode.TemporaryRedirect)
+ if (method == "POST")
method = "GET";
- uriString = webResponse.Headers ["Location"];
+ break;
+ case HttpStatusCode.TemporaryRedirect: // 307
break;
case HttpStatusCode.SeeOther: //303
method = "GET";
- uriString = webResponse.Headers ["Location"];
break;
case HttpStatusCode.NotModified: // 304
return false;
@@ -1109,6 +1108,11 @@ namespace System.Net
if (e != null)
throw e;
+ //contentLength = -1;
+ //bodyBufferLength = 0;
+ //bodyBuffer = null;
+ uriString = webResponse.Headers ["Location"];
+
if (uriString == null)
throw new WebException ("No Location header found for " + (int) code,
WebExceptionStatus.ProtocolError);
@@ -1163,7 +1167,9 @@ namespace System.Net
bool spoint10 = (proto_version == null || proto_version == HttpVersion.Version10);
if (keepAlive && (version == HttpVersion.Version10 || spoint10)) {
- webHeaders.RemoveAndAdd (connectionHeader, "keep-alive");
+ if (webHeaders[connectionHeader] == null
+ || webHeaders[connectionHeader].IndexOf ("keep-alive", StringComparison.OrdinalIgnoreCase) == -1)
+ webHeaders.RemoveAndAdd (connectionHeader, "keep-alive");
} else if (!keepAlive && version == HttpVersion.Version11) {
webHeaders.RemoveAndAdd (connectionHeader, "close");
}
@@ -1605,6 +1611,13 @@ namespace System.Net
throw throwMe;
}
+
+ internal bool ReuseConnection {
+ get;
+ set;
+ }
+
+ internal WebConnection StoredConnection;
}
}
diff --git a/mcs/class/System/System.Net/HttpWebResponse.cs b/mcs/class/System/System.Net/HttpWebResponse.cs
index 0cb3cd8c85..2b756a97bd 100644
--- a/mcs/class/System/System.Net/HttpWebResponse.cs
+++ b/mcs/class/System/System.Net/HttpWebResponse.cs
@@ -277,7 +277,7 @@ namespace System.Net
CheckDisposed ();
if (stream == null)
return Stream.Null;
- if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
+ if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase)) // see par 4.3 & 9.4
return Stream.Null;
return stream;
@@ -319,7 +319,6 @@ namespace System.Net
void IDisposable.Dispose ()
{
Dispose (true);
- GC.SuppressFinalize (this);
}
#if NET_4_0
diff --git a/mcs/class/System/System.Net/IPAddress.cs b/mcs/class/System/System.Net/IPAddress.cs
index 2dd7d1ab31..92c0f8e6e0 100644
--- a/mcs/class/System/System.Net/IPAddress.cs
+++ b/mcs/class/System/System.Net/IPAddress.cs
@@ -333,6 +333,16 @@ namespace System.Net {
}
}
+#if NET_4_0
+ public bool IsIPv6Teredo {
+ get {
+ return m_Family != AddressFamily.InterNetwork &&
+ NetworkToHostOrder ((short) m_Numbers [0]) == 0x2001 &&
+ m_Numbers[1] == 0;
+ }
+ }
+#endif
+
public long ScopeId {
get {
if (m_Family != AddressFamily.InterNetworkV6)
diff --git a/mcs/class/System/System.Net/MacProxy.cs b/mcs/class/System/System.Net/MacProxy.cs
index a21cf97c65..1a5e89ec0a 100644
--- a/mcs/class/System/System.Net/MacProxy.cs
+++ b/mcs/class/System/System.Net/MacProxy.cs
@@ -25,7 +25,9 @@
//
using System;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
+using System.Threading;
namespace System.Net
{
@@ -606,13 +608,87 @@ namespace System.Net
public const string CFNetworkLibrary = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
#endif
- [DllImport (CFNetworkLibrary)]
- // CFArrayRef CFNetworkCopyProxiesForAutoConfigurationScript (CFStringRef proxyAutoConfigurationScript, CFURLRef targetURL);
- extern static IntPtr CFNetworkCopyProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, IntPtr targetURL);
-
+ [DllImport (CFNetworkLibrary, EntryPoint = "CFNetworkCopyProxiesForAutoConfigurationScript")]
+ // CFArrayRef CFNetworkCopyProxiesForAutoConfigurationScript (CFStringRef proxyAutoConfigurationScript, CFURLRef targetURL, CFErrorRef* error);
+ extern static IntPtr CFNetworkCopyProxiesForAutoConfigurationScriptSequential (IntPtr proxyAutoConfigurationScript, IntPtr targetURL, out IntPtr error);
+
+ class GetProxyData : IDisposable {
+ public IntPtr script;
+ public IntPtr targetUri;
+ public IntPtr error;
+ public IntPtr result;
+ public ManualResetEvent evt = new ManualResetEvent (false);
+
+ public void Dispose ()
+ {
+ evt.Close ();
+ }
+ }
+
+ static object lock_obj = new object ();
+ static Queue<GetProxyData> get_proxy_queue;
+ static AutoResetEvent proxy_event;
+
+ static void CFNetworkCopyProxiesForAutoConfigurationScriptThread ()
+ {
+ GetProxyData data;
+ var data_left = true;
+
+ while (true) {
+ proxy_event.WaitOne ();
+
+ do {
+ lock (lock_obj) {
+ if (get_proxy_queue.Count == 0)
+ break;
+ data = get_proxy_queue.Dequeue ();
+ data_left = get_proxy_queue.Count > 0;
+ }
+
+ data.result = CFNetworkCopyProxiesForAutoConfigurationScriptSequential (data.script, data.targetUri, out data.error);
+ data.evt.Set ();
+ } while (data_left);
+ }
+ }
+
+ static IntPtr CFNetworkCopyProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, IntPtr targetURL, out IntPtr error)
+ {
+ // This method must only be called on only one thread during an application's life time.
+ // Note that it's not enough to use a lock to make calls sequential across different threads,
+ // it has to be one thread. Also note that that thread can't be the main thread, because the
+ // main thread might be blocking waiting for this network request to finish.
+ // Another possibility would be to use JavaScriptCore to execute this piece of
+ // javascript ourselves, but unfortunately it's not available before iOS7.
+ // See bug #7923 comment #21+.
+
+ using (var data = new GetProxyData ()) {
+ data.script = proxyAutoConfigurationScript;
+ data.targetUri = targetURL;
+
+ lock (lock_obj) {
+ if (get_proxy_queue == null) {
+ get_proxy_queue = new Queue<GetProxyData> ();
+ proxy_event = new AutoResetEvent (false);
+ new Thread (CFNetworkCopyProxiesForAutoConfigurationScriptThread) {
+ IsBackground = true,
+ }.Start ();
+ }
+ get_proxy_queue.Enqueue (data);
+ proxy_event.Set ();
+ }
+
+ data.evt.WaitOne ();
+
+ error = data.error;
+
+ return data.result;
+ }
+ }
+
static CFArray CopyProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, CFUrl targetURL)
{
- IntPtr native = CFNetworkCopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL.Handle);
+ IntPtr err = IntPtr.Zero;
+ IntPtr native = CFNetworkCopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL.Handle, out err);
if (native == IntPtr.Zero)
return null;
diff --git a/mcs/class/System/System.Net/ServicePointManager.cs b/mcs/class/System/System.Net/ServicePointManager.cs
index a6d456293e..27e9893a80 100644
--- a/mcs/class/System/System.Net/ServicePointManager.cs
+++ b/mcs/class/System/System.Net/ServicePointManager.cs
@@ -326,7 +326,8 @@ namespace System.Net
if (address == null)
throw new ArgumentNullException ("address");
- RecycleServicePoints ();
+ if ((servicePoints.Count % 4) == 0)
+ RecycleServicePoints ();
var origAddress = new Uri (address.Scheme + "://" + address.Authority);
@@ -346,8 +347,8 @@ namespace System.Net
address = new Uri (address.Scheme + "://" + address.Authority);
ServicePoint sp = null;
+ SPKey key = new SPKey (origAddress, usesProxy ? address : null, useConnect);
lock (servicePoints) {
- SPKey key = new SPKey (origAddress, usesProxy ? address : null, useConnect);
sp = servicePoints [key] as ServicePoint;
if (sp != null)
return sp;
diff --git a/mcs/class/System/System.Net/TransportContext.cs b/mcs/class/System/System.Net/TransportContext.cs
index 04d534fa13..e0366bb0db 100644
--- a/mcs/class/System/System.Net/TransportContext.cs
+++ b/mcs/class/System/System.Net/TransportContext.cs
@@ -26,7 +26,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_4_0
+#if NET_3_5
using System.Security.Authentication.ExtendedProtection;
diff --git a/mcs/class/System/System.Net/WebConnection.cs b/mcs/class/System/System.Net/WebConnection.cs
index 7f09859cb5..7f65751c67 100644
--- a/mcs/class/System/System.Net/WebConnection.cs
+++ b/mcs/class/System/System.Net/WebConnection.cs
@@ -62,7 +62,7 @@ namespace System.Net
{
ServicePoint sPoint;
Stream nstream;
- Socket socket;
+ internal Socket socket;
object socketLock = new object ();
WebExceptionStatus status;
WaitCallback initConn;
@@ -613,16 +613,16 @@ namespace System.Net
return (statusCode >= 200 && statusCode != 204 && statusCode != 304);
}
- internal void GetCertificates ()
+ internal void GetCertificates (Stream stream)
{
// here the SSL negotiation have been done
#if SECURITY_DEP && MONOTOUCH
- HttpsClientStream s = (nstream as HttpsClientStream);
+ HttpsClientStream s = (stream as HttpsClientStream);
X509Certificate client = s.SelectedClientCertificate;
X509Certificate server = s.ServerCertificate;
#else
- X509Certificate client = (X509Certificate) piClient.GetValue (nstream, null);
- X509Certificate server = (X509Certificate) piServer.GetValue (nstream, null);
+ X509Certificate client = (X509Certificate) piClient.GetValue (stream, null);
+ X509Certificate server = (X509Certificate) piServer.GetValue (stream, null);
#endif
sPoint.SetCertificates (client, server);
certsAvailable = (server != null);
@@ -750,6 +750,8 @@ namespace System.Net
{
HttpWebRequest request = (HttpWebRequest) state;
request.WebConnection = this;
+ if (request.ReuseConnection)
+ request.StoredConnection = this;
if (request.Aborted)
return;
@@ -1142,16 +1144,16 @@ namespace System.Net
lock (this) {
if (Data.request != request)
throw new ObjectDisposedException (typeof (NetworkStream).FullName);
- if (nstream == null)
- return false;
s = nstream;
+ if (s == null)
+ return false;
}
try {
s.Write (buffer, offset, size);
// here SSL handshake should have been done
if (ssl && !certsAvailable)
- GetCertificates ();
+ GetCertificates (s);
} catch (Exception e) {
err_msg = e.Message;
WebExceptionStatus wes = WebExceptionStatus.SendFailure;
@@ -1164,10 +1166,10 @@ namespace System.Net
// if SSL is in use then check for TrustFailure
if (ssl) {
#if SECURITY_DEP && MONOTOUCH
- HttpsClientStream https = (nstream as HttpsClientStream);
+ HttpsClientStream https = (s as HttpsClientStream);
if (https.TrustFailure) {
#else
- if ((bool) piTrustFailure.GetValue (nstream, null)) {
+ if ((bool) piTrustFailure.GetValue (s , null)) {
#endif
wes = WebExceptionStatus.TrustFailure;
msg = "Trust failure";
@@ -1183,6 +1185,11 @@ namespace System.Net
internal void Close (bool sendNext)
{
lock (this) {
+ if (Data != null && Data.request != null && Data.request.ReuseConnection) {
+ Data.request.ReuseConnection = false;
+ return;
+ }
+
if (nstream != null) {
try {
nstream.Close ();
diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
index 300e1140e1..4559687a7f 100644
--- a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
+++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509Certificate2.cs
@@ -426,17 +426,34 @@ namespace System.Security.Cryptography.X509Certificates {
}
}
- private void ImportPkcs12 (byte[] rawData, string password)
+ private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
{
MX.PKCS12 pfx = (password == null) ? new MX.PKCS12 (rawData) : new MX.PKCS12 (rawData, password);
- if (pfx.Certificates.Count > 0) {
- _cert = pfx.Certificates [0];
+ if (pfx.Certificates.Count == 0) {
+ // no certificate was found
+ return null;
+ } else if (pfx.Keys.Count == 0) {
+ // no key were found - pick the first certificate
+ return pfx.Certificates [0];
} else {
- _cert = null;
- }
- if (pfx.Keys.Count > 0) {
- _cert.RSA = (pfx.Keys [0] as RSA);
- _cert.DSA = (pfx.Keys [0] as DSA);
+ // find the certificate that match the first key
+ MX.X509Certificate cert = null;
+ var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
+ string pubkey = keypair.ToXmlString (false);
+ foreach (var c in pfx.Certificates) {
+ if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
+ ((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
+ cert = c;
+ break;
+ }
+ }
+ if (cert == null) {
+ cert = pfx.Certificates [0]; // no match, pick first certificate without keys
+ } else {
+ cert.RSA = (keypair as RSA);
+ cert.DSA = (keypair as DSA);
+ }
+ return cert;
}
}
@@ -448,14 +465,14 @@ namespace System.Security.Cryptography.X509Certificates {
[MonoTODO ("missing KeyStorageFlags support")]
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
{
- base.Import (rawData, password, keyStorageFlags);
+ MX.X509Certificate cert = null;
if (password == null) {
try {
- _cert = new MX.X509Certificate (rawData);
+ cert = new MX.X509Certificate (rawData);
}
catch (Exception e) {
try {
- ImportPkcs12 (rawData, null);
+ cert = ImportPkcs12 (rawData, null);
}
catch {
string msg = Locale.GetText ("Unable to decode certificate.");
@@ -466,14 +483,19 @@ namespace System.Security.Cryptography.X509Certificates {
} else {
// try PKCS#12
try {
- ImportPkcs12 (rawData, password);
+ cert = ImportPkcs12 (rawData, password);
}
catch {
// it's possible to supply a (unrequired/unusued) password
// fix bug #79028
- _cert = new MX.X509Certificate (rawData);
+ cert = new MX.X509Certificate (rawData);
}
}
+ // we do not have to fully re-decode the certificate since X509Certificate does not deal with keys
+ if (cert != null) {
+ base.Import (cert.RawData, (string) null, keyStorageFlags);
+ _cert = cert; // becuase base call will call Reset!
+ }
}
[MonoTODO ("SecureString is incomplete")]
@@ -484,35 +506,24 @@ namespace System.Security.Cryptography.X509Certificates {
public override void Import (string fileName)
{
- byte[] rawData = Load (fileName);
+ byte[] rawData = File.ReadAllBytes (fileName);
Import (rawData, (string)null, X509KeyStorageFlags.DefaultKeySet);
}
[MonoTODO ("missing KeyStorageFlags support")]
public override void Import (string fileName, string password, X509KeyStorageFlags keyStorageFlags)
{
- byte[] rawData = Load (fileName);
+ byte[] rawData = File.ReadAllBytes (fileName);
Import (rawData, password, keyStorageFlags);
}
[MonoTODO ("SecureString is incomplete")]
public override void Import (string fileName, SecureString password, X509KeyStorageFlags keyStorageFlags)
{
- byte[] rawData = Load (fileName);
+ byte[] rawData = File.ReadAllBytes (fileName);
Import (rawData, (string)null, keyStorageFlags);
}
- private static byte[] Load (string fileName)
- {
- byte[] data = null;
- using (FileStream fs = File.OpenRead (fileName)) {
- data = new byte [fs.Length];
- fs.Read (data, 0, data.Length);
- fs.Close ();
- }
- return data;
- }
-
public override void Reset ()
{
_cert = null;
@@ -654,7 +665,7 @@ namespace System.Security.Cryptography.X509Certificates {
if (fileName.Length == 0)
throw new ArgumentException ("fileName");
- byte[] data = Load (fileName);
+ byte[] data = File.ReadAllBytes (fileName);
return GetCertContentType (data);
}
diff --git a/mcs/class/System/System.Timers/Timer.cs b/mcs/class/System/System.Timers/Timer.cs
index d35ee4e0eb..28a7011bb5 100644
--- a/mcs/class/System/System.Timers/Timer.cs
+++ b/mcs/class/System/System.Timers/Timer.cs
@@ -159,7 +159,13 @@ namespace System.Timers
protected override void Dispose (bool disposing)
{
- Close ();
+ // If we're disposing explicitly, clear all
+ // fields. If not, all fields will have been
+ // nulled by the GC during finalization, so
+ // trying to lock on _lock will blow up.
+ if (disposing)
+ Close ();
+
base.Dispose (disposing);
}
diff --git a/mcs/class/System/System.Windows.Input/ICommand.cs b/mcs/class/System/System.Windows.Input/ICommand.cs
index c15af7e2d9..7cb430fef6 100644
--- a/mcs/class/System/System.Windows.Input/ICommand.cs
+++ b/mcs/class/System/System.Windows.Input/ICommand.cs
@@ -27,11 +27,15 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_4_0
+#if NET_4_5
+
+using System.Runtime.CompilerServices;
namespace System.Windows.Input {
- public interface ICommand {
+ [TypeForwardedFrom (Consts.AssemblyPresentationCore_4_0)]
+ public interface ICommand
+ {
bool CanExecute (object parameter);
void Execute (object parameter);
event EventHandler CanExecuteChanged;
diff --git a/mcs/class/System/System_test.dll.sources b/mcs/class/System/System_test.dll.sources
index a306d52be4..33f8326b2d 100644
--- a/mcs/class/System/System_test.dll.sources
+++ b/mcs/class/System/System_test.dll.sources
@@ -499,3 +499,4 @@ System.Collections.Concurrent/BlockingCollectionTests.cs
System.Collections.Concurrent/ConcurrentBagTests.cs
System.Collections.Concurrent/CollectionStressTestHelper.cs
System.Collections.Concurrent/ParallelTestHelper.cs
+System.Net.WebSockets/ClientWebSocketTest.cs
diff --git a/mcs/class/System/Test/Microsoft.CSharp/CSharpCodeProviderTest.cs b/mcs/class/System/Test/Microsoft.CSharp/CSharpCodeProviderTest.cs
index f34bcca6d6..fe60d4e5a8 100644
--- a/mcs/class/System/Test/Microsoft.CSharp/CSharpCodeProviderTest.cs
+++ b/mcs/class/System/Test/Microsoft.CSharp/CSharpCodeProviderTest.cs
@@ -360,6 +360,49 @@ namespace MonoTests.Microsoft.CSharp
}
[Test]
+ public void CompileFromSource_InMemory_Twice ()
+ {
+ CompilerParameters options = new CompilerParameters ();
+ options.GenerateExecutable = false;
+ options.GenerateInMemory = true;
+
+ ICodeCompiler compiler = _codeProvider.CreateCompiler ();
+
+ var src_1 = "class X { ";
+
+ CompilerResults results_1 = compiler.CompileAssemblyFromSource (options, src_1);
+ var output_1 = options.OutputAssembly;
+
+ var src_2 = "class X { }";
+
+ CompilerResults results_2 = compiler.CompileAssemblyFromSource (options, src_2);
+ var output_2 = options.OutputAssembly;
+
+ // verify compilation was successful
+ AssertCompileResults (results_2, true);
+
+ Assert.AreEqual (output_1, output_2, "#1");
+ }
+
+
+ [Test]
+ public void CompileFromSource_InMemory_With_Extra_Delete ()
+ {
+ CompilerParameters options = new CompilerParameters ();
+ options.GenerateExecutable = false;
+ options.GenerateInMemory = true;
+
+ ICodeCompiler compiler = _codeProvider.CreateCompiler ();
+
+ var src_1 = "class X { ";
+
+ compiler.CompileAssemblyFromSource (options, src_1);
+
+ options.TempFiles.Delete ();
+ options.TempFiles.Delete ();
+ }
+
+ [Test]
public void CompileFromSourceBatch_InMemory ()
{
// create a file in temp directory to ensure that compiler is not removing
diff --git a/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs b/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs
index 0098e2de92..9f0e9b0190 100644
--- a/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs
+++ b/mcs/class/System/Test/System.Collections.Concurrent/BlockingCollectionTests.cs
@@ -27,6 +27,7 @@ using System;
using System.Threading;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Threading.Tasks;
using NUnit.Framework;
@@ -192,6 +193,60 @@ namespace MonoTests.System.Collections.Concurrent
Assert.IsNull (o);
Assert.IsFalse (success);
}
+
+ [Test]
+ public void TakeAnyFromSecondCollection ()
+ {
+ var a = new BlockingCollection<string> ();
+ var b = new BlockingCollection<string> ();
+ var arr = new [] { a, b };
+ string res = null;
+
+ Task<int> t = Task.Factory.StartNew (() => BlockingCollection<string>.TakeFromAny (arr, out res));
+ a.Add ("foo");
+ Assert.AreEqual (0, t.Result, "#1");
+ Assert.AreEqual ("foo", res, "#2");
+
+ t = Task.Factory.StartNew (() => BlockingCollection<string>.TakeFromAny (arr, out res));
+ b.Add ("bar");
+ Assert.AreEqual (1, t.Result, "#3");
+ Assert.AreEqual ("bar", res, "#4");
+ }
+
+ [Test]
+ public void TakeAnyCancellable ()
+ {
+ var a = new BlockingCollection<string> ();
+ var b = new BlockingCollection<string> ();
+ var arr = new [] { a, b };
+ var cts = new CancellationTokenSource ();
+ string res = null;
+
+ Task<int> t = Task.Factory.StartNew (() => BlockingCollection<string>.TakeFromAny (arr, out res, cts.Token));
+ Thread.Sleep (100);
+ a.Add ("foo");
+ Assert.AreEqual (0, t.Result, "#1");
+ Assert.AreEqual ("foo", res, "#2");
+
+ t = Task.Factory.StartNew (() => BlockingCollection<string>.TakeFromAny (arr, out res, cts.Token));
+ Thread.Sleep (100);
+ b.Add ("bar");
+ Assert.AreEqual (1, t.Result, "#3");
+ Assert.AreEqual ("bar", res, "#4");
+
+ t = Task.Factory.StartNew (() => {
+ try {
+ return BlockingCollection<string>.TakeFromAny (arr, out res, cts.Token);
+ } catch (OperationCanceledException WE_GOT_CANCELED) {
+ res = "canceled";
+ return -10;
+ }
+ });
+
+ cts.Cancel ();
+ Assert.AreEqual (-10, t.Result, "#5");
+ Assert.AreEqual ("canceled", res, "#6");
+ }
}
}
#endif
diff --git a/mcs/class/System/Test/System.Collections.Concurrent/ConcurrentBagTests.cs b/mcs/class/System/Test/System.Collections.Concurrent/ConcurrentBagTests.cs
index 1262cc3947..b7bc6b5b7e 100644
--- a/mcs/class/System/Test/System.Collections.Concurrent/ConcurrentBagTests.cs
+++ b/mcs/class/System/Test/System.Collections.Concurrent/ConcurrentBagTests.cs
@@ -191,6 +191,50 @@ namespace MonoTests.System.Collections.Concurrent
Assert.IsTrue (valid, "Aggregate test");
}
+
+ [Test]
+ public void BasicRemoveEmptyTest ()
+ {
+ int result;
+ Assert.IsTrue(bag.IsEmpty);
+ Assert.IsFalse(bag.TryTake(out result));
+ }
+
+ [Test]
+ public void BasicRemoveTwiceTest()
+ {
+ bag.Add (1);
+ Assert.IsFalse (bag.IsEmpty);
+ Assert.AreEqual (1, bag.Count);
+
+ int result;
+ Assert.IsTrue (bag.TryTake (out result));
+ Assert.AreEqual (1, result);
+ Assert.IsTrue (bag.IsEmpty);
+ Assert.IsFalse (bag.TryTake (out result));
+ Assert.IsFalse (bag.TryTake (out result));
+ }
+
+ [Test]
+ public void AddRemoveAddTest()
+ {
+ bag.Add (1);
+ Assert.IsFalse (bag.IsEmpty);
+ Assert.AreEqual (1, bag.Count);
+
+ int result;
+ Assert.IsTrue (bag.TryTake (out result));
+ Assert.AreEqual (1, result);
+ Assert.IsTrue (bag.IsEmpty);
+
+ bag.Add (1);
+ Assert.IsFalse (bag.IsEmpty);
+ Assert.AreEqual (1, bag.Count);
+
+ Assert.IsTrue (bag.TryTake (out result));
+ Assert.AreEqual (1, result);
+ Assert.IsTrue (bag.IsEmpty);
+ }
[Test]
public void AddStressTest ()
diff --git a/mcs/class/System/Test/System.ComponentModel/BindingListTest.cs b/mcs/class/System/Test/System.ComponentModel/BindingListTest.cs
index 88be568f42..92a6253db9 100644
--- a/mcs/class/System/Test/System.ComponentModel/BindingListTest.cs
+++ b/mcs/class/System/Test/System.ComponentModel/BindingListTest.cs
@@ -629,6 +629,16 @@ namespace MonoTests.System.ComponentModel
Assert.IsTrue (added, "ItemAdded");
Assert.IsTrue (changed, "ItemChanged");
}
+
+ [Test] // https://bugzilla.xamarin.com/show_bug.cgi?id=16902
+ public void Bug16902 ()
+ {
+ var list = new BindingList<Item> ();
+ list.Insert (0, null);
+ var count = list.Count;
+
+ Assert.AreEqual (1, count, "1");
+ }
}
}
diff --git a/mcs/class/System/Test/System.Net.Sockets/SocketTest.cs b/mcs/class/System/Test/System.Net.Sockets/SocketTest.cs
index 6f0e4cf3ee..4bd26f9fae 100644..100755
--- a/mcs/class/System/Test/System.Net.Sockets/SocketTest.cs
+++ b/mcs/class/System/Test/System.Net.Sockets/SocketTest.cs
@@ -4144,6 +4144,54 @@ namespace MonoTests.System.Net.Sockets
}
[Test]
+ public void SetSocketOption_MulticastInterfaceIndex_Any ()
+ {
+ IPAddress ip = IPAddress.Parse ("239.255.255.250");
+ int index = 0;
+ using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
+ {
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, IPAddress.HostToNetworkOrder(index));
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, index));
+ }
+ }
+
+ [Test]
+ public void SetSocketOption_MulticastInterfaceIndex_Loopback ()
+ {
+ IPAddress ip = IPAddress.Parse ("239.255.255.250");
+ int index = 1;
+ using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
+ {
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, IPAddress.HostToNetworkOrder(index));
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, index));
+ }
+ }
+
+ [Test]
+ public void SetSocketOption_MulticastInterfaceIndex_Invalid ()
+ {
+ IPAddress ip = IPAddress.Parse ("239.255.255.250");
+ int index = 31415;
+ using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
+ {
+ try
+ {
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, IPAddress.HostToNetworkOrder(index));
+ Assert.Fail ("#1");
+ }
+ catch
+ {}
+ try
+ {
+ s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, index));
+ Assert.Fail ("#2");
+ }
+ catch
+ {}
+ }
+ }
+
+ [Test]
public void Shutdown_NoConnect ()
{
Socket s = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
diff --git a/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs b/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs
index 6fa403c607..710b4982c1 100644
--- a/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs
+++ b/mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs
@@ -1051,16 +1051,21 @@ namespace MonoTests.System.Net.Sockets {
[Test]
public void Available ()
{
- UdpClient client = new UdpClient (1238);
- IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 1238);
- byte[] bytes = new byte[] {10, 11, 12, 13};
-
- client.Send (bytes, bytes.Length, ep);
- int avail = client.Available;
-
- Assert.AreEqual (bytes.Length, avail, "Available #1");
+ using (UdpClient client = new UdpClient (1238)) {
+ IPEndPoint ep = new IPEndPoint (IPAddress.Loopback, 1238);
+ byte[] bytes = new byte[] {10, 11, 12, 13};
+
+ int res = client.Send (bytes, bytes.Length, ep);
+ Assert.AreEqual (bytes.Length, res, "Send");
+
+ // that might happen too quickly, data sent and not yet received/available
+ Thread.Sleep (100);
+ int avail = client.Available;
+
+ Assert.AreEqual (bytes.Length, avail, "Available #1");
- client.Close ();
+ client.Close ();
+ }
}
[Test]
diff --git a/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs b/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs
new file mode 100644
index 0000000000..3666003a3f
--- /dev/null
+++ b/mcs/class/System/Test/System.Net.WebSockets/ClientWebSocketTest.cs
@@ -0,0 +1,242 @@
+#if NET_4_5 && !MOBILE
+using System;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Net.WebSockets;
+using System.Reflection;
+using System.Text;
+
+using NUnit.Framework;
+
+
+namespace MonoTests.System.Net.WebSockets
+{
+ [TestFixture]
+ public class ClientWebSocketTest
+ {
+ const string EchoServerUrl = "ws://echo.websocket.org";
+ const int Port = 42123;
+ HttpListener listener;
+ ClientWebSocket socket;
+ MethodInfo headerSetMethod;
+
+ [SetUp]
+ public void Setup ()
+ {
+ listener = new HttpListener ();
+ listener.Prefixes.Add ("http://localhost:" + Port + "/");
+ listener.Start ();
+ socket = new ClientWebSocket ();
+ }
+
+ [TearDown]
+ public void Teardown ()
+ {
+ if (listener != null) {
+ listener.Stop ();
+ listener = null;
+ }
+ if (socket != null) {
+ if (socket.State == WebSocketState.Open)
+ socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ socket.Dispose ();
+ socket = null;
+ }
+ }
+
+ [Test]
+ public void ServerHandshakeReturnCrapStatusCodeTest ()
+ {
+ HandleHttpRequestAsync ((req, resp) => resp.StatusCode = 418);
+ try {
+ socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success, typeof (WebException));
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ [Test]
+ public void ServerHandshakeReturnWrongUpgradeHeader ()
+ {
+ HandleHttpRequestAsync ((req, resp) => {
+ resp.StatusCode = 101;
+ resp.Headers["Upgrade"] = "gtfo";
+ });
+ try {
+ socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success);
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ [Test]
+ public void ServerHandshakeReturnWrongConnectionHeader ()
+ {
+ HandleHttpRequestAsync ((req, resp) => {
+ resp.StatusCode = 101;
+ resp.Headers["Upgrade"] = "websocket";
+ // Mono http request doesn't like the forcing, test still valid since the default connection header value is empty
+ //ForceSetHeader (resp.Headers, "Connection", "Foo");
+ });
+ try {
+ socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success);
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ [Test]
+ public void EchoTest ()
+ {
+ const string Payload = "This is a websocket test";
+
+ Assert.AreEqual (WebSocketState.None, socket.State);
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.Open, socket.State);
+
+ var sendBuffer = Encoding.ASCII.GetBytes (Payload);
+ socket.SendAsync (new ArraySegment<byte> (sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
+
+ var receiveBuffer = new byte[Payload.Length];
+ var resp = socket.ReceiveAsync (new ArraySegment<byte> (receiveBuffer), CancellationToken.None).Result;
+
+ Assert.AreEqual (Payload.Length, resp.Count);
+ Assert.IsTrue (resp.EndOfMessage);
+ Assert.AreEqual (WebSocketMessageType.Text, resp.MessageType);
+ Assert.AreEqual (Payload, Encoding.ASCII.GetString (receiveBuffer, 0, resp.Count));
+
+ socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.Closed, socket.State);
+ }
+
+ [Test]
+ public void CloseOutputAsyncTest ()
+ {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.Open, socket.State);
+
+ socket.CloseOutputAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.CloseSent, socket.State);
+
+ var resp = socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None).Result;
+ Assert.AreEqual (WebSocketState.Closed, socket.State);
+ Assert.AreEqual (WebSocketMessageType.Close, resp.MessageType);
+ Assert.AreEqual (WebSocketCloseStatus.NormalClosure, resp.CloseStatus);
+ Assert.AreEqual (string.Empty, resp.CloseStatusDescription);
+ }
+
+ [Test]
+ public void CloseAsyncTest ()
+ {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.Open, socket.State);
+
+ socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ Assert.AreEqual (WebSocketState.Closed, socket.State);
+ }
+
+ [Test, ExpectedException (typeof (InvalidOperationException))]
+ public void SendAsyncArgTest_NotConnected ()
+ {
+ socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+
+ [Test, ExpectedException (typeof (ArgumentNullException))]
+ public void SendAsyncArgTest_NoArray ()
+ {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ socket.SendAsync (new ArraySegment<byte> (), WebSocketMessageType.Text, true, CancellationToken.None);
+ }
+
+ [Test, ExpectedException (typeof (InvalidOperationException))]
+ public void ReceiveAsyncArgTest_NotConnected ()
+ {
+ socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None);
+ }
+
+ [Test, ExpectedException (typeof (ArgumentNullException))]
+ public void ReceiveAsyncArgTest_NoArray ()
+ {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ socket.ReceiveAsync (new ArraySegment<byte> (), CancellationToken.None);
+ }
+
+ [Test]
+ public void ReceiveAsyncWrongState_Closed ()
+ {
+ try {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success);
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ [Test]
+ public void SendAsyncWrongState_Closed ()
+ {
+ try {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success);
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ [Test]
+ public void SendAsyncWrongState_CloseSent ()
+ {
+ try {
+ socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
+ socket.CloseOutputAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
+ socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
+ } catch (AggregateException e) {
+ AssertWebSocketException (e, WebSocketError.Success);
+ return;
+ }
+ Assert.Fail ("Should have thrown");
+ }
+
+ async Task HandleHttpRequestAsync (Action<HttpListenerRequest, HttpListenerResponse> handler)
+ {
+ var ctx = await listener.GetContextAsync ();
+ handler (ctx.Request, ctx.Response);
+ ctx.Response.Close ();
+ }
+
+ void AssertWebSocketException (AggregateException e, WebSocketError error, Type inner = null)
+ {
+ var wsEx = e.InnerException as WebSocketException;
+ Console.WriteLine (e.InnerException.ToString ());
+ Assert.IsNotNull (wsEx, "Not a websocketexception");
+ Assert.AreEqual (error, wsEx.WebSocketErrorCode);
+ if (inner != null) {
+ Assert.IsNotNull (wsEx.InnerException);
+ Assert.IsInstanceOfType (inner, wsEx.InnerException);
+ }
+ }
+
+ void ForceSetHeader (WebHeaderCollection headers, string name, string value)
+ {
+ if (headerSetMethod == null)
+ headerSetMethod = typeof (WebHeaderCollection).GetMethod ("AddValue", BindingFlags.NonPublic);
+ headerSetMethod.Invoke (headers, new[] { name, value });
+ }
+ }
+}
+
+#endif
diff --git a/mcs/class/System/Test/System.Net/IPAddressTest.cs b/mcs/class/System/Test/System.Net/IPAddressTest.cs
index 965b1cd44a..a07c1a19d9 100644
--- a/mcs/class/System/Test/System.Net/IPAddressTest.cs
+++ b/mcs/class/System/Test/System.Net/IPAddressTest.cs
@@ -545,6 +545,15 @@ public class IPAddressTest
Assert.IsTrue (IPAddress.Parse ("FF01::1").IsIPv6Multicast, "#2");
Assert.IsFalse (IPAddress.Parse ("FE00::1").IsIPv6Multicast, "#3");
}
+
+#if NET_4_0
+ [Test]
+ public void IsIPv6Teredo ()
+ {
+ Assert.IsTrue (IPAddress.Parse ("2001::1").IsIPv6Teredo, "#1");
+ Assert.IsFalse (IPAddress.Parse ("2002::1").IsIPv6Teredo, "#2");
+ }
+#endif
}
}
diff --git a/mcs/class/System/mobile_System.dll.sources b/mcs/class/System/mobile_System.dll.sources
index 8b5c746266..f5ffb4ac71 100644
--- a/mcs/class/System/mobile_System.dll.sources
+++ b/mcs/class/System/mobile_System.dll.sources
@@ -20,6 +20,8 @@ System.Collections.Specialized/HybridDictionary.cs
System.Collections.Specialized/ListDictionary.cs
System.Collections.Specialized/NameObjectCollectionBase.cs
System.Collections.Specialized/NameValueCollection.cs
+System.Collections.Specialized/IOrderedDictionary.cs
+System.Collections.Specialized/OrderedDictionary.cs
System.Collections.Specialized/ProcessStringDictionary.cs
System.Collections.Specialized/StringCollection.cs
System.Collections.Specialized/StringDictionary.cs
@@ -28,7 +30,28 @@ System.Collections.Specialized/INotifyCollectionChanged.cs
System.Collections.Specialized/NotifyCollectionChangedEventArgs.cs
System.Collections.Specialized/NotifyCollectionChangedAction.cs
System.Collections.Specialized/NotifyCollectionChangedEventHandler.cs
+System.ComponentModel.Design.Serialization/ComponentSerializationService.cs
+System.ComponentModel.Design.Serialization/ContextStack.cs
+System.ComponentModel.Design.Serialization/DefaultSerializationProviderAttribute.cs
+System.ComponentModel.Design.Serialization/DesignerLoader.cs
+System.ComponentModel.Design.Serialization/DesignerSerializerAttribute.cs
+System.ComponentModel.Design.Serialization/IDesignerLoaderHost.cs
+System.ComponentModel.Design.Serialization/IDesignerLoaderHost2.cs
+System.ComponentModel.Design.Serialization/IDesignerLoaderService.cs
+System.ComponentModel.Design.Serialization/IDesignerSerializationManager.cs
+System.ComponentModel.Design.Serialization/IDesignerSerializationProvider.cs
+System.ComponentModel.Design.Serialization/IDesignerSerializationService.cs
+System.ComponentModel.Design.Serialization/INameCreationService.cs
System.ComponentModel.Design.Serialization/InstanceDescriptor.cs
+System.ComponentModel.Design.Serialization/MemberRelationship.cs
+System.ComponentModel.Design.Serialization/MemberRelationshipService.cs
+System.ComponentModel.Design.Serialization/ResolveNameEventArgs.cs
+System.ComponentModel.Design.Serialization/ResolveNameEventHandler.cs
+System.ComponentModel.Design.Serialization/RootDesignerSerializerAttribute.cs
+System.ComponentModel.Design.Serialization/SerializationStore.cs
+System.ComponentModel.Design/ActiveDesignerEventArgs.cs
+System.ComponentModel.Design/ActiveDesignerEventHandler.cs
+System.ComponentModel.Design/CheckoutException.cs
System.ComponentModel.Design/CommandID.cs
System.ComponentModel.Design/ComponentChangedEventArgs.cs
System.ComponentModel.Design/ComponentChangedEventHandler.cs
@@ -38,31 +61,61 @@ System.ComponentModel.Design/ComponentEventArgs.cs
System.ComponentModel.Design/ComponentEventHandler.cs
System.ComponentModel.Design/ComponentRenameEventArgs.cs
System.ComponentModel.Design/ComponentRenameEventHandler.cs
+System.ComponentModel.Design/DesignerCollection.cs
+System.ComponentModel.Design/DesignerEventArgs.cs
+System.ComponentModel.Design/DesignerEventHandler.cs
+System.ComponentModel.Design/DesignerOptionService.cs
System.ComponentModel.Design/DesignerTransaction.cs
System.ComponentModel.Design/DesignerTransactionCloseEventArgs.cs
System.ComponentModel.Design/DesignerTransactionCloseEventHandler.cs
System.ComponentModel.Design/DesignerVerb.cs
System.ComponentModel.Design/DesignerVerbCollection.cs
+System.ComponentModel.Design/HelpContextType.cs
+System.ComponentModel.Design/HelpKeywordAttribute.cs
+System.ComponentModel.Design/HelpKeywordType.cs
System.ComponentModel.Design/IComponentChangeService.cs
+System.ComponentModel.Design/IComponentDiscoveryService.cs
+System.ComponentModel.Design/IComponentInitializer.cs
System.ComponentModel.Design/IDesigner.cs
+System.ComponentModel.Design/IDesignerEventService.cs
+System.ComponentModel.Design/IDesignerFilter.cs
System.ComponentModel.Design/IDesignerHost.cs
+System.ComponentModel.Design/IDesignerHostTransactionState.cs
+System.ComponentModel.Design/IDesignerOptionService.cs
+System.ComponentModel.Design/IDictionaryService.cs
+System.ComponentModel.Design/IEventBindingService.cs
+System.ComponentModel.Design/IExtenderListService.cs
+System.ComponentModel.Design/IExtenderProviderService.cs
+System.ComponentModel.Design/IHelpService.cs
+System.ComponentModel.Design/IInheritanceService.cs
+System.ComponentModel.Design/IMenuCommandService.cs
System.ComponentModel.Design/IReferenceService.cs
+System.ComponentModel.Design/IResourceService.cs
System.ComponentModel.Design/IRootDesigner.cs
+System.ComponentModel.Design/ISelectionService.cs
System.ComponentModel.Design/IServiceContainer.cs
+System.ComponentModel.Design/ITreeDesigner.cs
System.ComponentModel.Design/ITypeDescriptorFilterService.cs
+System.ComponentModel.Design/ITypeDiscoveryService.cs
System.ComponentModel.Design/ITypeResolutionService.cs
System.ComponentModel.Design/MenuCommand.cs
+System.ComponentModel.Design/SelectionTypes.cs
+System.ComponentModel.Design/ServiceContainer.cs
System.ComponentModel.Design/ServiceCreatorCallback.cs
System.ComponentModel.Design/StandardCommands.cs
+System.ComponentModel.Design/StandardToolWindows.cs
+System.ComponentModel.Design/TypeDescriptionProviderService.cs
System.ComponentModel.Design/ViewTechnology.cs
System.ComponentModel/AddingNewEventArgs.cs
System.ComponentModel/AddingNewEventHandler.cs
+System.ComponentModel/AmbientValueAttribute.cs
System.ComponentModel/ArrayConverter.cs
System.ComponentModel/AsyncCompletedEventArgs.cs
System.ComponentModel/AsyncCompletedEventHandler.cs
System.ComponentModel/AsyncOperation.cs
System.ComponentModel/AsyncOperationManager.cs
System.ComponentModel/AttributeCollection.cs
+System.ComponentModel/AttributeProviderAttribute.cs
System.ComponentModel/BackgroundWorker.cs
System.ComponentModel/BaseNumberConverter.cs
System.ComponentModel/BindableAttribute.cs
@@ -73,20 +126,32 @@ System.ComponentModel/BooleanConverter.cs
System.ComponentModel/BrowsableAttribute.cs
System.ComponentModel/ByteConverter.cs
System.ComponentModel/CancelEventArgs.cs
+System.ComponentModel/CancelEventHandler.cs
System.ComponentModel/CategoryAttribute.cs
System.ComponentModel/CharConverter.cs
System.ComponentModel/CollectionChangeAction.cs
System.ComponentModel/CollectionChangeEventArgs.cs
System.ComponentModel/CollectionChangeEventHandler.cs
System.ComponentModel/CollectionConverter.cs
+System.ComponentModel/ComplexBindingPropertiesAttribute.cs
System.ComponentModel/Component.cs
System.ComponentModel/ComponentCollection.cs
System.ComponentModel/ComponentConverter.cs
+System.ComponentModel/ComponentEditor.cs
+System.ComponentModel/ComponentResourceManager.cs
+System.ComponentModel/Container.cs
+System.ComponentModel/ContainerFilterService.cs
System.ComponentModel/CultureInfoConverter.cs
System.ComponentModel/CustomTypeDescriptor.cs
System.ComponentModel/DataErrorsChangedEventArgs.cs
+System.ComponentModel/DataObjectAttribute.cs
+System.ComponentModel/DataObjectFieldAttribute.cs
+System.ComponentModel/DataObjectMethodAttribute.cs
+System.ComponentModel/DataObjectMethodType.cs
System.ComponentModel/DateTimeConverter.cs
+System.ComponentModel/DateTimeOffsetConverter.cs
System.ComponentModel/DecimalConverter.cs
+System.ComponentModel/DefaultBindingPropertyAttribute.cs
System.ComponentModel/DefaultEventAttribute.cs
System.ComponentModel/DefaultPropertyAttribute.cs
System.ComponentModel/DefaultValueAttribute.cs
@@ -109,24 +174,35 @@ System.ComponentModel/EventDescriptor.cs
System.ComponentModel/EventDescriptorCollection.cs
System.ComponentModel/EventHandlerList.cs
System.ComponentModel/ExpandableObjectConverter.cs
+System.ComponentModel/ExtenderProvidedPropertyAttribute.cs
System.ComponentModel/GuidConverter.cs
+System.ComponentModel/HandledEventArgs.cs
+System.ComponentModel/HandledEventHandler.cs
System.ComponentModel/IBindingList.cs
System.ComponentModel/IBindingListView.cs
System.ComponentModel/ICancelAddNew.cs
System.ComponentModel/IChangeTracking.cs
System.ComponentModel/IComNativeDescriptorHandler.cs
System.ComponentModel/IComponent.cs
-System.ComponentModel/IComponent.cs
System.ComponentModel/IContainer.cs
System.ComponentModel/ICustomTypeDescriptor.cs
System.ComponentModel/IDataErrorInfo.cs
-System.ComponentModel/IDataErrorInfo.cs
System.ComponentModel/IEditableObject.cs
System.ComponentModel/IExtenderProvider.cs
+System.ComponentModel/IIntellisenseBuilder.cs
System.ComponentModel/IListSource.cs
+System.ComponentModel/ImmutableObjectAttribute.cs
+System.ComponentModel/INestedContainer.cs
+System.ComponentModel/INestedSite.cs
+System.ComponentModel/InheritanceAttribute.cs
+System.ComponentModel/InheritanceLevel.cs
+System.ComponentModel/InitializationEventAttribute.cs
System.ComponentModel/INotifyDataErrorInfo.cs
System.ComponentModel/INotifyPropertyChanged.cs
System.ComponentModel/INotifyPropertyChanging.cs
+System.ComponentModel/InstallerTypeAttribute.cs
+System.ComponentModel/InstanceCreationEditor.cs
+System.ComponentModel/InvalidAsynchronousStateException.cs
System.ComponentModel/IRaiseItemChangedEvents.cs
System.ComponentModel/IRevertibleChangeTracking.cs
System.ComponentModel/ISite.cs
@@ -139,7 +215,6 @@ System.ComponentModel/Int16Converter.cs
System.ComponentModel/Int32Converter.cs
System.ComponentModel/Int64Converter.cs
System.ComponentModel/InvalidEnumArgumentException.cs
-System.ComponentModel/InvalidEnumArgumentException.cs
System.ComponentModel/ListBindableAttribute.cs
System.ComponentModel/ListChangedEventArgs.cs
System.ComponentModel/ListChangedEventHandler.cs
@@ -147,14 +222,18 @@ System.ComponentModel/ListChangedType.cs
System.ComponentModel/ListSortDescription.cs
System.ComponentModel/ListSortDescriptionCollection.cs
System.ComponentModel/ListSortDirection.cs
-System.ComponentModel/ListSortDirection.cs
System.ComponentModel/LocalizableAttribute.cs
+System.ComponentModel/LookupBindingPropertiesAttribute.cs
System.ComponentModel/MarshalByValueComponent.cs
+System.ComponentModel/MaskedTextProvider.cs
+System.ComponentModel/MaskedTextResultHint.cs
System.ComponentModel/MemberDescriptor.cs
System.ComponentModel/MergablePropertyAttribute.cs
System.ComponentModel/MultilineStringConverter.cs
+System.ComponentModel/NestedContainer.cs
System.ComponentModel/NotifyParentPropertyAttribute.cs
System.ComponentModel/NullableConverter.cs
+System.ComponentModel/ParenthesizePropertyNameAttribute.cs
System.ComponentModel/PasswordPropertyTextAttribute.cs
System.ComponentModel/ProgressChangedEventArgs.cs
System.ComponentModel/ProgressChangedEventHandler.cs
@@ -163,24 +242,27 @@ System.ComponentModel/PropertyChangedEventHandler.cs
System.ComponentModel/PropertyChangingEventArgs.cs
System.ComponentModel/PropertyChangingEventHandler.cs
System.ComponentModel/PropertyDescriptor.cs
-System.ComponentModel/PropertyDescriptor.cs
System.ComponentModel/PropertyDescriptorCollection.cs
-System.ComponentModel/ReadOnlyAttribute.cs
+System.ComponentModel/PropertyTabAttribute.cs
+System.ComponentModel/PropertyTabScope.cs
+System.ComponentModel/ProvidePropertyAttribute.cs
System.ComponentModel/ReadOnlyAttribute.cs
System.ComponentModel/RecommendedAsConfigurableAttribute.cs
System.ComponentModel/ReferenceConverter.cs
-System.ComponentModel/ReferenceConverter.cs
System.ComponentModel/ReflectionEventDescriptor.cs
System.ComponentModel/ReflectionPropertyDescriptor.cs
System.ComponentModel/RefreshEventArgs.cs
System.ComponentModel/RefreshEventHandler.cs
System.ComponentModel/RefreshProperties.cs
System.ComponentModel/RefreshPropertiesAttribute.cs
+System.ComponentModel/RunInstallerAttribute.cs
System.ComponentModel/RunWorkerCompletedEventArgs.cs
System.ComponentModel/RunWorkerCompletedEventHandler.cs
System.ComponentModel/SByteConverter.cs
+System.ComponentModel/SettingsBindableAttribute.cs
System.ComponentModel/SingleConverter.cs
System.ComponentModel/StringConverter.cs
+System.ComponentModel/SyntaxCheck.cs
System.ComponentModel/TimeSpanConverter.cs
System.ComponentModel/ToolboxItemAttribute.cs
System.ComponentModel/ToolboxItemFilterAttribute.cs
@@ -188,11 +270,13 @@ System.ComponentModel/ToolboxItemFilterType.cs
System.ComponentModel/TypeConverter.cs
System.ComponentModel/TypeConverterAttribute.cs
System.ComponentModel/TypeDescriptionProvider.cs
+System.ComponentModel/TypeDescriptionProviderAttribute.cs
System.ComponentModel/TypeDescriptor.cs
System.ComponentModel/TypeListConverter.cs
System.ComponentModel/UInt16Converter.cs
System.ComponentModel/UInt32Converter.cs
System.ComponentModel/UInt64Converter.cs
+System.ComponentModel/WarningException.cs
System.ComponentModel/WeakObjectWrapper.cs
System.ComponentModel/WeakObjectWrapperComparer.cs
System.ComponentModel/Win32Exception.cs