public inbox for libc-hacker@sourceware.org
 help / color / mirror / Atom feed
From: Jakub Jelinek <jakub@redhat.com>
To: Ulrich Drepper <drepper@redhat.com>, Thorsten Kukuk <kukuk@suse.de>
Cc: Glibc hackers <libc-hacker@sources.redhat.com>
Subject: [PATCH] Avoid downloading whole NIS services.by{,service}name for getservby{name,port}{,_r} (, NULL)
Date: Tue, 30 Mar 2004 07:32:00 -0000	[thread overview]
Message-ID: <20040329210123.GC28220@sunsite.ms.mff.cuni.cz> (raw)

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  <jakub@redhat.com>

	* 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

             reply	other threads:[~2004-03-29 23:11 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-03-30  7:32 Jakub Jelinek [this message]
2004-03-30 15:40 ` Ulrich Drepper
2004-03-30 21:30 ` Thorsten Kukuk
2004-04-02  9:23   ` Thorsten Kukuk
2004-04-02 15:10     ` Ulrich Drepper

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040329210123.GC28220@sunsite.ms.mff.cuni.cz \
    --to=jakub@redhat.com \
    --cc=drepper@redhat.com \
    --cc=kukuk@suse.de \
    --cc=libc-hacker@sources.redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).