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