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
internal/socket/TcpServer.cpp
- Committer:
- dan_ackme
- Date:
- 2014-08-26
- Revision:
- 21:17bb3eddcbae
File content as of revision 21:17bb3eddcbae:
/** * ACKme WiConnect Host Library is licensed under the BSD licence: * * Copyright (c)2014 ACKme Networks. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #include "Wiconnect.h" #include "internal/common.h" #include "StringUtil.h" #include "types/SocketIrqHandlerMap.h" #define TCP_SERVER_MONITOR_PERIOD 250 //ms static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port); /*************************************************************************************************/ WiconnectResult SocketInterface::tcpListen(uint16_t listeningPort, int maxClients, Pin irqPin) { WiconnectResult result = WICONNECT_ERROR; enum { FS_SET_MAX_CLIENTS, FS_SET_DATA_GPIO, FS_START_SERVER, }; CHECK_OTHER_COMMAND_EXECUTING(); if(wiconnect->internalProcessingState == FS_SET_MAX_CLIENTS) { if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.max_clients", maxClients))) { wiconnect->internalProcessingState = FS_SET_DATA_GPIO; } else if(result == WICONNECT_CMD_RESPONSE_ERROR) { // if there was a module error, then the wiconnect version probably doesn't support this option // just continue to the next state wiconnect->internalProcessingState = FS_SET_DATA_GPIO; } } if(wiconnect->internalProcessingState == FS_SET_DATA_GPIO) { if(irqPin == PIN_NC) { wiconnect->internalProcessingState = FS_START_SERVER; } else { PinToGpioMapper mapper = wiconnect->pinToGpioMapper; if(mapper == NULL) { return WICONNECT_PINNAME_TO_GPIO_MAPPER_NULL; } int8_t gpio = mapper(irqPin); if(gpio == -1) { return WICONNECT_PINNAME_TO_GPIO_NO_MAPPING; } else if(!irqHandlers.pinIsRegistered(irqPin)) { return WICONNECT_NOT_FOUND; } else if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("set tcp.server.data_gpio %d", gpio))) { wiconnect->internalProcessingState = FS_START_SERVER; } } } if(wiconnect->internalProcessingState == FS_START_SERVER) { if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("tcps start %d", listeningPort))) { //#ifdef WICONNECT_ASYNC_TIMER_ENABLED // if(clientConnectedCallback.isValid() && !wiconnect->nonBlocking) // { // serverClientConnectedCallback = clientConnectedCallback; // serverMonitorTimer.start(this, &SocketInterface::serverClientMonitor, TCP_SERVER_MONITOR_PERIOD); // } //#endif } } CHECK_CLEANUP_COMMAND(); return result; } /*************************************************************************************************/ WiconnectResult SocketInterface::tcpAccept(WiconnectSocket &socket, int timeoutMs) { TimeoutTimer timer; do { uint8_t handle; uint16_t local, remote; uint32_t ipAddress; WiconnectResult result; if(WICONNECT_SUCCEEDED(result, pollForServerClient(&handle, &local, &remote, &ipAddress))) { if(WICONNECT_FAILED(result, socket.init(handle, SOCKET_TYPE_TCP, Wiconnect::ipToStr(ipAddress), remote, local))) { return result; } serverConnectedClientList[handle] = true; return WICONNECT_SUCCESS; } else if(!(result == WICONNECT_PROCESSING || result == WICONNECT_NOT_FOUND)) { return result; } } while(timeoutMs == WICONNECT_WAIT_FOREVER || !timer.timedOut(timeoutMs)); return WICONNECT_TIMEOUT; } /*************************************************************************************************/ WiconnectResult SocketInterface::tcpServerStop(void) { WiconnectResult result = WICONNECT_ERROR; CHECK_OTHER_COMMAND_EXECUTING(); result = wiconnect->sendCommand("tcps stop"); CHECK_CLEANUP_COMMAND(); return result; } /*************************************************************************************************/ WiconnectResult SocketInterface::pollForServerClient(uint8_t *handlePtr, uint16_t *localPort, uint16_t *remotePort, uint32_t *ipAddress) { WiconnectResult result; CHECK_OTHER_COMMAND_EXECUTING(); if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("list"))) { bool connectedClients[WICONNECT_MAX_SOCKETS]; char *line, *savedLine; result = WICONNECT_NOT_FOUND; memset(connectedClients, 0, sizeof(connectedClients)); for(savedLine = wiconnect->internalBuffer; (line = StringUtil::strtok_r(savedLine, "\r\n", &savedLine)) != NULL;) { char *toks[4], *savedTok; if(*line != '#') { continue; } savedTok = line + 2; for(int i = 0; i < 4 && (toks[i] = StringUtil::strtok_r(savedTok, " ", &savedTok)) != NULL; ++i) { if(toks[i] == NULL) { result = WICONNECT_RESPONSE_PARSE_ERROR; goto exit; } } if(strcmp(toks[1], "TCPS") != 0) { continue; } uint8_t handle = (uint8_t)(*toks[0] - '0'); if(handle >= WICONNECT_MAX_SOCKETS) { result = WICONNECT_RESPONSE_PARSE_ERROR; goto exit; } connectedClients[handle] = true; if(result == WICONNECT_SUCCESS) { continue; } else if(serverConnectedClientList[handle]) { continue; } result = WICONNECT_SUCCESS; if(handlePtr != NULL) { *handlePtr = handle; parseIpPortStr(toks[2], NULL, localPort); parseIpPortStr(toks[3], ipAddress, remotePort); } } for(int i = 0; i < WICONNECT_MAX_SOCKETS; ++i) { if(connectedClients[i] == false) { serverConnectedClientList[i] = false; } } } exit: CHECK_CLEANUP_COMMAND(); return result; } /*************************************************************************************************/ static WiconnectResult parseIpPortStr(char *str, uint32_t *ipAddress, uint16_t *port) { char *colon = strchr(str, ':'); if(colon == NULL) { return WICONNECT_RESPONSE_PARSE_ERROR; } *colon++ = 0; if(ipAddress != NULL && !Wiconnect::strToIp(str, ipAddress)) { return WICONNECT_RESPONSE_PARSE_ERROR; } else if(!StringUtil::strToUint16(colon, port)) { return WICONNECT_RESPONSE_PARSE_ERROR; } return WICONNECT_SUCCESS; }