tcp_socket.c
Go to the documentation of this file.
00001
00041 #include "tcp_socket.h"
00042
00043 #include "cfg/cfg_tcpsocket.h"
00044
00045 #define LOG_LEVEL   TCPSOCKET_LOG_LEVEL
00046 #define LOG_FORMAT  TCPSOCKET_LOG_FORMAT
00047 #include <cfg/log.h>
00048 #include <cpu/byteorder.h>
00049
00050 #include <lwip/ip_addr.h>
00051 #include <lwip/api.h>
00052 #include <lwip/netif.h>
00053 #include <lwip/netbuf.h>
00054 #include <lwip/tcpip.h>
00055
00056
00057 INLINE void close_socket(TcpSocket *socket)
00058 {
00059     /* Clean all previuos states */
00060     netbuf_delete(socket->rx_buf_conn);
00061     socket->rx_buf_conn = NULL;
00062     socket->remaning_data_len = 0;
00063
00064     if (!socket->sock)
00065         return;
00066
00067     /* Close socket if was open */
00068     netconn_delete(socket->sock);
00069     socket->sock = NULL;
00070     return;
00071 }
00072
00073 static bool tcpsocket_reconnect(TcpSocket *socket)
00074 {
00075     LOG_ERR("Reconnecting..\n");
00076
00077     /* Close socket if was open */
00078     close_socket(socket);
00079
00080     /* If we are in server mode we do nothing */
00081     if (socket->handler)
00082         return false;
00083
00084     /* Start with new connection */
00085     socket->sock = netconn_new(NETCONN_TCP);
00086     if(!socket->sock)
00087     {
00088         LOG_ERR("Unabe to alloc new connection\n");
00089         socket->error = -1;
00090         goto error;
00091     }
00092
00093     socket->error = netconn_bind(socket->sock, socket->local_addr, socket->port);
00094     if(socket->error != ERR_OK)
00095     {
00096         LOG_ERR("Connection error\n");
00097         goto error;
00098     }
00099
00100     socket->error = netconn_connect(socket->sock, socket->remote_addr, socket->port);
00101     if(socket->error != ERR_OK)
00102     {
00103         LOG_ERR("Cannot create socket\n");
00104         goto error;
00105     }
00106
00107     LOG_INFO("connected ip=%d.%d.%d.%d\n", IP_ADDR_TO_INT_TUPLE(socket->remote_addr->addr));
00108     return true;
00109
00110 error:
00111     netconn_delete(socket->sock);
00112     socket->sock = NULL;
00113     return false;
00114 }
00115
00116 static int tcpsocket_close(KFile *fd)
00117 {
00118     TcpSocket *socket = TCPSOCKET_CAST(fd);
00119     close_socket(socket);
00120     socket->error = 0;
00121     return 0;
00122 }
00123
00124 static KFile *tcpsocket_reopen(KFile *fd)
00125 {
00126     TcpSocket *socket = TCPSOCKET_CAST(fd);
00127     if (tcpsocket_reconnect(socket))
00128         return fd;
00129
00130     return NULL;
00131 }
00132
00133 /*
00134  * Read data from socket.
00135  *
00136  * The read return the bytes that had been received if they are less than we request too.
00137  * Otherwise if the byte that we want read are less that the received bytes, we return only
00138  * the requested bytes. To get the remaning bytes we need to make an others read, until the
00139  * buffer is empty.
00140  * When there are not any more bytes, a new read takes data from remote socket.
00141  */
00142 static size_t tcpsocket_read(KFile *fd, void *buf, size_t len)
00143 {
00144     TcpSocket *socket = TCPSOCKET_CAST(fd);
00145
00146     char *data;
00147     uint16_t read_len = 0;
00148
00149     if (socket->remaning_data_len <= 0)
00150     {
00151         LOG_INFO("No byte left.\n");
00152         netbuf_delete(socket->rx_buf_conn);
00153     }
00154     else /* We had byte into buffer use that */
00155     {
00156         LOG_INFO("Read stored bytes.\n");
00157         if (!socket->rx_buf_conn)
00158         {
00159             LOG_ERR("Byte stored are corrupted!\n");
00160             socket->remaning_data_len = 0;
00161             return 0;
00162         }
00163         uint16_t tot_data_len = 0;
00164         netbuf_data(socket->rx_buf_conn, (void **)&data, &tot_data_len);
00165
00166         if (data)
00167         {
00168             ASSERT(((int)tot_data_len - (int)socket->remaning_data_len) >= 0);
00169             size_t chunk_len = MIN((size_t)(socket->remaning_data_len), len);
00170             memcpy((char *)buf, &data[tot_data_len - socket->remaning_data_len], chunk_len);
00171
00172             socket->remaning_data_len -= chunk_len;
00173             return chunk_len;
00174         }
00175         else
00176         {
00177             LOG_ERR("No valid data to read\n");
00178             socket->remaning_data_len = 0;
00179             netbuf_delete(socket->rx_buf_conn);
00180             return 0;
00181         }
00182     }
00183
00184     /* Try reconnecting if our socket isn't valid */
00185     if ((socket->sock == NULL) && !tcpsocket_reconnect(socket))
00186         return 0;
00187
00188     while (len)
00189     {
00190         LOG_INFO("Get bytes from socket.\n");
00191         socket->rx_buf_conn = netconn_recv(socket->sock);
00192
00193         socket->error = netconn_err(socket->sock);
00194         if (socket->error != ERR_OK)
00195         {
00196             LOG_ERR("While recv %d\n", socket->error);
00197             close_socket(socket);
00198             return 0;
00199         }
00200
00201         size_t chunk_len = 0;
00202         uint16_t data_len = 0;
00203         if (socket->rx_buf_conn)
00204         {
00205             netbuf_data(socket->rx_buf_conn, (void **)&data, &data_len);
00206
00207             if (data)
00208             {
00209                 chunk_len = MIN((size_t)data_len, len);
00210                 memcpy(buf, data, chunk_len);
00211
00212                 socket->remaning_data_len = data_len - chunk_len;
00213             }
00214
00215             if (socket->remaning_data_len <= 0)
00216             {
00217                 netbuf_delete(socket->rx_buf_conn);
00218                 socket->rx_buf_conn = NULL;
00219                 socket->remaning_data_len = 0;
00220                 return chunk_len;
00221             }
00222         }
00223
00224         len -= chunk_len;
00225         read_len += chunk_len;
00226     }
00227
00228     return read_len;
00229 }
00230
00231 static size_t tcpsocket_write(KFile *fd, const void *buf, size_t len)
00232 {
00233     TcpSocket *socket = TCPSOCKET_CAST(fd);
00234
00235     /* Try reconnecting if our socket isn't valid */
00236     if ((socket->sock == NULL) && !tcpsocket_reconnect(socket))
00237         return 0;
00238
00239     socket->error = netconn_write(socket->sock, buf, len, NETCONN_COPY);
00240     if (socket->error != ERR_OK)
00241     {
00242         LOG_ERR("While writing %d\n", socket->error);
00243         close_socket(socket);
00244         return 0;
00245     }
00246
00247     return len;
00248 }
00249
00250 static int tcpsocket_error(KFile *fd)
00251 {
00252     TcpSocket *socket = TCPSOCKET_CAST(fd);
00253     return socket->error;
00254 }
00255
00256 static void tcpsocket_clearerr(KFile *fd)
00257 {
00258     TcpSocket *socket = TCPSOCKET_CAST(fd);
00259     socket->error = 0;
00260 }
00261
00262
00269 void tcpsocket_serverPoll(KFile *fd)
00270 {
00271     TcpSocket *socket = TCPSOCKET_CAST(fd);
00272
00273     if (!socket->sock)
00274         socket->sock = netconn_accept(socket->server_sock);
00275
00276     if (!socket->sock)
00277     {
00278         LOG_ERR("Unable to connect with client\n");
00279         return;
00280     }
00281
00282     socket->handler(fd);
00283 }
00284
00297 void tcpsocket_init(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *remote_addr, uint16_t port)
00298 {
00299     memset(socket, 0, sizeof(TcpSocket));
00300
00301     socket->local_addr = local_addr;
00302     socket->remote_addr = remote_addr;
00303     socket->port = port;
00304
00305     socket->fd._type = KFT_TCPSOCKET;
00306     socket->fd.read = tcpsocket_read;
00307     socket->fd.error = tcpsocket_error;
00308     socket->fd.close = tcpsocket_close;
00309     socket->fd.write = tcpsocket_write;
00310     socket->fd.clearerr = tcpsocket_clearerr;
00311     socket->fd.reopen = tcpsocket_reopen;
00312
00313 }
00314
00331 void tcpsocket_serverInit(TcpSocket *socket, struct ip_addr *local_addr, struct ip_addr *listen_addr, uint16_t port, tcphandler_t handler)
00332 {
00333     tcpsocket_init(socket, local_addr, listen_addr, port);
00334     socket->handler = handler;
00335
00336     socket->server_sock = netconn_new(NETCONN_TCP);
00337     socket->error = netconn_bind(socket->server_sock, listen_addr, port);
00338     socket->error = netconn_listen(socket->server_sock);
00339
00340     if(socket->error != ERR_OK)
00341         LOG_ERR("Init server\n");
00342 }