Subversion Repositories mdb

Rev

Rev 57 | Rev 59 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 andreas 1
/*
2
 * Copyright (C) 2015 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * All rights reserved. No warranty, explicit or implicit, provided.
5
 *
6
 * NOTICE:  All information contained herein is, and remains
7
 * the property of Andreas Theofilu and his suppliers, if any.
8
 * The intellectual and technical concepts contained
9
 * herein are proprietary to Andreas Theofilu and its suppliers and
10
 * may be covered by European and Foreign Patents, patents in process,
11
 * and are protected by trade secret or copyright law.
12
 * Dissemination of this information or reproduction of this material
13
 * is strictly forbidden unless prior written permission is obtained
14
 * from Andreas Theofilu.
15
 */
16
 
17
#include <stdio.h>
18
#include <string.h>
19
#include <unistd.h>
20
#include <stdlib.h>
21
#include <libgen.h>
22
#include <math.h>
23
#include <time.h>
24
#include <signal.h>
55 andreas 25
#ifndef __APPLE__
22 andreas 26
#include <wait.h>
55 andreas 27
#endif
2 andreas 28
#include <syslog.h>
29
#include <errno.h>
30
#include <pthread.h>
31
#include <sys/stat.h>
32
#include <sys/types.h>
33
#include <sys/socket.h>
34
#include <arpa/inet.h>
35
#include <fcntl.h>
36
#include <netdb.h>
37
#include <dirent.h>
38
#include <netinet/in.h>
39
#include <sys/param.h>
40
#include <sys/ioctl.h>
41
#include <pwd.h>
42
#include <grp.h>
43
#include "config.h"
44
#include "helplib.h"
45
#include "mdb.h"
11 andreas 46
#include "play.h"
2 andreas 47
 
19 andreas 48
#ifndef SIGCLD
49
#   define SIGCLD SIGCHLD
50
#endif
51
 
55 andreas 52
static pthread_t pthr_pars, pthr_cmds;
19 andreas 53
struct SOCKETS soc;
2 andreas 54
 
4 andreas 55
/* Prototypes */
2 andreas 56
void daemon_start(int ignsigcld);
21 andreas 57
void sig_child (int x);
2 andreas 58
void changeToUser(char *, char *);
59
void *pthr_parser(void *pV_data);
20 andreas 60
void *thread_wait(void *pV_data);
2 andreas 61
 
62
int main(int argc, char **argv)
63
{
4 andreas 64
	readConf();
11 andreas 65
	memset (&playCurrent, 0, sizeof(ST_PLAYING));
4 andreas 66
	/* Now daemonize this application */
19 andreas 67
	daemon_start(1);
2 andreas 68
	changeToUser(&configs.User[0], &configs.Grp[0]);
56 andreas 69
	handleInit();
2 andreas 70
 
4 andreas 71
	/* Now start our Thread */
2 andreas 72
	if (pthread_create(&pthr_pars, NULL, pthr_parser, (void *)0) != 0)
73
	{
74
		syslog (LOG_DAEMON, "Create of thread \"pthr_parser\" failed!");
75
		return 1;
76
	}
77
 
78
	while (1)
79
		sleep(3600);
80
 
81
	return 0;
82
}
83
 
84
/*
85
 * Detach application from console and make it a daemon.
86
 */
