1 /*
2  *  API - service related calls
3  *
4  *  Copyright (C) 2013 Adam Sutton
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef __TVH_API_SERVICE_H__
21 #define __TVH_API_SERVICE_H__
22 
23 #include "tvheadend.h"
24 #include "subscriptions.h"
25 #include "access.h"
26 #include "api.h"
27 #include "tcp.h"
28 #include "input.h"
29 
30 static int
api_status_inputs(access_t * perm,void * opaque,const char * op,htsmsg_t * args,htsmsg_t ** resp)31 api_status_inputs
32   ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
33 {
34   int c = 0;
35   htsmsg_t *l, *e;
36   tvh_input_t *ti;
37   tvh_input_stream_t *st;
38   tvh_input_stream_list_t stl = { 0 };
39 
40   pthread_mutex_lock(&global_lock);
41   TVH_INPUT_FOREACH(ti)
42     ti->ti_get_streams(ti, &stl);
43   pthread_mutex_unlock(&global_lock);
44 
45   l = htsmsg_create_list();
46   while ((st = LIST_FIRST(&stl))) {
47     e = tvh_input_stream_create_msg(st);
48     htsmsg_add_msg(l, NULL, e);
49     tvh_input_stream_destroy(st);
50     LIST_REMOVE(st, link);
51     free(st);
52     c++;
53   }
54 
55   *resp = htsmsg_create_map();
56   htsmsg_add_msg(*resp, "entries", l);
57   htsmsg_add_u32(*resp, "totalCount", c);
58 
59   return 0;
60 }
61 
62 static int
api_status_subscriptions(access_t * perm,void * opaque,const char * op,htsmsg_t * args,htsmsg_t ** resp)63 api_status_subscriptions
64   ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
65 {
66   int c;
67   htsmsg_t *l, *e;
68   th_subscription_t *ths;
69 
70   l = htsmsg_create_list();
71   c = 0;
72   pthread_mutex_lock(&global_lock);
73   LIST_FOREACH(ths, &subscriptions, ths_global_link) {
74     e = subscription_create_msg(ths, perm->aa_lang_ui);
75     htsmsg_add_msg(l, NULL, e);
76     c++;
77   }
78   pthread_mutex_unlock(&global_lock);
79 
80   *resp = htsmsg_create_map();
81   htsmsg_add_msg(*resp, "entries", l);
82   htsmsg_add_u32(*resp, "totalCount", c);
83 
84   return 0;
85 }
86 
87 static int
api_status_connections(access_t * perm,void * opaque,const char * op,htsmsg_t * args,htsmsg_t ** resp)88 api_status_connections
89   ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
90 {
91   pthread_mutex_lock(&global_lock);
92   *resp = tcp_server_connections();
93   pthread_mutex_unlock(&global_lock);
94   return 0;
95 }
96 
97 static int
api_connections_cancel(access_t * perm,void * opaque,const char * op,htsmsg_t * args,htsmsg_t ** resp)98 api_connections_cancel
99   ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
100 {
101   htsmsg_field_t *f;
102   htsmsg_t *ids;
103   uint32_t id;
104 
105   if (!(f = htsmsg_field_find(args, "id")))
106     return EINVAL;
107   if (!(ids = htsmsg_field_get_list(f)))
108     if (htsmsg_field_get_u32(f, &id))
109       return EINVAL;
110 
111   if (ids) {
112     HTSMSG_FOREACH(f, ids) {
113       if (htsmsg_field_get_u32(f, &id)) continue;
114       if (!id) continue;
115       pthread_mutex_lock(&global_lock);
116       tcp_connection_cancel(id);
117       pthread_mutex_unlock(&global_lock);
118     }
119   } else {
120     pthread_mutex_lock(&global_lock);
121     tcp_connection_cancel(id);
122     pthread_mutex_unlock(&global_lock);
123   }
124   return 0;
125 }
126 
127 static void
input_clear_stats(const char * uuid)128 input_clear_stats(const char *uuid)
129 {
130   tvh_input_instance_t *tii;
131   tvh_input_t *ti;
132 
133   pthread_mutex_lock(&global_lock);
134   if ((tii = tvh_input_instance_find_by_uuid(uuid)) != NULL)
135     if (tii->tii_clear_stats)
136       tii->tii_clear_stats(tii);
137   if ((ti = tvh_input_find_by_uuid(uuid)) != NULL)
138     if (ti->ti_clear_stats)
139       ti->ti_clear_stats(ti);
140   pthread_mutex_unlock(&global_lock);
141 }
142 
143 static int
api_status_input_clear_stats(access_t * perm,void * opaque,const char * op,htsmsg_t * args,htsmsg_t ** resp)144 api_status_input_clear_stats
145   ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
146 {
147   htsmsg_field_t *f;
148   htsmsg_t *ids;
149   const char *uuid;
150 
151   if (!(f = htsmsg_field_find(args, "uuid")))
152     return EINVAL;
153   if (!(ids = htsmsg_field_get_list(f))) {
154     if ((uuid = htsmsg_field_get_str(f)) == NULL)
155       return EINVAL;
156     input_clear_stats(uuid);
157   } else {
158     HTSMSG_FOREACH(f, ids) {
159       if ((uuid = htsmsg_field_get_str(f)) == NULL) continue;
160       input_clear_stats(uuid);
161     }
162   }
163   return 0;
164 }
165 
api_status_init(void)166 void api_status_init ( void )
167 {
168   static api_hook_t ah[] = {
169     { "status/connections",   ACCESS_ADMIN, api_status_connections, NULL },
170     { "status/subscriptions", ACCESS_ADMIN, api_status_subscriptions, NULL },
171     { "status/inputs",        ACCESS_ADMIN, api_status_inputs, NULL },
172     { "status/inputclrstats", ACCESS_ADMIN, api_status_input_clear_stats, NULL },
173     { "connections/cancel",   ACCESS_ADMIN, api_connections_cancel, NULL },
174     { NULL },
175   };
176 
177   api_register_all(ah);
178 }
179 
180 
181 #endif /* __TVH_API_IDNODE_H__ */
182