4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2012 Develer S.r.l. (http://www.develer.com/)
33 * \brief TCP sockect with kfile interface.
35 * \author Luca Ottaviano <lottaviano@develer.com>
36 * \author Daniele Basile <asterix@develer.com>
41 #include "tcp_socket.h"
43 #include "cfg/cfg_tcpsocket.h"
45 #define LOG_LEVEL TCPSOCKET_LOG_LEVEL
46 #define LOG_FORMAT TCPSOCKET_LOG_FORMAT
48 #include <cpu/byteorder.h>
50 #include <lwip/ip_addr.h>
52 #include <lwip/netif.h>
53 #include <lwip/netbuf.h>
54 #include <lwip/tcpip.h>
57 INLINE int close_socket(TcpSocket *socket)
59 /* Clean all previuos states */
60 netbuf_delete(socket->rx_buf_conn);
61 socket->rx_buf_conn = NULL;
62 socket->remaning_data_len = 0;
68 /* Close socket if was opened */
69 socket->error = netconn_delete(socket->sock);
72 if (socket->error != ERR_OK)
74 LOG_ERR("Closing socket\n");
81 static bool tcpsocket_reconnect(TcpSocket *socket)
83 LOG_INFO("Reconnecting...\n");
85 /* Close socket if was opened */
88 /* If we are in server mode we do nothing */
93 /* Start with new connection */
94 socket->sock = netconn_new(NETCONN_TCP);
97 LOG_ERR("Unabe to alloc new connection\n");
102 socket->error = netconn_bind(socket->sock, socket->local_addr, socket->port);
103 if(socket->error != ERR_OK)
105 LOG_ERR("Connection error\n");
109 socket->error = netconn_connect(socket->sock, socket->remote_addr, socket->port);
110 if(socket->error != ERR_OK)
112 LOG_ERR("Cannot create socket\n");
116 LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->remote_addr->addr));
120 netconn_delete(socket->sock);
125 static int tcpsocket_close(KFile *fd)
127 TcpSocket *socket = TCPSOCKET_CAST(fd);
128 return close_socket(socket);
131 static KFile *tcpsocket_reopen(KFile *fd)
133 TcpSocket *socket = TCPSOCKET_CAST(fd);
134 if (tcpsocket_reconnect(socket))
141 * Read data from socket.
143 * The read return the bytes that had been received if they are less than we request too.
144 * Otherwise if the byte that we want read are less that the received bytes, we return only
145 * the requested bytes. To get the remaning bytes we need to make an others read, until the
147 * When there are not any more bytes, a new read takes data from remote socket.
149 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
151 TcpSocket *socket = TCPSOCKET_CAST(fd);
154 uint16_t read_len = 0;
156 if (socket->remaning_data_len <= 0)
158 LOG_INFO("No byte left.\n");
159 netbuf_delete(socket->rx_buf_conn);
161 else /* We had byte into buffer use that */
163 LOG_INFO("Read stored bytes.\n");
164 if (!socket->rx_buf_conn)
166 LOG_ERR("Byte stored are corrupted!\n");
167 socket->remaning_data_len = 0;
170 uint16_t tot_data_len = 0;
171 netbuf_data(socket->rx_buf_conn, (void **)&data, &tot_data_len);
175 ASSERT(((int)tot_data_len - (int)socket->remaning_data_len) >= 0);
176 size_t chunk_len = MIN((size_t)(socket->remaning_data_len), len);
177 memcpy((char *)buf, &data[tot_data_len - socket->remaning_data_len], chunk_len);
179 socket->remaning_data_len -= chunk_len;
184 LOG_ERR("No valid data to read\n");
185 socket->remaning_data_len = 0;
186 netbuf_delete(socket->rx_buf_conn);
191 /* Try reconnecting if our socket isn't valid */
192 if (!socket->sock && !tcpsocket_reconnect(socket))
197 LOG_INFO("Get bytes from socket.\n");
198 socket->rx_buf_conn = netconn_recv(socket->sock);
200 socket->error = netconn_err(socket->sock);
201 if (socket->error != ERR_OK)
203 LOG_ERR("While recv %d\n", socket->error);
204 close_socket(socket);
208 size_t chunk_len = 0;
209 uint16_t data_len = 0;
210 if (socket->rx_buf_conn)
212 netbuf_data(socket->rx_buf_conn, (void **)&data, &data_len);
216 chunk_len = MIN((size_t)data_len, len);
217 memcpy(buf, data, chunk_len);
219 socket->remaning_data_len = data_len - chunk_len;
222 if (socket->remaning_data_len <= 0)
224 netbuf_delete(socket->rx_buf_conn);
225 socket->rx_buf_conn = NULL;
226 socket->remaning_data_len = 0;
232 read_len += chunk_len;
238 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
240 TcpSocket *socket = TCPSOCKET_CAST(fd);
242 /* Try reconnecting if our socket isn't valid */
243 if (!socket->sock && !tcpsocket_reconnect(socket))
246 socket->error = netconn_write(socket->sock, buf, len, NETCONN_COPY);
247 if (socket->error != ERR_OK)
249 LOG_ERR("While writing %d\n", socket->error);
250 close_socket(socket);
257 static int tcpsocket_error(KFile *fd)
259 TcpSocket *socket = TCPSOCKET_CAST(fd);
260 return socket->error;
263 static void tcpsocket_clearerr(KFile *fd)
265 TcpSocket *socket = TCPSOCKET_CAST(fd);
269 void tcpsocket_serverPoll(KFile *fd)
271 TcpSocket *socket = TCPSOCKET_CAST(fd);
275 socket->sock = netconn_accept(socket->server_sock);
279 LOG_ERR("Unable to connect with client\n");
286 void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *remote_addr, uint16_t port)
288 memset(socket, 0, sizeof(TcpSocket));
290 socket->local_addr = local_addr;
291 socket->remote_addr = remote_addr;
294 socket->fd._type = KFT_TCPSOCKET;
295 socket->fd.read = tcpsocket_read;
296 socket->fd.error = tcpsocket_error;
297 socket->fd.close = tcpsocket_close;
298 socket->fd.write = tcpsocket_write;
299 socket->fd.clearerr = tcpsocket_clearerr;
300 socket->fd.reopen = tcpsocket_reopen;
304 void tcpsocket_serverInit(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *listen_addr, uint16_t port, tcphandler_t handler)
306 tcpsocket_init(socket, local_addr, listen_addr, port);
307 socket->handler = handler;
309 socket->server_sock = netconn_new(NETCONN_TCP);
310 socket->error = netconn_bind(socket->server_sock, listen_addr, port);
311 socket->error = netconn_listen(socket->server_sock);
312 if(socket->error != ERR_OK)
313 LOG_ERR("Init server\n");