1 //---------------------------------------------------------------------------
2 //
3 // Notes for RELAY-NET-V5.7 LAN 8 channel relay and binary input card.
4 //
5 // Hard reset: Hold reset button and power until, after about 10 seconds, one
6 // of the green LEDS starts to flash to hard reset the relay card
7 //
8 // After Hard Reset:
9 // IpAddress = 192.168.1.166
10 // Username = admin
11 // Password = 12345678
12 //
13 // Connect to it from a browser, type HTTP://192.168.1.166 in the bar.
14 // Make sure you computer has access to the subnet.
15 //
16 // Relay-Net-V5.7 card settings:
17 //
18 // To use Inputs set scene settings to all "xxxxxxxx" for all inputs. This
19 // give full control of the relays and inputs to domoticz.
20 //
21 // Password does not matter when only TCP traffic is used.
22 // When HTTP is used then username / password setting on the module and domoticz must match.
23 // After init the is user:admin /password:12345678
24 //
25 // Select power down save
26 // Deselect Input output correlation
27 // Deselect scene mode
28 // Select touch input
29 //
30 // Make sure TCP address and port match domoticz settings (example addr:192.168.2.241 port:17494)
31 // Set HTTP port to 80 so you can access the module from your browser.
32 // If you have multiple modules make sure mac address settings are unique.
33 // Set Default Gateway, Primary & Secondary DNS server to 0.0.0.0 in most cases.
34 //
35 // To test the card using Linux curl:
36 // Turn relay1 on: curl --basic --user admin:12345678 --silent --data "saida1on=on"
37 // Turn relay1 off: curl --basic --user admin:12345678 --silent --data "saida1off=off"
38 // Pulse relay1 on: curl --basic --user admin:12345678 --silent --data "saida1pluse=pluse"
39 // (firmware pulse -> pluse)
40 //
41 // Relays: saida1..saida8 ~ relay1..relay8
42 // saida9 = ALL off, on or pluse
43 //
44 // TCP command examples:
45 // L1\r\n Turn on relay 1
46 // LA\r\n Turn on all relays
47 // D1\r\n Turn off relay1
48 // DA\r\n Turn off all relays
49 // P1\r\n Pulse relay 1
50 // R1\r\n Read state relay1
51 // DUMP\r\n Read state of all relays and all inputs
52 //
53 // setr00000001\r\n set all relays in one go
54 // getr\r\n get status of all relays in one go (result getr00000001)
55 //
56 // Using scenes (we disable this by putting all xxxxxxxx)
57 //
58 // INON=?\r\n
59 // result:
60 // INON1 = xxxxxxxx\r\n
61 // INON2 = xxxxxxxx\r\n
62 // INON3 = xxxxxxxx\r\n
63 // INON4 = xxxxxxxx\r\n
64 // INON5 = xxxxxxxx\r\n
65 // INON6 = xxxxxxxx\r\n
66 // INON7 = xxxxxxxx\r\n
67 // INON8 = xxxxxxxx\r\n
68 //
69 // INOFF=?\r\n
70 // result:
71 // INOFF1 = xxxxxxxx\r\n
72 // INOFF2 = xxxxxxxx\r\n
73 // INOFF3 = xxxxxxxx\r\n
74 // INOFF4 = xxxxxxxx\r\n
75 // INOFF5 = xxxxxxxx\r\n
76 // INOFF6 = xxxxxxxx\r\n
77 // INOFF7 = xxxxxxxx\r\n
78 // INOFF8 = xxxxxxxx\r\n
79 //
80 // INON1 = xxxxxxxx\r\n scene 1 ON part
81 // result:
82 // INON1 = xxxxxxxx\r\n
83 //
84 // INOFF1 = xxxxxxxx\r\n scene 1 OFF part
85 // result:
86 // INOFF1 = xxxxxxxx\r\n
87 //
88 // RESTART\r\n restart controller, takes 60 seconds before controller becomes responsive
89 //
90 // Wifi ESP8266 Relay Module 10A Network Relay
91 //
92 //---------------------------------------------------------------------------
93 #include "stdafx.h"
94 #include "RelayNet.h"
95 #include "hardwaretypes.h"
96 #include "ASyncTCP.h"
97 #include "../main/Helper.h"
98 #include "../main/Logger.h"
99 #include "../main/localtime_r.h"
100 #include "../main/mainworker.h"
101 #include "../main/SQLHelper.h"
102 #include "../webserver/Base64.h"
103 #include "../httpclient/HTTPClient.h"
104 #include <sstream>
105
106 //===========================================================================
107
108 #define RELAYNET_USE_HTTP false
109 #define RELAYNET_POLL_INPUTS true
110 #define RELAYNET_POLL_RELAYS true
111 #define RELAYNET_MIN_POLL_INTERVAL 1
112 #define MAX_INPUT_COUNT 64
113 #define MAX_RELAY_COUNT 64
114 #define KEEP_ALIVE_INTERVAL 10
115 #define RETRY_DELAY 30
116
117 //===========================================================================
118
RelayNet(const int ID,const std::string & IPAddress,const unsigned short usIPPort,const std::string & username,const std::string & password,const bool pollInputs,const bool pollRelays,const int pollInterval,const int inputCount,const int relayCount)119 RelayNet::RelayNet(const int ID, const std::string &IPAddress, const unsigned short usIPPort, const std::string &username, const std::string &password, const bool pollInputs, const bool pollRelays, const int pollInterval, const int inputCount, const int relayCount) :
120 m_szIPAddress(IPAddress),
121 m_username(CURLEncode::URLEncode(username)),
122 m_password(CURLEncode::URLEncode(password))
123 {
124 m_setup_devices = true;
125 m_bOutputLog = false;
126 m_bIsStarted = false;
127 m_HwdID = ID;
128 m_usIPPort = usIPPort;
129 m_poll_inputs = pollInputs;
130 m_poll_relays = pollRelays;
131 m_input_count = inputCount;
132 m_relay_count = relayCount;
133 m_poll_interval = pollInterval;
134 m_skip_relay_update = 0;
135 m_retrycntr = 0;
136
137 if (inputCount == 0)
138 {
139 m_poll_inputs = false;
140 }
141
142 if (relayCount == 0)
143 {
144 m_poll_relays = false;
145 }
146
147 if (pollInterval < RELAYNET_MIN_POLL_INTERVAL)
148 {
149 m_poll_interval = RELAYNET_MIN_POLL_INTERVAL;
150 }
151 }
152
153 //===========================================================================
154
~RelayNet(void)155 RelayNet::~RelayNet(void)
156 {
157 }
158
159 //===========================================================================
160
StartHardware()161 bool RelayNet::StartHardware()
162 {
163 RequestStart();
164
165 bool bOk = false;;
166 m_bIsStarted = false;
167 m_setup_devices = false;
168 m_bIsStarted = false;
169 m_retrycntr = RETRY_DELAY; //force connect the next first time
170
171 if (m_input_count || m_relay_count)
172 {
173 m_thread = std::make_shared<std::thread>(&RelayNet::Do_Work, this);
174 SetThreadNameInt(m_thread->native_handle());
175 }
176
177 if (m_thread)
178 {
179 bOk = true;
180 m_bIsStarted=true;
181 }
182
183 return bOk;
184 }
185
186 //===========================================================================
187
StopHardware()188 bool RelayNet::StopHardware()
189 {
190 if (m_thread)
191 {
192 RequestStop();
193 m_thread->join();
194 m_thread.reset();
195 }
196 m_bIsStarted = false;
197 _log.Log(LOG_STATUS, "RelayNet: Relay Module disconnected %s", m_szIPAddress.c_str());
198
199 return true;
200 }
201
202 //===========================================================================
203
WriteToHardware(const char * pdata,const unsigned char length)204 bool RelayNet::WriteToHardware(const char *pdata, const unsigned char length)
205 {
206 #if RELAYNET_USE_HTTP
207 return WriteToHardwareHttp(pdata);
208 #else
209 return WriteToHardwareTcp(pdata);
210 #endif
211 }
212
213 //===========================================================================
214
Do_Work()215 void RelayNet::Do_Work()
216 {
217 int sec_counter = 0;
218
219 /* Init */
220 Init();
221
222 if (m_poll_inputs || m_poll_relays)
223 {
224 _log.Log(LOG_STATUS, "RelayNet: %d-second poller started (%s)", m_poll_interval, m_szIPAddress.c_str());
225 }
226 connect(m_szIPAddress,m_usIPPort);
227 /* One second sleep */
228 while (!IsStopRequested(1000))
229 {
230 sec_counter++;
231
232 /* Heartbeat maintenance */
233 if (sec_counter % 10 == 0)
234 {
235 m_LastHeartbeat = mytime(NULL);
236 }
237
238 /* Prevent disconnect request by Relay Module */
239 if ((sec_counter % KEEP_ALIVE_INTERVAL == 0) &&
240 ((m_poll_interval > KEEP_ALIVE_INTERVAL) || (!m_poll_inputs && !m_poll_relays)))
241 {
242 KeepConnectionAlive();
243 }
244
245 /* Update relay module status when poll interval has expired */
246 if ((m_poll_inputs || m_poll_relays) && (sec_counter % m_poll_interval == 0))
247 {
248 TcpRequestRelaycardDump();
249 }
250 }
251 terminate();
252
253 /* Done */
254 if (m_poll_inputs || m_poll_relays)
255 {
256 _log.Log(LOG_STATUS, "RelayNet: %d-second poller stopped (%s)", m_poll_interval, m_szIPAddress.c_str());
257 }
258 }
259
260 //===========================================================================
261
Init()262 void RelayNet::Init()
263 {
264 BYTE id1 = 0x03;
265 BYTE id2 = 0x0E;
266 BYTE id3 = 0x0E;
267 BYTE id4 = m_HwdID & 0xFF;
268
269 /* Prepare packet for LIGHTING2 relay status packet */
270 memset(&m_Packet, 0, sizeof(m_Packet));
271
272 if (m_HwdID > 0xFF)
273 {
274 id3 = (m_HwdID >> 8) & 0xFF;
275 }
276
277 if (m_HwdID > 0xFFFF)
278 {
279 id3 = (m_HwdID >> 16) & 0xFF;
280 }
281
282 m_Packet.LIGHTING2.packetlength = sizeof(m_Packet.LIGHTING2) - 1;
283 m_Packet.LIGHTING2.packettype = pTypeLighting2;
284 m_Packet.LIGHTING2.subtype = sTypeAC;
285 m_Packet.LIGHTING2.unitcode = 0;
286 m_Packet.LIGHTING2.id1 = id1;
287 m_Packet.LIGHTING2.id2 = id2;
288 m_Packet.LIGHTING2.id3 = id3;
289 m_Packet.LIGHTING2.id4 = id4;
290 m_Packet.LIGHTING2.cmnd = 0;
291 m_Packet.LIGHTING2.level = 0;
292 m_Packet.LIGHTING2.filler = 0;
293 m_Packet.LIGHTING2.rssi = 12;
294
295 SetupDevices();
296 }
297
298 //===========================================================================
299
SetupDevices()300 void RelayNet::SetupDevices()
301 {
302 std::vector<std::vector<std::string> > result;
303 char szIdx[10];
304
305 sprintf(szIdx, "%X%02X%02X%02X",
306 m_Packet.LIGHTING2.id1,
307 m_Packet.LIGHTING2.id2,
308 m_Packet.LIGHTING2.id3,
309 m_Packet.LIGHTING2.id4);
310
311 if (m_relay_count)
312 {
313 for (int relayNumber = 1; relayNumber <= m_relay_count; relayNumber++)
314 {
315 result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit==%d)", m_HwdID, szIdx, relayNumber);
316
317 if (result.empty())
318 {
319 _log.Log(LOG_STATUS, "RelayNet: Create %s/Relay%i", m_szIPAddress.c_str(), relayNumber);
320
321 m_sql.InsertDevice(m_HwdID, szIdx, relayNumber, pTypeLighting2, sTypeAC, STYPE_OnOff, 0, " ", "Relay");
322 }
323 }
324 }
325
326 if (m_input_count)
327 {
328 for (int inputNumber = 1; inputNumber <= m_input_count; inputNumber++)
329 {
330 result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit==%d)", m_HwdID, szIdx, 100 + inputNumber);
331
332 if (result.empty())
333 {
334 _log.Log(LOG_STATUS, "RelayNet: Create %s/Input%i", m_szIPAddress.c_str(), inputNumber);
335
336 m_sql.InsertDevice(m_HwdID, szIdx, 100 + inputNumber, pTypeLighting2, sTypeAC, int(STYPE_Contact), 0, " ", "Input");
337 }
338 }
339 }
340 }
341
342 //===========================================================================
343
TcpRequestRelaycardDump()344 void RelayNet::TcpRequestRelaycardDump()
345 {
346 std::string sRequest = "DUMP\r\n";
347
348 write(sRequest);
349 }
350
351 //===========================================================================
352
KeepConnectionAlive()353 void RelayNet::KeepConnectionAlive()
354 {
355 std::string sRequest = "R1\r\n";
356
357 write(sRequest);
358 }
359
360 //===========================================================================
361
TcpGetSetRelay(int RelayNumber,bool SetRelay,bool State)362 void RelayNet::TcpGetSetRelay(int RelayNumber, bool SetRelay, bool State)
363 {
364 char sndbuf[4];
365
366 if (SetRelay)
367 {
368 if (State)
369 {
370 sndbuf[0] = 'L'; // Turn relay on & get status
371 }
372 else
373 {
374 sndbuf[0] = 'D'; // Turn relay off & get status
375 }
376 }
377 else
378 {
379 sndbuf[0] = 'R'; // Get relay status
380 }
381
382 sndbuf[1] = 0x30 + (char) RelayNumber;
383 sndbuf[2] = '\r';
384 sndbuf[3] = '\n';
385
386 write((const unsigned char*)&sndbuf[0], (size_t) sizeof(sndbuf));
387 }
388
SetRelayState(int RelayNumber,bool State)389 void RelayNet::SetRelayState(int RelayNumber, bool State)
390 {
391 TcpGetSetRelay(RelayNumber, true, State);
392
393 if (m_poll_relays)
394 {
395 m_skip_relay_update++;
396 }
397 }
398
399 //===========================================================================
400
WriteToHardwareTcp(const char * pdata)401 bool RelayNet::WriteToHardwareTcp(const char *pdata)
402 {
403 bool bOk = true;
404
405 const tRBUF *pSen = reinterpret_cast<const tRBUF*>(pdata);
406 unsigned char packettype = pSen->ICMND.packettype;
407
408 if (packettype == pTypeLighting2)
409 {
410 int relay = pSen->LIGHTING2.unitcode;
411
412 if ((relay >= 1) && (relay <= m_relay_count))
413 {
414 if (pSen->LIGHTING2.cmnd == light2_sOn)
415 {
416 SetRelayState(relay, true);
417 }
418 else
419 {
420 SetRelayState(relay, false);
421 }
422 }
423 else
424 {
425 bOk = false;
426 }
427 }
428
429 return bOk;
430 }
431
432 //===========================================================================
433
UpdateDomoticzInput(int InputNumber,bool State)434 void RelayNet::UpdateDomoticzInput(int InputNumber, bool State)
435 {
436 bool updateDatabase = false;
437 std::vector<std::vector<std::string> > result;
438 char szIdx[10];
439
440 sprintf(szIdx, "%X%02X%02X%02X",
441 m_Packet.LIGHTING2.id1,
442 m_Packet.LIGHTING2.id2,
443 m_Packet.LIGHTING2.id3,
444 m_Packet.LIGHTING2.id4);
445
446 result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit==%d)", m_HwdID, szIdx, 100 + InputNumber);
447
448 if ((!result.empty()) && (result.size()>0))
449 {
450 std::vector<std::string> sd=result[0];
451 bool dbState = true;
452
453 if (atoi(sd[1].c_str()) == 0)
454 {
455 dbState = false;
456 }
457
458 if (dbState != State)
459 {
460 updateDatabase = true;
461 }
462 }
463
464 if (updateDatabase)
465 {
466 if (State)
467 {
468 m_Packet.LIGHTING2.cmnd = light2_sOn;
469 m_Packet.LIGHTING2.level = 100;
470 }
471 else
472 {
473 m_Packet.LIGHTING2.cmnd = light2_sOff;
474 m_Packet.LIGHTING2.level = 0;
475 }
476 m_Packet.LIGHTING2.unitcode = 100 + (char) InputNumber;
477 m_Packet.LIGHTING2.seqnbr++;
478
479 /* send packet to Domoticz */
480 sDecodeRXMessage(this, (const unsigned char *)&m_Packet.LIGHTING2, "Input", 255);
481 }
482 }
483
484 //===========================================================================
485
UpdateDomoticzRelay(int RelayNumber,bool State)486 void RelayNet::UpdateDomoticzRelay(int RelayNumber, bool State)
487 {
488 bool updateDatabase = false;
489 std::vector<std::vector<std::string> > result;
490 char szIdx[10];
491
492 sprintf(szIdx, "%X%02X%02X%02X",
493 m_Packet.LIGHTING2.id1,
494 m_Packet.LIGHTING2.id2,
495 m_Packet.LIGHTING2.id3,
496 m_Packet.LIGHTING2.id4);
497
498 result = m_sql.safe_query("SELECT Name,nValue,sValue FROM DeviceStatus WHERE (HardwareID==%d) AND (DeviceID=='%q') AND (Unit==%d)", m_HwdID, szIdx, RelayNumber);
499
500 if ((!result.empty()) && (result.size()>0))
501 {
502 std::vector<std::string> sd = result[0];
503 bool dbState = true;
504
505 if (atoi(sd[1].c_str()) == 0)
506 {
507 dbState = false;
508 }
509
510 if (dbState != State)
511 {
512 updateDatabase = true;
513 }
514 }
515
516 if (updateDatabase)
517 {
518 if (State)
519 {
520 m_Packet.LIGHTING2.cmnd = light2_sOn;
521 m_Packet.LIGHTING2.level = 100;
522 }
523 else
524 {
525 m_Packet.LIGHTING2.cmnd = light2_sOff;
526 m_Packet.LIGHTING2.level = 0;
527 }
528 m_Packet.LIGHTING2.unitcode = (char) RelayNumber;
529 m_Packet.LIGHTING2.seqnbr++;
530
531 /* send packet to Domoticz */
532 sDecodeRXMessage(this, (const unsigned char *)&m_Packet.LIGHTING2, "Relay", 255);
533 }
534 }
535
536 //===========================================================================
537
ProcessRelaycardDump(char * Dump)538 void RelayNet::ProcessRelaycardDump(char* Dump)
539 {
540 char cTemp[16];
541 std::string sDump;
542 std::string sChkstr;
543
544 sDump = Dump;
545 boost::to_upper(sDump);
546
547 if (!m_skip_relay_update && m_relay_count && (m_poll_relays || m_setup_devices))
548 {
549 for (uint16_t i=1; i <= m_relay_count ; i++)
550 {
551 snprintf(&cTemp[0], sizeof(cTemp), "RELAYON %d", i);
552 sChkstr = cTemp;
553
554 if(sDump.find(sChkstr) != std::string::npos)
555 {
556 UpdateDomoticzRelay(i, true);
557 }
558
559 snprintf(&cTemp[0], sizeof(cTemp), "RELAYOFF %d", i);
560 sChkstr = cTemp;
561
562 if (sDump.find(sChkstr) != std::string::npos)
563 {
564 UpdateDomoticzRelay(i, false);
565 }
566 }
567 }
568
569 if (m_input_count && (m_poll_inputs || m_setup_devices))
570 {
571 for (uint16_t i = 1; i <= m_input_count; i++)
572 {
573 snprintf(&cTemp[0], sizeof(cTemp), "IH %d", i);
574 sChkstr = cTemp;
575
576 if (sDump.find(sChkstr) != std::string::npos)
577 {
578 UpdateDomoticzInput(i, true);
579 }
580
581 snprintf(&cTemp[0], sizeof(cTemp), "IL %d", i);
582 sChkstr = cTemp;
583
584 if (sDump.find(sChkstr) != std::string::npos)
585 {
586 UpdateDomoticzInput(i, false);
587 }
588 }
589 }
590
591 /* housekeeping */
592 m_setup_devices = false;
593
594 if (m_skip_relay_update)
595 {
596 m_skip_relay_update--;
597 }
598 }
599
600 //===========================================================================
601
ParseData(const unsigned char * pData,int Len)602 void RelayNet::ParseData(const unsigned char *pData, int Len)
603 {
604 char relayCardDump[512];
605
606 if ((Len > 64) && (Len <= sizeof(relayCardDump)))
607 {
608 /* Its a RelayCard dump message */
609 memset(&relayCardDump[0], 0, Len);
610 memcpy(&relayCardDump[0], pData, Len);
611 ProcessRelaycardDump(&relayCardDump[0]);
612 }
613 }
614
615 //===========================================================================
616 //
617 // Alternate way of turning relays on/off using HTTP.
618 // Currently not used.
619 //
WriteToHardwareHttp(const char * pdata)620 bool RelayNet::WriteToHardwareHttp(const char *pdata)
621 {
622 //-----------------------------------------------------------------------
623 //
624 // Notes:
625 //
626 // Use OpenSSL to manually create a base64 authorization string.
627 //
628 // Example:
629 // echo -n "admin:ok" | openssl base64 -base64
630 // Output generated: WRtaW46b2s=
631 //
632 // To use the string:
633 // std::string sAccessToken = "YWRtaW46b2s=";
634 //
635 //-----------------------------------------------------------------------
636
637 const tRBUF *pSen = reinterpret_cast<const tRBUF*>(pdata);
638 unsigned char packettype = pSen->ICMND.packettype;
639
640 if (packettype == pTypeLighting2)
641 {
642 std::stringstream sRelayCommand;
643 std::stringstream sLogin;
644 std::string sAccessToken;
645 std::stringstream sURL;
646 std::vector<std::string> ExtraHeaders;
647 std::string sResult;
648 int relay = pSen->LIGHTING2.unitcode;
649
650 if ((relay >= 1) && (relay <= m_relay_count))
651 {
652 if (pSen->LIGHTING2.cmnd == light2_sOff)
653 {
654 sRelayCommand << "saida" << relay << "off=off";
655 }
656 else
657 {
658 sRelayCommand << "saida" << relay << "on=on";
659 }
660
661 /* Setup URL, relay-command and username/password */
662 std::string sPostData = sRelayCommand.str();
663 sURL << "http://" << m_szIPAddress << "/relay_en.cgi";
664 sLogin << m_username << ":" << m_password;
665
666 /* Generate UnEncrypted base64 Basic Authorization for username/password and add result to ExtraHeaders */
667 sAccessToken = base64_encode(sLogin.str());
668 ExtraHeaders.push_back("Authorization: Basic " + sAccessToken);
669
670 /* Send URL to relay module and check return status */
671 if (!HTTPClient::POST(sURL.str(), sPostData, ExtraHeaders, sResult))
672 {
673 _log.Log(LOG_ERROR, "RelayNet: [1] Error sending relay command to: %s", m_szIPAddress.c_str());
674 return false;
675 }
676
677 /* Look for "saida" in response, if present all should be ok */
678 if (sResult.find("saida") == std::string::npos)
679 {
680 _log.Log(LOG_ERROR, "RelayNet: [2] Error sending relay command to: %s", m_szIPAddress.c_str());
681 return false;
682 }
683
684 return true;
685 }
686 }
687
688 return false;
689 }
690
691 //===========================================================================
692 //
693 // ASyncTCP support
694 //
OnConnect()695 void RelayNet::OnConnect()
696 {
697 _log.Log(LOG_STATUS, "RelayNet: Connected to Relay Module %s", m_szIPAddress.c_str());
698 m_bIsStarted = true;
699 }
700
701 //===========================================================================
702
OnDisconnect()703 void RelayNet::OnDisconnect()
704 {
705 _log.Log(LOG_STATUS, "RelayNet: Relay Module disconnected %s, reconnect", m_szIPAddress.c_str());
706 }
707
708 //===========================================================================
709
OnData(const unsigned char * pData,size_t length)710 void RelayNet::OnData(const unsigned char *pData, size_t length)
711 {
712 ParseData(pData, length);
713 }
714
715 //===========================================================================
716
OnError(const boost::system::error_code & error)717 void RelayNet::OnError(const boost::system::error_code& error)
718 {
719 if ((error == boost::asio::error::address_in_use) ||
720 (error == boost::asio::error::connection_refused) ||
721 (error == boost::asio::error::access_denied) ||
722 (error == boost::asio::error::host_unreachable) ||
723 (error == boost::asio::error::timed_out))
724 {
725 _log.Log(LOG_ERROR, "RelayNet: OnError: Can not connect to: %s:%d", m_szIPAddress.c_str(), m_usIPPort);
726 }
727 else if ((error == boost::asio::error::eof) || (error == boost::asio::error::connection_reset))
728 {
729 _log.Log(LOG_STATUS, "RelayNet: OnError: Connection reset!");
730 }
731 else
732 {
733 _log.Log(LOG_ERROR, "RelayNet: OnError: %s", error.message().c_str());
734 }
735 }
736
737 //===========================================================================
738