1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/***************************************************************************
18 * LPRng - An Extended Print Spooler System
19 *
20 * Copyright 1988-2003, Patrick Powell, San Diego, CA
21 *     papowell@lprng.com
22 * See LICENSE for conditions of use.
23 *
24 ***************************************************************************/
25
26 static char *const _id =
27"$Id: monitor.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $";
28
29
30#include "lp.h"
31#include "linelist.h"
32#include "getopt.h"
33#include "linksupport.h"
34#include "getqueue.h"
35/**** ENDINCLUDE ****/
36
37/*
38 * Monitor for TCP/UDP data
39 *  Opens a UDP or TCP socket and waits for data to be sent to it.
40 *
41 *  monitor [-t] [-u] [port]
42 *   port is an integer number or a service name in the services database
43 *   default is to use UDP.
44 */
45
46
47extern int errno;
48
49int udp_open( int port );
50int tcp_open( int port );
51
52void Decode( char *in );
53
54char buffer[1024*64];
55int use_tcp = 1;
56int use_udp = 1;
57int port_num = 2001;
58int udp_fd = -1;
59int tcp_fd = -1;
60fd_set readfds;
61fd_set testfds;
62int debug;
63
64char *prog = "???";
65
66/*****************************************************************
67 * Command line options and Debugging information
68 * Getopt is a modified version of the standard getopt(3) command
69 *  line parsing routine. See getopt.c for details
70 *****************************************************************/
71
72/* use this before any error printing, sets up program Name */
73
74struct info {
75	char *buffer;
76	int len;
77	int max_len;
78};
79
80struct info *inbuffers;
81int max_in_buffers;
82
83void Add_buffer( int n )
84{
85	int len = max_in_buffers, count;
86
87	if(debug)FPRINTF(STDERR, "Add_buffer: start n %d, inbuffers 0x%lx, max_in_buffers %d\n",
88		n, Cast_ptr_to_long(inbuffers), max_in_buffers );
89	if( max_in_buffers <= n ){
90		max_in_buffers = n+1;
91		count = sizeof(inbuffers[0])*max_in_buffers;
92		inbuffers = realloc( inbuffers, count );
93		if( inbuffers == 0 ){
94			FPRINTF(STDERR,"Add_buffer: realloc %d failed\n", n );
95			exit(1);
96		}
97		for( count = len; count < max_in_buffers; ++count ){
98			memset(inbuffers+count,0,sizeof(inbuffers[0]));
99		}
100	}
101	if(debug)FPRINTF(STDERR,"Add_buffer: end n %d, inbuffers 0x%lx, max_in_buffers %d\n",
102		n, Cast_ptr_to_long(inbuffers), max_in_buffers );
103}
104
105void Clear_buffer( int n )
106{
107	struct info *in;
108	if(debug)FPRINTF(STDERR,"Clear_buffer: n %d\n", n );
109	Add_buffer( n );
110	in = inbuffers+n;
111	in->len = 0;
112}
113
114struct info *Save_outbuf_len( int n,  char *str, int len )
115{
116	struct info *in;
117
118	if(debug)FPRINTF(STDERR,"Save_outbuf_len: n %d, len %d\n", n, len );
119	Add_buffer(n);
120	in = inbuffers+n;
121	if(debug)FPRINTF(STDERR,
122		"Save_outbuf_len: start inbuffers 0x%lx, in 0x%lx, buffer 0x%lx, len %d, max_len %d\n",
123		Cast_ptr_to_long(inbuffers), Cast_ptr_to_long(in),
124		Cast_ptr_to_long(in->buffer), in->len, in->max_len );
125	if( len + in->len >= in->max_len ){
126		in->max_len += len;
127		in->buffer = realloc( in->buffer, in->max_len+1 );
128		if( in->buffer == 0 ){
129			FPRINTF(STDERR,"Put_oubuf_len: realloc %d failed\n", in->max_len );
130			exit(1);
131		}
132	}
133	memcpy(in->buffer+in->len, str, len+1 );
134	in->len += len;
135	if(debug)FPRINTF(STDERR,
136		"Save_outbuf_len: start inbuffers 0x%lx, in 0x%lx, buffer 0x%lx, len %d, max_len %d\n",
137		Cast_ptr_to_long(inbuffers), Cast_ptr_to_long(in),
138		Cast_ptr_to_long(in->buffer), in->len, in->max_len );
139	return( in );
140}
141
142void usage(void)
143{
144	char *s;
145
146	if( (s = safestrrchr( prog, '/')) ){
147		prog  = s+1;
148	}
149	FPRINTF( STDERR, "usage: %s [-u] [-t] [port]\n", prog );
150	FPRINTF( STDERR, "  -u = use UDP\n" );
151	FPRINTF( STDERR, "  -t = use TCP (default)\n" );
152	FPRINTF( STDERR, "  -d = debug\n" );
153	FPRINTF( STDERR, "  port = port to use (%d default)\n", port_num  );
154	exit(1);
155}
156
157
158
159int main(int argc, char *argv[] )
160{
161	int n, i, c, err, max_port = 0;
162	char *portname, *s;
163	struct servent *servent;
164	struct info *in;
165
166	prog = argv[0];
167	Opterr = 1;
168	while( (n = Getopt(argc, argv, "dut")) != EOF ){
169		switch(n){
170		default:  usage(); break;
171		case 'u': use_udp = !use_udp; break;
172		case 't': use_tcp = !use_tcp; break;
173		case 'd': debug = 1; break;
174		}
175	}
176	i = argc - Optind;
177	if( i > 1 ) usage();
178	if( i == 1 ){
179		portname = argv[Optind];
180		n = atoi( portname );
181		if( n <= 0 ){
182			servent = getservbyname( portname, "udp" );
183			if( servent ){
184				n = ntohs( servent->s_port );
185			}
186		}
187		if( n <= 0 ){
188			FPRINTF( STDERR, "udp_open: bad port number '%s'\n",portname );
189			usage();
190		}
191		port_num = n;
192	}
193
194	if( !use_tcp && !use_udp ) use_udp = 1;
195	if( debug ){
196		FPRINTF(STDERR,"monitor: udp %d, tcp %d, port %d\n",
197			use_udp, use_tcp, port_num );
198	}
199
200	max_port = 0;
201	FD_ZERO( &readfds );
202	if( use_udp && (udp_fd = udp_open( port_num )) >= 0){
203		if( debug ) FPRINTF(STDERR,"monitor: udp port %d\n", udp_fd );
204		FD_SET(udp_fd, &readfds);
205		if( udp_fd >= max_port ) max_port = udp_fd+1;
206	}
207	if( use_tcp && (tcp_fd = tcp_open( port_num )) >= 0){
208		if( debug ) FPRINTF(STDERR,"monitor: tcp port %d\n", tcp_fd );
209		FD_SET(tcp_fd, &readfds);
210		if( tcp_fd >= max_port ) max_port = tcp_fd+1;
211	}
212	if( debug ){
213		FPRINTF(STDERR,"monitor: max_port %d\n", max_port );
214		for( i = 0; i < max_port; ++i ){
215			if( FD_ISSET(i, &readfds) ){
216				FPRINTF(STDERR,"monitor: initial on %d\n", i );
217			}
218		}
219	}
220
221
222	while(1){
223		FD_ZERO( &testfds );
224		for( i = 0; i < max_port; ++i ){
225			if( FD_ISSET(i, &readfds) ){
226				if( debug ) FPRINTF(STDERR,"monitor: waiting on %d\n", i );
227				FD_SET(i, &testfds);
228			}
229		}
230		if( debug ) FPRINTF(STDERR,"monitor: starting wait, max %d\n", i );
231		n = select( i,
232			FD_SET_FIX((fd_set *))&testfds,
233			FD_SET_FIX((fd_set *))0, FD_SET_FIX((fd_set *))0,
234			(struct timeval *)0 );
235		err = errno;
236		if( debug ) FPRINTF(STDERR,"monitor: select returned %d\n", n );
237		if( n < 0 ){
238			FPRINTF( STDERR, "select error - %s\n", Errormsg(errno) );
239			if( err != EINTR ) break;
240		}
241		if( n > 0 ) for( i = 0; i < max_port; ++i ){
242			if( FD_ISSET(i, &testfds) ){
243				if( debug ) FPRINTF(STDERR,"monitor: input on %d\n", i );
244				if( i == tcp_fd ){
245#if defined(HAVE_SOCKLEN_T)
246					socklen_t len;
247#else
248					int len;
249#endif
250					struct sockaddr_in sinaddr;
251					len = sizeof( sinaddr );
252					i = accept( tcp_fd, (struct sockaddr *)&sinaddr, &len );
253					if( i < 0 ){
254						FPRINTF( STDERR, "accept error - %s\n",
255							Errormsg(errno) );
256						continue;
257					}
258					FPRINTF( STDOUT, "connection from %s\n",
259						inet_ntoa( sinaddr.sin_addr ) );
260					if( i >= max_port ) max_port = i+1;
261					FD_SET(i, &readfds);
262				} else {
263					c = read( i, buffer, sizeof(buffer)-1 );
264					if( c == 0 ){
265						/* closed connection */
266						FPRINTF(STDOUT, "closed connection %d\n", i );
267						close( i );
268						FD_CLR(i, &readfds );
269						Clear_buffer(i);
270					} else if( c > 0 ){
271						buffer[c] = 0;
272						if(debug)FPRINTF( STDOUT, "recv port %d: %s\n", i, buffer );
273						Add_buffer(i);
274						in = Save_outbuf_len( i, buffer, c );
275						while( (s = safestrchr(in->buffer,'\n')) ){
276							*s++ = 0;
277							Decode(in->buffer);
278							memmove(in->buffer,s, safestrlen(s)+1 );
279							in->len = safestrlen(in->buffer);
280						}
281					} else {
282						FPRINTF( STDERR, "read error - %s\n",
283							Errormsg(errno) );
284						close( i );
285						FD_CLR(i, &readfds );
286					}
287				}
288			}
289		}
290	}
291	return(0);
292}
293
294void Decode( char *in )
295{
296	struct line_list l, cf, info;
297	char *s, *t, *header, *value;
298	int i;
299
300	Init_line_list(&l);
301	Init_line_list(&cf);
302	Init_line_list(&info);
303
304	FPRINTF(STDOUT,"****\n");
305	if( debug )FPRINTF(STDOUT, "Decode: %s\n", in );
306	if((s = safestrpbrk(in,Value_sep)) ){
307		*s++ = 0;
308		Unescape(s);
309		Free_line_list(&l);
310		Split(&l,s,Line_ends,1,Value_sep,1,1,1,0);
311		for( i = 0; i < l.count; ++i ){
312			t = l.list[i];
313			if( debug || safestrncasecmp(t,VALUE,5) ){
314				FPRINTF(STDOUT,"%s\n", t );
315			}
316		}
317		s = Find_str_value(&l,VALUE,Value_sep);
318		if( s ) Unescape(s);
319		if( !safestrcasecmp(in,TRACE) ){
320			FPRINTF(STDOUT,"TRACE: '%s'\n", s );
321		} else if( !safestrcasecmp(in,UPDATE) ){
322			FPRINTF(STDOUT,"UPDATE: '%s'\n", s );
323			Split(&info,s,Line_ends,0,0,0,0,0,0);
324			for( i = 0; i < info.count; ++i ){
325				header = info.list[i];
326				if( (value = safestrchr(header,'=')) ) *value++ = 0;
327				Unescape(value);
328				FPRINTF(STDOUT," [%d] %s='%s'\n", i, header, value );
329			}
330		} else if( !safestrcasecmp(in,PRSTATUS) ){
331			FPRINTF(STDOUT,"PRSTATUS: '%s'\n", s );
332		} else if( !safestrcasecmp(in,QUEUE) ){
333			FPRINTF(STDOUT,"QUEUE: '%s'\n", s );
334			Split(&info,s,Line_ends,0,0,0,0,0,0);
335			for( i = 0; i < info.count; ++i ){
336				header = info.list[i];
337				if( (value = safestrchr(header,'=')) ) *value++ = 0;
338				Unescape(value);
339				FPRINTF(STDOUT," [%d] %s='%s'\n", i, header, value );
340			}
341			Free_line_list(&info);
342		} else if( !safestrcasecmp(in,DUMP) ){
343			FPRINTF(STDOUT,"DUMP:\n");
344			Split(&info,s,Line_ends,0,0,0,0,0,0);
345			for( i = 0; i < info.count; ++i ){
346				header = info.list[i];
347				if( (value = safestrchr(header,'=')) ) *value++ = 0;
348				Unescape(value);
349				if(debug) FPRINTF(STDOUT," [%d] %s='%s'\n", i, header, value );
350				if( !safestrcasecmp(header,QUEUE) ){
351					FPRINTF(STDOUT," EXTRACT QUEUE '%s'\n",value);
352				} else if( !safestrcasecmp(header,UPDATE) ){
353					FPRINTF(STDOUT," EXTRACT UPDATE '%s'\n",value);
354				} else {
355					FPRINTF(STDOUT," EXTRACT '%s' '%s'\n",header, value);
356				}
357			}
358			Free_line_list(&info);
359		} else {
360			FPRINTF(STDOUT,"%s: '%s'\n", in, s );
361		}
362	}
363	Free_line_list(&l);
364	Free_line_list(&cf);
365	Free_line_list(&info);
366	FPRINTF(STDOUT,"\n");
367}
368int udp_open( int port )
369{
370	int i, fd, err;
371	struct sockaddr_in sinaddr;
372
373	sinaddr.sin_family = AF_INET;
374	sinaddr.sin_addr.s_addr = INADDR_ANY;
375	sinaddr.sin_port = htons( port );
376
377	fd = socket( AF_INET, SOCK_DGRAM, 0 );
378	Max_open(fd);
379	err = errno;
380	if( fd < 0 ){
381		FPRINTF(STDERR,"udp_open: socket call failed - %s\n", Errormsg(err) );
382		return( -1 );
383	}
384	i = -1;
385	i = bind( fd, (struct sockaddr *) & sinaddr, sizeof (sinaddr) );
386	err = errno;
387
388	if( i < 0 ){
389		FPRINTF(STDERR,"udp_open: bind to '%s port %d' failed - %s\n",
390			inet_ntoa( sinaddr.sin_addr ), ntohs( sinaddr.sin_port ),
391			Errormsg(errno) );
392		close(fd);
393		fd = -1;
394	}
395	if( fd == 0 ){
396		fd = dup(fd);
397		if( fd < 0 ){
398			FPRINTF(STDERR,"udp_open: dup failed - %s\n",
399				Errormsg(errno) );
400			close(fd);
401			fd = -1;
402		}
403	}
404	return( fd );
405}
406
407
408int tcp_open( int port )
409{
410	int i, fd, err;
411	struct sockaddr_in sinaddr;
412
413	sinaddr.sin_family = AF_INET;
414	sinaddr.sin_addr.s_addr = INADDR_ANY;
415	sinaddr.sin_port = htons( port );
416
417	fd = socket( AF_INET, SOCK_STREAM, 0 );
418#ifdef WINDOW_1
419int windowsize=1024;
420setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&windowsize, sizeof(windowsize));
421aaaaaa=fopen("/tmp/qqqqq", "a");
422fprintf(aaaaaa, " monitor: tcp_send\n");
423fclose(aaaaaa);
424#endif
425	Max_open(fd);
426	err = errno;
427	if( fd < 0 ){
428		FPRINTF(STDERR,"tcp_open: socket call failed - %s\n", Errormsg(err) );
429		return( -1 );
430	}
431	i = Link_setreuse( fd );
432	if( i >= 0 ) i = bind( fd, (struct sockaddr *) & sinaddr, sizeof (sinaddr) );
433	if( i >= 0 ) i = listen( fd, 10 );
434	err = errno;
435
436	if( i < 0 ){
437		FPRINTF(STDERR,"tcp_open: connect to '%s port %d' failed - %s\n",
438			inet_ntoa( sinaddr.sin_addr ), ntohs( sinaddr.sin_port ),
439			Errormsg(errno) );
440		close(fd);
441		fd = -1;
442	}
443	if( fd == 0 ){
444		fd = dup(fd);
445		if( fd < 0 ){
446			FPRINTF(STDERR,"tcp_open: dup failed - %s\n",
447				Errormsg(errno) );
448			close(fd);
449			fd = -1;
450		}
451	}
452	return( fd );
453}
454