implement mail dest cache usage
Signed-off-by: AGentooCat <agentoocat@mail.i2p>
This commit is contained in:
79
src/mail.c
79
src/mail.c
@ -109,6 +109,7 @@ sqlite3_stmt *cached_queue = NULL;
|
||||
sqlite3_stmt *cached_pick_1 = NULL;
|
||||
sqlite3_stmt *cached_pick_2 = NULL;
|
||||
sqlite3_stmt *cached_pick_3 = NULL;
|
||||
sqlite3_stmt *cached_gethost = NULL;
|
||||
sqlite3_stmt *cached_hostaddr = NULL;
|
||||
sqlite3_stmt *cached_failsend = NULL;
|
||||
sqlite3_stmt *cached_notefail = NULL;
|
||||
@ -173,6 +174,12 @@ void opendb(const char *filename) {
|
||||
ret = sqlite3_prepare_v3(conn, "INSERT INTO mail_lines (msgid,line) VALUES (:msgid,:line)", -1, SQLITE_PREPARE_PERSISTENT, &cached_line, NULL);
|
||||
if (ret == SQLITE_OK)
|
||||
ret = sqlite3_prepare_v3(conn, "INSERT INTO send_queue (msgid,addr) VALUES (:msgid,:addr)", -1, SQLITE_PREPARE_PERSISTENT, &cached_queue, NULL);
|
||||
if (ret == SQLITE_OK)
|
||||
ret = sqlite3_prepare_v3(conn,
|
||||
"SELECT addr,ttl,priority,weight,is_i2p,last_used FROM mail_dests "
|
||||
"WHERE host = ? "
|
||||
"AND (last_used == -1 OR ttl == -1 OR last_used + ttl > unixepoch()) "
|
||||
"ORDER BY priority ASC, weight DESC", -1, SQLITE_PREPARE_PERSISTENT, &cached_gethost, NULL);
|
||||
if (ret == SQLITE_OK)
|
||||
ret = sqlite3_prepare_v3(conn,
|
||||
"SELECT msgid FROM send_queue "
|
||||
@ -270,6 +277,7 @@ void closedb() {
|
||||
sqlite3_finalize(cached_failsend);
|
||||
sqlite3_finalize(cached_notefail);
|
||||
sqlite3_finalize(cached_hostaddr);
|
||||
sqlite3_finalize(cached_gethost);
|
||||
sqlite3_finalize(cached_pick_3);
|
||||
sqlite3_finalize(cached_pick_2);
|
||||
sqlite3_finalize(cached_pick_1);
|
||||
@ -281,6 +289,61 @@ void closedb() {
|
||||
conn = NULL;
|
||||
}
|
||||
|
||||
#define CLEARSQL(x) { \
|
||||
sqlite3_reset(x); \
|
||||
sqlite3_clear_bindings(x); \
|
||||
}
|
||||
#define CHKSQL(x) while ((ret = x) != SQLITE_OK) { if (ret == SQLITE_DONE) break; if (ret == SQLITE_BUSY) continue; err = (char*)sqlite3_errstr(ret); goto RETPATH; }
|
||||
#define BINDSTR(x, y, z) CHKSQL(sqlite3_bind_text(x, y, z, -1, SQLITE_STATIC))
|
||||
|
||||
int get_cached_mail_hosts(char *host, struct I2Host *addrs) {
|
||||
int ret;
|
||||
char *err, *mail_addr;
|
||||
#define RETPATH cachedhostfail
|
||||
BINDSTR(cached_gethost, 1, host);
|
||||
addrs->mailsrvl = 0;
|
||||
while ((ret = sqlite3_step(cached_gethost)) == SQLITE_ROW)
|
||||
addrs->mailsrvl++;
|
||||
if (ret != SQLITE_DONE)
|
||||
goto cachedhostfail;
|
||||
if (addrs->mailsrvl == 0) {
|
||||
CLEARSQL(cached_gethost);
|
||||
return 0;
|
||||
}
|
||||
sqlite3_reset(cached_gethost);
|
||||
if (!(addrs->mailsrv = malloc(addrs->mailsrvl * sizeof(struct SMTPAddr)))) {
|
||||
ret = SQLITE_NOMEM;
|
||||
goto cachedhostfail;
|
||||
}
|
||||
memset(addrs->mailsrv, 0, addrs->mailsrvl * sizeof(struct SMTPAddr));
|
||||
addrs->mailsrvl = 0;
|
||||
while ((ret = sqlite3_step(cached_gethost)) == SQLITE_ROW) {
|
||||
if (!(mail_addr = strdup(sqlite3_column_text(cached_gethost, 0)))) {
|
||||
ret = SQLITE_NOMEM;
|
||||
goto cachedhostfail;
|
||||
}
|
||||
addrs->mailsrv[addrs->mailsrvl].addr = mail_addr;
|
||||
addrs->mailsrv[addrs->mailsrvl].ttl = sqlite3_column_int(cached_gethost, 1);
|
||||
addrs->mailsrv[addrs->mailsrvl].priority = sqlite3_column_int(cached_gethost, 2);
|
||||
addrs->mailsrv[addrs->mailsrvl].weight = sqlite3_column_int(cached_gethost, 3);
|
||||
addrs->mailsrv[addrs->mailsrvl].is_i2p = sqlite3_column_int(cached_gethost, 4);
|
||||
addrs->mailsrvl++;
|
||||
}
|
||||
|
||||
CLEARSQL(cached_gethost);
|
||||
return 1;
|
||||
cachedhostfail:
|
||||
CLEARSQL(cached_gethost);
|
||||
if (addrs->mailsrv) {
|
||||
for (long i = 0; i < addrs->mailsrvl; i++)
|
||||
xfree(addrs->mailsrv[i].addr);
|
||||
free(addrs->mailsrv);
|
||||
}
|
||||
addrs->mailsrvl = 0;
|
||||
return -ret;
|
||||
#undef RETPATH
|
||||
}
|
||||
|
||||
int commit_mail(int is_incoming, struct Mail *mail, char *buf, char **tos, long tlen) {
|
||||
// the mail must have "From", "To" and "Subject" fields
|
||||
// if "Message-Id" is not given then we generate one
|
||||
@ -319,10 +382,6 @@ int commit_mail(int is_incoming, struct Mail *mail, char *buf, char **tos, long
|
||||
// it's commiting time
|
||||
char *err = NULL;
|
||||
int ret = sqlite3_exec(conn, "BEGIN TRANSACTION", NULL, NULL, &err);
|
||||
#define CLEARSQL(x) { \
|
||||
sqlite3_reset(x); \
|
||||
sqlite3_clear_bindings(x); \
|
||||
}
|
||||
if (ret != SQLITE_OK) {
|
||||
incommitfail:
|
||||
if (mid_alloc)
|
||||
@ -337,9 +396,6 @@ incommitfail:
|
||||
}
|
||||
#define RETPATH incommitfail
|
||||
|
||||
#define CHKSQL(x) while ((ret = x) != SQLITE_OK) { if (ret == SQLITE_DONE) break; if (ret == SQLITE_BUSY) continue; err = (char*)sqlite3_errstr(ret); goto RETPATH; }
|
||||
#define BINDSTR(x, y, z) CHKSQL(sqlite3_bind_text(x, y, z, -1, SQLITE_STATIC))
|
||||
|
||||
int idx[] = {
|
||||
sqlite3_bind_parameter_index(cached_mail, ":from"),
|
||||
sqlite3_bind_parameter_index(cached_mail, ":to"),
|
||||
@ -605,6 +661,7 @@ int sendmsgid_tohost(struct I2Host *host, struct Mail *thand, char **err) {
|
||||
long llen = 0;
|
||||
|
||||
char *serv32 = NULL;
|
||||
restart_sendhost:
|
||||
for (long i = 0; i < host->mailsrvl; i++) {
|
||||
if ((cfd = conn2host(host->mailsrv[i].addr, &conerr)) > -1) {
|
||||
serv32 = host->mailsrv[i].addr;
|
||||
@ -614,6 +671,10 @@ int sendmsgid_tohost(struct I2Host *host, struct Mail *thand, char **err) {
|
||||
xfree(conerr);
|
||||
}
|
||||
if (cfd < 0) {
|
||||
if (host->from_cache) {
|
||||
refresh_hosts(host);
|
||||
goto restart_sendhost;
|
||||
}
|
||||
asprintf(err, "SAM returned: %s", conerr);
|
||||
xfree(conerr);
|
||||
return -1;
|
||||
@ -976,12 +1037,12 @@ mailsendfail:
|
||||
}
|
||||
|
||||
if (idx == -1) {
|
||||
if (!(tos[tol] = lookup_host(dest, NULL))) {
|
||||
if (!(tos[tol] = lookup_host(dest, NULL, 0))) {
|
||||
for (long i = 0; i < tol; i++)
|
||||
free_lookup(tos[i]);
|
||||
free(tos);
|
||||
ret = SQLITE_OK;
|
||||
err = "failed to find a destination host online";
|
||||
err = "failed to find a destination host";
|
||||
goto mailsendfail;
|
||||
}
|
||||
*(dest - 1) = 0;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define MAIL_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
struct I2Host; // to prevent undeclared structs around this, smtp.h and sam.h
|
||||
|
||||
struct Header {
|
||||
long alen;
|
||||
@ -32,6 +33,7 @@ struct SizedMsgid {
|
||||
int deleted;
|
||||
};
|
||||
|
||||
int get_cached_mail_hosts(char *host, struct I2Host *addrs);
|
||||
int parse_save_header(struct Mail *mail, long len, char *buf);
|
||||
void freemail(struct Mail *mail);
|
||||
|
||||
|
25
src/sam.c
25
src/sam.c
@ -624,7 +624,17 @@ skiphostnote:
|
||||
commit_hostaddrs(host);
|
||||
}
|
||||
|
||||
struct I2Host *lookup_host(char *b32addr, char *knownas) {
|
||||
void refresh_hosts(struct I2Host *host) {
|
||||
if (host->mailsrv) {
|
||||
for (long i = 0; i < host->mailsrvl; i++)
|
||||
xfree(host->mailsrv[i].addr);
|
||||
free(host->mailsrv);
|
||||
}
|
||||
host->mailsrvl = host->from_cache = 0;
|
||||
lookup_mail(host);
|
||||
}
|
||||
|
||||
struct I2Host *lookup_host(char *b32addr, char *knownas, int force_lookup) {
|
||||
if ((b32addr && knownas) || !(b32addr || knownas))
|
||||
log(CRIT, "[BUG] both b32addr+knownas provided or omitted");
|
||||
while (ctlsock == -1)
|
||||
@ -633,7 +643,17 @@ struct I2Host *lookup_host(char *b32addr, char *knownas) {
|
||||
struct I2Host *host = malloc(sizeof(struct I2Host));
|
||||
if (!host) goto samlookfail;
|
||||
memset(host, 0, sizeof(*host));
|
||||
if (b32addr && !(host->b32addr = strdup(b32addr))) goto samlookfail;
|
||||
|
||||
if (!force_lookup && b32addr) {
|
||||
int cachret = get_cached_mail_hosts(b32addr, host);
|
||||
if (cachret > 0) {
|
||||
host->from_cache = 1;
|
||||
return host;
|
||||
}
|
||||
if (cachret < 0)
|
||||
log(WARN, "failed to get cached mail dests: %d/%s", -cachret, sqlite3_errstr(-cachret));
|
||||
}
|
||||
if (!(host->_under = samcomm(ctlsock, "NAMING", "LOOKUP", "NAME", b32addr ? b32addr : knownas, "OPTIONS", "true", NULL)))
|
||||
goto samlookfail;
|
||||
|
||||
@ -641,7 +661,6 @@ struct I2Host *lookup_host(char *b32addr, char *knownas) {
|
||||
|
||||
if (!host->_under->success) goto samlookfail;
|
||||
host->b64dest = get_samval(host->_under, "VALUE");
|
||||
if (!(host->b32addr = b64to32(host->b64dest))) goto samlookfail;
|
||||
lookup_mail(host);
|
||||
|
||||
return host;
|
||||
@ -709,7 +728,7 @@ void opensam(port_t port, char *me, char *dest) {
|
||||
log(CRIT, "SAM failed to create session tunnels: %s", get_samval(sesreply, "MESSAGE") ? get_samval(sesreply, "MESSAGE") : get_samval(sesreply, "RESULT"));
|
||||
free_sammsg(sesreply);
|
||||
|
||||
mehost = lookup_host(NULL, me);
|
||||
mehost = lookup_host(NULL, me, 1);
|
||||
if (!mehost)
|
||||
log(WARN, "configured hostname \"%s\" couldn't be looked up", me);
|
||||
else if (!mehost->mailsrvl)
|
||||
|
@ -12,7 +12,7 @@ struct I2Host {
|
||||
char *knownas;
|
||||
struct SMTPAddr *mailsrv;
|
||||
long mailsrvl;
|
||||
int is_self, is_failed;
|
||||
int is_self, is_failed, from_cache;
|
||||
|
||||
struct SAMMessage *_under;
|
||||
|
||||
@ -25,7 +25,8 @@ extern struct I2Host *mehost;
|
||||
extern struct linepoll_t *sam_sockpoll;
|
||||
|
||||
char *b64to32(char *dest);
|
||||
struct I2Host *lookup_host(char *b32addr, char *knownas);
|
||||
void refresh_hosts(struct I2Host *host);
|
||||
struct I2Host *lookup_host(char *b32addr, char *knownas, int force_lookup);
|
||||
void free_lookup(struct I2Host *host);
|
||||
int is_host_known(char *hostname);
|
||||
int conn2host(char *b32host, char **err);
|
||||
|
15
src/smtp.c
15
src/smtp.c
@ -394,9 +394,15 @@ int smtp_line(struct lineconn_t *hand) {
|
||||
goto smtplinefail;
|
||||
char *b32peer = b64to32(hand->edata);
|
||||
if (!b32peer) goto smtplinefail;
|
||||
struct I2Host *host = lookup_host(NULL, hostname);
|
||||
int host_good = 1;
|
||||
int force_lookup = 0;
|
||||
restart_lookup:
|
||||
int host_good = 1, found = 0;
|
||||
struct I2Host *host = lookup_host(NULL, hostname, force_lookup);
|
||||
if (!host || host->mailsrvl == 0) {
|
||||
if (host && host->mailsrvl == 0 && host->from_cache) {
|
||||
force_lookup = 1;
|
||||
goto restart_lookup;
|
||||
}
|
||||
host_good = 0;
|
||||
// run
|
||||
if (!gloconf->allow_unverified_hosts) {
|
||||
@ -405,13 +411,16 @@ int smtp_line(struct lineconn_t *hand) {
|
||||
goto smtplinefail;
|
||||
}
|
||||
}
|
||||
int found = 0;
|
||||
for (long i = 0; i < host->mailsrvl; i++) {
|
||||
if (!strcmp(b32peer, host->mailsrv[i].addr)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (host->from_cache && !found) {
|
||||
force_lookup = 1;
|
||||
goto restart_lookup;
|
||||
}
|
||||
|
||||
*(hostname - 1) = 0;
|
||||
if (!strcmp(com->argv[0], "itoomail-system")) {
|
||||
|
Reference in New Issue
Block a user