blob: 3a541fe590b3f586870251d63f10da9c8cac55e4 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2*(C) Copyright 2011 Marvell International Ltd.
3* All Rights Reserved
4******************************************************************************/
5/*--------------------------------------------------------------------------------------------------------------------
6 * -------------------------------------------------------------------------------------------------------------------
7 *
8 * Filename: command_api.c
9 *
10 * Description: The APIs to remotely control DIAG internal behaviors.
11 *
12 * History:
13 * Aug, 13 2012 - Haili Wang(hlw@marvell.com) Creation of file
14 *
15 * Notes:
16 *
17 ******************************************************************************/
18
19#include <unistd.h>
20#include <stdlib.h>
21#include <fcntl.h>
22#include <errno.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <sys/stat.h>
26#ifdef ANDROID
27#include <cutils/sockets.h>
28#endif
29
30#include "utlEventHandler.h"
31#include "media_manager.h"
32#include "diag_state_machine.h"
33#include "sd_api.h"
34#include "pxa_dbg.h"
35#include "diag_al.h"
36#include "diag_api.h"
37
38static const char response_error[] = "ERROR";
39static const char response_invalid[] = "INVALID";
40static const char response_success[] = "SUCCESS";
41
42static int cmdfd = -1;
43static utlEventHandlerId_T cmdHandler;
44
45
46struct command_client{
47 int fd;
48 utlEventHandlerId_T handle_id;
49};
50
51#define MAX_CLIENT_NUMBER 10
52static struct command_client clients[MAX_CLIENT_NUMBER];
53
54#ifdef ANDROID
55#define DIAG_CMD_SOCKET "diagcmd"
56#else
57#define DIAG_CMD_SOCKET "/tmp/diagcmd"
58#endif
59
60static void init_clients(void)
61{
62 int i;
63 for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
64 {
65 clients[i].fd = -1;
66 clients[i].handle_id = 0;
67 }
68}
69
70static int client_id_is_valid(int id)
71{
72 if((id >= 0) && (id < MAX_CLIENT_NUMBER))
73 return 1;
74 else
75 return 0;
76}
77
78static void close_client(int i)
79{
80 if(client_id_is_valid(i))
81 {
82 if(clients[i].handle_id > 0)
83 utlDeleteEventHandler(clients[i].handle_id);
84 if(clients[i].fd > 0)
85 close(clients[i].fd);
86 clients[i].handle_id = 0;
87 clients[i].fd = -1;
88 }
89}
90
91static void close_clients(void)
92{
93 int i;
94 for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
95 {
96 close_client(i);
97 }
98}
99
100static int get_free_client_id(void)
101{
102 int i;
103 for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
104 {
105 if(clients[i].fd == -1)
106 return i;
107 }
108 return -1;
109}
110
111static int get_client_id_by_fd(int fd)
112{
113 int i;
114 if(fd < 0)
115 return -1;
116 for(i = 0; i < MAX_CLIENT_NUMBER; i ++)
117 {
118 if(clients[i].fd == fd)
119 {
120 return i;
121 }
122 }
123 return -1;
124}
125
126static int sendReply(int fd, const char* cmd, const char* arg)
127{
128 char buf[128];
129 int len;
130
131 strncpy(buf, cmd, sizeof(buf) - 1);
132 if(arg)
133 {
134 len = strlen(cmd) + 1;
135 buf[len - 1] = ' ';
136 strncpy(buf + len, arg , sizeof(buf) - len - 1);
137 }
138
139 return send(fd, buf, strlen(buf) + 1, MSG_NOSIGNAL);
140}
141
142static void parseCommand(char* cmd, int client_id)
143{
144 char* command, *arg;
145 const char *reply = response_invalid, *reply_arg = NULL;
146 char media_list[32];
147 int ret;
148
149 arg = strchr(cmd, ' ');
150 if(arg != NULL)
151 *arg++ = '\0';
152 else
153 arg = "";
154 command = cmd;
155 DBGMSG("command:%s, arg:%s\n", command, arg);
156 if(strcasecmp(command,"start") == 0)
157 {
158 ret = getMediaByName(arg);
159 if(ret >= 0)
160 {
161 if(startMediaMachine(ret) == 0)
162 reply = response_success;
163 else
164 reply = response_error;
165 }
166 }
167 else if(strcasecmp(command,"folder") == 0)
168 {
169#if CONFIG_DIAG_ALL
170 if(switchSDFolder(arg) == 0)
171 reply = response_success;
172 else
173 reply = response_error;
174#endif
175 }
176 else if(strcasecmp(command,"switch") == 0)
177 {
178 ret = getMediaByName(arg);
179 if(ret >= 0)
180 {
181 if(switchMediaMachine(ret) == 0)
182 reply = response_success;
183 else
184 reply = response_error;
185 }
186 }
187 else if (strcasecmp(command,"stop") == 0)
188 {
189 ret = getMediaByName(arg);
190 if(ret >= 0)
191 {
192 if(stopMediaMachine(ret) == 0)
193 reply = response_success;
194 else
195 reply = response_error;
196 }
197 }
198 else if(strcasecmp(command,"dump") == 0)
199 {
200 if(dumpCPBuffer(arg) == 0)
201 reply = response_success;
202 else
203 reply = response_error;
204 }
205 else if(strcasecmp(command, "print") == 0)
206 {
207 if(strcasecmp(arg, "active") == 0)
208 {
209 if(getActiveMedia(media_list))
210 reply_arg = media_list;
211 reply = response_success;
212 }
213 else if(strcasecmp(arg, "status") == 0)
214 {
215 dumpMediaMachine();
216 reply = response_success;
217 }
218 }
219 else if(strcasecmp(command,"exit") == 0)
220 {
221 stopAllMediaMachine();
222 (void)sendReply(clients[client_id].fd, response_success, NULL);
223 sleep(3); // wait for CP to disconnect
224 exit(0);
225 }
226
227 (void)sendReply(clients[client_id].fd, reply, reply_arg);
228}
229
230static utlReturnCode_T ReceiveDataFromUtility(const utlEventHandlerType_T handler_type UNUSED,
231 const utlEventHandlerType_T event_type UNUSED,
232 const int fd,
233 const utlRelativeTime_P2c period_p UNUSED,
234 void *arg_p UNUSED)
235{
236 int received, offset, client_id;
237 char* current;
238 char cmdBuffer[512];
239
240 client_id = get_client_id_by_fd(fd);
241 if(client_id < 0)
242 return utlFAILED;
243
244 received = recv (fd, &cmdBuffer, sizeof(cmdBuffer), 0);
245
246 if(received == 0)
247 {
248 DBGMSG("***** DIAG Command Client %d Connection closed by peer *****\r\n", client_id);
249 close_client(client_id);
250 return utlSUCCESS;
251 }
252
253 else if(received < 0)
254 {
255 DBGMSG("***** DIAG Command Client %d Read failed:%s. *****\r\n", client_id, strerror(errno));
256 close_client(client_id);
257 return utlSUCCESS;
258 }
259
260 DBGMSG("Receive Diag Command from Client(%d) %d bytes!",client_id,received);
261 current = cmdBuffer;
262 for(offset = 0; received != 0; --received)
263 {
264 /* Each cmd message is terminated by '\0' */
265 if( current[offset] == '\0')
266 {//coverity[path_manipulation_sink:SUPPRESS]
267 parseCommand(current, client_id);
268 current += offset + 1;
269 offset = 0;
270 }
271 else ++offset;
272 }
273 if(offset != 0) //number of bytes left
274 {
275 ERRMSG("Fragmented packet received from DIAG command socket");
276 }
277 return utlSUCCESS;
278}
279
280
281static int acceptCmdPort(const utlEventHandlerType_T handler_type UNUSED,
282 const utlEventHandlerType_T event_type UNUSED,
283 const int fd UNUSED,
284 const utlRelativeTime_P2c period_p UNUSED,
285 void *arg_p UNUSED)
286{
287 int ret;
288 int flags;
289 int client_id;
290
291 ret = accept(cmdfd, NULL, NULL);
292 if( ret < 0)
293 {
294 ERRMSG("***** DIAG Command Port: accept control socket Error: %s *****\r\n",strerror(errno));
295 return utlFAILED;
296 }
297 else
298 {
299 flags = fcntl(ret,F_GETFL, 0);
300 (void)fcntl(ret,F_SETFL, flags | O_NONBLOCK);
301 client_id = get_free_client_id();
302 DBGMSG("Accept Diag Command Client:%d!",client_id);
303 if(client_id_is_valid(client_id))
304 {
305 clients[client_id].fd = ret;
306 clients[client_id].handle_id = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_LOW, ret, ReceiveDataFromUtility, NULL);
307 }
308 else
309 {
310 DBGMSG("Diag Command Clients reach max number! Connection will be closed");
311 close(ret);
312 }
313 }
314 return utlSUCCESS;
315}
316
317int openCmdPort(void)
318{
319 int len;
320 struct sockaddr_un socket_name;
321 init_clients();
322 socket_name.sun_family = AF_UNIX;
323#ifdef ANDROID
324 cmdfd = android_get_control_socket(DIAG_CMD_SOCKET);
325 if (cmdfd < 0 )
326 {
327 ERRMSG("***** DIAG Command Port: control socket Error: %s *****\r\n",strerror(errno));
328 return -1;
329 }
330#else
331 if (strlen(DIAG_CMD_SOCKET) < sizeof(socket_name.sun_path))
332 strcpy (socket_name.sun_path, DIAG_CMD_SOCKET);
333 else
334 {
335 /* socket path is TOO big for the socket name */
336 ERRMSG("socket path is TOO big for the socket name\n");
337 return -1;
338 }
339
340 cmdfd = socket(PF_UNIX, SOCK_STREAM, 0);
341 if ( cmdfd < 0 )
342 {
343 ERRMSG("***** DIAG Command Port: control socket Error: %s *****\r\n",strerror(errno));
344 return -1;
345 }
346
347 /* unlink to make sure the bind operation won't fail */
348 unlink(DIAG_CMD_SOCKET);
349
350 /* calculate length */
351 len = sizeof(socket_name.sun_family) + strlen(socket_name.sun_path);
352 if ( bind(cmdfd, (const struct sockaddr*) &socket_name, len) < 0 )
353 {
354 ERRMSG("***** DIAG Command Port: bind control socket Error: %s *****\r\n",strerror(errno));
355 close(cmdfd);
356 return -1;
357 }
358 (void)chmod(socket_name.sun_path, 0660);
359#endif
360
361 if( listen(cmdfd, MAX_CLIENT_NUMBER) < 0)
362 {
363 ERRMSG("***** DIAG Command Port: listen control socket Error: %s *****\r\n",strerror(errno));
364 close(cmdfd);
365 return -1;
366 }
367
368 cmdHandler = utlSetFdEventHandler(utlEVENT_HANDLER_TYPE_READ, utlEVENT_HANDLER_PRIORITY_LOW, cmdfd, acceptCmdPort, NULL);
369 return 0;
370}
371
372
373void closeCmdPort(void)
374{
375 utlDeleteEventHandler(cmdHandler);
376 close(cmdfd);
377 close_clients();
378 cmdfd = -1;
379}
380