3 * This routine is part of the client library. It handles
4 * creating a connection to the moira server.
6 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
11 #include <mit-copyright.h>
13 #include <moira_site.h>
14 #include "mr_private.h"
16 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
31 #define closesocket close
34 #define SOCKET_ERROR -1
41 /* This is declared in wshelper's resolv.h, but the definition of
42 * the putlong macro conflicts with Moira's
44 struct hostent * WINAPI rgethostbyname(char *name);
50 #define DEFAULT_SERV "moira_db"
51 #define DEFAULT_PORT 775
54 static char *mr_server_host = NULL;
56 /* mrgdb compatibility magic
58 The data looks like this:
61 00000036 [length of rest of packet]
62 00000004 [number of fields]
63 01 01 01 01 [types of fields: 4 strings]
64 "server_id\0parms\0host\0user\0" [field names]
65 00000001 [length of null-terminated server_id]
66 "\0" [server_id: ignored anyway]
67 00000001 [length of null-terminated parms]
68 "\0" [parms: ignored anyway]
69 00000001 [length of null-terminated client host]
70 "\0" [host: ignored anyway]
71 00000001 [length of null-terminated client name]
72 "\0" [user: ignored anyway]
75 00000031 [length of rest of packet]
76 00000003 [number of fields]
77 00 01 01 [types of fields: int and 2 strings]
78 "disposition\0server_id\0parms\0" [field names]
79 00000001 [GDB_ACCEPTED]
80 00000001 [length of null-terminated server_id]
81 "\0" [server_id: ignored anyway]
82 00000001 [length of null-terminated parms]
83 "\0" [parms: ignored anyway]
87 static 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";
88 static 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";
91 * Open a connection to the moira server. Looks for the server name
92 * 1) passed as an argument, 2) in environment variable, 3) by hesiod
93 * 4) compiled in default
96 int mr_connect(char *server)
98 char *port, **pp, *sbuf = NULL;
101 return MR_ALREADY_CONNECTED;
105 if (!server || (strlen(server) == 0))
106 server = getenv("MOIRASERVER");
109 if (!server || (strlen(server) == 0))
111 pp = hes_resolve("moira", "sloc");
117 if (!server || (strlen(server) == 0))
118 server = MOIRA_SERVER;
120 if (strchr(server, ':'))
122 int len = strcspn(server, ":");
123 sbuf = malloc(len + 1);
124 strncpy(sbuf, server, len);
126 port = strchr(server, ':') + 1;
130 port = strchr(MOIRA_SERVER, ':') + 1;
132 _mr_conn = mr_connect_internal(server, port);
135 return MR_CANT_CONNECT;
140 int mr_connect_internal(char *server, char *port)
143 struct sockaddr_in target;
144 struct hostent *shost;
145 char actualresponse[53];
147 int fd = SOCKET_ERROR;
149 int on = 1; /* Value variable for setsockopt() */
151 #if defined(_WIN32) && defined(HAVE_HESIOD)
152 shost = rgethostbyname(server);
154 shost = gethostbyname(server);
159 /* Get the host info in case some library decides to clobber shost. */
160 memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
161 target.sin_family = shost->h_addrtype;
162 host = strdup(shost->h_name);
165 target.sin_port = htons((unsigned short)atoi(port + 1));
170 s = getservbyname(port, "tcp");
172 target.sin_port = s->s_port;
174 if (!target.sin_port)
176 s = hes_getservbyname(port, "tcp");
178 target.sin_port = s->s_port;
181 if (!target.sin_port && !strcasecmp(port, DEFAULT_SERV))
182 target.sin_port = htons(DEFAULT_PORT);
183 if (!target.sin_port)
187 fd = socket(AF_INET, SOCK_STREAM, 0);
191 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(int)) < 0)
194 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
197 /* Do magic mrgdb initialization */
198 size = send(fd, challenge, sizeof(challenge), 0);
199 if (size != sizeof(challenge))
201 for (size = 0; size < sizeof(actualresponse); size += more)
203 more = recv(fd, actualresponse + size, sizeof(actualresponse) - size, 0);
207 if (size != sizeof(actualresponse))
209 if (memcmp(actualresponse, response, sizeof(actualresponse)))
213 mr_server_host = host;
220 if (fd != SOCKET_ERROR)
228 int mr_disconnect(void)
231 closesocket(_mr_conn);
233 free(mr_server_host);
234 mr_server_host = NULL;
238 int mr_host(char *host, int size)
242 /* If we are connected, mr_server_host points to a valid string. */
243 strncpy(host, mr_server_host, size);
244 host[size - 1] = '\0';
251 mr_params params, reply;
254 params.u.mr_procno = MR_NOOP;
256 params.mr_argl = NULL;
257 params.mr_argv = NULL;
259 if ((status = mr_do_call(¶ms, &reply)) == MR_SUCCESS)
260 status = reply.u.mr_status;
262 mr_destroy_reply(reply);
270 int mr_listen(char *port)
272 struct sockaddr_in sin;
275 memset(&sin, 0, sizeof(sin));
276 sin.sin_family = AF_INET;
278 sin.sin_port = atoi(port + 1);
282 s = getservbyname(port, "tcp");
284 sin.sin_port = s->s_port;
290 s = hes_getservbyname(port, "tcp");
292 sin.sin_port = s->s_port;
296 #endif /* HAVE_HESIOD */
299 s = socket(AF_INET, SOCK_STREAM, 0);
302 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
307 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
312 if (listen(s, 5) < 0)
321 /* mr_accept returns -1 on accept() error, 0 on bad connection,
322 or connection fd on success */
324 int mr_accept(int s, struct sockaddr_in *sin)
326 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
331 conn = accept(s, (struct sockaddr *)sin, &addrlen);
332 if (conn < 0 && errno != EINTR
337 && errno != ECONNABORTED
344 status = mr_cont_accept(conn, &buf, &nread);
345 while (status == -1);
350 /* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
351 or -1 if it is still making progress */
353 int mr_cont_accept(int conn, char **buf, int *nread)
360 if (recv(conn, lbuf, 4, 0) != 4)
368 if (len < 58 || len > 1000)
387 more = recv(conn, *buf + *nread, len - *nread, 0);
392 /* If we read 0 bytes, the remote end has gone away. */
395 /* If errno is EINTR, return -1 and try again, otherwise we failed. */
412 if (memcmp(*buf + 4, challenge + 4, 34))
422 if (send(conn, response, sizeof(response), 0) != sizeof(response))