File: wserv.c

package info (click to toggle)
epic5 3.0.3-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 5,328 kB
  • sloc: ansic: 75,810; makefile: 648; ruby: 227; python: 215; sh: 78; perl: 13
file content (331 lines) | stat: -rw-r--r-- 8,881 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * wserv.c -- A little program to act as a pipe between the ircII process
 * 	      and an xterm window or GNU screen.
 * Version 1 - Classic ircII wserv, Used Unix sockets, took /tmp/irc_xxxxxx arg
 * Version 2 - Circa 1997 EPIC, supported 4.4BSD Unix sockets as well
 * Version 3 - Circa 1998 EPIC, Used TCP sockets
 * Version 4 - Circa 1999 EPIC, Seperate Data and Command TCP sockets.
 *
 * Copyright (c) 1992 Troy Rollo.
 * Copyright (c) 1993 Matthew Green.
 * Copyright 1995-2002 EPIC Software Labs
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notices, the above paragraph (the one permitting redistribution),
 *    this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the distribution.
 * 3. The names of the author(s) may not be used to endorse or promote 
 *    products derived from this software without specific prior written
 *    permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */

#define WSERV_C
#define CURRENT_WSERV_VERSION 	4

#include "defs.h"
#include "config.h"
#include "irc_std.h"
#include <sys/ioctl.h>
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#else
# ifdef HAVE_SYS_TERMIOS_H
#  include <sys/termios.h>
# endif
#endif


static 	int 	data = -1;
static	int	cmd = -1;
static	char	buffer[256];
static	int	got_sigwinch = 0;
static	int	tty_des;
static	struct termios	oldb, newb;

static	void 	my_exit(int);
static	void 	ignore (int);
static	void	sigwinch_func (int);
static	int 	term_init (void);
static	void 	term_resize (void);
	void	yell (const char *format, ...);
static	int	connectory (const char *, const char *);


int	main (int argc, char **argv)
{
	fd_set	reads;
	int	nread;
	char * 	port;
	char *	host;
	char *	tmp;
	char	stuff[100];

	my_signal(SIGHUP, SIG_IGN);
	my_signal(SIGQUIT, SIG_IGN);
	my_signal(SIGINT, ignore);
	my_signal(SIGWINCH, sigwinch_func);

	if (argc != 3)    		/* no socket is passed */
		my_exit(1);

	host = argv[1];
	port = argv[2];

	if ((data = connectory(host, port)) < 0)
		my_exit(23);

	if ((cmd = connectory(host, port)) < 0)
		my_exit(25);

	/*
	 * First thing we do is tell the parent what protocol we plan on
	 * talking.  We will start the protocol at version 4, for this is
	 * the fourth generation of wservs.
	 *
	 * We cannot use 'snprintf' here because we do not have the compat
	 * functions and some systems do not have snprintf!  This use of
	 * sprintf is demonstrably safe.
	 */
#ifdef HAVE_SNPRINTF
	snprintf(stuff, sizeof(stuff), "version=%d\n", CURRENT_WSERV_VERSION);
#else
	sprintf(stuff, "version=%d\n", CURRENT_WSERV_VERSION);
#endif
	if (!write(cmd, stuff, strlen(stuff))) 
		(void) 0;

	/*
	 * Next thing we take care of is to tell the parent client
	 * what tty we are using and tell them what geometry our screen
	 * is.  This provides some amount of sanity against whatever
	 * brain damage might occur.  The parent client takes our word
	 * for what size this screen should be, and handles it accordingly.
	 *
	 * Warning:  I am using sprintf() and write() because previous
	 * attempts to use writev() have shown that linux does not have
	 * an atomic writev() function (boo, hiss).  The parent client
	 * does not take kindly to this data coming in multiple packets.
	 *
	 * Again, we use sprintf() here because we can't be guaranteed
	 * that snprintf() is available in this program.  So I do the 
	 * length check first, and fail if it would overrun.
	 */
	tmp = ttyname(0);
	if (strlen(tmp) > 90)
		my_exit(90);
#ifdef HAVE_SNPRINTF
	snprintf(stuff, sizeof(stuff), "tty=%s\n", tmp);
#else
	sprintf(stuff, "tty=%s\n", tmp);
#endif
	if (!write(cmd, stuff, strlen(stuff))) 
		(void) 0;

	term_init();		/* Set up the xterm */
	term_resize();		/* Figure out how big xterm is and tell epic */

	/*
	 * The select call..  reads from the socket, and from the window..
	 * and pipes the output from out to the other..  nice and simple.
	 * The command pipe is write-only.  The parent client does not
	 * send anything to us over the command pipe.
	 */
	for (;;)
	{
		FD_ZERO(&reads);
		FD_SET(0, &reads);
		FD_SET(data, &reads);
		if (select(data + 1, &reads, NULL, NULL, NULL) <= 0)
		{
			if (errno == EINTR && got_sigwinch)
			{
				got_sigwinch = 0;
				term_resize();
			}
			continue;
		}

		if (FD_ISSET(0, &reads))
		{
			if ((nread = read(0, buffer, sizeof(buffer))) > 0)
			{
				if (!write(data, buffer, nread)) 
					(void) 0;
			}
			else
				my_exit(3);
		}
		if (FD_ISSET(data, &reads))
		{
			if ((nread = read(data, buffer, sizeof(buffer))) > 0)
			{
				if (!write(0, buffer, nread)) 
					(void) 0;
			}
			else
				my_exit(4);
		}
	}

	my_exit(8);
}

