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
);