OpenCPN Partial API docs
Loading...
Searching...
No Matches
comm_drv_n0183_net.cpp
1/***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: Implement comm_drv_n0183_net.h -- network nmea0183 driver
5 * Author: David Register, Alec Leamas
6 *
7 ***************************************************************************
8 * Copyright (C) 2022 by David Register, Alec Leamas *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26#ifdef __MINGW32__
27#undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
28#include <ws2tcpip.h>
29#include <windows.h>
30#endif
31
32#ifdef __MSVC__
33#include "winsock2.h"
34#include <wx/msw/winundef.h>
35#include <ws2tcpip.h>
36#endif
37
38#include <wx/wxprec.h>
39
40#ifndef WX_PRECOMP
41#include <wx/wx.h>
42#endif // precompiled headers
43
44#include <wx/tokenzr.h>
45#include <wx/datetime.h>
46
47#include <stdlib.h>
48#include <math.h>
49#include <time.h>
50
51#ifndef __WXMSW__
52#include <arpa/inet.h>
53#include <netinet/tcp.h>
54#endif
55
56#include <vector>
57#include <wx/socket.h>
58#include <wx/log.h>
59#include <wx/memory.h>
60#include <wx/chartype.h>
61#include <wx/wx.h>
62#include <wx/sckaddr.h>
63
64#include "garmin_protocol_mgr.h"
65
66#include "comm_drv_n0183_net.h"
67#include "comm_navmsg_bus.h"
68#include "idents.h"
69
70#define N_DOG_TIMEOUT 5
71
72// FIXME (dave) This should be in some more "common" space, but where?
73bool CheckSumCheck(const std::string &sentence) {
74 size_t check_start = sentence.find('*');
75 if (check_start == wxString::npos || check_start > sentence.size() - 3)
76 return false; // * not found, or it didn't have 2 characters following it.
77
78 std::string check_str = sentence.substr(check_start + 1, 2);
79 unsigned long checksum = strtol(check_str.c_str(), 0, 16);
80 if (checksum == 0L && check_str != "00") return false;
81
82 unsigned char calculated_checksum = 0;
83 for (std::string::const_iterator i = sentence.begin() + 1;
84 i != sentence.end() && *i != '*'; ++i)
85 calculated_checksum ^= static_cast<unsigned char>(*i);
86
87 return calculated_checksum == checksum;
88}
89
92public:
93 struct ip_mreq m_mrq;
94 void SetMrqAddr(unsigned int addr) {
95 m_mrq.imr_multiaddr.s_addr = addr;
96 m_mrq.imr_interface.s_addr = INADDR_ANY;
97 }
98};
99
100wxDEFINE_EVENT(wxEVT_COMMDRIVER_N0183_NET, CommDriverN0183NetEvent);
101
103wxDECLARE_EVENT(wxEVT_COMMDRIVER_N0183_NET, CommDriverN0183NetEvent);
104
106class CommDriverN0183NetEvent : public wxEvent {
107public:
108 CommDriverN0183NetEvent(wxEventType commandType = wxEVT_NULL, int id = 0)
109 : wxEvent(id, commandType){};
111
112 // accessors
113 void SetPayload(std::shared_ptr<std::vector<unsigned char>> data) {
114 m_payload = data;
115 }
116 std::shared_ptr<std::vector<unsigned char>> GetPayload() { return m_payload; }
117
118 // required for sending with wxPostEvent()
119 wxEvent* Clone() const {
121 newevent->m_payload = this->m_payload;
122 return newevent;
123 };
124
125private:
126 std::shared_ptr<std::vector<unsigned char>> m_payload;
127};
128
129//========================================================================
130/* commdriverN0183Net implementation
131 * */
132
133BEGIN_EVENT_TABLE(CommDriverN0183Net, wxEvtHandler)
134EVT_TIMER(TIMER_SOCKET, CommDriverN0183Net::OnTimerSocket)
135EVT_SOCKET(DS_SOCKET_ID, CommDriverN0183Net::OnSocketEvent)
136EVT_SOCKET(DS_SERVERSOCKET_ID, CommDriverN0183Net::OnServerSocketEvent)
137EVT_TIMER(TIMER_SOCKET + 1, CommDriverN0183Net::OnSocketReadWatchdogTimer)
138END_EVENT_TABLE()
139
140// CommDriverN0183Net::CommDriverN0183Net() : CommDriverN0183() {}
141
143 DriverListener& listener)
144 : CommDriverN0183(NavAddr::Bus::N0183,
145 ((ConnectionParams*)params)->GetStrippedDSPort()),
146 m_params(*params),
147 m_listener(listener),
148 m_net_port(wxString::Format("%i", params->NetworkPort)),
149 m_net_protocol(params->NetProtocol),
150 m_sock(NULL),
151 m_tsock(NULL),
152 m_socket_server(NULL),
153 m_is_multicast(false),
154 m_txenter(0),
155 m_portstring(params->GetDSPort()),
156 m_io_select(params->IOSelect),
157 m_connection_type(params->Type),
158 m_bok(false)
159
160{
161 m_addr.Hostname(params->NetworkAddress);
162 m_addr.Service(params->NetworkPort);
163
164 m_socket_timer.SetOwner(this, TIMER_SOCKET);
165 m_socketread_watchdog_timer.SetOwner(this, TIMER_SOCKET + 1);
166
167 // Prepare the wxEventHandler to accept events from the actual hardware thread
168 Bind(wxEVT_COMMDRIVER_N0183_NET, &CommDriverN0183Net::handle_N0183_MSG, this);
169
170 m_mrq_container = new MrqContainer;
171
172 Open();
173}
174
175CommDriverN0183Net::~CommDriverN0183Net() {
176 delete m_mrq_container;
177 Close();
178}
179
180void CommDriverN0183Net::handle_N0183_MSG(CommDriverN0183NetEvent& event) {
181 auto p = event.GetPayload();
182 std::vector<unsigned char>* payload = p.get();
183
184 // Extract the NMEA0183 sentence
185 std::string full_sentence = std::string(payload->begin(), payload->end());
186
187 if ((full_sentence[0] == '$') || (full_sentence[0] == '!')) { // Sanity check
188 std::string identifier;
189 // We notify based on full message, including the Talker ID
190 identifier = full_sentence.substr(1, 5);
191
192 // notify message listener and also "ALL" N0183 messages, to support plugin
193 // API using original talker id
194 auto msg = std::make_shared<const Nmea0183Msg>(identifier, full_sentence,
195 GetAddress());
196 auto msg_all = std::make_shared<const Nmea0183Msg>(*msg, "ALL");
197
198 if (m_params.SentencePassesFilter(full_sentence, FILTER_INPUT))
199 m_listener.Notify(std::move(msg));
200 m_listener.Notify(std::move(msg_all));
201 }
202}
203
204void CommDriverN0183Net::Open(void) {
205#ifdef __UNIX__
206#if wxCHECK_VERSION(3, 0, 0)
207 in_addr_t addr =
208 ((struct sockaddr_in*)GetAddr().GetAddressData())->sin_addr.s_addr;
209#else
210 in_addr_t addr =
211 ((struct sockaddr_in*)GetAddr().GetAddress()->m_addr)->sin_addr.s_addr;
212#endif
213#else
214 unsigned int addr = inet_addr(GetAddr().IPAddress().mb_str());
215#endif
216 // Create the socket
217 switch (m_net_protocol) {
218 case GPSD: {
219 OpenNetworkGPSD();
220 break;
221 }
222 case TCP: {
223 OpenNetworkTCP(addr);
224 break;
225 }
226 case UDP: {
227 OpenNetworkUDP(addr);
228 break;
229 }
230 default:
231 break;
232 }
233 SetOk(true);
234}
235
236void CommDriverN0183Net::OpenNetworkUDP(unsigned int addr) {
237 if (GetPortType() != DS_TYPE_OUTPUT) {
238 // We need a local (bindable) address to create the Datagram receive socket
239 // Set up the receive socket
240 wxIPV4address conn_addr;
241 conn_addr.Service(GetNetPort());
242 conn_addr.AnyAddress();
243 SetSock(
244 new wxDatagramSocket(conn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
245
246 // Test if address is IPv4 multicast
247 if ((ntohl(addr) & 0xf0000000) == 0xe0000000) {
248 SetMulticast(true);
249 m_mrq_container->SetMrqAddr(addr);
250 GetSock()->SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &m_mrq_container->m_mrq,
251 sizeof(m_mrq_container->m_mrq));
252 }
253
254 GetSock()->SetEventHandler(*this, DS_SOCKET_ID);
255
256 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
257 wxSOCKET_LOST_FLAG);
258 GetSock()->Notify(TRUE);
259 GetSock()->SetTimeout(1); // Short timeout
260 }
261
262 // Set up another socket for transmit
263 if (GetPortType() != DS_TYPE_INPUT) {
264 wxIPV4address tconn_addr;
265 tconn_addr.Service(0); // use ephemeral out port
266 tconn_addr.AnyAddress();
267 SetTSock(
268 new wxDatagramSocket(tconn_addr, wxSOCKET_NOWAIT | wxSOCKET_REUSEADDR));
269 // Here would be the place to disable multicast loopback
270 // but for consistency with broadcast behaviour, we will
271 // instead rely on setting priority levels to ignore
272 // sentences read back that have just been transmitted
273 if ((!GetMulticast()) && (GetAddr().IPAddress().EndsWith(_T("255")))) {
274 int broadcastEnable = 1;
275 bool bam = GetTSock()->SetOption(
276 SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
277 }
278 }
279
280 // In case the connection is lost before acquired....
281 SetConnectTime(wxDateTime::Now());
282}
283
284void CommDriverN0183Net::OpenNetworkTCP(unsigned int addr) {
285 int isServer = ((addr == INADDR_ANY) ? 1 : 0);
286 wxLogMessage(wxString::Format(_T("Opening TCP Server %d"), isServer));
287
288 if (isServer) {
289 SetSockServer(new wxSocketServer(GetAddr(), wxSOCKET_REUSEADDR));
290 } else {
291 SetSock(new wxSocketClient());
292 }
293
294 if (isServer) {
295 GetSockServer()->SetEventHandler(*this, DS_SERVERSOCKET_ID);
296 GetSockServer()->SetNotify(wxSOCKET_CONNECTION_FLAG);
297 GetSockServer()->Notify(TRUE);
298 GetSockServer()->SetTimeout(1); // Short timeout
299 } else {
300 GetSock()->SetEventHandler(*this, DS_SOCKET_ID);
301 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
302 if (GetPortType() != DS_TYPE_INPUT) notify_flags |= wxSOCKET_OUTPUT_FLAG;
303 if (GetPortType() != DS_TYPE_OUTPUT) notify_flags |= wxSOCKET_INPUT_FLAG;
304 GetSock()->SetNotify(notify_flags);
305 GetSock()->Notify(TRUE);
306 GetSock()->SetTimeout(1); // Short timeout
307
308 SetBrxConnectEvent(false);
309 GetSocketTimer()->Start(100, wxTIMER_ONE_SHOT); // schedule a connection
310 }
311
312 // In case the connection is lost before acquired....
313 SetConnectTime(wxDateTime::Now());
314}
315
316void CommDriverN0183Net::OpenNetworkGPSD() {
317 SetSock(new wxSocketClient());
318 GetSock()->SetEventHandler(*this, DS_SOCKET_ID);
319 GetSock()->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG |
320 wxSOCKET_LOST_FLAG);
321 GetSock()->Notify(TRUE);
322 GetSock()->SetTimeout(1); // Short timeout
323
324 wxSocketClient* tcp_socket = static_cast<wxSocketClient*>(GetSock());
325 tcp_socket->Connect(GetAddr(), FALSE);
326 SetBrxConnectEvent(false);
327}
328
329void CommDriverN0183Net::OnSocketReadWatchdogTimer(wxTimerEvent& event) {
330 m_dog_value--;
331 if (m_dog_value <= 0) { // No receive in n seconds, assume connection lost
332 wxLogMessage(
333 wxString::Format(_T(" TCP NetworkDataStream watchdog timeout: %s"),
334 GetPort().c_str()));
335
336 if (GetProtocol() == TCP) {
337 wxSocketClient* tcp_socket = dynamic_cast<wxSocketClient*>(GetSock());
338 if (tcp_socket) {
339 tcp_socket->Close();
340 }
341 GetSocketTimer()->Start(5000, wxTIMER_ONE_SHOT); // schedule a reconnect
342 GetSocketThreadWatchdogTimer()->Stop();
343 }
344 }
345}
346
347void CommDriverN0183Net::OnTimerSocket(wxTimerEvent& event) {
348 // Attempt a connection
349 wxSocketClient* tcp_socket = dynamic_cast<wxSocketClient*>(GetSock());
350 if (tcp_socket) {
351 if (tcp_socket->IsDisconnected()) {
352 SetBrxConnectEvent(false);
353 tcp_socket->Connect(GetAddr(), FALSE);
354 GetSocketTimer()->Start(5000,
355 wxTIMER_ONE_SHOT); // schedule another attempt
356 }
357 }
358}
359
360bool CommDriverN0183Net::SendMessage(std::shared_ptr<const NavMsg> msg,
361 std::shared_ptr<const NavAddr> addr) {
362 auto msg_0183 = std::dynamic_pointer_cast<const Nmea0183Msg>(msg);
363 return SendSentenceNetwork(msg_0183->payload.c_str());
364}
365
366
367void CommDriverN0183Net::OnSocketEvent(wxSocketEvent& event) {
368 //#define RD_BUF_SIZE 200
369#define RD_BUF_SIZE \
370 4096 // Allows handling of high volume data streams, such as a National AIS
371 // stream with 100s of msgs a second.
372
373 switch (event.GetSocketEvent()) {
374 case wxSOCKET_INPUT: // from gpsd Daemon
375 {
376 // TODO determine if the follwing SetFlags needs to be done at every
377 // socket event or only once when socket is created, it it needs to be
378 // done at all!
379 // m_sock->SetFlags(wxSOCKET_WAITALL | wxSOCKET_BLOCK); // was
380 // (wxSOCKET_NOWAIT);
381
382 // We use wxSOCKET_BLOCK to avoid Yield() reentrancy problems
383 // if a long ProgressDialog is active, as in S57 SENC creation.
384
385 // Disable input event notifications to preclude re-entrancy on
386 // non-blocking socket
387 // m_sock->SetNotify(wxSOCKET_LOST_FLAG);
388
389 std::vector<char> data(RD_BUF_SIZE + 1);
390 event.GetSocket()->Read(&data.front(), RD_BUF_SIZE);
391 if (!event.GetSocket()->Error()) {
392 size_t count = event.GetSocket()->LastCount();
393 if (count) {
394 if (1 /*FIXME !g_benableUDPNullHeader*/) {
395 data[count] = 0;
396 m_sock_buffer += (&data.front());
397 } else {
398 // XXX FIXME: is it reliable?
399 // copy all received bytes
400 // there's 0 in furuno UDP tags before NMEA sentences.
401 m_sock_buffer.append(&data.front(), count);
402 }
403 }
404 }
405
406 bool done = false;
407
408 while (!done) {
409 int nmea_tail = 2;
410 size_t nmea_end = m_sock_buffer.find_first_of(
411 "*\r\n"); // detect the potential end of a NMEA string by finding
412 // the checkum marker or EOL
413
414 if (nmea_end ==
415 wxString::npos) // No termination characters: continue reading
416 break;
417
418 if (m_sock_buffer[nmea_end] != '*') nmea_tail = -1;
419
420 if (nmea_end < m_sock_buffer.size() - nmea_tail) {
421 nmea_end +=
422 nmea_tail +
423 1; // move to the char after the 2 checksum digits, if present
424 if (nmea_end == 0) // The first character in the buffer is a
425 // terminator, skip it to avoid infinite loop
426 nmea_end = 1;
427 std::string nmea_line = m_sock_buffer.substr(0, nmea_end);
428
429 // If, due to some logic error, the {nmea_end} parameter is larger
430 // than the length of the socket buffer, then std::string::substr()
431 // will throw an exception. We don't want that, so test for it. If
432 // found, the simple solution is to clear the socket buffer, and
433 // carry on This has been seen on high volume TCP feeds, Windows
434 // only. Hard to catch.....
435 if (nmea_end > m_sock_buffer.size())
436 m_sock_buffer.clear();
437 else
438 m_sock_buffer = m_sock_buffer.substr(nmea_end);
439
440 size_t nmea_start = nmea_line.find_last_of(
441 "$!"); // detect the potential start of a NMEA string, skipping
442 // preceding chars that may look like the start of a
443 // string.
444 if (nmea_start != wxString::npos) {
445 nmea_line = nmea_line.substr(nmea_start);
446 nmea_line += "\r\n"; // Add cr/lf, possibly superfluous
447 if (ChecksumOK(nmea_line)) {
448 CommDriverN0183NetEvent Nevent(wxEVT_COMMDRIVER_N0183_NET, 0);
449 if (nmea_line.size()) {
450 // Copy the message into a vector for tranmittal upstream
451 auto buffer = std::make_shared<std::vector<unsigned char>>();
452 std::vector<unsigned char>* vec = buffer.get();
453 std::copy(nmea_line.begin(), nmea_line.end(),
454 std::back_inserter(*vec));
455
456 Nevent.SetPayload(buffer);
457 AddPendingEvent(Nevent);
458 }
459 }
460 }
461 } else
462 done = true;
463 }
464
465 // Prevent non-nmea junk from consuming to much memory by limiting
466 // carry-over buffer size.
467 if (m_sock_buffer.size() > RD_BUF_SIZE)
468 m_sock_buffer =
469 m_sock_buffer.substr(m_sock_buffer.size() - RD_BUF_SIZE);
470
471 m_dog_value = N_DOG_TIMEOUT; // feed the dog
472 break;
473 }
474
475 case wxSOCKET_LOST: {
476 if (GetProtocol() == TCP || GetProtocol() == GPSD) {
477 if (GetBrxConnectEvent())
478 wxLogMessage(wxString::Format(
479 _T("NetworkDataStream connection lost: %s"), GetPort().c_str()));
480 if (GetSockServer()) {
481 GetSock()->Destroy();
482 SetSock(NULL);
483 break;
484 }
485 wxDateTime now = wxDateTime::Now();
486 wxTimeSpan since_connect(
487 0, 0, 10); // ten secs assumed, if connect time is uninitialized
488 if (GetConnectTime().IsValid()) since_connect = now - GetConnectTime();
489
490 int retry_time = 5000; // default
491
492 // If the socket has never connected, and it is a short interval since
493 // the connect request then stretch the time a bit. This happens on
494 // Windows if there is no dafault IP on any interface
495
496 if (!GetBrxConnectEvent() && (since_connect.GetSeconds() < 5))
497 retry_time = 10000; // 10 secs
498
499 GetSocketThreadWatchdogTimer()->Stop();
500 GetSocketTimer()->Start(
501 retry_time, wxTIMER_ONE_SHOT); // Schedule a re-connect attempt
502 }
503 break;
504 }
505
506 case wxSOCKET_CONNECTION: {
507 if (GetProtocol() == GPSD) {
508 // Sign up for watcher mode, Cooked NMEA
509 // Note that SIRF devices will be converted by gpsd into
510 // pseudo-NMEA
511 char cmd[] = "?WATCH={\"class\":\"WATCH\", \"nmea\":true}";
512 GetSock()->Write(cmd, strlen(cmd));
513 } else if (GetProtocol() == TCP) {
514 wxLogMessage(wxString::Format(
515 _T("TCP NetworkDataStream connection established: %s"),
516 GetPort().c_str()));
517 m_dog_value = N_DOG_TIMEOUT; // feed the dog
518 if (GetPortType() != DS_TYPE_OUTPUT)
519 GetSocketThreadWatchdogTimer()->Start(1000);
520 if (GetPortType() != DS_TYPE_INPUT && GetSock()->IsOk())
521 (void)SetOutputSocketOptions(GetSock());
522 GetSocketTimer()->Stop();
523 SetBrxConnectEvent(true);
524 }
525
526 SetConnectTime(wxDateTime::Now());
527 break;
528 }
529
530 default:
531 break;
532 }
533}
534
535void CommDriverN0183Net::OnServerSocketEvent(wxSocketEvent& event) {
536 switch (event.GetSocketEvent()) {
537 case wxSOCKET_CONNECTION: {
538 SetSock(GetSockServer()->Accept(false));
539
540 if (GetSock()) {
541 GetSock()->SetTimeout(2);
542 // GetSock()->SetFlags(wxSOCKET_BLOCK);
543 GetSock()->SetEventHandler(*this, DS_SOCKET_ID);
544 int notify_flags = (wxSOCKET_CONNECTION_FLAG | wxSOCKET_LOST_FLAG);
545 if (GetPortType() != DS_TYPE_INPUT) {
546 notify_flags |= wxSOCKET_OUTPUT_FLAG;
547 (void)SetOutputSocketOptions(GetSock());
548 }
549 if (GetPortType() != DS_TYPE_OUTPUT)
550 notify_flags |= wxSOCKET_INPUT_FLAG;
551 GetSock()->SetNotify(notify_flags);
552 GetSock()->Notify(true);
553 }
554
555 break;
556 }
557
558 default:
559 break;
560 }
561}
562
563bool CommDriverN0183Net::SendSentenceNetwork(const wxString& payload) {
564 if (m_txenter)
565 return false; // do not allow recursion, could happen with non-blocking
566 // sockets
567 m_txenter++;
568
569 bool ret = true;
570 wxDatagramSocket* udp_socket;
571 switch (GetProtocol()) {
572 case TCP:
573 if (GetSock() && GetSock()->IsOk()) {
574 GetSock()->Write(payload.mb_str(), strlen(payload.mb_str()));
575 if (GetSock()->Error()) {
576 if (GetSockServer()) {
577 GetSock()->Destroy();
578 SetSock(NULL);
579 } else {
580 wxSocketClient* tcp_socket =
581 dynamic_cast<wxSocketClient*>(GetSock());
582 if (tcp_socket) tcp_socket->Close();
583 if (!GetSocketTimer()->IsRunning())
584 GetSocketTimer()->Start(
585 5000, wxTIMER_ONE_SHOT); // schedule a reconnect
586 GetSocketThreadWatchdogTimer()->Stop();
587 }
588 ret = false;
589 }
590
591 } else
592 ret = false;
593 break;
594 case UDP:
595 udp_socket = dynamic_cast<wxDatagramSocket*>(GetTSock());
596 if (udp_socket && udp_socket->IsOk()) {
597 udp_socket->SendTo(GetAddr(), payload.mb_str(), payload.size());
598 if (udp_socket->Error()) ret = false;
599 } else
600 ret = false;
601 break;
602
603 case GPSD:
604 default:
605 ret = false;
606 break;
607 }
608 m_txenter--;
609 return ret;
610}
611
612void CommDriverN0183Net::Close() {
613 wxLogMessage(wxString::Format(_T("Closing NMEA NetworkDataStream %s"),
614 GetNetPort().c_str()));
615 // Kill off the TCP Socket if alive
616 if (m_sock) {
617 if (m_is_multicast)
618 m_sock->SetOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &m_mrq_container->m_mrq,
619 sizeof(m_mrq_container->m_mrq));
620 m_sock->Notify(FALSE);
621 m_sock->Destroy();
622 }
623
624 if (m_tsock) {
625 m_tsock->Notify(FALSE);
626 m_tsock->Destroy();
627 }
628
629 if (m_socket_server) {
630 m_socket_server->Notify(FALSE);
631 m_socket_server->Destroy();
632 }
633
634 m_socket_timer.Stop();
635 m_socketread_watchdog_timer.Stop();
636}
637
638bool CommDriverN0183Net::SetOutputSocketOptions(wxSocketBase* tsock) {
639 int ret;
640
641 // Disable nagle algorithm on outgoing connection
642 // Doing this here rather than after the accept() is
643 // pointless on platforms where TCP_NODELAY is
644 // not inherited. However, none of OpenCPN's currently
645 // supported platforms fall into that category.
646
647 int nagleDisable = 1;
648 ret = tsock->SetOption(IPPROTO_TCP, TCP_NODELAY, &nagleDisable,
649 sizeof(nagleDisable));
650
651 // Drastically reduce the size of the socket output buffer
652 // so that when client goes away without properly closing, the stream will
653 // quickly fill the output buffer, and thus fail the write() call
654 // within a few seconds.
655 unsigned long outbuf_size = 1024; // Smallest allowable value on Linux
656 return (tsock->SetOption(SOL_SOCKET, SO_SNDBUF, &outbuf_size,
657 sizeof(outbuf_size)) &&
658 ret);
659}
660
661bool CommDriverN0183Net::ChecksumOK(const std::string& sentence) {
662 if (!m_bchecksumCheck) return true;
663
664 return CheckSumCheck(sentence);
665}
Internal wxEvent worker thread – main driver.
Driver for NMEA0183 over TCP/IP.
Abstract NMEA0183 drivers common parts.
Interface implemented by transport layer and possible other parties like test code which should handl...
Definition: comm_driver.h:47
virtual void Notify(std::shared_ptr< const NavMsg > message)=0
Handle a received message.
Internal helper class.
Where messages are sent to or received from.
Definition: comm_navmsg.h:136