lib/wins_srv.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003    Samba wins server helper functions
00004    Copyright (C) Andrew Tridgell 1992-2002
00005    Copyright (C) Christopher R. Hertel 2000
00006    Copyright (C) Tim Potter 2003
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 #include "includes.h"
00024 
00025 extern struct in_addr loopback_ip;
00026 
00027 /*
00028   This is pretty much a complete rewrite of the earlier code. The main
00029   aim of the rewrite is to add support for having multiple wins server
00030   lists, so Samba can register with multiple groups of wins servers
00031   and each group has a failover list of wins servers.
00032 
00033   Central to the way it all works is the idea of a wins server
00034   'tag'. A wins tag is a label for a group of wins servers. For
00035   example if you use
00036 
00037       wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
00038 
00039   then you would have two groups of wins servers, one tagged with the
00040   name 'fred' and the other with the name 'mary'. I would usually
00041   recommend using interface names instead of 'fred' and 'mary' but
00042   they can be any alpha string.
00043 
00044   Now, how does it all work. Well, nmbd needs to register each of its
00045   IPs with each of its names once with each group of wins servers. So
00046   it tries registering with the first one mentioned in the list, then
00047   if that fails it marks that WINS server dead and moves onto the next
00048   one. 
00049 
00050   In the client code things are a bit different. As each of the groups
00051   of wins servers is a separate name space we need to try each of the
00052   groups until we either succeed or we run out of wins servers to
00053   try. If we get a negative response from a wins server then that
00054   means the name doesn't exist in that group, so we give up on that
00055   group and move to the next group. If we don't get a response at all
00056   then maybe the wins server is down, in which case we need to
00057   failover to the next one for that group.
00058 
00059   confused yet? (tridge)
00060 */
00061 
00062 /* how long a server is marked dead for */
00063 #define DEATH_TIME 600
00064 
00065 /* The list of dead wins servers is stored in gencache.tdb.  Each server is
00066    marked dead from the point of view of a given source address. We keep a 
00067    separate dead list for each src address to cope with multiple interfaces 
00068    that are not routable to each other.
00069   */
00070 
00071 #define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
00072 
00073 static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
00074 {
00075         char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
00076 
00077         wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
00078         src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
00079 
00080         if ( !wins_ip_addr || !src_ip_addr ) {
00081                 DEBUG(0,("wins_srv_keystr: malloc error\n"));
00082                 goto done;
00083         }
00084 
00085         if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
00086                 DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
00087         }
00088 
00089 done:
00090         SAFE_FREE(wins_ip_addr);
00091         SAFE_FREE(src_ip_addr);
00092 
00093         return keystr;
00094 }
00095 
00096 /*
00097   see if an ip is on the dead list
00098 */
00099 
00100 BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
00101 {
00102         char *keystr = wins_srv_keystr(wins_ip, src_ip);
00103         BOOL result;
00104 
00105         /* If the key exists then the WINS server has been marked as dead */
00106 
00107         result = gencache_get(keystr, NULL, NULL);
00108         SAFE_FREE(keystr);
00109 
00110         DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
00111                   result ? "dead" : "alive"));
00112 
00113         return result;
00114 }
00115 
00116 
00117 /*
00118   mark a wins server as being alive (for the moment)
00119 */
00120 void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
00121 {
00122         char *keystr = wins_srv_keystr(wins_ip, src_ip);
00123 
00124         gencache_del(keystr);
00125         SAFE_FREE(keystr);
00126 
00127         DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n", 
00128                   inet_ntoa(wins_ip)));
00129 }
00130 
00131 /*
00132   mark a wins server as temporarily dead
00133 */
00134 void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
00135 {
00136         char *keystr;
00137 
00138         if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
00139                 return;
00140 
00141         keystr = wins_srv_keystr(wins_ip, src_ip);
00142 
00143         gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
00144 
00145         SAFE_FREE(keystr);
00146 
00147         DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
00148                  inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
00149 }
00150 
00151 /*
00152   return the total number of wins servers, dead or not
00153 */
00154 unsigned wins_srv_count(void)
00155 {
00156         const char **list;
00157         int count = 0;
00158 
00159         if (lp_wins_support()) {
00160                 /* simple - just talk to ourselves */
00161                 return 1;
00162         }
00163 
00164         list = lp_wins_server_list();
00165         for (count=0; list && list[count]; count++)
00166                 /* nop */ ;
00167 
00168         return count;
00169 }
00170 
00171 /* an internal convenience structure for an IP with a short string tag
00172    attached */
00173 struct tagged_ip {
00174         fstring tag;
00175         struct in_addr ip;
00176 };
00177 
00178 /*
00179   parse an IP string that might be in tagged format
00180   the result is a tagged_ip structure containing the tag
00181   and the ip in in_addr format. If there is no tag then
00182   use the tag '*'
00183 */
00184 static void parse_ip(struct tagged_ip *ip, const char *str)
00185 {
00186         char *s = strchr(str, ':');
00187         if (!s) {
00188                 fstrcpy(ip->tag, "*");
00189                 ip->ip = *interpret_addr2(str);
00190                 return;
00191         } 
00192 
00193         ip->ip = *interpret_addr2(s+1);
00194         fstrcpy(ip->tag, str);
00195         s = strchr(ip->tag, ':');
00196         if (s) *s = 0;
00197 }
00198 
00199 
00200 
00201 /*
00202   return the list of wins server tags. A 'tag' is used to distinguish
00203   wins server as either belonging to the same name space or a separate
00204   name space. Usually you would setup your 'wins server' option to
00205   list one or more wins server per interface and use the interface
00206   name as your tag, but you are free to use any tag you like.
00207 */
00208 char **wins_srv_tags(void)
00209 {
00210         char **ret = NULL;
00211         int count=0, i, j;
00212         const char **list;
00213 
00214         if (lp_wins_support()) {
00215                 /* give the caller something to chew on. This makes
00216                    the rest of the logic simpler (ie. less special cases) */
00217                 ret = SMB_MALLOC_ARRAY(char *, 2);
00218                 if (!ret) return NULL;
00219                 ret[0] = SMB_STRDUP("*");
00220                 ret[1] = NULL;
00221                 return ret;
00222         }
00223 
00224         list = lp_wins_server_list();
00225         if (!list)
00226                 return NULL;
00227 
00228         /* yes, this is O(n^2) but n is very small */
00229         for (i=0;list[i];i++) {
00230                 struct tagged_ip t_ip;
00231                 
00232                 parse_ip(&t_ip, list[i]);
00233 
00234                 /* see if we already have it */
00235                 for (j=0;j<count;j++) {
00236                         if (strcmp(ret[j], t_ip.tag) == 0) {
00237                                 break;
00238                         }
00239                 }
00240 
00241                 if (j != count) {
00242                         /* we already have it. Move along */
00243                         continue;
00244                 }
00245 
00246                 /* add it to the list */
00247                 ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
00248                 if (!ret) {
00249                         return NULL;
00250                 }
00251                 ret[count] = SMB_STRDUP(t_ip.tag);
00252                 if (!ret[count]) break;
00253                 count++;
00254         }
00255 
00256         if (count) {
00257                 /* make sure we null terminate */
00258                 ret[count] = NULL;
00259         }
00260 
00261         return ret;
00262 }
00263 
00264 /* free a list of wins server tags given by wins_srv_tags */
00265 void wins_srv_tags_free(char **list)
00266 {
00267         int i;
00268         if (!list) return;
00269         for (i=0; list[i]; i++) {
00270                 free(list[i]);
00271         }
00272         free(list);
00273 }
00274 
00275 
00276 /*
00277   return the IP of the currently active wins server for the given tag,
00278   or the zero IP otherwise
00279 */
00280 struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
00281 {
00282         const char **list;
00283         int i;
00284         struct tagged_ip t_ip;
00285 
00286         /* if we are a wins server then we always just talk to ourselves */
00287         if (lp_wins_support()) {
00288                 return loopback_ip;
00289         }
00290 
00291         list = lp_wins_server_list();
00292         if (!list || !list[0]) {
00293                 struct in_addr ip;
00294                 zero_ip(&ip);
00295                 return ip;
00296         }
00297 
00298         /* find the first live one for this tag */
00299         for (i=0; list[i]; i++) {
00300                 parse_ip(&t_ip, list[i]);
00301                 if (strcmp(tag, t_ip.tag) != 0) {
00302                         /* not for the right tag. Move along */
00303                         continue;
00304                 }
00305                 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
00306                         fstring src_name;
00307                         fstrcpy(src_name, inet_ntoa(src_ip));
00308                         DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n", 
00309                                  tag, 
00310                                  src_name,
00311                                  inet_ntoa(t_ip.ip)));
00312                         return t_ip.ip;
00313                 }
00314         }
00315         
00316         /* they're all dead - try the first one until they revive */
00317         for (i=0; list[i]; i++) {
00318                 parse_ip(&t_ip, list[i]);
00319                 if (strcmp(tag, t_ip.tag) != 0) {
00320                         continue;
00321                 }
00322                 return t_ip.ip;
00323         }
00324 
00325         /* this can't happen?? */
00326         zero_ip(&t_ip.ip);
00327         return t_ip.ip;
00328 }
00329 
00330 
00331 /*
00332   return a count of the number of IPs for a particular tag, including
00333   dead ones
00334 */
00335 unsigned wins_srv_count_tag(const char *tag)
00336 {
00337         const char **list;
00338         int i, count=0;
00339 
00340         /* if we are a wins server then we always just talk to ourselves */
00341         if (lp_wins_support()) {
00342                 return 1;
00343         }
00344 
00345         list = lp_wins_server_list();
00346         if (!list || !list[0]) {
00347                 return 0;
00348         }
00349 
00350         /* find the first live one for this tag */
00351         for (i=0; list[i]; i++) {
00352                 struct tagged_ip t_ip;
00353                 parse_ip(&t_ip, list[i]);
00354                 if (strcmp(tag, t_ip.tag) == 0) {
00355                         count++;
00356                 }
00357         }
00358 
00359         return count;
00360 }

Sambaに対してSat Aug 29 21:23:00 2009に生成されました。  doxygen 1.4.7