1 /* $OpenBSD: queue_ram.c,v 1.6 2014/07/08 15:45:32 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/tree.h> 22 #include <sys/socket.h> 23 #include <sys/stat.h> 24 25 #include <ctype.h> 26 #include <err.h> 27 #include <errno.h> 28 #include <event.h> 29 #include <fcntl.h> 30 #include <imsg.h> 31 #include <inttypes.h> 32 #include <libgen.h> 33 #include <pwd.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <time.h> 38 #include <unistd.h> 39 40 #include "smtpd.h" 41 #include "log.h" 42 43 struct qr_envelope { 44 char *buf; 45 size_t len; 46 }; 47 48 struct qr_message { 49 char *buf; 50 size_t len; 51 struct tree envelopes; 52 }; 53 54 static struct tree messages; 55 56 static struct qr_message * 57 get_message(uint32_t msgid) 58 { 59 struct qr_message *msg; 60 61 msg = tree_get(&messages, msgid); 62 if (msg == NULL) 63 log_warn("warn: queue-ram: message not found"); 64 65 return (msg); 66 } 67 68 static int 69 queue_ram_message_create(uint32_t *msgid) 70 { 71 struct qr_message *msg; 72 73 msg = calloc(1, sizeof(*msg)); 74 if (msg == NULL) { 75 log_warn("warn: queue-ram: calloc"); 76 return (0); 77 } 78 tree_init(&msg->envelopes); 79 80 do { 81 *msgid = queue_generate_msgid(); 82 } while (tree_check(&messages, *msgid)); 83 84 tree_xset(&messages, *msgid, msg); 85 86 return (1); 87 } 88 89 static int 90 queue_ram_message_commit(uint32_t msgid, const char *path) 91 { 92 struct qr_message *msg; 93 struct stat sb; 94 size_t n; 95 FILE *f; 96 int ret; 97 98 if ((msg = tree_get(&messages, msgid)) == NULL) { 99 log_warnx("warn: queue-ram: msgid not found"); 100 return (0); 101 } 102 103 f = fopen(path, "rb"); 104 if (f == NULL) { 105 log_warn("warn: queue-ram: fopen: %s", path); 106 return (0); 107 } 108 if (fstat(fileno(f), &sb) == -1) { 109 log_warn("warn: queue-ram: fstat"); 110 fclose(f); 111 return (0); 112 } 113 114 msg->len = sb.st_size; 115 msg->buf = malloc(msg->len); 116 if (msg->buf == NULL) { 117 log_warn("warn: queue-ram: malloc"); 118 fclose(f); 119 return (0); 120 } 121 122 ret = 0; 123 n = fread(msg->buf, 1, msg->len, f); 124 if (ferror(f)) 125 log_warn("warn: queue-ram: fread"); 126 else if ((off_t)n != sb.st_size) 127 log_warnx("warn: queue-ram: bad read"); 128 else { 129 ret = 1; 130 stat_increment("queue.ram.message.size", msg->len); 131 } 132 fclose(f); 133 134 return (ret); 135 } 136 137 static int 138 queue_ram_message_delete(uint32_t msgid) 139 { 140 struct qr_message *msg; 141 struct qr_envelope *evp; 142 uint64_t evpid; 143 144 if ((msg = tree_pop(&messages, msgid)) == NULL) { 145 log_warnx("warn: queue-ram: not found"); 146 return (0); 147 } 148 while (tree_poproot(&messages, &evpid, (void**)&evp)) { 149 stat_decrement("queue.ram.envelope.size", evp->len); 150 free(evp->buf); 151 free(evp); 152 } 153 stat_decrement("queue.ram.message.size", msg->len); 154 free(msg->buf); 155 free(msg); 156 return (0); 157 } 158 159 static int 160 queue_ram_message_fd_r(uint32_t msgid) 161 { 162 struct qr_message *msg; 163 size_t n; 164 FILE *f; 165 int fd, fd2; 166 167 if ((msg = tree_get(&messages, msgid)) == NULL) { 168 log_warnx("warn: queue-ram: not found"); 169 return (-1); 170 } 171 172 fd = mktmpfile(); 173 if (fd == -1) { 174 log_warn("warn: queue-ram: mktmpfile"); 175 return (-1); 176 } 177 178 fd2 = dup(fd); 179 if (fd2 == -1) { 180 log_warn("warn: queue-ram: dup"); 181 close(fd); 182 return (-1); 183 } 184 f = fdopen(fd2, "w"); 185 if (f == NULL) { 186 log_warn("warn: queue-ram: fdopen"); 187 close(fd); 188 close(fd2); 189 return (-1); 190 } 191 n = fwrite(msg->buf, 1, msg->len, f); 192 if (n != msg->len) { 193 log_warn("warn: queue-ram: write"); 194 close(fd); 195 fclose(f); 196 return (-1); 197 } 198 fclose(f); 199 lseek(fd, 0, SEEK_SET); 200 return (fd); 201 } 202 203 static int 204 queue_ram_message_corrupt(uint32_t msgid) 205 { 206 return (queue_ram_message_delete(msgid)); 207 } 208 209 static int 210 queue_ram_envelope_create(uint32_t msgid, const char *buf, size_t len, 211 uint64_t *evpid) 212 { 213 struct qr_envelope *evp; 214 struct qr_message *msg; 215 216 if ((msg = get_message(msgid)) == NULL) 217 return (0); 218 219 do { 220 *evpid = queue_generate_evpid(msgid); 221 } while (tree_check(&msg->envelopes, *evpid)); 222 evp = calloc(1, sizeof *evp); 223 if (evp == NULL) { 224 log_warn("warn: queue-ram: calloc"); 225 return (0); 226 } 227 evp->len = len; 228 evp->buf = malloc(len); 229 if (evp->buf == NULL) { 230 log_warn("warn: queue-ram: malloc"); 231 free(evp); 232 return (0); 233 } 234 memmove(evp->buf, buf, len); 235 tree_xset(&msg->envelopes, *evpid, evp); 236 stat_increment("queue.ram.envelope.size", len); 237 return (1); 238 } 239 240 static int 241 queue_ram_envelope_delete(uint64_t evpid) 242 { 243 struct qr_envelope *evp; 244 struct qr_message *msg; 245 246 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 247 return (0); 248 249 if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) { 250 log_warnx("warn: queue-ram: not found"); 251 return (0); 252 } 253 stat_decrement("queue.ram.envelope.size", evp->len); 254 free(evp->buf); 255 free(evp); 256 if (tree_empty(&msg->envelopes)) { 257 tree_xpop(&messages, evpid_to_msgid(evpid)); 258 stat_decrement("queue.ram.message.size", msg->len); 259 free(msg->buf); 260 free(msg); 261 } 262 return (1); 263 } 264 265 static int 266 queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len) 267 { 268 struct qr_envelope *evp; 269 struct qr_message *msg; 270 void *tmp; 271 272 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 273 return (0); 274 275 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 276 log_warn("warn: queue-ram: not found"); 277 return (0); 278 } 279 tmp = malloc(len); 280 if (tmp == NULL) { 281 log_warn("warn: queue-ram: malloc"); 282 return (0); 283 } 284 memmove(tmp, buf, len); 285 free(evp->buf); 286 evp->len = len; 287 evp->buf = tmp; 288 stat_decrement("queue.ram.envelope.size", evp->len); 289 stat_increment("queue.ram.envelope.size", len); 290 return (1); 291 } 292 293 static int 294 queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len) 295 { 296 struct qr_envelope *evp; 297 struct qr_message *msg; 298 299 if ((msg = get_message(evpid_to_msgid(evpid))) == NULL) 300 return (0); 301 302 if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) { 303 log_warn("warn: queue-ram: not found"); 304 return (0); 305 } 306 if (len < evp->len) { 307 log_warnx("warn: queue-ram: buffer too small"); 308 return (0); 309 } 310 memmove(buf, evp->buf, evp->len); 311 return (evp->len); 312 } 313 314 static int 315 queue_ram_envelope_walk(uint64_t *evpid, char *buf, size_t len) 316 { 317 return (-1); 318 } 319 320 static int 321 queue_ram_init(struct passwd *pw, int server, const char * conf) 322 { 323 tree_init(&messages); 324 325 queue_api_on_message_create(queue_ram_message_create); 326 queue_api_on_message_commit(queue_ram_message_commit); 327 queue_api_on_message_delete(queue_ram_message_delete); 328 queue_api_on_message_fd_r(queue_ram_message_fd_r); 329 queue_api_on_message_corrupt(queue_ram_message_corrupt); 330 queue_api_on_envelope_create(queue_ram_envelope_create); 331 queue_api_on_envelope_delete(queue_ram_envelope_delete); 332 queue_api_on_envelope_update(queue_ram_envelope_update); 333 queue_api_on_envelope_load(queue_ram_envelope_load); 334 queue_api_on_envelope_walk(queue_ram_envelope_walk); 335 336 return (1); 337 } 338 339 struct queue_backend queue_backend_ram = { 340 queue_ram_init, 341 }; 342