87
void daemon_start (int ignsigcld)
88
{
89
	int childpid, fd;
90
	char hv0[64];
91
 
92
	if (getpid () == 1)
93
		goto out;
94
 
95
#ifdef SIGTTOU
96
	signal (SIGTTOU, SIG_IGN);
97
#endif
98
#ifdef SIGTTIN
99
	signal (SIGTTIN, SIG_IGN);
100
#endif
101
#ifdef SIGTSTP
102
	signal (SIGTSTP, SIG_IGN);
103
#endif
104
 
105
	if ((childpid = fork ()) < 0)
106
		fprintf (stderr, "Can't fork this child\n");
107
	else if (childpid > 0)
19 andreas 108
		exit (0);            /* Parent */
2 andreas 109
 
110
	if (setpgrp () == -1)
111
		fprintf (stderr, "Can't change process group\n");
112
 
113
	signal (SIGHUP, SIG_IGN);
114
 
115
	if ((childpid = fork ()) < 0)
116
		syslog (LOG_DAEMON, "Can't fork second child");
117
	else if (childpid > 0)
118
		exit (0);            /* first child */
119
 
120
	/* second child */
121
out:
122
 
123
	for (fd = 0; fd < NOFILE; fd++)
124
		close (fd);
125
 
126
	errno = 0;
127
	chdir ("/");
128
	umask (0);
14 andreas 129
#ifdef SIGCLD
2 andreas 130
	if (ignsigcld)
131
		signal (SIGCLD, SIG_IGN);
19 andreas 132
	else
133
		signal(SIGCLD, &sig_child);
14 andreas 134
#endif
4 andreas 135
	/* Create PID file */
2 andreas 136
	if ((fd = open(configs.Pidfile, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
137
	{
138
		syslog(LOG_WARNING, "Can't create PID file %s: %s", configs.Pidfile, strerror(errno));
139
		return;
140
	}
141
 
142
	sprintf(&hv0[0], "%d", getpid());
143
	write(fd, hv0, strlen(hv0));
144
	close(fd);
145
}
146
 
21 andreas 147
void sig_child (int x)
2 andreas 148
{
149
#if defined(BSD) && !defined(sinix) && !defined(Linux)
150
	int pid;
19 andreas 151
	int status;
2 andreas 152
 
19 andreas 153
	while ((pid = wait4 (0, &status, WNOHANG, (struct rusage *)0)) > 0)
154
		sleep(1);
155
#endif
156
}
2 andreas 157
 
158
void changeToUser(char *usr, char *grp)
159
{
160
	gid_t gr_gid;
161
 
162
	if (usr && strlen(usr))
163
	{
164
		/* get uid */
165
		struct passwd *userpwd;
19 andreas 166
		struct group *usergrp = NULL;
2 andreas 167
 
168
		if ((userpwd = getpwnam(usr)) == NULL)
169
		{
170
			syslog(LOG_DAEMON, "no such user: %s", usr);
171
			exit(EXIT_FAILURE);
172
		}
173
 
19 andreas 174
		if (grp != NULL && strlen(grp) && (usergrp = getgrnam(grp)) == NULL)
2 andreas 175
		{
176
			if (grp && strlen(grp))
177
				syslog(LOG_WARNING, "no such group: %s", grp);
178
 
179
			gr_gid = userpwd->pw_gid;
180
		}
19 andreas 181
		else if (usergrp != NULL)
182
			gr_gid = usergrp->gr_gid;
2 andreas 183
		else
19 andreas 184
			gr_gid = userpwd->pw_gid;
2 andreas 185
 
186
		if (setgid(gr_gid) == -1)
187
		{
188
			syslog(LOG_DAEMON, "cannot setgid of user %s: %s", usr, strerror(errno));
189
			exit(EXIT_FAILURE);
190
		}
191
 
192
#ifdef _BSD_SOURCE
193
 
194
		/* init suplementary groups
195
		 * (must be done before we change our uid)
196
		 */
197
		if (initgroups(usr, gr_gid) == -1)
198
			syslog(LOG_DAEMON, "cannot init suplementary groups of user %s: %s", usr, strerror(errno));
199
 
200
#endif
201
 
202
		/* set uid */
203
		if (setuid(userpwd->pw_uid) == -1)
204
		{
205
			syslog(LOG_DAEMON, "cannot change to uid of user %s: %s\n", usr, strerror(errno));
206
			exit(EXIT_FAILURE);
207
		}
208
 
209
		if (userpwd->pw_dir)
210
			setenv("HOME", userpwd->pw_dir, 1);
211
	}
212
}
213
 
214
void *pthr_parser(void *pV_data)
215
{
14 andreas 216
	char str[INET_ADDRSTRLEN];
4 andreas 217
	/* socket structure */
2 andreas 218
	struct sockaddr_in client1, server1;
219
	struct servent *serviceInfo;
220
	int s1, s;
221
	socklen_t length;
19 andreas 222
/*	struct SOCKETS soc; */
2 andreas 223
 
4 andreas 224
	/* socket server */
2 andreas 225
	if (configs.port > 0)
226
		server1.sin_port = htons(configs.port);
3 andreas 227
	else if ((serviceInfo = getservbyname ("mdb", "tcp")))
2 andreas 228
		server1.sin_port = serviceInfo->s_port;
229
	else
230
	{
231
		syslog(LOG_DAEMON,"Error: No TCP port defined!");
58 andreas 232
		pthread_exit(NULL);
2 andreas 233
		exit(EXIT_FAILURE);
234
	}
235
 
236
	server1.sin_family = AF_INET;
237
	server1.sin_addr.s_addr = INADDR_ANY;
238
	s = socket(AF_INET,SOCK_STREAM,0);
239
 
240
	if (s < 0)
241
	{
242
		syslog (LOG_DAEMON, "Error in socket: %s",strerror(errno));
58 andreas 243
		pthread_exit(NULL);
2 andreas 244
		exit(EXIT_FAILURE);
245
	}
246
 
247
	if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
248
	{
249
		syslog (LOG_DAEMON, "Error in bind: %s", strerror(errno));
58 andreas 250
		pthread_exit(NULL);
2 andreas 251
		exit(EXIT_FAILURE);
252
	}
253
 
254
	if (listen (s, 5) < 0)
255
	{
256
		syslog (LOG_DAEMON, "Error in listen: %s", strerror(errno));
58 andreas 257
		pthread_exit(NULL);
2 andreas 258
		exit(EXIT_FAILURE);
259
	}
260
 
261
	length = sizeof(client1);
262
	syslog (LOG_DEBUG, "Server ready: %d",s);
263
 
264
	while (1)
265
	{
55 andreas 266
/*		int childpid, status; */
19 andreas 267
 
2 andreas 268
		if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
269
		{
270
			syslog (LOG_DAEMON, "Error in accept: %d: %s", s1, strerror(errno));
271
			continue;
272
		}
273
 
274
		inet_ntop(AF_INET, &(client1.sin_addr), str, INET_ADDRSTRLEN);
275
		syslog (LOG_INFO, "Connected to client %s", str);
276
		soc.sockfd = s;
277
		soc.newfd = s1;
6 andreas 278
 
55 andreas 279
		/* start a new thread to parse the commands */
280
		if (pthread_create(&pthr_cmds, NULL, processCommands, (void *)&soc) != 0)
281
		{
282
			syslog (LOG_DAEMON,"Creation of thread \"pthr_cmds\" failed!");
283
			close(s1);
284
			close(s);
57 andreas 285
			pthread_exit(NULL);
55 andreas 286
			return NULL;
287
		}
288
 
289
/*		if ((childpid = fork()) < 0)
19 andreas 290
			syslog(LOG_DAEMON, "Can't fork a child: %s", strerror(errno));
291
 
292
		if (childpid == 0)
2 andreas 293
		{
55 andreas 294
			/ Child process /
19 andreas 295
			processCommands((void *)&soc);
296
			exit(EXIT_SUCCESS);
297
		}
22 andreas 298
 
299
#if defined(BSD) && !defined(Linux)
300
		while (wait3 (&status, WNOHANG, (struct rusage *)0) > 0)
301
			sleep(1);
302
#else
303
		while (waitpid(-1, &status, WNOHANG) > 0)
304
			sleep(1);
305
#endif
55 andreas 306
		close(s1); */
2 andreas 307
	}
308
 
309
	close (s);
57 andreas 310
	pthread_exit(NULL);
2 andreas 311
	return NULL;
312
}