1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2018 Intel Corporation
11 #include <sys/socket.h>
13 #include <sys/epoll.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
20 #define MSG_CMD_TOO_LONG "Command too long."
29 size_t msg_in_len_max
;
30 size_t msg_out_len_max
;
34 softnic_conn_msg_handle_t msg_handle
;
39 softnic_conn_init(struct softnic_conn_params
*p
)
41 struct sockaddr_in server_address
;
42 struct softnic_conn
*conn
;
43 int fd_server
, fd_client_group
, status
;
45 memset(&server_address
, 0, sizeof(server_address
));
47 /* Check input arguments */
53 p
->msg_in_len_max
== 0 ||
54 p
->msg_out_len_max
== 0 ||
55 p
->msg_handle
== NULL
)
58 status
= inet_aton(p
->addr
, &server_address
.sin_addr
);
62 /* Memory allocation */
63 conn
= calloc(1, sizeof(struct softnic_conn
));
67 conn
->welcome
= calloc(1, CONN_WELCOME_LEN_MAX
+ 1);
68 conn
->prompt
= calloc(1, CONN_PROMPT_LEN_MAX
+ 1);
69 conn
->buf
= calloc(1, p
->buf_size
);
70 conn
->msg_in
= calloc(1, p
->msg_in_len_max
+ 1);
71 conn
->msg_out
= calloc(1, p
->msg_out_len_max
+ 1);
73 if (conn
->welcome
== NULL
||
74 conn
->prompt
== NULL
||
76 conn
->msg_in
== NULL
||
77 conn
->msg_out
== NULL
) {
78 softnic_conn_free(conn
);
83 server_address
.sin_family
= AF_INET
;
84 server_address
.sin_port
= htons(p
->port
);
86 fd_server
= socket(AF_INET
,
87 SOCK_STREAM
| SOCK_NONBLOCK
,
89 if (fd_server
== -1) {
90 softnic_conn_free(conn
);
94 status
= bind(fd_server
,
95 (struct sockaddr
*)&server_address
,
96 sizeof(server_address
));
98 softnic_conn_free(conn
);
103 status
= listen(fd_server
, 16);
105 softnic_conn_free(conn
);
111 fd_client_group
= epoll_create(1);
112 if (fd_client_group
== -1) {
113 softnic_conn_free(conn
);
119 strncpy(conn
->welcome
, p
->welcome
, CONN_WELCOME_LEN_MAX
);
120 strncpy(conn
->prompt
, p
->prompt
, CONN_PROMPT_LEN_MAX
);
121 conn
->buf_size
= p
->buf_size
;
122 conn
->msg_in_len_max
= p
->msg_in_len_max
;
123 conn
->msg_out_len_max
= p
->msg_out_len_max
;
124 conn
->msg_in_len
= 0;
125 conn
->fd_server
= fd_server
;
126 conn
->fd_client_group
= fd_client_group
;
127 conn
->msg_handle
= p
->msg_handle
;
128 conn
->msg_handle_arg
= p
->msg_handle_arg
;
134 softnic_conn_free(struct softnic_conn
*conn
)
139 if (conn
->fd_client_group
)
140 close(conn
->fd_client_group
);
143 close(conn
->fd_server
);
153 softnic_conn_poll_for_conn(struct softnic_conn
*conn
)
155 struct sockaddr_in client_address
;
156 struct epoll_event event
;
157 socklen_t client_address_length
;
158 int fd_client
, status
;
160 /* Check input arguments */
165 client_address_length
= sizeof(client_address
);
166 fd_client
= accept4(conn
->fd_server
,
167 (struct sockaddr
*)&client_address
,
168 &client_address_length
,
170 if (fd_client
== -1) {
171 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
178 event
.events
= EPOLLIN
| EPOLLRDHUP
| EPOLLHUP
;
179 event
.data
.fd
= fd_client
;
181 status
= epoll_ctl(conn
->fd_client_group
,
191 status
= write(fd_client
,
193 strlen(conn
->welcome
));
199 status
= write(fd_client
,
201 strlen(conn
->prompt
));
211 data_event_handle(struct softnic_conn
*conn
,
214 ssize_t len
, i
, status
;
216 /* Read input message */
218 len
= read(fd_client
,
222 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
)
230 /* Handle input messages */
231 for (i
= 0; i
< len
; i
++) {
232 if (conn
->buf
[i
] == '\n') {
235 conn
->msg_in
[conn
->msg_in_len
] = 0;
236 conn
->msg_out
[0] = 0;
238 conn
->msg_handle(conn
->msg_in
,
240 conn
->msg_out_len_max
,
241 conn
->msg_handle_arg
);
243 n
= strlen(conn
->msg_out
);
245 status
= write(fd_client
,
252 conn
->msg_in_len
= 0;
253 } else if (conn
->msg_in_len
< conn
->msg_in_len_max
) {
254 conn
->msg_in
[conn
->msg_in_len
] = conn
->buf
[i
];
257 status
= write(fd_client
,
259 strlen(MSG_CMD_TOO_LONG
));
263 conn
->msg_in_len
= 0;
268 status
= write(fd_client
,
270 strlen(conn
->prompt
));
278 control_event_handle(struct softnic_conn
*conn
,
283 status
= epoll_ctl(conn
->fd_client_group
,
290 status
= close(fd_client
);
298 softnic_conn_poll_for_msg(struct softnic_conn
*conn
)
300 struct epoll_event event
;
301 int fd_client
, status
, status_data
= 0, status_control
= 0;
303 /* Check input arguments */
308 status
= epoll_wait(conn
->fd_client_group
,
317 fd_client
= event
.data
.fd
;
320 if (event
.events
& EPOLLIN
)
321 status_data
= data_event_handle(conn
, fd_client
);
324 if (event
.events
& (EPOLLRDHUP
| EPOLLERR
| EPOLLHUP
))
325 status_control
= control_event_handle(conn
, fd_client
);
327 if (status_data
|| status_control
)