Refactor to use new protocol module and sipo.
[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 #include "cfg/cfg_tcpsocket.h"
44
45 #define LOG_LEVEL   TCPSOCKET_LOG_LEVEL
46 #define LOG_FORMAT  TCPSOCKET_LOG_FORMAT
47 #include <cfg/log.h>
48 #include <cpu/byteorder.h>
49
50 #include <lwip/ip_addr.h>
51 #include <lwip/api.h>
52 #include <lwip/netif.h>
53 #include <lwip/netbuf.h>
54 #include <lwip/tcpip.h>
55
56
57 INLINE int close_socket(TcpSocket *socket)
58 {
59         /* Clean all previuos states */
60         netbuf_delete(socket->rx_buf_conn);
61         socket->rx_buf_conn = NULL;
62         socket->remaning_data_len = 0;
63         socket->error = 0;
64
65         if (!socket->sock)
66                 return 0;
67
68         /* Close socket if was opened */
69         socket->error = netconn_delete(socket->sock);
70         socket->sock = NULL;
71
72         if (socket->error != ERR_OK)
73         {
74                 LOG_ERR("Closing socket\n");
75                 return -1;
76         }
77
78         return 0;
79 }
80
81 static bool tcpsocket_reconnect(TcpSocket *socket)
82 {
83         LOG_INFO("Reconnecting...\n");
84
85         /* Close socket if was opened */
86         close_socket(socket);
87
88         /* If we are in server mode we do nothing */
89         if (socket->handler)
90                 return true;
91
92
93         /* Start with new connection */
94         socket->sock = netconn_new(NETCONN_TCP);
95         if(!socket->sock)
96         {
97                 LOG_ERR("Unabe to alloc new connection\n");
98                 socket->error = -1;
99                 goto error;
100         }
101
102         socket->error = netconn_bind(socket->sock, socket->local_addr, socket->port);
103         if(socket->error != ERR_OK)
104         {
105                 LOG_ERR("Connection error\n");
106                 goto error;
107         }
108
109         socket->error = netconn_connect(socket->sock, socket->remote_addr, socket->port);
110         if(socket->error != ERR_OK)
111         {
112                 LOG_ERR("Cannot create socket\n");
113                 goto error;
114         }
115
116         LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->remote_addr->addr));
117         return true;
118
119 error:
120         netconn_delete(socket->sock);
121         socket->sock = NULL;
122         return false;
123 }
124
125 static int tcpsocket_close(KFile *fd)
126 {
127         TcpSocket *socket = TCPSOCKET_CAST(fd);
128         return close_socket(socket);
129 }
130
131 static KFile *tcpsocket_reopen(KFile *fd)
132 {
133         TcpSocket *socket = TCPSOCKET_CAST(fd);
134         if (tcpsocket_reconnect(socket))
135                 return fd;
136
137         return NULL;
138 }
139
140 /*
141  * Read data from socket.
142  *
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
146  * buffer is empty.
147  * When there are not any more bytes, a new read takes data from remote socket.
148  */
149 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
150 {
151         TcpSocket *socket = TCPSOCKET_CAST(fd);
152
153         char *data;
154         uint16_t read_len = 0;
155
156         if (socket->remaning_data_len <= 0)
157         {
158                 LOG_INFO("No byte left.\n");
159                 netbuf_delete(socket->rx_buf_conn);
160         }
161         else /* We had byte into buffer use that */
162         {
163                 LOG_INFO("Read stored bytes.\n");
164                 if (!socket->rx_buf_conn)
165                 {
166                         LOG_ERR("Byte stored are corrupted!\n");
167                         socket->remaning_data_len = 0;
168                         return 0;
169                 }
170                 uint16_t tot_data_len = 0;
171                 netbuf_data(socket->rx_buf_conn, (void **)&data, &tot_data_len);
172
173                 if (data)
174                 {
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);
178
179                         socket->remaning_data_len -= chunk_len;
180                         return chunk_len;
181                 }
182                 else
183                 {
184                         LOG_ERR("No valid data to read\n");
185                         socket->remaning_data_len = 0;
186                         netbuf_delete(socket->rx_buf_conn);
187                         return 0;
188                 }
189         }
190
191         /* Try reconnecting if our socket isn't valid */
192         if (!socket->sock && !tcpsocket_reconnect(socket))
193                 return 0;
194
195         while (len)
196         {
197                 LOG_INFO("Get bytes from socket.\n");
198                 socket->rx_buf_conn = netconn_recv(socket->sock);
199
200                 socket->error = netconn_err(socket->sock);
201                 if (socket->error != ERR_OK)
202                 {
203                         LOG_ERR("While recv %d\n", socket->error);
204                         close_socket(socket);
205                         return 0;
206                 }
207
208                 size_t chunk_len = 0;
209                 uint16_t data_len = 0;
210                 if (socket->rx_buf_conn)
211                 {
212                         netbuf_data(socket->rx_buf_conn, (void **)&data, &data_len);
213
214                         if (data)
215                         {
216                                 chunk_len = MIN((size_t)data_len, len);
217                                 memcpy(buf, data, chunk_len);
218
219                                 socket->remaning_data_len = data_len - chunk_len;
220                         }
221
222                         if (socket->remaning_data_len <= 0)
223                         {
224                                 netbuf_delete(socket->rx_buf_conn);
225                                 socket->rx_buf_conn = NULL;
226                                 socket->remaning_data_len = 0;
227                                 return chunk_len;
228                         }
229                 }
230
231                 len -= chunk_len;
232                 read_len += chunk_len;
233         }
234
235         return read_len;
236 }
237
238 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
239 {
240         TcpSocket *socket = TCPSOCKET_CAST(fd);
241
242         /* Try reconnecting if our socket isn't valid */
243         if (!socket->sock && !tcpsocket_reconnect(socket))
244                 return 0;
245
246         socket->error = netconn_write(socket->sock, buf, len, NETCONN_COPY);
247         if (socket->error != ERR_OK)
248         {
249                 LOG_ERR("While writing %d\n", socket->error);
250                 close_socket(socket);
251                 return 0;
252         }
253
254         return len;
255 }
256
257 static int tcpsocket_error(KFile *fd)
258 {
259         TcpSocket *socket = TCPSOCKET_CAST(fd);
260         return socket->error;
261 }
262
263 static void tcpsocket_clearerr(KFile *fd)
264 {
265         TcpSocket *socket = TCPSOCKET_CAST(fd);
266         socket->error = 0;
267 }
268
269 void tcpsocket_serverPoll(KFile *fd)
270 {
271         TcpSocket *socket = TCPSOCKET_CAST(fd);
272
273
274         if (!socket->sock)
275                 socket->sock = netconn_accept(socket->server_sock);
276
277         if (!socket->sock)
278         {
279                 LOG_ERR("Unable to connect with client\n");
280                 return;
281         }
282
283         socket->handler(fd);
284 }
285
286 void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *remote_addr, uint16_t port)
287 {
288         memset(socket, 0, sizeof(TcpSocket));
289
290         socket->local_addr = local_addr;
291         socket->remote_addr = remote_addr;
292         socket->port = port;
293
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;
301
302 }
303
304 void tcpsocket_serverInit(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *listen_addr, uint16_t port, tcphandler_t handler)
305 {
306         tcpsocket_init(socket, local_addr, listen_addr, port);
307         socket->handler = handler;
308
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");
314 }