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;
144 shost = gethostbyname(server);
148 /* Get the host info in case some library decides to clobber shost. */
149 memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
150 target.sin_family = shost->h_addrtype;
151 host = strdup(shost->h_name);
154 target.sin_port = htons((unsigned short)atoi(port + 1));
159 s = getservbyname(port, "tcp");
161 target.sin_port = s->s_port;
163 if (!target.sin_port)
165 s = hes_getservbyname(port, "tcp");
167 target.sin_port = s->s_port;
170 if (!target.sin_port && !strcasecmp(port, DEFAULT_SERV))
171 target.sin_port = htons(DEFAULT_PORT);
172 if (!target.sin_port)
176 fd = socket(AF_INET, SOCK_STREAM, 0);
180 if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
183 /* Do magic mrgdb initialization */
184 size = send(fd, challenge, sizeof(challenge), 0);
185 if (size != sizeof(challenge))
187 for (size = 0; size < sizeof(actualresponse); size += more)
189 more = recv(fd, actualresponse + size, sizeof(actualresponse) - size, 0);
193 if (size != sizeof(actualresponse))
195 if (memcmp(actualresponse, response, sizeof(actualresponse)))
199 mr_server_host = host;
206 if (fd != SOCKET_ERROR)
214 int mr_disconnect(void)
217 closesocket(_mr_conn);
219 free(mr_server_host);
220 mr_server_host = NULL;
224 int mr_host(char *host, int size)
228 /* If we are connected, mr_server_host points to a valid string. */
229 strncpy(host, mr_server_host, size);
230 host[size - 1] = '\0';
237 mr_params params, reply;
240 params.u.mr_procno = MR_NOOP;
242 params.mr_argl = NULL;
243 params.mr_argv = NULL;
245 if ((status = mr_do_call(¶ms, &reply)) == MR_SUCCESS)
246 status = reply.u.mr_status;
248 mr_destroy_reply(reply);
256 int mr_listen(char *port)
258 struct sockaddr_in sin;
261 memset(&sin, 0, sizeof(sin));
263 sin.sin_port = atoi(port + 1);
267 s = getservbyname(port, "tcp");
269 sin.sin_port = s->s_port;
274 s = socket(AF_INET, SOCK_STREAM, 0);
277 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
282 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
287 if (listen(s, 5) < 0)
296 /* mr_accept returns -1 on accept() error, 0 on bad connection,
297 or connection fd on success */
299 int mr_accept(int s, struct sockaddr_in *sin)
301 int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
306 conn = accept(s, (struct sockaddr *)sin, &addrlen);
307 if (conn < 0 && errno != EINTR
316 status = mr_cont_accept(conn, &buf, &nread);
317 while (status == -1);
322 /* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
323 or -1 if it is still making progress */
325 int mr_cont_accept(int conn, char **buf, int *nread)
332 if (recv(conn, lbuf, 4, 0) != 4)
341 if (!*buf || len < 58)
354 more = recv(conn, *buf + *nread, len - *nread, 0);
356 if (more == -1 && errno != EINTR)
368 if (memcmp(*buf + 4, challenge + 4, 34))
378 if (send(conn, response, sizeof(response), 0) != sizeof(response))