]> andersk Git - moira.git/blobdiff - lib/mr_connect.c
add mr_proxy()
[moira.git] / lib / mr_connect.c
index 366166ad9c06ae31c0cad5f52da0b1b7125226ae..2448ecbe686b3dd934c7d68241c67e1bd9ac7a4b 100644 (file)
-/*
- *     $Source$
- *     $Author$
- *     $Header$
+/* $Id$
+ *
+ * This routine is part of the client library.  It handles
+ * creating a connection to the moira server.
  *
- *     Copyright (C) 1987 by the Massachusetts Institute of Technology
- *     For copying and distribution information, please see the file
- *     <mit-copyright.h>.
- *     
- *     This routine is part of the client library.  It handles
- *     creating a connection to the sms server.
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
  */
 
-#ifndef lint
-static char *rcsid_sms_connect_c = "$Header$";
-#endif lint
-
 #include <mit-copyright.h>
-#include "sms_private.h"
-#include <sms_app.h>
-#include <strings.h>
+#include <moira.h>
+#include <moira_site.h>
+#include "mr_private.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_HESIOD
+#include <hesiod.h>
+#endif
+
+RCSID("$Header$");
+
+int _mr_conn = 0;
+static char *mr_server_host = NULL;
+
+/* mrgdb compatibility magic
+
+   The data looks like this:
 
-static char *sms_server_host = 0;
+   client -> server
+     00000036                          [length of rest of packet]
+     00000004                          [number of fields]
+     01 01 01 01                       [types of fields: 4 strings]
+     "server_id\0parms\0host\0user\0"  [field names]
+     00000001                          [length of null-terminated server_id]
+     "\0"                              [server_id: ignored anyway]
+     00000001                          [length of null-terminated parms]
+     "\0"                              [parms: ignored anyway]
+     00000001                          [length of null-terminated client host]
+     "\0"                              [host: ignored anyway]
+     00000001                          [length of null-terminated client name]
+     "\0"                              [user: ignored anyway]
+
+   server -> client
+     00000031                          [length of rest of packet]
+     00000003                          [number of fields]
+     00 01 01                          [types of fields: int and 2 strings]
+     "disposition\0server_id\0parms\0" [field names]
+     00000001                          [GDB_ACCEPTED]
+     00000001                          [length of null-terminated server_id]
+     "\0"                              [server_id: ignored anyway]
+     00000001                          [length of null-terminated parms]
+     "\0"                              [parms: ignored anyway]
+
+*/
+
+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";
+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";
 
 /*
- * Open a connection to the sms server.  Looks for the server name
+ * Open a connection to the moira server.  Looks for the server name
  * 1) passed as an argument, 2) in environment variable, 3) by hesiod
- * 4) compiled in default (from sms_app.h).
+ * 4) compiled in default
  */
 
