Factor out common code
[dvblast.git] / comm.c
blobbd881e4456bbb19fc18fc04d6aa9569bbc73a8d0
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 *****************************************************************************/
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/un.h>
27 #include <errno.h>
29 #include "dvblast.h"
30 #include "en50221.h"
31 #include "comm.h"
33 /*****************************************************************************
34 * Local declarations
35 *****************************************************************************/
36 int i_comm_fd = -1;
38 /*****************************************************************************
39 * comm_Open
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) );
49 return;
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) );
63 close( i_comm_fd );
64 i_comm_fd = -1;
65 return;
69 /*****************************************************************************
70 * comm_Read
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,
89 strerror(errno) );
90 return;
92 if ( sun_length == 0 || sun_length > sizeof(sun_client) )
94 msg_Err( NULL, "anonymous packet from comm socket\n" );
95 return;
98 if ( p_buffer[0] != COMM_HEADER_MAGIC )
100 msg_Err( NULL, "wrong protocol version 0x%x", p_buffer[0] );
101 return;
104 i_command = p_buffer[1];
106 if ( i_frequency == 0 ) /* ASI or UDP, disable DVB only commands */
108 switch ( i_command )
110 case CMD_FRONTEND_STATUS:
111 case CMD_MMI_STATUS:
112 case CMD_MMI_SLOT_STATUS:
113 case CMD_MMI_OPEN:
114 case CMD_MMI_CLOSE:
115 case CMD_MMI_RECV:
116 case CMD_MMI_SEND_TEXT:
117 case CMD_MMI_SEND_CHOICE:
118 i_answer = RET_NODATA;
119 i_answer_size = 0;
120 goto return_answer;
124 switch ( i_command )
126 case CMD_RELOAD:
127 b_conf_reload = 1;
128 i_answer = RET_OK;
129 i_answer_size = 0;
130 break;
132 case CMD_FRONTEND_STATUS:
133 i_answer = dvb_FrontendStatus( p_answer + COMM_HEADER_SIZE,
134 &i_answer_size );
135 break;
137 case CMD_MMI_STATUS:
138 i_answer = en50221_StatusMMI( p_answer + COMM_HEADER_SIZE,
139 &i_answer_size );
140 break;
142 case CMD_MMI_SLOT_STATUS:
143 i_answer = en50221_StatusMMISlot( p_input, i_size - COMM_HEADER_SIZE,
144 p_answer + COMM_HEADER_SIZE,
145 &i_answer_size );
146 break;
148 case CMD_MMI_OPEN:
149 i_answer = en50221_OpenMMI( p_input, i_size - COMM_HEADER_SIZE );
150 break;
152 case CMD_MMI_CLOSE:
153 i_answer = en50221_CloseMMI( p_input, i_size - COMM_HEADER_SIZE );
154 break;
156 case CMD_MMI_RECV:
157 i_answer = en50221_GetMMIObject( p_input, i_size - COMM_HEADER_SIZE,
158 p_answer + COMM_HEADER_SIZE,
159 &i_answer_size );
160 break;
162 case CMD_MMI_SEND_TEXT:
163 case CMD_MMI_SEND_CHOICE:
164 i_answer = en50221_SendMMIObject( p_input, i_size - COMM_HEADER_SIZE );
165 break;
167 case CMD_SHUTDOWN:
168 b_exit_now = 1;
169 i_answer = RET_OK;
170 i_answer_size = 0;
171 break;
173 case CMD_GET_PAT:
174 case CMD_GET_CAT:
175 case CMD_GET_NIT:
176 case CMD_GET_SDT:
178 #define CASE_TABLE(x) \
179 case CMD_GET_##x: \
181 i_answer = RET_##x; \
182 p_packed_section = demux_get_current_packed_##x(&i_packed_section_size); \
183 break; \
185 switch ( i_command )
187 CASE_TABLE(PAT)
188 CASE_TABLE(CAT)
189 CASE_TABLE(NIT)
190 CASE_TABLE(SDT)
192 #undef CASE_TABLE
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 );
200 } else {
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 );
205 } else {
206 i_answer = RET_NODATA;
209 break;
212 case CMD_GET_PMT:
214 if ( i_size < COMM_HEADER_SIZE + 2 )
216 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
217 return;
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 )
225 i_answer = RET_PMT;
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 );
229 } else {
230 i_answer = RET_NODATA;
233 break;
236 case CMD_GET_PIDS:
238 i_answer = RET_PIDS;
239 i_answer_size = sizeof(struct cmd_pid_info);
240 demux_get_PIDS_info( p_output );
241 break;
244 case CMD_GET_PID:
246 if ( i_size < COMM_HEADER_SIZE + 2 )
248 msg_Err( NULL, "command packet is too short (%zd)\n", i_size );
249 return;
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;
255 } else {
256 i_answer = RET_PID;
257 i_answer_size = sizeof(ts_pid_info_t);
258 demux_get_PID_info( i_pid, p_output );
260 break;
263 default:
264 msg_Err( NULL, "wrong command %u", i_command );
265 i_answer = RET_HUH;
266 i_answer_size = 0;
267 break;
270 return_answer:
271 p_answer[0] = COMM_HEADER_MAGIC;
272 p_answer[1] = i_answer;
273 p_answer[2] = 0;
274 p_answer[3] = 0;
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,
279 i_answer_size );
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;
284 do {
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 );
289 if ( i_sent < 0 ) {
290 msg_Err( NULL, "cannot send comm socket (%s)", strerror(errno) );
291 break;
294 i_sended += i_sent;
295 i_to_send -= i_sent;
296 } while ( i_to_send > 0 );
297 #undef min