~ctrlproxy/ctrlproxy/trunk

« back to all changes in this revision

Viewing changes to main.c

  • Committer: jelmer
  • Date: 2003-10-18 22:02:02 UTC
  • Revision ID: jelmer@samba.org-20031018220202-6801a76318fb4d13
Update

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* 
2
2
        ctrlproxy: A modular IRC proxy
3
 
        (c) 2002 Jelmer Vernooij <jelmer@nl.linux.org>
 
3
        (c) 2002-2003 Jelmer Vernooij <jelmer@nl.linux.org>
4
4
 
5
5
        This program is free software; you can redistribute it and/or modify
6
6
        it under the terms of the GNU General Public License as published by
18
18
*/
19
19
 
20
20
#include "internals.h"
21
 
 
22
 
struct module_context *active_context = NULL;
23
 
 
 
21
#include "config.h"
 
22
 
 
23
#include <libxml/xmlmemory.h>
 
24
#include <libxml/parser.h>
 
25
 
 
26
#define BACKTRACE_STACK_SIZE 64
 
27
 
 
28
#ifdef HAVE_EXECINFO_H
 
29
#include <execinfo.h>
 
30
#endif
 
31
 
 
32
#define add_log_domain(domain) g_log_set_handler (domain, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, log_handler, NULL);
 
33
 
 
34
/* globals */
24
35
char my_hostname[MAXHOSTNAMELEN+2];
25
 
char output_debug = 0;
 
36
xmlNodePtr xmlNode_networks, xmlNode_plugins;
 
37
GHookList data_hook;
 
38
xmlDocPtr configuration;
 
39
char *configuration_file;
 
40
FILE *debugfd = NULL;
 
41
FILE *f_logfile = NULL;
 
42
 
 
43
GList *plugins = NULL;
26
44
 
27
45
void signal_crash(int sig) 
28
46
{
29
 
        if(active_context) 
30
 
        {
31
 
                /* If we crashed in the middle of a module, unload that module */
32
 
                unload_module(active_context);
33
 
        } else {
34
 
                /* Bug in the core. Just loop until someone runs gdb on us */ 
35
 
                while(1)sleep(5);
36
 
        }
 
47
#ifdef HAVE_BACKTRACE_SYMBOLS
 
48
        void *backtrace_stack[BACKTRACE_STACK_SIZE];
 
49
        size_t backtrace_size;
 
50
        char **backtrace_strings;
 
51
#endif
 
52
        g_critical("Received SIGSEGV!\n");
 
53
 
 
54
#ifdef HAVE_BACKTRACE_SYMBOLS
 
55
        /* get the backtrace (stack frames) */
 
56
        backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
 
57
        backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
 
58
 
 
59
        g_critical ("BACKTRACE: %d stack frames:\n", backtrace_size);
 
60
        
 
61
        if (backtrace_strings) {
 
62
                int i;
 
63
 
 
64
                for (i = 0; i < backtrace_size; i++)
 
65
                        g_critical(" #%u %s", i, backtrace_strings[i]);
 
66
 
 
67
                free(backtrace_strings);
 
68
        }
 
69
 
 
70
#endif
 
71
        
 
72
        g_error("Ctrlproxy core has segfaulted, exiting...\n");
 
73
}
 
74
 
 
75
void log_handler(const gchar *log_domain, GLogLevelFlags flags, const gchar *message, gpointer user_data) {
 
76
        if(!f_logfile)return;
 
77
        fprintf(f_logfile, "%s\n", message);
 
78
        fflush(f_logfile);
 
79
}
 
80
 
 
81
void clean_exit()
 
82
{
 
83
        GList *gl = networks;
 
84
        while(gl) {
 
85
                struct network *n = (struct network *)gl->data;
 
86
                close_server(n);
 
87
                gl = gl->next;
 
88
        }
 
89
        if(debugfd)fclose(debugfd);
37
90
}
38
91
 
