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
|
/* $Id: id_open.c 550 2004-06-17 01:27:41Z eagle $
**
** Low-level call to establish/initiate a connection to an ident server.
**
** Written by Peter Eriksson <pen@lysator.liu.se>
** Fixes by Pr Emanuelsson <pell@lysator.liu.se>
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
/* BSDI needs <netinet/in.h> before <arpa/inet.h>. */
#include <netinet/in.h>
#include <arpa/inet.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include "sident.h"
ident_t *
id_open(struct in_addr *laddr, struct in_addr *faddr, struct timeval *timeout)
{
ident_t *id;
int res, tmperrno;
struct sockaddr_in sin_laddr, sin_faddr;
int on = 1;
struct linger linger;
fd_set rs, ws, es;
id = malloc(sizeof(*id));
if (id == NULL)
return NULL;
id->fd = socket(AF_INET, SOCK_STREAM, 0);
if (id->fd < 0) {
free(id);
return NULL;
}
if (timeout) {
res = fcntl(id->fd, F_GETFL, 0);
if (res < 0)
goto error;
if (fcntl(id->fd, F_SETFL, res | FNDELAY) < 0)
goto error;
}
/* We silently ignore errors if we can't change LINGER. */
linger.l_onoff = 0;
linger.l_linger = 0;
setsockopt(id->fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
setsockopt(id->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
id->buf[0] = '\0';
memset(&sin_laddr, 0, sizeof(sin_laddr));
sin_laddr.sin_family = AF_INET;
sin_laddr.sin_addr = *laddr;
sin_laddr.sin_port = 0;
if (bind(id->fd, (struct sockaddr *) &sin_laddr, sizeof(sin_laddr)) < 0)
goto error;
memset(&sin_faddr, 0, sizeof(sin_faddr));
sin_faddr.sin_family = AF_INET;
sin_faddr.sin_addr = *faddr;
sin_faddr.sin_port = htons(IDPORT);
res = connect(id->fd, (struct sockaddr *) &sin_faddr, sizeof(sin_faddr));
if (res < 0 && errno != EINPROGRESS)
goto error;
if (timeout) {
FD_ZERO(&rs);
FD_ZERO(&ws);
FD_ZERO(&es);
FD_SET(id->fd, &rs);
FD_SET(id->fd, &ws);
FD_SET(id->fd, &es);
res = select(FD_SETSIZE, &rs, &ws, &es, timeout);
if (res < 0)
goto error;
else if (res == 0) {
errno = ETIMEDOUT;
goto error;
}
if (FD_ISSET(id->fd, &es))
goto error;
if (!FD_ISSET(id->fd, &rs) && !FD_ISSET(id->fd, &ws))
goto error;
}
return id;
error:
tmperrno = errno; /* Save, so close() won't erase it */
close(id->fd);
free(id);
errno = tmperrno;
return 0;
}
|