Subversion Repositories heating

Rev

Rev 3 | Rev 9 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 3 Rev 5
Line 37... Line 37...
37
#include <sys/ioctl.h>
37
#include <sys/ioctl.h>
38
#include <sys/param.h>
38
#include <sys/param.h>
39
#include <pwd.h>
39
#include <pwd.h>
40
#include <grp.h>
40
#include <grp.h>
41
#include "config.h"
41
#include "config.h"
-
 
42
#include "heating.h"
42
 
43
 
43
struct SOCKETS
44
struct SOCKETS
44
{
45
{
45
	int sockfd;
46
	int sockfd;
46
	int newfd;
47
	int newfd;
Line 51... Line 52...
51
void sig_handler(int sig);
52
void sig_handler(int sig);
52
void changeToUser(const char *usr, const char *grp);
53
void changeToUser(const char *usr, const char *grp);
53
void sig_child ();
54
void sig_child ();
54
 
55
 
55
void *pthr_parser(void *pV_data);
56
void *pthr_parser(void *pV_data);
56
void *pthr_Probe(void * pV_data);
57
void *pthr_Heat(void * pV_data);
57
void *processCommands(void *pV_data);
58
void *processCommands(void *pV_data);
58
int parseCommand(int s1, char *buf);
59
int parseCommand(int s1, char *buf);
59
 
60
 
-
 
61
static pthread_t pthr_pars, pthr_heat, pthr_process;
-
 
62
static pthread_mutex_t fastmutex_proc = PTHREAD_MUTEX_INITIALIZER;
-
 
63
 
-
 
64
heating *heat;
60
struct SOCKETS soc;				// The network sockets to be passed to a thread
65
struct SOCKETS soc;				// The network sockets to be passed to a thread
61
 
66
 
62
int main(int argc, char **argv) 
67
int main(int argc, char **argv) 
63
{
68
{
-
 
69
	heat = nullptr;
64
	// First read config file and check if it was ok
70
	// First read config file and check if it was ok
65
	config *cfg = new config();
71
	config *cfg = new config();
66
	
72
	
67
	if (!cfg->is_initialized())
73
	if (!cfg->is_initialized())
68
	{
74
	{
69
		std::cerr << "Error reading config file! Make sure there is one and that it is readable by root!" << std::endl;
75
		std::cerr << "Error reading config file! Make sure there is one and that it is readable by root!" << std::endl;
70
		exit (0);
76
		delete (cfg);
-
 
77
		return 1;
71
	}
78
	}
72
	
79
	
73
	CONFIGURE configs = cfg->getConfig();
80
	CONFIGURE configs = cfg->getConfig();
74
	// Daemonize and run in background
81
	// Daemonize and run in background
75
	daemon_start(0);
82
	daemon_start(0);
Line 78... Line 85...
78
	delete (cfg);
85
	delete (cfg);
79
	// Now start our Thread
86
	// Now start our Thread
80
	if (pthread_create(&pthr_pars, NULL, pthr_parser, (void *)0) != 0)
87
	if (pthread_create(&pthr_pars, NULL, pthr_parser, (void *)0) != 0)
81
	{
88
	{
82
		syslog (LOG_DAEMON,"Create of thread \"pthr_parser\" failed!");
89
		syslog (LOG_DAEMON,"Create of thread \"pthr_parser\" failed!");
83
		return 1;
90
		return 2;
84
	}
91
	}
85
	
92
	
86
	while (1)
93
	while (1)
87
		sleep(3600);
94
		sleep(3600);
88
	
95
	
89
	return 0;
96
	return 0;
90
}
97
}
-
 
98
 
-
 
99
/*
-
 
100
 * Detach application from console and make it a daemon.
-
 
101
 */
-
 
102
void daemon_start (int ignsigcld)
-
 
103
{
-
 
104
	int childpid, fd;
-
 
105
	char hv0[128];
-
 
106
	
-
 
107
	if (getpid () == 1)
-
 
108
		goto out;
-
 
109
 
-
 
110
	#ifdef SIGTTOU
-
 
111
	signal (SIGTTOU, SIG_IGN);
-
 
112
	#endif
-
 
113
	#ifdef SIGTTIN
-
 
114
	signal (SIGTTIN, SIG_IGN);
-
 
115
	#endif
-
 
116
	#ifdef SIGTSTP
-
 
117
	signal (SIGTSTP, SIG_IGN);
-
 
118
	#endif
-
 
119
 
-
 
120
	if ((childpid = fork ()) < 0)
-
 
121
		fprintf (stderr, "Can't fork this child\n");
-
 
122
	else if (childpid > 0)
-
 
123
		exit (0);
-
 
124
 
-
 
125
	if (setpgrp () == -1)
-
 
126
		fprintf (stderr, "Can't change process group\n");
-
 
127
 
-
 
128
	signal (SIGHUP, SIG_IGN);
-
 
129
 
-
 
130
	if ((childpid = fork ()) < 0)
-
 
131
		syslog (LOG_DAEMON, "Can't fork second child");
-
 
132
	else if (childpid > 0)
-
 
133
		exit (0);            /* first child */
-
 
134
 
-
 
135
	/* second child */
-
 
136
out:
-
 
137
	for (fd = 0; fd < NOFILE; fd++)
-
 
138
		close (fd);
-
 
139
 
-
 
140
	errno = 0;
-
 
141
	chdir ("/");
-
 
142
	umask (0);
-
 
143
 
-
 
144
	if (ignsigcld)
-
 
145
		signal (SIGCLD, SIG_IGN);
-
 
146
 
-
 
147
	// Define a signal handler for terminate signals
-
 
148
	if (signal(SIGTERM, sig_handler) == SIG_ERR)
-
 
149
		syslog(LOG_WARNING,"Can't catch signal SIGTERM!");
-
 
150
 
-
 
151
	// Create PID file
-
 
152
	if ((fd = open(Configure.pidfile, O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
-
 
153
	{
-
 
154
		syslog(LOG_WARNING,"Can't create PID file %s: %s",Configure.pidfile, strerror(errno));
-
 
155
		return;
-
 
156
	}
-
 
157
 
-
 
158
	sprintf(hv0, "%d", getpid());
-
 
159
	write(fd, hv0, strlen(hv0));
-
 
160
	close(fd);
-
 
161
}
-
 
162
 
-
 
163
void sig_child ()
-
 
164
{
-
 
165
#if defined(BSD) && !defined(sinix) && !defined(Linux)
-
 
166
	int pid;
-
 
167
	union wait status;
-
 
168
 
-
 
169
	while ((pid = wait3 (&status, WNOHANG, (struct rusage *)0)) > 0)
-
 
170
		;
-
 
171
#endif
-
 
172
}
-
 
173
 
-
 
174
/*
-
 
175
 * This is the signal handler who disconnects from network and terminates
-
 
176
 * this daemon
-
 
177
 */
-
 
178
void sig_handler(int sig)
-
 
179
{
-
 
180
	if (sig == SIGTERM || sig == SIGKILL)
-
 
181
	{
-
 
182
		syslog(LOG_INFO, "Terminating program! Killed by signal %d", sig);
-
 
183
 
-
 
184
		if (heat != nullptr)
-
 
185
		{
-
 
186
			heat->stopRun();
-
 
187
			sleep(2);
-
 
188
		}
-
 
189
 
-
 
190
		exit(0);
-
 
191
	}
-
 
192
}
-
 
193
 
-
 
194
void changeToUser(const char *usr, const char *grp)
-
 
195
{
-
 
196
gid_t gr_gid;
-
 
197
 
-
 
198
	if (usr && strlen(usr))
-
 
199
	{
-
 
200
		/* get uid */
-
 
201
		struct passwd *userpwd;
-
 
202
		struct group *usergrp;
-
 
203
 
-
 
204
		if ((userpwd = getpwnam(usr)) == NULL)
-
 
205
		{
-
 
206
			syslog(LOG_DAEMON,"no such user: %s", usr);
-
 
207
			exit(EXIT_FAILURE);
-
 
208
		}
-
 
209
 
-
 
210
		if (!grp || !strlen(grp) || (usergrp = getgrnam(grp)) == NULL)
-
 
211
		{
-
 
212
			if (grp && strlen(grp))
-
 
213
				syslog(LOG_WARNING,"no such group: %s", grp);
-
 
214
			
-
 
215
			gr_gid = userpwd->pw_gid;
-
 
216
		}
-
 
217
		else
-
 
218
			gr_gid = usergrp->gr_gid;
-
 
219
 
-
 
220
		if (setgid(gr_gid) == -1)
-
 
221
		{
-
 
222
			syslog(LOG_DAEMON,"cannot setgid of user %s: %s", usr, strerror(errno));
-
 
223
			//	      exit(EXIT_FAILURE);
-
 
224
		}
-
 
225
 
-
 
226
#ifdef _BSD_SOURCE
-
 
227
		/* init suplementary groups
-
 
228
		 * (must be done before we change our uid)
-
 
229
		 */
-
 
230
		if (initgroups(usr, gr_gid) == -1)
-
 
231
			syslog(LOG_DAEMON,"Cannot init suplementary groups of user %s: %s", usr, strerror(errno));
-
 
232
#endif
-
 
233
 
-
 
234
		/* set uid */
-
 
235
		if (setuid(userpwd->pw_uid) == -1)
-
 
236
		{
-
 
237
			syslog(LOG_DAEMON,"Cannot change to uid of user %s: %s\n", usr, strerror(errno));
-
 
238
			//	      exit(EXIT_FAILURE);
-
 
239
		}
-
 
240
 
-
 
241
		if(userpwd->pw_dir)
-
 
242
			setenv("HOME", userpwd->pw_dir, 1);
-
 
243
	}
-
 
244
}
-
 
245
 
-
 
246
void *pthr_Heat(void * pV_data)
-
 
247
{
-
 
248
	pthread_mutex_lock (&fastmutex_proc);
-
 
249
	
-
 
250
	if (heat != nullptr && !heat->statusRun())
-
 
251
		heat->run();
-
 
252
	
-
 
253
	pthread_mutex_unlock(&fastmutex_proc);
-
 
254
}
-
 
255
 
-
 
256
void *pthr_parser(void *pV_data)
-
 
257
{
-
 
258
char ch, str[INET_ADDRSTRLEN];
-
 
259
// socket structure
-
 
260
struct sockaddr_in client1, server1;
-
 
261
struct servent *serviceInfo;
-
 
262
int s1, s;
-
 
263
socklen_t length;
-
 
264
 
-
 
265
	// socket server
-
 
266
	if (Configure.port > 0)
-
 
267
		server1.sin_port = htons(Configure.port);
-
 
268
	else if ((serviceInfo = getservbyname ("heating", "tcp")))
-
 
269
		server1.sin_port = serviceInfo->s_port;
-
 
270
	else
-
 
271
	{
-
 
272
		syslog(LOG_DAEMON,"Error: No TCP port defined!");
-
 
273
		exit(EXIT_FAILURE);
-
 
274
	}
-
 
275
 
-
 
276
	server1.sin_family = AF_INET;
-
 
277
	server1.sin_addr.s_addr = INADDR_ANY;
-
 
278
	s = socket(AF_INET,SOCK_STREAM,0);
-
 
279
 
-
 
280
	if (s < 0)
-
 
281
	{
-
 
282
		syslog (LOG_DAEMON, "Error in socket: %s",strerror(errno));
-
 
283
		exit(EXIT_FAILURE);
-
 
284
	}
-
 
285
 
-
 
286
	if (bind (s, (struct sockaddr *)&server1, sizeof (server1)) < 0)
-
 
287
	{
-
 
288
		syslog (LOG_DAEMON, "Error in bind: %s", strerror(errno));
-
 
289
		exit(EXIT_FAILURE);
-
 
290
	}
-
 
291
 
-
 
292
	if (listen (s, 5) < 0)
-
 
293
	{
-
 
294
		syslog (LOG_DAEMON, "Error in listen: %s", strerror(errno));
-
 
295
		exit(EXIT_FAILURE);
-
 
296
	}
-
 
297
 
-
 
298
	length = sizeof(client1);
-
 
299
 
-
 
300
	if (Configure.debug)
-
 
301
		syslog (LOG_DEBUG, "Server ready: %d",s);
-
 
302
	// Initialize and start the probe
-
 
303
	if (heat == nullptr)
-
 
304
		heat = new heating();
-
 
305
 
-
 
306
	if (pthread_create(&pthr_heat, NULL, pthr_Heat, (void *)0) != 0)
-
 
307
	{
-
 
308
		syslog (LOG_DAEMON,"Create of thread \"pthr_heat\" failed!");
-
 
309
		close (s);
-
 
310
		exit(EXIT_FAILURE);
-
 
311
	}
-
 
312
	
-
 
313
	if (Configure.debug)
-
 
314
		syslog(LOG_DEBUG, "Heating was initialized and is polling ...");
-
 
315
	
-
 
316
	while (heat->statusRun())
-
 
317
	{
-
 
318
		if ((s1 = accept (s, (struct sockaddr *)&client1, &length)) < 0)
-
 
319
		{
-
 
320
			syslog (LOG_DAEMON, "Error in accept: %d: %s", s1, strerror(errno));
-
 
321
			continue;
-
 
322
		}
-
 
323
		
-
 
324
		inet_ntop(AF_INET, &(client1.sin_addr), str, INET_ADDRSTRLEN);
-
 
325
		
-
 
326
		if (Configure.debug)
-
 
327
			syslog (LOG_DEBUG, "Connected to client %s", str);
-
 
328
		
-
 
329
		soc.ip[0] = 0;
-
 
330
		soc.sockfd = s;
-
 
331
		soc.newfd = s1;
-
 
332
		
-
 
333
		// This thread will parse the commands comming to this daemon.
-
 
334
		if (pthread_create(&pthr_process, NULL, processCommands, (void *)&soc) != 0)
-
 
335
		{
-
 
336
			syslog (LOG_DAEMON,"Create of thread \"processCommands\" failed!");
-
 
337
			close(s1);
-
 
338
			soc.newfd = 0;
-
 
339
		}
-
 
340
	}
-
 
341
 
-
 
342
	close (s);
-
 
343
	soc.sockfd = 0;
-
 
344
	delete heat;
-
 
345
	heat = nullptr;
-
 
346
	return NULL;
-
 
347
}
-
 
348
 
-
 
349
void *processCommands(void *pV_data)
-
 
350
{
-
 
351
char ch, buf[128];
-
 
352
int i, s1, s;
-
 
353
bool initialized = false;
-
 
354
struct SOCKETS *socket;
-
 
355
 
-
 
356
	socket = (struct SOCKETS *)pV_data;
-
 
357
	s1 = socket->newfd;
-
 
358
	s = socket->sockfd;
-
 
359
	heat->setHandle(s1);
-
 
360
 
-
 
361
	if (Configure.debug)
-
 
362
		syslog(LOG_DEBUG, "Starting to process commands ...");
-
 
363
 
-
 
364
	memset(&buf[0], 0, sizeof(buf));
-
 
365
	i = 0;
-
 
366
	write(s1, "HEATING:READY;", 11);
-
 
367
 
-
 
368
	while (heat->statusRun() && read(s1,&ch,1) > 0)
-
 
369
	{
-
 
370
		if (i < (int)(sizeof(buf) - 1))
-
 
371
		{
-
 
372
			buf[i] = ch;
-
 
373
			
-
 
374
			if (ch < 0x0a || ch == 0x0b || ch == 0x0c)
-
 
375
				continue;
-
 
376
 
-
 
377
			if (ch == ';' || ch == 0x0d || ch == 0x0a)
-
 
378
			{
-
 
379
				int pstat;
-
 
380
 
-
 
381
				buf[i] = 0;
-
 
382
 
-
 
383
				if (!strncmp(buf, "quit", 4))
-
 
384
					break;
-
 
385
 
-
 
386
				if ((pstat = parseCommand(s1, buf)) == 0)
-
 
387
				{
-
 
388
					char hv0[128];
-
 
389
 
-
 
390
					sprintf(&hv0[0],"INVALID COMMAND:%s;",buf);
-
 
391
					write(s1,hv0,strlen(hv0));
-
 
392
				}
-
 
393
				else if (pstat == 2)
-
 
394
					write(s1, "NAK;", 4);
-
 
395
				else
-
 
396
					write(s1,"OK;",3);
-
 
397
 
-
 
398
				memset(&buf[0], 0, sizeof(buf));
-
 
399
				i = 0;
-
 
400
				continue;
-
 
401
			}
-
 
402
		}
-
 
403
 
-
 
404
		i++;
-
 
405
	}
-
 
406
 
-
 
407
	heat->removeHandle(s1);
-
 
408
	close(s1);
-
 
409
	socket->newfd = 0;
-
 
410
}
-
 
411
 
-
 
412
int parseCommand(int s1, char *buf)
-
 
413
{
-
 
414
std::string line(buf);
-
 
415
char hv0[64];
-
 
416
std::string vname, vcontent;
-
 
417
helper help;
-
 
418
 
-
 
419
	if (line.find(":") != std::string::npos)
-
 
420
	{
-
 
421
		vname = line.substr(0, line.find(":"));
-
 
422
		vcontent = line.substr(line.find(":") + 1);
-
 
423
 
-
 
424
		if (Configure.debug)
-
 
425
			syslog(LOG_DEBUG, "Command: %s, Content: %s", vname.c_str(), vcontent.c_str());
-
 
426
	}
-
 
427
	else
-
 
428
	{
-
 
429
		vname = line;
-
 
430
		vcontent = "";
-
 
431
 
-
 
432
		if (Configure.debug)
-
 
433
			syslog(LOG_DEBUG, "Command only: %s", vname.c_str());
-
 
434
	}
-
 
435
 
-
 
436
	// INCREMENT:<room>;
-
 
437
	if (vname.compare("INCREMENT") == 0 && vcontent.length() > 0)
-
 
438
	{
-
 
439
		int room = atoi(vcontent.c_str());
-
 
440
		heat->incSoll(room);
-
 
441
		return 1;
-
 
442
	}
-
 
443
 
-
 
444
	// DECREMENT:<room>;
-
 
445
	if (vname.compare("DECREMENT") == 0 && vcontent.length() > 0)
-
 
446
	{
-
 
447
		int room = atoi(vcontent.c_str());
-
 
448
		heat->decSoll(room);
-
 
449
		return 1;
-
 
450
	}
-
 
451
 
-
 
452
	// GET CONFIG;
-
 
453
	if (vname.compare("GET CONFIG") == 0)
-
 
454
	{
-
 
455
		heat->getConfig(s1);
-
 
456
		return 1;
-
 
457
	}
-
 
458
 
-
 
459
	// POWER:<ON|OFF>;
-
 
460
	if (vname.compare("POWER") == 0)
-
 
461
	{
-
 
462
		if (vcontent.compare("ON") == 0)
-
 
463
			heat->switchOnOff(true);
-
 
464
		else
-
 
465
			heat->switchOnOff(false);
-
 
466
 
-
 
467
		return 1;
-
 
468
	}
-
 
469
 
-
 
470
	// TODO: SET SOLL:<room>:<soll>; --> Solltemperatur direkt setzen
-
 
471
	// TODO: SET NIGHT:<room>:<soll>;
-
 
472
	// TODO: SET MINIMAL:<room>:<soll>;
-
 
473
	// TODO: NIGHT:<soll>;
-
 
474
	// TODO: MINIMAL:<soll>;
-
 
475
	return 0;
-
 
476
}