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