6e146167b3a205c84f1a10ce4341cc3f7a8743f4
1 /*
2 * Copyright (C) 2013-2015 Texas Instruments Incorporated - http://www.ti.com/
3 *
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
15 * distribution.
16 *
17 * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
34 /* Standard includes */
35 #include <stdio.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41 #include <signal.h>
42 #include <fcntl.h>
43 #include <getopt.h>
44 #include <unistd.h>
46 #include <libdaemon/daemon.h>
48 /* Socket Includes */
49 #include "serverlogutil.h"
50 #include "sockutils.h"
51 #include "sockrmmsg.h"
53 /* RM includes */
54 #include <ti/drv/rm/rm.h>
55 #include <ti/drv/rm/rm_transport.h>
57 #define RMSERVER_DAEMON_PID_FILE_NAME "/var/run/rmServer/pid"
59 /* Error checking macro */
60 #define ERROR_CHECK(checkVal, resultVal, rmInstName, printMsg) \
61 if (resultVal != checkVal) { \
62 char errorMsgToPrint[] = printMsg; \
63 error_msg("%s : ", rmInstName); \
64 error_msg("%s with error code : %d\n", errorMsgToPrint, resultVal); \
65 exit(EXIT_FAILURE); \
66 }
68 /* logging errors */
69 #define error_msg(...) rmsrv_log(LOG_ERR, __func__, __FILE__, __LINE__, __VA_ARGS__);
70 /* logging warnings */
71 #define warning_msg(...) rmsrv_log(LOG_WARNING, __func__, __FILE__, __LINE__, __VA_ARGS__);
72 /* logging information */
73 #define info_msg(...) rmsrv_log(LOG_INFO, __func__, __FILE__, __LINE__, __VA_ARGS__);
74 /* logging debug information */
75 #define debug_msg(...) rmsrv_log(LOG_DEBUG, __func__, __FILE__, __LINE__, __VA_ARGS__);
77 #define LOG_APPEND(x) \
78 do { \
79 int len; \
80 len = MAX_PRE_LOG_BUF_LEN - strlen(rmsrv_log_buf); \
81 if (len > 0) { \
82 strncat(rmsrv_log_buf, x, len); \
83 } \
84 else { \
85 return; \
86 } \
87 } while(0)
89 /* RM registered transport mapping structure */
90 typedef struct trans_map_entry_s {
91 /* Registered RM transport handle */
92 Rm_TransportHandle trans_handle;
93 /* Remote socket tied to the transport handle */
94 sock_name_t *remote_sock;
95 /* Next entry in the transport map */
96 struct trans_map_entry_s *n;
97 } trans_map_entry_t;
99 /**********************************************************************
100 ********************** Global Variables ******************************
101 **********************************************************************/
103 /* RM Server instance name (must match with RM Global Resource List (GRL) and policies */
104 char server_name[RM_NAME_MAX_CHARS] = "RM_Server";
106 Rm_Handle server_h;
108 sock_h server_sock = NULL;
110 rmserver_cfg_t rmsrv_cfg;
112 char rmsrv_log_buf[MAX_PRE_LOG_BUF_LEN];
114 /**********************************************************************
115 ********************** External Variables ****************************
116 **********************************************************************/
118 extern int optind;
119 extern char *optarg;
121 /**********************************************************************
122 ************************** Server Functions **************************
123 **********************************************************************/
125 /* RM Server logging utility (need to move it to another file) */
126 void rmsrv_log(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
127 {
128 int len;
129 char lineno_a[32];
130 va_list args;
131 struct stat fbuf;
133 snprintf(lineno_a, MAX_PRE_LOG_BUF_LEN, "%d", lineNo);
135 rmsrv_log_buf[0] = 0;
137 LOG_APPEND(fileName);
138 LOG_APPEND(":");
139 LOG_APPEND(lineno_a);
140 LOG_APPEND(":");
141 LOG_APPEND(functionName);
142 LOG_APPEND(":");
144 len = MAX_PRE_LOG_BUF_LEN - strlen(rmsrv_log_buf);
145 if (len <= 0) {
146 return;
147 }
149 va_start(args, format);
150 vsnprintf(&rmsrv_log_buf[strlen(rmsrv_log_buf)], len, format, args);
151 va_end(args);
153 /* logfile reset if going over max_len */
154 if (fstat(fileno(rmsrv_cfg.logfile_p), &fbuf) == 0) {
155 if ((fbuf.st_size + strlen(rmsrv_log_buf)) > rmsrv_cfg.logfile_max_len) {
156 freopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+", rmsrv_cfg.logfile_p);
157 }
158 }
160 fprintf(rmsrv_cfg.logfile_p, "%s", rmsrv_log_buf);
161 fflush(rmsrv_cfg.logfile_p);
162 }
164 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
165 {
166 Rm_Packet *rm_pkt = NULL;
168 rm_pkt = calloc(1, sizeof(*rm_pkt));
169 if (!rm_pkt) {
170 error_msg("Failed to malloc RM packet (err: %s)\n",
171 strerror(errno));
172 return (NULL);
173 }
174 rm_pkt->pktLenBytes = pktSize;
175 *pktHandle = rm_pkt;
177 return(rm_pkt);
178 }
180 void transportFree (Rm_Packet *rm_pkt)
181 {
182 int32_t status;
184 if (rm_pkt) {
185 free (rm_pkt);
186 }
187 }
189 int32_t transportSend (Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
190 {
191 sock_name_t *client_sock_name = (sock_name_t *)appTransport;
192 Rm_Packet *rm_pkt = (Rm_Packet *)pktHandle;
194 if (sock_send(server_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, client_sock_name)) {
195 error_msg("Failed to send RM packet\n");
196 }
197 else {
198 /* Print resources after sending response */
199 Rm_resourceStatus(server_h, 1);
200 }
202 transportFree(rm_pkt);
203 return (0);
204 }
206 int rm_server_run(void *grl, void *policy, void *lin_dtb, int is_daemon)
207 {
208 Rm_InitCfg rm_init_cfg;
209 Rm_TransportCfg rm_trans_cfg;
210 int32_t rm_result;
211 trans_map_entry_t *trans_map = NULL;
212 trans_map_entry_t *new_map_entry;
213 trans_map_entry_t *map_index;
214 int retval;
215 int length = 0;
216 sock_name_t serv_sock_name;
217 sock_name_t client_sock_addr;
218 Rm_Packet *rm_pkt = NULL;
219 char pkt_src[RM_NAME_MAX_CHARS];
220 struct sockaddr_un client_addr;
221 int signal_fd = -1;
222 char rm_socket_name[] = RM_SERVER_SOCKET_NAME;
224 rmsrv_cfg.logfile_p = fopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+");
225 if (!rmsrv_cfg.logfile_p) {
226 printf("Error in opening log file %s (%s)", RMSERVER_DAEMON_LOG_FILE_NAME, strerror(errno));
227 }
229 debug_msg("Starting RM server");
231 /* Create the Server instance */
232 memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
233 rm_init_cfg.instName = server_name;
234 rm_init_cfg.instType = Rm_instType_SERVER;
235 rm_init_cfg.instCfg.serverCfg.globalResourceList = grl;
236 rm_init_cfg.instCfg.serverCfg.linuxDtb = lin_dtb;
237 rm_init_cfg.instCfg.serverCfg.globalPolicy = policy;
238 server_h = Rm_init(&rm_init_cfg, &rm_result);
239 ERROR_CHECK(RM_OK, rm_result, server_name, "Initialization failed\n");
241 debug_msg("RM Server initialized with name: %s", server_name);
243 Rm_resourceStatus(server_h, 1);
245 serv_sock_name.type = sock_name_e;
246 serv_sock_name.s.name = rm_socket_name;
247 server_sock = sock_open (&serv_sock_name);
248 if (!server_sock) {
249 error_msg("Error when opening socket %s", rm_socket_name);
250 return -1;
251 }
253 if (is_daemon){
254 signal_fd = daemon_signal_fd();
255 }
257 while(1) {
258 info_msg("Waiting for messages from Clients\n");
259 retval = sock_wait(server_sock, &length, NULL, signal_fd);
260 if (retval < 0) {
261 error_msg("Error in reading from socket\n");
262 goto loop_continue;
263 }
265 if (length < sizeof(rm_pkt)) {
266 error_msg("invalid RM message length %d\n", length);
267 goto loop_continue;
268 }
269 rm_pkt = calloc(1, length);
270 if (!rm_pkt) {
271 error_msg("can't malloc for recv'd RM message (err: %s)\n",
272 strerror(errno));
273 goto loop_continue;
274 }
276 client_sock_addr.type = sock_addr_e;
277 client_sock_addr.s.addr = &client_addr;
278 retval = sock_recv(server_sock, (char *)rm_pkt, length, &client_sock_addr);
279 if (retval != length) {
280 error_msg("recv RM pkt failed from socket, received = %d, expected = %d\n",
281 retval, length);
282 goto loop_continue;
283 }
285 info_msg("Received RM pkt of size %d bytes from socket %s\n", length, client_sock_addr.s.addr->sun_path);
286 if (Rm_receiveGetPktSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
287 info_msg(" RM pkt originated from %s instance\n", &pkt_src[0]);
288 }
289 if (Rm_receiveGetPktServiceSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
290 info_msg(" Service request within RM pkt originated from %s instance\n", &pkt_src[0]);
291 }
293 map_index = trans_map;
294 while(map_index != NULL) {
295 if (strncmp(map_index->remote_sock->s.addr->sun_path,
296 client_addr.sun_path,
297 sizeof(client_addr.sun_path)) == 0) {
298 break;
299 }
300 map_index = map_index->n;
301 }
303 if (!map_index) {
304 new_map_entry = calloc(1, sizeof(*new_map_entry));
305 new_map_entry->remote_sock = calloc(1, sizeof(sock_name_t));
306 new_map_entry->remote_sock->s.addr = calloc(1, sizeof(struct sockaddr_un));
307 new_map_entry->remote_sock->type = sock_addr_e;
308 memcpy(new_map_entry->remote_sock->s.addr, &client_addr, sizeof(struct sockaddr_un));
310 /* Register the Client with the Server instance */
311 rm_trans_cfg.rmHandle = server_h;
312 rm_trans_cfg.appTransportHandle = (Rm_AppTransportHandle)new_map_entry->remote_sock;
313 rm_trans_cfg.remoteInstType = Rm_instType_CLIENT;
314 rm_trans_cfg.transportCallouts.rmAllocPkt = transportAlloc;
315 rm_trans_cfg.transportCallouts.rmSendPkt = transportSend;
316 new_map_entry->trans_handle = Rm_transportRegister(&rm_trans_cfg, &rm_result);
318 new_map_entry->n = NULL;
320 if (trans_map == NULL) {
321 trans_map = new_map_entry;
322 }
323 else {
324 map_index = trans_map;
326 while(map_index->n != NULL) {
327 map_index = map_index->n;
328 }
329 map_index->n = new_map_entry;
330 }
332 map_index = new_map_entry;
333 }
335 /* Provide packet to RM Server for processing */
336 if (rm_result = Rm_receivePacket(map_index->trans_handle, rm_pkt)) {
337 error_msg("RM failed to process received packet: %d\n", rm_result);
338 }
340 loop_continue:
341 /* Cleanups */
342 length = 0;
343 transportFree(rm_pkt);
344 memset(&client_sock_addr, 0, sizeof(sock_name_t));
345 memset(&client_addr, 0, sizeof(struct sockaddr_un));
346 }
347 }
349 char *get_pid_file_name(void) {
350 static char pid_file_name[] = RMSERVER_DAEMON_PID_FILE_NAME;
352 return pid_file_name;
353 }
355 static void print_usage(char *appname)
356 {
357 printf ("Usage: %s [OPTION]... [GRL] [POLICY]\n", appname);
358 printf ("Run a resource manager server with the specified [GRL] and [POLICY]\n"
359 "[GRL] and [POLICY] must be device tree blob (DTB) files\n"
360 "Example: rmserver grl.dtb policy.dtb\n\n"
361 "Configuration:\n"
362 " -s, --logsize MAXLOGSIZE MAXLOGSIZE bytes will be written to the\n"
363 " log file before the log is reset. On\n"
364 " reset, the log file will be wiped.\n"
365 "\n"
366 " The default for MAXLOGSIZE is 8MB if\n"
367 " logsize is not specified\n"
368 "Optional Input:\n"
369 " -l, --lindtb [LINUX_DTB] Optionally, provide a Linux DTB file\n"
370 " that RM will use to reserve resources\n"
371 " for Linux. The GRL must have the\n"
372 " proper Linux DTB resource mappings\n"
373 " for this feature to work\n"
374 "Miscellaneous:\n"
375 " -n, --nodaemon do not daemonize, run in foreground\n"
376 " -k, --kill kill the existing daemon\n"
377 " -h, --help print this message\n"
378 "\n"
379 "rmserver will run as a daemon by default.\n\n");
380 }
382 int main(int argc, char *argv[])
383 {
384 int opt;
385 int daemonize = 1, kill = 0;
386 int fd;
387 struct stat file_stat;
388 pid_t pid;
389 char *grl_file = NULL;
390 char *policy_file = NULL;
391 char *lin_dtb_file = NULL;
392 void *grl = NULL;
393 void *policy = NULL;
394 void *lin_dtb = NULL;
396 const struct option longopts[] =
397 {
398 {"nodaemon", no_argument, 0, 'n'},
399 {"kill", no_argument, 0, 'k'},
400 {"help", no_argument, 0, 'h'},
401 {"lindtb", required_argument, 0, 'l'},
402 {"logsize", required_argument, 0, 's'},
403 {0, 0, 0, 0},
404 };
406 rmsrv_cfg.logfile_max_len = DEFAULT_LOG_LEN;
408 while((opt = getopt_long(argc, argv, "nkhl:s:", longopts, NULL)) != -1) {
409 switch (opt) {
410 case 'n':
411 daemonize = 0;
412 break;
413 case 'k':
414 kill = 1;
415 break;
416 case 'l':
417 lin_dtb_file = optarg;
418 break;
419 case 's':
420 rmsrv_cfg.logfile_max_len = strtol(optarg, NULL, 0);
421 break;
422 case 'h':
423 default:
424 print_usage(argv[0]);
425 exit(EXIT_SUCCESS);
426 }
427 }
429 if (!kill) {
430 /* GRL and Policy must always be provided */
431 if (optind == (argc - 2)) {
432 /* First must be GRL */
433 grl_file = argv[optind++];
434 /* Second must be policy */
435 policy_file = argv[optind++];
436 }
437 else {
438 printf("GRL or policy not provided\n\n");
439 print_usage(argv[0]);
440 exit(EXIT_FAILURE);
441 }
443 /* mmap the GRL */
444 fd = open(grl_file, O_RDONLY);
445 if (fd == -1) {
446 printf("Error opening GRL: %s\n", strerror(errno));
447 exit(EXIT_FAILURE);
448 }
449 /* Obtain file size */
450 if (fstat(fd, &file_stat) == -1) {
451 printf("Error getting GRL size\n");
452 exit(EXIT_FAILURE);
453 }
454 grl = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
455 if (grl == MAP_FAILED) {
456 printf("mmap of GRL failed\n");
457 exit(EXIT_FAILURE);
458 }
460 /* mmap the Global Policy */
461 fd = open(policy_file, O_RDONLY);
462 if (fd == -1) {
463 printf("Error opening Global Policy: %s\n", strerror(errno));
464 exit(EXIT_FAILURE);
465 }
466 /* Obtain file size */
467 if (fstat(fd, &file_stat) == -1) {
468 printf("Error getting Global Policy size\n");
469 exit(EXIT_FAILURE);
470 }
471 policy = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
472 if (policy == MAP_FAILED) {
473 printf("mmap of Global Policy failed\n");
474 exit(EXIT_FAILURE);
475 }
477 if (lin_dtb_file) {
478 /* mmap the Linux DTB if it was provided */
479 fd = open(lin_dtb_file, O_RDONLY);
480 if (fd == -1) {
481 printf("Error opening Linux DTB: %s\n", strerror(errno));
482 exit(EXIT_FAILURE);
483 }
484 /* Obtain file size */
485 if (fstat(fd, &file_stat) == -1) {
486 printf("Error getting Linux DTB size\n");
487 exit(EXIT_FAILURE);
488 }
489 lin_dtb = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
490 if (lin_dtb == MAP_FAILED) {
491 printf("mmap of Linux DTB failed\n");
492 exit(EXIT_FAILURE);
493 }
494 }
495 }
497 if (daemonize) {
498 if (kill) {
499 printf("Killing %s\n", argv[0]);
500 }
501 else {
502 printf("Starting %s\n", argv[0]);
503 }
505 /* Reset signal handlers */
506 if (daemon_reset_sigs(-1) < 0) {
507 printf("Failed to reset all signal handlers: %s\n", strerror(errno));
508 exit(EXIT_FAILURE);
509 }
511 /* Unblock signals */
512 if (daemon_unblock_sigs(-1) < 0) {
513 printf("Failed to unblock all signals: %s\n", strerror(errno));
514 exit(EXIT_FAILURE);
515 }
517 if (check_and_create_path (get_pid_file_name()) < 0) {
518 printf("Failed to create pid file path: %s\n", get_pid_file_name());
519 exit(EXIT_FAILURE);
520 }
522 /* set daemon id string */
523 daemon_log_ident = daemon_ident_from_argv0(argv[0]);
524 daemon_pid_file_proc = (daemon_pid_file_proc_t) get_pid_file_name;
526 if (kill) {
527 if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
528 printf("Failed to kill daemon: %s\n", strerror(errno));
529 exit(EXIT_FAILURE);
530 }
531 daemon_pid_file_remove();
532 exit(EXIT_SUCCESS);
533 }
535 /* Single instance */
536 if ((pid = daemon_pid_file_is_running()) >= 0) {
537 printf("Daemon already running on PID file %u\n", pid);
538 exit(EXIT_FAILURE);
539 }
541 if (daemon_retval_init() < 0) {
542 printf("Failed to create pipe.\n");
543 exit(EXIT_FAILURE);
544 }
546 /* Do the fork */
547 if ((pid = daemon_fork()) < 0) {
548 daemon_retval_done();
549 printf("Error in daemon fork %s\n", strerror(errno));
550 exit(EXIT_FAILURE);
551 }
552 else if (pid) { /* The parent */
553 int ret;
555 /* Wait for 20 seconds for the return value passed from the daemon process */
556 if ((ret = daemon_retval_wait(20)) < 0) {
557 printf("Could not receive return value from daemon process: %s\n", strerror(errno));
558 return -1;
559 }
561 printf("Daemon returned %i as return value.\n", ret);
562 return ret;
563 }
565 /* Close FDs */
566 if (daemon_close_all(-1) < 0) {
567 printf("Failed to close all file descriptors: %s\n", strerror(errno));
569 /* Send the error condition to the parent process */
570 daemon_retval_send(1);
571 goto close_n_exit;
572 }
574 /* Create the PID file */
575 if (daemon_pid_file_create() < 0) {
576 printf("Could not create PID file (%s).\n", strerror(errno));
577 daemon_retval_send(2);
578 goto close_n_exit;
579 }
581 /* Initialize signal handling */
582 if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) {
583 printf("Could not register signal handlers (%s).\n", strerror(errno));
584 daemon_retval_send(3);
585 goto close_n_exit;
586 }
588 /* Send OK to parent process */
589 daemon_retval_send(0);
590 }
591 else {
592 if (kill) {
593 printf("Can't kill undaemonized RM server\n");
594 exit(EXIT_FAILURE);
595 }
596 }
598 rm_server_run(grl, policy, lin_dtb, daemonize);
600 close_n_exit:
601 printf("Exiting %s daemon\n", argv[0]);
602 if (daemonize) {
603 daemon_retval_send(255);
604 daemon_signal_done();
605 daemon_pid_file_remove();
606 }
607 }