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 #define LOG_LEVEL LOG_LVL_INFO
44 #define LOG_FORMAT LOG_FMT_TERSE
46 #include <cpu/byteorder.h>
48 #include <lwip/ip_addr.h>
50 #include <lwip/netif.h>
51 #include <lwip/netbuf.h>
52 #include <lwip/tcpip.h>
54 static int tcpConnect(TcpSocket *socket)
56 socket->remaning_data_len = 0;
57 socket->sock = netconn_new(NETCONN_TCP);
60 if(netconn_bind(socket->sock, socket->local_addr, socket->port) != ERR_OK)
62 LOG_ERR("Connection error\n");
66 if(netconn_connect(socket->sock, socket->remote_addr, socket->port) != ERR_OK)
68 LOG_ERR("Cannot create socket\n");
72 LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->local_addr->addr));
76 netconn_delete(socket->sock);
82 static bool reconnect(TcpSocket *socket)
84 LOG_INFO("Reconnecting...\n");
85 // Release old socket if needed
88 if (netconn_delete(socket->sock) != ERR_OK)
89 LOG_ERR("Error closing socket\n");
94 // Connect to our peer peer
95 if (tcpConnect(socket) < 0)
97 LOG_ERR("Reconnect error!\n");
98 socket->error |= ERR_TCP_NOTCONN;
102 LOG_INFO("Reconnecting DONE!\n");
107 static int tcpsocket_close(KFile *fd)
109 TcpSocket *socket = TCPSOCKET_CAST(fd);
110 int ret = netconn_delete(socket->sock);
115 LOG_ERR("Close error\n");
116 socket->error |= ERR_CONN_CLOSE;
122 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
124 TcpSocket *socket = TCPSOCKET_CAST(fd);
126 uint16_t read_len = 0;
127 uint16_t recv_data_len = 0;
130 if (socket->remaning_data_len == 0)
132 LOG_INFO("No byte left.\n");
133 if (socket->rx_buf_conn)
134 netbuf_delete(socket->rx_buf_conn);
136 else if (socket->remaning_data_len > 0)
138 LOG_INFO("Return stored bytes.\n");
139 ASSERT(socket->rx_buf_conn);
140 netbuf_data(socket->rx_buf_conn, (void **)&_buf, &recv_data_len);
144 ASSERT((recv_data_len - socket->remaning_data_len) > 0);
145 _len = MIN((size_t)(socket->remaning_data_len), len);
146 memcpy((char *)buf, &_buf[recv_data_len - socket->remaning_data_len], _len);
148 socket->remaning_data_len -= _len;
153 LOG_ERR("No valid data to read\n");
154 socket->remaning_data_len = 0;
155 netbuf_delete(socket->rx_buf_conn);
160 /* Try reconnecting if our socket isn't valid */
163 if (!reconnect(socket))
169 LOG_INFO("Get bytes from socket.\n");
170 socket->rx_buf_conn = netconn_recv(socket->sock);
171 socket->error = netconn_err(socket->sock);
173 if (socket->error != ERR_OK)
175 LOG_ERR("While recv %d\n", socket->error);
176 socket->rx_buf_conn = NULL;
180 if (socket->rx_buf_conn)
182 netbuf_data(socket->rx_buf_conn, (void **)&_buf, &recv_data_len);
185 socket->remaning_data_len = recv_data_len;
186 _len = MIN((size_t)recv_data_len, len);
187 memcpy(buf, _buf, _len);
188 socket->remaning_data_len -= _len;
191 if (socket->remaning_data_len <= 0)
193 netbuf_delete(socket->rx_buf_conn);
205 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
207 TcpSocket *socket = TCPSOCKET_CAST(fd);
209 // Try reconnecting if our socket isn't valid
212 if (!reconnect(socket))
216 int result = netconn_write(socket->sock, buf, len, NETCONN_COPY);
217 if (result != ERR_OK)
219 LOG_ERR("While writing %d\n", result);
220 if (result == ERR_RST)
222 LOG_INFO("Connection close\n");
224 if (tcpsocket_close(fd) == EOF)
225 LOG_ERR("Error closing socket, leak detected\n");
234 static int tcpsocket_error(KFile *fd)
236 TcpSocket *socket = TCPSOCKET_CAST(fd);
237 return socket->error;
240 static void tcpsocket_clearerr(KFile *fd)
242 TcpSocket *socket = TCPSOCKET_CAST(fd);
246 void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *remote_addr, uint16_t port)
249 socket->local_addr = local_addr;
250 socket->remote_addr = remote_addr;
253 socket->fd._type = KFT_TCPSOCKET;
254 socket->fd.read = tcpsocket_read;
255 socket->fd.error = tcpsocket_error;
256 socket->fd.close = tcpsocket_close;
257 socket->fd.write = tcpsocket_write;
258 socket->fd.clearerr = tcpsocket_clearerr;