summaryrefslogtreecommitdiff
path: root/nfcommander.c
blob: 125b237ad03c073ddcd665a832348d4fc385e2e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdio.h>
#include <signal.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <errno.h>

#include "nfcommander.h"
#include "config.h"
#include "reader.h"
#include "control.h"
#include "command.h"

typedef union {
	struct {
		uint32_t system;
		uint32_t fd;
	} components;
	uint64_t u64;
} epoll_private_t;

static volatile sig_atomic_t shutdown_requested = 0;
static volatile sig_atomic_t pid_signaled = 0;
static int epoll_fd = -1;

static void signal_handler(int signum){
	if(signum == SIGCHLD){
		pid_signaled = 1;
	}
	else {
		shutdown_requested = 1;
	}
}

static int usage(char* fn){
	printf("NFCommander %s - trigger actions based on near-field tags\n",
			NFCOMMANDER_VERSION);
	printf("\tUsage: %s <config-file>\n", fn);
	return EXIT_FAILURE;
}

int core_manage_fd(int fd, int manage, notification_target_t system){
	epoll_private_t data = {
		.components.system = system,
		.components.fd = fd
	};

	struct epoll_event event = {
		.events = EPOLLIN,
		.data.u64 = data.u64
	};

	if(fd < 0){
		return 0;
	}

	if(epoll_ctl(epoll_fd, manage ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, fd, &event)){
		perror("core/epoll_mod");
		shutdown_requested = 1;
		return 1;
	}
	return 0;
}

int main(int argc, char** argv){
	size_t n;
	int event_count;
	epoll_private_t polldata;

	if(argc < 2){
		return usage(argv[0]);
	}

	//set up epoll instance
	struct epoll_event events[10];
	epoll_fd = epoll_create1(EPOLL_CLOEXEC);
	if(epoll_fd < 0){
		perror("core/epoll");
		return EXIT_FAILURE;
	}

	//read configuration
	if(config_read(argv[1])){
		//TODO cleanup
		return usage(argv[0]);
	}

	//start reader api
	if(reader_init()){
		//TODO cleanup
		return EXIT_FAILURE;
	}

	//start control api
	if(control_start()){
		printf("Failed to start control interface\n");
		//TODO cleanup
		return EXIT_FAILURE;
	}

	//handle signals
	signal(SIGINT, signal_handler);
	signal(SIGCHLD, signal_handler);
	signal(SIGPIPE, SIG_IGN);

	//handle events
	while(!shutdown_requested){
		event_count = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(struct epoll_event), 1000);
		if(event_count < 0){
			perror("core/poll");
			break;
		}

		for(n = 0; n < event_count; n++){
			polldata.u64 = events[n].data.u64;
			//TODO error checking
			switch(polldata.components.system){
				case system_control:
					control_handle(polldata.components.fd);
					break;
				case system_reader:
					reader_handle(polldata.components.fd);
					break;
				case system_command:
					command_handle(polldata.components.fd);
					break;
				default:
					printf("Unhandled target system for fd %d\n", polldata.components.fd);
					break;
			}
		}

		if(pid_signaled){
			pid_signaled = 0;
			command_reap();
		}
	}
	
	//clean up
	reader_free();
	control_free();
	command_free();
	config_free();
	close(epoll_fd);
	epoll_fd = -1;
}