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;
}
|