source: BMXNET_RPMS_dotNET_UTILITIES-BMX/branch/IHS BMX Framework/IndianHealthService.BMXNet/BMXNetSessionConnection.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: 24.4 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;
12using IndianHealthService.BMXNet.Net;
13using IndianHealthService.BMXNet.Services;
14using IndianHealthService.BMXNet.Model;
15using System.Windows.Forms;
16
17namespace IndianHealthService.BMXNet
18{
19 /// <summary>
20 /// BMXNetSessionConnection implements low-level connectivity to RPMS databases.
21 /// </summary>
22 [DnsPermission(SecurityAction.Assert, Unrestricted = true)]
23 internal abstract class BMXNetSessionConnection
24 {
25 public BMXNetSessionConnection(BMXNetBroker aBroker)
26 {
27 this.Broker = aBroker;
28 m_sWKID = "BMX";
29 m_sWINH = "";
30 m_sPRCH = "";
31 m_sWISH = "";
32 m_cHDR = ADEBHDR(m_sWKID, m_sWINH, m_sPRCH, m_sWISH);
33 }
34
35 protected BMXNetBroker _broker=null;
36
37 public BMXNetBroker Broker
38 {
39 get { return _broker; }
40 set { _broker=value;}
41 }
42
43 protected EncryptionProvider EncryptionProvider
44 {
45 get
46 {
47 return this.Broker.EncryptionProvider;
48 }
49 }
50
51
52 #region RPX Fields
53
54 private string m_sWKID;
55 private string m_sWISH;
56 private string m_sPRCH;
57 private string m_sWINH;
58 private string m_cHDR;
59 protected string m_cAppContext;
60 private string m_cDUZ;
61
62 #endregion RPX Fields
63
64 #region RPX Functions
65
66 /// <summary>
67 /// Given strInput = "13" builds "013" if nLength = 3. Default for nLength is 3.
68 /// </summary>
69 /// <param name="strInput"></param>
70 /// <returns></returns>
71 protected string ADEBLDPadString(string strInput)
72 {
73 return ADEBLDPadString(strInput, 3);
74 }
75
76 /// <summary>
77 /// Given strInput = "13" builds "013" if nLength = 3 Default for nLength is 3.
78 /// </summary>
79 /// <param name="strInput"></param>
80 /// <param name="nLength">Default = 3</param>
81 /// <returns></returns>
82 protected string ADEBLDPadString(string strInput, int nLength /*=3*/)
83 {
84 return strInput.PadLeft(nLength, '0');
85 }
86
87 /// <summary>
88 /// Concatenates zero-padded length of sInput to sInput
89 /// Given "Hello" returns "004Hello"
90 /// If nSize = 5, returns "00004Hello"
91 /// Default for nSize is 3.
92 /// </summary>
93 /// <param name="sInput"></param>
94 /// <returns></returns>
95 protected string ADEBLDB(string sInput)
96 {
97 return ADEBLDB(sInput, 3);
98 }
99
100 /// <summary>
101 /// Concatenates zero-padded length of sInput to sInput
102 /// Given "Hello" returns "004Hello"
103 /// If nSize = 5, returns "00004Hello"
104 /// Default for nSize is 3.
105 /// </summary>
106 /// <param name="sInput"></param>
107 /// <param name="nSize"></param>
108 /// <returns></returns>
109 protected string ADEBLDB(string sInput, int nSize /*=3*/)
110 {
111 int nLen = sInput.Length;
112 string sLen = this.ADEBLDPadString(nLen.ToString(), nSize);
113 return sLen + sInput;
114 }
115
116 /// <summary>
117 /// Build protocol header
118 /// </summary>
119 /// <param name="sWKID"></param>
120 /// <param name="sWINH"></param>
121 /// <param name="sPRCH"></param>
122 /// <param name="sWISH"></param>
123 /// <returns></returns>
124 protected string ADEBHDR(string sWKID, string sWINH, string sPRCH, string sWISH)
125 {
126 string strResult;
127 strResult = sWKID + ";" + sWINH + ";" + sPRCH + ";" + sWISH + ";";
128 strResult = ADEBLDB(strResult);
129 return strResult;
130 }
131 protected string ADEBLDMsg(string cHDR, string cRPC, string cParam)
132 {
133 string sMult = "";
134 return ADEBLDMsg(cHDR, cRPC, cParam, ref sMult);
135 }
136
137 protected string ADEBLDPadString(int anInteger)
138 {
139 return ADEBLDPadString(anInteger.ToString(), 3);
140 }
141
142 protected string ADEBLDPadString(int anInteger, int nLength /*=3*/)
143 {
144 return this.ADEBLDPadString(anInteger.ToString(), nLength);
145 }
146
147
148 protected string ADEBLDMsg(string cHDR, string cRPC, string cParam, ref string cMult)
149 {
150 //Builds RPC message
151 //Automatically splits parameters longer than 200 into subscripted array
152 String body;
153 cMult = "";
154
155 if (cParam == "")
156 {
157 body = "0" + cRPC;
158 }
159 else
160 {
161 StringBuilder parametersBuilder = new StringBuilder((int)(cParam.Length * 1.2));
162 int parameterCount = M.PieceLength(cParam, "^");
163 int maxChunkLength = 400;
164
165 for (int j = 1; j <= parameterCount; j++)
166 {
167 String piece = M.Piece(cParam, "^", j);
168
169 if (piece.Length > maxChunkLength)
170 {
171 if (j == parameterCount)
172 {
173 //Place holder for the long parameter
174 String prefix = ".x";
175 parametersBuilder.Append(ADEBLDPadString(prefix.Length + 1) + "2" + prefix);
176
177 StringBuilder encodedMultiPart = new StringBuilder((int)(piece.Length * 1.2));
178 int subscript = 1;
179 int startChunk = 0;
180 do
181 {
182 int chunkLength = Math.Min(piece.Length - startChunk, maxChunkLength);
183 String chunk = piece.Substring(startChunk, chunkLength);
184 String subscriptString = subscript.ToString();
185
186 encodedMultiPart.Append(ADEBLDPadString(subscriptString.Length));
187 encodedMultiPart.Append(subscriptString);
188 encodedMultiPart.Append(ADEBLDPadString(chunk.Length));
189 encodedMultiPart.Append(chunk);
190
191 subscript++;
192 startChunk += chunkLength;
193 } while (startChunk < piece.Length);
194 cMult = encodedMultiPart.ToString();
195 }
196 else
197 {
198 throw new BMXNetException("RPC parameter exceeds " + maxChunkLength.ToString() + ". Lone long parameter must be last.");
199 }
200 }
201 else
202 {
203 parametersBuilder.Append(ADEBLDPadString(piece.Length + 1) + "0" + piece);
204 }
205 }
206
207 String parameters = parametersBuilder.ToString();
208 body = (cMult.Length > 0 ? "1" : "0") + cRPC + "^" + ADEBLDPadString(parameters.Length, 5) + parameters;
209 }
210
211 return cHDR + ADEBLDB(body, 5);
212 }
213
214
215 public static int FindChar(byte[] c, char y)
216 {
217 int n = 0;
218 int nRet = -1;
219 for (n = 0; n < c.Length; n++)
220 {
221 if (y == (char)c[n])
222 {
223 nRet = n;
224 break;
225 }
226 }
227
228 return nRet;
229 }
230
231 public static int FindChar(string s, char y)
232 {
233 int n = 0;
234 int nRet = -1;
235 foreach (char c in s)
236 {
237 if (y == c)
238 {
239 nRet = n;
240 break;
241 }
242 n++;
243 }
244 return nRet;
245 }
246
247
248 /// <summary>
249 /// Returns index of first instance of sSubString in sString.
250 /// If sSubString not found, returns -1.
251 /// </summary>
252 /// <param name="sString"></param>
253 /// <param name="sSubString"></param>
254 /// <returns></returns>
255 public static int FindSubString(string sString, string sSubString)
256 {
257 int nFound = -1;
258 int nLimit = sString.Length - sSubString.Length + 1;
259 if (nLimit < 0)
260 return -1;
261
262 int nSubLength = sSubString.Length;
263 for (int j = 0; j < nLimit; j++)
264 {
265 if (sString.Substring(j, nSubLength) == sSubString)
266 {
267 nFound = j;
268 break;
269 }
270 }
271 return nFound;
272 }
273
274
275 protected StreamWriter m_LogWriter;
276 bool m_bLogging = false;
277
278 public void StartLog()
279 {
280 try
281 {
282 if (m_bLogging)
283 {
284 throw new Exception("Already logging.");
285 }
286 string sFile = "BMXLog " + DateTime.Now.DayOfYear.ToString() + " " +
287 DateTime.Now.Hour.ToString() + " " + DateTime.Now.Minute.ToString()
288 + " " + DateTime.Now.Second.ToString() + ".log";
289 StartLog(sFile);
290 return;
291 }
292 catch (Exception ex)
293 {
294 throw ex;
295 }
296 }
297
298 public void StartLog(string LogFileName)
299 {
300 try
301 {
302 if (m_bLogging)
303 {
304 throw new Exception("Already logging.");
305 }
306 m_LogWriter = File.AppendText(LogFileName);
307 m_bLogging = true;
308 return;
309 }
310 catch (Exception ex)
311 {
312 throw ex;
313 }
314 }
315
316 public void StopLog()
317 {
318 try
319 {
320 //Close the writer and underlying file.
321 if (m_bLogging == false)
322 {
323 return;
324 }
325 m_LogWriter.Close();
326 m_bLogging = false;
327 return;
328 }
329 catch (Exception ex)
330 {
331 throw ex;
332 }
333 }
334
335 private static void Log(String logMessage, TextWriter w)
336 {
337 w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
338 DateTime.Now.ToLongDateString());
339 w.WriteLine(" :");
340 w.WriteLine(" :{0}", logMessage);
341 w.WriteLine("-------------------------------");
342 // Update the underlying file.
343 w.Flush();
344 }
345
346
347
348 public bool Lock(string Variable)
349 {
350 return Lock(Variable, "", "");
351 }
352
353 public bool Lock(string Variable, string Increment)
354 {
355 return Lock(Variable, Increment, "");
356 }
357
358 /// <summary>
359 /// Lock a local or global M variable
360 /// Returns true if lock is obtained during TimeOut seconds
361 /// Use + to increment, - to decrement lock.
362 /// </summary>
363 /// <param name="Variable"></param>
364 /// <param name="Increment"></param>
365 /// <param name="TimeOut"></param>
366 /// <returns></returns>
367 public bool Lock(string Variable, string Increment, string TimeOut)
368 {
369 try
370 {
371 Variable = Variable.Replace("^", "~");
372 string sParam = Variable + "^" + Increment + "^" + TimeOut;
373 string sRet = TransmitRPC("BMX LOCK", sParam);
374 return (sRet == "1");
375 }
376 catch (Exception ex)
377 {
378
379 string sMsg = ex.Message;
380 return false;
381 }
382 }
383
384 static ReaderWriterLock m_rwl = new ReaderWriterLock();
385
386
387 /// <summary>
388 /// Returns a reference to the internal ReaderWriterLock member.
389 /// </summary>
390 public ReaderWriterLock BMXRWL
391 {
392 get
393 {
394 return m_rwl;
395 }
396 }
397
398 public abstract bool IsConnected { get; }
399
400 public abstract void Close();
401
402 protected string EncodeSendString(String cSendString, String cMulti)
403 {
404 String encoded = null;
405
406 int nLen = cSendString.Length;
407 string sLen = nLen.ToString();
408 sLen = sLen.PadLeft(5, '0');
409 encoded = sLen + cSendString;
410
411 nLen += 15;
412 sLen = nLen.ToString();
413 sLen = sLen.PadLeft(5, '0');
414
415 encoded = "{BMX}" + sLen + encoded;
416 encoded = encoded + cMulti;
417
418 return encoded;
419 }
420
421 protected string DecodeReceiveString(String aString)
422 {
423 return aString;
424 }
425
426 protected String SendReceiveString(String sendString)
427 {
428 return this.SendReceiveString(sendString, "");
429 }
430
431 private String _createContextRpc = "BMX CREATE CONTEXT";
432
433 protected String CreateContextRpc
434 {
435 get { return _createContextRpc; }
436 set { _createContextRpc = value; }
437 }
438
439 protected abstract String SendReceiveString(String sendString, String multi);
440
441 public abstract int ReceiveTimeout { get; set; }
442 public abstract int SendTimeout { get; set; }
443
444
445 /// <remarks>
446 /// AppContext is managed an client and server with c/s calls to change
447 /// appContext on the server. There is no use for AppContext on the client
448 /// so recommend integrated AppContext into BMX Protocol so always passing
449 /// it and managing switching it on the server.
450 /// </remarks>
451 public string TransmitRPC(string anRpc, string rpcParameter)
452 {
453 this.AssertConnected();
454
455
456 if (rpcParameter.Length > 32600)
457 {
458 throw new Exception("RPC parameter length exceeds maximum allowable size.");
459 }
460
461 try
462 {
463 string sMult = "";
464 string sSend = ADEBLDMsg(m_cHDR, anRpc, rpcParameter, ref sMult);
465 return this.SendReceiveString(sSend, sMult);
466 }
467 catch (ApplicationException exception)
468 {
469 // The writer lock request timed out.
470 //TODO: Remark: to writer lock for Transmit RPC
471 Debug.Write("TransmitRPC writer lock request timed out.\n");
472 throw exception;
473 }
474 catch (Exception problem)
475 {
476 throw problem;
477 }
478 }
479
480
481 public abstract string GetLoginFacility(String aDuz);
482
483
484 #endregion RPX Functions
485
486 protected void AssertConnected()
487 {
488 if (!this.IsConnected)
489 {
490 throw new BMXNetException("BMXNetBroker.TransmitRPC failed because BMXNetBroker is not connected to RPMS.");
491 }
492 }
493
494 private String _job = "";
495
496 public String Job
497 {
498 get { return _job; }
499 set { _job = value; }
500 }
501
502 /// <summary>
503 /// Gets/sets the Kernel Application context
504 /// Throws an exception if unable to set the context.
505 /// </summary>
506 public string AppContext
507 {
508 get
509 {
510 return m_cAppContext;
511 }
512 set
513 {
514 if (m_cAppContext == value)
515 return;
516
517 //Send the changed context to RPMS
518 if ((value != null) && (value != ""))
519 {
520 string encryptedContext = this.EncryptionProvider.Encrypt(value);
521 string sAuthentication = this.TransmitRPC("BMX CREATE CONTEXT", encryptedContext);
522
523 if (BMXNetBroker.FindSubString(sAuthentication, "does not have access to option") > -1)
524 {
525 throw new BMXNetException(sAuthentication);
526 }
527 if (BMXNetBroker.FindSubString(sAuthentication, "is not registered with port") > -1)
528 {
529 throw new BMXNetException(sAuthentication);
530 }
531 m_cAppContext = value;
532 }
533
534 }
535 }
536
537 public string DUZ
538 {
539 get
540 {
541 return m_cDUZ;
542 }
543 set { this.m_cDUZ = value; }
544 }
545
546 private EncryptionKeyProvider _keyProvider = null;
547
548 public EncryptionKeyProvider KeyProvider
549 {
550 get { return _keyProvider; }
551 set { _keyProvider = value; }
552 }
553
554
555 protected string RemoveADEEncryp(string sInput)
556 {
557 //Encrypt a string
558 string strResult = null;
559 string strPercent = null;
560 string strAssoc = null;
561 string strIdix = null;
562 int nPercent = 0;
563 int nAssocix = 0;
564 int nIdix = 0;
565 Debug.Assert(sInput != "");
566 System.Random rRand = new Random(DateTime.Now.Second);
567
568 nPercent = rRand.Next(0, 10000);
569 nPercent += 72439;
570 nAssocix = nPercent % 20;
571 nAssocix++;
572 Debug.Assert(nAssocix < 21);
573 strPercent = nPercent.ToString();
574 strPercent = strPercent.Substring(1, 2);
575 nIdix = Convert.ToInt32(strPercent);
576 nIdix = nIdix % 20;
577 nIdix++;
578 Debug.Assert(nIdix < 21);
579
580 Debug.Assert(strAssoc.Length == 94);
581 Debug.Assert(strIdix.Length == 94);
582 string sEncrypted = "";
583
584 foreach (char c in sInput)
585 {
586 string d = c.ToString();
587 int nFindChar = strIdix.IndexOf(c);
588 if (nFindChar > -1)
589 {
590 d = strAssoc.Substring(nFindChar, 1);
591 }
592 sEncrypted += d;
593 }
594
595 strResult = (char)(nIdix + 31) + sEncrypted + (char)(nAssocix + 31);
596
597 return strResult;
598 }
599
600
601 protected string RemoveLoadKey(int nID)
602 {
603 nID -= 102;
604 Debug.Assert(nID < 20);
605 return this.KeyProvider.Keys[nID];
606 }
607
608
609 internal string RemoveADEDecryp(string sInput)
610 {
611 //Encrypt a string
612 string strAssoc = null;
613 string strIdix = null;
614 int nAssocix;
615 int nIdix;
616 Debug.Assert(sInput != "");
617
618 //get associator string index
619 char cAssocix = sInput[sInput.Length - 1];
620 nAssocix = (int)cAssocix;
621 nAssocix -= 31;
622 Debug.Assert(nAssocix < 21);
623
624 //get identifier string index
625 char cIdix = sInput[0];
626 nIdix = (int)cIdix;
627 nIdix -= 31;
628 Debug.Assert(nIdix < 21);
629
630 //get associator string
631 Debug.Assert(strAssoc.Length == 94);
632 Debug.Assert(strIdix.Length == 94);
633
634 //translated result
635 string sDecrypted = "";
636 sInput = sInput.Substring(1, sInput.Length - 2);
637 foreach (char c in sInput)
638 {
639 string d = c.ToString();
640 int nFindChar = strAssoc.IndexOf(c);
641 if (nFindChar > -1)
642 {
643 d = strIdix.Substring(nFindChar, 1);
644 }
645 sDecrypted += d;
646 }
647
648 return sDecrypted;
649 }
650
651 internal string RemoveBMXEncrypt(string sInput)
652 {
653
654 ASCIIEncoding textConverter = new ASCIIEncoding();
655 RijndaelManaged myRijndael = new RijndaelManaged();
656 byte[] encrypted;
657 byte[] toEncrypt;
658 byte[] key;
659 byte[] IV;
660
661 string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz";
662 string sIV = "Gichin Funakoshi";
663 key = textConverter.GetBytes(sKey);
664 IV = textConverter.GetBytes(sIV);
665
666 //Get an encryptor.
667 ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
668
669 //Encrypt the data.
670 MemoryStream msEncrypt = new MemoryStream();
671 CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
672
673 //Convert the input data to a byte array.
674 toEncrypt = textConverter.GetBytes(sInput);
675
676 //Write all data to the crypto stream and flush it.
677 csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
678 csEncrypt.FlushFinalBlock();
679
680 //Get encrypted array of bytes.
681 encrypted = msEncrypt.ToArray();
682
683 //Convert to string to send to RPMS
684 string sEncrypted = "";
685 byte bTmp;
686 string sTmp;
687 for (int j = 0; j < encrypted.Length; j++)
688 {
689 bTmp = encrypted[j];
690 sTmp = bTmp.ToString();
691 sEncrypted += sTmp;
692 if (j < (encrypted.Length - 1))
693 sEncrypted += "~";
694 }
695 return sEncrypted;
696 }
697
698 internal string BMXDecrypt(string sInput)
699 {
700 try
701 {
702 byte[] fromEncrypt;
703 ASCIIEncoding textConverter = new ASCIIEncoding();
704 RijndaelManaged myRijndael = new RijndaelManaged();
705 string sRPMSEncrypted = sInput;
706 string sBar = "~";
707 char[] cBar = sBar.ToCharArray();
708 string[] sArray;
709 sArray = sRPMSEncrypted.Split(cBar);
710 byte[] bRPMSEncrypted = new byte[sArray.GetLength(0)];
711 byte[] key;
712 byte[] IV;
713
714 //Convert the RPMS-stored string to a byte array
715 for (int j = 0; j < sArray.GetLength(0); j++)
716 {
717 bRPMSEncrypted[j] = Byte.Parse(sArray[j]);
718 }
719
720 //Get a decryptor that uses the same key and IV as the encryptor.
721 string sKey = "pouphfoz sfdbqjuvmbwft qizmphfoz";
722 string sIV = "Gichin Funakoshi";
723 key = textConverter.GetBytes(sKey);
724 IV = textConverter.GetBytes(sIV);
725 ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
726
727 MemoryStream msDecrypt = new MemoryStream(bRPMSEncrypted);
728 CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
729
730 fromEncrypt = new byte[bRPMSEncrypted.Length - 2];
731
732 //Read the data out of the crypto stream.
733 csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
734
735 int nZ = FindChar(fromEncrypt, (char)0);
736
737 //Convert the byte array back into a string.
738 string sResult;
739 if (nZ < 0)
740 {
741 sResult = textConverter.GetString(fromEncrypt);
742 }
743 else
744 {
745 sResult = textConverter.GetString(fromEncrypt, 0, nZ);
746 }
747 return sResult;
748 }
749 catch (Exception ex)
750 {
751 Debug.Write(ex.Message);
752 return "";
753 }
754 }
755
756
757 private String _userName = null;
758
759 public String UserName
760 {
761 get {
762 if (_userName == null)
763 {
764 this._userName = this.TransmitRPC("BMX USER", this.DUZ);
765 }
766
767 return _userName; }
768 set { _userName = value; }
769 }
770 }
771}
Note: See TracBrowser for help on using the repository browser.