Commit | Line | Data |
---|---|---|
72af8b59 TB |
1 | /* Copyright (C) 2018 Thomas Balzer */ |
2 | ||
3 | /* This file is part of tomd. */ | |
4 | ||
5 | /* tomd is free software: you can redistribute it and/or modify */ | |
6 | /* it under the terms of the GNU General Public License as published by */ | |
7 | /* the Free Software Foundation, either version 3 of the License, or */ | |
8 | /* (at your option) any later version. */ | |
9 | ||
10 | /* tomd is distributed in the hope that it will be useful, */ | |
11 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 | /* GNU General Public License for more details. */ | |
14 | ||
15 | /* You should have received a copy of the GNU General Public License */ | |
16 | /* along with tomd. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #include <stddef.h> | |
19 | #include <stdio.h> | |
20 | #include <errno.h> | |
21 | #include <stdlib.h> | |
22 | #include <unistd.h> | |
23 | #include <string.h> | |
24 | #include <sys/un.h> | |
25 | #include <sys/stat.h> | |
26 | #include <sys/socket.h> | |
27 | ||
57c82614 TB |
28 | #include "../../include/macros.h" |
29 | #include "../../include/manifest.h" | |
30 | ||
72af8b59 TB |
31 | static void header(void) |
32 | { | |
57c82614 TB |
33 | tomd_p("Tom's Daemon, Copyright (C) 2018 Thomas Balzer"); |
34 | tomd_p("GPL v3 or later license."); | |
72af8b59 TB |
35 | } |
36 | ||
37 | static int sfd; | |
38 | static char socket_dirname[100]; | |
39 | static char socket_filename[100]; | |
40 | ||
41 | static void gen_socket_filename(void) | |
42 | { | |
43 | uid_t this_user_id = | |
44 | getuid(); | |
45 | sprintf(socket_dirname, | |
46 | "/run/user/%d/tomd", | |
47 | this_user_id); | |
48 | sprintf(socket_filename, | |
49 | "/run/user/%d/tomd/socket", | |
50 | this_user_id); | |
51 | ||
57c82614 | 52 | tomd_p("making dir '%s'", socket_dirname); |
72af8b59 TB |
53 | /* lazy way */ |
54 | char buf[100]; | |
55 | sprintf(buf, "mkdir -p %s", socket_dirname); | |
56 | system(buf); | |
57 | /* if(mkdir(socket_dirname, S_IRWXU) != 0){ */ | |
58 | /* perror("socket mkdir"); */ | |
59 | /* exit(EXIT_FAILURE); */ | |
60 | /* } */ | |
61 | ||
57c82614 | 62 | tomd_p("removing file '%s'", socket_filename); |
72af8b59 TB |
63 | if(unlink(socket_filename) != 0){ |
64 | if(errno == ENOENT){ | |
57c82614 | 65 | tomd_p("socket file doesn't exist"); |
72af8b59 | 66 | }else{ |
da4c0e62 | 67 | perror("[tomd] socket unlink"); |
72af8b59 TB |
68 | exit(EXIT_FAILURE); |
69 | } | |
70 | } | |
71 | } | |
72 | ||
57c82614 | 73 | static void socket_init(void) |
72af8b59 TB |
74 | { |
75 | gen_socket_filename(); | |
76 | ||
77 | /* listen on socket, respond to requests. */ | |
78 | /* perform all registered 'tick' operations */ | |
79 | sfd = | |
80 | socket(PF_LOCAL, /* namespace - local unix socket */ | |
81 | SOCK_STREAM, /* style */ | |
82 | 0); /* protocol */ | |
83 | ||
84 | if(sfd < 0){ | |
da4c0e62 | 85 | perror("[tomd] socket"); |
72af8b59 TB |
86 | exit(EXIT_FAILURE); |
87 | } | |
88 | ||
89 | struct sockaddr_un name; | |
90 | size_t size; | |
91 | ||
92 | name.sun_family = AF_LOCAL; | |
93 | strncpy(name.sun_path, | |
94 | socket_filename, | |
95 | sizeof(name.sun_path)); | |
96 | ||
97 | size = SUN_LEN(&name); | |
57c82614 | 98 | tomd_p("attempting to bind to '%s'", |
72af8b59 TB |
99 | socket_filename); |
100 | if(bind(sfd, | |
101 | (struct sockaddr *) &name, | |
102 | size) < 0){ | |
da4c0e62 | 103 | perror("[tomd] bind"); |
72af8b59 TB |
104 | exit(EXIT_FAILURE); |
105 | } | |
106 | ||
57c82614 TB |
107 | tomd_p("initialized tomd socket connections"); |
108 | } | |
109 | ||
110 | static void init(void) | |
111 | { | |
112 | socket_init(); | |
113 | load_jobs(); | |
72af8b59 TB |
114 | } |
115 | ||
81215080 TB |
116 | #define SEND_ACK { \ |
117 | int size; \ | |
118 | if(size = write(asfd, "ACK", sizeof "ACK") != sizeof "ACK") { \ | |
119 | tomd_p("didn't send as much as we though (%d != %d)", size, sizeof "ACK"); \ | |
120 | } \ | |
121 | } | |
122 | ||
72af8b59 TB |
123 | #define CHDIR 0 |
124 | #define DONT_CHDIR 1 | |
125 | #define CLOSE_PIPES 0 | |
126 | #define DONT_CLOSE_PIPES 1 | |
127 | ||
128 | static void daemonize(void) | |
129 | { | |
130 | /* daemon is in unistd. */ | |
131 | /* arg1 - 0 changes dir to / */ | |
132 | /* arg2 - 0 closes all pipes (/dev/null) */ | |
133 | /* WARNING > THIS BEHAVIOR IS SILENT AND EASY TO MISPLACE THE | |
134 | PROCESS */ | |
135 | daemon(DONT_CHDIR, DONT_CLOSE_PIPES); | |
136 | } | |
137 | ||
81215080 TB |
138 | #define READ_SOCKET {\ |
139 | int size = read(asfd, buf, 100); \ | |
140 | buf[size] = '\0'; \ | |
141 | } | |
142 | ||
143 | static int validate_sender(int asfd, char *buf) | |
144 | { | |
145 | READ_SOCKET; | |
146 | if(strcmp(buf, "client:tomc") == 0){ | |
147 | SEND_ACK; | |
148 | return 0; | |
149 | } | |
150 | tomd_p("received '%s' instead of client:tomc", buf); | |
151 | return -1; | |
152 | } | |
153 | ||
154 | enum requests { KILL, STATUS, STOP, START, UNKNOWN}; | |
155 | #define X(a, b) { a, b } | |
156 | static struct { | |
157 | char *str; | |
158 | enum requests request; | |
159 | } request_types[] = | |
160 | { | |
161 | X("kill", KILL), | |
162 | X("status", STATUS), | |
163 | X("start", START), | |
164 | X("stop", STOP), | |
165 | X(NULL, -1) | |
166 | }; | |
167 | #undef X | |
168 | ||
169 | static void handle_request(int asfd, char *buf) | |
170 | { | |
171 | READ_SOCKET; | |
172 | enum requests request = UNKNOWN; | |
173 | int i = 0; | |
174 | while(1){ | |
175 | if(request_types[i].str == NULL){ | |
176 | break; | |
177 | } | |
178 | ||
179 | tomd_p("loop [%d]: comparing '%s' to '%s'", | |
180 | i, buf, request_types[i].str); | |
181 | if(strcmp(buf, request_types[i].str) == 0){ | |
182 | request = request_types[i].request; | |
183 | break; | |
184 | } | |
185 | ||
186 | i++; | |
187 | } | |
188 | ||
189 | if(request == UNKNOWN){ | |
190 | tomd_p("unknown request type!"); | |
191 | return; | |
192 | } | |
193 | ||
194 | SEND_ACK; | |
195 | READ_SOCKET; | |
196 | // cross reference given name against known services | |
197 | tomd_p("looking up '%s'", buf); | |
198 | SEND_ACK; | |
199 | /* lookup_job(buf); */ | |
200 | } | |
201 | ||
202 | static void handle_connection(int asfd) | |
203 | { | |
204 | char buf[100] = {}; | |
205 | ||
206 | if(validate_sender(asfd, buf) != 0){ | |
207 | tomd_p("invalid sender."); | |
208 | return; | |
209 | } | |
210 | ||
211 | tomd_p("validated client"); | |
212 | handle_request(asfd, buf); | |
213 | ||
214 | close(asfd); | |
215 | } | |
216 | ||
72af8b59 TB |
217 | static void run(void) |
218 | { | |
219 | /* loop: */ | |
220 | /* 1 listen */ | |
221 | /* 2 accept/select */ | |
222 | /* 3 handle dgram */ | |
223 | int listen_bool = | |
224 | listen(sfd, | |
225 | 10); /* max connection limit is 10 for arbitrary reasons */ | |
226 | if(listen_bool == -1){ | |
da4c0e62 | 227 | perror("[tomd] listen"); |
72af8b59 TB |
228 | exit(EXIT_FAILURE); |
229 | } | |
230 | ||
81215080 | 231 | int i = 0; |
72af8b59 | 232 | for(;;){ |
da4c0e62 | 233 | struct sockaddr addr; |
81215080 TB |
234 | /* sometimes gives EINVAL if not initialized. */ |
235 | socklen_t size = sizeof(addr); | |
236 | tomd_p("accept loop [%d]", i++); | |
237 | errno = 0; | |
72af8b59 TB |
238 | int accept_sfd = |
239 | accept(sfd, | |
bd11173e | 240 | &addr, /* requester info */ |
da4c0e62 | 241 | &size); /* len of requester info */ |
72af8b59 | 242 | if(accept_sfd < 0){ |
81215080 TB |
243 | if(errno == EINVAL){ |
244 | tomd_p("EINVAL"); | |
245 | } | |
da4c0e62 | 246 | perror("[tomd] accept socket"); |
72af8b59 TB |
247 | exit(EXIT_FAILURE); |
248 | } | |
da4c0e62 | 249 | |
81215080 | 250 | handle_connection(accept_sfd); |
72af8b59 TB |
251 | } |
252 | } | |
253 | ||
254 | static void cleanup(void) | |
255 | { | |
256 | if(sfd >= 0){ | |
257 | close(sfd); | |
258 | } | |
259 | } | |
260 | ||
261 | int main(int argc, char **argv) | |
262 | { | |
263 | header(); | |
264 | init(); | |
7813ae49 | 265 | run_jobs(); |
952aba97 TB |
266 | daemonize(); |
267 | run(); | |
72af8b59 TB |
268 | cleanup(); |
269 | ||
270 | return EXIT_SUCCESS; | |
271 | } |