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
44 #define DEFAULT_SERV "moira_db"
45 #define DEFAULT_PORT 775
48 static char *mr_server_host = NULL;
50 /* mrgdb compatibility magic
52 The data looks like this:
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]
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]
81 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";
82 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";
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
90 int mr_connect(char *server)
92 char *port, **pp, *sbuf = NULL;
95 return MR_ALREADY_CONNECTED;
99 if (!server || (strlen(server) == 0))
100 server = getenv("MOIRASERVER");
103 if (!server || (strlen(server) == 0))
105 pp = hes_resolve("moira", "sloc");
111 if (!server || (strlen(server) == 0))
112 server = MOIRA_SERVER;
114 if (strchr(server, ':'))
116 int len = strcspn(server, ":");
117 sbuf = malloc(len + 1);
118 strncpy(sbuf, server, len);
120 port = strchr(server, ':') + 1;
124 port = strchr(MOIRA_SERVER, ':') + 1;
126 _mr_conn = mr_connect_internal(server, port);
129 return MR_CANT_CONNECT;
134 int mr_connect_internal(char *server, char *port)
137 struct sockaddr_in target;
138 struct hostent *shost;
139 char actualresponse[53];
141 int fd = SOCKET_ERROR;
143 int on = 1; /* Value variable for setsockopt() */
145 shost = gethostbyname(server);
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);
155 target.sin_port = htons((unsigned short)atoi(port + 1));
160 s = getservbyname(port, "tcp");
162 target.sin_port = s->s_port;
164 if (!target.sin_port)
166 s = hes_getservbyname(port, "tcp");
168 target.sin_port = s->s_port;
171 if (!target.sin_port && !strcasecmp(port, DEFAULT_SERV))
172 target.sin_port = htons(DEFAULT_PORT);
173 if (!target.sin_port)
177 fd = socket(AF_INET, SOCK_STREAM, 0);
181 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(int)) < 0)
184 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
187 /* Do magic mrgdb initialization */
188 size = send(fd, challenge, sizeof(challenge), 0);
189 if (size != sizeof(challenge))
191 for (size = 0; size < sizeof(actualresponse); size += more)
193 more = recv(fd, actualresponse + size, sizeof(actualresponse) - size, 0);
197 if (size != sizeof(actualresponse))
199 if (memcmp(actualresponse, response, sizeof(actualresponse)))
203 mr_server_host = host;
210 if (fd != SOCKET_ERROR)
218 int mr_disconnect(void)
221 closesocket(_mr_conn);
223 free(mr_server_host);
224 mr_server_host = NULL;
228 int mr_host(char *host, int size)
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';
241 mr_params params, reply;
244 params.u.mr_procno = MR_NOOP;
246 params.mr_argl = NULL;
247 params.mr_argv = NULL;
249 if ((status = mr_do_call(¶ms, &reply)) == MR_SUCCESS)
250 status = reply.u.mr_status;
252 mr_destroy_reply(reply);
260 int mr_listen(char *port)
262 struct sockaddr_in sin;
265 memset(&sin, 0, sizeof(sin));
267 sin.sin_port = atoi(port + 1);
271 s = getservbyname(port, "tcp");
273 sin.sin_port = s->s_port;
278 s = socket(AF_INET, SOCK_STREAM, 0);
281 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
286 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
291 if (listen(s, 5) < 0)
300 /* mr_accept returns -1 on accept() error, 0 on bad connection,
301 or connection fd on success */
303 int mr_accept(int s, struct sockaddr_in *sin)
305 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
310 conn = accept(s, (struct sockaddr *)sin, &addrlen);
311 if (conn < 0 && errno != EINTR
320 status = mr_cont_accept(conn, &buf, &nread);
321 while (status == -1);
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 */
329 int mr_cont_accept(int conn, char **buf, int *nread)
336 if (recv(conn, lbuf, 4, 0) != 4)
345 if (!*buf || len < 58)
358 more = recv(conn, *buf + *nread, len - *nread, 0);
360 if (more == -1 && errno != EINTR)
372 if (memcmp(*buf + 4, challenge + 4, 34))
382 if (send(conn, response, sizeof(response), 0) != sizeof(response))