1 // socket_io.cxx
2 //
3 // Author: Dave Freese, W1HKJ
4 // Stelios Bounanos, M0GLD
5 //
6 // ----------------------------------------------------------------------------
7 // Copyright (C) 2014
8 // David Freese, W1HKJ
9 //
10 // This file is part of flrig
11 //
12 // flrig is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // flrig is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 // ----------------------------------------------------------------------------
25
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <iostream>
29 #include <fstream>
30 #include <cstring>
31 #include <ctime>
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <errno.h>
35 #include <pthread.h>
36
37 #include <FL/Fl.H>
38 #include <FL/Enumerations.H>
39 #include <FL/Fl_Window.H>
40 #include <FL/Fl_Button.H>
41 #include <FL/Fl_Group.H>
42 #include <FL/Fl_Sys_Menu_Bar.H>
43 #include <FL/x.H>
44 #include <FL/Fl_Help_Dialog.H>
45 #include <FL/Fl_Menu_Item.H>
46 #include <FL/Fl_File_Icon.H>
47 #include <math.h>
48
49 #include "config.h"
50
51 #include "status.h"
52 #include "debug.h"
53 #include "util.h"
54 #include "gettext.h"
55 #include "rigpanel.h"
56
57 #include "socket_io.h"
58 #include "socket.h"
59
60 #include <FL/x.H>
61 #include <FL/Fl_Pixmap.H>
62 #include <FL/Fl_Image.H>
63
64 #ifdef WIN32
65 # include <winsock2.h>
66 #else
67 # include <arpa/inet.h>
68 #endif
69
70 using namespace std;
71
72 Socket *tcpip = (Socket *)0;
73 Address *remote_addr = (Address *)0;
74
75 static bool exit_socket_loop = false;
76
77 static string rxbuffer;
78 pthread_t *rcv_socket_thread = 0;
79 pthread_mutex_t mutex_rcv_socket = PTHREAD_MUTEX_INITIALIZER;
80
log_level(int level,string s,string data)81 static void log_level(int level, string s, string data)
82 {
83 time_t now;
84 time(&now);
85 struct tm *local = localtime(&now);
86 char sztm[20];
87 strftime(sztm, sizeof(sztm), "%H:%M:%S", local);
88
89 string s1;
90 s1 = selrig->data_type == BINARY ? str2hex(data.c_str(), data.length()) : data;
91
92 if (selrig->data_type == STRING) {
93 s1 = data;
94 size_t p;
95 while((p = s1.find('\r')) != string::npos)
96 s1.replace(p, 1, "<cr>");
97 while((p = s1.find('\n')) != string::npos)
98 s1.replace(p, 1, "<lf>");
99 } else
100 s1 = str2hex(data.c_str(), data.length());
101
102
103 switch (level) {
104 case QUIET:
105 LOG_QUIET("%s: %s : %s", sztm, s.c_str(), s1.c_str());
106 break;
107 case ERR:
108 LOG_ERROR("%s: %s : %s", sztm, s.c_str(), s1.c_str());
109 break;
110 case WARN:
111 LOG_WARN("%s: %s : %s", sztm, s.c_str(), s1.c_str());
112 break;
113 case INFO:
114 LOG_INFO("%s: %s : %s", sztm, s.c_str(), s1.c_str());
115 break;
116 default:
117 LOG_DEBUG("%s: %s : %s", sztm, s.c_str(), s1.c_str());
118 }
119 }
120
rcv_socket_loop(void *)121 void *rcv_socket_loop(void *)
122 {
123 for (;;) {
124 MilliSleep(50);
125 { guard_lock socket_lock(&mutex_rcv_socket);
126 if (exit_socket_loop) break;
127 if (tcpip && tcpip->fd() != -1) {
128 try {
129 tcpip->recv(rxbuffer);
130 box_tcpip_connect->color(FL_GREEN);
131 box_tcpip_connect->redraw();
132 box_xcvr_connect->color(FL_GREEN);
133 box_xcvr_connect->redraw();
134 tcpip_menu_box->color(FL_GREEN);
135 tcpip_menu_box->redraw();
136 } catch (const SocketException& e) {
137 LOG_ERROR("Error %d, %s", e.error(), e.what());
138 box_tcpip_connect->color(FL_YELLOW);
139 box_tcpip_connect->redraw();
140 box_xcvr_connect->color(FL_YELLOW);
141 box_xcvr_connect->redraw();
142 tcpip_menu_box->color(FL_YELLOW);
143 tcpip_menu_box->redraw();
144 }
145 }
146 } // end guard_lock
147 }
148 exit_socket_loop = false;
149 return NULL;
150 }
151
connect_to_remote()152 void connect_to_remote()
153 {
154 try {
155 if (remote_addr) delete remote_addr;
156 remote_addr = new Address(progStatus.tcpip_addr.c_str(), progStatus.tcpip_port.c_str());
157 LOG_QUIET("Created new remote_addr @ %p", remote_addr);
158 if (!tcpip) {
159 guard_lock socket_lock(&mutex_rcv_socket);
160 tcpip = new Socket(*remote_addr);
161 LOG_QUIET("Created new socket @ %p", tcpip);
162 tcpip->set_timeout(0.001);
163 tcpip->connect();
164 tcpip->set_nonblocking(true);
165 LOG_QUIET("Connected to %d", tcpip->fd());
166 tcpip_box->show();
167 box_tcpip_connect->color(FL_GREEN);
168 box_tcpip_connect->redraw();
169 box_xcvr_connect->color(FL_GREEN);
170 box_xcvr_connect->redraw();
171 tcpip_menu_box->color(FL_GREEN);
172 tcpip_menu_box->redraw();
173 }
174 if (tcpip->fd() == -1) {
175 guard_lock socket_lock(&mutex_rcv_socket);
176 try {
177 tcpip->connect(*remote_addr);
178 tcpip->set_nonblocking(true);
179 LOG_QUIET("Connected to %d", tcpip->fd());
180 tcpip_box->show();
181 box_tcpip_connect->color(FL_GREEN);
182 box_tcpip_connect->redraw();
183 box_xcvr_connect->color(FL_GREEN);
184 box_xcvr_connect->redraw();
185 tcpip_menu_box->color(FL_GREEN);
186 tcpip_menu_box->redraw();
187 } catch (const SocketException & e) {
188 LOG_ERROR("Error: %d, %s", e.error(), e.what());
189 delete remote_addr;
190 remote_addr = 0;
191 delete tcpip;
192 tcpip = 0;
193 box_tcpip_connect->color(FL_LIGHT1);
194 box_tcpip_connect->redraw();
195 box_xcvr_connect->color(FL_LIGHT1);
196 box_xcvr_connect->redraw();
197 tcpip_menu_box->color(FL_LIGHT1);
198 tcpip_menu_box->redraw();
199 throw e;
200 }
201 }
202 if (!rcv_socket_thread) {
203 rcv_socket_thread = new pthread_t;
204 if (pthread_create(rcv_socket_thread, NULL, rcv_socket_loop, NULL)) {
205 perror("pthread_create");
206 exit(EXIT_FAILURE);
207 }
208 LOG_QUIET("%s", "Socket receive thread started");
209 }
210 }
211 catch (const SocketException& e) {
212 LOG_ERROR("Error: %d, %s", e.error(), e.what());
213
214 delete remote_addr;
215 remote_addr = 0;
216 LOG_ERROR("Deleted remote address");
217
218 delete tcpip;
219 tcpip = 0;
220 LOG_ERROR("Deleted tcpip socket");
221
222 throw e;
223 }
224 return;
225 }
226
disconnect_from_remote()227 void disconnect_from_remote()
228 {
229 if (!tcpip || tcpip->fd() == -1) return;
230
231 {
232 guard_lock socket_lock(&mutex_rcv_socket);
233 tcpip->close();
234 delete tcpip;
235 tcpip = 0;
236 LOG_QUIET("%s", "Deleted tcpip socket instance");
237 delete remote_addr;
238 remote_addr = 0;
239 LOG_QUIET("%s", "Deleted socket address instance");
240 exit_socket_loop = true;
241 }
242 pthread_join(*rcv_socket_thread, NULL);
243 rcv_socket_thread = NULL;
244 LOG_QUIET("%s", "Exited from socket read thread");
245
246 box_tcpip_connect->color(FL_LIGHT1);
247 box_tcpip_connect->redraw();
248 box_xcvr_connect->color(FL_LIGHT1);
249 box_xcvr_connect->redraw();
250 tcpip_menu_box->color(FL_LIGHT1);
251 tcpip_menu_box->redraw();
252 }
253
254 int retry_after = 0;
255 int drop_count = 0;
256
send_to_remote(string cmd_string,int pace)257 void send_to_remote(string cmd_string, int pace)
258 {
259 if (retry_after > 0) {
260 retry_after -= progStatus.serloop_timing;
261 if (retry_after < 0) retry_after = 0;
262 return;
263 }
264
265 if (!tcpip || tcpip->fd() == -1) {
266 try {
267 connect_to_remote();
268 } catch (...) {
269 LOG_QUIET("Retry connect in %d seconds", progStatus.tcpip_reconnect_after);
270 retry_after = 1000 * progStatus.tcpip_reconnect_after;
271 return;
272 }
273 }
274
275 try {
276 guard_lock send_lock(&mutex_rcv_socket);
277 size_t len = cmd_string.length();
278 for (size_t i = 0; i < len; i += 8)
279 tcpip->send(&cmd_string[i], len - i > 8 ? 8 : len - i);
280 log_level(WARN, "send to remote", cmd_string);
281 drop_count = 0;
282 } catch (const SocketException& e) {
283 LOG_ERROR("Error: %d, %s", e.error(), e.what());
284 drop_count++;
285 if (drop_count == progStatus.tcpip_drops_allowed) {
286 disconnect_from_remote();
287 drop_count = 0;
288 }
289 }
290 return;
291 }
292
read_from_remote(string & str)293 int read_from_remote(string &str)
294 {
295 if (!tcpip || tcpip->fd() == -1) return 0;
296
297 guard_lock socket_lock(&mutex_rcv_socket);
298 str = rxbuffer;
299 rxbuffer.clear();
300 if (!str.empty())
301 log_level(WARN, "receive from remote", str);
302 else
303 log_level(WARN, "receive from remote", "no data");
304
305 return str.length();
306 }
307