Formated by GeSHi
/* main.c */ /* * This code is public domain as declared by Sturm S. Mabie. */ #include <unistd.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/select.h> #include <netinet/in.h> #include <netdb.h> #include <fcntl.h> #include <arpa/inet.h> #include <getopt.h> #include <err.h> #include <db4.1/db_185.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* * Apparantly, HOST_NAME_MAX isn't defined on some systems */ #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 256 #endif /* * Currently, all commands are <10 characters */ #define CMD_SIZ 10 #define NICK_SIZ 64 #define MSG_SIZ 1024 #define NMAIL 64 #define MAIL_SIZ 512 #define NAME_SIZ 128 #define EMAIL_SIZ 64 #define DROP_SIZ 128 /* * Because using write() correctly is a bitch */ ssize_t writeall(int, const void *, size_t); void usage(); int handler(const char *, int); int handler_im(const char *, int); int handler_ison(const char *, int); int handler_isreg(const char *, int); int handler_mail(const char *, int); int handler_pass(const char *, int); int handler_pickup(const char *, int); int handler_pong(const char *, int); int handler_quit(const char *, int); int handler_register(const char *, int); int handler_servinfo(const char *, int); int handler_to(const char *, int); int handler_whois(const char *, int); int activedb_add(int, char *); int activedb_del(int); char *activedb_getnick(int); int activedb_getfd(char *); /* int regdb_add(char *, struct scmp_user *); */ /* * Each registered user of the system gets a scmp_user structure */ struct scmp_user { char nick[NICK_SIZ]; /* nick name or user name*/ char email[EMAIL_SIZ]; /* email address for the account */ char name[NAME_SIZ]; /* real name */ char mail[MAIL_SIZ][NMAIL]; /* the queued mail */ char drop[NICK_SIZ][DROP_SIZ]; /* a list of names that are dropped */ }; /* * This is an in memory only db that maps the current open fds to nicks. The * dbfdtonick db converts fds to nicks while the dbnicktofd db converts, * obviously, nicks to fds. These dbs should be in parallel, in that, they * should contain the same information, just with the key/values reversed. */ struct { DB *dbfdtonick; DB *dbnicktofd; } activedb; /* * When the command is encountered, a binary search is used to find it in * icmdtab */ struct input_cmd { const char *cmd; int (*fp)(const char *, int); } icmdtab[] = { { "IM" , handler_im }, { "ISON" , handler_ison }, { "ISREG" , handler_isreg }, { "MAIL" , handler_mail }, { "PASS" , handler_pass }, { "PICKUP" , handler_pickup }, { "PONG" , handler_pong }, { "QUIT" , handler_quit }, { "REGISTER" , handler_register }, { "SERVINFO" , handler_servinfo }, { "TO" , handler_to }, { "WHOIS" , handler_whois } }; const char servinfo_msg[] = "INFO scmpd version 0.1\n"; DB *regdb; int fdhwm; fd_set set, rset; int main(int argc, char *argv[]) { struct addrinfo hint, *infop; struct sockaddr_in *sa; int skfd, cskfd, fd, c; int fflg; char buf[MSG_SIZ], host[HOST_NAME_MAX], port[9], dbpath[PATH_MAX]; ssize_t nr; fflg = 0; (void)gethostname(host, sizeof(host)); (void)strcpy(port, "7777"); (void)strcpy(dbpath, "/var/lib/scmpd.db"); while ((c = getopt(argc, argv, "fd:i:p:")) != -1) { switch (c) { case 'd': (void)strncpy(dbpath, optarg, sizeof(dbpath)); break; case 'f': fflg = 1; break; case 'i': (void)strncpy(host, optarg, sizeof(host)); break; case 'p': (void)strncpy(port, optarg, sizeof(port)); break; default: usage(); break; } } argc -= optind; argv += optind; if (!fflg) { if (daemon(0, 0) == -1) err(1, "daemon()"); } fdhwm = 0; infop = NULL; (void)memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_INET; hint.ai_socktype = SOCK_STREAM; hint.ai_flags = AI_PASSIVE; if (getaddrinfo(host, port, &hint, &infop) != 0) err(1, "getaddrinfo()"); sa = (struct sockaddr_in *)infop->ai_addr; if ((skfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) err(1, "socket()"); if (bind(skfd, (struct sockaddr *)sa, sizeof(*sa)) == -1) err(1, NULL); if (listen(skfd, SOMAXCONN) == -1) err(1, "listen()"); /* initialize dbs */ if ((activedb.dbfdtonick = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL) err(1, "dbopen()"); if ((activedb.dbnicktofd = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL) err(1, "dbopen()"); if ((regdb = dbopen(dbpath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, DB_HASH, NULL)) == NULL) err(1, "dbopen()"); if (skfd > fdhwm) fdhwm = skfd; FD_ZERO(&set); FD_SET(skfd, &set); loop: rset = set; if (select(fdhwm + 1, &rset, NULL, NULL, NULL) == -1) err(1, "select()"); for (fd = 0; fd <= fdhwm; fd++) { if (FD_ISSET(fd, &rset)) { if (fd == skfd) { if ((cskfd = accept(skfd, NULL, 0)) == -1) err(1, "accept()"); FD_SET(cskfd, &set); if (cskfd > fdhwm) fdhwm = cskfd; } else { if ((nr = read(fd, buf, sizeof(buf))) == -1) err(1, "read()"); if (nr == 0) (void)activedb_del(fd); else { buf[nr] = '\0'; (void)handler(buf, fd); } } } } goto loop; freeaddrinfo(infop); (void)activedb.dbfdtonick->close(activedb.dbfdtonick); (void)activedb.dbnicktofd->close(activedb.dbnicktofd); (void)close(skfd); (void)close(cskfd); return 0; } void usage() { (void)fprintf(stderr, "usage: scmpd [-f] [-d database] [-i address] [-p port] \n"); exit(1); } int handler(const char *s, int fd) { char buf[CMD_SIZ]; int in, c, j; int l, h, m, cmp; in = j = l = 0; h = sizeof(icmdtab) / sizeof(*icmdtab) - 1; for (c = 0; s[c] != '\0'; c++) { if (j > CMD_SIZ) return -1; if (isspace(s[c])) { if (in) break; } else { if (!in) in = 1; buf[j++] = s[c]; } } buf[j] = '\0'; while (l <= h) { m = (l + h) / 2; cmp = strcmp(buf, icmdtab[m].cmd); if (cmp < 0) h = m - 1; else if (cmp > 0) l = m + 1; else break; } if (l > h) return -1; (void)icmdtab[m].fp(s + c + 1, fd); return 0; } int handler_im(const char *s, int fd) { char buf[NICK_SIZ]; char sbuf[MSG_SIZ]; int in, j, c; ssize_t nw; in = j = 0; for (c = 0; s[c] != '\0'; c++) { if (j > NICK_SIZ) return -1; if (isspace(s[c])) { if (in) break; } else { if (!in) in = 1; buf[j++] = s[c]; } } buf[j] = '\0'; if (activedb_getfd(buf) != -1) { char tmp[] = "DENIED This user name is already in use\n"; if ((nw = writeall(fd, tmp, sizeof(tmp) - 1)) == -1 || nw == 0) return -1; return 0; } (void)activedb_add(fd, buf); (void)snprintf(sbuf, MSG_SIZ, "HELLO %s\n", buf); if ((nw = writeall(fd, sbuf, strlen(sbuf))) == -1 || nw == 0) return -1; return 0; } int handler_ison(const char *s, int fd) { char buf[NICK_SIZ]; int c, j, in; ssize_t nw; j = in = 0; for (c = 0; s[c] != '\0'; c++) { if (j > NICK_SIZ) return -1; if (isspace(s[c])) { if (in) break; } else { if (!in) in = 1; buf[j++] = s[c]; } } buf[j] = '\0'; if (activedb_getfd(buf) == -1) { if ((nw = writeall(fd, "NO\n", 3)) == -1 || nw == 0) return -1; } else { if ((nw = writeall(fd, "YES\n", 4)) == -1 || nw == 0) return -1; } return 0; } int handler_isreg(const char *s, int fd) { } int handler_mail(const char *s, int fd) { } int handler_pass(const char *s, int fd) { } int handler_pickup(const char *s, int fd) { } int handler_pong(const char *s, int fd) { } int handler_quit(const char *s, int fd) { ssize_t nw; if ((nw = writeall(fd, "BYE\n", 4)) == -1 || nw == 0) return -1; return activedb_del(fd); } int handler_register(const char *s, int fd) { } /* args not used */ int handler_servinfo(const char *s, int fd) { ssize_t nw; if ((nw = writeall(fd, servinfo_msg, sizeof(servinfo_msg) - 1)) == -1 || nw == 0) return -1; return 0; } int handler_to(const char *s, int fd) { char buf[NICK_SIZ]; char sbuf[MSG_SIZ]; char *name; int c, j, in, rfd; ssize_t nw; j = in = 0; for (c = 0; s[c] != '\0'; c++) { if (j > NICK_SIZ) return -1; if (isspace(s[c])) { if (in) break; } else { if (!in) in = 1; buf[j++] = s[c]; } } buf[j] = '\0'; if ((name = activedb_getnick(fd)) == NULL) return -1; (void)snprintf(sbuf, MSG_SIZ, "FROM %s %s", name, s + c + 1); if ((rfd = activedb_getfd(buf)) == -1) return -1; if ((nw = writeall(rfd, sbuf, strlen(sbuf))) == -1 || nw == 0) return -1; if ((nw = writeall(fd, "SENT\n", 5)) == -1 || nw == 0) return -1; free(name); return 0; } int handler_whois(const char *s, int fd) { } ssize_t writeall(int fd, const void *buf, size_t size) { ssize_t nw, tmp; nw = 0; do { if ((tmp = write(fd, buf + nw, size - nw)) == -1) return -1; else if (tmp == 0) return nw; } while ((nw += tmp) < size); return nw; } int activedb_add(int fd, char *s) { DBT dbtfd, dbts; dbtfd.data = &fd; dbtfd.size = sizeof(int); dbts.data = s; dbts.size = strlen(s) + 1; if (activedb.dbfdtonick->put(activedb.dbfdtonick, &dbtfd, &dbts, 0) == -1) err(1, "DB->put()"); if (activedb.dbnicktofd->put(activedb.dbnicktofd, &dbts, &dbtfd, 0) == -1) err(1, "DB->put()"); return 0; } /* * Caller must free() */ char * activedb_getnick(int fd) { DBT ret, dbtfd; char *sret; dbtfd.data = &fd; dbtfd.size = sizeof(int); if (activedb.dbfdtonick->get(activedb.dbfdtonick, &dbtfd, &ret, 0) == 1) return NULL; if ((sret = strdup(ret.data)) == NULL) err(1, "strdup()"); return sret; } int activedb_getfd(char *s) { DBT ret, dbts; dbts.data = s; dbts.size = strlen(s) + 1; if (activedb.dbnicktofd->get(activedb.dbnicktofd, &dbts, &ret, 0) == 1) return -1; return *((int *)ret.data); } int activedb_del(int fd) { DBT dbtfd, dbts; char *s; if ((s = activedb_getnick(fd)) == NULL) return -1; dbtfd.data = &fd; dbtfd.size = sizeof(int); dbts.data = s; dbts.size = strlen(s) + 1; if (activedb.dbnicktofd->del(activedb.dbnicktofd, &dbts, 0) == -1) return -1; if (activedb.dbfdtonick->del(activedb.dbfdtonick, &dbtfd, 0) == -1) return -1; FD_CLR(fd, &set); if (fd == fdhwm) fdhwm--; if (close(fd) == -1) err(1, "close()"); free(s); return 0; } Parsed in 0.243325 seconds
| :: Download | ||||
| :: Print into | ||||
:: Make Diff
:: Erase Post