Host library for controlling a WiConnect enabled Wi-Fi module.

Dependents:   wiconnect-ota_example wiconnect-web_setup_example wiconnect-test-console wiconnect-tcp_server_example ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TcpServer.cpp Source File

TcpServer.cpp

00001 /**
00002  * ACKme WiConnect Host Library is licensed under the BSD licence:
00003  *
00004  * Copyright (c)2014 ACKme Networks.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without modification,
00008  * are permitted provided that the following conditions are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright notice,
00011  * this list of conditions and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright notice,
00013  * this list of conditions and the following disclaimer in the documentation
00014  * and/or other materials provided with the distribution.
00015  * 3. The name of the author may not be used to endorse or promote products
00016  * derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED
00019  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00021  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00022  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00023  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00026  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00027  * OF SUCH DAMAGE.
00028  */
00029 
00030 #include "Wiconnect.h"
00031 #include "internal/common.h"
00032 #include "api/StringUtil.h"
00033 
00034 #ifdef WICONNECT_GPIO_IRQ_ENABLED
00035 #include "api/types/SocketIrqHandlerMap.h"
00036 #endif
00037 
00038 #define TCP_SERVER_MONITOR_PERIOD 250 //ms
00039 
00040 
00041 
00042 static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port);
00043 
00044 
00045 
00046 
00047 /*************************************************************************************************/
00048 WiconnectResult SocketInterface::tcpListen(uint16_t listeningPort, int maxClients GPIO_IRQ_ARG)
00049 {
00050     WiconnectResult result = WICONNECT_ERROR;
00051 
00052     enum
00053     {
00054         FS_SET_MAX_CLIENTS,
00055         FS_SET_DATA_GPIO,
00056         FS_START_SERVER,
00057     };
00058 
00059     CHECK_OTHER_COMMAND_EXECUTING();
00060 
00061     if(wiconnect->internalProcessingState == FS_SET_MAX_CLIENTS)
00062     {
00063         if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.max_clients", maxClients)))
00064         {
00065             wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
00066         }
00067         else if(result == WICONNECT_CMD_RESPONSE_ERROR)
00068         {
00069             // if there was a module error, then the wiconnect version probably doesn't support this option
00070             // just continue to the next state
00071             wiconnect->internalProcessingState = FS_SET_DATA_GPIO;
00072         }
00073     }
00074 
00075     if(wiconnect->internalProcessingState == FS_SET_DATA_GPIO)
00076     {
00077 #ifdef WICONNECT_GPIO_IRQ_ENABLED
00078         if(irqPin == PIN_NC)
00079         {
00080             wiconnect->internalProcessingState = FS_START_SERVER;
00081         }
00082         else
00083         {
00084             PinToGpioMapper mapper = wiconnect->pinToGpioMapper;
00085             if(mapper == NULL)
00086             {
00087                 return WICONNECT_PINNAME_TO_GPIO_MAPPER_NULL;
00088             }
00089             int8_t gpio = mapper(irqPin);
00090             if(gpio == -1)
00091             {
00092                 return WICONNECT_PINNAME_TO_GPIO_NO_MAPPING;
00093             }
00094             else if(!irqHandlers.pinIsRegistered(irqPin))
00095             {
00096                 return WICONNECT_NOT_FOUND;
00097             }
00098             else if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.data_gpio %d", gpio)))
00099             {
00100                 wiconnect->internalProcessingState = FS_START_SERVER;
00101             }
00102         }
00103 #else
00104         wiconnect->internalProcessingState = FS_START_SERVER;
00105 #endif
00106     }
00107 
00108     if(wiconnect->internalProcessingState == FS_START_SERVER)
00109     {
00110         if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("tcps start %d", listeningPort)))
00111         {
00112 //#ifdef WICONNECT_ASYNC_TIMER_ENABLED
00113 //            if(clientConnectedCallback.isValid() && !wiconnect->nonBlocking)
00114 //            {
00115 //                serverClientConnectedCallback = clientConnectedCallback;
00116 //                serverMonitorTimer.start(this, &SocketInterface::serverClientMonitor, TCP_SERVER_MONITOR_PERIOD);
00117 //            }
00118 //#endif
00119         }
00120     }
00121 
00122     CHECK_CLEANUP_COMMAND();
00123 
00124     return result;
00125 }
00126 
00127 /*************************************************************************************************/
00128 WiconnectResult SocketInterface::tcpAccept(WiconnectSocket &socket, uint32_t timeoutMs)
00129 {
00130     TimeoutTimer timer;
00131 
00132     do
00133     {
00134         uint8_t handle;
00135         uint16_t local, remote;
00136         uint32_t ipAddress;
00137         WiconnectResult result;
00138 
00139         if(WICONNECT_SUCCEEDED(result, pollForServerClient(&handle, &local, &remote, &ipAddress)))
00140         {
00141             char ipBuffer[17];
00142             if(WICONNECT_FAILED(result, socket.init(handle, SOCKET_TYPE_TCP, Wiconnect::ipToStr(ipAddress, ipBuffer), remote, local)))
00143             {
00144                 return result;
00145             }
00146             serverConnectedClientList |= (1 << handle);
00147             return WICONNECT_SUCCESS;
00148         }
00149         else if(!(result == WICONNECT_PROCESSING || result == WICONNECT_NOT_FOUND))
00150         {
00151             return result;
00152         }
00153 
00154     } while(timeoutMs == WICONNECT_WAIT_FOREVER || !timer.timedOut(timeoutMs));
00155 
00156     return WICONNECT_TIMEOUT;
00157 }
00158 
00159 /*************************************************************************************************/
00160 WiconnectResult SocketInterface::tcpServerStop(void)
00161 {
00162     WiconnectResult result = WICONNECT_ERROR;
00163 
00164     CHECK_OTHER_COMMAND_EXECUTING();
00165 
00166     result = wiconnect->sendCommand("tcps stop");
00167 
00168     CHECK_CLEANUP_COMMAND();
00169 
00170     return result;
00171 }
00172 
00173 /*************************************************************************************************/
00174 WiconnectResult SocketInterface::pollForServerClient(uint8_t *handlePtr, uint16_t *localPort, uint16_t *remotePort, uint32_t *ipAddress)
00175 {
00176     WiconnectResult result;
00177 
00178     CHECK_OTHER_COMMAND_EXECUTING();
00179 
00180     if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("list")))
00181     {
00182         uint32_t connectedClients = 0;
00183         char *line, *savedLine;
00184         result = WICONNECT_NOT_FOUND;
00185 
00186         for(savedLine = wiconnect->internalBuffer; (line = StringUtil::strtok_r(savedLine, "\r\n", &savedLine)) != NULL;)
00187         {
00188             char *toks[4], *savedTok;
00189 
00190             if(*line != '#')
00191             {
00192                 continue;
00193             }
00194             savedTok = line + 2;
00195 
00196             for(int i = 0; i < 4 && (toks[i] = StringUtil::strtok_r(savedTok, " ", &savedTok)) != NULL; ++i)
00197             {
00198                 if(toks[i] == NULL)
00199                 {
00200                     result = WICONNECT_RESPONSE_PARSE_ERROR;
00201                     goto exit;
00202                 }
00203             }
00204 
00205             if(strcmp(toks[1], "TCPS") != 0)
00206             {
00207                 continue;
00208             }
00209 
00210             uint8_t handle = (uint8_t)(*toks[0] - '0');
00211             if(handle >= WICONNECT_MAX_SOCKETS)
00212             {
00213                 result = WICONNECT_RESPONSE_PARSE_ERROR;
00214                 goto exit;
00215             }
00216             const uint32_t handleMask = (1 << handle);
00217             connectedClients |= handleMask;
00218 
00219             if(result == WICONNECT_SUCCESS)
00220             {
00221                 continue;
00222             }
00223             else if(serverConnectedClientList & handleMask)
00224             {
00225                 continue;
00226             }
00227 
00228             result = WICONNECT_SUCCESS;
00229 
00230             if(handlePtr != NULL)
00231             {
00232                 *handlePtr = handle;
00233                 parseIpPortStr(toks[2], NULL, localPort);
00234                 parseIpPortStr(toks[3], ipAddress, remotePort);
00235             }
00236         }
00237 
00238         uint32_t mask = 1;
00239         for(int i = 0; i < WICONNECT_MAX_SOCKETS; ++i, mask <<= 1)
00240         {
00241             if(!(connectedClients & mask))
00242             {
00243                 serverConnectedClientList &= ~mask;
00244             }
00245         }
00246     }
00247 
00248 
00249 exit:
00250     CHECK_CLEANUP_COMMAND();
00251 
00252     return result;
00253 }
00254 
00255 /*************************************************************************************************/
00256 static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port)
00257 {
00258     char *colon = strchr(str, ':');
00259     if(colon == NULL)
00260     {
00261         return WICONNECT_RESPONSE_PARSE_ERROR;
00262     }
00263     *colon++ = 0;
00264 
00265     if(ipAddress != NULL && !Wiconnect::strToIp(str, ipAddress))
00266     {
00267         return WICONNECT_RESPONSE_PARSE_ERROR;
00268     }
00269     else if(!StringUtil::strToUint16(colon, port))
00270     {
00271         return WICONNECT_RESPONSE_PARSE_ERROR;
00272     }
00273 
00274     return WICONNECT_SUCCESS;
00275 }