sapserver.cpp 8.87 KB
Newer Older
1
/*****************************************************************************
2
 * sapserver.cpp : SAP discovery service mini-server
3
 ****************************************************************************
4
 * Copyright (C) 1998-2004 VideoLAN
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
5
 * $Id$ 
6
 *
7
 * Authors: Arnaud Schauly <gitan@via.ecp.fr>
8
 *          Clément Stenac <zorglub@via.ecp.fr>
9
 *          Damien Lucas <nitrox@videolan.org>
10
 *          Rémi Denis-Courmont <rem # videolan.org>
11
 *
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

27 28 29
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
30
#include <inttypes.h>
31 32 33 34
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <string.h>
35
#include <stdlib.h>
36
#include <stdio.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
37
#include <signal.h>
38
#include <unistd.h>
39
#include <locale.h>
40 41
#include <string>
#include <vector>
42 43 44
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
45

46
using namespace std;
47

48
#include "sapserver.h"
49 50 51 52
#include "program.h"
#include "message.h"
#include "broadcast.h"
#include "parser.h"
53

54
#ifdef CONFIG_SLP
55
    #include <slp.h>
56
    #include "lslp.h"
57
#endif
58

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
59 60 61 62 63 64 65 66 67 68 69 70 71
/*************************************************
 * Signal handler
 *************************************************/
static int should_exit = 0;

static void
exit_handler (int signum)
{
    signal (signum, exit_handler);
    should_exit = 1;
}


72 73 74
/*************************************************
 * Display the help
 *************************************************/
75 76
static void
help(void)
77
{
78
  printf(PACKAGE_NAME"\n"
79 80 81
  "Options:\n"
  "  -d      Use this to daemonize the process (run in the background)\n"
  "  -f      Use this to give a configuration file "
82
                "(default is %s)\n"
83 84 85 86 87
  "  -c      Same as -f\n"
  "  -h      Display this help\n"
  "  -t      \"slp\" or \"sap\". sap is default\n"
  "  -s      Display a dot for each packet sent\n"
  "  -u      Unregister services (SLP only)\n"
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
88
  "  -V      Display version information\n", DEFAULT_CONF);
89
}
90

91 92
static void
version(void)
93 94 95 96 97 98 99
{
    puts(PACKAGE_NAME" version "PACKAGE_VERSION"\n"
    "Copyright (C) 1999-2005 VideoLAN project\n"
    "This is free software; see the source for copying conditions.\n"
    "There is NO warranty; not even for MERCHANTABILITY or\n"
    "FITNESS FOR A PARTICULAR PURPOSE.");
}
100 101 102 103 104 105 106 107

typedef struct
{
    struct sockaddr_storage addr;
    socklen_t addrlen;
    Message *message;
} Announce;

108
#ifndef HAVE_CLEARENV
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
109 110
extern char **environ;

111 112 113 114 115 116 117 118
static int
clearenv (void)
{
	environ = NULL;
	return 0;
}
#endif

119 120 121
/*************************************************
 * The main function
 *************************************************/
