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