Directory structure changed based on IGDv2 Architecture Design document.
[igd2-for-linux:wanipconnection2.git] / linuxigd2 / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <syslog.h>
5 #include <signal.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include <sys/stat.h>
9 #include <sys/resource.h>
10 #include <time.h>
11 #include <net/if.h>
12 #include <upnp/upnp.h>
13 #include "globals.h"
14 #include "config.h"
15 #include "gatedevice.h"
16 #include "util.h"
17 #include "pmlist.h"
18
19 // Global variables
20 globals g_vars;
21
22 int main (int argc, char** argv)
23 {
24         char descDocUrl[7+15+1+5+1+sizeof(g_vars.descDocName)+1]; // http://ipaddr:port/docName<null>
25         char intIpAddress[16];     // Server internal ip address
26         sigset_t sigsToCatch;
27         int ret, signum, arg = 1, foreground = 0;
28
29         if (argc < 3 || argc > 4) {
30           printf("Usage: upnpd [-f] <external ifname> <internal ifname>\n");
31           printf("  -f\tdon't daemonize\n");
32           printf("Example: upnpd ppp0 eth0\n");
33           exit(0);
34         }
35
36         parseConfigFile(&g_vars);
37
38         // check for '-f' option
39         if (strcmp(argv[arg], "-f") == 0) {
40                 foreground = 1;
41                 arg++;
42         }
43
44         // Save interface names for later use
45         strncpy(g_vars.extInterfaceName, argv[arg++], IFNAMSIZ);
46         strncpy(g_vars.intInterfaceName, argv[arg++], IFNAMSIZ);
47
48         // Get the internal ip address to start the daemon on
49         if (GetIpAddressStr(intIpAddress, g_vars.intInterfaceName) == 0) {
50                 fprintf(stderr, "Invalid internal interface name '%s'\n", g_vars.intInterfaceName);
51                 exit(EXIT_FAILURE);
52         }
53
54         if (!foreground) {
55                 struct rlimit resourceLimit = { 0, 0 };
56                 pid_t pid, sid;
57                 unsigned int i;
58
59                 // Put igd in the background as a daemon process.
60                 pid = fork();
61                 if (pid < 0)
62                 {
63                         perror("Error forking a new process.");
64                         exit(EXIT_FAILURE);
65                 }
66                 if (pid > 0)
67                         exit(EXIT_SUCCESS);
68
69                 // become session leader
70                 if ((sid = setsid()) < 0)
71                 {
72                         perror("Error running setsid");
73                         exit(EXIT_FAILURE);
74                 }
75
76                 // close all file handles
77                 resourceLimit.rlim_max = 0;
78                 ret = getrlimit(RLIMIT_NOFILE, &resourceLimit);
79                 if (ret == -1) /* shouldn't happen */
80                 {
81                     perror("error in getrlimit()");
82                     exit(EXIT_FAILURE);
83                 }
84                 if (0 == resourceLimit.rlim_max)
85                 {
86                     fprintf(stderr, "Max number of open file descriptors is 0!!\n");
87                     exit(EXIT_FAILURE);
88                 }       
89                 for (i = 0; i < resourceLimit.rlim_max; i++)
90                     close(i);
91         
92                 // fork again so child can never acquire a controlling terminal
93                 pid = fork();
94                 if (pid < 0)
95                 {
96                         perror("Error forking a new process.");
97                         exit(EXIT_FAILURE);
98                 }
99                 if (pid > 0)
100                         exit(EXIT_SUCCESS);
101         
102                 if ((chdir("/")) < 0)
103                 {
104                         perror("Error setting root directory");
105                         exit(EXIT_FAILURE);
106                 }
107         }
108
109         umask(0);
110
111 // End Daemon initialization
112
113         openlog("upnpd", LOG_CONS | LOG_NDELAY | LOG_PID | (foreground ? LOG_PERROR : 0), LOG_LOCAL6);
114
115         // Initialize UPnP SDK on the internal Interface
116         trace(3, "Initializing UPnP SDK ... ");
117         if ( (ret = UpnpInit(intIpAddress,g_vars.listenport) ) != UPNP_E_SUCCESS)
118         {
119                 syslog (LOG_ERR, "Error Initializing UPnP SDK on IP %s port %d",intIpAddress,g_vars.listenport);
120                 syslog (LOG_ERR, "  UpnpInit returned %d", ret);
121                 UpnpFinish();
122                 exit(1);
123         }
124         trace(2, "UPnP SDK Successfully Initialized.");
125
126         // Set the Device Web Server Base Directory
127         trace(3, "Setting the Web Server Root Directory to %s",g_vars.xmlPath);
128         if ( (ret = UpnpSetWebServerRootDir(g_vars.xmlPath)) != UPNP_E_SUCCESS )
129         {
130                 syslog (LOG_ERR, "Error Setting Web Server Root Directory to: %s", g_vars.xmlPath);
131                 syslog (LOG_ERR, "  UpnpSetWebServerRootDir returned %d", ret); 
132                 UpnpFinish();
133                 exit(1);
134         }
135         trace(2, "Succesfully set the Web Server Root Directory.");
136
137         //initialize the timer thread for expiration of mappings
138         if (ExpirationTimerThreadInit()!=0) {
139           syslog(LOG_ERR,"ExpirationTimerInit failed");
140           UpnpFinish();
141           exit(1);
142         }
143
144         // Form the Description Doc URL to pass to RegisterRootDevice
145         sprintf(descDocUrl, "http://%s:%d/%s", UpnpGetServerIpAddress(),
146                                 UpnpGetServerPort(), g_vars.descDocName);
147
148         // Register our IGD as a valid UPnP Root device
149         trace(3, "Registering the root device with descDocUrl %s", descDocUrl);
150         if ( (ret = UpnpRegisterRootDevice(descDocUrl, EventHandler, &deviceHandle,
151                                            &deviceHandle)) != UPNP_E_SUCCESS )
152         {
153                 syslog(LOG_ERR, "Error registering the root device with descDocUrl: %s", descDocUrl);
154                 syslog(LOG_ERR, "  UpnpRegisterRootDevice returned %d", ret);
155                 UpnpFinish();
156                 exit(1);
157         }
158
159         trace(2, "IGD root device successfully registered.");
160         
161         // Initialize the state variable table.
162         StateTableInit(descDocUrl);
163         
164         // Record the startup time, for uptime
165         startup_time = time(NULL);
166         
167         // Send out initial advertisements of our device's services with timeouts of 30 minutes
168         if ( (ret = UpnpSendAdvertisement(deviceHandle, 1800) != UPNP_E_SUCCESS ))
169         {
170                 syslog(LOG_ERR, "Error Sending Advertisements.  Exiting ...");
171                 UpnpFinish();
172                 exit(1);
173         }
174         trace(2, "Advertisements Sent.  Listening for requests ... ");
175         
176         // Loop until program exit signals received
177         do {
178           sigemptyset(&sigsToCatch);
179           sigaddset(&sigsToCatch, SIGINT);
180           sigaddset(&sigsToCatch, SIGTERM);
181           sigaddset(&sigsToCatch, SIGUSR1);
182           pthread_sigmask(SIG_SETMASK, &sigsToCatch, NULL);
183           sigwait(&sigsToCatch, &signum);
184           trace(3, "Caught signal %d...\n", signum);
185           switch (signum) {
186           case SIGUSR1:
187             DeleteAllPortMappings();
188             break;
189           default:
190             break;
191           }
192         } while (signum!=SIGTERM && signum!=SIGINT);
193
194         trace(2, "Shutting down on signal %d...\n", signum);
195
196         // Cleanup UPnP SDK and free memory
197         DeleteAllPortMappings();
198         ExpirationTimerThreadShutdown();
199
200         UpnpUnRegisterRootDevice(deviceHandle);
201         UpnpFinish();
202
203         // Exit normally
204         return (0);
205 }