]> andersk Git - moira.git/blame - lib/mr_connect.c
from epeisach: fallback to hes_getservbyname if we're not in /etc/services
[moira.git] / lib / mr_connect.c
CommitLineData
fa59b86f 1/* $Id$
e2a67c78 2 *
7ac48069 3 * This routine is part of the client library. It handles
4 * creating a connection to the moira server.
5eaef520 5 *
7ac48069 6 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
e2a67c78 9 */
10
babbc197 11#include <mit-copyright.h>
7ac48069 12#include <moira.h>
8defc06b 13#include <moira_site.h>
7ac48069 14#include "mr_private.h"
15
85330553 16#include <sys/types.h>
17#include <sys/socket.h>
18
19#include <netinet/in.h>
20#include <netdb.h>
21
7ac48069 22#include <errno.h>
a43ce477 23#include <stdlib.h>
7ac48069 24#include <string.h>
85330553 25#include <unistd.h>
7ac48069 26
ea0caf4a 27#ifdef HAVE_HESIOD
a43ce477 28#include <hesiod.h>
ea0caf4a 29#endif
05fb8281 30
7ac48069 31RCSID("$Header$");
32
85330553 33int _mr_conn = 0;
34static char *mr_server_host = NULL;
35
36/* mrgdb compatibility magic
37
38 The data looks like this:
39
40 client -> server
41 00000036 [length of rest of packet]
42 00000004 [number of fields]
43 01 01 01 01 [types of fields: 4 strings]
44 "server_id\0parms\0host\0user\0" [field names]
45 00000001 [length of null-terminated server_id]
46 "\0" [server_id: ignored anyway]
47 00000001 [length of null-terminated parms]
48 "\0" [parms: ignored anyway]
49 00000001 [length of null-terminated client host]
50 "\0" [host: ignored anyway]
51 00000001 [length of null-terminated client name]
52 "\0" [user: ignored anyway]
53
54 server -> client
55 00000031 [length of rest of packet]
56 00000003 [number of fields]
57 00 01 01 [types of fields: int and 2 strings]
58 "disposition\0server_id\0parms\0" [field names]
59 00000001 [GDB_ACCEPTED]
60 00000001 [length of null-terminated server_id]
61 "\0" [server_id: ignored anyway]
62 00000001 [length of null-terminated parms]
63 "\0" [parms: ignored anyway]
64
65*/
66
67static char challenge[58] = "\0\0\0\066\0\0\0\004\001\001\001\001server_id\0parms\0host\0user\0\0\0\0\001\0\0\0\0\001\0\0\0\0\001\0\0\0\0\001\0";
68static char response[53] = "\0\0\0\061\0\0\0\003\0\001\001disposition\0server_id\0parms\0\0\0\0\001\0\0\0\001\0\0\0\0\001\0";
e2a67c78 69
70/*
85330553 71 * Open a connection to the moira server. Looks for the server name
5450e3a1 72 * 1) passed as an argument, 2) in environment variable, 3) by hesiod
85330553 73 * 4) compiled in default
e2a67c78 74 */
75
5eaef520 76int mr_connect(char *server)
e2a67c78 77{
85330553 78 char *port, **pp, *sbuf = NULL;
5eaef520 79
5eaef520 80 if (_mr_conn)
81 return MR_ALREADY_CONNECTED;
85330553 82 if (!mr_inited)
83 mr_init();
5eaef520 84
85 if (!server || (strlen(server) == 0))
86 server = getenv("MOIRASERVER");
5450e3a1 87
ea0caf4a 88#ifdef HAVE_HESIOD
5eaef520 89 if (!server || (strlen(server) == 0))
90 {
91 pp = hes_resolve("moira", "sloc");
92 if (pp)
93 server = *pp;
5450e3a1 94 }
a43ce477 95#endif
5450e3a1 96
5eaef520 97 if (!server || (strlen(server) == 0))
98 server = MOIRA_SERVER;
5450e3a1 99
85330553 100 if (strchr(server, ':'))
5eaef520 101 {
85330553 102 int len = strcspn(server, ":");
103 sbuf = malloc(len + 1);
104 strncpy(sbuf, server, len);
b59b20cd 105 sbuf[len] = '\0';
85330553 106 port = strchr(server, ':') + 1;
b59b20cd 107 server = sbuf;
85330553 108 }
109 else
110 port = strchr(MOIRA_SERVER, ':') + 1;
111
112 _mr_conn = mr_connect_internal(server, port);
113 free(sbuf);
114 if (!_mr_conn)
115 return MR_CANT_CONNECT;
116
85330553 117 return MR_SUCCESS;
118}
119
120int mr_connect_internal(char *server, char *port)
121{
122 int fd, size, more;
123 struct sockaddr_in target;
124 struct hostent *shost;
125 char actualresponse[53];
126
127 shost = gethostbyname(server);
128 if (!shost)
129 return 0;
130
131 if (port[0] == '#')
b59b20cd 132 target.sin_port = htons(atoi(port + 1));
85330553 133 else
134 {
135 struct servent *s;
136 s = getservbyname(port, "tcp");
137 if (s)
138 target.sin_port = s->s_port;
139 else
88a72f00 140#ifdef HAVE_HESIOD
141 {
142 s = hes_getservbyname(port, "tcp");
143 if (s)
144 target.sin_port = s->s_port;
145 else
146 return 0;
147 }
148#else
85330553 149 return 0;
88a72f00 150#endif
5450e3a1 151 }
152
85330553 153 memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
154 target.sin_family = shost->h_addrtype;
155
156 fd = socket(AF_INET, SOCK_STREAM, 0);
157 if (fd < 0)
158 return 0;
159
160 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
5eaef520 161 {
85330553 162 close(fd);
163 return 0;
83e80378 164 }
05fb8281 165
85330553 166 /* Do magic mrgdb initialization */
167 size = write(fd, challenge, sizeof(challenge));
168 if (size != sizeof(challenge))
169 {
170 close(fd);
171 return 0;
172 }
173 for (size = 0; size < sizeof(actualresponse); size += more)
174 {
175 more = read(fd, actualresponse + size, sizeof(actualresponse) - size);
12cbd6bd 176 if (more <= 0)
85330553 177 break;
178 }
179 if (size != sizeof(actualresponse))
180 {
181 close(fd);
182 return 0;
183 }
184 if (memcmp(actualresponse, response, sizeof(actualresponse)))
185 {
186 close(fd);
187 return 0;
188 }
05fb8281 189
b59b20cd 190 mr_server_host = strdup(shost->h_name);
191
85330553 192 /* You win */
193 return fd;
e2a67c78 194}
5eaef520 195
196int mr_disconnect(void)
e2a67c78 197{
5eaef520 198 CHECK_CONNECTED;
85330553 199 close(_mr_conn);
200 _mr_conn = 0;
5eaef520 201 free(mr_server_host);
85330553 202 mr_server_host = NULL;
203 return MR_SUCCESS;
e2a67c78 204}
205
5eaef520 206int mr_host(char *host, int size)
05fb8281 207{
5eaef520 208 CHECK_CONNECTED;
05fb8281 209
5eaef520 210 /* If we are connected, mr_server_host points to a valid string. */
211 strncpy(host, mr_server_host, size);
85330553 212 host[size - 1] = '\0';
213 return MR_SUCCESS;
05fb8281 214}
215
5eaef520 216int mr_noop(void)
e2a67c78 217{
5eaef520 218 int status;
85330553 219 mr_params params, reply;
5eaef520 220
221 CHECK_CONNECTED;
85330553 222 params.u.mr_procno = MR_NOOP;
223 params.mr_argc = 0;
224 params.mr_argl = NULL;
225 params.mr_argv = NULL;
5eaef520 226
85330553 227 if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
228 status = reply.u.mr_status;
5eaef520 229
230 mr_destroy_reply(reply);
231
232 return status;
6c00b7c4 233}
85330553 234
235
236/* Server side */
237
238int mr_listen(char *port)
239{
240 struct sockaddr_in sin;
241 int s, on = 1;
242
243 memset(&sin, 0, sizeof(sin));
244 if (port[0] == '#')
245 sin.sin_port = atoi(port + 1);
246 else
247 {
248 struct servent *s;
249 s = getservbyname(port, "tcp");
250 if (s)
251 sin.sin_port = s->s_port;
252 else
253 return -1;
254 }
255
256 s = socket(AF_INET, SOCK_STREAM, 0);
257 if (s < 0)
258 return -1;
259 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
260 {
261 close(s);
262 return -1;
263 }
264 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
265 {
266 close(s);
267 return -1;
268 }
269 if (listen(s, 5) < 0)
270 {
271 close(s);
272 return -1;
273 }
274
275 return s;
276}
277
12cbd6bd 278/* mr_accept returns -1 on accept() error, 0 on bad connection,
279 or connection fd on success */
280
85330553 281int mr_accept(int s, struct sockaddr_in *sin)
282{
78eea87c 283 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
767253c8 284 char *buf = NULL;
85330553 285
78eea87c 286 while (conn < 0)
287 {
288 conn = accept(s, (struct sockaddr *)sin, &addrlen);
f237ecc9 289 if (conn < 0 && errno != EINTR
290#ifdef ERESTART
291 && errno != ERESTART
292#endif
293 )
78eea87c 294 return -1;
295 }
85330553 296
12cbd6bd 297 do
298 status = mr_cont_accept(conn, &buf, &nread);
299 while (status == -1);
85330553 300
12cbd6bd 301 return status;
302}
85330553 303
88381def 304/* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
305 or -1 if it is still making progress */
306
12cbd6bd 307int mr_cont_accept(int conn, char **buf, int *nread)
308{
309 long len, more;
310
311 if (!*buf)
85330553 312 {
12cbd6bd 313 char lbuf[4];
314 if (read(conn, lbuf, 4) != 4)
315 {
316 close(conn);
88381def 317 return 0;
12cbd6bd 318 }
319 getlong(lbuf, len);
320 len += 4;
321
322 *buf = malloc(len);
323 if (!*buf || len < 58)
324 {
325 close(conn);
767253c8 326 free(*buf);
12cbd6bd 327 return 0;
328 }
329 putlong(*buf, len);
330 *nread = 4;
85330553 331 return -1;
332 }
12cbd6bd 333 else
334 getlong(*buf, len);
85330553 335
12cbd6bd 336 more = read(conn, *buf + *nread, len - *nread);
337
338 if (more == -1 && errno != EINTR)
85330553 339 {
340 close(conn);
12cbd6bd 341 free(*buf);
85330553 342 return 0;
343 }
344
12cbd6bd 345 *nread += more;
346
347 if (*nread != len)
348 return -1;
349
350 if (memcmp(*buf + 4, challenge + 4, 34))
85330553 351 {
352 close(conn);
12cbd6bd 353 free(*buf);
85330553 354 return 0;
355 }
356
357 /* good enough */
12cbd6bd 358 free(*buf);
85330553 359
360 if (write(conn, response, sizeof(response)) != sizeof(response))
361 {
362 close(conn);
12cbd6bd 363 return 0;
85330553 364 }
365 return conn;
366}
This page took 0.159188 seconds and 5 git commands to generate.