Exemple #1
0
void
tree_add_duplicate(uschar *s, address_item *addr)
{
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.ptr = addr;
if (!tree_insertnode(&tree_duplicates, node)) store_reset(node);
}
Exemple #2
0
void
tree_add_nonrecipient(uschar *s)
{
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.ptr = NULL;
if (!tree_insertnode(&tree_nonrecipients, node)) store_reset(node);
}
Exemple #3
0
static int
dns_return(const uschar * name, int type, int rc)
{
res_state resp = os_get_dns_resolver_res();
tree_node *node = store_get_perm(sizeof(tree_node) + 290);
sprintf(CS node->name, "%.255s-%s-%lx", name, dns_text_type(type),
  resp->options);
node->data.val = rc;
(void)tree_insertnode(&tree_dns_fails, node);
return rc;
}
Exemple #4
0
void
tree_add_unusable(host_item *h)
{
tree_node *node;
uschar s[256];
sprintf(CS s, "T:%.200s:%s", h->name, h->address);
node = store_get(sizeof(tree_node) + Ustrlen(s));
Ustrcpy(node->name, s);
node->data.val = h->why;
if (h->status == hstatus_unusable_expired) node->data.val += 256;
if (!tree_insertnode(&tree_unusable, node)) store_reset(node);
}
Exemple #5
0
static uschar *
internal_search_find(void *handle, uschar *filename, uschar *keystring)
{
tree_node *t = (tree_node *)handle;
search_cache *c = (search_cache *)(t->data.ptr);
uschar *data = NULL;
int search_type = t->name[0] - '0';
int old_pool = store_pool;

/* Lookups that return DEFER may not always set an error message. So that
the callers don't have to test for NULL, set an empty string. */

search_error_message = US"";
search_find_defer = FALSE;

DEBUG(D_lookup) debug_printf("internal_search_find: file=\"%s\"\n  "
  "type=%s key=\"%s\"\n", filename,
  lookup_list[search_type]->name, keystring);

/* Insurance. If the keystring is empty, just fail. */

if (keystring[0] == 0) return NULL;

/* Use the special store pool for search data */

store_pool = POOL_SEARCH;

/* Look up the data for the key, unless it is already in the cache for this
file. No need to check c->item_cache for NULL, tree_search will do so. */

if ((t = tree_search(c->item_cache, keystring)) == NULL)
  {
  BOOL do_cache = TRUE;
  int keylength = Ustrlen(keystring);

  DEBUG(D_lookup)
    {
    if (filename != NULL)
      debug_printf("file lookup required for %s\n  in %s\n",
        keystring, filename);
    else
      debug_printf("database lookup required for %s\n", keystring);
    }

  /* Call the code for the different kinds of search. DEFER is handled
  like FAIL, except that search_find_defer is set so the caller can
  distinguish if necessary. */

  if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
      &data, &search_error_message, &do_cache) == DEFER)
    {
    search_find_defer = TRUE;
    }

  /* A record that has been found is now in data, which is either NULL
  or points to a bit of dynamic store. Cache the result of the lookup if
  caching is permitted. Lookups can disable caching, when they did something
  that changes their data. The mysql and pgsql lookups do this when an
  UPDATE/INSERT query was executed. */

  else if (do_cache)
    {
    int len = keylength + 1;
    t = store_get(sizeof(tree_node) + len);
    memcpy(t->name, keystring, len);
    t->data.ptr = data;
    tree_insertnode(&c->item_cache, t);
    }

  /* If caching was disabled, empty the cache tree. We just set the cache
  pointer to NULL here, because we cannot release the store at this stage. */

  else
    {
    DEBUG(D_lookup) debug_printf("lookup forced cache cleanup\n");
    c->item_cache = NULL;
    }
  }
Exemple #6
0
void *
search_open(uschar *filename, int search_type, int modemask, uid_t *owners,
  gid_t *owngroups)
{
void *handle;
tree_node *t;
search_cache *c;
lookup_info *lk = lookup_list[search_type];
uschar keybuffer[256];
int old_pool = store_pool;

/* Change to the search store pool and remember our reset point */

store_pool = POOL_SEARCH;
if (search_reset_point == NULL) search_reset_point = store_get(0);

DEBUG(D_lookup) debug_printf("search_open: %s \"%s\"\n", lk->name,
  (filename == NULL)? US"NULL" : filename);

/* See if we already have this open for this type of search, and if so,
pass back the tree block as the handle. The key for the tree node is the search
type plus '0' concatenated with the file name. There may be entries in the tree
with closed files if a lot of files have been opened. */

sprintf(CS keybuffer, "%c%.254s", search_type + '0',
  (filename == NULL)? US"" : filename);

if ((t = tree_search(search_tree, keybuffer)) != NULL)
  {
  c = (search_cache *)(t->data.ptr);
  if (c->handle != NULL)
    {
    DEBUG(D_lookup) debug_printf("  cached open\n");
    store_pool = old_pool;
    return t;
    }
  DEBUG(D_lookup) debug_printf("  cached closed\n");
  }

/* Otherwise, we need to open the file or database - each search type has its
own code, which is now split off into separately compiled modules. Before doing
this, if the search type is one that uses real files, check on the number that
we are holding open in the cache. If the limit is reached, close the least
recently used one. */

if (lk->type == lookup_absfile && open_filecount >= lookup_open_max)
  {
  if (open_bot == NULL)
    log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find "
      "one to close");
  else
    {
    search_cache *c = (search_cache *)(open_bot->data.ptr);
    DEBUG(D_lookup) debug_printf("Too many lookup files open\n  closing %s\n",
      open_bot->name);
    open_bot = c->up;
    if (open_bot != NULL)
      ((search_cache *)(open_bot->data.ptr))->down = NULL;
    else
      open_top = NULL;
    ((lookup_list[c->search_type])->close)(c->handle);
    c->handle = NULL;
    open_filecount--;
    }
  }