-int sms_connect(server)
-char *server;
+int mr_connect(char *server)
 {
-    extern int errno;
-    char *p, **pp, sbuf[256];
-    extern char *getenv(), **hes_resolve();
-       
-    if (!sms_inited) sms_init();
-    if (_sms_conn) return SMS_ALREADY_CONNECTED;
-               
-    if (!server || (strlen(server) == 0)) {
-       server = getenv("MOIRASERVER");
-    }
-
-#ifdef HESIOD
-    if (!server || (strlen(server) == 0)) {
-       pp = hes_resolve("moira", "sloc");
-       if (pp) server = *pp;
-    }
-#endif HESIOD
-
-    if (!server || (strlen(server) == 0)) {
-       server = SMS_SERVER;
-    }
-
-    if (!index(server, ':')) {
-       p = index(SMS_SERVER, ':');
-       p++;
-       sprintf(sbuf, "%s:%s", server, p);
-       server = sbuf;
-    }
-
-    errno = 0;
-    _sms_conn = start_server_connection(server, ""); 
-    if (_sms_conn == NULL)
-       return errno;
-    if (connection_status(_sms_conn) == CON_STOPPED) {
-       register status = connection_errno(_sms_conn);
-       if (!status) status = SMS_CANT_CONNECT;
-       sms_disconnect();
-       return status;
-    }
-
-    /*
-     * stash hostname for later use
-     */
-
-    sms_server_host = strsave(server);
-    if (p = index(sms_server_host, ':'))
-       *p = 0;
-    sms_server_host = canonicalize_hostname(sms_server_host);
-    return 0;
+  char *port, **pp, *sbuf = NULL;
+
+  if (_mr_conn)
+    return MR_ALREADY_CONNECTED;
+  if (!mr_inited)
+    mr_init();
+
+  if (!server || (strlen(server) == 0))
+    server = getenv("MOIRASERVER");
+
+#ifdef HAVE_HESIOD
+  if (!server || (strlen(server) == 0))
+    {
+      pp = hes_resolve("moira", "sloc");
+      if (pp)
+       server = *pp;
+    }
+#endif
+
+  if (!server || (strlen(server) == 0))
+    server = MOIRA_SERVER;
+
+  if (strchr(server, ':'))
+    {
+      int len = strcspn(server, ":");
+      sbuf = malloc(len + 1);
+      strncpy(sbuf, server, len);
+      sbuf[len] = '\0';
+      port = strchr(server, ':') + 1;
+      server = sbuf;
+    }
+  else
+    port = strchr(MOIRA_SERVER, ':') + 1;
+
+  _mr_conn = mr_connect_internal(server, port);
+  free(sbuf);
+  if (!_mr_conn)
+    return MR_CANT_CONNECT;
+
+  return MR_SUCCESS;
 }
-       
-int sms_disconnect()
+
+int mr_connect_internal(char *server, char *port)
 {
-    CHECK_CONNECTED;
-    _sms_conn = sever_connection(_sms_conn);
-    free(sms_server_host);
-    sms_server_host = 0;
+  int fd, size, more;
+  struct sockaddr_in target;
+  struct hostent *shost;
+  char actualresponse[53];
+
+  shost = gethostbyname(server);
+  if (!shost)
     return 0;
+
+  if (port[0] == '#')
+    target.sin_port = htons(atoi(port + 1));
+  else
+    {
+      struct servent *s;
+      s = getservbyname(port, "tcp");
+      if (s)
+       target.sin_port = s->s_port;
+      else
+       return 0;
+    }
+
+  memcpy(&target.sin_addr, shost->h_addr, shost->h_length);
+  target.sin_family = shost->h_addrtype;
+
+  fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (fd < 0)
+    return 0;
+
+  if (connect(fd, (struct sockaddr *)&target, sizeof(target)) < 0)
+    {
+      close(fd);
+      return 0;
+    }
+
+  /* Do magic mrgdb initialization */
+  size = write(fd, challenge, sizeof(challenge));
+  if (size != sizeof(challenge))
+    {
+      close(fd);
+      return 0;
+    }
+  for (size = 0; size < sizeof(actualresponse); size += more)
+    {
+      more = read(fd, actualresponse + size, sizeof(actualresponse) - size);
+      if (more <= 0)
+       break;
+    }
+  if (size != sizeof(actualresponse))
+    {
+      close(fd);
+      return 0;
+    }
+  if (memcmp(actualresponse, response, sizeof(actualresponse)))
+    {
+      close(fd);
+      return 0;
+    }
+
+  mr_server_host = strdup(shost->h_name);
+
+  /* You win */
+  return fd;
+}
+
+int mr_disconnect(void)
+{
+  CHECK_CONNECTED;
+  close(_mr_conn);
+  _mr_conn = 0;
+  free(mr_server_host);
+  mr_server_host = NULL;
+  return MR_SUCCESS;
+}
+
+int mr_host(char *host, int size)
+{
+  CHECK_CONNECTED;
+
+  /* If we are connected, mr_server_host points to a valid string. */
+  strncpy(host, mr_server_host, size);
+  host[size - 1] = '\0';
+  return MR_SUCCESS;
+}
+
+int mr_noop(void)
+{
+  int status;
+  mr_params params, reply;
+
+  CHECK_CONNECTED;
+  params.u.mr_procno = MR_NOOP;
+  params.mr_argc = 0;
+  params.mr_argl = NULL;
+  params.mr_argv = NULL;
+
+  if ((status = mr_do_call(&params, &reply)) == MR_SUCCESS)
+    status = reply.u.mr_status;
+
+  mr_destroy_reply(reply);
+
+  return status;
+}
+
+
+/* Server side */
+
+int mr_listen(char *port)
+{
+  struct sockaddr_in sin;
+  int s, on = 1;
+
+  memset(&sin, 0, sizeof(sin));
+  if (port[0] == '#')
+    sin.sin_port = atoi(port + 1);
+  else
+    {
+      struct servent *s;
+      s = getservbyname(port, "tcp");
+      if (s)
+       sin.sin_port = s->s_port;
+      else
+       return -1;
+    }
+
+  s = socket(AF_INET, SOCK_STREAM, 0);
+  if (s < 0)
+    return -1;
+  if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
+    {
+      close(s);
+      return -1;
+    }
+  if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+    {
+      close(s);
+      return -1;
+    }
+  if (listen(s, 5) < 0)
+    {
+      close(s);
+      return -1;
+    }
+
+  return s;
 }
 
