root/rat/trunk/main_control.c @ 2876

Revision 2876, 9.6 KB (checked in by ucaccsp, 14 years ago)

Sigh. Helps if you get the arguments in the right order...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:    main.c
3 * PROGRAM: RAT - controller
4 * AUTHOR:  Colin Perkins
5 *
6 * This is the main program for the RAT controller.  It starts the
7 * media engine and user interface, and controls them via the mbus.
8 *
9 * $Revision$
10 * $Date$
11 *
12 * Copyright (c) 1999 University College London
13 * All rights reserved.
14 *
15 */
16
17#include "config_unix.h"
18#include "config_win32.h"
19#include "debug.h"
20#include "mbus.h"
21#include "version.h"
22#include "mbus_control.h"
23#include "crypt_random.h"
24
25#ifdef WIN32
26#define UI_NAME     "ratui.exe"
27#define ENGINE_NAME "ratmedia.exe"
28#else
29#define UI_NAME     "rat-"##VERSION_NUM##"-ui"
30#define ENGINE_NAME "rat-"##VERSION_NUM##"-media"
31#endif
32
33pid_t    pid_ui, pid_engine;
34int      should_exit;
35
36#ifdef FreeBSD
37int kill(pid_t pid, int sig);
38#endif
39
40#ifdef NEED_SNPRINTF
41static int snprintf(char *s, int buf_size, const char *format, ...)
42{
43        /* Quick hack replacement for snprintf... note that this */
44        /* doesn't check for buffer overflows, and so is open to */
45        /* many really nasty attacks!                            */
46        va_list ap;
47        int     rc;
48
49        UNUSED(buf_size);
50        va_start(ap, format);
51        rc = sprintf(s, format, ap);
52        va_end(ap);
53        return rc;
54}
55#endif
56
57static char *fork_process(struct mbus *m, char *proc_name, char *ctrl_addr, pid_t *pid, char *token)
58{
59#ifdef WIN32
60        char                     args[1024];
61        LPSTARTUPINFO            startup_info;
62        LPPROCESS_INFORMATION    proc_info;
63
64        startup_info = (LPSTARTUPINFO) xmalloc(sizeof(STARTUPINFO));
65        startup_info->cb              = sizeof(STARTUPINFO);
66        startup_info->lpReserved      = 0;
67        startup_info->lpDesktop       = 0;
68        startup_info->lpTitle         = 0;
69        startup_info->dwX             = 0;
70        startup_info->dwY             = 0;
71        startup_info->dwXSize         = 0;
72        startup_info->dwYSize         = 0;
73        startup_info->dwXCountChars   = 0;
74        startup_info->dwYCountChars   = 0;
75        startup_info->dwFillAttribute = 0;
76        startup_info->dwFlags         = 0;
77        startup_info->wShowWindow     = 0;
78        startup_info->cbReserved2     = 0;
79        startup_info->lpReserved2     = 0;
80        startup_info->hStdInput       = 0;
81        startup_info->hStdOutput      = 0;
82        startup_info->hStdError       = 0;
83
84        proc_info = (LPPROCESS_INFORMATION) xmalloc(sizeof(PROCESS_INFORMATION));
85
86        sprintf(args, "%s -ctrl \"%s\" -token %s", proc_name, ctrl_addr, token);
87
88        if (!CreateProcess(NULL, args, NULL, NULL, TRUE, 0, NULL, NULL, startup_info, proc_info)) {
89                perror("Couldn't create process");
90                abort();
91        }
92        *pid = (pid_t) proc_info->hProcess;     /* Sigh, hope a HANDLE fits into 32 bits... */
93        debug_msg("Forked %s\n", proc_name);
94#else
95#ifdef DEBUG_FORK
96        debug_msg("%s -ctrl '%s' -token %s\n", proc_name, ctrl_addr, token);
97        UNUSED(pid);
98#else
99        *pid = fork();
100        if (*pid == -1) {
101                perror("Cannot fork");
102                abort();
103        } else if (*pid == 0) {
104                execl(proc_name, proc_name, "-ctrl", ctrl_addr, "-token", token, NULL);
105                perror("Cannot execute subprocess");
106                /* Note: this MUST NOT be exit() or abort(), since they affect the standard */
107                /* IO channels in the parent process (fork duplicates file descriptors, but */
108                /* they still point to the same underlying file).                           */
109                _exit(1);       
110        }
111#endif
112#endif
113        /* This is the parent: we have to wait for the child to say hello before continuing. */
114        return mbus_rendezvous_waiting(m, "()", token, m);
115}
116
117static void kill_process(pid_t proc)
118{
119        if (proc == 0) {
120                debug_msg("Process %d already marked as dead\n", proc);
121                return;
122        }
123#ifdef WIN32
124        /* This doesn't close down DLLs or free resources, so we have to  */
125        /* hope it doesn't get called. With any luck everything is closed */
126        /* down by sending it an mbus.exit() message, anyway...           */
127        TerminateProcess((HANDLE) proc, 0);
128#else
129        kill(proc, SIGINT);
130#endif
131}
132
133static void inform_addrs(struct mbus *m, char *e_addr, char *u_addr)
134{
135        /* Inform the media engine and user interface of each other's mbus address. */
136        char            *tmp;
137        struct timeval   timeout;
138
139        tmp = mbus_encode_str(u_addr);
140        mbus_qmsgf(m, e_addr, TRUE, "tool.rat.addr.ui", "%s", tmp);
141        xfree(tmp);
142
143        tmp = mbus_encode_str(e_addr);
144        mbus_qmsgf(m, u_addr, TRUE, "tool.rat.addr.engine", "%s", tmp);
145        xfree(tmp);
146
147        do {
148                mbus_send(m);
149                mbus_heartbeat(m, 1);
150                mbus_retransmit(m);
151                timeout.tv_sec  = 0;
152                timeout.tv_usec = 20000;
153                mbus_recv(m, NULL, &timeout);
154        } while (!mbus_sent_all(m));
155}
156
157static void parse_options(struct mbus *m, char *e_addr, char *u_addr, int argc, char *argv[])
158{
159        int              i;
160        int              ttl = 15;
161        char            *addr, *rx_port, *tx_port, *tmp;
162        struct timeval   timeout;
163
164        /* Parse the list of addresses/ports at the end of the command line... */
165        addr    = (char *) strtok(argv[argc-1], "/");
166        rx_port = (char *) strtok(NULL, "/");
167        tx_port = (char *) strtok(NULL, "/");
168        if (tx_port == NULL) {
169                tx_port = rx_port;
170        }
171        addr    = mbus_encode_str(addr);
172        mbus_qmsgf(m, e_addr, TRUE, "rtp.addr", "%s %d %d %d", addr, atoi(rx_port), atoi(tx_port), ttl);
173        xfree(addr);
174
175        /* Parse those command line parameters which are intended for the media engine. */
176        for (i = 1; i < argc; i++) {
177                debug_msg("argv[%d]=%s\n", i, argv[i]);
178                if ((strcmp(argv[i], "-ui") == 0) && (argc > i+1)) {
179                } else if  (strcmp(argv[i], "-allowloopback") == 0) {
180                } else if ((strcmp(argv[i], "-C") == 0) && (argc > i+1)) {
181                        tmp = mbus_encode_str(argv[i+1]);
182                        mbus_qmsgf(m, e_addr, TRUE, "session.title", tmp);
183                        xfree(tmp);
184                } else if ((strcmp(argv[i], "-t") == 0) && (argc > i+1)) {
185                        ttl = atoi(argv[i+1]);
186                        if (ttl > 255) {
187                                fprintf(stderr, "TTL must be in the range 0 to 255.\n");
188                                ttl = 255;
189                        }
190                        i++;
191                } else if ((strcmp(argv[i], "-p") == 0) && (argc > i+1)) {
192                } else if  (strcmp(argv[i], "-seed") == 0) {
193                } else if  (strcmp(argv[i], "-codecs") == 0) {
194                } else if ((strcmp(argv[i], "-pt") == 0) && (argc > i+1)) {
195                } else if ((strcmp(argv[i], "-K") == 0) && (argc > i+1)) {
196                        tmp = mbus_encode_str(argv[i+1]);
197                        mbus_qmsgf(m, e_addr, TRUE, "security.encryption.key", tmp);
198                        xfree(tmp);
199                } else if ((strcmp(argv[i], "-crypt") == 0) && (argc > i+1)) {
200                        tmp = mbus_encode_str(argv[i+1]);
201                        mbus_qmsgf(m, e_addr, TRUE, "security.encryption.key", tmp);
202                        xfree(tmp);
203                } else if  (strcmp(argv[i], "-sync") == 0) {
204                } else if ((strcmp(argv[i], "-agc") == 0) && (argc > i+1)) {
205                } else if ((strcmp(argv[i], "-silence") == 0) && (argc > i+1)) {
206                } else if ((strcmp(argv[i], "-repair") == 0) && (argc > i+1)) {
207                } else if ((strcmp(argv[i], "-f") == 0) && (argc > i+1)) {
208                        /* Set primary codec: "-f codec". You cannot set the   */
209                        /* redundant codec with this option, use "-r" instead. */
210                        /* The codec should be of the form "pcmu-8k-mono".     */
211                        char *name = strtok(argv[i+1], "-");
212                        char *freq = strtok(NULL, "-");
213                        char *chan = strtok(NULL, "");
214
215                        name = mbus_encode_str(name);
216                        freq = mbus_encode_str(freq);
217                        chan = mbus_encode_str(chan);
218                        mbus_qmsgf(m, e_addr, TRUE, "tool.rat.codec", "%s %s %s", name, chan, freq);
219                        xfree(name);
220                        xfree(freq);
221                        xfree(chan);
222                } else if ((strcmp(argv[i], "-r") == 0) && (argc > i+1)) {
223                        /* Set channel coding to redundancy: "-r codec/offset" */
224                } else if ((strcmp(argv[i], "-l") == 0) && (argc > i+1)) {
225                        /* Set channel coding to layered */
226                } else if ((strcmp(argv[i], "-i") == 0) && (argc > i+1)) {
227                        /* Set channel coding to interleaved */
228                }
229        }
230
231        /* Synchronize with the sub-processes... */
232        do {
233                mbus_send(m);
234                mbus_heartbeat(m, 1);
235                mbus_retransmit(m);
236                timeout.tv_sec  = 0;
237                timeout.tv_usec = 20000;
238                mbus_recv(m, NULL, &timeout);
239        } while (!mbus_sent_all(m));
240
241        UNUSED(u_addr);
242}
243
244static void mbus_err_handler(int seqnum, int reason)
245{
246        /* Something has gone wrong with the mbus transmission. At this time */
247        /* we don't try to recover, just kill off the media engine and user  */
248        /* interface processes and exit.                                     */
249        printf("FATAL ERROR: couldn't send mbus message (%d:%d)\n", seqnum, reason);
250        kill_process(pid_ui);
251        kill_process(pid_engine);
252        abort();
253}
254
255static void terminate(struct mbus *m, char *addr)
256{
257        if (mbus_addr_valid(m, addr)) {
258                /* This is a valid address, ask that process to quit. */
259                mbus_qmsgf(m, addr, TRUE, "mbus.quit", "");
260                do {
261                        struct timeval   timeout;
262                        mbus_send(m);
263                        mbus_heartbeat(m, 1);
264                        mbus_retransmit(m);
265                        timeout.tv_sec  = 0;
266                        timeout.tv_usec = 20000;
267                        mbus_recv(m, NULL, &timeout);
268                } while (!mbus_sent_all(m));
269        } else {
270                /* That process has already terminated, do nothing. */
271        }
272}
273
274int main(int argc, char *argv[])
275{
276        struct mbus     *m;
277        char             c_addr[60], token_ui[20], token_engine[20];
278        char            *u_addr, *e_addr;
279        int              seed = (gethostid() << 8) | (getpid() & 0xff);
280        struct timeval   timeout;
281
282        srand48(seed);
283
284        m = mbus_init(mbus_control_rx, mbus_err_handler);
285        snprintf(c_addr, 60, "(media:audio module:control app:rat instance:%lu)", (u_int32) getpid());
286        mbus_addr(m, c_addr);
287
288        sprintf(token_ui,     "rat-token-%08lx", lrand48());
289        sprintf(token_engine, "rat-token-%08lx", lrand48());
290
291        u_addr = fork_process(m, UI_NAME,     c_addr, &pid_ui,     token_ui);
292        e_addr = fork_process(m, ENGINE_NAME, c_addr, &pid_engine, token_engine);
293
294        inform_addrs(m, e_addr, u_addr);
295        parse_options(m, e_addr, u_addr, argc, argv);
296
297        mbus_rendezvous_go(m, token_ui, (void *) m);
298        mbus_rendezvous_go(m, token_engine, (void *) m);
299
300        should_exit = FALSE;
301        while (!should_exit) {
302                mbus_send(m);
303                mbus_heartbeat(m, 1);
304                mbus_retransmit(m);
305                timeout.tv_sec  = 0;
306                timeout.tv_usec = 20000;
307                mbus_recv(m, NULL, &timeout);
308        }
309
310        terminate(m, u_addr);
311        terminate(m, e_addr);
312
313        kill_process(pid_ui);
314        kill_process(pid_engine);
315        return 0;
316}
Note: See TracBrowser for help on using the browser.