1 /*-
2  * Copyright (c) 1999 Thomas Runge (coto@core.de)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <netdb.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <X11/Intrinsic.h>
40 
41 #include "lcd_net.h"
42 #include "radio.h"
43 
44 static char buffer[MAXMSG];
45 extern XtAppContext app_con;
46 extern int sockfd;
47 extern int lcd_stereo;
48 extern int lcd_fieldstrength;
49 static XtIntervalId timerId;
50 static int width, height, cellw, cellh;
51 
52 static int lcd_net_handle();
53 static void lcd_net_handler(XtPointer clientData, XtIntervalId *id);
54 static int lcd_net_read(char *buffer, int nbytes);
55 static int lcd_net_writen(const char *buffer, int nbytes);
56 static void lcd_net_update_values();
57 static void lcd_net_updateLCD(XtPointer, XtIntervalId*);
58 
sig_pipe_handler()59 void sig_pipe_handler()
60 {
61 	if(debug)
62 		printf("got SIGPIPE!\n");
63 	lcd_net_stop();
64 }
65 
lcd_net_init(const char * host,u_short port,const char ** neterror)66 int lcd_net_init(const char *host, u_short port, const char **neterror)
67 {
68 	int sock;
69 	struct sockaddr_in	serv_addr;
70 	struct hostent *he;
71 	unsigned long arg;
72 
73 	width = 20;
74 	height = 4;
75 	cellw = 5;
76 	cellh = 8;
77 
78 	signal(SIGPIPE, (void*) sig_pipe_handler);
79 
80 	he = gethostbyname(host);
81 	if(!he)
82 	{
83 		*neterror = hstrerror(h_errno);
84 		return(-1);
85 	}
86 
87 	bzero((char*) &serv_addr, sizeof(serv_addr));
88 	serv_addr.sin_family	= AF_INET;
89 	serv_addr.sin_addr		= *(struct in_addr *) he->h_addr_list[0];
90 	serv_addr.sin_port		= htons(port);
91 
92 	if(debug)
93 		printf("lcd_net: socket\n");
94 
95 	if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
96 	{
97 		*neterror = hstrerror(h_errno);
98 		return(-1);
99 	}
100 
101 	if(debug)
102 		printf("lcd_net: connect\n");
103 
104 	if(connect(sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
105 	{
106 		*neterror = hstrerror(h_errno);
107 		return(-1);
108 	}
109 
110 	arg = 1;
111 	if(ioctl(sock, FIONBIO, &arg) == -1)
112 		fprintf(stderr,
113 				"lcd_net error setting socket to non blocking mode: %s\n",
114 				strerror(errno));
115 
116 	return(sock);
117 }
118 
lcd_net_start()119 int lcd_net_start()
120 {
121 	sprintf(buffer, "hello\n");
122 	lcd_net_writen(buffer, strlen(buffer));
123 
124 	sprintf(buffer, "client_set name %s %s\n", APPNAME, APPVERSION);
125 	lcd_net_writen(buffer, strlen(buffer));
126 
127 	sprintf(buffer, "screen_add %s\n", APPNAME);
128 	lcd_net_writen(buffer, strlen(buffer));
129 
130 	sprintf(buffer, "screen_set %s name %s\n", APPNAME, APPNAME);
131 	lcd_net_writen(buffer, strlen(buffer));
132 
133 	sprintf(buffer, "widget_add %s title title\n", APPNAME);
134 	lcd_net_writen(buffer, strlen(buffer));
135 
136 	sprintf(buffer, "widget_set %s title %s-%s\n", APPNAME,
137 													APPNAME, APPVERSION);
138 	lcd_net_writen(buffer, strlen(buffer));
139 
140 	sprintf(buffer, "widget_add %s stationlabel string\n", APPNAME);
141 	lcd_net_writen(buffer, strlen(buffer));
142 
143 	sprintf(buffer, "widget_add %s freqlabel string\n", APPNAME);
144 	lcd_net_writen(buffer, strlen(buffer));
145 
146 	sprintf(buffer, "widget_add %s station string\n", APPNAME);
147 	lcd_net_writen(buffer, strlen(buffer));
148 
149 	sprintf(buffer, "widget_add %s freq string\n", APPNAME);
150 	lcd_net_writen(buffer, strlen(buffer));
151 
152 	/* check for display height before */
153 	sprintf(buffer, "widget_add %s stereo string\n", APPNAME);
154 	lcd_net_writen(buffer, strlen(buffer));
155 
156 	/* check for display height before */
157 	sprintf(buffer, "widget_add %s fsindic string\n", APPNAME);
158 	lcd_net_writen(buffer, strlen(buffer));
159 
160 	/* check for display height before */
161 	sprintf(buffer, "widget_add %s fstrength hbar\n", APPNAME);
162 	lcd_net_writen(buffer, strlen(buffer));
163 
164 	sprintf(buffer, "widget_set %s stationlabel 1 2 Station:\n", APPNAME);
165 	lcd_net_writen(buffer, strlen(buffer));
166 
167 	sprintf(buffer, "widget_set %s freqlabel 1 3 {Freq   :}\n", APPNAME);
168 	lcd_net_writen(buffer, strlen(buffer));
169 
170 	sprintf(buffer, "widget_set %s fsindic 1 4 {Sig: }\n", APPNAME);
171 	lcd_net_writen(buffer, strlen(buffer));
172 
173 	lcd_net_update_values();
174 
175 	XtAppAddTimeOut(app_con, 250, lcd_net_handler, (XtPointer)NULL);
176 	timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD, (XtPointer)NULL);
177 
178 	return(1);
179 }
180 
lcd_net_stop()181 int lcd_net_stop()
182 {
183 	int res = close(sockfd);
184 
185 	sockfd = 0;
186 	sprintf(buffer, "lost connection to LCD server.");
187 	lcdDisconnectCB(buffer);
188 	return(res);
189 }
190 
lcd_net_update_values()191 static void lcd_net_update_values()
192 {
193 	if(!sockfd)
194 		return;
195 
196 	sprintf(buffer, "widget_set %s station 10 2 {%s}\n",
197 								APPNAME, global_station_name);
198 	lcd_net_writen(buffer, strlen(buffer));
199 
200 	sprintf(buffer, "widget_set %s freq 10 3 {%3.2f MHz}\n", APPNAME,
201 															frequency/100.);
202 	lcd_net_writen(buffer, strlen(buffer));
203 
204 	/* check for display height before */
205 	sprintf(buffer, "widget_set %s stereo 15 4 %s\n", APPNAME,
206 												lcd_stereo ? "stereo" : "mono");
207 	lcd_net_writen(buffer, strlen(buffer));
208 
209 	/* check for display height before */
210 	sprintf(buffer, "widget_set %s fstrength 6 4 %d\n", APPNAME,
211 													lcd_fieldstrength * cellw);
212 	lcd_net_writen(buffer, strlen(buffer));
213 }
214 
lcd_net_updateLCD(XtPointer clientData,XtIntervalId * id)215 static void lcd_net_updateLCD(XtPointer clientData, XtIntervalId *id)
216 {
217 	static int old_freq = -1;
218 	static int old_stereo = -1;
219 	static int old_fieldstrength = -1;
220 
221 	if(!sockfd)
222 		return;
223 
224 	if(old_freq != frequency ||
225 		old_stereo != lcd_stereo ||
226 		old_fieldstrength != lcd_fieldstrength)
227 	{
228 		lcd_net_update_values();
229 
230 		old_freq = frequency;
231 		old_stereo = lcd_stereo;
232 		old_fieldstrength = lcd_fieldstrength;
233 	}
234 
235 	timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD,
236 													(XtPointer)NULL);
237 }
238 
lcd_net_handler(XtPointer clientData,XtIntervalId * id)239 static void lcd_net_handler(XtPointer clientData, XtIntervalId *id)
240 {
241 	if(sockfd)
242 	{
243 		lcd_net_handle();
244 		XtAppAddTimeOut(app_con, 250, lcd_net_handler, (XtPointer)NULL);
245 	}
246 }
247 
lcd_net_handle()248 static int lcd_net_handle()
249 {
250 	int res;
251 
252 	res = lcd_net_read(buffer, MAXMSG);
253 	switch(res)
254 	{
255 		case -2:		/* no data to read */
256 			break;
257 		case -1:		/* socket related problem */
258 			perror("socket");
259 			lcd_net_stop();
260 			return(False);
261 			break;
262 		case 0:			/* server died or connection lost */
263 			fprintf(stderr, "connection to LCD server down.\n");
264 			lcd_net_stop();
265 			return(False);
266 			break;
267 		default:
268 			if(!strncmp(buffer, "huh", 3))
269 			{
270 				fprintf(stderr, "server replied an error: %s\n", buffer);
271 				break;
272 			}
273 
274 			if(!strncmp(buffer, "listen", 6))
275 			{
276 				timerId = XtAppAddTimeOut(app_con, 250, lcd_net_updateLCD,
277 												(XtPointer)NULL);
278 				break;
279 			}
280 
281 			if(!strncmp(buffer, "ignore", 6))
282 			{
283 				if(timerId)
284 					XtRemoveTimeOut(timerId);
285 				break;
286 			}
287 
288 			if(!strncmp(buffer, "connect", 7))
289 			{
290 				char *tmp;
291 
292 				tmp = strtok(buffer, " ");
293 				while(tmp)
294 				{
295 					if(!strcmp(tmp, "wid"))
296 					{
297 						tmp = strtok(NULL, " ");
298 						if(!tmp)
299 							break;
300 						width = atoi(tmp);
301 					}
302 					if(!strcmp(tmp, "hgt"))
303 					{
304 						tmp = strtok(NULL, " ");
305 						if(!tmp)
306 							break;
307 						height = atoi(tmp);
308 					}
309 					if(!strcmp(tmp, "cellwid"))
310 					{
311 						tmp = strtok(NULL, " ");
312 						if(!tmp)
313 							break;
314 						cellw = atoi(tmp);
315 					}
316 					if(!strcmp(tmp, "cellhgt"))
317 					{
318 						tmp = strtok(NULL, " ");
319 						if(!tmp)
320 							break;
321 						cellh = atoi(tmp);
322 					}
323 					tmp = strtok(NULL, " ");
324 				}
325 				if(debug)
326 					printf("got lcd. w: %d  h: %d   cw: %d   ch: %d\n",
327 										width, height, cellw, cellh);
328 				break;
329 			}
330 
331 			if(!strncmp(buffer, "bye", 3))
332 			{
333 				fprintf(stderr, "LCD server will go, quitting.\n");
334 				lcd_net_stop();
335 				break;
336 			}
337 
338 			printf("unhandled message: %s\n", buffer);
339 	}
340 
341 	return(True);
342 }
343 
lcd_net_read(char * buf,int nbytes)344 static int lcd_net_read(char *buf, int nbytes)
345 {
346 	int nread;
347 
348 	nread = read(sockfd, buf, nbytes);
349 	if(nread == -1 && errno == EWOULDBLOCK)	/* assume non blocking socket */
350 		return(-2);
351 
352 	return(nread);
353 }
354 
lcd_net_writen(const char * buf,int nbytes)355 static int lcd_net_writen(const char *buf, int nbytes)
356 {
357 	int nleft, nwritten = 0;
358 
359 	nleft = nbytes;
360 	while(nleft > 0)
361 	{
362 		nwritten = write(sockfd, buf, nleft);
363 		if(nwritten <= 0)
364 			return(nwritten);
365 
366 		nleft -= nwritten;
367 		buf+= nwritten;
368 	}
369 	return(nbytes-nleft);
370 }
371 
372