Clean up the code. Manage the reconnection. Use the lwip error, insted
[bertos.git] / bertos / net / tcp_socket.c
index 1924a60495b1d48777cac0588b1633866541f2d5..030f55f3351e50a7cb11ce0bb16bf3d50c03ddc2 100644 (file)
  *
  * \author Luca Ottaviano <lottaviano@develer.com>
  * \author Daniele Basile <asterix@develer.com>
+ *
+ * notest:avr
  */
 
 #include "tcp_socket.h"
 
-#define LOG_LEVEL   LOG_LVL_WARN
+#define LOG_LEVEL   LOG_LVL_INFO
 #define LOG_FORMAT  LOG_FMT_TERSE
 #include <cfg/log.h>
 #include <cpu/byteorder.h>
 
 #include <lwip/ip_addr.h>
+#include <lwip/api.h>
 #include <lwip/netif.h>
 #include <lwip/netbuf.h>
 #include <lwip/tcpip.h>
 
-static int tcpConnect(TcpSocket *socket)
+
+INLINE int close_socket(TcpSocket *socket)
 {
-       socket->sock = netconn_new(NETCONN_TCP);
-       ASSERT(socket->sock);
+       /* Clean all previuos states */
+       netbuf_delete(socket->rx_buf_conn);
+       socket->rx_buf_conn = NULL;
+       socket->remaning_data_len = 0;
+       socket->error = 0;
 
-       if(netconn_bind(socket->sock, socket->local_addr, socket->port) != ERR_OK)
-       {
-               LOG_ERR("Connection error\n");
-               goto error;
-       }
+       if (!socket->sock)
+               return 0;
+
+       /* Close socket if was opened */
+       socket->error = netconn_delete(socket->sock);
+       socket->sock = NULL;
 
-       if(netconn_connect(socket->sock, socket->remote_addr, socket->port) != ERR_OK)
+       if (socket->error != ERR_OK)
        {
-               LOG_ERR("Cannot create socket\n");
-               goto error;
+               LOG_ERR("Closing socket\n");
+               return -1;
        }
 
-       LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->local_addr->addr));
        return 0;
-
-error:
-       netconn_delete(socket->sock);
-       socket->sock = NULL;
-       return -1;
 }
 
-
-static bool reconnect(TcpSocket *socket)
+static bool tcpsocket_reconnect(TcpSocket *socket)
 {
        LOG_INFO("Reconnecting...\n");
-       // Release old socket if needed
-       if (socket->sock)
-       {
-               if (netconn_delete(socket->sock) != ERR_OK)
-                       LOG_ERR("Error closing socket\n");
 
-               socket->sock = NULL;
+       /* Close socket if was opened */
+       close_socket(socket);
+
+       /* Start with new connection */
+       socket->sock = netconn_new(NETCONN_TCP);
+       if(!socket->sock)
+       {
+               LOG_ERR("Unabe to alloc new connection\n");
+               socket->error = -1;
+               goto error;
        }
 
-       // Connect to our peer peer
-       if (tcpConnect(socket) < 0)
+       socket->error = netconn_bind(socket->sock, socket->local_addr, socket->port);
+       if(socket->error != ERR_OK)
        {
-               LOG_ERR("Reconnect error!\n");
-               socket->error |= ERR_TCP_NOTCONN;
-               return false;
+               LOG_ERR("Connection error\n");
+               goto error;
        }
 
-       LOG_INFO("Reconnecting DONE!\n");
+       socket->error = netconn_connect(socket->sock, socket->remote_addr, socket->port);
+       if(socket->error != ERR_OK)
+       {
+               LOG_ERR("Cannot create socket\n");
+               goto error;
+       }
 
+       LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->remote_addr->addr));
        return true;
+
+error:
+       netconn_delete(socket->sock);
+       socket->sock = NULL;
+       return false;
 }
 
 static int tcpsocket_close(KFile *fd)
 {
        TcpSocket *socket = TCPSOCKET_CAST(fd);
-       int ret = netconn_delete(socket->sock);
-       socket->sock = NULL;
+       return close_socket(socket);
+}
 