39
92
void signal_quit(int sig)
40
93
{
41
 
        close_all();
42
 
        sleep(5);
 
94
        g_log(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Received signal %d, quitting...\n", sig);
 
95
        clean_exit();
43
96
        exit(0);
44
97
}
45
98
 
 
99
gboolean unload_plugin(struct plugin *p)
 
100
{
 
101
        plugin_fini_function f;
 
102
 
 
103
        /* Run exit function if present */
 
104
        if(g_module_symbol(p->module, "fini_plugin", (gpointer *)&f)) {
 
105
                if(!f(p)) {
 
106
                        g_warning("Unable to unload plugin '%s': still in use?\n", p->name);
 
107
                        return FALSE;
 
108
                }
 
109
        } else {
 
110
                g_warning("No symbol 'fini_plugin' in plugin '%s'. Module does not support unloading, so no unload will be attempted\n", p->name);
 
111
                return FALSE;
 
112
        }
 
113
 
 
114
        g_module_close(p->module);
 
115
 
 
116
        /* Remove autoload from this plugins' element */
 
117
        xmlUnsetProp(p->xmlConf, "autoload");
 
118
        return TRUE;
 
119
}
 
120
 
 
121
gboolean plugin_loaded(char *name)
 
122
{
 
123
        GList *gl = plugins;
 
124
        while(gl) {
 
125
                struct plugin *p = (struct plugin *)gl->data;
 
126
                if(!strcmp(p->name, name)) return TRUE;
 
127
                gl = gl->next;
 
128
        }
 
129
        return FALSE;
 
130
}
 
131
 
 
132
gboolean load_plugin(xmlNodePtr cur)
 
133
{
 
134
        GModule *m;
 
135
        char *mod_name;
 
136
        struct plugin *p;
 
137
        char *modulesdir;
 
138
        gchar *path_name;
 
139
        plugin_init_function f = NULL; 
 
140
 
 
141
        mod_name = xmlGetProp(cur, "file");
 
142
        if(!mod_name) {
 
143
                g_warning("No filename specified for plugin");
 
144
                return FALSE;
 
145
        }
 
146
 
 
147
        /* Determine correct modules directory */
 
148
        if(getenv("MODULESDIR"))modulesdir = getenv("MODULESDIR"); 
 
149
        else modulesdir = MODULESDIR;
 
150
 
 
151
        if(mod_name[0] == '/')path_name = g_strdup(mod_name);
 
152
        else path_name = g_module_build_path(modulesdir, mod_name);
 
153
 
 
154
 
 
155
        m = g_module_open(path_name, 0);
 
156
        if(!m) {
 
157
                g_warning("Unable to open module %s(%s), ignoring\n", path_name, g_module_error()); 
 
158
                xmlFree(mod_name);
 
159
                g_free(path_name);
 
160
                return FALSE;
 
161
        } else {
 
162
                if(!g_module_symbol(m, "init_plugin", (gpointer *)&f)) {
 
163
                        g_warning("Can't find symbol 'init_plugin' in module %s\n", path_name);
 
164
                        g_free(path_name);
 
165
                        return FALSE;
 
166
                }
 
167
        }
 
168
 
 
169
        g_free(path_name);
 
170
 
 
171
        p = malloc(sizeof(struct plugin));
 
172
        p->name = strdup(mod_name);
 
173
        p->module = m;
 
174
        p->xmlConf = cur;
 
175
 
 
176
        if(!f(p)) {
 
177
                g_warning("Running initialization function for plugin '%s' failed.\n", mod_name);
 
178
                free(p->name);
 
179
                free(p);
 
180
                return FALSE;
 
181
        }
 
182
 
 
183
        plugins = g_list_append(plugins, p);
 
184
        
 
185
        xmlSetProp(cur, "autoload", "1");
 
186
        xmlFree(mod_name);
 
187
        return TRUE;
 
188
}
 
189
 
 
190
void save_configuration()
 
191
{
 
192
        xmlSaveFile(configuration_file, configuration);
 
193
}
 
194
 
 
195
void signal_save(int sig)
 
196
{
 
197
        save_configuration();
 
198
}
 
199
 
 
200
void readConfig(char *file) {
 
201
    xmlNodePtr cur;
 
202
 
 
203
        configuration = xmlParseFile(file);
 
204
        g_assert(configuration);
 
205
 
 
206
        cur = xmlDocGetRootElement(configuration);
 
207
        g_assert(cur);
 
208
 
 
209
        g_assert(!strcmp(cur->name, "ctrlproxy"));
 
210
 
 
211
        cur = cur->xmlChildrenNode;
 
212
        while(cur) {
 
213
                if(xmlIsBlankNode(cur) || !strcmp(cur->name, "comment")) {
 
214
                        cur = cur->next;
 
215
                        continue;
 
216
                }
 
217
                
 
218
                if(!strcmp(cur->name, "plugins")) {
 
219
                        xmlNode_plugins = cur;
 
220
                } else if(!strcmp(cur->name, "networks")) {
 
221
                        xmlNode_networks = cur;
 
222
                } else g_assert(0);
 
223
                
 
224
                cur = cur->next;
 
225
        }
 
226
}
 
227
 
46
228
int main(int argc, const char *argv[])
47
229
{
48
 
        struct server *s;
49
 
        char **sections;
50
 
        int i;
51
 
        char *t;
52
 
        char *nick, *port, *host, *pass, *mods, *modsdup;
53
 
        char *tmp;
54
 
        char *autojoin;
55
 
        int final = 0;
 
230
        GMainLoop *loop;
 
231
        char isdaemon = 0;
 
232
        char *logfile = NULL, *rcfile = NULL;
 
233
#ifdef HAVE_POPT_H
 
234
        int c;
56
235
        poptContext pc;
57
 
        char daemon = 0;
58
 
        char *rcfile_default, *rcfile;
59
 
        int c;
60
236
        struct poptOption options[] = {
61
237
                POPT_AUTOHELP
62
 
                {"rc-file", 'r', POPT_ARG_STRING, &rcfile, 0, "Use alternative ctrlproxyrc file", "RCFILE"},
63
 
                {"daemon", 'D', POPT_ARG_VAL, &daemon, 1, "Run in the background (as a daemon)"},
 
238
                {"debug", 'd', POPT_ARG_STRING, NULL, 'd', "Write irc traffic to specified file", "FILE" },
 
239
                {"daemon", 'D', POPT_ARG_VAL, &isdaemon, 1, "Run in the background (as a daemon)"},
 
240
                {"log", 'l', POPT_ARG_STRING, &logfile, 0, "Log messages to specified file", "FILE"},
 
241
                {"rc-file", 'r', POPT_ARG_STRING, &rcfile, 0, "Use configuration file from specified location", "FILE"},
64
242
                {"version", 'v', POPT_ARG_NONE, NULL, 'v', "Show version information"},
65
 
                {"debug", 'd', POPT_ARG_VAL, &output_debug, 1, "Output debug information"},
66
243
                POPT_TABLEEND
67
244
        };
 
245
#endif
 
246
    xmlNodePtr cur;
68
247
 
69
248
        signal(SIGINT, signal_quit);
70
249
        signal(SIGTERM, signal_quit);
71
250
        signal(SIGPIPE, SIG_IGN);
72
251
        signal(SIGHUP, SIG_IGN);
73
252
        signal(SIGSEGV, signal_crash);
74
 
 
75
 
        asprintf(&rcfile_default, "%s/.ctrlproxyrc", getenv("HOME")?getenv("HOME"):"");
76
 
        rcfile = rcfile_default;
77
 
 
 
253
        signal(SIGUSR1, signal_save);
 
254
 
 
255
        replicate_function = default_replicate_function;
 
256
        g_hook_list_init(&data_hook, sizeof(GHook));
 
257
 
 
258
        loop = g_main_new(FALSE);
 
259
 
 
260
#ifdef HAVE_POPT_H
78
261
        pc = poptGetContext(argv[0], argc, argv, options, 0);
79
262
 
80
263
        while((c = poptGetNextOpt(pc)) >= 0) {
81
264
                switch(c) {
 
265
                case 'd': 
 
266
                        {
 
267
                                const char *fname = poptGetOptArg(pc);
 
268
                                if(!strcmp(fname, "-")) { debugfd = stdout; break; }
 
269
                                debugfd = fopen(fname, "w+"); 
 
270
                        }
 
271
                        break;
82
272
                case 'v':
83
 
                        printf("ctrlproxy %s\n", CTRLPROXY_VERSION);
84
 
                        printf("(c) 2002 Jelmer Vernooij <jelmer@nl.linux.org>\n");
85
 
                        exit(1);
86
 
                        break;
 
273
                        printf("ctrlproxy %s\n", PACKAGE_VERSION);
 
274
                        printf("(c) 2002-2003 Jelmer Vernooij <jelmer@nl.linux.org>\n");
 
275
                        return 0;
87
276
                }
88
277
        }
 
278
#endif
89
279
 
90
280
        if(gethostname(my_hostname, MAXHOSTNAMELEN) != 0) {
91
 
                fprintf(stderr, "Can't figure out hostname of local host!\n");
92
 
                return 1;
93
 
        }
94
 
 
95
 
        if(SLang_init_slang() == -1) {
96
 
                fprintf(stderr, "Unable to initialize S-Lang\n");
97
 
                return 1;
98
 
        }
99
 
 
100
 
        if(SLang_load_file(rcfile) == -1) {
101
 
                fprintf(stderr, "Unable to load %s!\n", rcfile);
102
 
                return 1;
103
 
        }
104
 
        
105
 
        sections = enum_sections();
106
 
 
107
 
        for(i = 0; sections[i]; i++) {
108
 
                t = sections[i];
109
 
                nick = get_conf(t, "nick");
110
 
                if(!nick)nick = getenv("USER");
111
 
                port = get_conf(t, "port");
112
 
                if(!port)port = "6667";
113
 
                host = get_conf(t, "host");
114
 
                if(!host) {
115
 
                        fprintf(stderr, "No host specified for %s !\n", t);
116
 
                        return 1;
117
 
                }
118
 
                pass = get_conf(t, "password");
119
 
                
120
 
                s = connect_to_server(host, atoi(port), nick, pass);
121
 
                if(!s)return 1;
122
 
 
123
 
                s->abbrev = t;
124
 
 
125
 
                /* Do autojoin stuff */
126
 
                autojoin = get_conf(t, "autojoin");
127
 
                if(autojoin)server_send(s, NULL, "JOIN", autojoin, NULL);
128
 
 
129
 
                /* Load modules */
130
 
                mods = get_conf(t, "modules");
131
 
                if(!mods)continue;
132
 
                modsdup = strdup(mods);
133
 
                
134
 
                final = 0;
135
 
                mods = modsdup;
136
 
                while((tmp = strchr(mods, ' ')) || (tmp = strchr(mods, '\0'))) {
137
 
                        if(*tmp == '\0')final = 1;
138
 
                        *tmp = '\0';
139
 
                        
140
 
                        load_module(s, mods);
141
 
 
142
 
                        if(final)break;
143
 
                        mods = tmp+1;
144
 
                }
145
 
                free(modsdup);
146
 
        }
147
 
        
148
 
        if(daemon) {
 
281
                g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "Can't figure out hostname of local host!\n");
 
282
                return 1;
 
283
        }
 
284
 
 
285
        if(logfile) {
 
286
                f_logfile = fopen(logfile, "a+");
 
287
                if(!f_logfile) g_warning("Can't open logfile %s!", logfile);
 
288
        }
 
289
 
 
290
        add_log_domain("GLib");
 
291
        add_log_domain("ctrlproxy");
 
292
 
 
293
        g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "Logfile opened");
 
