Updated tomd and tomc to do solid communication over sockets.
[tlb/tomd.git] / src / tomd / main.c
CommitLineData
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
31static 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
37static int sfd;
38static char socket_dirname[100];
39static char socket_filename[100];
40
41static 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 73static 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
110static 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
128static 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
143static 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
154enum requests { KILL, STATUS, STOP, START, UNKNOWN};
155#define X(a, b) { a, b }
156static 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
169static 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
202static 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
217static 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
254static void cleanup(void)
255{
256 if(sfd >= 0){
257 close(sfd);
258 }
259}
260
261int 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}