summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:53 +0000
commitdffaba3a2b5c9ba6db9fc9d866f39647dfae7d08 (patch)
tree067b38c5fa0e0d66b63919c6cc5f60718eb3535b
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r--config.c199
-rw-r--r--config.h47
-rw-r--r--main.c1113
-rw-r--r--pmconfig.cpp12
-rw-r--r--pmdb.c771
-rw-r--r--pmdb.h149
-rw-r--r--pmint.h184
-rw-r--r--proxymngr.man174
8 files changed, 2649 insertions, 0 deletions
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..7cc4f09
--- /dev/null
+++ b/config.c
@@ -0,0 +1,199 @@
+/* $Xorg: config.c,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+#include "pmint.h"
+#include "config.h"
+
+
+static Bool
+getline (
+char **pbuf,
+int *plen,
+FILE *f)
+
+{
+ int c, i;
+
+ i = 0;
+ while(1)
+ {
+ if (i+2 > *plen)
+ {
+ if (*plen)
+ *plen *= 2;
+ else
+ *plen = BUFSIZ;
+ if (*pbuf)
+ *pbuf = (char *) realloc (*pbuf, *plen + 1);
+ else
+ *pbuf = (char *) malloc (*plen + 1);
+ if (! *pbuf) {
+ fprintf (stderr, "Memory allocation failure reading config file\n");
+ return 0;
+ }
+ }
+ c = getc (f);
+ if (c == EOF)
+ break;
+ (*pbuf)[i++] = c;
+ if (c == '\n') {
+ i--;
+ break;
+ }
+ }
+ (*pbuf)[i] = '\0';
+ return i;
+}
+
+
+#ifdef NEED_STRCASECMP
+int
+ncasecmp (str1, str2, n)
+ char *str1, *str2;
+ int n;
+{
+ char buf1[512],buf2[512];
+ char c, *s;
+ register int i;
+
+ for (i=0, s = buf1; i < n && (c = *str1++); i++) {
+ if (isupper(c))
+ c = tolower(c);
+ if (i>510)
+ break;
+ *s++ = c;
+ }
+ *s = '\0';
+ for (i=0, s = buf2; i < n && (c = *str2++); i++) {
+ if (isupper(c))
+ c = tolower(c);
+ if (i>510)
+ break;
+ *s++ = c;
+ }
+ *s = '\0';
+ return (strncmp(buf1, buf2, n));
+}
+#endif /* NEED_STRCASECMP */
+
+
+Status
+GetConfig (
+ char *configFile,
+ char *serviceName,
+ Bool *managed,
+ char **startCommand,
+ char **proxyAddress)
+
+{
+ FILE *fp;
+ int found = 0;
+ char *buf, *p;
+ int buflen, n;
+
+ *startCommand = *proxyAddress = NULL;
+
+ fp = fopen (configFile, "r");
+
+ if (!fp)
+ return 0;
+
+ buf = NULL;
+ buflen = 0;
+ n = strlen (serviceName);
+
+ while (!found && getline (&buf, &buflen, fp))
+ {
+ if (buf[0] == '!')
+ continue;
+
+ if (!(ncasecmp (buf, serviceName, n) == 0 && buf[n] == ' '))
+ continue;
+
+ /* found the right config line */
+ p = buf + n + 1;
+ while (*p == ' ')
+ p++;
+ if (ncasecmp (p, "managed", 7) == 0)
+ {
+ *managed = 1;
+ p += 7;
+ }
+ else if (ncasecmp (p, "unmanaged", 9) == 0)
+ {
+ *managed = 0;
+ p += 9;
+ }
+ else
+ {
+ fprintf (stderr, "Error in config file at line \"%s\"\n", buf);
+ break;
+ }
+
+ while (*p == ' ')
+ p++;
+
+ if (*managed)
+ {
+ n = strlen (p);
+ *startCommand = (char *) malloc (n + 2);
+ if (! *startCommand) {
+ fprintf (stderr,
+ "Memory allocation failed for service \"%s\"\n",
+ serviceName);
+ break;
+ }
+ strcpy (*startCommand, p);
+ (*startCommand)[n] = '&';
+ (*startCommand)[n + 1] = '\0';
+ }
+ else
+ {
+ *proxyAddress = (char *) malloc (strlen (p) + 1);
+ if (! *proxyAddress) {
+ fprintf (stderr,
+ "Memory allocation failed for service \"%s\" at %s\n",
+ serviceName, p);
+ break;
+ }
+ strcpy (*proxyAddress, p);
+ }
+
+ found = 1;
+ }
+
+ if (buf)
+ free (buf);
+
+ fclose (fp);
+ return found;
+}
+
+
+
+
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..484b2a2
--- /dev/null
+++ b/config.h
@@ -0,0 +1,47 @@
+/* $Xorg: config.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+
+Status
+GetConfig (
+ char *configFile,
+ char *proxyService,
+ Bool *managed,
+ char **startCommand,
+ char **proxyAddress);
+
+#ifdef NEED_STRCASECMP
+int
+ncasecmp (
+ char *str1,
+ char *str2,
+ int n);
+#else
+#include <string.h>
+#define ncasecmp(s1,s2,n) strncasecmp(s1,s2,n)
+#endif /* NEED_STRCASECMP */
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2131092
--- /dev/null
+++ b/main.c
@@ -0,0 +1,1113 @@
+/* $Xorg: main.c,v 1.6 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+#include <stdlib.h>
+#include "pmint.h"
+#include <X11/StringDefs.h>
+#include <X11/Intrinsic.h>
+#include <X11/ICE/ICEmsg.h>
+#include <X11/ICE/ICEproto.h>
+#include <X11/PM/PMproto.h>
+#include <X11/PM/PM.h>
+#include "pmdb.h"
+#include "config.h"
+#include <assert.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+void InstallIOErrorHandler ();
+void NewConnectionXtProc ();
+static Status PMprotocolSetupProc ();
+void PMReplyProcessMessages ();
+void PMSetupProcessMessages ();
+Bool HostBasedAuthProc ();
+
+static int PMAcceptorOpcode;
+static int PMOriginatorOpcode;
+
+int PMversionCount = 1;
+IcePaVersionRec PMReplyVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION,
+ PMReplyProcessMessages}};
+IcePoVersionRec PMSetupVersions[] = {{PM_MAJOR_VERSION, PM_MINOR_VERSION,
+ PMSetupProcessMessages}};
+
+char *PM_VENDOR_STRING = "The X.Org Group";
+char *PM_VENDOR_RELEASE = "Release 6.6";
+
+int verbose = 0;
+
+XtAppContext appContext;
+
+#define PM_PORT "6500"
+
+char *configFile = NULL;
+
+void
+Usage ()
+{
+ fprintf (stderr, "Usage: proxymngr [-config file] [-verbose]\n");
+ exit (1);
+}
+
+void
+SetCloseOnExec (fd)
+ int fd;
+{
+ int ret;
+#ifdef F_SETFD
+#ifdef FD_CLOEXEC
+ ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
+#else
+ ret = fcntl (fd, F_SETFD, 1);
+#endif /* FD_CLOEXEC */
+#endif /* F_SETFD */
+}
+
+/*
+ * Main program
+ */
+
+main (argc, argv)
+
+int argc;
+char **argv;
+
+{
+ IceListenObj *listenObjs;
+ int numTransports, i;
+ char errormsg[256];
+ char *networkIds, *p;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "-config") == 0)
+ {
+ if (++i < argc)
+ configFile = argv[i];
+ else
+ Usage ();
+ }
+ else if (strcmp(argv[i], "-verbose") == 0)
+ {
+ verbose = 1;
+ }
+ else
+ Usage ();
+ }
+
+ if (!configFile)
+ configFile = CONFIG_FILE;
+
+ if (verbose)
+ fprintf (stderr, "config file = %s\n", configFile);
+
+ /*
+ * Install an IO error handler.
+ */
+ InstallIOErrorHandler ();
+
+ /*
+ * Register support for PROXY_MANAGEMENT.
+ */
+
+ /* For Managed proxies, the proxy does the Setup */
+ if ((PMAcceptorOpcode = IceRegisterForProtocolReply (
+ PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE,
+ PMversionCount, PMReplyVersions,
+ 0, /* authcount */
+ NULL, /* authnames */
+ NULL, /* authprocs */
+ HostBasedAuthProc,
+ PMprotocolSetupProc,
+ NULL, /* protocolActivateProc */
+ NULL /* IceIOErrorProc */ )) < 0)
+ {
+ fprintf (stderr,
+ "Could not register PROXY_MANAGEMENT protocol reply with ICE");
+ exit (1);
+ }
+
+ /* For Unmanaged proxies, we do the Setup
+ * ICElib doesn't specify that the same opCode will be returned
+ * so don't bet on it.
+ */
+ if ((PMOriginatorOpcode = IceRegisterForProtocolSetup (
+ PM_PROTOCOL_NAME, PM_VENDOR_STRING, PM_VENDOR_RELEASE,
+ PMversionCount, PMSetupVersions,
+ 0, /* authcount */
+ NULL, /* authnames */
+ NULL, /* authprocs */
+ NULL /* IceIOErrorProc */ )) < 0)
+ {
+ fprintf (stderr,
+ "Could not register PROXY_MANAGEMENT protocol setup with ICE");
+ exit (1);
+ }
+
+
+ if (!IceListenForWellKnownConnections (
+ PM_PORT, &numTransports, &listenObjs, 256, errormsg))
+ {
+ fprintf (stderr, "%s\n", errormsg);
+ exit (1);
+ }
+
+ networkIds = IceComposeNetworkIdList (numTransports, listenObjs);
+ p = (char *) malloc(sizeof ("PROXY_MANAGER") + strlen(networkIds) + 2);
+ sprintf (p, "PROXY_MANAGER=%s", networkIds);
+ putenv (p);
+ printf ("%s\n", p);
+ free (networkIds);
+
+ appContext = XtCreateApplicationContext ();
+
+ InitWatchProcs (appContext);
+
+ for (i = 0; i < numTransports; i++)
+ {
+ XtAppAddInput (appContext,
+ IceGetListenConnectionNumber (listenObjs[i]),
+ (XtPointer) XtInputReadMask,
+ NewConnectionXtProc, (XtPointer) listenObjs[i]);
+
+ IceSetHostBasedAuthProc (listenObjs[i], HostBasedAuthProc);
+
+ SetCloseOnExec (IceGetListenConnectionNumber (listenObjs[i]));
+ }
+
+ /*
+ * Main loop
+ */
+ XtAppMainLoop (appContext);
+}
+
+
+/*
+ * Xt callback invoked when a client attempts to connect.
+ */
+
+/* ARGSUSED */
+void
+NewConnectionXtProc (client_data, source, id)
+
+XtPointer client_data;
+int *source;
+XtInputId *id;
+
+{
+ IceConn ice_conn;
+ char *connstr;
+ IceAcceptStatus status;
+
+ ice_conn = IceAcceptConnection((IceListenObj) client_data, &status);
+ if (! ice_conn) {
+ if (verbose)
+ printf ("IceAcceptConnection failed\n");
+ } else {
+ IceConnectStatus cstatus;
+
+ /*
+ * Mark this fd to be closed upon exec
+ */
+ SetCloseOnExec (IceConnectionNumber (ice_conn));
+
+ while ((cstatus = IceConnectionStatus (ice_conn))==IceConnectPending) {
+ XtAppProcessEvent (appContext, XtIMAll);
+ }
+
+ if (cstatus == IceConnectAccepted) {
+ if (verbose) {
+ printf ("ICE Connection opened by client, IceConn fd = %d, ",
+ IceConnectionNumber (ice_conn));
+ connstr = IceConnectionString (ice_conn);
+ printf ("Accept at networkId %s\n", connstr);
+ free (connstr);
+ printf ("\n");
+ }
+ } else {
+ if (verbose)
+ {
+ if (cstatus == IceConnectIOError)
+ printf ("IO error opening ICE Connection!\n");
+ else
+ printf ("ICE Connection rejected!\n");
+ }
+
+ IceCloseConnection (ice_conn);
+ }
+ }
+}
+
+
+/*
+ * See ConnectToProxy() if you change any of the pmConn structure
+ */
+static Status
+PMprotocolSetupProc (iceConn,
+ majorVersion, minorVersion, vendor, release,
+ clientDataRet, failureReasonRet)
+
+IceConn iceConn;
+int majorVersion;
+int minorVersion;
+char *vendor;
+char *release;
+IcePointer *clientDataRet;
+char **failureReasonRet;
+
+{
+ /*
+ * Allocate new pmConn.
+ */
+
+ static char standardError[] = "Could not allocate memory for new client";
+ PMconn *pmConn;
+
+ if ((pmConn = (PMconn *) malloc (sizeof (PMconn))) == NULL)
+ {
+ if (verbose)
+ fprintf (stderr, "%s\n", standardError);
+
+ *failureReasonRet = standardError;
+ return (0);
+ }
+
+ pmConn->iceConn = iceConn;
+ pmConn->pmOpcode = PMAcceptorOpcode;
+ pmConn->proto_major_version = majorVersion;
+ pmConn->proto_minor_version = minorVersion;
+ pmConn->vendor = vendor;
+ pmConn->release = release;
+
+ *clientDataRet = (IcePointer) pmConn;
+
+ return (1);
+}
+
+
+static void
+SendGetProxyAddr (
+ PMconn *pmConn,
+ char *serviceName,
+ char *serverAddress,
+ char *hostAddress,
+ char *startOptions,
+ int authLen,
+ char *authName,
+ char *authData)
+
+{
+ IceConn iceConn = pmConn->iceConn;
+ pmGetProxyAddrMsg *pMsg;
+ char *pData;
+ int len;
+
+ if (verbose) {
+ printf ("Sending GetProxyAddr to proxy %d, serviceName = %s, serverAddr = %s\n",
+ IceConnectionNumber(iceConn), serviceName, serverAddress);
+ printf (" hostAddr = %s, options = %s, authLen = %d\n",
+ hostAddress ? hostAddress : "",
+ startOptions ? startOptions : "",
+ authLen);
+ if (authLen > 0)
+ printf (" authName = %s\n", authName);
+ }
+
+ len = STRING_BYTES (serviceName) +
+ STRING_BYTES (serverAddress) +
+ STRING_BYTES (hostAddress) +
+ STRING_BYTES (startOptions) +
+ (authLen > 0 ? (STRING_BYTES (authName) + authLen) : 0);
+
+ IceGetHeaderExtra (iceConn, pmConn->pmOpcode, PM_GetProxyAddr,
+ SIZEOF (pmGetProxyAddrMsg), WORD64COUNT (len),
+ pmGetProxyAddrMsg, pMsg, pData);
+
+ pMsg->authLen = authLen;
+
+ STORE_STRING (pData, serviceName);
+ STORE_STRING (pData, serverAddress);
+ STORE_STRING (pData, hostAddress);
+ STORE_STRING (pData, startOptions);
+ if (authLen > 0)
+ {
+ STORE_STRING (pData, authName);
+ memcpy (pData, authData, authLen);
+ }
+
+ IceFlush (iceConn);
+}
+
+
+void
+SendGetProxyAddrReply (
+ PMconn *requestor,
+ int status,
+ char *addr,
+ char *error)
+
+{
+ int len = STRING_BYTES (addr) + STRING_BYTES (error);
+ pmGetProxyAddrReplyMsg *pReply;
+ char *pData;
+
+ if (verbose) {
+ fputs ("Replying with ", stderr);
+ fputs (status == PM_Success ? "Success: " :
+ status == PM_Failure ? "Failure: " :
+ status == PM_Unable ? "Unable: " :
+ "?unknown status", stderr);
+ fputs (status == PM_Success ? addr : error, stderr);
+ fputc ('\n', stderr);
+ }
+
+ IceGetHeaderExtra (requestor->iceConn,
+ requestor->pmOpcode, PM_GetProxyAddrReply,
+ SIZEOF (pmGetProxyAddrReplyMsg), WORD64COUNT (len),
+ pmGetProxyAddrReplyMsg, pReply, pData);
+
+ pReply->status = status;
+
+ STORE_STRING (pData, addr);
+ STORE_STRING (pData, error);
+
+ IceFlush (requestor->iceConn);
+}
+
+
+
+void
+PMReplyProcessMessages (iceConn, clientData, opcode, length, swap)
+
+IceConn iceConn;
+IcePointer clientData;
+int opcode;
+unsigned long length;
+Bool swap;
+
+{
+ PMconn *pmConn = (PMconn *) clientData;
+
+ assert(pmConn->iceConn == iceConn);
+
+ switch (opcode)
+ {
+ case PM_GetProxyAddr:
+ {
+ pmGetProxyAddrMsg *pMsg;
+ char *pData, *pStart;
+ char *serviceName = NULL, *serverAddress = NULL;
+ char *hostAddress = NULL, *startOptions = NULL;
+ char *authName = NULL, *authData = NULL;
+ int authLen;
+
+ CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, SIZEOF (pmGetProxyAddrMsg), IceFatalToProtocol);
+
+ IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrMsg),
+ pmGetProxyAddrMsg, pMsg, pStart);
+
+ if (!IceValidIO (iceConn))
+ {
+ IceDisposeCompleteMessage (iceConn, pStart);
+ return;
+ }
+
+ authLen = swap ? lswaps (pMsg->authLen) : pMsg->authLen;
+
+ pData = pStart;
+
+ SKIP_STRING (pData, swap); /* proxy-service */
+ SKIP_STRING (pData, swap); /* server-address */
+ SKIP_STRING (pData, swap); /* host-address */
+ SKIP_STRING (pData, swap); /* start-options */
+ if (authLen > 0)
+ {
+ SKIP_STRING (pData, swap); /* auth-name */
+ pData += (authLen + PAD64 (authLen)); /* auth-data */
+ }
+
+ CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, pData - pStart + SIZEOF (pmGetProxyAddrMsg),
+ pStart, IceFatalToProtocol);
+
+ pData = pStart;
+
+ EXTRACT_STRING (pData, swap, serviceName);
+ EXTRACT_STRING (pData, swap, serverAddress);
+ EXTRACT_STRING (pData, swap, hostAddress);
+ EXTRACT_STRING (pData, swap, startOptions);
+ if (authLen > 0)
+ {
+ EXTRACT_STRING (pData, swap, authName);
+ authData = (char *) malloc (authLen);
+ memcpy (authData, pData, authLen);
+ }
+
+ if (serverAddress)
+ {
+ /*
+ * Assume that if serverAddress is something like :0 or :0.0
+ * then the request is for a server on the client's host.
+ *
+ * However, the proxy handling this request may be on a
+ * different host than the client or the client host,
+ * proxy host and the server host may all be different,
+ * thus a serverAddress of :0 or :0.0 is not useful.
+ * Therefore, change serverAddrees to use the client's
+ * hostname.
+ */
+ char *tmpName;
+
+ tmpName = strchr (serverAddress, ':');
+
+ if (tmpName && ((serverAddress[0] == ':') ||
+ (!strncmp (serverAddress, "unix:", 5))))
+ {
+ struct sockaddr_in serverSock;
+ int retVal;
+ int addrLen = sizeof(serverSock);
+
+ retVal = getpeername(IceConnectionNumber(iceConn),
+ (struct sockaddr *) &serverSock,
+ &addrLen);
+ if (!retVal)
+ {
+ struct hostent *hostent;
+
+ hostent = gethostbyname (inet_ntoa(serverSock.sin_addr));
+
+ if (hostent && hostent->h_name)
+ {
+ int len;
+ char * pch = strdup (tmpName);
+
+ len = strlen(hostent->h_name) + strlen(tmpName) + 1;
+ serverAddress = (char *) realloc (serverAddress, len);
+ sprintf (serverAddress, "%s%s", hostent->h_name, pch);
+ free (pch);
+ }
+ }
+ }
+ }
+
+ if (verbose) {
+ printf ("Got GetProxyAddr, serviceName = %s, serverAddr = %s\n",
+ serviceName, serverAddress);
+ printf (" hostAddr = %s, options = %s, authLen = %d\n",
+ hostAddress, startOptions, authLen);
+ if (authLen > 0)
+ printf (" authName = %s\n", authName);
+ }
+
+ IceDisposeCompleteMessage (iceConn, pStart);
+
+ ForwardRequest (pmConn, serviceName, serverAddress, hostAddress,
+ startOptions, authLen, authName, authData);
+
+ if (serviceName)
+ free (serviceName);
+ if (serverAddress)
+ free (serverAddress);
+ if (hostAddress)
+ free (hostAddress);
+ if (startOptions)
+ free (startOptions);
+ if (authName)
+ free (authName);
+ if (authData)
+ free (authData);
+
+ break;
+ }
+
+ case PM_StartProxy:
+ {
+ pmStartProxyMsg *pMsg;
+ char *pData, *pStart;
+ char *serviceName = NULL;
+ char *serverAddress;
+ char *hostAddress;
+ char *startOptions;
+ int authLen;
+ char *authName;
+ char *authData;
+
+ CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, SIZEOF (pmStartProxyMsg), IceFatalToProtocol);
+
+ IceReadCompleteMessage (iceConn, SIZEOF (pmStartProxyMsg),
+ pmStartProxyMsg, pMsg, pStart);
+
+ if (!IceValidIO (iceConn))
+ {
+ IceDisposeCompleteMessage (iceConn, pStart);
+ return;
+ }
+
+ pData = pStart;
+
+ SKIP_STRING (pData, swap); /* proxy-service */
+
+ CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, pData - pStart + SIZEOF (pmStartProxyMsg),
+ pStart, IceFatalToProtocol);
+
+ pData = pStart;
+
+ EXTRACT_STRING (pData, swap, serviceName);
+
+ assert(serviceName);
+
+ if (verbose)
+ printf ("Got StartProxy on fd %d, serviceName = %s\n",
+ IceConnectionNumber(iceConn), serviceName);
+
+ IceDisposeCompleteMessage (iceConn, pStart);
+
+ if (! ActivateProxyService (serviceName, pmConn)) {
+ fputs ("Configuration error: received unexpected StartProxy for service ", stderr);
+ fputs (serviceName, stderr);
+ fputc ('\n', stderr);
+ IceCloseConnection (iceConn);
+ }
+ else {
+
+ /*
+ * Now send the GetProxyAddr message to the proxy.
+ */
+ if (PeekRequestorQueue(pmConn,
+ NULL, NULL, NULL,
+ &serverAddress, &hostAddress, &startOptions,
+ &authLen, &authName, &authData)) {
+ SendGetProxyAddr(pmConn,
+ serviceName, serverAddress,
+ hostAddress, startOptions,
+ authLen, authName, authData);
+ }
+ else if (verbose) {
+ fputs ("Received StartProxy for service ", stderr);
+ fputs (serviceName, stderr);
+ fputs (" but no waiting GetproxyAddr requests\n", stderr);
+ }
+ }
+
+ free (serviceName);
+
+ break;
+ }
+
+ case PM_GetProxyAddrReply:
+
+ {
+ pmGetProxyAddrReplyMsg *pMsg;
+ char *pData, *pStart;
+ char *addr = NULL, *error = NULL;
+
+ CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, SIZEOF (pmGetProxyAddrReplyMsg), IceFatalToProtocol);
+
+ IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrReplyMsg),
+ pmGetProxyAddrReplyMsg, pMsg, pStart);
+
+ if (!IceValidIO (iceConn))
+ {
+ IceDisposeCompleteMessage (iceConn, pStart);
+ return;
+ }
+
+ pData = pStart;
+
+ SKIP_STRING (pData, swap); /* proxy-address */
+ SKIP_STRING (pData, swap); /* failure-reason */
+
+ CHECK_COMPLETE_SIZE (iceConn, pmConn->pmOpcode, opcode,
+ length, pData - pStart + SIZEOF (pmGetProxyAddrReplyMsg),
+ pStart, IceFatalToProtocol);
+
+ pData = pStart;
+
+ EXTRACT_STRING (pData, swap, addr);
+ EXTRACT_STRING (pData, swap, error);
+
+ if (verbose) {
+ printf ("Got GetProxyAddrReply from proxy %d, status = %d, ",
+ IceConnectionNumber(iceConn), pMsg->status);
+ if (pMsg->status == PM_Success)
+ printf ("addr = %s\n", addr);
+ else
+ printf ("error = %s\n", error);
+ }
+
+ { /* Ignore any unsolicited replies so we don't get further confused */
+ running_proxy *proxy = ProxyForPMconn(pmConn);
+
+ if (!proxy || !proxy->requests)
+ {
+ if (verbose)
+ fprintf (stderr, "Received unsolicited GetProxyAddrReply from proxy %d; ignoring it.\n",
+ IceConnectionNumber(iceConn));
+
+ IceDisposeCompleteMessage (iceConn, pStart);
+ break;
+ }
+ }
+
+ switch (pMsg->status) {
+
+ case PM_Success:
+ {
+ /*
+ * Now send the GetProxyAddr reply to xfindproxy.
+ */
+
+ SendGetProxyAddrReply (
+ PopRequestorQueue (pmConn, True, True /* free proxy list */),
+ PM_Success /* status */, addr, NULL);
+
+ break;
+ }
+
+ case PM_Unable:
+ {
+ running_proxy_list *proxyList;
+ char *serviceName, *serverAddress, *hostAddress, *startOptions;
+ PMconn *requestor;
+ int authLen;
+ char *authName;
+ char *authData;
+
+ {
+ running_proxy *proxy = ProxyForPMconn(pmConn);
+ if (proxy)
+ proxy->refused_service = True;
+ else
+ fputs("Internal error: received GetProxyAddrReply from an unknown proxy\n", stderr);
+ }
+
+ if (! PeekRequestorQueue (pmConn, &requestor,
+ &proxyList, &serviceName, &serverAddress,
+ &hostAddress, &startOptions,
+ &authLen, &authName, &authData)) {
+ if (verbose)
+ fputs("Received GetProxyAddrReply from a proxy with no requests\n", stderr);
+
+ proxyList = NULL;
+ serviceName = "?unknown service--internal error";
+ }
+
+ if (proxyList && (proxyList->current < proxyList->count - 1))
+ {
+ /*
+ * Ask the next running proxy if it can service this request.
+ */
+ running_proxy *nextProxy;
+
+ proxyList->current++;
+ nextProxy = proxyList->list[proxyList->current];
+
+ if (nextProxy->pmConn != NULL) {
+ /* send only if the proxy has started */
+ SendGetProxyAddr (nextProxy->pmConn, serviceName,
+ serverAddress, hostAddress, startOptions,
+ authLen, authName, authData);
+ }
+
+ PushRequestorQueue (nextProxy, requestor, proxyList,
+ serviceName, serverAddress, hostAddress, startOptions,
+ authLen, authName, authData);
+
+ PopRequestorQueue (pmConn, False, False);
+ }
+ else
+ {
+ /*
+ * Start a new proxy.
+ */
+
+ running_proxy *runningProxy = NULL;
+ char *startCommand;
+ char *proxyAddress;
+ Bool managed;
+
+ if (!GetConfig (configFile, serviceName, &managed,
+ &startCommand, &proxyAddress))
+ {
+ SendGetProxyAddrReply (requestor, PM_Failure,
+ NULL, "Could not read proxy manager config file");
+ }
+ else
+ {
+ runningProxy = StartNewProxy (serviceName, startCommand);
+
+ if (runningProxy)
+ {
+ PushRequestorQueue (runningProxy,
+ requestor, proxyList,
+ serviceName, serverAddress,
+ hostAddress, startOptions,
+ authLen, authName, authData);
+ }
+ else
+ {
+ SendGetProxyAddrReply (pmConn, PM_Failure,
+ NULL, "Can't start new proxy");
+ }
+ }
+
+ if (startCommand)
+ free (startCommand);
+ if (proxyAddress)
+ free (proxyAddress);
+
+ PopRequestorQueue (pmConn, False,
+ runningProxy ? False : True /* free proxy list */);
+ }
+ break;
+ }
+
+ default:
+ if (verbose && pMsg->status != PM_Unable)
+ fprintf(stderr,
+ "Error: proxy returned unrecognized status: %d\n",
+ pMsg->status);
+ /* FALLTHROUGH */
+
+ case PM_Failure:
+ SendGetProxyAddrReply (
+ PopRequestorQueue (pmConn, True, True /* free proxy list */),
+ pMsg->status, NULL, error);
+ }
+
+ IceDisposeCompleteMessage (iceConn, pStart);
+
+ /* see if there was more work queued for this proxy */
+ {
+ char *serviceName, *serverAddress, *hostAddress, *startOptions;
+ int authLen;
+ char *authName, *authData;
+
+ if (PeekRequestorQueue(pmConn,
+ NULL, NULL, &serviceName,
+ &serverAddress, &hostAddress, &startOptions,
+ &authLen, &authName, &authData)) {
+ SendGetProxyAddr(pmConn,
+ serviceName, serverAddress,
+ hostAddress, startOptions,
+ authLen, authName, authData);
+ }
+ }
+
+ if (addr)
+ free (addr);
+ if (error)
+ free (error);
+
+ break;
+ }
+
+ case PM_Error:
+ {
+ iceErrorMsg *pMsg;
+ char *pStart;
+
+ CHECK_AT_LEAST_SIZE (iceConn, pmConn->pmOpcode, PM_Error, length,
+ sizeof(iceErrorMsg), IceFatalToProtocol);
+
+ IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
+ iceErrorMsg, pMsg, pStart);
+
+ if (!IceValidIO (iceConn))
+ {
+ IceDisposeCompleteMessage (iceConn, pStart);
+ return;
+ }
+
+ if (swap)
+ {
+ pMsg->errorClass = lswaps (pMsg->errorClass);
+ pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
+ }
+
+ fprintf(stderr, "Received ICE Error: class=0x%x\n offending minor opcode=%d, severity=%d, sequence=%d\n",
+ pMsg->errorClass, pMsg->offendingMinorOpcode, pMsg->severity,
+ pMsg->offendingSequenceNum);
+
+ IceDisposeCompleteMessage (iceConn, pStart);
+
+ break;
+ }
+
+ default:
+ {
+ _IceErrorBadMinor (iceConn, pmConn->pmOpcode, opcode, IceCanContinue);
+ _IceReadSkip (iceConn, length << 3);
+ break;
+ }
+ }
+}
+
+void
+PMSetupProcessMessages (iceConn, clientData, opcode, length, swap,
+ replyWait, replyReadyRet)
+
+IceConn iceConn;
+IcePointer clientData;
+int opcode;
+unsigned long length;
+Bool swap;
+IceReplyWaitInfo *replyWait;
+Bool *replyReadyRet;
+
+{
+ assert (replyWait == NULL);
+
+ PMReplyProcessMessages (iceConn, clientData, opcode, length, swap);
+}
+
+
+void
+ForwardRequest( requestor, serviceName, serverAddress, hostAddress,
+ startOptions, authLen, authName, authData )
+ PMconn *requestor;
+ char *serviceName, *serverAddress, *hostAddress, *startOptions;
+ int authLen;
+ char *authName, *authData;
+{
+ running_proxy_list *proxyList;
+ running_proxy *runningProxy;
+ int pushRequest = 0;
+
+ if ((proxyList = GetRunningProxyList (
+ serviceName, serverAddress)) != NULL)
+ {
+ while (proxyList->current < proxyList->count) {
+ runningProxy = proxyList->list[proxyList->current];
+
+ if (runningProxy->pmConn != NULL) {
+ SendGetProxyAddr (runningProxy->pmConn, serviceName,
+ serverAddress, hostAddress, NULL,
+ authLen, authName, authData);
+ break;
+ }
+ proxyList->current++;
+ }
+
+ pushRequest = 1;
+ }
+ else
+ {
+ Bool managed;
+ char *startCommand;
+ char *proxyAddress;
+
+ if (!GetConfig (configFile, serviceName, &managed,
+ &startCommand, &proxyAddress))
+ {
+ SendGetProxyAddrReply (requestor, PM_Failure,
+ NULL, "Could not find requested service");
+ }
+ else
+ {
+ if (managed)
+ {
+ runningProxy = StartNewProxy (serviceName, startCommand);
+
+ if (runningProxy)
+ pushRequest = 1;
+ else
+ {
+ SendGetProxyAddrReply (requestor, PM_Failure,
+ NULL, "Can't start new proxy");
+ }
+ }
+ else
+ {
+ /*
+ * We have the unmanged proxy's address; now forward
+ * the request to it.
+ */
+
+ runningProxy = ConnectToProxy (PMOriginatorOpcode,
+ serviceName, proxyAddress);
+
+ if (runningProxy) {
+ SendGetProxyAddr (runningProxy->pmConn,
+ serviceName, serverAddress,
+ hostAddress, startOptions,
+ authLen, authName, authData);
+ pushRequest = 1;
+ }
+ else
+ {
+ /* %%% We should reread the config file and look
+ * for another proxy address before giving up.
+ */
+ SendGetProxyAddrReply (requestor, PM_Failure,
+ NULL, "Can't connect to proxy");
+ }
+ }
+
+ if (startCommand)
+ free (startCommand);
+ if (proxyAddress)
+ free (proxyAddress);
+ }
+ }
+
+ if (pushRequest)
+ {
+ PushRequestorQueue (runningProxy, requestor, proxyList,
+ serviceName, serverAddress, hostAddress, startOptions,
+ authLen, authName, authData);
+ }
+}
+
+
+/* ARGSUSED */
+void
+_XtProcessIceMsgProc (client_data, source, id)
+
+XtPointer client_data;
+int *source;
+XtInputId *id;
+
+{
+ IceConn ice_conn = (IceConn) client_data;
+ IceProcessMessagesStatus status;
+
+ status = IceProcessMessages (ice_conn, NULL, NULL);
+
+ if (status == IceProcessMessagesIOError)
+ {
+ Bool activeReqs;
+
+ ProxyGone (ice_conn, &activeReqs);
+ IceSetShutdownNegotiation (ice_conn, False);
+ IceCloseConnection (ice_conn);
+ }
+}
+
+
+void
+_XtIceWatchProc (ice_conn, client_data, opening, watch_data)
+
+IceConn ice_conn;
+IcePointer client_data;
+Bool opening;
+IcePointer *watch_data;
+
+{
+ if (opening)
+ {
+ XtAppContext appContext = (XtAppContext) client_data;
+ void _XtProcessIceMsgProc ();
+
+ *watch_data = (IcePointer) XtAppAddInput (
+ appContext,
+ IceConnectionNumber (ice_conn),
+ (XtPointer) XtInputReadMask,
+ _XtProcessIceMsgProc,
+ (XtPointer) ice_conn);
+ }
+ else
+ {
+ XtRemoveInput ((XtInputId) *watch_data);
+ }
+}
+
+
+Status
+InitWatchProcs (appContext)
+
+XtAppContext appContext;
+
+{
+ return (IceAddConnectionWatch (_XtIceWatchProc, (IcePointer) appContext));
+}
+
+
+/*
+ * The real way to handle IO errors is to check the return status
+ * of IceProcessMessages. xsm properly does this.
+ *
+ * Unfortunately, a design flaw exists in the ICE library in which
+ * a default IO error handler is invoked if no IO error handler is
+ * installed. This default handler exits. We must avoid this.
+ *
+ * To get around this problem, we install an IO error handler that
+ * does a little magic. Since a previous IO handler might have been
+ * installed, when we install our IO error handler, we do a little
+ * trick to get both the previous IO error handler and the default
+ * IO error handler. When our IO error handler is called, if the
+ * previous handler is not the default handler, we call it. This
+ * way, everyone's IO error handler gets called except the stupid
+ * default one which does an exit!
+ */
+
+static IceIOErrorHandler prev_handler;
+
+void
+MyIoErrorHandler (ice_conn)
+
+IceConn ice_conn;
+
+{
+ if (prev_handler)
+ (*prev_handler) (ice_conn);
+}
+
+void
+InstallIOErrorHandler ()
+
+{
+ IceIOErrorHandler default_handler;
+
+ prev_handler = IceSetIOErrorHandler (NULL);
+ default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
+ if (prev_handler == default_handler)
+ prev_handler = NULL;
+}
+
+
+/*
+ * Since proxy manager does not authenticate connections, we disable
+ * authentication by always returning true in the host based auth proc.
+ */
+
+Bool
+HostBasedAuthProc (hostname)
+
+char *hostname;
+
+{
+ return (1);
+}
diff --git a/pmconfig.cpp b/pmconfig.cpp
new file mode 100644
index 0000000..1b9091d
--- /dev/null
+++ b/pmconfig.cpp
@@ -0,0 +1,12 @@
+! $Xorg: pmconfig.cpp,v 1.3 2000/08/17 19:54:00 cpqbld Exp $
+! proxy manager config file
+!
+! Each line has the format:
+! <serviceName> managed <startCommand>
+! or
+! <serviceName> unmanaged <proxyAddress>
+!
+lbx managed LBXPROXY
+!
+! substitute site-specific info
+!xfwp unmanaged firewall:4444
diff --git a/pmdb.c b/pmdb.c
new file mode 100644
index 0000000..67842ed
--- /dev/null
+++ b/pmdb.c
@@ -0,0 +1,771 @@
+/* $Xorg: pmdb.c,v 1.5 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+#include "pmint.h"
+#include "pmdb.h"
+#include "config.h"
+#include <assert.h>
+#include <stdio.h>
+#include <signal.h>
+
+#if defined(X_NOT_POSIX) && defined(SIGNALRETURNSINT)
+#define SIGVAL int
+#else
+#define SIGVAL void
+#endif
+
+void SetCloseOnExec (int fd);
+
+static proxy_service *proxyServiceList = NULL;
+
+SIGVAL (*Signal (sig, handler))()
+ int sig;
+ SIGVAL (*handler)();
+{
+#ifndef X_NOT_POSIX
+ struct sigaction sigact, osigact;
+ sigact.sa_handler = handler;
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigaction(sig, &sigact, &osigact);
+ return osigact.sa_handler;
+#else
+ return signal(sig, handler);
+#endif
+}
+
+proxy_service *
+FindProxyService (
+ char *serviceName,
+ Bool createIf)
+
+{
+ proxy_service *service = proxyServiceList;
+ int nameLen = strlen (serviceName);
+
+ while (service)
+ {
+ if (strcmp (service->serviceName, serviceName) == 0)
+ return service;
+ else if (ncasecmp (service->serviceName, serviceName, nameLen) == 0)
+ return service;
+ else
+ service = service->next;
+ }
+
+ if (createIf) {
+ service = (proxy_service *) malloc (sizeof (proxy_service));
+ if (!service)
+ return NULL;
+
+ service->serviceName = (char *) malloc (nameLen + 1);
+ if (!service->serviceName)
+ {
+ free (service);
+ return NULL;
+ }
+
+ strcpy (service->serviceName, serviceName);
+ service->proxyCount = 0;
+ service->proxyList = NULL;
+
+ if (proxyServiceList == NULL)
+ {
+ proxyServiceList = service;
+ service->next = NULL;
+ }
+ else
+ {
+ service->next = proxyServiceList;
+ proxyServiceList = service;
+ }
+ }
+
+ return service;
+
+}
+
+
+running_proxy *
+StartNewProxy (
+ char *serviceName,
+ char *startCommand)
+
+{
+ proxy_service *service = FindProxyService (serviceName, True);
+ running_proxy *proxy;
+
+ if (!service)
+ return NULL;
+
+ proxy = (running_proxy *) malloc (sizeof (running_proxy));
+ if (!proxy)
+ return NULL;
+
+ proxy->active = 0;
+ proxy->pmConn = NULL;
+ proxy->requests = NULL;
+ proxy->servers = NULL;
+ proxy->refused_service = False;
+
+ if (service->proxyList == NULL)
+ {
+ service->proxyList = proxy;
+ proxy->next = NULL;
+ }
+ else
+ {
+ proxy->next = service->proxyList;
+ service->proxyList = proxy;
+ }
+
+ if (system (startCommand) == -1)
+ {
+ printf ("unable to start managed proxy: %s\n", startCommand);
+ service->proxyList = proxy->next;
+ free (proxy);
+ return NULL;
+ }
+
+ if (verbose) {
+ printf ("started managed proxy: %s\n", startCommand);
+ printf ("waiting for StartProxy message\n");
+ }
+
+ service->proxyCount++;
+
+ return proxy;
+}
+
+/*
+ * ConnectToProxy( pmOpcode, serviceName, proxyAddress )
+ *
+ * Connects to an unmanaged proxy to forward the GetProxyAddr request
+ * to it to handle.
+ *
+ * Ideally this would be non-blocking but there is no non-blocking
+ * variant of IceOpenConnection/IceProtocolSetup. So we sit here a while.
+ */
+running_proxy *
+ConnectToProxy (
+ int pmOpcode,
+ char *serviceName,
+ char *proxyAddress)
+
+{
+ proxy_service *service = FindProxyService (serviceName, True);
+ running_proxy *proxy;
+ IceConn proxy_iceConn;
+ PMconn *pmConn;
+
+ if (!service)
+ return NULL;
+
+ {
+ int majorVersion, minorVersion;
+ char *vendor, *release;
+ char errorString[256];
+
+ /*
+ * IceOpenConnection will do more than one write to the proxy.
+ * If the proxy closes the connection before the second write,
+ * the second write may generate a SIGPIPE (empirically this
+ * happens on at least AIX). So, temporarily ignore this signal.
+ */
+
+ Signal (SIGPIPE, SIG_IGN);
+
+ proxy_iceConn = IceOpenConnection( proxyAddress, NULL,
+ False, pmOpcode,
+ sizeof(errorString), errorString);
+
+ Signal (SIGPIPE, SIG_DFL);
+
+ if (! proxy_iceConn) {
+ printf("unable to open connection to unmanaged proxy \"%s\" at %s\n",
+ serviceName, proxyAddress);
+ return NULL;
+ }
+
+ /*
+ * Mark this fd to be closed upon exec
+ */
+ SetCloseOnExec (IceConnectionNumber (proxy_iceConn));
+
+ /* See PMprotocolSetupProc */
+ pmConn = (PMconn *) malloc (sizeof (PMconn));
+
+ if (pmConn == NULL) {
+ IceCloseConnection (proxy_iceConn);
+ return NULL;
+ }
+
+ if (IceProtocolSetup (proxy_iceConn, pmOpcode,
+ (IcePointer)pmConn, /* client_data */
+ False, /* must_authenticate */
+ &majorVersion, &minorVersion,
+ &vendor, &release,
+ sizeof(errorString), errorString)
+ != IceProtocolSetupSuccess) {
+ IceCloseConnection (proxy_iceConn);
+ free (pmConn);
+ printf ("Could not initialize proxy management protocol with\n unmanaged proxy \"%s\" at address %s:\n %s\n",
+ serviceName, proxyAddress, errorString);
+ return NULL;
+ }
+
+ pmConn->iceConn = proxy_iceConn;
+ pmConn->pmOpcode = pmOpcode;
+ pmConn->proto_major_version = majorVersion;
+ pmConn->proto_minor_version = minorVersion;
+ pmConn->vendor = vendor;
+ pmConn->release = release;
+ }
+
+ proxy = (running_proxy *) malloc (sizeof (running_proxy));
+ if (!proxy) {
+ IceCloseConnection (proxy_iceConn);
+ free (pmConn);
+ return NULL;
+ }
+
+ proxy->active = 1;
+ proxy->pmConn = pmConn;
+ proxy->requests = NULL;
+ proxy->servers = NULL;
+ proxy->refused_service = False;
+
+ if (service->proxyList == NULL)
+ {
+ service->proxyList = proxy;
+ proxy->next = NULL;
+ }
+ else
+ {
+ proxy->next = service->proxyList;
+ service->proxyList = proxy;
+ }
+
+ if (verbose)
+ printf ("connected to unmanaged proxy: %s at %s\n",
+ serviceName, proxyAddress);
+
+ service->proxyCount++;
+
+ return proxy;
+}
+
+
+Status
+ActivateProxyService (
+ char *serviceName,
+ PMconn *pmConn)
+
+{
+ proxy_service *service = FindProxyService (serviceName, False);
+ running_proxy *proxy;
+
+ if (!service)
+ return 0;
+
+ proxy = service->proxyList;
+
+ while (proxy)
+ {
+ if (!proxy->active)
+ {
+ proxy->active = 1;
+ proxy->pmConn = pmConn;
+ return 1;
+ }
+ else
+ proxy = proxy->next;
+ }
+
+ return 0;
+}
+
+
+void
+ProxyGone (
+ IceConn proxyIceConn,
+ Bool *activeReqs)
+
+{
+ proxy_service *service = proxyServiceList;
+
+ while (service)
+ {
+ running_proxy *proxy = service->proxyList;
+ running_proxy *prevProxy = NULL;
+
+ while (proxy)
+ {
+ if (proxy->pmConn && (proxy->pmConn->iceConn == proxyIceConn))
+ {
+ server_list *server;
+ request_list *req;
+
+ if (verbose)
+ printf ("Proxy disconnected on fd %d",
+ IceConnectionNumber(proxyIceConn));
+
+ server = proxy->servers;
+ if (verbose && server)
+ fputs (" for server", stdout);
+
+ while (server)
+ {
+ server_list *next_server = server->next;
+ if (verbose) {
+ fputc (' ', stdout);
+ fputs (server->serverAddress, stdout);
+ }
+ free (server->serverAddress);
+ free (server);
+ server = next_server;
+ }
+
+ if (verbose)
+ fputc ('\n', stdout);
+
+ if (prevProxy == NULL)
+ service->proxyList = proxy->next;
+ else
+ prevProxy->next = proxy->next;
+
+ service->proxyCount--;
+
+ *activeReqs = proxy->requests != NULL;
+ req = proxy->requests;
+ while (req)
+ {
+ request_list *nextreq = req->next;
+
+ if (req->requestor) {
+ assert (req->requestor->iceConn != NULL);
+ if (verbose)
+ printf ("Reprocessing request from fd %d for service %s at %s\n",
+ IceConnectionNumber (req->requestor->iceConn),
+ req->serviceName, req->serverAddress);
+
+ ForwardRequest( req->requestor,
+ req->serviceName, req->serverAddress,
+ req->hostAddress, req->startOptions,
+ req->authLen, req->authName,
+ req->authData);
+ }
+ if (req->serviceName)
+ free (req->serviceName);
+ if (req->serverAddress)
+ free (req->serverAddress);
+ if (req->hostAddress)
+ free (req->hostAddress);
+ if (req->startOptions)
+ free (req->startOptions);
+ if (req->listData)
+ free (req->listData); /* proxyList */
+ if (req->authName)
+ free (req->authName);
+ if (req->authData)
+ free (req->authData);
+ free (req);
+ req = nextreq;
+ }
+
+ free (proxy);
+ return;
+ }
+ else if (proxy->requests) {
+ /*
+ * If it wasn't a proxy that disconnected, so it might
+ * have been a requestor. Search through all the requests
+ * while we're here and look for a match. If found, delete
+ * the request.
+ */
+ request_list **prev_reqP = &proxy->requests;
+ request_list *req = proxy->requests;
+ while (req) {
+ if (req->requestor->iceConn == proxyIceConn) {
+ if (verbose) {
+ printf ("Requestor disconnected on fd %d while awaiting reply\n for service %s (%s)",
+ IceConnectionNumber(proxyIceConn),
+ req->serviceName, req->serverAddress);
+ if (proxy->pmConn && proxy->pmConn->iceConn) {
+ printf (" from proxy on fd %d\n",
+ IceConnectionNumber(proxy->pmConn->iceConn));
+ }
+ else
+ fputc ('\n', stdout);
+ }
+
+ *prev_reqP = req->next;
+
+ if (req->serviceName)
+ free (req->serviceName);
+ if (req->serverAddress)
+ free (req->serverAddress);
+ if (req->hostAddress)
+ free (req->hostAddress);
+ if (req->startOptions)
+ free (req->startOptions);
+ if (req->listData)
+ free (req->listData); /* proxyList */
+ if (req->authName)
+ free (req->authName);
+ if (req->authData)
+ free (req->authData);
+ free (req);
+
+ /* return; */ /* should but only one req, but... */
+ }
+ else
+ prev_reqP = &req->next;
+
+ req = *prev_reqP;
+ }
+ }
+
+ prevProxy = proxy;
+ proxy = proxy->next;
+ }
+
+ service = service->next;
+ }
+}
+
+
+/*
+ * GetRuningProxyList returns a list of current proxies for a given
+ * service. The list is ordered, with proxies serving an address that
+ * matches the argument appearing first on the list and all others
+ * appearing at the end. If a proxy ever refused a request for additional
+ * service then it is excluded from the list if it doesn't match the
+ * server address.
+ */
+running_proxy_list *
+GetRunningProxyList (
+ char *serviceName, char *serverAddress)
+
+{
+ proxy_service *service = FindProxyService (serviceName, False);
+ running_proxy **proxyList, *proxy;
+ running_proxy_list *runList;
+ int headIndex, tailIndex;
+
+ if (!service || !service->proxyCount)
+ return NULL;
+
+ runList = (running_proxy_list *) malloc (sizeof (running_proxy_list) +
+ service->proxyCount * sizeof (running_proxy *));
+
+ if (!runList)
+ return NULL;
+
+ runList->count = 0;
+ runList->current = 0;
+ runList->list = proxyList = (running_proxy **) (runList + 1);
+
+ proxy = service->proxyList;
+ headIndex = 0;
+ tailIndex = service->proxyCount - 1;
+
+ while (proxy)
+ {
+ server_list *server = proxy->servers;
+ int match = 0;
+
+ while (server)
+ {
+ if (strcmp (server->serverAddress, serverAddress) == 0)
+ {
+ match = 1;
+ break;
+ }
+
+ server = server->next;
+ }
+
+ if (match) {
+ proxyList[headIndex++] = proxy;
+ runList->count++;
+ }
+ else if (! proxy->refused_service) {
+ proxyList[tailIndex--] = proxy;
+ runList->count++;
+ }
+
+ proxy = proxy->next;
+ }
+
+ if (!runList->count) {
+ free ((char*)runList);
+ return NULL;
+ }
+
+ /* if we didn't fill the list due to skipping proxies that had previously
+ * refused to service a new address, then remove the gaps in the list
+ * between the matched and unmatched server names
+ */
+ if (runList->count < service->proxyCount) {
+ while (tailIndex < service->proxyCount - 1)
+ proxyList[headIndex++] = proxyList[++tailIndex];
+ }
+
+ return runList;
+}
+
+
+void
+FreeProxyList (running_proxy_list *list)
+
+{
+ free (list);
+}
+
+
+Status
+PushRequestorQueue (
+ running_proxy *proxy,
+ PMconn *requestor,
+ running_proxy_list *runList,
+ char *serviceName,
+ char *serverAddress,
+ char *hostAddress,
+ char *startOptions,
+ int authLen,
+ char *authName,
+ char *authData)
+
+{
+ request_list *newreq = (request_list *) malloc (sizeof (request_list));
+
+ if (!newreq)
+ return 0;
+
+ newreq->serviceName = (char *) malloc (strlen (serviceName) + 1);
+ newreq->serverAddress = (char *) malloc (strlen (serverAddress) + 1);
+ newreq->hostAddress = (char *) malloc (strlen (hostAddress) + 1);
+ newreq->startOptions = (char *) malloc (strlen (startOptions) + 1);
+ if (authLen > 0)
+ {
+ newreq->authName = (char *) malloc (strlen (authName) + 1);
+ newreq->authData = (char *) malloc (authLen);
+ }
+
+ if (!newreq->serviceName ||
+ !newreq->serverAddress ||
+ !newreq->hostAddress ||
+ !newreq->startOptions ||
+ (authLen > 0 && (!newreq->authName || !newreq->authData)))
+ {
+ if (newreq->serviceName)
+ free (newreq->serviceName);
+ if (newreq->serverAddress)
+ free (newreq->serverAddress);
+ if (newreq->hostAddress)
+ free (newreq->hostAddress);
+ if (newreq->startOptions)
+ free (newreq->startOptions);
+ if (newreq->authName)
+ free (newreq->authName);
+ if (newreq->authData)
+ free (newreq->authData);
+ free (newreq);
+ return 0;
+ }
+
+ strcpy (newreq->serviceName, serviceName);
+ strcpy (newreq->serverAddress, serverAddress);
+ strcpy (newreq->hostAddress, hostAddress);
+ strcpy (newreq->startOptions, startOptions);
+ if (authLen > 0)
+ {
+ strcpy (newreq->authName, authName);
+ memcpy (newreq->authData, authData, authLen);
+ }
+ else
+ {
+ newreq->authName = newreq->authData = NULL;
+ }
+
+ newreq->requestor = requestor;
+ newreq->listData = (char *) runList;
+ newreq->authLen = authLen;
+ newreq->next = NULL;
+
+ if (proxy->requests == NULL)
+ proxy->requests = newreq;
+ else
+ {
+ request_list *p = proxy->requests;
+
+ while (p->next)
+ p = p->next;
+
+ p->next = newreq;
+ }
+
+ return 1;
+}
+
+
+Status
+PeekRequestorQueue (
+ PMconn *pmConn,
+ PMconn **requestor,
+ running_proxy_list **runList,
+ char **serviceName,
+ char **serverAddress,
+ char **hostAddress,
+ char **startOptions,
+ int *authLen,
+ char **authName,
+ char **authData)
+{
+ running_proxy *proxy = ProxyForPMconn (pmConn);
+
+ if (proxy && proxy->requests) {
+ if (requestor)
+ *requestor = proxy->requests->requestor;
+ if (runList)
+ *runList = (running_proxy_list *)
+ proxy->requests->listData;
+ if (serviceName)
+ *serviceName = proxy->requests->serviceName;
+ if (serverAddress)
+ *serverAddress = proxy->requests->serverAddress;
+ if (hostAddress)
+ *hostAddress = proxy->requests->hostAddress;
+ if (startOptions)
+ *startOptions = proxy->requests->startOptions;
+ if (authLen)
+ *authLen = proxy->requests->authLen;
+ if (authName)
+ *authName = proxy->requests->authName;
+ if (authData)
+ *authData = proxy->requests->authData;
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+
+running_proxy *
+ProxyForPMconn (
+ PMconn *pmConn)
+{
+ proxy_service *service = proxyServiceList;
+
+ while (service)
+ {
+ running_proxy *proxy = service->proxyList;
+
+ while (proxy)
+ {
+ if (proxy->pmConn == pmConn)
+ return proxy;
+ else
+ proxy = proxy->next;
+ }
+
+ service = service->next;
+ }
+
+ return NULL;
+}
+
+
+PMconn*
+PopRequestorQueue (
+ PMconn *pmConn,
+ Bool addServer, /* record this server address */
+ Bool freeProxyList)
+{
+ running_proxy *proxy = ProxyForPMconn (pmConn);
+
+ if (proxy) {
+ PMconn *requestor;
+ server_list *server;
+ request_list *nextreq;
+ Bool newServer = False;
+
+ if (addServer) {
+ newServer = True;
+ server = proxy->servers;
+
+ while (server)
+ {
+ if (strcmp (server->serverAddress,
+ proxy->requests->serverAddress) == 0)
+ {
+ newServer = False;
+ break;
+ }
+
+ server = server->next;
+ }
+
+ if (newServer)
+ {
+ server = (server_list *) malloc (sizeof (server_list));
+ server->serverAddress = proxy->requests->serverAddress;
+ server->next = proxy->servers;
+ proxy->servers = server;
+ }
+ }
+
+ if (!newServer)
+ free (proxy->requests->serverAddress);
+
+ if (proxy->requests->serviceName)
+ free (proxy->requests->serviceName);
+ if (proxy->requests->hostAddress)
+ free (proxy->requests->hostAddress);
+ if (proxy->requests->startOptions)
+ free (proxy->requests->startOptions);
+ if (freeProxyList && proxy->requests->listData)
+ free (proxy->requests->listData); /* proxyList */
+ if (proxy->requests->authName)
+ free (proxy->requests->authName);
+ if (proxy->requests->authData)
+ free (proxy->requests->authData);
+
+ requestor = proxy->requests->requestor;
+
+ nextreq = proxy->requests->next;
+ free (proxy->requests);
+ proxy->requests = nextreq;
+
+ return requestor;
+ }
+
+ return NULL;
+}
diff --git a/pmdb.h b/pmdb.h
new file mode 100644
index 0000000..eee5ad3
--- /dev/null
+++ b/pmdb.h
@@ -0,0 +1,149 @@
+/* $Xorg: pmdb.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+
+#include <X11/ICE/ICElib.h>
+
+
+typedef struct _server_list {
+ char *serverAddress;
+ struct _server_list *next;
+} server_list;
+
+
+typedef struct _request_list {
+ char *serviceName;
+ char *serverAddress;
+ char *hostAddress;
+ char *startOptions;
+ PMconn *requestor;
+ char *listData;
+ int authLen;
+ char *authName;
+ char *authData;
+ struct _request_list *next;
+} request_list;
+
+
+typedef struct _running_proxy {
+ Bool active;
+ PMconn *pmConn;
+ request_list *requests;
+ server_list *servers;
+ Bool refused_service;
+ struct _running_proxy *next;
+} running_proxy;
+
+
+typedef struct _proxy_service {
+ char *serviceName;
+ int proxyCount;
+ running_proxy *proxyList;
+ struct _proxy_service *next;
+} proxy_service;
+
+
+typedef struct {
+ int count;
+ int current;
+ running_proxy **list;
+} running_proxy_list;
+
+
+
+proxy_service
+*FindProxyService (
+ char *serviceName,
+ Bool createIf);
+
+running_proxy *
+StartNewProxy (
+ char *serviceName,
+ char *startCommand);
+
+running_proxy *
+ConnectToProxy (
+ int pmOpcode,
+ char *serviceName,
+ char *proxyAddress);
+
+Status
+ActivateProxyService (
+ char *serviceName,
+ PMconn *proxy);
+
+void
+ProxyGone (
+ IceConn proxyIceConn,
+ Bool *activeReqs);
+
+running_proxy_list *
+GetRunningProxyList (
+ char *serviceName,
+ char *serverAddress);
+
+void
+FreeProxyList (
+ running_proxy_list *list);
+
+Status
+PushRequestorQueue (
+ running_proxy *proxy,
+ PMconn *requestor,
+ running_proxy_list *runList,
+ char *serviceName,
+ char *serverAddress,
+ char *hostAddress,
+ char *startOptions,
+ int authLen,
+ char *authName,
+ char *authData);
+
+
+Status
+PeekRequestorQueue (
+ PMconn *proxy,
+ PMconn **requestor,
+ running_proxy_list **runList,
+ char **serviceName,
+ char **serverAddress,
+ char **hostAddress,
+ char **startOptions,
+ int *authLen,
+ char **authName,
+ char **authData);
+
+PMconn*
+PopRequestorQueue (
+ PMconn *pmConn,
+ Bool addServer,
+ Bool freeProxyList);
+
+running_proxy *
+ProxyForPMconn(
+ PMconn *pmConn);
diff --git a/pmint.h b/pmint.h
new file mode 100644
index 0000000..cd43127
--- /dev/null
+++ b/pmint.h
@@ -0,0 +1,184 @@
+/* $Xorg: pmint.h,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $ */
+
+/*
+Copyright 1996, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+*/
+
+#include <stdio.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xmd.h>
+#include <X11/ICE/ICElib.h>
+
+#define Status int
+#define Bool int
+#define True 1
+#define False 0
+
+extern char *PM_VENDOR_STRING;
+extern char *PM_VENDOR_RELEASE;
+
+extern int verbose;
+
+typedef struct {
+ IceConn iceConn;
+ int pmOpcode;
+ int proto_major_version;
+ int proto_minor_version;
+ char *vendor;
+ char *release;
+} PMconn;
+
+extern void
+SendGetProxyAddrReply (
+ PMconn* /* requestor */,
+ int /* status */,
+ char* /* addr */,
+ char* /* error */);
+
+extern void
+ForwardRequest(
+ PMconn* /* requestor */,
+ char* /* serviceName */,
+ char* /* serverAddress */,
+ char* /* hostAddress */,
+ char* /* startOptions */,
+ int /* authLen */,
+ char* /* authName */,
+ char* /* authData */);
+
+
+/*
+ * Pad to a 64 bit boundary
+ */
+
+#define PAD64(_bytes) ((8 - ((unsigned int) (_bytes) % 8)) % 8)
+
+#define PADDED_BYTES64(_bytes) (_bytes + PAD64 (_bytes))
+
+
+/*
+ * Number of 8 byte units in _bytes.
+ */
+
+#define WORD64COUNT(_bytes) (((unsigned int) ((_bytes) + 7)) >> 3)
+
+
+/*
+ * Compute the number of bytes for a STRING representation
+ */
+
+#define STRING_BYTES(_str) (2 + (_str ? strlen (_str) : 0) + \
+ PAD64 (2 + (_str ? strlen (_str) : 0)))
+
+
+
+#define SKIP_STRING(_pBuf, _swap) \
+{ \
+ CARD16 _len; \
+ EXTRACT_CARD16 (_pBuf, _swap, _len); \
+ _pBuf += _len; \
+ if (PAD64 (2 + _len)) \
+ _pBuf += PAD64 (2 + _len); \
+}
+
+/*
+ * STORE macros
+ */
+
+#define STORE_CARD16(_pBuf, _val) \
+{ \
+ *((CARD16 *) _pBuf) = _val; \
+ _pBuf += 2; \
+}
+
+#define STORE_STRING(_pBuf, _string) \
+{ \
+ int _len = _string ? strlen (_string) : 0; \
+ STORE_CARD16 (_pBuf, _len); \
+ if (_len) { \
+ memcpy (_pBuf, _string, _len); \
+ _pBuf += _len; \
+ } \
+ if (PAD64 (2 + _len)) \
+ _pBuf += PAD64 (2 + _len); \
+}
+
+
+/*
+ * EXTRACT macros
+ */
+
+#define EXTRACT_CARD16(_pBuf, _swap, _val) \
+{ \
+ _val = *((CARD16 *) _pBuf); \
+ _pBuf += 2; \
+ if (_swap) \
+ _val = lswaps (_val); \
+}
+
+#define EXTRACT_STRING(_pBuf, _swap, _string) \
+{ \
+ CARD16 _len; \
+ EXTRACT_CARD16 (_pBuf, _swap, _len); \
+ _string = (char *) malloc (_len + 1); \
+ memcpy (_string, _pBuf, _len); \
+ _string[_len] = '\0'; \
+ _pBuf += _len; \
+ if (PAD64 (2 + _len)) \
+ _pBuf += PAD64 (2 + _len); \
+}
+
+
+/*
+ * Byte swapping
+ */
+
+/* byte swap a long literal */
+#define lswapl(_val) ((((_val) & 0xff) << 24) |\
+ (((_val) & 0xff00) << 8) |\
+ (((_val) & 0xff0000) >> 8) |\
+ (((_val) >> 24) & 0xff))
+
+/* byte swap a short literal */
+#define lswaps(_val) ((((_val) & 0xff) << 8) | (((_val) >> 8) & 0xff))
+
+
+#define CHECK_AT_LEAST_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \
+ if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) > _expected_len) \
+ { \
+ _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
+ return; \
+ }
+
+
+#define CHECK_COMPLETE_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _pStart, _severity) \
+ if (((PADDED_BYTES64((_actual_len)) - SIZEOF (iceMsg)) >> 3) \
+ != _expected_len) \
+ { \
+ _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
+ IceDisposeCompleteMessage (iceConn, _pStart); \
+ return; \
+ }
diff --git a/proxymngr.man b/proxymngr.man
new file mode 100644
index 0000000..0129d7f
--- /dev/null
+++ b/proxymngr.man
@@ -0,0 +1,174 @@
+.\" $Xorg: proxymngr.man,v 1.4 2001/02/09 02:05:34 xorgcvs Exp $
+.\" Copyright 1996, 1998 The Open Group
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation.
+.\"
+.\" The above copyright notice and this permission notice shall be included
+.\" in all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+.\" OTHER DEALINGS IN THE SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of The Open Group shall
+.\" not be used in advertising or otherwise to promote the sale, use or
+.\" other dealings in this Software without prior written authorization
+.\" from The Open Group.
+.\"
+.TH PROXYMNGR 1 "Release 6.4" "X Version 11"
+.SH NAME
+proxymngr - proxy manager service
+.SH SYNOPSIS
+\fBproxymngr\fP [\fB\-config\fP \fIfilename\fP] [\fB\-timeout\fP \fIseconds\fP] [\fB\-retries\fP \fI#\fP] [\fB\-verbose\fP]
+.SH DESCRIPTION
+The proxy manager (proxymngr) is responsible for resolving requests from
+xfindproxy (and other similar clients), starting new proxies when
+appropriate, and keeping track of all of the available proxy services.
+The proxy manager strives to reuse existing proxies whenever possible.
+.PP
+There are two types of proxies that the proxy manager deals with, \fImanaged\fP
+and \fIunmanaged\fP proxies.
+.PP
+A \fImanaged\fP proxy is a proxy that is started ``on demand'' by the proxy manager.
+.PP
+An \fIunmanaged\fP proxy, on the other hand, is started either at system boot time,
+or manually by a system administrator. The proxy manager is made aware of
+its existence, but no attempt is made by the proxy manager to start unmanaged
+proxies.
+.PP
+The command line options that can be specified to
+.B proxymngr
+are:
+.PP
+.TP 8
+.B \-config
+Used to override the default proxymngr config file.
+See below for more details about the config file.
+.PP
+.TP 8
+.B \-timeout
+Sets the number of seconds between attempts made by the
+proxy manager to find an unmanaged proxy. The default is 10.
+.PP
+.TP 8
+.B \-retries
+Sets the maximum number of retries made by the proxy
+manager to find an an unmanaged proxy. The default is 3.
+.PP
+.TP 8
+.B \-verbose
+Causes various debugging and tracing records to be displayed as
+requests are received and proxies are started.
+.PP
+.PP
+.SH Proxy Manager Config File
+.PP
+The proxy manager maintains a local configuration file describing the proxy
+services available. This configuration file is installed
+in /usr/X11R6.4/lib/X11/proxymngr/pmconfig during the installation
+of proxymngr. The location of the configuration file can be overwritten using
+the \fB\-config\fP command line option.
+.PP
+Aside from lines starting with an exclamation point for comments, each line
+of the configuration file describes either an unmanaged or managed proxy
+service.
+.PP
+For unmanaged proxies, the format is:
+.IP
+<service-name> unmanaged <proxy-address>
+.PP
+service-name is the name of the unmanaged proxy service, and must not
+contain any spaces, for example ``XFWP''. service-name is case
+insenstive.
+.PP
+proxy-address is the network address of the unmanaged proxy. The format
+of the address is specific to the service-name. For example, for the
+``XFWP'' service, the proxy-address might be ``firewall.x.org:100''.
+.PP
+If there is more than one entry in the config file with the same
+unmanaged service-name, the proxy manager will try to use the proxies
+in the order presented in the config file.
+.PP
+For managed proxies, the format is:
+.IP
+<service-name> managed <command-to-start-proxy>
+.PP
+service-name is the name of the managed proxy service, and must not
+contain any spaces, for example ``LBX''. service-name is case insensitive.
+.PP
+command-to-start-proxy is the command executed by the proxy manager to
+start a new instance of the proxy. If command-to-start-proxy contains
+spaces, the complete command should be surrounded by single quotes.
+If desired, command-to-start-proxy can be used to start a proxy on a
+remote machine. The specifics of the remote execution method used to
+do this is not specified here.
+.PP
+.SH EXAMPLE
+.PP
+Here is a sample configuration file:
+.PP
+.nf
+\fC
+.RS
+! proxy manager config file
+!
+! Each line has the format:
+! <serviceName> managed <startCommand>
+! or
+! <serviceName> unmanaged <proxyAddress>
+!
+lbx managed /usr/X11R6.4/bin/lbxproxy
+!
+! substitute site-specific info
+xfwp unmanaged firewall:4444
+\fP
+.RE
+.fi
+.PP
+.SH PROXY MANAGER DETAILS
+.PP
+When the proxy manager gets a request from xfindproxy (or another similar
+client), its course of action will depend on the service-name in question.
+.PP
+For a managed proxy service, the proxy manager will find out if any of the
+already running proxies for this service can handle a new request. If not,
+the proxy manager will attempt to start up a new instance of the proxy
+(using the command-to-start-proxy found in the config file). If that fails,
+an error will be returned to the caller.
+.PP
+For an unmanaged proxy service, the proxy manager will look in the config
+file to find all unmanaged proxies for this service. If there is more than
+one entry in the config file with the same unmanaged service-name, the
+proxy manager will try to use the proxies in the order presented in the
+config file. If none of the unmanged proxies can satisfy the request, the
+proxy manager will timeout for a configurable amount of time (specified by
+.B \-timeout
+or default of 10) and reattempt to find an unmanaged proxy willing
+to satisfy the request. The number of retries can be specified by the
+.B \-retries
+argument, or a default of 3 will be used. If the retries fail,
+the proxy manager has no choice but to return an error to the caller (since
+the proxy manager can not start unmanaged proxy services).
+.PP
+.SH BUGS
+proxy manager listen port should be configurable.
+.PP
+.B \-timeout
+and
+.B \-retries
+is not implemented in proxymngr.
+.PP
+proxymngr does not utilize the ``options'' and ``host'' fields in the
+proxy management protocol GetProxyAddr request.
+.SH SEE ALSO
+xfindproxy (1), xfwp (1), Proxy Management Protocol spec V1.0
+.SH AUTHOR
+Ralph Mor, X Consortium