Subversion Repositories mdb

Rev

Rev 59 | 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
 
60 andreas 71
	/* Prepare the thread attributes */
59 andreas 72
	if (pthread_attr_init(&pattr) != 0)
73
	{
74
		syslog(LOG_DAEMON,"Error getting thread attributes.");
75
		return FALSE;
76
	}
77
 
78
	if (pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED) != 0)
79
	{
80
		syslog(LOG_DAEMON,"Error setting thread attributes.");
81
		return FALSE;
82
	}
83
 
4 andreas 84
	/* Now start our Thread */
59 andreas 85
	if (pthread_create(&pthr_pars, &pattr, pthr_parser, (void *)0) != 0)
2 andreas 86
	{
87
		syslog (LOG_DAEMON, "Create of thread \"pthr_parser\" failed!");
88
		return 1;
89
	}
90
 
91
	while (1)
92
		sleep(3600);
93
 
94
	return 0;
95
}
96
 
97
/*
98
 * Detach application from console and make it a daemon.
99
 */
100
void daemon_start (int ignsigcld)
101
{
102
	int childpid, fd;
103
	char hv0[64];
104
 
105
	if (getpid () == 1)
106
		goto out;
107
 
108
#ifdef SIGTTOU
109
	signal (SIGTTOU, SIG_IGN);
110
#endif
111
#ifdef SIGTTIN
112
	signal (SIGTTIN, SIG_IGN);
113
#endif
114
#ifdef SIGTSTP
115
	signal (SIGTSTP, SIG_IGN);
116
#endif
117
 
118
	if ((childpid = fork ()) < 0)
119
		fprintf (stderr, "Can't fork this child\n");
120
	else if (childpid > 0)
19 andreas 121
		exit (0);            /* Parent */
2 andreas 122
 
123
	if (setpgrp () == -1)
124
		fprintf (stderr, "Can't change process group\n");
125
 
126
	signal (SIGHUP, SIG_IGN);
127
 
128
	if ((childpid = fork ()) < 0)
129
		syslog (LOG_DAEMON, "Can't fork second child");
130
	else if (childpid > 0)
131
		exit (0);            /* first child */
132
 
133
	/* second child */
134
out:
135
 
136
	for (fd = 0; fd < NOFILE; fd++)
137
		close (fd);
138
 
139
	errno = 0;
140
	chdir ("/");
141
	umask (0);
14 andreas 142
#ifdef SIGCLD
2 andreas 143
	if (ignsigcld)
144
		signal (SIGCLD, SIG_IGN);
19 andreas 145
	else
146
		signal(SIGCLD, &sig_child);
14 andreas 147
#endif
4 andreas 148
	/* Create PID file */
2 andreas 149
	if ((fd = open(configs.Pidfile, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
150
	{
151
		syslog(LOG_WARNING, "Can't create PID file %s: %s", configs.Pidfile, strerror(errno));
152
		return;
153
	}
154
 
155
	sprintf(&hv0[0], "%d", getpid());
156
	write(fd, hv0, strlen(hv0));
157
	close(fd);
158
}
159
 
21 andreas 160
void sig_child (int x)
2 andreas 161
{
162
#if defined(BSD) && !defined(sinix) && !defined(Linux)
163
	int pid;
19 andreas 164
	int status;
2 andreas 165
 
19 andreas 166
	while ((pid = wait4 (0, &status, WNOHANG, (struct rusage *)0)) > 0)
167
		sleep(1);
168
#endif
169
}
2 andreas 170
 
171
void changeToUser(char *usr, char *grp)
172
{
173
	gid_t gr_gid;
174
 
175
	if (usr && strlen(usr))
176
	{
177
		/* get uid */
178
		struct passwd *userpwd;
19 andreas 179
		struct group *usergrp = NULL;
2 andreas 180
 
181
		if ((userpwd = getpwnam(usr)) == NULL)
182
		{
183
			syslog(LOG_DAEMON, "no such user: %s", usr);
184
			exit(EXIT_FAILURE);
185
		}
186
 
19 andreas 187
		if (grp != NULL && strlen(grp) && (usergrp = getgrnam(grp)) == NULL)
2 andreas 188
		{
189
			if (grp && strlen(grp))
190
				syslog(LOG_WARNING, "no such group: %s", grp);
191
 
192
			gr_gid = userpwd->pw_gid;
193
		}
19 andreas 194
		else if (usergrp != NULL)
195
			gr_gid = usergrp->gr_gid;
2 andreas 196
		else
19 andreas 197
			gr_gid = userpwd->pw_gid;
2 andreas 198
 
199
		if (setgid(gr_gid) == -1)
200
		{
201
			syslog(LOG_DAEMON, "cannot setgid of user %s: %s", usr, strerror(errno));
202
			exit(EXIT_FAILURE);
203
		}
204
 
205
#ifdef _BSD_SOURCE
206
 
207
		/* init suplementary groups
208
		 * (must be done before we change our uid)
209
		 */
210
		if (initgroups(usr, gr_gid) == -1)
211
			syslog(LOG_DAEMON, "cannot init suplementary groups of user %s: %s", usr, strerror(errno));
212
 
213
#endif
214
 
215
		/* set uid */
216
		if (setuid(userpwd->pw_uid) == -1)
217
		{
218
			syslog(LOG_DAEMON, "cannot change to uid of user %s: %s\n", usr, strerror(errno));
219
			exit(EXIT_FAILURE);
220
		}
221
 
222
		if (userpwd->pw_dir)
223
			setenv("HOME", userpwd->pw_dir, 1);
224
	}
225
}
226
 
227
void *pthr_parser(void *pV_data)
228
{
14 andreas 229
	char str[INET_ADDRSTRLEN];
4 andreas 230
	/* socket structure */
2 andreas 231
	struct sockaddr_in client1, server1;
232
	struct servent *serviceInfo;
233
	int s1, s;
234
	socklen_t length;
19 andreas 235
/*	struct SOCKETS soc; */
2 andreas 236
 
4 andreas 237
	/* socket server */
2 andreas 238
	if (configs.port > 0)
239
		server1.sin_port = htons(configs.port);
3 andreas 240
	else if ((serviceInfo = getservbyname ("mdb", "tcp")))
2 andreas 241
		server1.sin_port = serviceInfo->s_port;
242
	else
243
	{
244
		syslog(LOG_DAEMON,"Error: No TCP port defined!");
58 andreas 245
		pthread_exit(NULL);
2 andreas 246
		exit(EXIT_FAILURE);
247
	}
248
 
249
	server1.sin_family = AF_INET;
250
	server1.sin_addr.s_addr = INADDR_ANY;
251
	s = socket(AF_INET,SOCK_STREAM,0);
252
 
253
	if (s < 0)
254
	{
255
		syslog (LOG_DAEMON, "Error in socket: %s",strerror(errno));
58 andreas 256
		pthread_exit(NULL);
2 andreas 257
		exit(EXIT_FAILURE);
258
	}
259
 
260
	if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
261
	{
262
		syslog (LOG_DAEMON, "Error in bind: %s", strerror(errno));
58 andreas 263
		pthread_exit(NULL);
2 andreas 264
		exit(EXIT_FAILURE);
265
	}
266
 
267
	if (listen (s, 5) < 0)
268
	{
269
		syslog (LOG_DAEMON, "Error in listen: %s", strerror(errno));
58 andreas 270
		pthread_exit(NULL);
2 andreas 271
		exit(EXIT_FAILURE);
272
	}
273
 
274
	length = sizeof(client1);
275
	syslog (LOG_DEBUG, "Server ready: %d",s);
276
 
277
	while (1)
278
	{
55 andreas 279
/*		int childpid, status; */
19 andreas 280
 
2 andreas 281
		if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
282
		{
283
			syslog (LOG_DAEMON, "Error in accept: %d: %s", s1, strerror(errno));
284
			continue;
285
		}
286
 
287
		inet_ntop(AF_INET, &(client1.sin_addr), str, INET_ADDRSTRLEN);
288
		syslog (LOG_INFO, "Connected to client %s", str);
289
		soc.sockfd = s;
290
		soc.newfd = s1;
6 andreas 291
 
55 andreas 292
		/* start a new thread to parse the commands */
59 andreas 293
		if (pthread_create(&pthr_cmds, &pattr, processCommands, (void *)&soc) != 0)
55 andreas 294
		{
295
			syslog (LOG_DAEMON,"Creation of thread \"pthr_cmds\" failed!");
296
			close(s1);
297
			close(s);
57 andreas 298
			pthread_exit(NULL);
55 andreas 299
			return NULL;
300
		}
301
 
302
/*		if ((childpid = fork()) < 0)
19 andreas 303
			syslog(LOG_DAEMON, "Can't fork a child: %s", strerror(errno));
304
 
305
		if (childpid == 0)
2 andreas 306
		{
55 andreas 307
			/ Child process /
19 andreas 308
			processCommands((void *)&soc);
309
			exit(EXIT_SUCCESS);
310
		}
22 andreas 311
 
312
#if defined(BSD) && !defined(Linux)
313
		while (wait3 (&status, WNOHANG, (struct rusage *)0) > 0)
314
			sleep(1);
315
#else
316
		while (waitpid(-1, &status, WNOHANG) > 0)
317
			sleep(1);
318
#endif
55 andreas 319
		close(s1); */
2 andreas 320
	}
321
 
322
	close (s);
57 andreas 323
	pthread_exit(NULL);
2 andreas 324
	return NULL;
325
}