]> diplodocus.org Git - nmh/blob - sbr/client.c
2bed9052b953502d5eb7822dae01228352e7698a
[nmh] / sbr / client.c
1 /* client.c -- connect to a server
2 *
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
6 */
7
8 #include "h/mh.h"
9 #include "client.h"
10 #include "h/mts.h"
11 #include "h/utils.h"
12 #include <fcntl.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <netdb.h>
16 #include <arpa/inet.h>
17 #include <errno.h>
18
19
20 int
21 client (char *server, char *service, char *response, int len_response,
22 int debug)
23 {
24 int sd, rc;
25 struct addrinfo hints, *res, *ai;
26
27 if (!server || *server == '\0') {
28 snprintf(response, len_response, "Internal error: NULL server name "
29 "passed to client()");
30 return NOTOK;
31 }
32
33 ZERO(&hints);
34 #ifdef AI_ADDRCONFIG
35 hints.ai_flags = AI_ADDRCONFIG;
36 #endif
37 hints.ai_family = PF_UNSPEC;
38 hints.ai_socktype = SOCK_STREAM;
39
40 if (debug) {
41 fprintf(stderr, "Trying to connect to \"%s\" ...\n", server);
42 }
43
44 rc = getaddrinfo(server, service, &hints, &res);
45
46 if (rc) {
47 snprintf(response, len_response, "Lookup of \"%s\" failed: %s",
48 server, gai_strerror(rc));
49 return NOTOK;
50 }
51
52 for (ai = res; ai != NULL; ai = ai->ai_next) {
53 if (debug) {
54 char address[NI_MAXHOST];
55 char port[NI_MAXSERV];
56
57 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
58 sizeof(address), port, sizeof port,
59 NI_NUMERICHOST | NI_NUMERICSERV);
60
61 fprintf(stderr, "Connecting to %s:%s...\n",
62 rc ? "unknown" : address, rc ? "--" : port);
63 }
64
65 sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
66
67 if (sd < 0) {
68 if (debug)
69 fprintf(stderr, "socket() failed: %s\n", strerror(errno));
70 rc = errno;
71 continue;
72 }
73
74 if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
75 int flags;
76
77 freeaddrinfo(res);
78
79 flags = fcntl(sd, F_GETFD, 0);
80
81 if (flags != -1)
82 fcntl(sd, F_SETFD, flags | FD_CLOEXEC);
83
84 return sd;
85 }
86
87 rc = errno;
88
89 if (debug) {
90 fprintf(stderr, "Connection failed: %s\n", strerror(errno));
91 }
92
93 close(sd);
94 }
95
96 /*
97 * Improve error handling a bit. If we were given multiple IP addresses
98 * then return the old "no servers available" error, but point the user
99 * to -snoop (hopefully that's universal). Otherwise report a specific
100 * error.
101 */
102
103 if (res->ai_next)
104 snprintf(response, len_response, "no servers available (use -snoop "
105 "for details");
106 else
107 snprintf(response, len_response, "Connection to \"%s\" failed: %s",
108 server, strerror(errno));
109
110 freeaddrinfo(res);
111
112 return NOTOK;
113 }