122 123
int main(int argc, char *argv[])
{
124
    int result;
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    const struct option opts[] =
        {
                { "conf",       required_argument, NULL, 'c' },
                { "config",     required_argument, NULL, 'c' },
                { "daemon",     no_argument,       NULL, 'd' },
                { "daemonize",  no_argument,       NULL, 'd' },
                { "file",       required_argument, NULL, 'f' },
                { "help",       no_argument,       NULL, 'h' },
                { "dotmode",    no_argument,       NULL, 's' },
                { "type",       required_argument, NULL, 't' },
                { "unregister", no_argument,       NULL, 'u' },
                { "version",    no_argument,       NULL, 'V' },
                { NULL,         no_argument,       NULL, '\0'}
        };

140

141 142
    setvbuf (stdout, NULL, _IOLBF, 0);
    setvbuf (stderr, NULL, _IOLBF, 0);
143
    setlocale(LC_ALL, "");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
144
    Config config(DEFAULT_CONF);
145 146

    /* Parse the command line */
147
    while((result = getopt_long(argc,argv,"c:df:hst:uV", opts, NULL))>0)
148
    {
149
        switch(result)
150
        {
151 152
            case 'c':
            case 'f':
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
153
                config.SetFile(optarg);
154 155
                break;
            case 's':
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
156
                config.SetDotMode(true);
157 158
                break;
            case 'd':
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
159 160 161 162 163 164 165
                config.SetDaemonMode(true);
                break;
            case 't':
                config.SetType(optarg);
                break;
            case 'u':
                config.SetReverse(true);
166 167 168
                break;
            case 'h':
                help();
169
                return 0;
170 171 172
            case 'V':
                version();
                return 0;
173
            default:
174
                return -1;
175
        }
176 177
    }

178
    /* clean up environment */
179
    clearenv();
180 181 182 183
    /* make sure stdin, stdout and stderr exists */
    if (dup (2) < 3)
        return 1;

184
    /* Get the programs */
185
    puts("+ Parsing configuration file\n");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
186
    if(config.Parse())
187
    {
188
        fputs("+ Parsing failed\n", stderr);
189
        return 1;
190
    }
191

192
    /* TODO check configuration */
193
    printf("+ %u programs loaded\n",config.Programs.size());
194 195 196 197 198
    if (config.Programs.size() == 0)
    {
        puts ("+ Nothing to do. Exiting.");
        return 0;
    }
199

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
200
    if(config.GetType() == TYPE_SAP)
201
    {
202
        printf("+ Packet TTL set to %u\n",config.GetTTL());
203
        printf("+ Running as %s.\n",
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
204
               config.GetDaemonMode() ? "daemon" : "program");
205 206

        /* Create the broadcast object */
207
        Broadcast broadcast (config.GetTTL (), config.GetInterface ());
208

209 210 211
        vector<Announce *> announces;

        for (unsigned int i = 0; i < config.Programs.size(); i++)
212
        {
213
            Program *program = config.Programs[i];
214

215 216 217 218 219 220 221 222 223 224
            Announce *announce = new Announce;
            if (broadcast.GuessDestination (program->GetAddress ().c_str (),
                                            &announce->addr,
                                            &announce->addrlen))
            {
                fputs("- Network initialization failed. Aborting\n", stderr);
                delete announce;
                /* FIXME memory leak in announces */
                return 1;
            }
225

226
            /* Create a new message */
227
            Message *message = new Message(0x4212+i, "1.2.3.4");
228 229
            /* Add the program */
            message->AddProgram(config.Programs[i]);
230

231 232
            announce->message = message;
            announces.push_back( announce );
233
        }
234

235
        /* Forking if necessary */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
236
        if(config.GetDaemonMode())
237
        {
238
            puts("+ Forking ... \n");
239 240 241
            daemon(0,0);
        }

242
        unsigned n = config.Programs.size();
243
        lldiv_t d = lldiv (1000000000LL * config.GetDelay() / n, 1000000000);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
244
        struct timespec delay;
245 246
        delay.tv_sec = d.quot;
        delay.tv_nsec = d.rem;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
247 248 249 250 251

        signal (SIGINT, exit_handler);
        signal (SIGTERM, exit_handler);
        signal (SIGHUP, exit_handler);
        signal (SIGQUIT, exit_handler);
252
        setvbuf (stdout, NULL, _IONBF, 0);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
253 254

        while(!should_exit)
255
        {
256
            for( unsigned int i = 0; i< announces.size() ; i ++ )
257
            {
258
                Announce *announce = announces[i];
259
                /* Send the message */
260 261 262 263 264 265 266
                if (broadcast.Send (announce->message ,
                                    (struct sockaddr *)&announce->addr,
                                    announce->addrlen))
                {
                    fputs ("- Message send failed\n", stderr);
                }
                else
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
267
                if(config.GetDotMode())
268
                    fputc('.', stdout);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
269

270
                /* Wait for next sending */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
271 272 273
                if(should_exit)
                    break;
                nanosleep( &delay, NULL );
274
            }
275
        }
276

277 278 279 280 281 282
        for( unsigned int i = 0; i < announces.size() ; i ++ )
        {
            Announce *announce = announces[i];
            delete announce->message;
            delete announce;
        }
283
    }
284
    else
285
    {
286
#ifndef CONFIG_SLP
287
        fputs("- SLP not compiled in...Aborting\n", stderr);
288
        return 1;
289 290
#endif
#ifdef CONFIG_SLP
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        SLP slp;

        for(unsigned int i=0 ; i<config.Programs.size(); i++)
        {
            if(!config.GetReverse())
            {
                slp.Register(config.Programs[i]);
            }
            else
            {
                slp.UnRegister(config.Programs[i]);
            }
        }
        if(!config.GetReverse())
        {
306
            puts("+ Programs registered. To unregister them, run me with -u");
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
307 308 309
        }
        else
        {
310
            puts("+ Programs unregistered");
311 312
        }
#endif
313
    }
314

315
    puts("Done.");
316 317

    return 0;
318
}