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 *****************************************************************************/
22 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
35 /*****************************************************************************
37 *****************************************************************************/
38 static int i_comm_fd
= -1;
39 static struct ev_io comm_watcher
;
41 /*****************************************************************************
43 *****************************************************************************/
44 static void comm_Read(struct ev_loop
*loop
, struct ev_io
*w
, int revents
);
46 /*****************************************************************************
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
) );
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
) );
78 ev_io_init(&comm_watcher
, comm_Read
, i_comm_fd
, EV_READ
);
79 ev_io_start(event_loop
, &comm_watcher
);
82 /*****************************************************************************
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
,
105 if ( sun_length
== 0 || sun_length
> sizeof(sun_client
) )
107 msg_Err( NULL
, "anonymous packet from comm socket\n" );
111 if ( p_buffer
[0] != COMM_HEADER_MAGIC
)
113 msg_Err( NULL
, "wrong protocol version 0x%x", p_buffer
[0] );
117 i_command
= p_buffer
[1];
119 if ( i_frequency
== 0 ) /* ASI or UDP, disable DVB only commands */
123 case CMD_FRONTEND_STATUS
:
125 case CMD_MMI_SLOT_STATUS
:
129 case CMD_MMI_SEND_TEXT
:
130 case CMD_MMI_SEND_CHOICE
:
131 i_answer
= RET_NODATA
;
145 #ifdef HAVE_DVB_SUPPORT
146 case CMD_FRONTEND_STATUS
:
147 i_answer
= dvb_FrontendStatus( p_answer
+ COMM_HEADER_SIZE
,
152 i_answer
= en50221_StatusMMI( p_answer
+ COMM_HEADER_SIZE
,
156 case CMD_MMI_SLOT_STATUS
:
157 i_answer
= en50221_StatusMMISlot( p_input
, i_size
- COMM_HEADER_SIZE
,
158 p_answer
+ COMM_HEADER_SIZE
,
163 i_answer
= en50221_OpenMMI( p_input
, i_size
- COMM_HEADER_SIZE
);
167 i_answer
= en50221_CloseMMI( p_input
, i_size
- COMM_HEADER_SIZE
);
171 i_answer
= en50221_GetMMIObject( p_input
, i_size
- COMM_HEADER_SIZE
,
172 p_answer
+ COMM_HEADER_SIZE
,
176 case CMD_MMI_SEND_TEXT
:
177 case CMD_MMI_SEND_CHOICE
:
178 i_answer
= en50221_SendMMIObject( p_input
, i_size
- COMM_HEADER_SIZE
);
183 ev_break(loop
, EVBREAK_ALL
);
193 #define CASE_TABLE(x) \
196 i_answer = RET_##x; \
197 p_packed_section = demux_get_current_packed_##x(&i_packed_section_size); \
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
);
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
);
221 i_answer
= RET_NODATA
;
228 case CMD_GET_EIT_SCHEDULE
:
231 if ( i_size
< COMM_HEADER_SIZE
+ 2 )
233 msg_Err( NULL
, "command packet is too short (%zd)\n", i_size
);
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
);
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
);
255 i_answer
= RET_NODATA
;
264 i_answer_size
= sizeof(struct cmd_pid_info
);
265 demux_get_PIDS_info( p_output
);
271 if ( i_size
< COMM_HEADER_SIZE
+ 2 )
273 msg_Err( NULL
, "command packet is too short (%zd)\n", i_size
);
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
;
282 i_answer_size
= sizeof(ts_pid_info_t
);
283 demux_get_PID_info( i_pid
, p_output
);
289 msg_Err( NULL
, "wrong command %u", i_command
);
296 p_answer
[0] = COMM_HEADER_MAGIC
;
297 p_answer
[1] = i_answer
;
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,
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
;
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
);
315 msg_Err( NULL
, "cannot send comm socket (%s)", strerror(errno
) );
321 } while ( i_to_send
> 0 );
325 /*****************************************************************************
327 *****************************************************************************/
328 void comm_Close( void )
332 ev_io_stop(event_loop
, &comm_watcher
);
334 unlink(psz_srv_socket
);