/** * Confine all interactions with ActiveX controls to this thread * Other threads access this thread by adding IMessages to the work_queue * and should monitor the http_mailbox for responses */ public void DeviceLoop() { Console.WriteLine("Starting device thread: " + Thread.CurrentThread.ManagedThreadId); this.ReInitDevice(); while (true) { var msg = this.work_queue.Take(); if (msg.type() == "simple") { this.ProcessUdpMessage(msg.body()); } else if (msg.type() == "emv") { string result = emv_ax_control.ProcessTransaction(msg.body()); if (msg.from() == "http") { this.http_mailbox.Add(result); } } else if (msg.type() == "pdc") { string result = pdc_ax_control.ProcessTransaction(msg.body(), 1, null, null); if (msg.from() == "http") { this.http_mailbox.Add(result); } } } }
/** * Process XML transaction using dsiPDCX */ protected string ProcessEMV(string xml) { /* * Substitute values into the XML request * This is so the driver can handle any change * in which hardware device is connected as well * as so tracking SequenceNo values is not POS' * problem. */ xml = xml.Trim(new char[] { '"' }); xml = xml.Replace("{{SequenceNo}}", SequenceNo()); if (IsCanadianDeviceType(this.device_identifier)) { // tag name is different in this case; // replace placeholder then the open/close tags xml = xml.Replace("{{SecureDevice}}", this.device_identifier); xml = xml.Replace("SecureDevice", "PadType"); } else { xml = xml.Replace("{{SecureDevice}}", SecureDeviceToEmvType(this.device_identifier)); } xml = xml.Replace("{{ComPort}}", com_port); if (this.verbose_mode > 0) { Console.WriteLine(xml); } if (log_xml) { using (StreamWriter file = new StreamWriter("log.xml", true)) { file.WriteLine(xml); } } string result = emv_ax_control.ProcessTransaction(xml); // track SequenceNo values in responses XmlDocument doc = new XmlDocument(); try { doc.LoadXml(result); XmlNode sequence = doc.SelectSingleNode("RStream/CmdResponse/SequenceNo"); sequence_no = sequence.Value; } catch (Exception ex) { if (this.verbose_mode > 0) { Console.WriteLine(ex); } } return(result); }
/** * Process XML transaction using dsiPDCX * @param xml the request body * @param autoReset true if the request requires a reset, false if the request IS a reset */ protected string ProcessEMV(string xml, bool autoReset) { /* * Substitute values into the XML request * This is so the driver can handle any change * in which hardware device is connected as well * as so tracking SequenceNo values is not POS' * problem. */ xml = xml.Trim(new char[] { '"' }); xml = xml.Replace("{{SequenceNo}}", SequenceNo()); if (IsCanadianDeviceType(this.device_identifier)) { // tag name is different in this case; // replace placeholder then the open/close tags xml = xml.Replace("{{SecureDevice}}", this.device_identifier); xml = xml.Replace("SecureDevice", "PadType"); } else { xml = xml.Replace("{{SecureDevice}}", SecureDeviceToEmvType(this.device_identifier)); } xml = xml.Replace("{{ComPort}}", com_port); if (this.terminalID.Length > 0) { xml = xml.Replace("{{TerminalID}}", this.terminalID); } try { /** * Extract HostOrIP field and split it on commas * to allow multiple IPs */ XmlDocument request = new XmlDocument(); request.LoadXml(xml); var IPs = request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string result = ""; foreach (string IP in IPs) { // try request with an IP // If this is NOT a pad reset request, check the emv_reset // flag to see if a reset is needed. If so, execute one // and update the flag if (autoReset) { FlaggedReset(); } lock (emvLock) { emv_active = true; } request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml = IP; result = emv_ax_control.ProcessTransaction(request.OuterXml); lock (emvLock) { emv_active = false; // if this is not a reset command, set the reset needed flag if (autoReset) { emv_reset = true; } } if (enable_xml_log) { using (StreamWriter sw = new StreamWriter(xml_log, true)) { sw.WriteLine(DateTime.Now.ToString() + " (send emv): " + request.OuterXml); sw.WriteLine(DateTime.Now.ToString() + " (recv emv): " + result); } } XmlDocument doc = new XmlDocument(); try { doc.LoadXml(result); // track SequenceNo values in responses XmlNode sequence = doc.SelectSingleNode("RStream/CmdResponse/SequenceNo"); sequence_no = sequence.InnerXml; XmlNode return_code = doc.SelectSingleNode("RStream/CmdResponse/DSIXReturnCode"); XmlNode origin = doc.SelectSingleNode("RStream/CmdResponse/ResponseOrigin"); /** * On anything that is not a local connectivity failure, exit the * loop and return the result without trying any further IPs. */ if (origin.InnerXml != "Client" || return_code.InnerXml != "003006") { break; } } catch (Exception ex) { // response was invalid xml this.LogMessage(ex.ToString()); // status is unclear so do not attempt // another transaction break; } } if (autoReset && this.always_reset) { FlaggedReset(); } return(result); } catch (Exception ex) { // request was invalid xml this.LogMessage(ex.ToString()); } return(""); }
/** * Process XML transaction using dsiPDCX * @param xml the request body * @param autoReset true if the request requires a reset, false if the request IS a reset */ protected string ProcessEMV(string xml, bool autoReset) { /* * Substitute values into the XML request * This is so the driver can handle any change * in which hardware device is connected as well * as so tracking SequenceNo values is not POS' * problem. */ xml = xml.Replace("{{SequenceNo}}", SequenceNo()); if (IsCanadianDeviceType(this.device_identifier)) { // tag name is different in this case; // replace placeholder then the open/close tags xml = xml.Replace("{{SecureDevice}}", this.device_identifier); xml = xml.Replace("SecureDevice", "PadType"); } else { xml = xml.Replace("{{SecureDevice}}", SecureDeviceToEmvType(this.device_identifier)); } xml = xml.Replace("{{ComPort}}", com_port); if (this.terminalID.Length > 0) { xml = xml.Replace("{{TerminalID}}", this.terminalID); } if (this.device_ip.Length > 0) { xml = xml.Replace("<ComPort>1</ComPort>", "<ComPort>1</ComPort><PinPadIpAddress>" + this.device_ip + "</PinPadIpAddress><PinPadIpPort>12000</PinPadIpPort>"); } try { /** * Extract HostOrIP field and split it on commas * to allow multiple IPs */ XmlDocument request = new XmlDocument(); request.LoadXml(xml); var IPs = request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (this.reverse_servers) { Array.Reverse(IPs); } string result = ""; foreach (string IP in IPs) { // try request with an IP // If this is NOT a pad reset request, check the emv_reset // flag to see if a reset is needed. If so, execute one // and update the flag if (autoReset) { FlaggedReset(); } lock (emvLock) { emv_active = true; } request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml = IP; result = emv_ax_control.ProcessTransaction(request.OuterXml); lock (emvLock) { emv_active = false; // if this is not a reset command, set the reset needed flag if (autoReset) { emv_reset = true; } } if (enable_xml_log) { using (StreamWriter sw = new StreamWriter(xml_log, true)) { sw.WriteLine(DateTime.Now.ToString() + " (send emv): " + request.OuterXml); sw.WriteLine(DateTime.Now.ToString() + " (recv emv): " + result); } } XmlDocument doc = new XmlDocument(); try { doc.LoadXml(result); // track SequenceNo values in responses XmlNode sequence = doc.SelectSingleNode("RStream/CmdResponse/SequenceNo"); sequence_no = sequence.InnerXml; XmlNode return_code = doc.SelectSingleNode("RStream/CmdResponse/DSIXReturnCode"); XmlNode origin = doc.SelectSingleNode("RStream/CmdResponse/ResponseOrigin"); /** * On a client/3006 error or server/4003 error keep trying IPs. * Both indicate a network connectivity error that may just be * transient. * 003327 is a Com Port access error. May be transient in some cases. */ if (origin.InnerXml == "Client" && return_code.InnerXml == "003006") { this.LogMessage("Retry on client 3006 (epay: " + IP + ")"); this.reverse_servers = !this.reverse_servers; } else if (origin.InnerXml == "Client" && return_code.InnerXml == "003327") { this.LogMessage("Retry on client 3006 (COM error)"); Thread.Sleep(500); var new_port = this.PortSearch(this.device_identifier); if (new_port != "" && new_port != this.com_port && new_port.All(char.IsNumber)) { this.com_port = new_port; } } else if (origin.InnerXml == "Server" && return_code.InnerXml == "004003") { this.LogMessage("Retry on server 4003 (epay: " + IP + ")"); } else { break; } } catch (Exception ex) { // response was invalid xml this.LogMessage(ex.ToString()); // status is unclear so do not attempt // another transaction break; } } if (autoReset && this.always_reset) { FlaggedReset(); } return(result); } catch (Exception ex) { // request was invalid xml this.LogMessage(ex.ToString()); } return(""); }
/** * Process XML transaction using dsiPDCX */ protected string ProcessEMV(string xml) { /* * Substitute values into the XML request * This is so the driver can handle any change * in which hardware device is connected as well * as so tracking SequenceNo values is not POS' * problem. */ xml = xml.Trim(new char[] { '"' }); xml = xml.Replace("{{SequenceNo}}", SequenceNo()); if (IsCanadianDeviceType(this.device_identifier)) { // tag name is different in this case; // replace placeholder then the open/close tags xml = xml.Replace("{{SecureDevice}}", this.device_identifier); xml = xml.Replace("SecureDevice", "PadType"); } else { xml = xml.Replace("{{SecureDevice}}", SecureDeviceToEmvType(this.device_identifier)); } xml = xml.Replace("{{ComPort}}", com_port); if (this.verbose_mode > 0) { Console.WriteLine(xml); } if (log_xml) { using (StreamWriter file = new StreamWriter("log.xml", true)) { file.WriteLine(xml); } } try { /** * Extract HostOrIP field and split it on commas * to allow multiple IPs */ XmlDocument request = new XmlDocument(); request.LoadXml(xml); var IPs = request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml.Split(new Char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string result = ""; foreach (string IP in IPs) { // try request with an IP request.SelectSingleNode("TStream/Transaction/HostOrIP").InnerXml = IP; result = emv_ax_control.ProcessTransaction(request.OuterXml); XmlDocument doc = new XmlDocument(); try { doc.LoadXml(result); // track SequenceNo values in responses XmlNode sequence = doc.SelectSingleNode("RStream/CmdResponse/SequenceNo"); sequence_no = sequence.InnerXml; XmlNode return_code = doc.SelectSingleNode("RStream/CmdResponse/DSIXReturnCode"); XmlNode origin = doc.SelectSingleNode("RStream/CmdResponse/ResponseOrigin"); /** * On anything that is not a local connectivity failure, exit the * loop and return the result without trying any further IPs. */ if (origin.InnerXml != "Client" || return_code.InnerXml != "003006") { break; } } catch (Exception ex) { // response was invalid xml if (this.verbose_mode > 0) { Console.WriteLine(ex); } // status is unclear so do not attempt // another transaction break; } } return(result); } catch (Exception ex) { // request was invalid xml if (this.verbose_mode > 0) { Console.WriteLine(ex); } } return(""); }