This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Avoid downloading whole NIS services.by{,service}name for getservby{name,port}{,_r} (, NULL)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]