Subversion Repositories mdb

Rev

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