File: id_open.c

package info (click to toggle)
sident 3.6-2
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 1,960 kB
  • ctags: 719
  • sloc: sh: 8,131; ansic: 6,784; makefile: 231; perl: 147
file content (112 lines) | stat: -rw-r--r-- 2,768 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
/*  $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;
}