-       if (ret)
-       {
-               LOG_ERR("Close error\n");
-               socket->error |= ERR_CONN_CLOSE;
-               return EOF;
-       }
-       return 0;
+static KFile *tcpsocket_reopen(KFile *fd)
+{
+       TcpSocket *socket = TCPSOCKET_CAST(fd);
+       if (tcpsocket_reconnect(socket))
+               return fd;
+
+       return NULL;
 }
 
 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
 {
        TcpSocket *socket = TCPSOCKET_CAST(fd);
-       uint16_t recv_len = 0;
 
-       // Try reconnecting if our socket isn't valid
-       if (!socket->sock)
+       char *data;
+       uint16_t read_len = 0;
+
+       if (socket->remaning_data_len <= 0)
+       {
+               LOG_INFO("No byte left.\n");
+               netbuf_delete(socket->rx_buf_conn);
+       }
+       else /* We had byte into buffer use that */
        {
-               if (!reconnect(socket))
+               LOG_INFO("Read stored bytes.\n");
+               if (!socket->rx_buf_conn)
+               {
+                       LOG_ERR("Byte stored are corrupted!\n");
+                       socket->remaning_data_len = 0;
+                       return 0;
+               }
+               uint16_t tot_data_len = 0;
+               netbuf_data(socket->rx_buf_conn, (void **)&data, &tot_data_len);
+
+               if (data)
+               {
+                       ASSERT(((int)tot_data_len - (int)socket->remaning_data_len) >= 0);
+                       size_t chunk_len = MIN((size_t)(socket->remaning_data_len), len);
+                       memcpy((char *)buf, &data[tot_data_len - socket->remaning_data_len], chunk_len);
+
+                       socket->remaning_data_len -= chunk_len;
+                       return chunk_len;
+               }
+               else
+               {
+                       LOG_ERR("No valid data to read\n");
+                       socket->remaning_data_len = 0;
+                       netbuf_delete(socket->rx_buf_conn);
                        return 0;
+               }
        }
 
+       /* Try reconnecting if our socket isn't valid */
+       LOG_INFO("sock[%s]\n", socket->sock ? "valido":"nullo");
+       if (!socket->sock && !tcpsocket_reconnect(socket))
+               return 0;
+       LOG_INFO("sock1[%s]\n", socket->sock ? "valido":"nullo");
+
        while (len)
        {
-               struct netbuf *rx_buf_conn = netconn_recv(socket->sock);
-               if (rx_buf_conn)
-               {
-                       netbuf_data(rx_buf_conn, (void **)&buf, &recv_len);
+               LOG_INFO("Get bytes from socket.\n");
+               socket->rx_buf_conn = netconn_recv(socket->sock);
 
-                       socket->error |= ERR_RECV_DATA;
-                       return recv_len;
+               socket->error = netconn_err(socket->sock);
+               if (socket->error != ERR_OK)
+               {
+                       LOG_ERR("While recv %d\n", socket->error);
+                       close_socket(socket);
+                       return 0;
                }
 
-               // Do we have an EOF condition? If so, bailout.
-               if (recv_len == 0 && len != 0)
+               size_t chunk_len = 0;
+               uint16_t data_len = 0;
+               if (socket->rx_buf_conn)
                {
-                       LOG_INFO("Connection reset by peer\n");
-                       socket->error = 0;
-
-                       if (tcpsocket_close(fd) == EOF)
-                               LOG_ERR("Error closing socket, leak detected\n");
-
-                       return recv_len;
+                       netbuf_data(socket->rx_buf_conn, (void **)&data, &data_len);
+
+                       if (data)
+                       {
+                               chunk_len = MIN((size_t)data_len, len);
+                               memcpy(buf, data, chunk_len);
+
+                               socket->remaning_data_len = data_len - chunk_len;
+                       }
+
+                       if (socket->remaning_data_len <= 0)
+                       {
+                               netbuf_delete(socket->rx_buf_conn);
+                               socket->rx_buf_conn = NULL;
+                               socket->remaning_data_len = 0;
+                               return chunk_len;
+                       }
                }
-               len -= recv_len;
+
+               len -= chunk_len;
+               read_len += chunk_len;
        }
 
-       return recv_len;
+       return read_len;
 }
 
 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
 {
        TcpSocket *socket = TCPSOCKET_CAST(fd);
-       ssize_t result;
 
-       // Try reconnecting if our socket isn't valid
-       if (!socket->sock)
-       {
-               if (!reconnect(socket))
-                       return 0;
-       }
+       /* Try reconnecting if our socket isn't valid */
+       if (!socket->sock && !tcpsocket_reconnect(socket))
+               return 0;
 
-       result = netconn_write(socket->sock, buf, len, NETCONN_COPY);
-       if (result != ERR_OK)
+       socket->error = netconn_write(socket->sock, buf, len, NETCONN_COPY);
+       if (socket->error != ERR_OK)
        {
-               LOG_ERR("While writing %d\n", result);
-               if (result == ERR_RST)
-               {
-                       LOG_INFO("Connection close\n");
-
-                       if (tcpsocket_close(fd) == EOF)
-                               LOG_ERR("Error closing socket, leak detected\n");
-                       return 0;
-               }
+               LOG_ERR("While writing %d\n", socket->error);
+               close_socket(socket);
                return 0;
        }
 
@@ -210,5 +265,6 @@ void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_add
        socket->fd.close = tcpsocket_close;
        socket->fd.write = tcpsocket_write;
        socket->fd.clearerr = tcpsocket_clearerr;
+       socket->fd.reopen = tcpsocket_reopen;
 
 }