-int sms_host(host, size)
-  char *host;
-  int size;
+/* mr_accept returns -1 on accept() error, 0 on bad connection,
+   or connection fd on success */
+
+int mr_accept(int s, struct sockaddr_in *sin)
 {
-    CHECK_CONNECTED;
+  int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
+  char *buf = NULL;
+
+  while (conn < 0)
+    {
+      conn = accept(s, (struct sockaddr *)sin, &addrlen);
+      if (conn < 0 && errno != EINTR
+#ifdef ERESTART
+         && errno != ERESTART
+#endif
+         )
+       return -1;
+    }
 
-    /* If we are connected, sms_server_host points to a valid string. */
-    strncpy(host, sms_server_host, size);
-    return(0);
+  do
+    status = mr_cont_accept(conn, &buf, &nread);
+  while (status == -1);
+
+  return status;
 }
 
-int sms_noop()
+/* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
+   or -1 if it is still making progress */
+
+int mr_cont_accept(int conn, char **buf, int *nread)
 {
-    int status;
-    sms_params param_st;
-    struct sms_params *params = NULL;
-    struct sms_params *reply = NULL;
-
-    CHECK_CONNECTED;
-    params = &param_st;
-    params->sms_version_no = sending_version_no;
-    params->sms_procno = SMS_NOOP;
-    params->sms_argc = 0;
-    params->sms_argl = NULL;
-    params->sms_argv = NULL;
-       
-    if ((status = sms_do_call(params, &reply)) == 0)
-       status = reply->sms_status;
-       
-    sms_destroy_reply(reply);
-
-    return status;
+  long len, more;
+
+  if (!*buf)
+    {
+      char lbuf[4];
+      if (read(conn, lbuf, 4) != 4)
+       {
+         close(conn);
+         return 0;
+       }
+      getlong(lbuf, len);
+      len += 4;
+
+      *buf = malloc(len);
+      if (!*buf || len < 58)
+       {
+         close(conn);
+         free(*buf);
+         return 0;
+       }
+      putlong(*buf, len);
+      *nread = 4;
+      return -1;
+    }
+  else
+    getlong(*buf, len);
+
+  more = read(conn, *buf + *nread, len - *nread);
+
+  if (more == -1 && errno != EINTR)
+    {
+      close(conn);
+      free(*buf);
+      return 0;
+    }
+
+  *nread += more;
+
+  if (*nread != len)
+    return -1;
+
+  if (memcmp(*buf + 4, challenge + 4, 34))
+    {
+      close(conn);
+      free(*buf);
+      return 0;
+    }
+
+  /* good enough */
+  free(*buf);
+
+  if (write(conn, response, sizeof(response)) != sizeof(response))
+    {
+      close(conn);
+      return 0;
+    }
+  return conn;
 }
This page took 0.150204 seconds and 4 git commands to generate.