2 Copyright 2004-2019 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP. If not, see <https://www.gnu.org/licenses/>.
20 #include "mvpserver.h"
25 extern pthread_mutex_t threadClientMutex;
27 #define UDP6PORT 51056
29 MVPServer::MVPServer()
31 // MH in case anbody has a better position :-)
32 pthread_mutex_init(&threadClientMutex, NULL);
40 MVPServer::~MVPServer()
42 if (logoDir) delete[] logoDir;
43 if (resourceDir) delete[] resourceDir;
44 if (imageDir) delete[] imageDir;
45 if (cacheDir) delete[] cacheDir;
51 if (threadIsActive()) threadCancel();
52 close(listeningSocket);
60 log.log("Main", Log::INFO, "Stopped main server thread");
68 int MVPServer::run(char* tconfigDir)
70 if (threadIsActive()) return 1;
72 configDir = tconfigDir;
76 #define dsyslog(x) std::cout << x << std::endl;
79 char configFileName[PATH_MAX];
80 snprintf(configFileName, PATH_MAX, "%s/vomp.conf", configDir);
82 if (config.init(configFileName))
84 dsyslog("VOMP: Config file found");
88 dsyslog("VOMP: Config file not found");
93 char* cfgLogFilename = config.getValueString("General", "Log file");
96 log.init(Log::DEBUG, cfgLogFilename);
97 delete[] cfgLogFilename;
98 log.log("Main", Log::INFO, "Logging started");
102 dsyslog("VOMP: Logging disabled");
105 const char *bigresdir = cPlugin::ResourceDirectory();
106 const char *bigcachedir = cPlugin::CacheDirectory();
107 // get logo directory
108 logoDir = config.getValueString("General", "Channel logo directory");
112 log.log("Main", Log::INFO, "LogoDir set %s", logoDir);
115 logoDir = new char[strlen(bigresdir)+1+7];
116 sprintf(logoDir,"%s/logos/",bigresdir);
117 log.log("Main", Log::INFO, "No LogoDir set, default %s",logoDir);
119 log.log("Main", Log::INFO, "No LogoDir set, no res dir");
124 // get epg Image directory
125 imageDir = config.getValueString("General", "Epg image directory");
129 log.log("Main", Log::INFO, "ImageDir set %s", imageDir);
132 imageDir = new char[strlen(bigcachedir)+1+11+3];
133 sprintf(imageDir,"%s/../epgimages/",bigcachedir);
134 log.log("Main", Log::INFO, "No ImageDir set, default %s",imageDir);
136 log.log("Main", Log::INFO, "No ImageDir set, no cache dir");
141 resourceDir = new char[strlen(bigresdir)+1];
142 strcpy(resourceDir,bigresdir);
143 log.log("Main", Log::INFO, "Resource directory is %s",bigresdir);
145 log.log("Main", Log::INFO, "Resource directory is not set");
149 cacheDir = new char[strlen(bigcachedir)+1];
150 strcpy(cacheDir,bigcachedir);
151 log.log("Main", Log::INFO, "Cache directory is %s",bigcachedir);
153 log.log("Main", Log::INFO, "Cache directory is not set");
155 // Get UDP port number for discovery service
158 int udpport = config.getValueLong("General", "UDP port", &fail);
159 if (fail) udpport = 51051;
161 // Work out a name for this server
165 // Try to get from vomp.conf
166 serverName = config.getValueString("General", "Server name");
167 if (!serverName) // If not, get the hostname
169 serverName = new char[1024];
170 if (gethostname(serverName, 1024)) // if not, set default
172 strcpy(serverName, "VOMP Server");
176 // Get VOMP server TCP port to give to UDP replier to put in packets
178 tcpServerPort = config.getValueLong("General", "TCP port", &fail);
179 if (fail) tcpServerPort = 3024;
181 int udpSuccess = udpr.run(udpport, serverName, tcpServerPort);
182 int udp6Success = udpr6.run(UDP6PORT, serverName, tcpServerPort);
188 log.log("Main", Log::CRIT, "Could not start UDP replier");
195 log.log("Main", Log::CRIT, "Could not start UDP6 replier");
200 // Read config and start bootp and tftp as appropriate
203 int bootpEnabled = 0;
205 int mvprelayEnabled = 1;
207 configString = config.getValueString("General", "Bootp server enabled");
208 if (configString && (!strcasecmp(configString, "yes"))) bootpEnabled = 1;
209 if (configString) delete[] configString;
211 configString = config.getValueString("General", "TFTP server enabled");
212 if (configString && (!strcasecmp(configString, "yes"))) tftpEnabled = 1;
213 if (configString) delete[] configString;
215 configString = config.getValueString("General", "MVPRelay enabled");
216 if (configString && (strcasecmp(configString, "yes"))) mvprelayEnabled = 0;
217 if (configString) delete[] configString;
222 if (!bootpd.run(configDir))
224 log.log("Main", Log::CRIT, "Could not start Bootpd");
231 log.log("Main", Log::INFO, "Not starting Bootpd");
236 char tftpPath[PATH_MAX];
238 configString = config.getValueString("General", "TFTP directory");
241 snprintf(tftpPath, PATH_MAX, "%s", configString);
243 // this will never happen.. surely.
244 if ((strlen(tftpPath) + 2) >= PATH_MAX)
246 delete[] configString;
247 log.log("Main", Log::CRIT, "Could not understand TFTP directory from config");
252 // if there isn't a / at the end of the dir, add one
253 if (tftpPath[strlen(tftpPath) - 1] != '/') strcat(tftpPath, "/");
255 delete[] configString;
259 snprintf(tftpPath, PATH_MAX, "%s/", configDir);
262 log.log("Main", Log::INFO, "TFTP path '%s'", tftpPath);
264 if (!tftpd.run(tftpPath))
266 log.log("Main", Log::CRIT, "Could not start TFTPd");
273 log.log("Main", Log::INFO, "Not starting TFTPd");
276 // Start mvprelay thread
281 log.log("Main", Log::CRIT, "Could not start MVPRelay");
287 log.log("Main", Log::INFO, "MVPRelay started");
292 log.log("Main", Log::INFO, "Not starting MVPRelay");
298 log.log("Main", Log::CRIT, "Could not start MVPServer thread");
303 log.log("Main", Log::DEBUG, "MVPServer run success");
307 void MVPServer::threadMethod()
309 // I want to die as soon as I am cancelled because I'll be in accept()
310 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
311 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
314 struct sockaddr_in address;
315 address.sin_family = AF_INET;
316 address.sin_port = htons(tcpServerPort);
317 address.sin_addr.s_addr = INADDR_ANY;
318 socklen_t length = sizeof(address);
320 listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
323 struct sockaddr_in6 address;
324 address.sin6_family = AF_INET6;
325 address.sin6_port = htons(tcpServerPort);
326 address.sin6_addr = in6addr_any;
327 socklen_t length = sizeof(address);
329 listeningSocket = socket(AF_INET6, SOCK_STREAM, 0);
332 if (listeningSocket < 0)
334 log.log("MVPServer", Log::CRIT, "Could not get TCP socket in vompserver");
339 setsockopt(listeningSocket,SOL_SOCKET,SO_REUSEADDR,&value,sizeof(value));
341 if (bind(listeningSocket,(struct sockaddr *)&address,sizeof(address)) < 0)
343 log.log("MVPServer", Log::CRIT, "Could not bind to socket in vompserver");
344 close(listeningSocket);
348 listen(listeningSocket, 5);
354 clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length);
355 VompClient* m = new VompClient(&config, configDir, logoDir, resourceDir, imageDir, cacheDir, clientSocket);