static void 	ignore (int value)
{
	/* send a ^C */
	char foo = 3;
	if (!write(data, &foo, 1)) 
		(void) 0;
}

static void	sigwinch_func (int value)
{
	got_sigwinch = 1;
}

static void 	my_exit(int value)
{
	printf("exiting with %d!\n", value);
	printf("errno is %d (%s)\n", errno, strerror(errno));
	exit(value);
}


static int	connectory (const char *host, const char *port)
{
	AI	hints;
	AI *	results;
	int 	retval;
	int	s;

	memset(&hints, 0, sizeof(hints));
	hints.ai_flags = 0;
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;

	if ((retval = getaddrinfo(host, port, &hints, &results))) {
	    yell("getaddrinfo(%s): %s", host, gai_strerror(retval));
	    my_exit(6);
	}

	if ((s = socket(results->ai_family, results->ai_socktype, results->ai_protocol)) < 0) {
	    yell("socket(%s): %s", host, gai_strerror(retval));
	    my_exit(6);
	}

	if (connect(s, results->ai_addr, results->ai_addrlen) < 0) {
	    yell("connect(%s): %s", host, strerror(errno));
	    my_exit(6);
	}

	freeaddrinfo(results);
	return s;
}


/*
 * term_init: does all terminal initialization... sets the terminal to 
 * CBREAK, no ECHO mode.    (Maybe should set RAW mode?)
 */
static int 	term_init (void)
{
	/* Set up the terminal discipline */
	tty_des = 0;			/* Has to be. */
	tcgetattr(tty_des, &oldb);

	newb = oldb;
	newb.c_lflag &= ~(unsigned int)(ICANON | ECHO); /* set equ. of CBREAK, no ECHO */
	newb.c_cc[VMIN] = 1;	          /* read() satified after 1 char */
	newb.c_cc[VTIME] = 0;	          /* No timer */

#       if !defined(_POSIX_VDISABLE)
#               if defined(HAVE_FPATHCONF)
#                       define _POSIX_VDISABLE fpathconf(tty_des, _PC_VDISABLE)
#               else
#                       define _POSIX_VDISABLE 0
#               endif
#       endif

	newb.c_cc[VQUIT] = _POSIX_VDISABLE;
#	ifdef VDSUSP
		newb.c_cc[VDSUSP] = _POSIX_VDISABLE;
# 	endif
#	ifdef VSUSP
		newb.c_cc[VSUSP] = _POSIX_VDISABLE;
#	endif

	newb.c_iflag &= ~(unsigned long)(IXON | IXOFF); /* No XON/XOFF */
	tcsetattr(tty_des, TCSADRAIN, &newb);
	return 0;
}


/*
 * term_resize: gets the terminal height and width.  Trys to get the info
 * from the tty driver about size, if it can't... it punts.  If the size
 * has changed, it tells the parent client about the change.
 */
static void 	term_resize (void)
{
	static	int	old_li = -1,
			old_co = -1;
	struct winsize window;

#if !defined (TIOCGWINSZ)
	return;
#endif

	if (ioctl(tty_des, TIOCGWINSZ, &window) < 0)
		return;		/* *Shrug* What can we do? */

	if (window.ws_row == 0 || window.ws_col == 0)
		return;		/* Ugh.  Bummer. */

	window.ws_col--;

	if ((old_li != window.ws_row) || (old_co != window.ws_col))
	{
		old_li = window.ws_row;
		old_co = window.ws_col;
#ifdef HAVE_SNPRINTF
		snprintf(buffer, sizeof(buffer), "geom=%d %d\n", old_li, old_co);
#else
		sprintf(buffer, "geom=%d %d\n", old_li, old_co);
#endif
		if (!write(cmd, buffer, strlen(buffer))) 
			(void) 0;
	}
}

void	yell (const char *format, ...)
{
        if (format)
        {
                va_list args;
                va_start(args, format);
		vfprintf(stderr, format, args);
		sleep(5);
		my_exit(4);
        }
}

/* End of file */