Merge branch 'nto-signal-stats'
[dvblast.git] / comm.c
blob8f353a340eab05c3511df64cc23c02b78dca8a49
1 /*****************************************************************************
2 * comm.c: Handles the communication socket
3 *****************************************************************************
4 * Copyright (C) 2008, 2015 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software. It comes without any warranty, to
9 * the extent permitted by applicable law. You can redistribute it
10 * and/or modify it under the terms of the Do What The Fuck You Want
11 * To Public License, Version 2, as published by Sam Hocevar. See
12 * http://sam.zoy.org/wtfpl/COPYING for more details.
13 *****************************************************************************/
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <sys/un.h>
28 #include <errno.h>
29 #include <ev.h>
31 #include "dvblast.h"
32 #include "en50221.h"
33 #include "comm.h"
35 /*****************************************************************************
36 * Local declarations
37 *****************************************************************************/
38 static int i_comm_fd = -1;
39 static struct ev_io comm_watcher;
41 /*****************************************************************************
42 * Local prototypes
43 *****************************************************************************/
44 static void comm_Read(struct ev_loop *loop, struct ev_io *w, int revents);
46 /*****************************************************************************
47 * comm_Open
48 *****************************************************************************/
49 void comm_Open( void )
51 int i_size = COMM_MAX_MSG_CHUNK;
52 struct sockaddr_un sun_server;
54 unlink( psz_srv_socket );
56 if ( (i_comm_fd = socket( AF_UNIX, SOCK_DGRAM, 0 )) == -1 )
58 msg_Err( NULL, "cannot create comm socket (%s)", strerror(errno) );
59 return;
62 setsockopt( i_comm_fd, SOL_SOCKET, SO_RCVBUF, &i_size, sizeof(i_size) );
64 memset( &sun_server, 0, sizeof(sun_server) );
65 sun_server.sun_family = AF_UNIX;
66 strncpy( sun_server.sun_path, psz_srv_socket, sizeof(sun_server.sun_path) );
67 sun_server.sun_path[sizeof(sun_server.sun_path) - 1] = '\0';
69 if ( bind( i_comm_fd, (struct sockaddr *)&sun_server,
70 SUN_LEN(&sun_server) ) < 0 )
72 msg_Err( NULL, "cannot bind comm socket (%s)", strerror(errno) );
73 close( i_comm_fd );
74 i_comm_fd = -1;
75 return;
78 ev_io_init(&comm_watcher, comm_Read, i_comm_fd, EV_READ);
79 ev_io_start(event_loop, &comm_watcher);
82 /*****************************************************************************
83 * comm_Read
84 *****************************************************************************/
85 static void comm_Read(struct ev_loop *loop, struct ev_io *w, int revents)
87 struct sockaddr_un sun_client;
88 socklen_t sun_length = sizeof(sun_client);
89 ssize_t i_size, i_answer_size = 0;
90 uint8_t p_buffer[COMM_BUFFER_SIZE], p_answer[COMM_BUFFER_SIZE];
91 uint8_t i_command, i_answer;
92 uint8_t *p_packed_section;
93 unsigned int i_packed_section_size;
94 uint8_t *p_input = p_buffer + COMM_HEADER_SIZE;
95 uint8_t *p_output = p_answer + COMM_HEADER_SIZE;
97 i_size = recvfrom( i_comm_fd, p_buffer, COMM_BUFFER_SIZE, 0,
98 (struct sockaddr *)&sun_client, &sun_length );
99 if ( i_size < COMM_HEADER_SIZE )
101 msg_Err( NULL, "cannot read comm socket (%zd:%s)\n", i_size,
102 strerror(errno) );
103 return;
105 if ( sun_length == 0 || sun_length > sizeof(sun_client) )
107 msg_Err( NULL, "anonymous packet from comm socket\n" );
108 return;
111 if ( p_buffer[0] != COMM_HEADER_MAGIC )
113 msg_Err( NULL, "wrong protocol version 0x%x", p_buffer[0] );
114 return;
117 i_command = p_buffer[1];
119 if ( i_frequency == 0 ) /* ASI or UDP, disable DVB only commands */
121 switch ( i_command )
123 case CMD_FRONTEND_STATUS:
124 case CMD_MMI_STATUS:
125 case CMD_MMI_SLOT_STATUS:
126 case CMD_MMI_OPEN:
127 case CMD_MMI_CLOSE:
128 case CMD_MMI_RECV:
129 case CMD_MMI_SEND_TEXT:
130 case CMD_MMI_SEND_CHOICE:
131 i_answer = RET_NODATA;
132 i_answer_size = 0;
133 goto return_answer;
137 switch ( i_command )
139 case CMD_RELOAD:
140 config_ReadFile();
141 i_answer = RET_OK;
142 i_answer_size = 0;
143 break;
145 #ifdef HAVE_DVB_SUPPORT
146 case CMD_FRONTEND_STATUS:
147 i_answer = dvb_FrontendStatus( p_answer + COMM_HEADER_SIZE,
148 &i_answer_size );
149 break;
151 case CMD_MMI_STATUS:
152 i_answer = en50221_StatusMMI( p_answer + COMM_HEADER_SIZE,
153 &i_answer_size );
154 break;
156 case CMD_MMI_SLOT_STATUS:
157 i_answer = en50221_StatusMMISlot( p_input, i_size - COMM_HEADER_SIZE,
158 p_answer + COMM_HEADER_SIZE,
159 &i_answer_size );
160 break;
162 case CMD_MMI_OPEN:
163 i_answer = en50221_OpenMMI( p_input, i_size - COMM_HEADER_SIZE );
164 break;
166 case CMD_MMI_CLOSE:
167 i_answer = en50221_CloseMMI( p_input, i_size - COMM_HEADER_SIZE );
168 break;
170 case CMD_MMI_RECV:
171 i_answer = en50221_GetMMIObject( p_input, i_size - COMM_HEADER_SIZE,
172 p_answer + COMM_HEADER_SIZE,
173 &i_answer_size );
174 break;
176 case CMD_MMI_SEND_TEXT:
177 case CMD_MMI_SEND_CHOICE:
178 i_answer = en50221_SendMMIObject( p_input, i_size - COMM_HEADER_SIZE );
179 break;
180 #endif
182 case CMD_SHUTDOWN:
183 ev_break(loop, EVBREAK_ALL);
184 i_answer = RET_OK;
185 i_answer_size = 0;
186 break;
188 case CMD_GET_PAT:
189 case CMD_GET_CAT:
190 case CMD_GET_NIT:
191 case CMD_GET_SDT:
193 #define CASE_TABLE(x) \
194 case CMD_GET_##x: \
196 i_answer = RET_##x; \
197 p_packed_section = demux_get_current_packed_##x(&i_packed_section_size); \
198 break; \
200 switch ( i_command )
202 CASE_TABLE(PAT)
203 CASE_TABLE(CAT)
204 CASE_TABLE(NIT)
205 CASE_TABLE(SDT)
207 #undef CASE_TABLE
209 if ( p_packed_section && i_packed_section_size )
211 if ( i_packed_section_size <= COMM_BUFFER_SIZE - COMM_HEADER_SIZE )
213 i_answer_size = i_packed_section_size;
214 memcpy( p_answer + COMM_HEADER_SIZE, p_packed_section, i_packed_section_size );
215 } else {
216 msg_Err( NULL, "section size is too big (%u)\n", i_packed_section_size );
217 i_answer = RET_NODATA;
219 free( p_packed_section );
220 } else {
221 i_answer = RET_NODATA;
224 break;
227 case CMD_GET_EIT_PF:
228 case CMD_GET_EIT_SCHEDULE:
229 case CMD_GET_PMT:
231 if ( i_size < COMM_HEADER_SIZE + 2 )
233 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
234 return;
237 uint16_t i_sid = (uint16_t)((p_input[0] << 8) | p_input[1]);
238 if ( i_command == CMD_GET_EIT_PF ) {
239 i_answer = RET_EIT_PF;
240 p_packed_section = demux_get_packed_EIT_pf( i_sid, &i_packed_section_size );
241 } else if ( i_command == CMD_GET_EIT_SCHEDULE ) {
242 i_answer = RET_EIT_SCHEDULE;
243 p_packed_section = demux_get_packed_EIT_schedule( i_sid, &i_packed_section_size );
244 } else {
245 i_answer = RET_PMT;
246 p_packed_section = demux_get_packed_PMT(i_sid, &i_packed_section_size);
249 if ( p_packed_section && i_packed_section_size )
251 i_answer_size = i_packed_section_size;
252 memcpy( p_answer + COMM_HEADER_SIZE, p_packed_section, i_packed_section_size );
253 free( p_packed_section );
254 } else {
255 i_answer = RET_NODATA;
258 break;
261 case CMD_GET_PIDS:
263 i_answer = RET_PIDS;
264 i_answer_size = sizeof(struct cmd_pid_info);
265 demux_get_PIDS_info( p_output );
266 break;
269 case CMD_GET_PID:
271 if ( i_size < COMM_HEADER_SIZE + 2 )
273 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
274 return;
277 uint16_t i_pid = (uint16_t)((p_input[0] << 8) | p_input[1]);
278 if ( i_pid >= MAX_PIDS ) {
279 i_answer = RET_NODATA;
280 } else {
281 i_answer = RET_PID;
282 i_answer_size = sizeof(ts_pid_info_t);
283 demux_get_PID_info( i_pid, p_output );
285 break;
288 default:
289 msg_Err( NULL, "wrong command %u", i_command );
290 i_answer = RET_HUH;
291 i_answer_size = 0;
292 break;
295 return_answer:
296 p_answer[0] = COMM_HEADER_MAGIC;
297 p_answer[1] = i_answer;
298 p_answer[2] = 0;
299 p_answer[3] = 0;
300 uint32_t *p_size = (uint32_t *)&p_answer[4];
301 *p_size = i_answer_size + COMM_HEADER_SIZE;
303 /* msg_Dbg( NULL, "answering %d to %d with size %zd", i_answer, i_command,
304 i_answer_size ); */
306 #define min(a, b) (a < b ? a : b)
307 ssize_t i_sended = 0;
308 ssize_t i_to_send = i_answer_size + COMM_HEADER_SIZE;
309 do {
310 ssize_t i_sent = sendto( i_comm_fd, p_answer + i_sended,
311 min(i_to_send, COMM_MAX_MSG_CHUNK), 0,
312 (struct sockaddr *)&sun_client, sun_length );
314 if ( i_sent < 0 ) {
315 msg_Err( NULL, "cannot send comm socket (%s)", strerror(errno) );
316 break;
319 i_sended += i_sent;
320 i_to_send -= i_sent;
321 } while ( i_to_send > 0 );
322 #undef min
325 /*****************************************************************************
326 * comm_Close
327 *****************************************************************************/
328 void comm_Close( void )
330 if (i_comm_fd > -1)
332 ev_io_stop(event_loop, &comm_watcher);
333 close(i_comm_fd);
334 unlink(psz_srv_socket);