]> andersk Git - moira.git/blob - lib/mr_connect.c
fix bug introduced in previous patch: `[' is no longer a glob character,
[moira.git] / lib / mr_connect.c
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 #include <sys/socket.h>
18
19 #include <netinet/in.h>
20 #include <netdb.h>
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include <hesiod.h>
28
29 RCSID("$Header$");
30
31 int _mr_conn = 0;
32 static char *mr_server_host = NULL;
33
34 /* mrgdb compatibility magic
35
36    The data looks like this:
37
38    client -> server
39      00000036                           [length of rest of packet]
40      00000004                           [number of fields]
41      01 01 01 01                        [types of fields: 4 strings]
42      "server_id\0parms\0host\0user\0"   [field names]
43      00000001                           [length of null-terminated server_id]
44      "\0"                               [server_id: ignored anyway]
45      00000001                           [length of null-terminated parms]
46      "\0"                               [parms: ignored anyway]
47      00000001                           [length of null-terminated client host]
48      "\0"                               [host: ignored anyway]
49      00000001                           [length of null-terminated client name]
50      "\0"                               [user: ignored anyway]
51
52    server -> client
53      00000031                           [length of rest of packet]
54      00000003                           [number of fields]
55      00 01 01                           [types of fields: int and 2 strings]
56      "disposition\0server_id\0parms\0"  [field names]
57      00000001                           [GDB_ACCEPTED]
58      00000001                           [length of null-terminated server_id]
59      "\0"                               [server_id: ignored anyway]
60      00000001                           [length of null-terminated parms]
61      "\0"                               [parms: ignored anyway]
62
63 */
64
65 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";
66 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";
67
68 /*
69  * Open a connection to the moira server.  Looks for the server name
70  * 1) passed as an argument, 2) in environment variable, 3) by hesiod
71  * 4) compiled in default
72  */
73
74 int mr_connect(char *server)
75 {
76   char *port, **pp, *sbuf = NULL;
77   struct hostent *shost;
78
79   if (_mr_conn)
80     return MR_ALREADY_CONNECTED;
81   if (!mr_inited)
82     mr_init();
83
84   if (!server || (strlen(server) == 0))
85     server = getenv("MOIRASERVER");
86
87 #ifdef HESIOD
88   if (!server || (strlen(server) == 0))
89     {
90       pp = hes_resolve("moira", "sloc");
91       if (pp)
92         server = *pp;
93     }
94 #endif
95
96   if (!server || (strlen(server) == 0))
97     server = MOIRA_SERVER;
98
99   shost = gethostbyname(server);
100   if (!shost)
101     return MR_CANT_CONNECT;
102
103   if (strchr(server, ':'))
104     {
105       int len = strcspn(server, ":");
106       sbuf = malloc(len + 1);
107       strncpy(sbuf, server, len);
108       sbuf[len - 1] = '\0';
109       server = sbuf;
110       port = strchr(server, ':') + 1;
111     }
112   else
113     port = strchr(MOIRA_SERVER, ':') + 1;
114
115   _mr_conn = mr_connect_internal(server, port);
116   free(sbuf);
117   if (!_mr_conn)
118     return MR_CANT_CONNECT;
119
120   /* stash hostname for later use */
121   mr_server_host = strdup(shost->h_name);
122   return MR_SUCCESS;
123 }
124
125 int mr_connect_internal(char *server, char *port)
126 {
127   int fd, size, more;
128   struct sockaddr_in target;
129   struct hostent *shost;
130   char actualresponse[53];
131
132   shost = gethostbyname(server);
133   if (!shost)
134     return 0;
135
136   if (port[0] == '#')
137     target.sin_port = atoi(port + 1);
138   else
139     {
140       struct servent *s;
141       s = getservbyname(port, "tcp");
142       if (s)
143         target.sin_port = s->s_port;
144       else
145         return 0;
146     }
147
148   memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
149   target.sin_family = shost->h_addrtype;
150
151   fd = socket(AF_INET, SOCK_STREAM, 0);
152   if (fd < 0)
153     return 0;
154
155   if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
156     {
157       close(fd);
158       return 0;
159     }
160
161   /* Do magic mrgdb initialization */
162   size = write(fd, challenge, sizeof(challenge));
163   if (size != sizeof(challenge))
164     {
165       close(fd);
166       return 0;
167     }
168   for (size = 0; size < sizeof(actualresponse); size += more)
169     {
170       more = read(fd, actualresponse + size, sizeof(actualresponse) - size);
171       if (!more)
172         break;
173     }
174   if (size != sizeof(actualresponse))
175     {
176       close(fd);
177       return 0;
178     }
179   if (memcmp(actualresponse, response, sizeof(actualresponse)))
180     {
181       close(fd);
182       return 0;
183     }
184
185   /* You win */
186   return fd;
187 }
188
189 int mr_disconnect(void)
190 {
191   CHECK_CONNECTED;
192   close(_mr_conn);
193   _mr_conn = 0;
194   free(mr_server_host);
195   mr_server_host = NULL;
196   return MR_SUCCESS;
197 }
198
199 int mr_host(char *host, int size)
200 {
201   CHECK_CONNECTED;
202
203   /* If we are connected, mr_server_host points to a valid string. */
204   strncpy(host, mr_server_host, size);
205   host[size - 1] = '\0';
206   return MR_SUCCESS;
207 }
208
209 int mr_noop(void)
210 {
211   int status;
212   mr_params params, reply;
213
214   CHECK_CONNECTED;
215   params.u.mr_procno = MR_NOOP;
216   params.mr_argc = 0;
217   params.mr_argl = NULL;
218   params.mr_argv = NULL;
219
220   if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
221     status = reply.u.mr_status;
222
223   mr_destroy_reply(reply);
224
225   return status;
226 }
227
228
229 /* Server side */
230
231 int mr_listen(char *port)
232 {
233   struct sockaddr_in sin;
234   int s, on = 1;
235
236   memset(&sin, 0, sizeof(sin));
237   if (port[0] == '#')
238     sin.sin_port = atoi(port + 1);
239   else
240     {
241       struct servent *s;
242       s = getservbyname(port, "tcp");
243       if (s)
244         sin.sin_port = s->s_port;
245       else
246         return -1;
247     }
248
249   s = socket(AF_INET, SOCK_STREAM, 0);
250   if (s < 0)
251     return -1;
252   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
253     {
254       close(s);
255       return -1;
256     }
257   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
258     {
259       close(s);
260       return -1;
261     }
262   if (listen(s, 5) < 0)
263     {
264       close(s);
265       return -1;
266     }
267
268   return s;
269 }
270
271 int mr_accept(int s, struct sockaddr_in *sin)
272 {
273   int conn, addrlen = sizeof(struct sockaddr_in);
274   char lbuf[4], *buf;
275   long len, size, more;
276
277   conn = accept(s, (struct sockaddr *)sin, &addrlen);
278   if (conn < 0)
279     return -1;
280
281   /* Now do mrgdb accept protocol */
282   /* XXX timeout */
283
284   if (read(conn, lbuf, 4) != 4)
285     {
286       close(conn);
287       return -1;
288     }
289   getlong(lbuf, len);
290
291   buf = malloc(len);
292   if (!buf || len < 54)
293     {
294       close(conn);
295       free(buf);
296       return -1;
297     }
298
299   for (size = 0; size < len; size += more)
300     {
301       more = read(conn, buf + size, len - size);
302       if (!more)
303         break;
304     }
305   if (size != len)
306     {
307       close(conn);
308       free(buf);
309       return 0;
310     }
311
312   if (memcmp(buf, challenge + 4, 34))
313     {
314       close(conn);
315       free(buf);
316       return 0;
317     }
318
319   /* good enough */
320   free(buf);
321
322   if (write(conn, response, sizeof(response)) != sizeof(response))
323     {
324       close(conn);
325       return -1;
326     }
327   return conn;
328 }
This page took 0.061637 seconds and 5 git commands to generate.