source: BMXNET_RPMS_dotNET_UTILITIES-BMX/branch/IHS BMX Framework/IndianHealthService.BMXNet/Net/BMXNetSessionSocketConnection.cs@ 1146

Last change on this file since 1146 was 1146, checked in by Sam Habiel, 13 years ago

Initial Import of BMX4

File size: 17.9 KB
Line 
1using System;
2using System.Diagnostics;
3using System.Text;
4using System.IO;
5using System.Net.Sockets;
6using System.Net;
7using System.Security.Cryptography;
8using System.Security.Permissions;
9using System.Security.Principal;
10using System.Threading;
11using System.Timers;
12
13namespace IndianHealthService.BMXNet.Net
14{
15 /// <summary>
16 /// BMXNetBroker implements low-level socket connectivity to RPMS databases.
17 /// The VA RPC Broker must be running on the RPMS server in order for
18 /// BMXNetBroker to connect.
19 /// </summary>
20 [DnsPermission(SecurityAction.Assert, Unrestricted = true)]
21 internal class BMXNetSessionSocketConnection : BMXNetSessionConnection
22 {
23 public static int DefaultSendTimeout = 20000;
24 public static int DefaultReceiveTimeout = 40000;
25
26 private int _sendTimeout = 0;
27
28 public override int SendTimeout
29 {
30 get
31 {
32 if (_sendTimeout != 0)
33 {
34 return _sendTimeout;
35 }
36 return this.ConnectionSpec.SendTimeout == 0 ? DefaultSendTimeout : this.ConnectionSpec.SendTimeout;
37 }
38 set { _sendTimeout = value; }
39 }
40
41
42 private int _receiveTimeout = 0;
43
44 /// <summary>
45 /// Set and retrieve the timeout, in milliseconds, to receive a response from the RPMS server.
46 /// If the retrieve time exceeds the timeout, an exception will be thrown and the connection will be closed.
47 /// The default is 30 seconds.
48 /// </summary>
49 public override int ReceiveTimeout
50 {
51 get
52 {
53 if (_receiveTimeout != 0)
54 {
55 return _receiveTimeout;
56 }
57 return this.ConnectionSpec.ReceiveTimeout == 0 ? DefaultReceiveTimeout : this.ConnectionSpec.ReceiveTimeout;
58 }
59 set
60 {
61 _receiveTimeout = value;
62 }
63 }
64
65 public BMXNetSessionSocketConnection(BMXNetBroker aBroker):base(aBroker)
66 {
67 m_sWKID = "BMX";
68 m_sWINH = "";
69 m_sPRCH = "";
70 m_sWISH = "";
71 m_cHDR = ADEBHDR(m_sWKID,m_sWINH,m_sPRCH,m_sWISH);
72
73 }
74
75
76
77 #region RPX Fields
78
79 private string m_sWKID;
80 private string m_sWISH;
81 private string m_sPRCH;
82 private string m_sWINH;
83 private string m_cHDR;
84 private bool m_bConnected;
85 private TcpClient m_pCommSocket;
86 private string m_sNameSpace = "";
87
88 #endregion RPX Fields
89
90
91 public TcpClient Socket
92 {
93 get { return this.m_pCommSocket; }
94 }
95
96 /// <summary>
97 /// Returns index of first instance of sSubString in sString.
98 /// If sSubString not found, returns -1.
99 /// </summary>
100 /// <returns></returns>
101
102 [SocketPermissionAttribute(SecurityAction.Assert,
103 Access = "Connect",
104 Host = "All",
105 Port = "All",
106 Transport = "All")]
107 protected virtual void OpenConnectionCommon()
108 {
109 try
110 {
111 TcpClient connector = null;
112
113 try
114 {
115 connector = new TcpClient();
116 connector.SendTimeout = this.SendTimeout;
117 connector.ReceiveTimeout = this.ReceiveTimeout;
118 connector.Connect(this.ServerAddress, this.ServerPort);
119 }
120 catch (SocketException exSocket)
121 {
122 string s = exSocket.Message + exSocket.StackTrace;
123 throw new BMXNetException(s);
124 }
125
126 //Prepare & send the connect message
127 string cSend = "TCPconnect^" + m_sNameSpace + "^^";
128 int nLen = cSend.Length;
129 string sLen = nLen.ToString();
130 sLen = sLen.PadLeft(5, '0');
131 cSend = "{BMX}" + sLen + cSend;
132
133 NetworkStream ns = connector.GetStream();
134 byte[] sendBytes = Encoding.ASCII.GetBytes(cSend);
135 ns.Write(sendBytes,0,sendBytes.Length);
136
137 m_pCommSocket = connector;
138 return;
139
140 }
141 catch (BMXNetException bmxEx)
142 {
143 throw bmxEx;
144 }
145 catch (Exception ex)
146 {
147 string s = ex.Message + ex.StackTrace;
148 throw new BMXNetException(s);
149 }
150 }//End OpenConnectionCommon
151
152
153 private BMXNetSocketConnectionSpec _connectionSpec = null;
154
155 internal BMXNetSocketConnectionSpec ConnectionSpec
156 {
157 get { return _connectionSpec; }
158 set { _connectionSpec = value; }
159 }
160
161
162 [SocketPermissionAttribute(SecurityAction.Assert,
163 Access = "Connect",
164 Host = "All",
165 Port = "All",
166 Transport = "All")]
167 public virtual bool OpenConnection(BMXNetSocketConnectionSpec aSpec)
168 {
169 this.ConnectionSpec = aSpec;
170
171 try
172 {
173 m_bConnected = false;
174 this.OpenConnectionCommon();
175 if (this.CheckConnection())
176 {
177 bool authenicated = false;
178
179 if (aSpec.UseWindowsAuthentication)
180 {
181 authenicated = this.SendSecurityRequest(aSpec.WindowsIdentity);
182 }
183 else
184 {
185 authenicated = SendSecurityRequest(aSpec.EncryptedAccessVerifyCode);
186 }
187
188 this.m_bConnected = authenicated;
189
190
191
192 int integerDuz = 0;
193 if (!int.TryParse(this.DUZ, out integerDuz))
194 {
195 throw new BMXNetException("Invalid DUZ, Unable to authenticate user.");
196 }
197
198 this.UserName = this.GetUserName();
199 }
200 return this.IsConnected;
201 }
202 catch (BMXNetException bmxEx)
203 {
204 throw bmxEx;
205 }
206 catch (Exception ex)
207 {
208 string s = ex.Message + ex.StackTrace;
209 throw new BMXNetException(s);
210 }
211 finally
212 {
213 if (!this.IsConnected)
214 {
215 this.PrimitiveCloseConnection();
216 }
217 }
218 }
219
220
221
222
223 bool m_bLogging = false;
224
225 private static void Log(String logMessage, TextWriter w)
226 {
227 w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
228 DateTime.Now.ToLongDateString());
229 w.WriteLine(" :");
230 w.WriteLine(" :{0}", logMessage);
231 w.WriteLine("-------------------------------");
232 // Update the underlying file.
233 w.Flush();
234 }
235
236 private bool CheckConnection()
237 {
238 try
239 {
240 String cMSG = ADEBLDMsg(m_cHDR, "BMX CONNECT STATUS", "");
241
242 this.SendString(this.Socket, cMSG);
243 String strReceive = ReceiveString(this.Socket);
244 String port = BMXNetBroker.Piece(strReceive, "|", 1);
245 String message = BMXNetBroker.Piece(strReceive, "|", 2);
246
247 if (!message.Contains("OK"))
248 {
249 throw new BMXNetException(message.Length==0 ? strReceive : message);
250 }
251
252 this.Job = BMXNetBroker.Piece(strReceive, "|", 3);
253
254 return true;
255 }
256 catch (Exception potentialProblem)
257 { //If there's an issue, assume old BMX 2.x/3.x so this feature is not supports BMX CONNECT STATUS
258 if (potentialProblem.Message.Contains("BMX CONNECT STATUS"))
259 {
260 return true;
261 }
262 else
263 {
264 throw potentialProblem;
265 }
266 }
267 }
268
269 public override bool IsConnected
270 {
271 get
272 {
273 return this.m_bConnected;
274 }
275 }
276
277
278 protected override String SendReceiveString(string cSendString, string cMult)
279 {
280#if DEBUG
281 Stopwatch _watch = new Stopwatch();
282 _watch.Start();
283 Debug.WriteLine("Sending (T:" + Thread.CurrentThread.ManagedThreadId + "): " + cSendString);
284#endif
285 this.SendString(this.m_pCommSocket, cSendString, cMult);
286 string _received = this.ReceiveString(this.m_pCommSocket);
287#if DEBUG
288 Debug.WriteLine("Received(T:" + Thread.CurrentThread.ManagedThreadId + "): " + _received.Replace((char) 30, (char) 10));
289 Debug.WriteLine("Time: " + _watch.ElapsedMilliseconds + " ms");
290 Debug.WriteLine("---");
291 _watch = null;
292#endif
293 return _received;
294 }
295
296
297 protected virtual void SendString(TcpClient tcpClient, string cSendString)
298 {
299 string sMult = "";
300 SendString(tcpClient, cSendString, sMult);
301 }
302
303 protected virtual void SendString(TcpClient tcpClient, string cSendString, string cMult)
304 {
305 String encodedString = this.EncodeSendString(cSendString, cMult);
306
307 NetworkStream ns = tcpClient.GetStream();
308 ns.WriteTimeout = this.SendTimeout;
309 byte[] sendBytes = Encoding.ASCII.GetBytes(encodedString);
310 ns.Write(sendBytes,0,sendBytes.Length);
311 if (this.m_bLogging == true)
312 {
313 Log("Sent: " + cSendString, this.m_LogWriter);
314 }
315 return;
316 }
317
318
319 private string ReceiveString(TcpClient tcpClient)
320 {
321 NetworkStream ns = tcpClient.GetStream();
322 ns.ReadTimeout = this.ReceiveTimeout;
323
324
325 //TAE: This following is suspect. NetworkSTream Read and ReadTimeout provide
326 //the same behavior. Look at removing in the futuer. For now, this works.
327 int cyclePause = 25;
328 int cycles = 0;
329 DateTime start = DateTime.Now;
330 while (ns.DataAvailable == false)
331 {
332 if (cycles++ > 999)
333 break;
334 if ((DateTime.Now-start).TotalMilliseconds > this.ReceiveTimeout)
335 break;
336 Thread.Sleep(cyclePause);
337 }
338
339 Debug.Assert(ns.DataAvailable);
340 if (!ns.DataAvailable)
341 {
342 this.Close();
343 throw new Exception("BMXNetBroker.ReceiveString timeout. Connection Closed.");
344 }
345
346 byte[] bReadBuffer = new byte[1024];
347 string sReadBuffer = "";
348 StringBuilder sbAll = new StringBuilder("", 1024);
349 int numberOfBytesRead = 0;
350
351 // Incoming message may be larger than the buffer size.
352
353 bool bFinished = false;
354 bool bStarted = false;
355 int lpBuf = 0;
356 string sError = "";
357 string sAppError = "";
358 do
359 {
360
361 numberOfBytesRead = ns.Read(bReadBuffer, 0, bReadBuffer.Length);
362 if ((numberOfBytesRead == 1)&&(bStarted == false))
363 {
364 //TAE: This following is suspect. If Read is blocking then this sleep is extra.
365 //This is rarely called
366 Thread.Sleep(15);
367 numberOfBytesRead += ns.Read(bReadBuffer,1, bReadBuffer.Length-1);
368 }
369 if (bStarted == false)
370 {
371 //Process error info at beginning of returned string
372 int nErrLen = bReadBuffer[0];
373 int nAppLen = bReadBuffer[bReadBuffer[0]+1];
374 if ((bReadBuffer[2] == 0)&&(bReadBuffer[3] == 0))
375 { //special case: M error trap invoked in SND^XWBTCPC
376 lpBuf += 2;
377 }
378 sError = Encoding.ASCII.GetString(bReadBuffer, lpBuf + 1, nErrLen);
379 if (sError != "")
380 {
381 sAppError = Encoding.ASCII.GetString(bReadBuffer, lpBuf + 1 + nErrLen + 1, nAppLen);
382 throw new BMXNetException(sError);
383 }
384 sAppError = Encoding.ASCII.GetString(bReadBuffer, lpBuf+1+nErrLen+1, nAppLen);
385 lpBuf += (nErrLen + nAppLen + 2);
386 numberOfBytesRead -= (nErrLen + nAppLen + 2);
387 bStarted = true;
388 }
389
390 bFinished = FindChar(bReadBuffer, (char)4) > -1;
391 Debug.Assert(numberOfBytesRead > -1);
392 sReadBuffer = Encoding.ASCII.GetString(bReadBuffer, lpBuf, numberOfBytesRead);
393 lpBuf = 0;
394 if (bFinished)
395 {
396 sbAll.Append(sReadBuffer, 0, numberOfBytesRead -1);
397 }
398 else
399 {
400 sbAll.Append(sReadBuffer);
401 }
402 }
403 while(!bFinished);
404
405 String decodedReceiveString = this.DecodeReceiveString(sbAll.ToString());
406
407 if (this.m_bLogging)
408 {
409 Log("Received: " + decodedReceiveString, this.m_LogWriter);
410 }
411 return decodedReceiveString;
412
413 }
414
415
416 private bool SendSecurityRequest(WindowsIdentity winIdentity)
417 {
418 string strReceive = "";
419 string cMSG;
420 string sTest;
421
422 //Build AV Call
423 cMSG = ADEBLDMsg(m_cHDR, "BMX AV CODE", winIdentity.Name);
424 SendString(this.Socket, cMSG);
425
426 strReceive = ReceiveString(this.Socket);
427 sTest = strReceive.Substring(0,3);
428
429 char[] cDelim = {(char) 13,(char) 10,(char) 0};
430 string sDelim = new string(cDelim);
431 int nPiece = 1;
432 this.DUZ = M.Piece(strReceive, sDelim , nPiece);
433 if ((this.DUZ.Length==0 ) || ("0".Equals(this.DUZ)))
434 {
435 nPiece = 7;
436 string sReason = M.Piece(strReceive, sDelim, nPiece);
437 throw new Exception(sReason);
438 }
439
440 return true;
441 }
442
443 public String EncryptAccessVerifyCode(string anAccessCode, string aVerifyCode)
444 {
445 string accessVerifyPair = anAccessCode.ToUpper() + ";" + aVerifyCode.ToUpper();
446 return this.EncryptionProvider.Encrypt(accessVerifyPair);
447 }
448
449 private bool SendSecurityRequest(string encryptedAccessVerifyCode)
450 {
451 string strReceive = "";
452 string cMSG;
453
454 cMSG = ADEBLDMsg(m_cHDR, "XUS AV CODE", encryptedAccessVerifyCode);
455 SendString(this.Socket, cMSG);
456
457 strReceive = ReceiveString(this.Socket);
458
459 if (strReceive.StartsWith("M ERROR="))
460 {
461 this.DUZ = "0";
462 throw new BMXNetException("Server error has occured: " + strReceive);
463 }
464
465
466 char[] cDelim = {(char) 13,(char) 10,(char) 0};
467 string U = new string(cDelim);
468
469 this.DUZ = M.Piece(strReceive,U, 1);
470 String resultCode = M.Piece(strReceive, U, 2);
471 String resultMessageIndex = M.Piece(strReceive, U, 3);
472//R(0)=DUZ if sign-on was OK, zero if not OK.
473 //R(1)=(0=OK, 1,2...=Can't sign-on for some reason).
474 //R(2)=verify needs changing.
475 //R(3)=Message.
476 //R(4)=0
477 //R(5)=count of the number of lines of text, zero if none.
478
479 //extracall but same code-path as winidentity login
480
481 if ((this.DUZ == "0") || (this.DUZ == ""))
482 {
483 string sReason = M.Piece(strReceive, U, 7);
484 throw new BMXNetException(sReason);
485 }
486
487 return true;
488 }
489
490
491 public override void Close()
492 {
493 if (m_bConnected)
494 {
495 this.PrimitiveCloseConnection();
496 }
497 }
498
499 protected void PrimitiveCloseConnection() {
500
501 if (this.Socket != null)
502 {
503 SendString(this.Socket, "#BYE#");
504 this.Socket.Close();
505 m_pCommSocket = null;
506 }
507 this.ConnectionSpec = null;
508 this.DUZ = "";
509 m_bConnected=false;
510 }
511
512
513 public override string GetLoginFacility(String aDuz)
514 {
515 try
516 {
517 if (!this.IsConnected)
518 {
519 throw new BMXNetException("BMXNetBroker is not connected to RPMS");
520 }
521
522 this.SendString(this.Socket, ADEBLDMsg(m_cHDR, "BMXGetFac", aDuz));
523 return this.ReceiveString(this.Socket);
524 }
525 catch (BMXNetException bmxEx)
526 {
527 throw new BMXNetException(bmxEx.Message + " || "+bmxEx.StackTrace);
528 }
529 catch (Exception ex)
530 {
531 throw ex;
532 }
533 }
534
535
536 protected String GetUserName()
537 {
538 return this.TransmitRPC("BMX USER", this.DUZ);
539 }
540
541 /// <summary>
542 /// Ping the server, will reset read-timeout
543 /// </summary>
544 /// <returns>Answer the #milliseconds to run or -1 if theres an issue</returns>
545 public double ImHereServer()
546 {
547 try
548 {
549 if (this.IsConnected)
550 {
551 DateTime past = DateTime.Now;
552 this.TransmitRPC("BMX IM HERE","");
553 return (DateTime.Now - past).TotalMilliseconds;
554 }
555 else
556 {
557 return -1;
558 }
559 }
560 catch
561 {
562 return -1;
563 }
564 }
565
566 #region RPX Properties
567
568
569
570 public bool Connected
571 {
572 get
573 {
574 return m_bConnected;
575 }
576 }
577
578
579 public string ServerAddress
580 {
581 get
582 {
583 return this.ConnectionSpec.Server;
584 }
585 }
586
587 public string ServerNamespace
588 {
589 get
590 {
591 return this.ConnectionSpec.NameSpace;
592 }
593 }
594
595 public int ServerPort
596 {
597 get
598 {
599 return this.ConnectionSpec.Port;
600 }
601 }
602
603
604 #endregion RPX Properties
605
606
607
608
609 }
610
611 /*
6121 ;;1;Signons not currently allowed on this processor.
6132 ;;1;Maximum number of users already signed on to this processor.
6143 ;;1;This device has not been defined to the system -- contact system manager.
6154 ;;0;Not a valid Windows Identity map value.
6165 ;;0;No Access Allowed for this User.
6176 ;;0;Invalid device password.
6187 ;;0;Device locked due to too many invalid sign-on attempts.
6198 ;;1;This device is out of service.
6209 ;;0;*** MULTIPLE SIGN-ONS NOT ALLOWED ***
62110 ;;1;You don't have access to this device!
62211 ;;0;Your access code has been terminated. Please see your site manager!
62312 ;;0;VERIFY CODE MUST be changed before continued use.
62413 ;;1;This device may only be used outside of this time frame |
62514 ;;0;'|' is not a valid UCI!
62615 ;;0;'|' is not a valid program name!
62716 ;;0;No PRIMARY MENU assigned to user or User is missing KEY to menu!
62817 ;;0;Your access to the system is prohibited from |.
62918 ;;0;Windows Integrated Security Not Allowed on this port.*/
630}
Note: See TracBrowser for help on using the repository browser.