This repository has been archived by the owner on Mar 31, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mukite.c
156 lines (127 loc) · 4.28 KB
/
mukite.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "xmcomp/network.h"
#include "xmcomp/sighelper.h"
#include "xmcomp/logger.h"
#include "config.h"
#define APP_NAME "mukite"
BOOL running = TRUE;
static void reload_config(int signal) {
config_read();
config_apply();
}
static void save_data(int signal) {
int error;
FILE *output = 0;
LINFO("received signal %d, saving to the file: '%s'", signal, config.worker.data_file);
if ((output = fopen(config.worker.data_file, "w"))) {
if (!rooms_serialize(&config.rooms, output)) {
LERROR("serialization failure, probably disk error");
}
fclose(output);
} else {
error = errno;
LERRNO("failed to save data", error);
}
}
static void load_data() {
int error;
FILE *input = 0;
LINFO("loading from the file: '%s'", config.worker.data_file);
if ((input = fopen(config.worker.data_file, "r"))) {
if (!rooms_deserialize(&config.rooms, input, 10000)) {
LFATAL("deserialization failure, probably disk error/version mismatch;\n"
"please rename or remove the data file to start from scratch");
}
fclose(input);
} else {
error = errno;
LERRNO("failed to load data", error);
}
}
static void terminate(int signal) {
save_data(signal);
running = FALSE;
if (config.reader_thread.enabled) {
// SIGUSR2 the reader thread to interrupt the recv() call
config.reader_thread.enabled = FALSE;
pthread_kill(config.reader_thread.thread, SIGUSR2);
// As soon as reader thread is terminated, main() terminates the writer thread and wraps up
}
}
int main(int argc, char **argv) {
// For connect/authenticate failures
int reconnect_delay = 1;
// RingBuffer buffer for the writer
char *writer_buffer = 0;
LINFO("%s starting", APP_NAME);
config_init(argc > 1 ? argv[1] : 0);
pthread_create(&config.timer_thread.thread, 0, timer_thread_entry, (void *)&config.timer_thread);
if (!config_read()) {
return 1;
}
load_data();
sighelper_sigaction(SIGHUP, reload_config);
sighelper_sigaction(SIGUSR1, save_data);
sighelper_sigaction(SIGTERM, terminate);
sighelper_sigaction(SIGQUIT, terminate);
sighelper_sigaction(SIGINT, terminate);
LDEBUG("allocating writer buffer, size %d", config.writer.buffer);
writer_buffer = malloc(config.writer.buffer);
ringbuffer_init(&config.writer_thread.ringbuffer,
writer_buffer, config.writer.buffer);
LDEBUG("creating reader queue, size %d", config.reader.queue);
queue_init(&config.reader_thread.queue, config.reader.queue);
while (running) {
LINFO("connecting to %s:%d", config.network.host, config.network.port);
if (net_connect(&config.socket, config.network.host, config.network.port)) {
LINFO("opening XMPP stream to %s", config.component.hostname);
if (!net_stream(&config.socket,
"xmcomp",
config.component.hostname,
config.component.password)) {
net_disconnect(&config.socket);
}
}
if (!config.socket.connected) {
LERROR("retrying in %d second(s)", reconnect_delay);
sleep(reconnect_delay);
if (reconnect_delay < 60) {
reconnect_delay <<= 1;
}
continue;
}
reconnect_delay = 1;
LINFO("creating writer thread");
config.writer_thread.socket = &config.socket;
config.writer_thread.enabled = TRUE;
pthread_create(&config.writer_thread.thread, 0, writer_thread_entry, (void *)&config.writer_thread);
LINFO("creating reader thread");
config.reader_thread.socket = &config.socket;
config.reader_thread.enabled = TRUE;
pthread_create(&config.reader_thread.thread, 0, reader_thread_entry, (void *)&config.reader_thread);
LINFO("creating worker threads");
config_apply();
LINFO("started");
LDEBUG("joining reader thread");
pthread_join(config.reader_thread.thread, 0);
// Switch ringbuffer to offline, indicating no more data is expected.
// As soon as the writer finishes the job, it will terminate
ringbuffer_offline(&config.writer_thread.ringbuffer);
LDEBUG("joining writer thread");
pthread_join(config.writer_thread.thread, 0);
LINFO("clearing output buffer and disconnecting");
ringbuffer_clear(&config.writer_thread.ringbuffer);
net_unstream(&config.socket);
net_disconnect(&config.socket);
}
LINFO("cleaning up");
ringbuffer_destroy(&config.writer_thread.ringbuffer);
queue_destroy(&config.reader_thread.queue);
free(writer_buffer);
config_destroy();
return 0;
}