1 /* $Id: talktcp.c,v 1.12 2006/09/16 02:21:26 jared Exp $ */
2 #include "config.h"
3 
4 extern struct clientstatus *clienthead;
5 
6 /* handle sig pipes instead of killing process */
7 void
handle_sig_pipe()8 handle_sig_pipe()
9 {
10 }
11 
is_open(int fd)12 int is_open(int fd)
13 /* check to see if the socket is ready for IO -- usually called once
14    open_host returns 10 (Connection in progress)  It will return
15    if there is an error such as connection refused, conn timed out,
16    otherwise it returns 10 if the socket is not connected yet */
17 {
18 	int vals = -1, size = 0;
19 	unsigned int optval = 0;
20 	int serrno = 0; /* saved errno */
21 
22 	size = sizeof(optval);
23 
24 	errno = 0;
25 
26 	/* check socket for error */
27 	vals = getsockopt(fd, SOL_SOCKET, SO_ERROR,  (void*)&optval, &size);
28 
29         serrno = optval;
30 
31 	if (vals == -1)
32 	{
33 		errno = serrno;
34 		if (debug)
35 			perror("is_open:getsockopt");
36 	}
37 
38 	if (serrno != 0)
39 		switch(serrno)
40 		{
41 			case ECONNREFUSED:
42 			case EINTR:
43 				return SYSM_CONNREF;
44 			case ENETUNREACH:
45 				return SYSM_NETUNRCH;
46 			case EHOSTDOWN:
47 			case EHOSTUNREACH:
48 				return SYSM_HOSTDOWN;
49 			case ETIMEDOUT:
50 				return SYSM_TIMEDOUT;
51 			case EINPROGRESS:
52 				return SYSM_INPROG;
53 			case EBADF:
54 				return -1;
55 			default:
56 				perror("is_open:getsockopt");
57 				break;
58 		}
59 
60 	/* check socket for connection */
61 	vals = can_write(fd,0);
62 	if (vals == 1)
63 		return SYSM_OK;
64 
65 	if (debug)
66 		print_err(0, "can_write returned %d", vals);
67 
68 	if (vals == -1)
69 	{
70 		print_err(0, "error checking socket for data");
71 		return -1;
72 	}
73 
74 	errno = 0;
75         /* check socket for error */
76         vals = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*) &optval, &size);
77 #ifdef __svr4__
78         serrno = errno;
79 #endif
80 #ifndef __svr4__
81         serrno = optval;
82 #endif
83         if (vals == -1)
84                 perror("getsockopt");
85 
86         if (vals == 0)
87                 return -1;
88 
89         if (serrno != 0)
90 		switch(serrno)
91 		{
92 			case ECONNREFUSED:
93 			case EINTR:
94 				close(fd);
95                         	return SYSM_CONNREF;
96 			case ENETUNREACH:
97 				close(fd);
98                         	return SYSM_NETUNRCH;
99                 	case EHOSTDOWN:
100 			case EHOSTUNREACH:
101 				close(fd);
102                         	return SYSM_HOSTDOWN;
103 			case ETIMEDOUT:
104 				close(fd);
105 				return SYSM_TIMEDOUT;
106 			case EINPROGRESS:
107 				return SYSM_INPROG;
108 			case EBADF:
109 				close(fd);
110 				return -1;
111 			default:
112 				close(fd);
113 				perror("getsockopt");
114 				break;
115                 }
116 
117 	/* return 0 if socket ok to do I/O */
118         vals = can_write(fd,0);
119 
120 	if (debug)
121 		print_err(0, "talktcp.c:can_write returned %d", vals);
122 
123         if ( vals == TRUE )
124                 return SYSM_OK;
125 
126 	return SYSM_INPROG; /* connection still in progress */
127 }
128 
129 /*
130  * sends the specified line out the specified filedescriptor -- we add
131  * cr and newline to the end.  return: bytes written out socket
132  */
sendline(int fd,char * buffer)133 int sendline(int fd, char *buffer)
134 {
135 	int val = -1;
136 	char *space;
137 
138 	signal(SIGPIPE, handle_sig_pipe); /* set signal handler if there is
139 			a problem */
140 	space = MALLOC(strlen(buffer)+3, "sendline-temp buffer"); /* allocate memory for buffer */
141 	memset(space, 0, strlen(buffer)+3);
142 	strncpy(space, buffer, strlen(buffer)); /* copy stuff to temp buffer */
143 	strncat(space, "\r\n", 2); /* add end stuff */
144 	val = write(fd, space, strlen(space)/* - test - jared +1 */);
145 	if (val == -1)
146 	{
147 		perror("sendline:write");
148 	}
149 	signal(SIGPIPE, SIG_DFL); /* set signal type back to default */
150 	FREE(space); /* free the memory */
151 	return val; /* return the number of bytes written */
152 }
153 
can_write(int fd,int secs)154 int can_write(int fd, int secs)
155 {
156         /* check the descriptor fd for pending data -- wait up to 'secs'
157                 seconds for data, else return a timeout (FALSE)
158          */
159         fd_set rd, wr, except;
160         struct timeval local_timeout;
161 
162         int ret = 0;
163 
164         /* set up all the data structures */
165         FD_ZERO(&wr);
166         FD_ZERO(&except);
167         FD_ZERO(&rd);
168         FD_SET(fd, &wr);
169         local_timeout.tv_sec = secs;
170         local_timeout.tv_usec = 0;
171         /* done */
172 
173         ret = select(fd+1, &rd, &wr, &except, &local_timeout);
174         if (ret < 0)
175         {
176 		if (debug)
177 		{
178 	                perror("talktcp.c:can_write:select");
179 		}
180                 return -1;
181         }
182 
183         if (ret == 0) /* if timelimit exceeded */
184                 return FALSE;
185 
186         /* else, there is data waiting in this socket */
187         return TRUE;
188 }
189 
data_waiting_read(int fd,int secs)190 int data_waiting_read(int fd, int secs)
191 {
192 	/* check the descriptor fd for pending data -- wait up to 'secs'
193 		seconds for data, else return a timeout (FALSE)
194 	 */
195 	fd_set rd, wr, except;
196 	struct timeval local_timeout;
197 
198 	int ret = 0;
199 
200 	/* set up all the data structures */
201 	FD_ZERO(&wr);
202 	FD_ZERO(&except);
203 	FD_ZERO(&rd);
204 	FD_SET(fd, &rd);
205 	local_timeout.tv_sec = secs;
206 	local_timeout.tv_usec = 0;
207 	/* done */
208 
209 	ret = select(fd+1, &rd, &wr, &except, &local_timeout);
210 	if (ret < 0)
211 	{
212 		if (debug)
213 		{
214 			perror("talktcp.c:data_waiting_read:select");
215 		}
216 		return -1;
217 	}
218 
219 	if (ret == 0) /* if timelimit exceeded */
220 		return FALSE;
221 
222 	/* else, there is data waiting in this socket */
223 	return TRUE;
224 }
225 
getline_tcp(int fd,char * buffer)226 int getline_tcp(int fd, char *buffer)
227 {
228         char buf; /* buffer */
229         int red = 0; /* bytes read */
230 	int counter = 0;
231 	int selTimeout = 0;
232 	int ret = 0;
233 
234 	/* Null it out */
235 	memset(buffer, 0, sizeof(buffer));
236 
237         while ( 1 ) /* while forever */
238         {
239 		if (clienthead == NULL)
240 		{
241 			ret = data_waiting_read(fd, 1);
242 		} else if (clienthead->filedes == -1)
243 		{
244 			ret = data_waiting_read(fd, 1);
245 		} else {
246 			ret = data_waiting_read(fd, 0);
247 		}
248 
249 		if (ret == -1) /* if an error */
250 		{
251 			selTimeout++;
252 			if (selTimeout > 20) /* if we've waited too long */
253 			{
254 				if (debug)
255 				print_err(0, "Timeout REACHED-selTimeout");
256 				return 0; /* bail */
257 			}
258 
259 			if (clienthead->filedes == -1)
260 				continue;
261 
262 			continue; /* go along and try again */
263 		}
264 
265 		red = 0; /* init it */
266 		if (ret > 0) /* if there's data waiting */
267 		{
268 	                red = read(fd, &buf, 1);
269 		}
270 
271                 if (red == -1)
272 		{
273 			perror("talktcp.c:getline_tcp:read");
274                         return -1;
275 		}
276 
277                 if (red == 0)
278                 {
279 			counter++;
280 			if (counter > 20)
281 			{
282 				return -1; /* error */
283 			}
284                         continue;
285                 }
286         	if ((strlen(buffer) == 0) && ((buf == '\n') || (buf == '\r')))
287 		{
288 			continue; /* throw \r or \n if at beginning of line */
289 		}
290                 if ((buf == '\n') || (buf == '\r'))
291 		{
292                         return 0;
293 		}
294                 strncat(buffer, &buf, 1);
295 		if (strlen(buffer) > 200)
296 		{
297 			return 0;
298 		}
299         }
300 }
301 
302 /* this socket will be used for both sending and receiving */
open_host(char * host,int port,int * filedes,int ltimeout)303 int open_host(char *host, int port, int *filedes, int ltimeout)
304 {
305 	int fails = 0;
306         struct sockaddr_in name;
307         struct my_hostent *hp;
308         int errcode = -1;
309 	int serrno = 0 ;
310 	time_t start_time;
311 
312 	/* record current time */
313 	start_time = time(NULL);
314 
315 	/* open a filedescriptor to use */
316         *filedes = open_sock();
317 
318 	/* check for error */
319 	if (*filedes == -1)
320 	{
321 		/* try again.. maybe a fluke */
322 		*filedes = open_sock();
323 		if (*filedes == -1)
324 			return(-1); /* return error */
325 	}
326 
327 	/* get the data structure for the hostname */
328         hp = my_gethostbyname(host, AF_INET);
329 
330         if (hp == 0)
331 	{
332 		/* print an error if one happened */
333 		if (debug)
334 	                print_err(0, "%s: unknown host", host);
335                 return SYSM_NODNS;
336         }
337 
338 	/* zero out the space */
339         memset ( &name, 0, sizeof ( name ) );
340 
341 	/* copy data */
342         memcpy((char*)&name.sin_addr, (char*)hp->my_h_addr_v4, hp->h_length_v4);
343 
344 	/* set family type */
345         name.sin_family = AF_INET;
346 
347 	/* set the port we're connecting to */
348         name.sin_port = htons(port);
349 
350         /* try to make the connection */
351         while (1)
352 	{
353 		if (debug)
354 			print_err(0, "Calling connect() with fd = %d", *filedes);
355 
356                 errcode = connect(*filedes, (struct sockaddr*)&name,
357                                   sizeof(struct sockaddr_in));
358 		/* doesn't happen often, but can, so we must trap
359 		 * for it, duh! PR#34
360 		 */
361 
362 		if (errcode == 0)
363 			return SYSM_OK;
364 
365 		/* Save that error code so it doesn't get clobbered */
366 		serrno = errno;
367 
368 		if (debug)
369 			print_err(0, "serrno = %d, errcode = %d", serrno, errcode);
370 
371 		if ((errcode == -1) && (serrno == EINPROGRESS))
372 		{
373 			if (debug)
374 			{
375 				print_err(0, "talktcp.c:connection in progress");
376 			}
377 			break;
378 		} else if (errcode == -1) {
379 			perror("open_host:connect");
380 		}
381 
382                 if ((errcode == -1) && (serrno != EINPROGRESS))
383 		{
384 			if (close(*filedes) == -1)
385 			{
386 				return -1; /* close the fd incase it's left */
387 			}
388 			fails ++; /* failure my son */
389 
390 			switch(serrno)
391 			{
392 				case ECONNREFUSED:
393 				case EINTR:
394 					if (fails >= MAX_TRIES)
395 						return SYSM_CONNREF;
396                                 	*filedes = open_sock();
397 					break;
398 				case ENETUNREACH:
399 					return SYSM_NETUNRCH;
400 				case EHOSTDOWN:
401 				case EHOSTUNREACH:
402 					return SYSM_HOSTDOWN;
403 				case ETIMEDOUT:
404 					return SYSM_TIMEDOUT;
405 				default:
406 					break;
407                 	}
408 		}
409         }
410 
411 	if (serrno == EINPROGRESS)
412 	while (1)
413 	{
414 		errcode = is_open(*filedes);
415 		if (errcode == 0)
416 		{
417 			break;
418 		}
419 
420 		/* check to see if we should have timed out already */
421 		if (time(NULL) >= start_time+ltimeout)
422 		{
423 			if (debug)
424 				print_err(0, "open_host: timeout reached");
425 			if (close(*filedes) == -1)
426 				return -1; /* don't leak that fd */
427 			return SYSM_TIMEDOUT; /* return connection timed out */
428 		}
429 
430 		if (debug)
431 			print_err(0, "While connecting, got %s(%d)",
432 				errtostr(errcode),errcode);
433 		if (errcode == 1 || errcode == 2 || errcode == 3 ||
434 			errcode == 4)
435 		{
436 			if (close(*filedes) == -1)
437 			{
438 				perror("talktcp.c:open_host:second_loop_close");
439 				return -1;
440 			}
441 			return errcode;
442 		}
443 	}
444 
445         return 0; /* return ok status */
446 }
447 
448 /*
449  * Create a nonblocking socket for the other functions to
450  * handle and do processing with
451  */
open_sock()452 int open_sock()
453 {
454         int sock = 0;
455 
456 	sock = socket(AF_INET, SOCK_STREAM, 0);
457 
458         if (sock == -1)
459         {
460                 perror("opening datagram socket");
461 		if (debug)
462 			print_err(0, "sock = %d at return(-1)", sock);
463 		return -1;
464         }
465 
466 	set_nonblock(sock);
467 
468         return sock;
469 }
470 
471 /*
472  *
473  */
set_nonblock(int sock)474 void set_nonblock(int sock)
475 {
476 	int errcode;
477 
478 #if defined (NBIO_FCNTL)
479 #if ! defined (FNDELAY)
480 #define FNDELAY O_NDELAY
481 #endif /* ! defined (FNDELAY) */
482 
483 	errcode = fcntl (sock, F_SETFL, FNDELAY) ;
484 
485 #else /* defined NBIO_FCNTL */
486 	/* linux and whatnot */
487 	int state = 1;
488 
489 	errcode = ioctl (sock, FIONBIO, (char *) &state) ;
490 #endif /* defined NBIO_FCNTL */
491 
492 	if (errcode == -1)
493 	{
494 		perror("set_nonblock");
495 	}
496 
497 }
498 
499 /*
500  * wait until we are ready
501  */
blocktillready(int fd,int secs)502 void blocktillready(int fd, int secs)
503 {
504 	time_t start = time(NULL); /* duh */
505 
506 	while ((time(NULL) - start) > secs)
507 	{
508 		if (is_open(fd))
509 			return;
510 		sleep(1);
511 	}
512 }
513