92e0711331f7dbd5a9e89e2ecbfb352cb2395859
[mmh] / sbr / client.c
1
2 /*
3  * client.c -- connect to a server
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9
10 #include <h/mh.h>
11 #include <h/mts.h>
12 #include <h/utils.h>
13 #include <errno.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17
18 #ifdef HAVE_ARPA_INET_H
19 # include <arpa/inet.h>
20 #endif
21
22 #define TRUE         1
23 #define FALSE        0
24
25 #define MAXARGS   1000
26
27 /*
28  * static prototypes
29  */
30
31 /* client's own static version of several nmh subroutines */
32 static char **client_brkstring (char *, char *, char *);
33 static int client_brkany (char, char *);
34 static char **client_copyip (char **, char **, int);
35 static char *client_getcpy (char *);
36 static void client_freelist(char **);
37
38
39 int
40 client (char *args, char *service, char *response, int len_response, int debug)
41 {
42     int sd, rc;
43     char **ap, *arguments[MAXARGS];
44     struct addrinfo hints, *res, *ai;
45
46     ap = arguments;
47     if (args != NULL && *args != 0) {
48         ap = client_copyip (client_brkstring (client_getcpy (args), " ", "\n"),
49                 ap, MAXARGS);
50     }
51     if (ap == arguments) {
52         *ap++ = client_getcpy ("localhost");
53         *ap = NULL;
54     }
55
56     memset(&hints, 0, sizeof(hints));
57 #ifdef AI_ADDRCONFIG
58     hints.ai_flags = AI_ADDRCONFIG;
59 #endif
60     hints.ai_family = PF_UNSPEC;
61     hints.ai_socktype = SOCK_STREAM;
62
63     for (ap = arguments; *ap; ap++) {
64
65         if (debug) {
66             fprintf(stderr, "Trying to connect to \"%s\" ...\n", *ap);
67         }
68
69         rc = getaddrinfo(*ap, service, &hints, &res);
70
71         if (rc) {
72             if (debug) {
73                 fprintf(stderr, "Lookup of \"%s\" failed: %s\n", *ap,
74                         gai_strerror(rc));
75             }
76             continue;
77         }
78
79         for (ai = res; ai != NULL; ai = ai->ai_next) {
80             if (debug) {
81                 char address[NI_MAXHOST];
82
83                 rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, address,
84                                  sizeof(address), NULL, 0, NI_NUMERICHOST);
85
86                 fprintf(stderr, "Connecting to %s...\n",
87                         rc ? "unknown" : address);
88             }
89
90             sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
91
92             if (sd < 0) {
93                 if (debug)
94                     fprintf(stderr, "socket() failed: %s\n", strerror(errno));
95                 continue;
96             }
97
98             if (connect(sd, ai->ai_addr, ai->ai_addrlen) == 0) {
99                 freeaddrinfo(res);
100                 client_freelist(ap);
101                 return sd;
102             }
103
104             if (debug) {
105                 fprintf(stderr, "Connection failed: %s\n", strerror(errno));
106             }
107
108             close(sd);
109         }
110
111         freeaddrinfo(res);
112     }
113
114     client_freelist(ap);
115     strncpy (response, "no servers available", len_response);
116     return NOTOK;
117 }
118
119
120 /*
121  * Free a list of strings
122  */
123
124 static void
125 client_freelist(char **list)
126 {
127     while (*list++ != NULL)
128         free(*list);
129 }
130
131
132 /*
133  * static copies of three nmh subroutines
134  */
135
136 static char *broken[MAXARGS + 1];
137
138 static char **
139 client_brkstring (char *strg, char *brksep, char *brkterm)
140 {
141     register int bi;
142     register char c, *sp;
143
144     sp = strg;
145
146     for (bi = 0; bi < MAXARGS; bi++) {
147         while (client_brkany (c = *sp, brksep))
148             *sp++ = 0;
149         if (!c || client_brkany (c, brkterm)) {
150             *sp = 0;
151             broken[bi] = 0;
152             return broken;
153         }
154
155         broken[bi] = sp;
156         while ((c = *++sp) && !client_brkany (c, brksep) && !client_brkany (c, brkterm))
157             continue;
158     }
159     broken[MAXARGS] = 0;
160
161     return broken;
162 }
163
164
165 /*
166  * returns 1 if chr in strg, 0 otherwise
167  */
168 static int
169 client_brkany (char chr, char *strg)
170 {
171     register char *sp;
172  
173     if (strg)
174         for (sp = strg; *sp; sp++)
175             if (chr == *sp)
176                 return 1;
177     return 0;
178 }
179
180
181 /*
182  * copy a string array and return pointer to end
183  */
184 static char **
185 client_copyip (char **p, char **q, int len_q)
186 {
187     while (*p && --len_q > 0)
188         *q++ = *p++;
189
190     *q = NULL;
191
192     return q;
193 }
194
195
196 static char *
197 client_getcpy (char *str)
198 {
199     char *cp;
200     size_t len;
201
202     len = strlen(str) + 1;
203     cp = mh_xmalloc(len);
204
205     memcpy (cp, str, len);
206     return cp;
207 }
208