From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9246 invoked by alias); 29 Mar 2004 23:11:33 -0000 Mailing-List: contact libc-hacker-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sources.redhat.com Received: (qmail 9092 invoked from network); 29 Mar 2004 23:11:24 -0000 Received: from unknown (HELO sunsite.ms.mff.cuni.cz) (195.113.15.26) by sources.redhat.com with SMTP; 29 Mar 2004 23:11:24 -0000 Received: from sunsite.ms.mff.cuni.cz (sunsite.mff.cuni.cz [127.0.0.1]) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8) with ESMTP id i2TL1OHS002754; Mon, 29 Mar 2004 23:01:24 +0200 Received: (from jakub@localhost) by sunsite.ms.mff.cuni.cz (8.12.8/8.12.8/Submit) id i2TL1NH6002748; Mon, 29 Mar 2004 23:01:23 +0200 Date: Tue, 30 Mar 2004 07:32:00 -0000 From: Jakub Jelinek To: Ulrich Drepper , Thorsten Kukuk Cc: Glibc hackers Subject: [PATCH] Avoid downloading whole NIS services.by{,service}name for getservby{name,port}{,_r} (, NULL) Message-ID: <20040329210123.GC28220@sunsite.ms.mff.cuni.cz> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2004-03/txt/msg00142.txt.bz2 Hi! Only lightly tested so far. It is not neccessary to download, allocate and copy whole services map and then search through it. Instead, we can search already in the foreach callback and if we find something tell the caller we don't need further input. BTW: __xdr_ypresp_all uses the foreach callback return value as 0 -> need further data, != 0 break the loop. But saveit callbacks I see return 0 when further data should be examined and YP_FALSE (== 0) on error (e.g. memory failures). This certainly doesn't sound right. 2004-03-30 Jakub Jelinek * nis/nss_nis/nis-service.c (struct search_t): New type. (dosearch): New function. (_nss_nis_getservbyname_r): Use it. Call yp_get_default_domain unconditionally. (_nss_nis_getservbyport_r): Likewise. --- libc/nis/nss_nis/nis-service.c.jj 2003-01-18 11:18:41.000000000 +0100 +++ libc/nis/nss_nis/nis-service.c 2004-03-30 00:49:23.341175888 +0200 @@ -51,6 +51,18 @@ typedef struct intern_t intern_t; static intern_t intern = { NULL, NULL }; +struct search_t +{ + const char *name; + const char *proto; + int port; + enum nss_status status; + struct servent *serv; + char *buffer; + size_t buflen; + int *errnop; +}; + static int saveit (int instatus, char *inkey, int inkeylen, char *inval, int invallen, char *indata) @@ -87,6 +99,68 @@ saveit (int instatus, char *inkey, int i return 0; } +static int +dosearch (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, char *indata) +{ + struct search_t *req = (struct search_t *) indata; + + if (instatus != YP_TRUE) + return 1; + + if (inkey && inkeylen > 0 && inval && invallen > 0) + { + struct parser_data *pdata = (void *) req->buffer; + int parse_res; + char *p; + + if ((size_t) (invallen + 1) > req->buflen) + { + *req->errnop = ERANGE; + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + p = strncpy (req->buffer, inval, invallen); + req->buffer[invallen] = '\0'; + while (isspace (*p)) + ++p; + + parse_res = _nss_files_parse_servent (p, req->serv, pdata, req->buflen, + req->errnop); + if (parse_res == -1) + { + req->status = NSS_STATUS_TRYAGAIN; + return 1; + } + + if (!parse_res) + return 0; + + if (req->proto != NULL && strcmp (req->serv->s_proto, req->proto) != 0) + return 0; + + if (req->port != -1 && req->serv->s_port != req->port) + return 0; + + if (req->name != NULL && strcmp (req->serv->s_name, req->name) != 0) + { + char **cp; + for (cp = req->serv->s_aliases; *cp; cp++) + if (strcmp (req->name, *cp) == 0) + break; + + if (*cp == NULL) + return 0; + } + + req->status = NSS_STATUS_SUCCESS; + return 1; + } + + return 0; +} + static enum nss_status internal_nis_endservent (intern_t * intern) { @@ -136,6 +210,7 @@ internal_nis_setservent (intern_t *inter return status; } + enum nss_status _nss_nis_setservent (int stayopen) { @@ -201,9 +276,8 @@ _nss_nis_getservbyname_r (const char *na struct servent *serv, char *buffer, size_t buflen, int *errnop) { - intern_t data = { NULL, NULL }; enum nss_status status; - int found; + char *domain; if (name == NULL) { @@ -211,19 +285,18 @@ _nss_nis_getservbyname_r (const char *na return NSS_STATUS_UNAVAIL; } + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; + /* If the protocol is given, we could try if our NIS server knows about services.byservicename map. If yes, we only need one query */ if (protocol != NULL) { char key[strlen (name) + strlen (protocol) + 2]; - char *cp, *domain, *result; + char *cp, *result; size_t keylen, len; int int_len; - /* If this fails, the other solution will also fail. */ - if (yp_get_default_domain (&domain)) - return NSS_STATUS_UNAVAIL; - /* key is: "name/protocol" */ cp = stpcpy (key, name); *cp++ = '/'; @@ -267,34 +340,25 @@ _nss_nis_getservbyname_r (const char *na } } - status = internal_nis_setservent (&data); - if (status != NSS_STATUS_SUCCESS) - return status; - - found = 0; - while (!found && - ((status = internal_nis_getservent_r (serv, buffer, buflen, errnop, - &data)) == NSS_STATUS_SUCCESS)) - { - if (protocol == NULL || strcmp (serv->s_proto, protocol) == 0) - { - char **cp; - - if (strcmp (serv->s_name, name) == 0) - found = 1; - else - for (cp = serv->s_aliases; *cp; cp++) - if (strcmp (name, *cp) == 0) - found = 1; - } - } + struct ypall_callback ypcb; + struct search_t req; - internal_nis_endservent (&data); + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = name; + req.proto = protocol; + req.port = -1; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + status = yperr2nss (yp_all (domain, "services.byservicename", &ypcb)); - if (!found && status == NSS_STATUS_SUCCESS) - return NSS_STATUS_NOTFOUND; - else + if (status != NSS_STATUS_SUCCESS) return status; + + return req.status; } enum nss_status @@ -302,22 +366,20 @@ _nss_nis_getservbyport_r (int port, cons struct servent *serv, char *buffer, size_t buflen, int *errnop) { - intern_t data = { NULL, NULL }; enum nss_status status; - int found; + char *domain; + + if (yp_get_default_domain (&domain)) + return NSS_STATUS_UNAVAIL; /* If the protocol is given, we only need one query */ if (protocol != NULL) { char key[100 + strlen (protocol) + 2]; - char *domain, *result; + char *result; size_t keylen, len; int int_len; - /* If this fails, the other solution will also fail. */ - if (yp_get_default_domain (&domain)) - return NSS_STATUS_UNAVAIL; - /* key is: "port/protocol" */ keylen = snprintf (key, sizeof (key), "%d/%s", port, protocol); status = yperr2nss (yp_match (domain, "services.byname", key, @@ -358,22 +420,26 @@ _nss_nis_getservbyport_r (int port, cons } } - status = internal_nis_setservent (&data); - if (status != NSS_STATUS_SUCCESS) - return status; + if (port == -1) + return NSS_STATUS_NOTFOUND; - found = 0; - while (!found && - ((status = internal_nis_getservent_r (serv, buffer, buflen, errnop, - &data)) == NSS_STATUS_SUCCESS)) - if (serv->s_port == port && - (protocol == NULL || strcmp (serv->s_proto, protocol) == 0)) - found = 1; + struct ypall_callback ypcb; + struct search_t req; - internal_nis_endservent (&data); + ypcb.foreach = dosearch; + ypcb.data = (char *) &req; + req.name = NULL; + req.proto = protocol; + req.port = port; + req.serv = serv; + req.buffer = buffer; + req.buflen = buflen; + req.errnop = errnop; + req.status = NSS_STATUS_NOTFOUND; + status = yperr2nss (yp_all (domain, "services.byname", &ypcb)); - if (!found && status == NSS_STATUS_SUCCESS) - return NSS_STATUS_NOTFOUND; - else + if (status != NSS_STATUS_SUCCESS) return status; + + return req.status; } Jakub