-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathm3_cli.c
246 lines (216 loc) · 6.66 KB
/
m3_cli.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#include "m3_cli.h"
#include <libmcip.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
/* free wrapper function to avoid dangling pointers */
void safefree(void **pp)
{
if (pp != NULL) {
free(*pp);
*pp = NULL;
}
return;
}
/* generic read from the cli socket
fd is needed
answer if given, the answer is written into the buffer (careful, allocated)
prompt if given, the reading of the answer stops on receipt of the prompt (and the prompt is trimmed from the answer)
waittime_ms maximum amount of time (in milliseconds) to wait for an answer (use 0 to simply read and discard present data on the socket) */
bool m3_cli_read_socket(int fd, char **answer, char *prompt, int waittime_ms)
{
char buffer[100];
fd_set read_fds;
struct timeval tv;
int ret, read_bytes, current_size = 0;
char *cli_reply = NULL, *p;
for (;;) {
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
/* use the correct waittime */
if (waittime_ms) {
tv.tv_sec = waittime_ms / 1000;
tv.tv_usec = waittime_ms * 1000;
}
else {
tv.tv_sec = 0;
tv.tv_usec = 0;
}
ret = select(fd + 1, &read_fds, NULL, NULL, &tv);
/* on timeout always return */
if (ret == 0) {
break;
}
if (ret == -1) {
safefree((void **) &cli_reply);
return false;
}
/* the socket is ready */
if (FD_ISSET(fd, &read_fds)) {
read_bytes = read(fd, buffer, 100);
/* if there are no bytes any more (EOF) return */
if (read_bytes == 0) {
break;
}
if (read_bytes == -1) {
safefree((void **) &cli_reply);
return false;
}
/* append to the internal reply */
cli_reply = realloc(cli_reply, current_size + read_bytes + 1);
memcpy(cli_reply + current_size, buffer, read_bytes);
current_size += read_bytes;
cli_reply[current_size] = '\0';
/* detect a prompt (if given) */
if (prompt != NULL) {
p = strstr(cli_reply, prompt);
if (p != NULL) {
*p = '\0';
break;
}
}
}
}
/* if the answer is queried, store it in the given buffer */
if (answer != NULL) {
*answer = calloc(1, current_size + 1);
memcpy(*answer, cli_reply, current_size);
}
safefree((void **) &cli_reply);
return true;
}
/* close the socket */
void m3_cli_close(struct s_m3_cli *cli)
{
if (cli->fd != -1) {
close(cli->fd);
}
return;
}
/* read the cli prompt */
bool m3_cli_read_prompt(struct s_m3_cli *cli)
{
if (cli->fd == -1) {
errno = EBADF;
return false;
}
/* discard all data on the socket */
if (!m3_cli_read_socket(cli->fd, NULL, NULL, cli->waittime_ms) ||
write(cli->fd, "\n", 1) != 1 ||
!m3_cli_read_socket(cli->fd, &(cli->prompt), NULL, cli->waittime_ms)) {
m3_cli_close(cli);
errno = EIO;
return false;
}
return true;
}
/* open UDS connection and read prompt */
bool m3_cli_open(struct s_m3_cli *cli)
{
/* open UDS connection */
cli->fd = mcip_open_uds_socket(cli->socket_path);
if (cli->fd < 0) {
return false;
}
/* read prompt */
return m3_cli_read_prompt(cli);
}
/* function that send a command to the socket and retrieves the answer */
bool m3_cli_command(struct s_m3_cli *cli, char *command, char **answer, int waittime_ms)
{
/* if the socket is down, open it (and read prompt) */
if (cli->fd == -1) {
if (!m3_cli_open(cli)) {
errno = EIO;
return false;
}
}
/* clear the socket from not fetched data, send command, send \n and get the answer */
if (!m3_cli_read_socket(cli->fd, NULL, NULL, 0) ||
write(cli->fd, command, strlen(command)) != strlen(command) ||
write(cli->fd, "\n", 1) != 1 ||
!m3_cli_read_socket(cli->fd, answer, cli->prompt, waittime_ms)) {
m3_cli_close(cli);
errno = EIO;
return false;
}
return true;
}
/* warpper to send a command to the cli without caring about the answer */
bool m3_cli_send(struct s_m3_cli *cli, char *command)
{
/* discard data on the socket */
if (cli == NULL || command == NULL) {
errno = EINVAL;
return false;
}
return m3_cli_command(cli, command, NULL, cli->waittime_ms);
}
/* wrapper to send a command to the cli but read back the answer */
bool m3_cli_query(struct s_m3_cli *cli, char *command, char **answer, int waittime_ms)
{
/* discard data on the socket */
if (cli == NULL || command == NULL || answer == NULL) {
errno = EINVAL;
return false;
}
if (waittime_ms == 0) {
waittime_ms = cli->waittime_ms;
}
return m3_cli_command(cli, command, answer, waittime_ms);
}
/* wrapper to send a command to the cli but read back the answer and report if the answer is a null sting or "is unknown" */
bool m3_cli_query_verified(struct s_m3_cli *cli, char *command, char **answer, int waittime_ms)
{
if (m3_cli_query(cli, command, answer, waittime_ms) == false) {
return false;
}
if (*answer == NULL) {
errno = EINVAL;
return false;
}
if (strlen(*answer) < 1 || strstr(*answer, "is unknown")) {
safefree((void **) answer);
errno = EINVAL;
return false;
}
return true;
}
/* close cli socket and free the struct */
void m3_cli_shutdown(struct s_m3_cli **cli)
{
if ( cli == NULL || (*cli) == NULL) {
return;
}
m3_cli_close(*cli);
safefree((void **)&((*cli)->socket_path));
safefree((void **)&((*cli)->prompt));
safefree((void **)cli);
return;
}
/* open the cli socket and get the prompt
returns a struct containing all cli information
on error, NULL is returned and errno set appropriately */
struct s_m3_cli *m3_cli_initialise(const char *socket_path, int default_waittime_ms)
{
struct s_m3_cli *cli;
if (socket_path == NULL || default_waittime_ms == 0) {
errno = EINVAL;
return NULL;
}
if (access(socket_path, F_OK)) {
errno = ENODEV;
return NULL;
}
cli = calloc(1, sizeof(struct s_m3_cli));
cli->fd = -1;
cli->waittime_ms = default_waittime_ms;
cli->socket_path = calloc(1, strlen(socket_path) + 1);
strcpy(cli->socket_path, socket_path);
if (!m3_cli_open(cli)) {
m3_cli_shutdown(&cli);
errno = EIO;
return NULL;
}
return cli;
}