Espruino/targets/esp8266/emulator/esp8266_stub_sockets.c
2015-10-08 12:51:21 -05:00

260 lines
7.4 KiB
C

/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2015 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains ESP8266 board specific functions.
* ----------------------------------------------------------------------------
*/
#include <winsock2.h>
#include <stdio.h>
#include <assert.h>
#undef TRUE
#undef FALSE
#include "esp8266_stub_sockets.h"
static int telnetServerSocket;
static int telnetClient;
void esp8266_stub_initSockets() {
WSADATA wsaData;
int rc = WSAStartup(0x202, &wsaData);
if (rc != 0) {
printf("Error with WSAStartup(): %d\n", WSAGetLastError());
}
}
/**
* \brief Set the socket to be non-blocking.
*/
static void setSocketNonblocking(int s) {
u_long iMode = 1; // Any value other than 0 means non-blocking is enabled.
ioctlsocket(s, FIONBIO, &iMode);
}
/**
* \brief Set the socket to be blocking.
*/
/*
static void setSocketBlocking(int s) {
u_long iMode = 0; // Disable non-blocking (i.e. make blocking)
ioctlsocket(s, FIONBIO, &iMode);
}
*/
/**
* \brief Start the telnet server.
*/
void esp8266_stub_startTelnetServer() {
telnetServerSocket = socket(AF_INET, SOCK_STREAM, 0);
if (telnetServerSocket < 0) {
printf("socket: %d", WSAGetLastError());
return;
}
struct sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = INADDR_ANY;
servAddr.sin_port = htons(23);
int rc = bind(telnetServerSocket, (struct sockaddr *)&servAddr, sizeof(servAddr));
if (rc == SOCKET_ERROR) {
printf("esp8266_stub_startTelnetServer: bind: %d", WSAGetLastError());
return;
}
listen(telnetServerSocket, 5);
printf("Starting to listen for a client ...\n");
telnetClient = accept(telnetServerSocket, NULL, NULL);
setSocketNonblocking(telnetClient);
printf("We got a telnet client!\n");
}
void esp8266_stub_stopTelnetServer() {
}
void esp8266_stub_sendCharacter(char c) {
int rc = send(telnetClient, &c, 1, 0);
if (rc == SOCKET_ERROR) {
printf("Send error: %d\n", WSAGetLastError());
}
}
/**
* \brief Get a character from the telnet client.
* \return <0 An error occurred. 0 no character.
*/
int esp8266_stub_getCharacter() {
char c;
int rc = recv(telnetClient, &c, 1, 0);
if (rc == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
return 0;
}
printf("Recv error: %d\n", WSAGetLastError());
return -1;
}
return c;
}
/**
* \brief Retrieve the local IP address.
* \return The local IP address.
*/
uint32_t esp8266_stub_getLocalIP() {
char ac[80];
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) {
return 0;
}
struct hostent *phe = gethostbyname(ac);
if (phe == 0) {
return 0;
}
return *(uint32_t *)(phe->h_addr_list[0]);
}
/**
* \brief Connect to a partner.
* We form a connection to the partner specified in the socket structure.
* Specifically, the parameters remoteAddress and remotePort are used to define
* the target of the connection.
* \return 0 on error and 1 on success.
*/
int esp8266_stub_connect(struct stub_ESP8266Socket *pSocket) {
assert(pSocket != NULL);
// Perform a TCP/IP connect request.
// Create a new socket
pSocket->socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (pSocket->socketId == INVALID_SOCKET) {
printf("esp8266_stub_connect: socket: %d\n", WSAGetLastError());
return 0;
}
printf("esp8266_stub_connect: Created a new socket with id: %d\n", pSocket->socketId);
// Connect to the partner over the new socket.
// Prep the address structure.
struct sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_port = htons(pSocket->pEspconn->proto.tcp->remote_port);
clientService.sin_addr.s_addr = *(uint32_t *)pSocket->pEspconn->proto.tcp->remote_ip;
// Debug
printf("esp8266_stub_connect .. connecting to %s[%d]\n",
inet_ntoa((struct in_addr)clientService.sin_addr),
pSocket->pEspconn->proto.tcp->remote_port);
// Perform the actual network level connection. We need to make sure that the socket
// is flagged as blocking otherwise we will be a WSAEWOULDBLOCK error indication.
int rc = connect(pSocket->socketId, (struct sockaddr *)&clientService, sizeof(clientService));
if (rc == SOCKET_ERROR) {
printf("esp8266_stub_connect: Error: %d\n", WSAGetLastError());
return 0;
}
setSocketNonblocking(pSocket->socketId);
// Retrieve the local port number and local address.
struct sockaddr_in localName;
int size = sizeof(localName);
getsockname(pSocket->socketId, (struct sockaddr *)&localName, &size );
pSocket->pEspconn->proto.tcp->local_port = ntohs(localName.sin_port);
*(uint32_t *)pSocket->pEspconn->proto.tcp->local_ip = localName.sin_addr.s_addr;
return 1;
}
/**
* Return 0 on success.
*/
int esp8266_stub_listen(struct stub_ESP8266Socket *pSocket) {
pSocket->socketId = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = INADDR_ANY;
servAddr.sin_port = htons(pSocket->pEspconn->proto.tcp->local_port);
int rc = bind(telnetServerSocket, (struct sockaddr *)&servAddr, sizeof(servAddr));
if (rc<0) {
printf("esp8266_stub_listen: bind: %d", WSAGetLastError());
return 0;
}
setSocketNonblocking(pSocket->socketId);
listen(pSocket->socketId, 5);
return 1;
}
/**
* \brief Disconnect (close) the socket represented by the pSocket.
* \return Returns 1 on success.
*/
int esp8266_stub_disconnect(struct stub_ESP8266Socket *pSocket) {
closesocket(pSocket->socketId);
return 1;
}
/**
* \brief Send data to a TCP partner.
* Send data to a TCP partner where the partner is identified by the socket contained in
* the pSocket structure.
* \return If <0 then an error has occurred otherwise we return how much data was actually sent.
*/
int eps8266_stub_send(
struct stub_ESP8266Socket *pSocket,
uint8_t *pBuf,
uint16_t size
) {
assert(pSocket != NULL);
assert(pSocket->socketId != -1);
int rc = send(pSocket->socketId, (char *)pBuf, size, 0);
if (rc == SOCKET_ERROR) {
printf("eps8266_stub_send: Error: %d on socket: %d\n", WSAGetLastError(), pSocket->socketId);
return -1;
}
return rc;
}
/**
* \brief Receive data from the partner.
* Receive data in a non-blocking fashion from the partner.
* \return <0 then an error has occurred otherwise how much data actually read.
*/
int esp8266_stub_recv(
struct stub_ESP8266Socket *pSocket, //!< The identity of the socket to receive from.
uint8_t *pBuf, //!< A buffer into which to read received data.
uint16_t size //!< The size of the data buffer into which we can receive.
) {
int rc = recv(pSocket->socketId, (char *)pBuf, size, 0);
if (rc == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
return 0;
}
printf("esp8266_stub_recv: recv: %d\n", WSAGetLastError());
return -1;
}
return rc;
}
/**
* \brief Check to see if the given socket has a new client connection.
* \return -1 if there is no new client.
*/
int esp8266_stub_checkAccept(struct stub_ESP8266Socket *pSocket) {
int newClientSocket = -1;
return newClientSocket;
}