2 * Copyright (C) 2005-2009 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
8 * \file stat.c Functions used for sending/receiving the status of para_server
13 #include <sys/types.h>
17 #include "close_on_fork.h"
23 /** The maximal number of simultaneous connections. */
24 #define MAX_STAT_CLIENTS 50
26 extern char *stat_item_values[NUM_STAT_ITEMS];
28 /** Flags used for the stat command of para_audiod. */
29 enum stat_client_flags {
30 /** Enable parser-friendly output. */
31 SCF_PARSER_FRIENDLY = 1,
35 * Describes a status client of para_audiod.
37 * There's one such structure per audiod client that sent the 'stat' command.
39 * A status client is identified by its file descriptor. para_audiod
40 * keeps a list of connected status clients.
43 /** The stat client's file descriptor. */
45 /** Bitmask of those status items the client is interested in. */
47 /** See \ref stat_client flags. s*/
49 /** Its entry in the list of stat clients. */
50 struct list_head node;
53 static struct list_head client_list;
54 static int initialized;
55 static int num_clients;
57 /** The list of all status items used by para_{server,audiod,gui}. */
58 const char *status_item_list[] = {STATUS_ITEM_ARRAY};
60 static void dump_stat_client_list(void)
62 struct stat_client *sc;
66 list_for_each_entry(sc, &client_list, node)
67 PARA_INFO_LOG("stat client on fd %d\n", sc->fd);
70 * Add a status client to the list.
72 * \param fd The file descriptor of the client.
73 * \param mask Bitfield of status items for this client.
74 * \param parser_friendly Enable parser-friendly output mode.
76 * Only those status items having the bit set in \a mask will be
79 * \return Positive value on success, or -E_TOO_MANY_CLIENTS if
80 * the number of connected clients exceeds #MAX_STAT_CLIENTS.
82 int stat_client_add(int fd, uint64_t mask, int parser_friendly)
84 struct stat_client *new_client;
86 if (num_clients >= MAX_STAT_CLIENTS) {
87 PARA_ERROR_LOG("maximal number of stat clients (%d) exceeded\n",
89 return -E_TOO_MANY_CLIENTS;
92 INIT_LIST_HEAD(&client_list);
95 PARA_INFO_LOG("adding client on fd %d\n", fd);
96 new_client = para_calloc(sizeof(struct stat_client));
98 new_client->item_mask = mask;
100 new_client->flags = SCF_PARSER_FRIENDLY;
101 para_list_add(&new_client->node, &client_list);
102 dump_stat_client_list();
107 * Write a message to all connected status clients.
109 * \param item_num The number of the status item of \a msg.
111 * On write errors, remove the status client from the client list and close its
114 void stat_client_write_item(int item_num)
116 struct stat_client *sc, *tmp;
117 struct para_buffer pb = {.flags = 0};
118 struct para_buffer pfpb = {.flags = PBF_SIZE_PREFIX};
119 const uint64_t one = 1;
123 list_for_each_entry_safe(sc, tmp, &client_list, node) {
124 int fd = sc->fd, ret;
126 if (!((one << item_num) & sc->item_mask))
128 if (write_ok(fd) > 0) {
129 struct para_buffer *b =
130 (sc->flags & SCF_PARSER_FRIENDLY)? &pfpb : &pb;
131 char *msg = stat_item_values[item_num];
133 WRITE_STATUS_ITEM(b, item_num, "%s\n",
135 ret = write(fd, b->buf, b->offset);
136 if (ret == b->offset)
139 /* write error or fd not ready for writing */
142 PARA_INFO_LOG("deleting client on fd %d\n", fd);
145 dump_stat_client_list();
150 // PARA_DEBUG_LOG("%d client(s)\n", num_clients);
154 * Check if string is a known status item.
156 * \param item Buffer containing the text to check.
158 * \return If \a item is a valid status item, the number of that status item is
159 * returned. Otherwise, this function returns \p -E_UNKNOWN_STAT_ITEM.
161 int stat_item_valid(const char *item)
164 if (!item || !*item) {
165 PARA_ERROR_LOG("%s\n", "no item");
166 return -E_UNKNOWN_STAT_ITEM;
168 FOR_EACH_STATUS_ITEM(i)
169 if (!strcmp(status_item_list[i], item))
171 PARA_ERROR_LOG("invalid stat item: %s\n", item);
172 return -E_UNKNOWN_STAT_ITEM;
175 /** The minimal length of a status item buffer. */
176 #define MIN_STAT_ITEM_LEN 9 /* 5 + 2 + 2, e.g. '0005 00:\n' */
179 * Call a function for each complete status item of a buffer.
181 * \param item_buf The source buffer.
182 * \param num_bytes The length of \a buf.
183 * \param item_handler Function to call for each complete item.
185 * \return Negative on errors, the number of bytes _not_ passed to \a
188 * Status items are expected in the format used by parser-friendly output mode
189 * of the stat command of para_client/para_audioc.
191 int for_each_stat_item(char *item_buf, size_t num_bytes,
192 int (*item_handler)(int, char *))
194 char *buf = item_buf;
198 int i, ret, item_len, item_num = 0;
199 if (len < MIN_STAT_ITEM_LEN)
201 ret = read_size_header(buf);
205 if (item_len > len - 5) /* item not complete */
207 for (i = 0; i < 2; i++) {
208 unsigned char c = buf[5 + i];
210 if (c >= '0' && c <= '9') {
214 if (c >= 'a' && c <= 'f') {
215 item_num += c - 'a' + 10;
218 return -E_STAT_ITEM_PARSE;
220 if (buf[7] != ':' || buf[5 + item_len - 1] != '\n')
221 return -E_STAT_ITEM_PARSE;
222 buf[5 + item_len - 1] = '\0';
223 if (item_num >= NUM_STAT_ITEMS)
224 PARA_WARNING_LOG("unknown status item %d: %s\n",
227 ret = item_handler(item_num, buf + 8);
233 assert(len >= 0 && buf <= item_buf + num_bytes);
236 if (len && len != num_bytes)
237 memmove(item_buf, item_buf + num_bytes - len, len);