1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Globalization;
7     using System.Net;
8     using System.ServiceModel;
9     using System.Text;
10 
11     static class MsmqUri
12     {
13         static IAddressTranslator netMsmqAddressTranslator;
14         static IAddressTranslator activeDirectoryAddressTranslator;
15         static IAddressTranslator deadLetterQueueAddressTranslator;
16         static IAddressTranslator srmpAddressTranslator;
17         static IAddressTranslator srmpsAddressTranslator;
18         static IAddressTranslator formatnameAddressTranslator;
19 
20         public static IAddressTranslator NetMsmqAddressTranslator
21         {
22             get
23             {
24                 if (null == netMsmqAddressTranslator)
25                     netMsmqAddressTranslator = new MsmqUri.NetMsmq();
26                 return netMsmqAddressTranslator;
27             }
28         }
29 
30         public static IAddressTranslator ActiveDirectoryAddressTranslator
31         {
32             get
33             {
34                 if (null == activeDirectoryAddressTranslator)
35                     activeDirectoryAddressTranslator = new MsmqUri.ActiveDirectory();
36                 return activeDirectoryAddressTranslator;
37             }
38         }
39 
40         public static IAddressTranslator DeadLetterQueueAddressTranslator
41         {
42             get
43             {
44                 if (null == deadLetterQueueAddressTranslator)
45                     deadLetterQueueAddressTranslator = new MsmqUri.Dlq();
46                 return deadLetterQueueAddressTranslator;
47             }
48         }
49 
50         public static IAddressTranslator SrmpAddressTranslator
51         {
52             get
53             {
54                 if (null == srmpAddressTranslator)
55                     srmpAddressTranslator = new MsmqUri.Srmp();
56                 return srmpAddressTranslator;
57             }
58         }
59 
60         public static IAddressTranslator SrmpsAddressTranslator
61         {
62             get
63             {
64                 if (null == srmpsAddressTranslator)
65                     srmpsAddressTranslator = new MsmqUri.SrmpSecure();
66                 return srmpsAddressTranslator;
67             }
68         }
69 
70         public static IAddressTranslator FormatNameAddressTranslator
71         {
72             get
73             {
74                 if (null == formatnameAddressTranslator)
75                     formatnameAddressTranslator = new MsmqUri.FormatName();
76                 return formatnameAddressTranslator;
77             }
78         }
79 
UriToFormatNameByScheme(Uri uri)80         public static string UriToFormatNameByScheme(Uri uri)
81         {
82             if (uri.Scheme == NetMsmqAddressTranslator.Scheme)
83             {
84                 return NetMsmqAddressTranslator.UriToFormatName(uri);
85             }
86             else if (uri.Scheme == FormatNameAddressTranslator.Scheme)
87             {
88                 return FormatNameAddressTranslator.UriToFormatName(uri);
89             }
90             else
91             {
92                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("uri");
93             }
94         }
95 
AppendQueueName(StringBuilder builder, string relativePath, string slash)96         static void AppendQueueName(StringBuilder builder, string relativePath, string slash)
97         {
98             const string privatePart = "/private";
99 
100             if (relativePath.StartsWith("/private$", StringComparison.OrdinalIgnoreCase))
101                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MsmqWrongPrivateQueueSyntax)));
102 
103             if (relativePath.StartsWith(privatePart, StringComparison.OrdinalIgnoreCase))
104             {
105                 if (privatePart.Length == relativePath.Length)
106                 {
107                     builder.Append("private$");
108                     builder.Append(slash);
109                     relativePath = "/";
110                 }
111                 else if ('/' == relativePath[privatePart.Length])
112                 {
113                     builder.Append("private$");
114                     builder.Append(slash);
115                     relativePath = relativePath.Substring(privatePart.Length);
116                 }
117             }
118             builder.Append(relativePath.Substring(1));
119         }
120 
121         internal interface IAddressTranslator
122         {
123             string Scheme { get; }
UriToFormatName(Uri uri)124             string UriToFormatName(Uri uri);
CreateUri(string host, string name, bool isPrivate)125             Uri CreateUri(string host, string name, bool isPrivate);
126         }
127 
128         class NetMsmq : IAddressTranslator
129         {
130             public string Scheme
131             {
132                 get { return "net.msmq"; }
133             }
134 
UriToFormatName(Uri uri)135             public string UriToFormatName(Uri uri)
136             {
137                 if (null == uri)
138                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("uri"));
139                 if (uri.Scheme != this.Scheme)
140                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqInvalidScheme), "uri"));
141                 if (String.IsNullOrEmpty(uri.Host))
142                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.MsmqWrongUri));
143                 if (-1 != uri.Port)
144                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.MsmqUnexpectedPort));
145 
146                 StringBuilder builder = new StringBuilder();
147                 builder.Append("DIRECT=");
148                 if (0 == String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
149                     builder.Append("OS:.");
150                 else
151                 {
152                     IPAddress address = null;
153                     if (IPAddress.TryParse(uri.Host, out address))
154                         builder.Append("TCP:");
155                     else
156                         builder.Append("OS:");
157 
158                     builder.Append(uri.Host);
159                 }
160                 builder.Append("\\");
161                 MsmqUri.AppendQueueName(builder, Uri.UnescapeDataString(uri.PathAndQuery), "\\");
162 
163                 return builder.ToString();
164             }
165 
CreateUri(string host, string name, bool isPrivate)166             public Uri CreateUri(string host, string name, bool isPrivate)
167             {
168                 string path = "/" + name;
169                 if (isPrivate)
170                 {
171                     path = "/private" + path;
172                 }
173 
174                 return (new UriBuilder(Scheme, host, -1, path)).Uri;
175             }
176         }
177 
178         class PathName : IAddressTranslator
179         {
180             public string Scheme
181             {
182                 get { return "net.msmq"; }
183             }
184 
UriToFormatName(Uri uri)185             public virtual string UriToFormatName(Uri uri)
186             {
187                 if (null == uri)
188                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("uri"));
189                 if (uri.Scheme != this.Scheme)
190                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqInvalidScheme), "uri"));
191                 if (String.IsNullOrEmpty(uri.Host))
192                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.MsmqWrongUri));
193                 if (-1 != uri.Port)
194                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.MsmqUnexpectedPort));
195 
196                 uri = PostVerify(uri);
197 
198                 StringBuilder builder = new StringBuilder();
199                 if (0 == String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
200                     builder.Append(".");
201                 else
202                     builder.Append(uri.Host);
203 
204                 builder.Append("\\");
205                 MsmqUri.AppendQueueName(builder, Uri.UnescapeDataString(uri.PathAndQuery), "\\");
206 
207                 return builder.ToString();
208             }
209 
CreateUri(string host, string name, bool isPrivate)210             public Uri CreateUri(string host, string name, bool isPrivate)
211             {
212                 string path = "/" + name;
213                 if (isPrivate)
214                 {
215                     path = "/private" + path;
216                 }
217 
218                 return (new UriBuilder(Scheme, host, -1, path)).Uri;
219             }
220 
PostVerify(Uri uri)221             protected virtual Uri PostVerify(Uri uri)
222             {
223                 return uri;
224             }
225         }
226 
227         class ActiveDirectory : PathName
228         {
UriToFormatName(Uri uri)229             public override string UriToFormatName(Uri uri)
230             {
231                 return MsmqFormatName.FromQueuePath(base.UriToFormatName(uri));
232             }
233         }
234 
235         class Dlq : PathName
236         {
PostVerify(Uri uri)237             protected override Uri PostVerify(Uri uri)
238             {
239                 if (0 == String.Compare(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
240                     return uri;
241                 try
242                 {
243                     if (0 == String.Compare(DnsCache.MachineName, DnsCache.Resolve(uri).HostName, StringComparison.OrdinalIgnoreCase))
244                     {
245                         return new UriBuilder(Scheme, "localhost", -1, uri.PathAndQuery).Uri;
246                     }
247                 }
248                 catch (EndpointNotFoundException ex)
249                 {
250                     MsmqDiagnostics.ExpectedException(ex);
251                 }
252                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqDLQNotLocal), "uri"));
253             }
254         }
255 
256         abstract class SrmpBase : IAddressTranslator
257         {
258             const string msmqPart = "/msmq/";
259 
260             public string Scheme
261             {
262                 get { return "net.msmq"; }
263             }
264 
UriToFormatName(Uri uri)265             public string UriToFormatName(Uri uri)
266             {
267                 if (null == uri)
268                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("uri"));
269                 if (uri.Scheme != this.Scheme)
270                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqInvalidScheme), "uri"));
271                 if (String.IsNullOrEmpty(uri.Host))
272                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.MsmqWrongUri));
273 
274                 StringBuilder builder = new StringBuilder();
275                 builder.Append("DIRECT=");
276                 builder.Append(this.DirectScheme);
277                 builder.Append(uri.Host);
278                 if (-1 != uri.Port)
279                 {
280                     builder.Append(":");
281                     builder.Append(uri.Port.ToString(CultureInfo.InvariantCulture));
282                 }
283 
284                 string relativePath = Uri.UnescapeDataString(uri.PathAndQuery);
285                 builder.Append(msmqPart);
286                 MsmqUri.AppendQueueName(builder, relativePath, "/");
287 
288                 return builder.ToString();
289             }
290 
291             abstract protected string DirectScheme { get; }
292 
CreateUri(string host, string name, bool isPrivate)293             public Uri CreateUri(string host, string name, bool isPrivate)
294             {
295                 string path = "/" + name;
296                 if (isPrivate)
297                 {
298                     path = "/private" + path;
299                 }
300 
301                 return (new UriBuilder(Scheme, host, -1, path)).Uri;
302             }
303         }
304 
305         class Srmp : SrmpBase
306         {
307             protected override string DirectScheme
308             {
309                 get { return "http://"; }
310             }
311         }
312 
313         class SrmpSecure : SrmpBase
314         {
315             protected override string DirectScheme
316             {
317                 get { return "https://"; }
318             }
319         }
320 
321         class FormatName : IAddressTranslator
322         {
323             public string Scheme
324             {
325                 get { return "msmq.formatname"; }
326             }
327 
UriToFormatName(Uri uri)328             public string UriToFormatName(Uri uri)
329             {
330                 if (null == uri)
331                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("uri"));
332                 if (uri.Scheme != this.Scheme)
333                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.MsmqInvalidScheme), "uri"));
334                 return Uri.UnescapeDataString(uri.AbsoluteUri.Substring(this.Scheme.Length + 1));
335             }
336 
CreateUri(string host, string name, bool isPrivate)337             public Uri CreateUri(string host, string name, bool isPrivate)
338             {
339                 string path;
340                 if (isPrivate)
341                 {
342                     path = "PRIVATE$\\" + name;
343                 }
344                 else
345                 {
346                     path = name;
347                 }
348 
349                 path = "DIRECT=OS:" + host + "\\" + path;
350 
351                 return new Uri(Scheme + ":" + path);
352             }
353         }
354     }
355 }
356