1 /*****************************************************************************
2 * comm.c: Handles the communication socket (linux-dvb only)
3 *****************************************************************************
4 * Copyright (C) 2008 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 *****************************************************************************/
21 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
33 /*****************************************************************************
35 *****************************************************************************/
38 /*****************************************************************************
40 *****************************************************************************/
41 void comm_Open( void )
43 int i_size
= COMM_MAX_MSG_CHUNK
;
44 struct sockaddr_un sun_server
;
46 if ( (i_comm_fd
= socket( AF_UNIX
, SOCK_DGRAM
, 0 )) == -1 )
48 msg_Err( NULL
, "cannot create comm socket (%s)", strerror(errno
) );
52 setsockopt( i_comm_fd
, SOL_SOCKET
, SO_RCVBUF
, &i_size
, sizeof(i_size
) );
54 memset( &sun_server
, 0, sizeof(sun_server
) );
55 sun_server
.sun_family
= AF_UNIX
;
56 strncpy( sun_server
.sun_path
, psz_srv_socket
, sizeof(sun_server
.sun_path
) );
57 sun_server
.sun_path
[sizeof(sun_server
.sun_path
) - 1] = '\0';
59 if ( bind( i_comm_fd
, (struct sockaddr
*)&sun_server
,
60 SUN_LEN(&sun_server
) ) < 0 )
62 msg_Err( NULL
, "cannot bind comm socket (%s)", strerror(errno
) );
69 /*****************************************************************************
71 *****************************************************************************/
72 void comm_Read( void )
74 struct sockaddr_un sun_client
;
75 socklen_t sun_length
= sizeof(sun_client
);
76 ssize_t i_size
, i_answer_size
= 0;
77 uint8_t p_buffer
[COMM_BUFFER_SIZE
], p_answer
[COMM_BUFFER_SIZE
];
78 uint8_t i_command
, i_answer
;
79 uint8_t *p_packed_section
;
80 unsigned int i_packed_section_size
;
81 uint8_t *p_input
= p_buffer
+ COMM_HEADER_SIZE
;
82 uint8_t *p_output
= p_answer
+ COMM_HEADER_SIZE
;
84 i_size
= recvfrom( i_comm_fd
, p_buffer
, COMM_BUFFER_SIZE
, 0,
85 (struct sockaddr
*)&sun_client
, &sun_length
);
86 if ( i_size
< COMM_HEADER_SIZE
)
88 msg_Err( NULL
, "cannot read comm socket (%zd:%s)\n", i_size
,
92 if ( sun_length
== 0 || sun_length
> sizeof(sun_client
) )
94 msg_Err( NULL
, "anonymous packet from comm socket\n" );
98 if ( p_buffer
[0] != COMM_HEADER_MAGIC
)
100 msg_Err( NULL
, "wrong protocol version 0x%x", p_buffer
[0] );
104 i_command
= p_buffer
[1];
106 if ( i_frequency
== 0 ) /* ASI or UDP, disable DVB only commands */
110 case CMD_FRONTEND_STATUS
:
112 case CMD_MMI_SLOT_STATUS
:
116 case CMD_MMI_SEND_TEXT
:
117 case CMD_MMI_SEND_CHOICE
:
118 i_answer
= RET_NODATA
;
132 case CMD_FRONTEND_STATUS
:
133 i_answer
= dvb_FrontendStatus( p_answer
+ COMM_HEADER_SIZE
,
138 i_answer
= en50221_StatusMMI( p_answer
+ COMM_HEADER_SIZE
,
142 case CMD_MMI_SLOT_STATUS
:
143 i_answer
= en50221_StatusMMISlot( p_input
, i_size
- COMM_HEADER_SIZE
,
144 p_answer
+ COMM_HEADER_SIZE
,
149 i_answer
= en50221_OpenMMI( p_input
, i_size
- COMM_HEADER_SIZE
);
153 i_answer
= en50221_CloseMMI( p_input
, i_size
- COMM_HEADER_SIZE
);
157 i_answer
= en50221_GetMMIObject( p_input
, i_size
- COMM_HEADER_SIZE
,
158 p_answer
+ COMM_HEADER_SIZE
,
162 case CMD_MMI_SEND_TEXT
:
163 case CMD_MMI_SEND_CHOICE
:
164 i_answer
= en50221_SendMMIObject( p_input
, i_size
- COMM_HEADER_SIZE
);
178 #define CASE_TABLE(x) \
181 i_answer = RET_##x; \
182 p_packed_section = demux_get_current_packed_##x(&i_packed_section_size); \
194 if ( p_packed_section
&& i_packed_section_size
)
196 if ( i_packed_section_size
<= COMM_BUFFER_SIZE
- COMM_HEADER_SIZE
)
198 i_answer_size
= i_packed_section_size
;
199 memcpy( p_answer
+ COMM_HEADER_SIZE
, p_packed_section
, i_packed_section_size
);
201 msg_Err( NULL
, "section size is too big (%u)\n", i_packed_section_size
);
202 i_answer
= RET_NODATA
;
204 free( p_packed_section
);
206 i_answer
= RET_NODATA
;
214 if ( i_size
< COMM_HEADER_SIZE
+ 2 )
216 msg_Err( NULL
, "command packet is too short (%zd)\n", i_size
);
220 uint16_t i_sid
= (uint16_t)((p_input
[0] << 8) | p_input
[1]);
221 p_packed_section
= demux_get_packed_PMT(i_sid
, &i_packed_section_size
);
223 if ( p_packed_section
&& i_packed_section_size
)
226 i_answer_size
= i_packed_section_size
;
227 memcpy( p_answer
+ COMM_HEADER_SIZE
, p_packed_section
, i_packed_section_size
);
228 free( p_packed_section
);
230 i_answer
= RET_NODATA
;
239 i_answer_size
= sizeof(struct cmd_pid_info
);
240 demux_get_PIDS_info( p_output
);
246 if ( i_size
< COMM_HEADER_SIZE
+ 2 )
248 msg_Err( NULL
, "command packet is too short (%zd)\n", i_size
);
252 uint16_t i_pid
= (uint16_t)((p_input
[0] << 8) | p_input
[1]);
253 if ( i_pid
>= MAX_PIDS
) {
254 i_answer
= RET_NODATA
;
257 i_answer_size
= sizeof(ts_pid_info_t
);
258 demux_get_PID_info( i_pid
, p_output
);
264 msg_Err( NULL
, "wrong command %u", i_command
);
271 p_answer
[0] = COMM_HEADER_MAGIC
;
272 p_answer
[1] = i_answer
;
275 uint32_t *p_size
= (uint32_t *)&p_answer
[4];
276 *p_size
= i_answer_size
+ COMM_HEADER_SIZE
;
278 msg_Dbg( NULL
, "answering %d to %d with size %zd", i_answer
, i_command
,
281 #define min(a, b) (a < b ? a : b)
282 ssize_t i_sended
= 0;
283 ssize_t i_to_send
= i_answer_size
+ COMM_HEADER_SIZE
;
285 ssize_t i_sent
= sendto( i_comm_fd
, p_answer
+ i_sended
,
286 min(i_to_send
, COMM_MAX_MSG_CHUNK
), 0,
287 (struct sockaddr
*)&sun_client
, sun_length
);
290 msg_Err( NULL
, "cannot send comm socket (%s)", strerror(errno
) );
296 } while ( i_to_send
> 0 );