Subversion Repositories mdb

Rev

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