Clean up the code. Manage the reconnection. Use the lwip error, insted
[bertos.git] / bertos / net / tcp_socket.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
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.
10  *
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.
15  *
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
19  *
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.
28  *
29  * Copyright 2012 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief TCP sockect with kfile interface.
34  *
35  * \author Luca Ottaviano <lottaviano@develer.com>
36  * \author Daniele Basile <asterix@develer.com>
37  *
38  * notest:avr
39  */
40
41 #include "tcp_socket.h"
42
43 #define LOG_LEVEL   LOG_LVL_INFO
44 #define LOG_FORMAT  LOG_FMT_TERSE
45 #include <cfg/log.h>
46 #include <cpu/byteorder.h>
47
48 #include <lwip/ip_addr.h>
49 #include <lwip/api.h>
50 #include <lwip/netif.h>
51 #include <lwip/netbuf.h>
52 #include <lwip/tcpip.h>
53
54
55 INLINE int close_socket(TcpSocket *socket)
56 {
57         /* Clean all previuos states */
58         netbuf_delete(socket->rx_buf_conn);
59         socket->rx_buf_conn = NULL;
60         socket->remaning_data_len = 0;
61         socket->error = 0;
62
63         if (!socket->sock)
64                 return 0;
65
66         /* Close socket if was opened */
67         socket->error = netconn_delete(socket->sock);
68         socket->sock = NULL;
69
70         if (socket->error != ERR_OK)
71         {
72                 LOG_ERR("Closing socket\n");
73                 return -1;
74         }
75
76         return 0;
77 }
78
79 static bool tcpsocket_reconnect(TcpSocket *socket)
80 {
81         LOG_INFO("Reconnecting...\n");
82
83         /* Close socket if was opened */
84         close_socket(socket);
85
86         /* Start with new connection */
87         socket->sock = netconn_new(NETCONN_TCP);
88         if(!socket->sock)
89         {
90                 LOG_ERR("Unabe to alloc new connection\n");
91                 socket->error = -1;
92                 goto error;
93         }
94
95         socket->error = netconn_bind(socket->sock, socket->local_addr, socket->port);
96         if(socket->error != ERR_OK)
97         {
98                 LOG_ERR("Connection error\n");
99                 goto error;
100         }
101
102         socket->error = netconn_connect(socket->sock, socket->remote_addr, socket->port);
103         if(socket->error != ERR_OK)
104         {
105                 LOG_ERR("Cannot create socket\n");
106                 goto error;
107         }
108
109         LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->remote_addr->addr));
110         return true;
111
112 error:
113         netconn_delete(socket->sock);
114         socket->sock = NULL;
115         return false;
116 }
117
118 static int tcpsocket_close(KFile *fd)
119 {
120         TcpSocket *socket = TCPSOCKET_CAST(fd);
121         return close_socket(socket);
122 }
123
124 static KFile *tcpsocket_reopen(KFile *fd)
125 {
126         TcpSocket *socket = TCPSOCKET_CAST(fd);
127         if (tcpsocket_reconnect(socket))
128                 return fd;
129
130         return NULL;
131 }
132
133 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
134 {
135         TcpSocket *socket = TCPSOCKET_CAST(fd);
136
137         char *data;
138         uint16_t read_len = 0;
139
140         if (socket->remaning_data_len <= 0)
141         {
142                 LOG_INFO("No byte left.\n");
143                 netbuf_delete(socket->rx_buf_conn);
144         }
145         else /* We had byte into buffer use that */
146         {
147                 LOG_INFO("Read stored bytes.\n");
148                 if (!socket->rx_buf_conn)
149                 {
150                         LOG_ERR("Byte stored are corrupted!\n");
151                         socket->remaning_data_len = 0;
152                         return 0;
153                 }
154                 uint16_t tot_data_len = 0;
155                 netbuf_data(socket->rx_buf_conn, (void **)&data, &tot_data_len);
156
157                 if (data)
158                 {
159                         ASSERT(((int)tot_data_len - (int)socket->remaning_data_len) >= 0);
160                         size_t chunk_len = MIN((size_t)(socket->remaning_data_len), len);
161                         memcpy((char *)buf, &data[tot_data_len - socket->remaning_data_len], chunk_len);
162
163                         socket->remaning_data_len -= chunk_len;
164                         return chunk_len;
165                 }
166                 else
167                 {
168                         LOG_ERR("No valid data to read\n");
169                         socket->remaning_data_len = 0;
170                         netbuf_delete(socket->rx_buf_conn);
171                         return 0;
172                 }
173         }
174
175         /* Try reconnecting if our socket isn't valid */
176         LOG_INFO("sock[%s]\n", socket->sock ? "valido":"nullo");
177         if (!socket->sock && !tcpsocket_reconnect(socket))
178                 return 0;
179         LOG_INFO("sock1[%s]\n", socket->sock ? "valido":"nullo");
180
181         while (len)
182         {
183                 LOG_INFO("Get bytes from socket.\n");
184                 socket->rx_buf_conn = netconn_recv(socket->sock);
185
186                 socket->error = netconn_err(socket->sock);
187                 if (socket->error != ERR_OK)
188                 {
189                         LOG_ERR("While recv %d\n", socket->error);
190                         close_socket(socket);
191                         return 0;
192                 }
193
194                 size_t chunk_len = 0;
195                 uint16_t data_len = 0;
196                 if (socket->rx_buf_conn)
197                 {
198                         netbuf_data(socket->rx_buf_conn, (void **)&data, &data_len);
199
200                         if (data)
201                         {
202                                 chunk_len = MIN((size_t)data_len, len);
203                                 memcpy(buf, data, chunk_len);
204
205                                 socket->remaning_data_len = data_len - chunk_len;
206                         }
207
208                         if (socket->remaning_data_len <= 0)
209                         {
210                                 netbuf_delete(socket->rx_buf_conn);
211                                 socket->rx_buf_conn = NULL;
212                                 socket->remaning_data_len = 0;
213                                 return chunk_len;
214                         }
215                 }
216
217                 len -= chunk_len;
218                 read_len += chunk_len;
219         }
220
221         return read_len;
222 }
223
224 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
225 {
226         TcpSocket *socket = TCPSOCKET_CAST(fd);
227
228         /* Try reconnecting if our socket isn't valid */
229         if (!socket->sock && !tcpsocket_reconnect(socket))
230                 return 0;
231
232         socket->error = netconn_write(socket->sock, buf, len, NETCONN_COPY);
233         if (socket->error != ERR_OK)
234         {
235                 LOG_ERR("While writing %d\n", socket->error);
236                 close_socket(socket);
237                 return 0;
238         }
239
240         return len;
241 }
242
243 static int tcpsocket_error(KFile *fd)
244 {
245         TcpSocket *socket = TCPSOCKET_CAST(fd);
246         return socket->error;
247 }
248
249 static void tcpsocket_clearerr(KFile *fd)
250 {
251         TcpSocket *socket = TCPSOCKET_CAST(fd);
252         socket->error = 0;
253 }
254
255 void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *remote_addr, uint16_t port)
256 {
257         socket->sock = NULL;
258         socket->local_addr = local_addr;
259         socket->remote_addr = remote_addr;
260         socket->port = port;
261
262         socket->fd._type = KFT_TCPSOCKET;
263         socket->fd.read = tcpsocket_read;
264         socket->fd.error = tcpsocket_error;
265         socket->fd.close = tcpsocket_close;
266         socket->fd.write = tcpsocket_write;
267         socket->fd.clearerr = tcpsocket_clearerr;
268         socket->fd.reopen = tcpsocket_reopen;
269
270 }