fix memory leak when reloading the application
[dvblast.git] / comm.c
blobf75f56609e7671689f0482025a6882bfcdd92275
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_PMT:
229 if ( i_size < COMM_HEADER_SIZE + 2 )
231 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
232 return;
235 uint16_t i_sid = (uint16_t)((p_input[0] << 8) | p_input[1]);
236 p_packed_section = demux_get_packed_PMT(i_sid, &i_packed_section_size);
238 if ( p_packed_section && i_packed_section_size )
240 i_answer = RET_PMT;
241 i_answer_size = i_packed_section_size;
242 memcpy( p_answer + COMM_HEADER_SIZE, p_packed_section, i_packed_section_size );
243 free( p_packed_section );
244 } else {
245 i_answer = RET_NODATA;
248 break;
251 case CMD_GET_PIDS:
253 i_answer = RET_PIDS;
254 i_answer_size = sizeof(struct cmd_pid_info);
255 demux_get_PIDS_info( p_output );
256 break;
259 case CMD_GET_PID:
261 if ( i_size < COMM_HEADER_SIZE + 2 )
263 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
264 return;
267 uint16_t i_pid = (uint16_t)((p_input[0] << 8) | p_input[1]);
268 if ( i_pid >= MAX_PIDS ) {
269 i_answer = RET_NODATA;
270 } else {
271 i_answer = RET_PID;
272 i_answer_size = sizeof(ts_pid_info_t);
273 demux_get_PID_info( i_pid, p_output );
275 break;
278 default:
279 msg_Err( NULL, "wrong command %u", i_command );
280 i_answer = RET_HUH;
281 i_answer_size = 0;
282 break;
285 return_answer:
286 p_answer[0] = COMM_HEADER_MAGIC;
287 p_answer[1] = i_answer;
288 p_answer[2] = 0;
289 p_answer[3] = 0;
290 uint32_t *p_size = (uint32_t *)&p_answer[4];
291 *p_size = i_answer_size + COMM_HEADER_SIZE;
293 /* msg_Dbg( NULL, "answering %d to %d with size %zd", i_answer, i_command,
294 i_answer_size ); */
296 #define min(a, b) (a < b ? a : b)
297 ssize_t i_sended = 0;
298 ssize_t i_to_send = i_answer_size + COMM_HEADER_SIZE;
299 do {
300 ssize_t i_sent = sendto( i_comm_fd, p_answer + i_sended,
301 min(i_to_send, COMM_MAX_MSG_CHUNK), 0,
302 (struct sockaddr *)&sun_client, sun_length );
304 if ( i_sent < 0 ) {
305 msg_Err( NULL, "cannot send comm socket (%s)", strerror(errno) );
306 break;
309 i_sended += i_sent;
310 i_to_send -= i_sent;
311 } while ( i_to_send > 0 );
312 #undef min
315 /*****************************************************************************
316 * comm_Close
317 *****************************************************************************/
318 void comm_Close( void )
320 if (i_comm_fd > -1)
322 ev_io_stop(event_loop, &comm_watcher);
323 close(i_comm_fd);
324 unlink(psz_srv_socket);