File: client.c

package info (click to toggle)
nmh 1.8-4
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 7,860 kB
  • sloc: ansic: 50,445; sh: 22,697; makefile: 1,138; lex: 740; perl: 509; yacc: 265
file content (119 lines) | stat: -rw-r--r-- 2,776 bytes parent folder | download | duplicates (3)
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
/* client.c -- connect to a server
 *
 * This code is Copyright (c) 2002, by the authors of nmh.  See the
 * COPYRIGHT file in the root directory of the nmh distribution for
 * complete copyright information.
 */

#include "h/mh.h"
#include "client.h"
#include "mts.h"
#include <fcntl.h>
#include "utils.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>


int
client (char *server, char *service, char *response, int len_response,
	int debug)
{
    int sd, rc;
    struct addrinfo hints, *res, *ai;

    if (!server || *server == '\0') {
	snprintf(response, len_response, "Internal error: NULL server name "
		 "passed to client()");
	return NOTOK;
    }

    ZERO(&hints);
#ifdef AI_ADDRCONFIG
    hints.ai_flags = AI_ADDRCONFIG;
#endif
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if (debug) {
	fprintf(stderr, "Trying to connect to \"%s\" ...\n", server);
    }

    rc = getaddrinfo(server, service, &hints, &res);

    if (rc) {
	snprintf(response, len_response, "Lookup of \"%s\" failed: %s",
		 server, gai_strerror(rc));
	return NOTOK;
    }

    for (ai = res; ai != NULL; ai = ai->ai_next) {
	if (debug) {
	    char address[NI_MAXHOST];
	    char port[NI_MAXSERV];

	    rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
			     sizeof(address), port, sizeof port,
			     NI_NUMERICHOST | NI_NUMERICSERV);

	    fprintf(stderr, "Connecting to %s:%s...\n",
		    rc ? "unknown" : address, rc ? "--" : port);
	}

	sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

	if (sd < 0) {
	    if (debug)
		fprintf(stderr, "socket() failed: %s\n", strerror(errno));
	    continue;
	}

	if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
	    int flags;

	    freeaddrinfo(res);

	    flags = fcntl(sd, F_GETFD, 0);

	    if (flags != -1)
		fcntl(sd, F_SETFD, flags | FD_CLOEXEC);

	    return sd;
	}

	if (debug) {
	    fprintf(stderr, "Connection failed: %s\n", strerror(errno));
	}

	close(sd);
    }

    /*
     * Improve error handling a bit. If we were given multiple IP addresses
     * then return the old "no servers available" error, but point the user
     * to -snoop (hopefully that's universal).  Otherwise report a specific
     * error.
     */

    if (res == NULL || res->ai_next)
	snprintf(response, len_response, "no servers available (use -snoop "
		 "for details)");
    else {
	char port[NI_MAXSERV];

	if (getnameinfo(res->ai_addr, res->ai_addrlen, NULL, 0, port,
			sizeof port, NI_NUMERICSERV)) {
	    strncpy(port, "unknown", sizeof port);
	    port[sizeof(port) - 1] = '\0';
	}

	snprintf(response, len_response, "Connection to \"%s:%s\" failed: %s",
		 server, port, strerror(errno));
    }

    freeaddrinfo(res);

    return NOTOK;
}