/* Configuration Manager for RPC cm_env.c ** ============================= ** ** This module provides address translation facilities for an RPC system, ** using the process environment (on VMS: logical name tables) as a ** local database, and then the WAY name server. ** ** Authors: ** ** Roberto Bagnara CERN, Univ. Pisa (RB) ** Tim Berners-Lee CERN (TBL) ** ** History: ** ** 4 Dec 89 Adapted from cm_env.c (RB) ** Dec 89 Various small bug fixes (TBL) */ #define RPC_S_NO_WAY_ACCESS 120 /* ** Include files. ** -------------- */ #include #include /* ANSI form of strings.h */ #include "rpcrts.h" /* RPC macros. */ #include "syspec.h" /* Condition the internal macros */ #include "rpc_code.h" /* Macros for internal use by RPC code. */ #include "way.h" /* ** External functions. ** ------------------- */ #ifdef __STDC__ extern char *malloc(int size); extern void free(char *ptr); extern void abort(void); extern void rpc_open(rpc_status *status, int *phandle, rpc_name service_name); extern void rpc_close(rpc_status *status, int handle); extern way_status way_register(const char *service, int version, int compatibility, const char *address); extern way_status way_unregister(const char *service, int version, const char *address); extern way_status way_request(const char *service, int version, int compatibility, const char *pref_addresses, int address_length, char *address); extern rpc_status way_register_errors(void); #else extern char *malloc(); extern void free(); extern void abort(); extern void rpc_open(); extern void rpc_close(); extern way_status way_register(); extern way_status way_unregister(); extern way_status way_request(); extern rpc_status way_register_errors(); #endif /* ** ** Capitalise a character. ** ----------------------- ** ** ** char uppercase(char c) ** ** Parameters: c character to be upper-cased. ** ** Return: upper-cased character. ** ** On entry: none ** ** On exit: none ** ** Description: ** ** Self explanatory. ** ** History: ** ** 14 Aug 89 Cleaned up. (RB) ** */ #ifdef UPPERCASE_LOGICALS #ifdef __STDC__ char uppercase(char c) #else char uppercase(c) char c; #endif { return ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 'A') : c; } #endif /* ** ** Capitalise a string. ** -------------------- ** ** ** void capital(char *string) ** ** Parameters: string pointer to string to be capitalised. ** ** Return: none ** ** On entry: string null terminated string. ** ** On exit: string same as above but capitalised. ** ** Description: ** ** Self explanatory. ** ** History: ** ** 14 Aug 89 Cleaned up. (RB) ** */ #ifdef UPPERCASE_LOGICALS #ifdef __STDC__ void capital(char *string) #else void capital(string) char *string; #endif { register char *p; for (p = string; *p; p++) *p = uppercase(*p); } #endif /* ** ** Recursively translates logical names. ** ------------------------------------- ** ** ** rpc_status translate(char *buffer, int buflen, int curlevel, ** int maxlevel, char *previous[]) ** ** Parameters: buffer pointer to string containing the name to ** be translated on entry, its translation ** on exit; ** ** buflen maximum length of the translation; ** ** curlevel current recursion level; ** ** maxlevel maximum recursion level; ** ** previous array of pointers to previous translation ** strings. ** ** Return: RPC_S_NO_TRANSLATION if no translation exist ** or if a translation loop was detected; ** RPC_S_BUFFER_OVERFLOW if the supplied buffer ** was not big enough to hold the ** translation; ** RPC_S_NORMAL otherwise. ** ** On entry: buffer null terminated string containing the name to ** translate; ** ** previous contains in positions 0 to curlevel-1 ** pointers to the previous translation strings. ** ** On exit: buffer null terminated translation string. ** ** Description: ** ** Recursively gets the translation of the string contained in 'buffer' ** from the environment. Recursion stops when either the maximum ** recursion level 'maxlevel' is reached, or there is no translation, ** or a translation loop is detected (in this case RPC_S_NO_TRANSLATION ** is returned). ** ** History: ** ** 14 Aug 89 Rewritten. (RB) ** 4 Dec 89 Bug fix (return NO_TRANSATION if no translation). (TBL) */ #ifdef __STDC__ static rpc_status translate(char *buffer, int buflen, int curlevel, int maxlevel, char *previous[]) #else static rpc_status translate(buffer, buflen, curlevel, maxlevel, previous) char *buffer; int buflen; int curlevel; int maxlevel; char *previous[]; #endif { int status; if (curlevel < maxlevel) { extern char *getenv(); char *translation; char *aux_buf; /* Copy the input string into our private buffer. */ aux_buf = malloc(buflen); (void) strcpy(aux_buf, buffer); #ifdef UPPERCASE_LOGICALS /* Lowercase environment variables are not allowed. */ capital(aux_buf); #endif /* Save pointer to name we are trying to translate. */ previous[curlevel] = aux_buf; /* Try translating. */ if ((translation = getenv(aux_buf)) != NULL) { int k; /* Translation worked: save and retry. */ if (strlen(translation) > buflen - 1) { CTRACE(tfp, "RPC/CM: Buffer overflow translating `%s' to `%s'\n", aux_buf, translation); return RPC_S_BUFFER_OVERFLOW; } (void) strcpy(buffer, translation); CTRACE(tfp, "RPC/CM: Translated `%s' to `%s'\n", aux_buf, buffer); /* Check for translation loop. */ for (k = 0; k <= curlevel; k++) if (strcmp(previous[k], buffer) == 0) { UTRACE(tfp, "RPC/CM: Translation loop detected, fail.\n"); free(aux_buf); return RPC_S_NO_TRANSLATION; } status = translate(buffer, buflen, curlevel+1, maxlevel, previous); if (status == RPC_S_NO_TRANSLATION) /* If we couldn't again, */ status = RPC_S_NORMAL; /* we did it once, anyway */ } else { /* Translation didn't work, say it's bad. */ CTRACE(tfp, "RPC/CM: No translation for `%s'.\n", aux_buf); status = RPC_S_NO_TRANSLATION; } free(aux_buf); } else { /* Maximum translation level reached, return ok. */ status = RPC_S_NORMAL; } return status; } /* ** ** Satisfy requests for configuration items. ** ----------------------------------------- ** ** ** rpc_status cm_translate(const char *name, char *expansion, int explen) ** ** Parameters: name pointer to string containing the name to be ** looked up; ** ** expansion pointer to string where the expansion for ** 'name' will be stored; ** ** explen maximum length of the expansion for 'name'. ** ** Return: RPC_S_NO_TRANSLATION if no translation exist ** or if a translation loop was detected; ** RPC_S_BUFFER_OVERFLOW if the supplied buffer ** was not big enough to hold the ** translation; ** RPC_S_NORMAL otherwise. ** ** On entry: name Null terminated string containing the name to ** looked up. ** ** On exit: expansion Null terminated string containing the expansion ** for name, possibly truncated to explen-1 ** characters. ** ** Description: ** ** Initialises for calling the translate() recursive function ** that will do the real job. ** ** History: ** ** 14 Aug 89 Rewritten. (RB) ** */ #ifdef __STDC__ rpc_status cm_translate(const char *name, char *expansion, int explen) #else rpc_status cm_translate(name, expansion, explen) char *name; char *expansion; int explen; #endif { #define TRANSLATION_LIMIT 10 /* This array is used to detect translation loops. */ char *previous[TRANSLATION_LIMIT]; /* Copy name to expansion, if there is enough room. */ if (strlen(name) > explen - 1) { CTRACE(tfp, "RPC/CM: Buffer overflow when translating `%s'.\n", name); return RPC_S_BUFFER_OVERFLOW; } (void) strcpy(expansion, name); /* Do the actual translation. */ return translate(expansion, explen, 0, TRANSLATION_LIMIT, previous); } #define WAY_REGISTER_NAME "way_register" #define WAY_REQUEST_NAME "way_request" /* ** ** Satisfy requests for named service. ** ----------------------------------- ** ** ** rpc_status cm_request(rpc_name logical, int version, ** int compatibility, rpc_name buffer, int buffer_size) ** ** Parameters: logical pointer to the null-terminated string ** containing the name of the requested service; ** ** version is the actual version of the client; ** ** compatibility is the lowest previous version of server ** which is also supported; ** ** buffer pointer to string where the server RPC address ** will be stored; ** ** buffer_size maximum length of the server address. ** ** Return: RPC_S_NO_TRANSLATION if no suitable server is ** available or if a translation loop ** was detected; ** RPC_S_BUFFER_OVERFLOW if the supplied buffer ** was not big enough to hold the ** server address; ** RPC_S_NORMAL otherwise. ** ** On entry: logical Null terminated string containing the name to ** looked up. ** ** On exit: expansion Null terminated string containing the ** server address, if RPC_S_NORMAL was returned. ** ** Description: ** ** Given the logical name of a requested service, this procedure does ** whatever is necessary to locate the service, and return the physical ** address. ** ** WARNING ** ------- ** ** THIS FUNCTION IS SUBJECT TO FREQUENT CHANGES, AS THE ** WAY FUNCTIONALITIES ARE EXTENDED AND THE INTEGRATION ** WITH RaPaCe IS IMPROVED. ** ** This (preliminary) implementation tries a local translation first, ** using the environment as the database: this is done by calling ** cm_translate(). If the translation succeeds then its result is ** returned as the server address. If it fails because a symbol ** correspondent to the service logical name could not be found ** in the environment, then an attempt to use the WAY name server ** takes place. ** ** This is done by first trying to establish a connection with the WAY ** server providing the "WAY Request Service". If the communication ** can be set up, the WAY server is asked to look into its database ** for the specified service logical name (with version checking and ** so on). The WAY completion code returned is then directly translated ** into an RPC one and returned to the caller. ** ** History: ** ** 14 Aug 89 Rewritten. (RB) ** 16 Nov 89 Added code for WAY interrogation. (RB) ** 7 Dec 89 original_h_way remembered in case recursive (TBL) ** */ #ifdef __STDC__ rpc_status cm_request(rpc_name logical, int version, int compatibility, rpc_name buffer, int buffer_size) #else rpc_status cm_request(logical, version, compatibility, buffer, buffer_size) #endif { rpc_status r_status; way_status w_status; extern rpc_handle h_way; rpc_handle original_h_way; /* Try a translation using the environment as the database. */ r_status = cm_translate(logical, buffer, buffer_size); /* If it worked or something horrible has happened, or we are trying to use WAY, just return the status. */ if (r_status != RPC_S_NO_TRANSLATION || !strcmp(logical, WAY_REQUEST_NAME)) return r_status; /* Try using WAY (Where Are You ?). */ original_h_way = h_way; /* Save old handle */ rpc_open(&r_status, &h_way, WAY_REQUEST_NAME); /* If open failed return RPC_S_NO_TRANSLATION. */ if (BAD(r_status)) { CTRACE(tfp, "RPC/CM: Cannot access WAY, no translation is possible.\n"); h_way = original_h_way; /* restore original version */ return RPC_S_NO_TRANSLATION; } /* Open succeeded, ask WAY if a suitable server is around. */ w_status = way_request(logical, version, compatibility, "*", buffer_size, buffer); /* Close the connection with WAY. */ rpc_close(&r_status, h_way); h_way = original_h_way; /* restore original version */ /* Return the appropriate completion code. */ switch (w_status) { case WAY_S_NORMAL: { CTRACE(tfp, "RPC/CM/WAY: A compatible `%s' server is available at `%s'.\n", logical, buffer); r_status = RPC_S_NORMAL; break; } case WAY_S_NO_SERVER: { CTRACE(tfp, "RPC/CM/WAY: No compatible `%s' server is available.\n", logical); r_status = RPC_S_NO_TRANSLATION; break; } case WAY_S_BUFFER_OVERFLOW: { CTRACE(tfp, "RPC/CM/WAY: Buffer overflow looking for a `%s' server.\n", logical); r_status = RPC_S_BUFFER_OVERFLOW; break; } default: /* Should never happen. */ abort(); break; } /* Return the appropriate RPC status. */ return r_status; } /* ** ** Register a service. ** ------------------- ** ** ** rpc_status cm_register(const char *service, int version, ** int compatibility, const char *address) ** ** Parameters: service pointer to the null-terminated string ** containing the name of the offered service; ** ** version is the actual version of the server; ** ** compatibility is the lowest previous version of client ** which is also supported; ** ** address pointer to the null-terminated string ** containing the server RPC address. ** ** Return: RPC_S_NO_WAY_ACCESS if no WAY server was ** available making the registration ** impossible; ** RPC_S_NORMAL if the registration succeeded. ** ** On entry: All the parameters are set to the appropriate ** value. ** ** On exit: The parameters are unchanged. ** ** Description: ** ** This routine records, when possible, the provision of a service at ** a particular given RPC address. The service is characterized by its ** name and its version and compatibility number. At present the only ** possibility to achieve such a recording is to call a remote WAY ** server, if one is defined. ** ** WARNING ** ------- ** ** THIS FUNCTION IS SUBJECT TO FREQUENT CHANGES, AS THE ** WAY FUNCTIONALITIES ARE EXTENDED AND THE INTEGRATION ** WITH RaPaCe IS IMPROVED. ** ** This (preliminary) implementation tries to establish a connection ** with the WAY server providing the "WAY Register Service". If the ** communication can be set up, the WAY server is asked to do the ** registration. The WAY completion code returned is then directly ** translated into an RPC one and returned to the caller. ** ** History: ** ** 18 Nov 89 Written. (RB) ** 7 Dec 89 original_h_way remembered in case recursive (TBL) ** */ #ifdef __STDC__ rpc_status cm_register(const char *service, int version, int compatibility, const char *address) #else rpc_status cm_register(service, version, compatibility, address) char *service; int version; int compatibility; char *address; #endif { rpc_status r_status; way_status w_status; extern rpc_handle h_way; rpc_handle original_h_way; /* Try to avoid entering an endless loop. Really, since in principle a WAY server could register itself into another WAY server, a neater implementation would check both the service name and the server address. This could be done in future revisions. */ if (!strcmp(service, WAY_REGISTER_NAME)) return RPC_S_NORMAL; /* Try to open a connection with the remote WAY server. */ original_h_way = h_way; /* Save in case recursively called */ rpc_open(&r_status, &h_way, WAY_REGISTER_NAME); /* If open failed return RPC_S_NO_WAY_ACCESS. */ if (BAD(r_status)) { CTRACE(tfp, "RPC/CM: Cannot access WAY, no registration is possible.\n"); h_way = original_h_way; /* Restore */ return RPC_S_NO_WAY_ACCESS; } /* Open succeeded, ask WAY to do the registration. */ w_status = way_register(service, version, compatibility, address); /* Close the connection with WAY. */ rpc_close(&r_status, h_way); h_way = original_h_way; /* Restore */ /* Return the appropriate completion code. */ switch (w_status) { case WAY_S_NORMAL: { CTRACE(tfp, "RPC/CM/WAY: Registered `%s' (Version %d Compat %d) at `%s'.", service, version, compatibility, address); r_status = RPC_S_NORMAL; break; } default: /* Should never happen. */ abort(); break; } /* Return the appropriate RPC status. */ return r_status; } /* ** ** Remove a registration. ** ---------------------- ** ** ** rpc_status cm_unregister(const char *service, int version, ** const char *address) ** ** Parameters: service pointer to the null-terminated string ** containing the name of the service to ** be unregistered; ** ** version is the actual version of the server; ** ** address pointer to the null-terminated string ** containing the server address. ** ** Return: RPC_S_NO_WAY_ACCESS if no WAY server was ** available making the unregistration ** impossible; ** RPC_S_NORMAL if the un registration succeeded. ** ** On entry: All the parameters are set to the appropriate ** value. ** ** On exit: The parameters are unchanged. ** ** Description: ** ** This routine removes the record of the provision of a service at a ** particular given RPC address. The service is characterized by its ** name and its version number. This routine is the symmetrical ** counterpart of cm_register(), the same general comments apply. ** ** WARNING ** ------- ** ** THIS FUNCTION IS SUBJECT TO FREQUENT CHANGES, AS THE ** WAY FUNCTIONALITIES ARE EXTENDED AND THE INTEGRATION ** WITH RaPaCe IS IMPROVED. ** ** This (preliminary) implementation tries to establish a connection ** with the WAY server providing the "WAY Register Service". If the ** communication can be set up, the WAY server is asked to do the ** unregistration. The WAY completion code returned is then directly ** translated into an RPC one and returned to the caller. ** ** History: ** ** 18 Nov 89 Written. (RB) ** 7 Dec 89 original_h_way remembered in case recursive (TBL) ** */ #ifdef __STDC__ rpc_status cm_unregister(const char *service, int version, const char *address) #else rpc_status cm_unregister(service, version, address) char *service; int version; char *address; #endif { rpc_status r_status; way_status w_status; extern rpc_handle h_way; rpc_handle original_h_way; /* The same comment in cm_register() apply here. */ if (!strcmp(service, WAY_REGISTER_NAME)) return RPC_S_NORMAL; /* Try to open a connection with the remote WAY server. */ original_h_way = h_way; /* Save */ rpc_open(&r_status, &h_way, WAY_REGISTER_NAME); /* If open failed return RPC_S_NO_WAY_ACCESS. */ if (BAD(r_status)) { CTRACE(tfp, "RPC/CM: Cannot access WAY, no unregistration is possible.\n"); h_way = original_h_way; /* Restore */ return RPC_S_NO_WAY_ACCESS; } /* Open succeeded, ask WAY to do the unregistration. */ w_status = way_unregister(service, version, address); /* Close the connection with WAY. */ rpc_close(&r_status, h_way); h_way = original_h_way; /* Restore */ /* Return the appropriate completion code. */ switch (w_status) { case WAY_S_NORMAL: { CTRACE(tfp, "RPC/CM/WAY: Unregistered `%s' (Version %d) at `%s'.", service, version, address); r_status = RPC_S_NORMAL; break; } default: /* Should never happen. */ abort(); break; } /* Return the appropriate RPC status. */ return r_status; } /* Initialse This Module cm_init() ** --------------------- ** ** On entry, ** No prerequisites. ** ** On exit, ** CM may be used. More specifically, the error codes reported by ** CM will be registered for translation. ** */ #ifdef __STDC__ rpc_status cm_init(void) #else rpc_status cm_init() #endif { #ifndef vms return way_register_errors(); #else globalvalue way_s_normal; /* Force inclusion of error module */ return way_s_normal; #endif }