]> andersk Git - moira.git/blame - lib/mr_connect.c
Switch from Imake-based build system to autoconf-based.
[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;
79 struct hostent *shost;
5eaef520 80
5eaef520 81 if (_mr_conn)
82 return MR_ALREADY_CONNECTED;
85330553 83 if (!mr_inited)
84 mr_init();
5eaef520 85
86 if (!server || (strlen(server) == 0))
87 server = getenv("MOIRASERVER");
5450e3a1 88
ea0caf4a 89#ifdef HAVE_HESIOD
5eaef520 90 if (!server || (strlen(server) == 0))
91 {
92 pp = hes_resolve("moira", "sloc");
93 if (pp)
94 server = *pp;
5450e3a1 95 }
a43ce477 96#endif
5450e3a1 97
5eaef520 98 if (!server || (strlen(server) == 0))
99 server = MOIRA_SERVER;
5450e3a1 100
85330553 101 shost = gethostbyname(server);
102 if (!shost)
103 return MR_CANT_CONNECT;
104
105 if (strchr(server, ':'))
5eaef520 106 {
85330553 107 int len = strcspn(server, ":");
108 sbuf = malloc(len + 1);
109 strncpy(sbuf, server, len);
110 sbuf[len - 1] = '\0';
5eaef520 111 server = sbuf;
85330553 112 port = strchr(server, ':') + 1;
113 }
114 else
115 port = strchr(MOIRA_SERVER, ':') + 1;
116
117 _mr_conn = mr_connect_internal(server, port);
118 free(sbuf);
119 if (!_mr_conn)
120 return MR_CANT_CONNECT;
121
122 /* stash hostname for later use */
123 mr_server_host = strdup(shost->h_name);
124 return MR_SUCCESS;
125}
126
127int mr_connect_internal(char *server, char *port)
128{
129 int fd, size, more;
130 struct sockaddr_in target;
131 struct hostent *shost;
132 char actualresponse[53];
133
134 shost = gethostbyname(server);
135 if (!shost)
136 return 0;
137
138 if (port[0] == '#')
139 target.sin_port = atoi(port + 1);
140 else
141 {
142 struct servent *s;
143 s = getservbyname(port, "tcp");
144 if (s)
145 target.sin_port = s->s_port;
146 else
147 return 0;
5450e3a1 148 }
149
85330553 150 memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
151 target.sin_family = shost->h_addrtype;
152
153 fd = socket(AF_INET, SOCK_STREAM, 0);
154 if (fd < 0)
155 return 0;
156
157 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
5eaef520 158 {
85330553 159 close(fd);
160 return 0;
83e80378 161 }
05fb8281 162
85330553 163 /* Do magic mrgdb initialization */
164 size = write(fd, challenge, sizeof(challenge));
165 if (size != sizeof(challenge))
166 {
167 close(fd);
168 return 0;
169 }
170 for (size = 0; size < sizeof(actualresponse); size += more)
171 {
172 more = read(fd, actualresponse + size, sizeof(actualresponse) - size);
173 if (!more)
174 break;
175 }
176 if (size != sizeof(actualresponse))
177 {
178 close(fd);
179 return 0;
180 }
181 if (memcmp(actualresponse, response, sizeof(actualresponse)))
182 {
183 close(fd);
184 return 0;
185 }
05fb8281 186
85330553 187 /* You win */
188 return fd;
e2a67c78 189}
5eaef520 190
191int mr_disconnect(void)
e2a67c78 192{
5eaef520 193 CHECK_CONNECTED;
85330553 194 close(_mr_conn);
195 _mr_conn = 0;
5eaef520 196 free(mr_server_host);
85330553 197 mr_server_host = NULL;
198 return MR_SUCCESS;
e2a67c78 199}
200
5eaef520 201int mr_host(char *host, int size)
05fb8281 202{
5eaef520 203 CHECK_CONNECTED;
05fb8281 204
5eaef520 205 /* If we are connected, mr_server_host points to a valid string. */
206 strncpy(host, mr_server_host, size);
85330553 207 host[size - 1] = '\0';
208 return MR_SUCCESS;
05fb8281 209}
210
5eaef520 211int mr_noop(void)
e2a67c78 212{
5eaef520 213 int status;
85330553 214 mr_params params, reply;
5eaef520 215
216 CHECK_CONNECTED;
85330553 217 params.u.mr_procno = MR_NOOP;
218 params.mr_argc = 0;
219 params.mr_argl = NULL;
220 params.mr_argv = NULL;
5eaef520 221
85330553 222 if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
223 status = reply.u.mr_status;
5eaef520 224
225 mr_destroy_reply(reply);
226
227 return status;
6c00b7c4 228}
85330553 229
230
231/* Server side */
232
233int mr_listen(char *port)
234{
235 struct sockaddr_in sin;
236 int s, on = 1;
237
238 memset(&sin, 0, sizeof(sin));
239 if (port[0] == '#')
240 sin.sin_port = atoi(port + 1);
241 else
242 {
243 struct servent *s;
244 s = getservbyname(port, "tcp");
245 if (s)
246 sin.sin_port = s->s_port;
247 else
248 return -1;
249 }
250
251 s = socket(AF_INET, SOCK_STREAM, 0);
252 if (s < 0)
253 return -1;
254 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
255 {
256 close(s);
257 return -1;
258 }
259 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
260 {
261 close(s);
262 return -1;
263 }
264 if (listen(s, 5) < 0)
265 {
266 close(s);
267 return -1;
268 }
269
270 return s;
271}
272
273int mr_accept(int s, struct sockaddr_in *sin)
274{
275 int conn, addrlen = sizeof(struct sockaddr_in);
276 char lbuf[4], *buf;
277 long len, size, more;
278
279 conn = accept(s, (struct sockaddr *)sin, &addrlen);
280 if (conn < 0)
281 return -1;
282
283 /* Now do mrgdb accept protocol */
284 /* XXX timeout */
285
286 if (read(conn, lbuf, 4) != 4)
287 {
288 close(conn);
289 return -1;
290 }
291 getlong(lbuf, len);
292
293 buf = malloc(len);
294 if (!buf || len < 54)
295 {
296 close(conn);
297 free(buf);
298 return -1;
299 }
300
301 for (size = 0; size < len; size += more)
302 {
303 more = read(conn, buf + size, len - size);
304 if (!more)
305 break;
306 }
307 if (size != len)
308 {
309 close(conn);
310 free(buf);
311 return 0;
312 }
313
314 if (memcmp(buf, challenge + 4, 34))
315 {
316 close(conn);
317 free(buf);
318 return 0;
319 }
320
321 /* good enough */
322 free(buf);
323
324 if (write(conn, response, sizeof(response)) != sizeof(response))
325 {
326 close(conn);
327 return -1;
328 }
329 return conn;
330}
This page took 0.130975 seconds and 5 git commands to generate.