294
 
 
295
        if(isdaemon) {
 
296
 
149
297
#ifdef SIGTTOU
150
298
                signal(SIGTTOU, SIG_IGN);
151
299
#endif
157
305
#ifdef SIGTSTP
158
306
                signal(SIGTSTP, SIG_IGN);
159
307
#endif
160
 
 
161
 
                if(fork() != 0)exit(0);
162
 
 
163
 
                setsid();
164
308
                signal(SIGHUP, SIG_IGN);
165
 
                close(STDIN_FILENO);
166
 
                close(STDOUT_FILENO);
167
 
                close(STDERR_FILENO);
168
 
 
169
 
        }
170
 
 
171
 
        while(1) {
172
 
                loop_all();
173
 
        }
 
309
                daemon(0, 0);
 
310
                isdaemon = 1;
 
311
        } else if(!f_logfile)f_logfile = stdout;
 
312
 
 
313
        if(rcfile) configuration_file = strdup(rcfile);
 
314
        else { 
 
315
                asprintf(&configuration_file, "%s/.ctrlproxyrc", g_get_home_dir());
 
316
        }
 
317
 
 
318
        readConfig(configuration_file);
 
319
 
 
320
        if(!g_module_supported()) {
 
321
                g_warning("DSO's not supported on this platform. Not loading any modules");
 
322
        } else {
 
323
                cur = xmlNode_plugins->xmlChildrenNode;
 
324
                while(cur) {
 
325
 
 
326
                        if(xmlIsBlankNode(cur) || !strcmp(cur->name, "comment")){ cur = cur->next; continue; }
 
327
 
 
328
                        g_assert(!strcmp(cur->name, "plugin"));
 
329
 
 
330
                        if(xmlHasProp(cur, "autoload"))load_plugin(cur);
 
331
 
 
332
                        cur = cur->next;
 
333
                }
 
334
        }
 
335
 
 
336
        cur = xmlNode_networks->xmlChildrenNode;
 
337
        while(cur) {
 
338
                char *autoconnect;
 
339
                if(xmlIsBlankNode(cur) || !strcmp(cur->name, "comment")){ cur = cur->next; continue; }
 
340
                g_assert(!strcmp(cur->name, "network"));
 
341
 
 
342
                autoconnect = xmlGetProp(cur, "autoconnect");
 
343
                if(autoconnect && !strcmp(autoconnect, "1"))connect_to_server(cur);
 
344
                xmlFree(autoconnect);
 
345
 
 
346
                cur = cur->next;
 
347
        }
 
348
 
 
349
 
 
350
        g_timeout_add(1000 * 300, ping_loop, NULL);
 
351
        g_main_run(loop);
 
352
 
 
353
        return 0;
174
354
}
 
355
 
 
356