]> andersk Git - moira.git/blob - lib/mr_connect.c
oops. don't rely on stack garbage to initialize our pointers
[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 #ifdef HAVE_HESIOD
28 #include <hesiod.h>
29 #endif
30
31 RCSID("$Header$");
32
33 int _mr_conn = 0;
34 static 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
67 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";
68 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";
69
70 /*
71  * Open a connection to the moira server.  Looks for the server name
72  * 1) passed as an argument, 2) in environment variable, 3) by hesiod
73  * 4) compiled in default
74  */
75
76 int mr_connect(char *server)
77 {
78   char *port, **pp, *sbuf = NULL;
79
80   if (_mr_conn)
81     return MR_ALREADY_CONNECTED;
82   if (!mr_inited)
83     mr_init();
84
85   if (!server || (strlen(server) == 0))
86     server = getenv("MOIRASERVER");
87
88 #ifdef HAVE_HESIOD
89   if (!server || (strlen(server) == 0))
90     {
91       pp = hes_resolve("moira", "sloc");
92       if (pp)
93         server = *pp;
94     }
95 #endif
96
97   if (!server || (strlen(server) == 0))
98     server = MOIRA_SERVER;
99
100   if (strchr(server, ':'))
101     {
102       int len = strcspn(server, ":");
103       sbuf = malloc(len + 1);
104       strncpy(sbuf, server, len);
105       sbuf[len] = '\0';
106       port = strchr(server, ':') + 1;
107       server = sbuf;
108     }
109   else
110     port = strchr(MOIRA_SERVER, ':') + 1;
111
112   _mr_conn = mr_connect_internal(server, port);
113   free(sbuf);
114   if (!_mr_conn)
115     return MR_CANT_CONNECT;
116
117   return MR_SUCCESS;
118 }
119
120 int mr_connect_internal(char *server, char *port)
121 {
122   int fd, size, more;
123   struct sockaddr_in target;
124   struct hostent *shost;
125   char actualresponse[53];
126
127   shost = gethostbyname(server);
128   if (!shost)
129     return 0;
130
131   if (port[0] == '#')
132     target.sin_port = htons(atoi(port + 1));
133   else
134     {
135       struct servent *s;
136       s = getservbyname(port, "tcp");
137       if (s)
138         target.sin_port = s->s_port;
139       else
140         return 0;
141     }
142
143   memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
144   target.sin_family = shost->h_addrtype;
145
146   fd = socket(AF_INET, SOCK_STREAM, 0);
147   if (fd < 0)
148     return 0;
149
150   if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
151     {
152       close(fd);
153       return 0;
154     }
155
156   /* Do magic mrgdb initialization */
157   size = write(fd, challenge, sizeof(challenge));
158   if (size != sizeof(challenge))
159     {
160       close(fd);
161       return 0;
162     }
163   for (size = 0; size < sizeof(actualresponse); size += more)
164     {
165       more = read(fd, actualresponse + size, sizeof(actualresponse) - size);
166       if (more <= 0)
167         break;
168     }
169   if (size != sizeof(actualresponse))
170     {
171       close(fd);
172       return 0;
173     }
174   if (memcmp(actualresponse, response, sizeof(actualresponse)))
175     {
176       close(fd);
177       return 0;
178     }
179
180   mr_server_host = strdup(shost->h_name);
181
182   /* You win */
183   return fd;
184 }
185
186 int mr_disconnect(void)
187 {
188   CHECK_CONNECTED;
189   close(_mr_conn);
190   _mr_conn = 0;
191   free(mr_server_host);
192   mr_server_host = NULL;
193   return MR_SUCCESS;
194 }
195
196 int mr_host(char *host, int size)
197 {
198   CHECK_CONNECTED;
199
200   /* If we are connected, mr_server_host points to a valid string. */
201   strncpy(host, mr_server_host, size);
202   host[size - 1] = '\0';
203   return MR_SUCCESS;
204 }
205
206 int mr_noop(void)
207 {
208   int status;
209   mr_params params, reply;
210
211   CHECK_CONNECTED;
212   params.u.mr_procno = MR_NOOP;
213   params.mr_argc = 0;
214   params.mr_argl = NULL;
215   params.mr_argv = NULL;
216
217   if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
218     status = reply.u.mr_status;
219
220   mr_destroy_reply(reply);
221
222   return status;
223 }
224
225
226 /* Server side */
227
228 int mr_listen(char *port)
229 {
230   struct sockaddr_in sin;
231   int s, on = 1;
232
233   memset(&sin, 0, sizeof(sin));
234   if (port[0] == '#')
235     sin.sin_port = atoi(port + 1);
236   else
237     {
238       struct servent *s;
239       s = getservbyname(port, "tcp");
240       if (s)
241         sin.sin_port = s->s_port;
242       else
243         return -1;
244     }
245
246   s = socket(AF_INET, SOCK_STREAM, 0);
247   if (s < 0)
248     return -1;
249   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
250     {
251       close(s);
252       return -1;
253     }
254   if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
255     {
256       close(s);
257       return -1;
258     }
259   if (listen(s, 5) < 0)
260     {
261       close(s);
262       return -1;
263     }
264
265   return s;
266 }
267
268 /* mr_accept returns -1 on accept() error, 0 on bad connection,
269    or connection fd on success */
270
271 int mr_accept(int s, struct sockaddr_in *sin)
272 {
273   int conn, addrlen = sizeof(struct sockaddr_in), nread, status;
274   char *buf = NULL;
275
276   conn = accept(s, (struct sockaddr *)sin, &addrlen);
277   if (conn < 0)
278     return -1;
279
280   do
281     status = mr_cont_accept(conn, &buf, &nread);
282   while (status == -1);
283
284   return status;
285 }
286
287 /* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
288    or -1 if it is still making progress */
289
290 int mr_cont_accept(int conn, char **buf, int *nread)
291 {
292   long len, more;
293
294   if (!*buf)
295     {
296       char lbuf[4];
297       if (read(conn, lbuf, 4) != 4)
298         {
299           close(conn);
300           return 0;
301         }
302       getlong(lbuf, len);
303       len += 4;
304
305       *buf = malloc(len);
306       if (!*buf || len < 58)
307         {
308           close(conn);
309           free(*buf);
310           return 0;
311         }
312       putlong(*buf, len);
313       *nread = 4;
314       return -1;
315     }
316   else
317     getlong(*buf, len);
318
319   more = read(conn, *buf + *nread, len - *nread);
320
321   if (more == -1 && errno != EINTR)
322     {
323       close(conn);
324       free(*buf);
325       return 0;
326     }
327
328   *nread += more;
329
330   if (*nread != len)
331     return -1;
332
333   if (memcmp(*buf + 4, challenge + 4, 34))
334     {
335       close(conn);
336       free(*buf);
337       return 0;
338     }
339
340   /* good enough */
341   free(*buf);
342
343   if (write(conn, response, sizeof(response)) != sizeof(response))
344     {
345       close(conn);
346       return 0;
347     }
348   return conn;
349 }
This page took 0.059917 seconds and 5 git commands to generate.