1 /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "ioloop.h"
5 #include "hash.h"
6 #include "llist.h"
7 #include "global-memory.h"
8 #include "stats-settings.h"
9 #include "mail-stats.h"
10 #include "mail-ip.h"
11
12 static HASH_TABLE(struct ip_addr *, struct mail_ip *) mail_ips_hash;
13 /* ips are sorted by their last_update timestamp, oldest first */
14 static struct mail_ip *mail_ips_head, *mail_ips_tail;
15 struct mail_ip *stable_mail_ips;
16
mail_ip_memsize(const struct mail_ip * ip)17 static size_t mail_ip_memsize(const struct mail_ip *ip)
18 {
19 return sizeof(*ip);
20 }
21
mail_ip_login(const struct ip_addr * ip_addr)22 struct mail_ip *mail_ip_login(const struct ip_addr *ip_addr)
23 {
24 struct mail_ip *ip;
25
26 ip = hash_table_lookup(mail_ips_hash, ip_addr);
27 if (ip != NULL) {
28 ip->num_logins++;
29 ip->num_connected_sessions++;
30 mail_ip_refresh(ip, NULL);
31 return ip;
32 }
33
34 ip = i_malloc(MALLOC_ADD(sizeof(struct mail_ip), stats_alloc_size()));
35 ip->stats = (void *)(ip + 1);
36 ip->ip = *ip_addr;
37 ip->reset_timestamp = ioloop_time;
38
39 hash_table_insert(mail_ips_hash, &ip->ip, ip);
40 DLLIST_PREPEND_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
41 DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
42 sorted_prev, sorted_next);
43 ip->num_logins++;
44 ip->num_connected_sessions++;
45 ip->last_update = ioloop_timeval;
46 global_memory_alloc(mail_ip_memsize(ip));
47 return ip;
48 }
49
mail_ip_disconnected(struct mail_ip * ip)50 void mail_ip_disconnected(struct mail_ip *ip)
51 {
52 i_assert(ip->num_connected_sessions > 0);
53 ip->num_connected_sessions--;
54 }
55
mail_ip_lookup(const struct ip_addr * ip_addr)56 struct mail_ip *mail_ip_lookup(const struct ip_addr *ip_addr)
57 {
58 return hash_table_lookup(mail_ips_hash, ip_addr);
59 }
60
mail_ip_ref(struct mail_ip * ip)61 void mail_ip_ref(struct mail_ip *ip)
62 {
63 ip->refcount++;
64 }
65
mail_ip_unref(struct mail_ip ** _ip)66 void mail_ip_unref(struct mail_ip **_ip)
67 {
68 struct mail_ip *ip = *_ip;
69
70 i_assert(ip->refcount > 0);
71 ip->refcount--;
72
73 *_ip = NULL;
74 }
75
mail_ip_free(struct mail_ip * ip)76 static void mail_ip_free(struct mail_ip *ip)
77 {
78 i_assert(ip->refcount == 0);
79 i_assert(ip->sessions == NULL);
80
81 global_memory_free(mail_ip_memsize(ip));
82 hash_table_remove(mail_ips_hash, &ip->ip);
83 DLLIST_REMOVE_FULL(&stable_mail_ips, ip, stable_prev, stable_next);
84 DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
85 sorted_prev, sorted_next);
86
87 i_free(ip);
88 }
89
mail_ip_refresh(struct mail_ip * ip,const struct stats * diff_stats)90 void mail_ip_refresh(struct mail_ip *ip, const struct stats *diff_stats)
91 {
92 if (diff_stats != NULL)
93 stats_add(ip->stats, diff_stats);
94 ip->last_update = ioloop_timeval;
95 DLLIST2_REMOVE_FULL(&mail_ips_head, &mail_ips_tail, ip,
96 sorted_prev, sorted_next);
97 DLLIST2_APPEND_FULL(&mail_ips_head, &mail_ips_tail, ip,
98 sorted_prev, sorted_next);
99 }
100
mail_ips_free_memory(void)101 void mail_ips_free_memory(void)
102 {
103 unsigned int diff;
104
105 while (mail_ips_head != NULL && mail_ips_head->refcount == 0) {
106 mail_ip_free(mail_ips_head);
107
108 if (global_used_memory < stats_settings->memory_limit ||
109 mail_ips_head == NULL)
110 break;
111
112 diff = ioloop_time - mail_ips_head->last_update.tv_sec;
113 if (diff < stats_settings->ip_min_time)
114 break;
115 }
116 }
117
mail_ips_init(void)118 void mail_ips_init(void)
119 {
120 hash_table_create(&mail_ips_hash, default_pool, 0,
121 net_ip_hash, net_ip_cmp);
122 }
123
mail_ips_deinit(void)124 void mail_ips_deinit(void)
125 {
126 while (mail_ips_head != NULL)
127 mail_ip_free(mail_ips_head);
128 hash_table_destroy(&mail_ips_hash);
129 }
130