/* swebs - a simple web server Copyright (C) 2022 Nate Choe This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include static FILE *logs; int initLogging(char *path) { logs = fopen(path, "a"); return logs == NULL; } int smalloc(size_t size) { return shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); } void *saddr(int id) { void *addr; addr = shmat(id, NULL, 0); if (addr == (void *) -1) return NULL; return addr; } void sfree(void *addr) { shmdt(addr); } void sdestroy(int id) { shmctl(id, IPC_RMID, 0); } void *xmalloc(size_t size) { void *ret; ret = malloc(size); if (ret == NULL) { fputs("xmalloc() failed\n", stderr); exit(EXIT_FAILURE); } return ret; } void *xrealloc(void *ptr, size_t size) { void *ret; ret = realloc(ptr, size); if (ret == NULL) { fputs("xrealloc() failed\n", stderr); exit(EXIT_FAILURE); } return ret; } char *xstrdup(char *str) { char *ret; ret = strdup(str); if (ret == NULL) { fputs("xstrdup() failed\n", stderr); exit(EXIT_FAILURE); } return ret; } int createLog(char *msg) { time_t currenttime; struct tm *timeinfo; time(¤ttime); timeinfo = gmtime(¤ttime); if (timeinfo == NULL) return 1; fprintf(logs, "[%d-%02d-%02dT%02d:%02d:%02dZ] %s\n", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, msg); fflush(logs); return 0; } int createErrorLog(char *msg, int err) { time_t currenttime; struct tm *timeinfo; time(¤ttime); timeinfo = gmtime(¤ttime); if (timeinfo == NULL) return 1; fprintf(logs, "[%d-%02d-%02dT%02d:%02d:%02dZ] %s: %s\n", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, msg, strerror(err)); fflush(logs); return 0; } int createFormatLog(char *fmt, ...) { va_list ap; char *log; int code; va_start(ap, fmt); log = malloc(vsnprintf(NULL, 0, fmt, ap) + 1); va_end(ap); if (log == NULL) return 1; va_start(ap, fmt); vsprintf(log, fmt, ap); va_end(ap); code = createLog(log); return code; } int istrcmp(char *s1, char *s2) { int i; for (i = 0;; i++) { char c1 = tolower(s1[i]); char c2 = tolower(s2[i]); if (c1 != c2) return c1 - c2; if (c1 == '\0') return 0; } } RequestType getType(char *str) { if (strcmp(str, "GET") == 0) return GET; if (strcmp(str, "POST") == 0) return POST; if (strcmp(str, "PUT") == 0) return PUT; if (strcmp(str, "HEAD") == 0) return HEAD; if (strcmp(str, "DELETE") == 0) return DELETE; if (strcmp(str, "PATCH") == 0) return PATCH; if (strcmp(str, "OPTIONS") == 0) return OPTIONS; return INVALID; } void sendFd(int fd, int dest, void *data, size_t len) { struct msghdr msg; struct cmsghdr *cmsg; char iobuf[1]; struct iovec io; union { char buf[CMSG_SPACE(sizeof(fd))]; struct cmsghdr align; } u; memset(&msg, 0, sizeof(msg)); if (data == NULL) { io.iov_base = iobuf; io.iov_len = sizeof(iobuf); } else { io.iov_base = data; io.iov_len = len; } msg.msg_iov = &io; msg.msg_iovlen = 1; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); sendmsg(dest, &msg, 0); } int recvFd(int source, void *data, size_t len) { union { char buff[CMSG_SPACE(sizeof(int))]; struct cmsghdr align; } cmsghdr; struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; ssize_t nr; int ret; char buf[1]; msg.msg_name = NULL; msg.msg_namelen = 0; if (data == NULL) { data = buf; len = sizeof buf; } iov.iov_base = data; iov.iov_len = len; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsghdr.buff; msg.msg_controllen = sizeof(cmsghdr.buff); nr = recvmsg(source, &msg, 0); if (nr < 0) return -1; cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(len)) return -1; if (cmsg->cmsg_level != SOL_SOCKET) return -1; if (cmsg->cmsg_type != SCM_RIGHTS) return -1; memcpy(&ret, CMSG_DATA(cmsg), sizeof(ret)); return ret; } int createTmpName(char *path) { size_t len; char possibleChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; len = strlen(path); if (len < 5) return 1; for (;;) { int i; for (i = 0; i < 5; i++) path[len - i - 1] = possibleChars[rand() % sizeof(possibleChars)]; if (!faccessat(-1, path, F_OK, AT_EACCESS)) continue; if (faccessat(-1, path, R_OK | W_OK, AT_EACCESS)) return 1; return 0; } } void setsignal(int signal, void (*handler)(int)) { struct sigaction action; sigset_t sigset; sigemptyset(&sigset); action.sa_handler = handler; action.sa_mask = sigset; action.sa_flags = 0; sigaction(signal, &action, NULL); } void unsetsignal(int signal) { struct sigaction action; sigset_t sigset; sigemptyset(&sigset); action.sa_handler = SIG_DFL; action.sa_mask = sigset; action.sa_flags = SA_NODEFER; sigaction(signal, &action, NULL); }