]> andersk Git - moira.git/blame_incremental - lib/mr_connect.c
Use mrcl_connect() so we send a query version.
[moira.git] / lib / mr_connect.c
... / ...
CommitLineData
1/* $Id$
2 *
3 * This routine is part of the client library. It handles
4 * creating a connection to the moira server.
5 *
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>.
9 */
10
11#include <mit-copyright.h>
12#include <moira.h>
13#include <moira_site.h>
14#include "mr_private.h"
15
16#include <sys/types.h>
17
18#include <errno.h>
19#include <stdlib.h>
20#include <string.h>
21
22#ifdef HAVE_UNISTD_H
23#include <unistd.h>
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
37
38#ifdef HAVE_HESIOD
39#include <hesiod.h>
40#endif
41
42RCSID("$Header$");
43
44#define DEFAULT_SERV "moira_db"
45#define DEFAULT_PORT 775
46
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";
83
84/*
85 * Open a connection to the moira server. Looks for the server name
86 * 1) passed as an argument, 2) in environment variable, 3) by hesiod
87 * 4) compiled in default
88 */
89
90int mr_connect(char *server)
91{
92 char *port, **pp, *sbuf = NULL;
93
94 if (_mr_conn)
95 return MR_ALREADY_CONNECTED;
96 if (!mr_inited)
97 mr_init();
98
99 if (!server || (strlen(server) == 0))
100 server = getenv("MOIRASERVER");
101
102#ifdef HAVE_HESIOD
103 if (!server || (strlen(server) == 0))
104 {
105 pp = hes_resolve("moira", "sloc");
106 if (pp)
107 server = *pp;
108 }
109#endif
110
111 if (!server || (strlen(server) == 0))
112 server = MOIRA_SERVER;
113
114 if (strchr(server, ':'))
115 {
116 int len = strcspn(server, ":");
117 sbuf = malloc(len + 1);
118 strncpy(sbuf, server, len);
119 sbuf[len] = '\0';
120 port = strchr(server, ':') + 1;
121 server = sbuf;
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
131 return MR_SUCCESS;
132}
133
134int mr_connect_internal(char *server, char *port)
135{
136 int size, more;
137 struct sockaddr_in target;
138 struct hostent *shost;
139 char actualresponse[53];
140 char *host = NULL;
141 int fd = SOCKET_ERROR;
142 int ok = 0;
143 int on = 1; /* Value variable for setsockopt() */
144
145 shost = gethostbyname(server);
146 if (!shost)
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);
153
154 if (port[0] == '#')
155 target.sin_port = htons((unsigned short)atoi(port + 1));
156 else
157 {
158 struct servent *s;
159 target.sin_port = 0;
160 s = getservbyname(port, "tcp");
161 if (s)
162 target.sin_port = s->s_port;
163#ifdef HAVE_HESIOD
164 if (!target.sin_port)
165 {
166 s = hes_getservbyname(port, "tcp");
167 if (s)
168 target.sin_port = s->s_port;
169 }
170#endif
171 if (!target.sin_port && !strcasecmp(port, DEFAULT_SERV))
172 target.sin_port = htons(DEFAULT_PORT);
173 if (!target.sin_port)
174 goto cleanup;
175 }
176
177 fd = socket(AF_INET, SOCK_STREAM, 0);
178 if (fd < 0)
179 goto cleanup;
180
181 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(int)) < 0)
182 goto cleanup;
183
184 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
185 goto cleanup;
186
187 /* Do magic mrgdb initialization */
188 size = send(fd, challenge, sizeof(challenge), 0);
189 if (size != sizeof(challenge))
190 goto cleanup;
191 for (size = 0; size < sizeof(actualresponse); size += more)
192 {
193 more = recv(fd, actualresponse + size, sizeof(actualresponse) - size, 0);
194 if (more <= 0)
195 break;
196 }
197 if (size != sizeof(actualresponse))
198 goto cleanup;
199 if (memcmp(actualresponse, response, sizeof(actualresponse)))
200 goto cleanup;
201
202 ok = 1;
203 mr_server_host = host;
204
205 cleanup:
206 if (!ok)
207 {
208 if (host)
209 free(host);
210 if (fd != SOCKET_ERROR)
211 closesocket(fd);
212 return 0;
213 }
214 /* You win */
215 return fd;
216}
217
218int mr_disconnect(void)
219{
220 CHECK_CONNECTED;
221 closesocket(_mr_conn);
222 _mr_conn = 0;
223 free(mr_server_host);
224 mr_server_host = NULL;
225 return MR_SUCCESS;
226}
227
228int mr_host(char *host, int size)
229{
230 CHECK_CONNECTED;
231
232 /* If we are connected, mr_server_host points to a valid string. */
233 strncpy(host, mr_server_host, size);
234 host[size - 1] = '\0';
235 return MR_SUCCESS;
236}
237
238int mr_noop(void)
239{
240 int status;
241 mr_params params, reply;
242
243 CHECK_CONNECTED;
244 params.u.mr_procno = MR_NOOP;
245 params.mr_argc = 0;
246 params.mr_argl = NULL;
247 params.mr_argv = NULL;
248
249 if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
250 status = reply.u.mr_status;
251
252 mr_destroy_reply(reply);
253
254 return status;
255}
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 {
283 closesocket(s);
284 return -1;
285 }
286 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
287 {
288 closesocket(s);
289 return -1;
290 }
291 if (listen(s, 5) < 0)
292 {
293 closesocket(s);
294 return -1;
295 }
296
297 return s;
298}
299
300/* mr_accept returns -1 on accept() error, 0 on bad connection,
301 or connection fd on success */
302
303int mr_accept(int s, struct sockaddr_in *sin)
304{
305 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
306 char *buf = NULL;
307
308 while (conn < 0)
309 {
310 conn = accept(s, (struct sockaddr *)sin, &addrlen);
311 if (conn < 0 && errno != EINTR
312#ifdef ERESTART
313 && errno != ERESTART
314#endif
315 )
316 return -1;
317 }
318
319 do
320 status = mr_cont_accept(conn, &buf, &nread);
321 while (status == -1);
322
323 return status;
324}
325
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
329int mr_cont_accept(int conn, char **buf, int *nread)
330{
331 long len, more;
332
333 if (!*buf)
334 {
335 char lbuf[4];
336 if (recv(conn, lbuf, 4, 0) != 4)
337 {
338 closesocket(conn);
339 return 0;
340 }
341 getlong(lbuf, len);
342 len += 4;
343
344 *buf = malloc(len);
345 if (!*buf || len < 58)
346 {
347 closesocket(conn);
348 free(*buf);
349 return 0;
350 }
351 putlong(*buf, len);
352 *nread = 4;
353 return -1;
354 }
355 else
356 getlong(*buf, len);
357
358 more = recv(conn, *buf + *nread, len - *nread, 0);
359
360 if (more == -1 && errno != EINTR)
361 {
362 closesocket(conn);
363 free(*buf);
364 return 0;
365 }
366
367 *nread += more;
368
369 if (*nread != len)
370 return -1;
371
372 if (memcmp(*buf + 4, challenge + 4, 34))
373 {
374 closesocket(conn);
375 free(*buf);
376 return 0;
377 }
378
379 /* good enough */
380 free(*buf);
381
382 if (send(conn, response, sizeof(response), 0) != sizeof(response))
383 {
384 closesocket(conn);
385 return 0;
386 }
387 return conn;
388}
This page took 2.482866 seconds and 5 git commands to generate.