/* If opening is successful, call the file-checking function if there is one,
and if all is still well, enter the open database into the tree. */

handle = (lk->open)(filename, &search_error_message);
if (handle == NULL)
  {
  store_pool = old_pool;
  return NULL;
  }

if (lk->check != NULL &&
   !lk->check(handle, filename, modemask, owners, owngroups,
     &search_error_message))
  {
  lk->close(handle);
  store_pool = old_pool;
  return NULL;
  }

/* If this is a search type that uses real files, keep count. */

if (lk->type == lookup_absfile) open_filecount++;

/* If we found a previously opened entry in the tree, re-use it; otherwise
insert a new entry. On re-use, leave any cached lookup data and the lookup
count alone. */

if (t == NULL)
  {
  t = store_get(sizeof(tree_node) + Ustrlen(keybuffer));
  t->data.ptr = c = store_get(sizeof(search_cache));
  c->item_cache = NULL;
  Ustrcpy(t->name, keybuffer);
  tree_insertnode(&search_tree, t);
  }
else c = t->data.ptr;

c->handle = handle;
c->search_type = search_type;
c->up = c->down = NULL;

store_pool = old_pool;
return t;
}
Exemple #7
0
static uschar *
internal_search_find(void *handle, uschar *filename, uschar *keystring)
{
tree_node *t = (tree_node *)handle;
search_cache *c = (search_cache *)(t->data.ptr);
expiring_data *e;
uschar *data = NULL;
int search_type = t->name[0] - '0';
int old_pool = store_pool;

/* Lookups that return DEFER may not always set an error message. So that
the callers don't have to test for NULL, set an empty string. */

search_error_message = US"";
search_find_defer = FALSE;

DEBUG(D_lookup) debug_printf("internal_search_find: file=\"%s\"\n  "
  "type=%s key=\"%s\"\n", filename,
  lookup_list[search_type]->name, keystring);

/* Insurance. If the keystring is empty, just fail. */

if (keystring[0] == 0) return NULL;

/* Use the special store pool for search data */

store_pool = POOL_SEARCH;

/* Look up the data for the key, unless it is already in the cache for this
file. No need to check c->item_cache for NULL, tree_search will do so. */

if (  (t = tree_search(c->item_cache, keystring))
   && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
   )
  { /* Data was in the cache already; set the pointer from the tree node */
  data = e->ptr;
  DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
    keystring,
    filename ? US"\n  in " : US"", filename ? filename : US"");
  }
else
  {
  uint do_cache = UINT_MAX;
  int keylength = Ustrlen(keystring);

  DEBUG(D_lookup)
    {
    if (t) debug_printf("cached data found but past valid time; ");
    debug_printf("%s lookup required for %s%s%s\n",
      filename ? US"file" : US"database",
      keystring,
      filename ? US"\n  in " : US"", filename ? filename : US"");
    }

  /* Call the code for the different kinds of search. DEFER is handled
  like FAIL, except that search_find_defer is set so the caller can
  distinguish if necessary. */

  if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
      &data, &search_error_message, &do_cache) == DEFER)
    search_find_defer = TRUE;

  /* A record that has been found is now in data, which is either NULL
  or points to a bit of dynamic store. Cache the result of the lookup if
  caching is permitted. Lookups can disable caching, when they did something
  that changes their data. The mysql and pgsql lookups do this when an
  UPDATE/INSERT query was executed. */

  else if (do_cache)
    {
    int len = keylength + 1;

    if (t)	/* Previous, out-of-date cache entry.  Update with the */
      { 	/* new result and forget the old one */
      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
      e->ptr = data;
      }
    else
      {
      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len);
      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
      e->ptr = data;
      t = (tree_node *)(e+1);
      memcpy(t->name, keystring, len);
      t->data.ptr = e;
      tree_insertnode(&c->item_cache, t);
      }
    }

  /* If caching was disabled, empty the cache tree. We just set the cache
  pointer to NULL here, because we cannot release the store at this stage. */

  else
    {
    DEBUG(D_lookup) debug_printf("lookup forced cache cleanup\n");
    c->item_cache = NULL;
    }
  }

DEBUG(D_lookup)
  {
  if (data)
    debug_printf("lookup yielded: %s\n", data);
  else if (search_find_defer)
    debug_printf("lookup deferred: %s\n", search_error_message);
  else debug_printf("lookup failed\n");
  }

/* Return it in new dynamic store in the regular pool */

store_pool = old_pool;
return data ? string_copy(data) : NULL;
}