Added global variables in sitefiles to allow for https support
This commit is contained in:
@@ -32,8 +32,8 @@
|
||||
#include <responses.h>
|
||||
#include <connections.h>
|
||||
|
||||
int newConnection(int fd, Connection *ret) {
|
||||
ret->fd = fd;
|
||||
int newConnection(Stream *stream, Connection *ret) {
|
||||
ret->stream = stream;
|
||||
ret->progress = RECEIVE_REQUEST;
|
||||
|
||||
ret->currLineAlloc = 30;
|
||||
@@ -66,7 +66,7 @@ void resetConnection(Connection *conn) {
|
||||
}
|
||||
|
||||
void freeConnection(Connection *conn) {
|
||||
shutdown(conn->fd, SHUT_RDWR);
|
||||
freeStream(conn->stream);
|
||||
free(conn->currLine);
|
||||
free(conn->path);
|
||||
free(conn->fields);
|
||||
@@ -198,7 +198,7 @@ static int processChar(Connection *conn, char c, Sitefile *site) {
|
||||
int updateConnection(Connection *conn, Sitefile *site) {
|
||||
char buff[300];
|
||||
for (;;) {
|
||||
ssize_t received = read(conn->fd, buff, sizeof(buff));
|
||||
ssize_t received = recvStream(conn->stream, buff, sizeof(buff));
|
||||
if (received < 0)
|
||||
return errno != EAGAIN;
|
||||
if (received == 0)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef _HAVE_CONNECTIONS
|
||||
#define _HAVE_CONNECTIONS
|
||||
#include <runner.h>
|
||||
#include <sockets.h>
|
||||
#include <sitefile.h>
|
||||
|
||||
typedef enum {
|
||||
@@ -33,7 +34,7 @@ typedef struct {
|
||||
} Field;
|
||||
|
||||
typedef struct Connection {
|
||||
int fd;
|
||||
Stream *stream;
|
||||
ConnectionSteps progress;
|
||||
|
||||
RequestType type;
|
||||
@@ -60,7 +61,7 @@ typedef struct Connection {
|
||||
//Ephemeral fields: Things which are freed and reallocated after each new
|
||||
//request, path, body
|
||||
|
||||
int newConnection(int fd, Connection *ret);
|
||||
int newConnection(Stream *stream, Connection *ret);
|
||||
//returns non-zero on error. creates a new connection bound to fd
|
||||
void resetConnection(Connection *conn);
|
||||
void freeConnection(Connection *conn);
|
||||
|
||||
@@ -36,8 +36,11 @@ typedef struct {
|
||||
typedef struct {
|
||||
int size;
|
||||
SiteCommand *content;
|
||||
SocketType type;
|
||||
char *key;
|
||||
char *cert;
|
||||
} Sitefile;
|
||||
|
||||
Sitefile *parseFile(char *path);
|
||||
Sitefile *parseSitefile(char *path);
|
||||
void freeSitefile(Sitefile *site);
|
||||
#endif
|
||||
|
||||
56
src/include/sockets.h
Normal file
56
src/include/sockets.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef _HAVE_SOCKETS
|
||||
#define _HAVE_SOCKETS
|
||||
#include <stddef.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
#include <util.h>
|
||||
|
||||
typedef struct {
|
||||
SocketType type;
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen;
|
||||
gnutls_certificate_credentials_t creds;
|
||||
gnutls_priority_t priority;
|
||||
} Listener;
|
||||
|
||||
typedef struct {
|
||||
SocketType type;
|
||||
int fd;
|
||||
gnutls_session_t session;
|
||||
} Stream;
|
||||
|
||||
int initTLS();
|
||||
Listener *createListener(SocketType type, uint16_t port, int backlog, ...);
|
||||
//extra arguments depend on type (similar to fcntl):
|
||||
//tcp: (void)
|
||||
//tls: (char *keyfile, char *certfile, char *ocspfile)
|
||||
Stream *acceptStream(Listener *listener, int flags);
|
||||
//returns 1 on error, accepts fcntl flags
|
||||
|
||||
void freeListener(Listener *listener);
|
||||
void freeStream(Stream *stream);
|
||||
|
||||
ssize_t sendStream(Stream *stream, void *data, size_t len);
|
||||
ssize_t recvStream(Stream *stream, void *data, size_t len);
|
||||
//return value is the same as the read and write syscalls.
|
||||
#endif
|
||||
@@ -17,6 +17,11 @@
|
||||
*/
|
||||
#ifndef _HAVE_UTIL
|
||||
#define _HAVE_UTIL
|
||||
typedef enum {
|
||||
TCP,
|
||||
TLS,
|
||||
} SocketType;
|
||||
|
||||
typedef enum {
|
||||
GET,
|
||||
POST,
|
||||
@@ -30,6 +35,8 @@ typedef enum {
|
||||
//INVALID in HTTP/1.1.
|
||||
} RequestType;
|
||||
|
||||
int initLogging(char *path);
|
||||
int createLog(char *msg);
|
||||
int istrcmp(char *s1, char *s2);
|
||||
//case insensitive strcmp
|
||||
RequestType getType(char *str);
|
||||
|
||||
85
src/main.c
85
src/main.c
@@ -20,25 +20,25 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <util.h>
|
||||
#include <runner.h>
|
||||
#include <sockets.h>
|
||||
#include <sitefile.h>
|
||||
|
||||
FILE *logs;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *logout = "/var/log/swebs.log";
|
||||
char *sitefile = NULL;
|
||||
int processes = 8;
|
||||
uint16_t port = htons(80);
|
||||
uint16_t port = 443;
|
||||
int backlog = 100;
|
||||
for (;;) {
|
||||
int c = getopt(argc, argv, "o:j:s:c:p:b:h");
|
||||
int c = getopt(argc, argv, "o:j:s:p:b:c:hl");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c) {
|
||||
@@ -52,11 +52,26 @@ int main(int argc, char **argv) {
|
||||
sitefile = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
port = htons(atoi(optarg));
|
||||
port = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
backlog = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
printf(
|
||||
"swebs Copyright (C) 2022 Nate Choe\n"
|
||||
"This is free software, and you are welcome to redistribute under certain\n"
|
||||
"conditions, but comes with ABSOLUTELY NO WARRANTY. For more details see the\n"
|
||||
"GNU General Public License Version 3\n"
|
||||
"\n"
|
||||
"This program dynamically links with:\n"
|
||||
" gnutls (gnutls.org)\n"
|
||||
"\n"
|
||||
"For any complaints, email me at natechoe9@gmail.com\n"
|
||||
"I'm a programmer not a lawyer, so there's a good chance I accidentally\n"
|
||||
"violated the LGPL.\n"
|
||||
);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'h':
|
||||
printf(
|
||||
"Usage: swebs [options]\n"
|
||||
@@ -65,39 +80,44 @@ int main(int argc, char **argv) {
|
||||
" -s [site file] Use that site file (required)\n"
|
||||
" -p [port] Set the port (default: 443)\n"
|
||||
" -b [backlog] Set the socket backlog (default: 100)\n"
|
||||
" -l Show some legal details\n"
|
||||
" -h Show this help message\n"
|
||||
);
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
fprintf(stderr, "-h for help\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
assert(fd >= 0);
|
||||
int opt = 1;
|
||||
assert(setsockopt(fd, SOL_SOCKET,
|
||||
SO_REUSEPORT,
|
||||
&opt, sizeof(opt)) >= 0);
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = port;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
assert(bind(fd, (struct sockaddr *) &addr, addrlen) >= 0);
|
||||
assert(listen(fd, backlog) >= 0);
|
||||
|
||||
if (sitefile == NULL) {
|
||||
fprintf(stderr, "No sitefile configured\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Sitefile *site = parseFile(sitefile);
|
||||
Sitefile *site = parseSitefile(sitefile);
|
||||
if (site == NULL) {
|
||||
fprintf(stderr, "Invalid sitefile %s\n", sitefile);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
logs = fopen(logout, "a");
|
||||
if (logs == NULL) {
|
||||
Listener *listener;
|
||||
switch (site->type) {
|
||||
case TCP: default:
|
||||
listener = createListener(TCP, port, backlog);
|
||||
break;
|
||||
case TLS:
|
||||
initTLS();
|
||||
listener = createListener(TLS, port, backlog,
|
||||
site->key, site->cert);
|
||||
break;
|
||||
}
|
||||
if (listener == NULL) {
|
||||
fprintf(stderr, "Failed to create socket\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (initLogging(logout)) {
|
||||
fprintf(stderr, "Couldn't open logs file %s\n", logout);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -122,16 +142,15 @@ int main(int argc, char **argv) {
|
||||
(void*(*)(void*)) runServer, args);
|
||||
}
|
||||
|
||||
createLog("swebs started");
|
||||
|
||||
for (;;) {
|
||||
fsync(fd);
|
||||
//TODO: Find out why this works
|
||||
int newfd = accept(fd, (struct sockaddr *) &addr,
|
||||
&addrlen);
|
||||
if (newfd < 0)
|
||||
exit(EXIT_FAILURE);
|
||||
int flags = fcntl(newfd, F_GETFL);
|
||||
if (fcntl(newfd, F_SETFL, flags | O_NONBLOCK))
|
||||
exit(EXIT_FAILURE);
|
||||
Stream *stream = acceptStream(listener, O_NONBLOCK);
|
||||
if (stream == NULL) {
|
||||
createLog("Accepting a stream failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
int lowestThread = 0;
|
||||
int lowestCount = pending[0];
|
||||
for (int i = 1; i < processes - 1; i++) {
|
||||
@@ -140,8 +159,8 @@ int main(int argc, char **argv) {
|
||||
lowestCount = pending[i];
|
||||
}
|
||||
}
|
||||
if (write(notify[lowestThread][1], &newfd, sizeof(newfd))
|
||||
< sizeof(newfd))
|
||||
if (write(notify[lowestThread][1], &stream, sizeof(&stream))
|
||||
< sizeof(&stream))
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,6 @@ static void readResponse(Connection *conn, char *path) {
|
||||
if (sendBinaryResponse(conn, "200 OK", data, len) < len)
|
||||
goto error;
|
||||
free(data);
|
||||
fsync(conn->fd);
|
||||
return;
|
||||
error:
|
||||
sendErrorResponse(conn, ERROR_500);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <responseutil.h>
|
||||
@@ -40,7 +40,7 @@ static int sendConnection(Connection *conn, char *format, ...) {
|
||||
va_start(ap, format);
|
||||
|
||||
vsprintf(data, format, ap);
|
||||
if (write(conn->fd, data, len) < len) {
|
||||
if (sendStream(conn->stream, data, len) < len) {
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
@@ -83,5 +83,5 @@ int sendBinaryResponse(Connection *conn, char *status,
|
||||
, status, len)
|
||||
)
|
||||
return 1;
|
||||
return write(conn->fd, data, len) < len;
|
||||
return sendStream(conn->stream, data, len) < len;
|
||||
}
|
||||
|
||||
10
src/runner.c
10
src/runner.c
@@ -23,9 +23,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <runner.h>
|
||||
#include <sitefile.h>
|
||||
@@ -74,13 +72,13 @@ void *runServer(RunnerArgs *args) {
|
||||
exit(EXIT_FAILURE);
|
||||
connections = newconns;
|
||||
}
|
||||
int newfd;
|
||||
if (read(notify, &newfd, sizeof(newfd)) < sizeof(newfd))
|
||||
Stream *stream;
|
||||
if (read(notify, &stream, sizeof(stream)) < sizeof(stream))
|
||||
exit(EXIT_FAILURE);
|
||||
fds[connCount].fd = newfd;
|
||||
fds[connCount].fd = stream->fd;
|
||||
fds[connCount].events = POLLIN;
|
||||
|
||||
if (newConnection(newfd, connections + connCount))
|
||||
if (newConnection(stream, connections + connCount))
|
||||
exit(EXIT_FAILURE);
|
||||
connCount++;
|
||||
pending[id]++;
|
||||
|
||||
@@ -165,13 +165,16 @@ static char *copyString(char *str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Sitefile *parseFile(char *path) {
|
||||
Sitefile *parseSitefile(char *path) {
|
||||
FILE *file = fopen(path, "r");
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
Sitefile *ret = malloc(sizeof(Sitefile));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->type = TCP;
|
||||
ret->key = NULL;
|
||||
ret->cert = NULL;
|
||||
int allocatedLength = 50;
|
||||
ret->size = 0;
|
||||
ret->content = malloc(allocatedLength * sizeof(SiteCommand));
|
||||
@@ -219,6 +222,25 @@ Sitefile *parseFile(char *path) {
|
||||
setValue:
|
||||
continue;
|
||||
}
|
||||
else if (strcmp(argv[0], "define") == 0) {
|
||||
if (argc < 3)
|
||||
goto error;
|
||||
if (strcmp(argv[1], "transport") == 0) {
|
||||
if (strcmp(argv[2], "TCP") == 0)
|
||||
ret->type = TCP;
|
||||
else if (strcmp(argv[2], "TLS") == 0)
|
||||
ret->type = TLS;
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
else if (strcmp(argv[1], "key") == 0)
|
||||
ret->key = copyString(argv[2]);
|
||||
else if (strcmp(argv[1], "cert") == 0)
|
||||
ret->cert = copyString(argv[2]);
|
||||
else
|
||||
goto error;
|
||||
continue;
|
||||
}
|
||||
if (ret->size >= allocatedLength) {
|
||||
allocatedLength *= 2;
|
||||
SiteCommand *newcontent = realloc(ret->content,
|
||||
|
||||
178
src/sockets.c
Normal file
178
src/sockets.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <sockets.h>
|
||||
|
||||
int initTLS() {
|
||||
assert(gnutls_global_init() >= 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Listener *createListener(SocketType type, uint16_t port, int backlog, ...) {
|
||||
Listener *ret = malloc(sizeof(Listener));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->type = type;
|
||||
ret->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (ret->fd < 0) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
int opt = 1;
|
||||
if (setsockopt(ret->fd, SOL_SOCKET,
|
||||
SO_REUSEPORT,
|
||||
&opt, sizeof(opt)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
ret->addr.sin_family = AF_INET;
|
||||
ret->addr.sin_addr.s_addr = INADDR_ANY;
|
||||
ret->addr.sin_port = htons(port);
|
||||
ret->addrlen = sizeof(ret->addr);
|
||||
if (bind(ret->fd, (struct sockaddr *) &ret->addr, ret->addrlen) < 0)
|
||||
goto error;
|
||||
if (listen(ret->fd, backlog) < 0)
|
||||
goto error;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, backlog);
|
||||
switch (type) {
|
||||
case TCP: default:
|
||||
break;
|
||||
case TLS: {
|
||||
char *keyfile = va_arg(ap, char *);
|
||||
char *certfile = va_arg(ap, char *);
|
||||
if (gnutls_certificate_allocate_credentials(&ret->creds)
|
||||
< 0)
|
||||
goto error;
|
||||
if (gnutls_certificate_set_x509_key_file(ret->creds,
|
||||
certfile, keyfile,
|
||||
GNUTLS_X509_FMT_PEM) < 0)
|
||||
goto error;
|
||||
if (gnutls_priority_init(&ret->priority,
|
||||
NULL, NULL) < 0)
|
||||
goto error;
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030506
|
||||
gnutls_certificate_set_known_dh_params(ret->creds,
|
||||
GNUTLS_SEC_PARAM_MEDIUM);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
return ret;
|
||||
error:
|
||||
close(ret->fd);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Stream *acceptStream(Listener *listener, int flags) {
|
||||
Stream *ret = malloc(sizeof(Stream));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->type = listener->type;
|
||||
ret->fd = accept(listener->fd, (struct sockaddr *) &listener->addr,
|
||||
&listener->addrlen);
|
||||
|
||||
if (ret->fd < 0) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (listener->type) {
|
||||
case TCP: default:
|
||||
break;
|
||||
case TLS:
|
||||
if (gnutls_init(&ret->session, GNUTLS_SERVER) < 0)
|
||||
goto error;
|
||||
if (gnutls_priority_set(ret->session,
|
||||
listener->priority) < 0)
|
||||
goto error;
|
||||
if (gnutls_credentials_set(ret->session,
|
||||
GNUTLS_CRD_CERTIFICATE,
|
||||
listener->creds) < 0)
|
||||
goto error;
|
||||
gnutls_certificate_server_set_request(ret->session,
|
||||
GNUTLS_CERT_IGNORE);
|
||||
gnutls_handshake_set_timeout(ret->session,
|
||||
GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
||||
gnutls_transport_set_int(ret->session, ret->fd);
|
||||
if (gnutls_handshake(ret->session) < 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
{
|
||||
int flags = fcntl(ret->fd, F_GETFD);
|
||||
fcntl(ret->fd, F_SETFD, flags | O_NONBLOCK);
|
||||
}
|
||||
return ret;
|
||||
error:
|
||||
close(ret->fd);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void freeListener(Listener *listener) {
|
||||
if (listener->type == TLS) {
|
||||
gnutls_certificate_free_credentials(listener->creds);
|
||||
gnutls_priority_deinit(listener->priority);
|
||||
}
|
||||
close(listener->fd);
|
||||
free(listener);
|
||||
}
|
||||
|
||||
void freeStream(Stream *stream) {
|
||||
if (stream->type == TLS) {
|
||||
gnutls_bye(stream->session, GNUTLS_SHUT_RDWR);
|
||||
gnutls_deinit(stream->session);
|
||||
}
|
||||
close(stream->fd);
|
||||
free(stream);
|
||||
}
|
||||
|
||||
ssize_t sendStream(Stream *stream, void *data, size_t len) {
|
||||
switch (stream->type) {
|
||||
case TCP:
|
||||
return write(stream->fd, data, len);
|
||||
case TLS:
|
||||
return gnutls_record_send(stream->session, data, len);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t recvStream(Stream *stream, void *data, size_t len) {
|
||||
switch (stream->type) {
|
||||
case TCP:
|
||||
return read(stream->fd, data, len);
|
||||
case TLS:
|
||||
return gnutls_record_recv(stream->session, data, len);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
27
src/util.c
27
src/util.c
@@ -15,12 +15,39 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <util.h>
|
||||
|
||||
static FILE *logs;
|
||||
|
||||
int initLogging(char *path) {
|
||||
logs = fopen(path, "a");
|
||||
return logs == NULL;
|
||||
}
|
||||
|
||||
int createLog(char *msg) {
|
||||
time_t currenttime;
|
||||
time(¤ttime);
|
||||
struct tm *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 istrcmp(char *s1, char *s2) {
|
||||
for (int i = 0;; i++) {
|
||||
char c1 = tolower(s1[i]);
|
||||
|
||||
Reference in New Issue
Block a user