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