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