1 /**************************************************************************************************
2 	$Header: /pub/cvsroot/yencode/src/ypost/sock.c,v 1.2 2002/03/21 04:58:31 bboy Exp $
3 
4 	Copyright (C) 2002  Don Moore <bboy@bboy.net>
5 
6 	This program is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 2 of the License, or
9 	(at Your option) any later version.
10 
11 	This program is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with this program; if not, write to the Free Software
18 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 **************************************************************************************************/
20 
21 
22 #include "ypost.h"
23 
24 
25 /* Current socket operation being performed (for timeout handler). */
26 static char *current_operation;
27 
28 /* Macro to start a timeout condition block. */
29 #define START_TIMEOUT(s) \
30 	if (opt_timeout) { \
31 		current_operation = s; \
32 		signal(SIGALRM, sock_timeout_handler); \
33 		alarm(opt_timeout); \
34 	}
35 
36 /* Macro to stop a timeout condition block. */
37 #define STOP_TIMEOUT \
38 	if (opt_timeout) { \
39 		signal(SIGALRM, SIG_DFL); \
40 		alarm(0); \
41 	}
42 
43 /* Read buffers grow by this many bytes at a time. */
44 #define BUFFER_INCREMENT 128
45 
46 /* Current FD if sock_setfd() is used. */
47 int _sock_current_fd = -1;
48 
49 #define	Y_SOCKDEBUG_SEND	0
50 #define	Y_SOCKDEBUG_RECV	1
51 
52 
53 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
54 	SOCKDEBUG
55 	If debug is enabled, this will output the data sent or received, hiding wierd control chars
56 	and converting CR and LF to '\r' and '\n'.
57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
58 static void
sockdebug(int direction,unsigned char * buf,size_t buflen)59 sockdebug(int direction, unsigned char *buf, size_t buflen)
60 {
61 	register int ct;
62 
63 	if (!buf)
64 		return;
65 
66 	if (direction == Y_SOCKDEBUG_RECV)
67 		fputs("[DEBUG]  IN: `", stderr);
68 	else
69 		fputs("[DEBUG] OUT: `", stderr);
70 
71 	for (ct = 0; ct < buflen; ct++)
72 	{
73 		if (buf[ct] == CR)
74 		{
75 			fputc('\\', stderr);
76 			fputc('r', stderr);
77 		}
78 		else if (buf[ct] == LF)
79 		{
80 			fputc('\\', stderr);
81 			fputc('n', stderr);
82 		}
83 //		else if (iscntrl(buf[ct]))
84 //			fputc('?', stderr);
85 		else
86 			fputc(buf[ct], stderr);
87 	}
88 	fputc('\'', stderr);
89 	fputc('\n', stderr);
90 	fflush(stderr);
91 }
92 /*--- sockdebug() -------------------------------------------------------------------------------*/
93 
94 
95 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
96 	SOCK_TIMEOUT_HANDLER
97 	Called if socket operations time out.
98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
99 void
sock_timeout_handler(int signo)100 sock_timeout_handler(int signo)
101 {
102 	Err("%s: %s\n", current_operation ? current_operation : _("socket operation"),
103 		 _("specified timeout exceeded"));
104 	exit(EXIT_FAILURE);
105 }
106 /*--- sock_timeout_handler() --------------------------------------------------------------------*/
107 
108 
109 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
110 	Given a host and port, which should be specified in the format "host:port", constructs and
111 	returns a sockaddr_in record.
112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
113 struct sockaddr_in *
sock_getsockaddr(char * address)114 sock_getsockaddr(char *address)
115 {
116 	static struct sockaddr_in sa;								// Socket structureA
117 	struct servent *ent;											// Service entry
118 	struct hostent *he;											// Host entry
119 	char *hostname, *portname;									// Host and port part of `hostport'
120 
121 	memset(&sa, 0, sizeof(struct sockaddr_in));        // Reset socket structure
122 	sa.sin_family = AF_INET;
123 	portname = address;
124 	hostname = strsep(&portname, ":");
125 	if (!hostname)
126 		Err("%s: %s", address, _("invalid server name"));
127 
128 	if (portname)
129 		sa.sin_port = htons(atoi(portname));
130 	else
131 	{
132 		START_TIMEOUT(_("service entry lookup"));
133 		if (!(ent = getservbyname("nntp", "tcp")))
134 			Err(_("unable to get default port for service `nntp/tcp'"));
135 		STOP_TIMEOUT;
136 		sa.sin_port = ent->s_port;
137 	}
138 
139 	START_TIMEOUT(_("server name resolution"));
140 	if (!(he = gethostbyname(hostname)))
141 		Err("%s: %s", address, _("unable to resolve server address"));
142 	STOP_TIMEOUT;
143 
144 	memcpy(&sa.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
145 	return (&sa);
146 }
147 /*--- sock_getsockaddr() ------------------------------------------------------------------------*/
148 
149 
150 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
151 	Opens a connection to the specified address.  Returns the new file descriptor.  Errors fatal.
152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
153 int
sock_open(struct sockaddr_in * sa)154 sock_open(struct sockaddr_in *sa)
155 {
156 	int fd;															// File descriptor of new socket
157 	int rv;															// Return value from connect
158 
159 	START_TIMEOUT(_("socket creation"));
160 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)		// Create socket
161 		ErrERR(_("error creating socket"));
162 	STOP_TIMEOUT;
163 
164 	START_TIMEOUT(_("socket connection"));
165 	while ((rv = connect(fd, (struct sockaddr *)sa, sizeof(struct sockaddr_in))) != 0)
166 	{
167 		if (errno == EAGAIN)
168 			continue;
169 		else
170 			ErrERR(_("error connecting to server"));
171 	}
172 	STOP_TIMEOUT;
173 	return (fd);
174 }
175 /*--- sock_open() -------------------------------------------------------------------------------*/
176 
177 
178 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
179 	SOCK_READ_FD
180 	Reads from the socket, obeying timeout.  Returns number of bytes read.
181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
182 ssize_t
sock_read_fd(int fd,unsigned char * buf,size_t count)183 sock_read_fd(int fd, unsigned char *buf, size_t count)
184 {
185 	int  rv;															// Return value from read()
186 
187 	memset(buf, 0, count);										// XXX Is this necessary?
188 
189 	START_TIMEOUT(_("socket read"));
190 	rv = read(fd, buf, count);
191 	STOP_TIMEOUT;
192 
193 	if (rv < 0)														// Will this fail falsely on EAGAIN?
194 		ErrERR(_("error reading from socket"));
195 
196 	return (rv);
197 }
198 /*--- sock_read_fd() ----------------------------------------------------------------------------*/
199 
200 
201 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
202 	SOCK_GETS_FD
203 	Reads from the specified descriptor until '\n' is read.  Returns a pointer to a dynamically
204 	allocated buffer, which should be free()'d when no longer needed.
205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
206 unsigned char *
sock_gets_fd(int fd)207 sock_gets_fd(int fd)
208 {
209 	int rv;															// Return value from select
210 	int offset = 0;												// Number of characters read
211 	int buflen = 0;												// Current size of input buffer
212 	unsigned char *buf;											// Input buffer
213 
214 	// Start our input buffer off
215 	buf = (unsigned char *)xmalloc(BUFFER_INCREMENT, 1);
216 	memset(buf, 0, BUFFER_INCREMENT);
217 	buflen = BUFFER_INCREMENT;
218 
219 	for (;;)
220 	{
221 		START_TIMEOUT(_("socket read"));
222 		if (!(rv = sock_read_fd(fd, buf + offset, 1)))		// Read one char at a time
223 			Err(_("connection closed by remote"));
224 		STOP_TIMEOUT;
225 
226 		if (buf[offset] == LF)										// Are we done?
227 			break;
228 
229 		// Grow the buffer if necessary
230 		if (++offset == buflen - 1)
231 		{
232 			buf = xrealloc(buf, buflen + BUFFER_INCREMENT);
233 			memset(buf + buflen, 0, BUFFER_INCREMENT);
234 			buflen += BUFFER_INCREMENT;
235 		}
236 	};
237 
238 	if (opt_debug)
239 		sockdebug(Y_SOCKDEBUG_RECV, buf, strlen(buf));
240 
241 	while ((buf[offset] == CR) || (buf[offset] == LF))
242 		buf[offset--] = (unsigned char)'\0';
243 
244 	return (buf);
245 }
246 /*--- sock_gets_fd() ----------------------------------------------------------------------------*/
247 
248 
249 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
250 	SOCK_WRITE_FD
251 	Writes to the socket, obeying timeout.
252 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
253 void
sock_write_fd(int fd,const unsigned char * buf,int count)254 sock_write_fd(int fd, const unsigned char *buf, int count)
255 {
256 	int  offset = 0;												// Number of bytes written
257 	int  rv;															// Return value from write()
258 
259 	do
260 	{
261 		START_TIMEOUT(_("socket write"));
262 		rv = write(fd, buf + offset, count - offset);
263 		STOP_TIMEOUT;
264 		if (rv == 0)
265 			Err(_("connection closed by remote"));
266 		if (rv < 0)
267 		{
268 			if (errno == EAGAIN)
269 				continue;
270 			Err(_("error writing to socket"));
271 		}
272 		if (opt_debug)
273 			sockdebug(Y_SOCKDEBUG_SEND, (unsigned char *)(buf+offset), rv);
274 		offset += rv;
275 
276 	} while (offset < count);
277 }
278 /*--- sock_write_fd() ---------------------------------------------------------------------------*/
279 
280 
281 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
282 	SOCK_PUTS_FD
283 	Writes a line to the descriptor.  Appends CR/LF if necessary.
284 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
285 void
sock_puts_fd(int fd,const unsigned char * data)286 sock_puts_fd(int fd, const unsigned char *data)
287 {
288 	int datalen = strlen(data);
289 
290 	if (!strstr(data, CRLF))										// Append CR/LF if necessary
291 	{
292 		unsigned char *buf;
293 
294 		buf = (unsigned char *)xmalloc((datalen + 3) * sizeof(unsigned char));
295 		memcpy(buf, data, datalen);
296 		buf[datalen] = CR;
297 		buf[datalen+1] = LF;
298 		buf[datalen+2] = (unsigned char)'\0';
299 		sock_write_fd(fd, buf, datalen + 2);
300 		free(buf);
301 	}
302 	else
303 		sock_write_fd(fd, data, datalen);
304 }
305 /*--- sock_puts_fd() ----------------------------------------------------------------------------*/
306 
307 
308 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
309 	SOCK_PRINTF
310 	Only works if _sock_current_fd is set.
311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
312 void
sock_printf(const char * fmt,...)313 sock_printf(const char *fmt, ...)
314 {
315 	va_list	ap;
316 	size_t	len;
317 	unsigned char buf[BUFSIZ];
318 	unsigned char *outbuf;
319 	register unsigned char *i, *o;
320 
321 	if (_SOCK_CURRENT_FD == -1)
322 		Err(_("unable to write; not connected to remote server"));
323 
324 	va_start(ap, fmt);
325 	len = vsnprintf(buf, sizeof(buf)-4, fmt, ap);
326 	va_end(ap);
327 
328 	/* Remove CR, convert LF to CRLF */
329 	outbuf = (unsigned char *)xmalloc(((len * 2) + 1) * sizeof(unsigned char));
330 	for (i = buf, o = outbuf; *i; i++)
331 	{
332 		if (*i == CR)
333 			continue;
334 		else if (*i == LF)
335 		{
336 			*(o++) = CR;
337 			*(o++) = LF;
338 		}
339 		else
340 			*(o++) = *i;
341 	}
342 	*o = '\0';
343 	sock_puts_fd(_SOCK_CURRENT_FD, outbuf);
344 	free(outbuf);
345 }
346 /*--- sock_printf() -----------------------------------------------------------------------------*/
347 
348 
349 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
350 	SOCK_PUTS_METER_FD
351 	Writes a line to the descriptor, displaying a meter.  Appends CR/LF if necessary.
352 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
353 long
sock_puts_meter_fd(int fd,const unsigned char * buf,long current,long total,const char * desc)354 sock_puts_meter_fd(int fd, const unsigned char *buf, long current, long total, const char *desc)
355 {
356 	int datalen = strlen(buf);									// Length of data to write
357 	unsigned char *data = NULL;								// The data to send
358 	register int  offset = 0;									// Number of bytes written
359 	int  rv;															// Return value from write()
360 
361 	if (!strstr(buf, CRLF))										// Append CR/LF if necessary
362 	{
363 		data = (unsigned char *)xmalloc((datalen + 3) * sizeof(unsigned char));
364 		memcpy(data, buf, datalen);
365 		data[datalen] = CR;
366 		data[datalen+1] = LF;
367 		data[datalen+2] = (unsigned char)'\0';
368 		datalen += 2;
369 	}
370 	else
371 		data = (unsigned char *)xstrdup(buf);
372 
373 	/* Write the data */
374 	do
375 	{
376 		START_TIMEOUT(_("socket write"));
377 		rv = write(fd, data + offset, datalen - offset);
378 		STOP_TIMEOUT;
379 		if (rv == 0)
380 			Err(_("connection closed by remote"));
381 		if (rv < 0)
382 		{
383 			if (errno == EAGAIN)
384 				continue;
385 			Err(_("error writing to socket"));
386 		}
387 		if (opt_debug)
388 			sockdebug(Y_SOCKDEBUG_SEND, (unsigned char *)(data+offset), rv);
389 		offset += rv;
390 		meter(current + offset, total, desc);
391 	} while (offset < datalen);
392 
393 	free(data);
394 	return (offset);
395 }
396 /*--- sock_puts_fd() ----------------------------------------------------------------------------*/
397 
398 
399 /* vi:set ts=3: */
400