<commit_before>
/*
 * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
 *
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 *
 * 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 Duo board network specific functions.
 * ----------------------------------------------------------------------------
 */

#include "jsinteractive.h"
#include "network_duo.h"
#include "socketerrors.h"

#include "tcpclient_api.h"
#include "tcpserver_api.h"
#include "wifi_api.h"


typedef struct {
  tcp_server *server;
  sock_handle_t socket_id;
}tcp_server_t;

typedef struct {
  tcp_client *client;
  sock_handle_t socket_id;
}tcp_client_t;

static tcp_server_t servers[MAX_SERVER_SOCKETS];
static tcp_client_t clients[MAX_CLIENT_SOCKETS];

static uint32_t g_nextSocketId = 0;


static uint32_t getNextGlobalSocketId(void);
static int getClientIndexBySocketId(int socketId);
static int getServerIndexBySocketId(int socketId);
static int allocateNewClient(void);
static int allocateNewServer(void);

/**
 * Get the next new global socket id.
 * \return A new socketId that is assured to be unique.
 */
static uint32_t getNextGlobalSocketId(void) {
  if(g_nextSocketId < (SOCKET_INVALID-1)) return ++g_nextSocketId;
  else return SOCKET_INVALID;
}

static int getClientIndexBySocketId(int socketId) {
  int i;
  
  if(socketId <= 0) return -1;
  
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    if(clients[i].socket_id == (uint32_t)socketId) return i;
  }
  return -1;
}

static int getServerIndexBySocketId(int socketId) {
  int i;
  
  if(socketId <= 0) return -1;
  
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    if(servers[i].socket_id == (uint32_t)socketId) return i;
  }
  return -1;
}

static int allocateNewClient(void) {
  int i;
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    if(clients[i].socket_id == SOCKET_UNUSED) return i;
  }

  return -1;
}

static int allocateNewServer(void) {
  int i;
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    if(servers[i].socket_id == SOCKET_UNUSED) return i;
  }

  return -1;
}

/**
 * Initialize the entire socket array
 */
void netInit_duo(void) {
  uint8_t i;
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    servers[i].server = NULL;
    servers[i].socket_id = SOCKET_UNUSED;
  }
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    clients[i].client = NULL;
    clients[i].socket_id = SOCKET_UNUSED;
  }
}

/**
 * Define the implementation functions for the logical network functions.
 */
void netSetCallbacks_duo(JsNetwork *net) {
    net->idle          = net_duo_idle;
    net->checkError    = net_duo_checkError;
    net->createsocket  = net_duo_createSocket;
    net->closesocket   = net_duo_closeSocket;
    net->accept        = net_duo_accept;
    net->gethostbyname = net_duo_gethostbyname;
    net->recv          = net_duo_recv;
    net->send          = net_duo_send;
    // The TCP MSS is 536, we use half that 'cause otherwise we easily run out of JSvars memory
    net->chunkSize     = 536/2;
}

/**
 * Determine if there is a new client connection on the server socket.
 * This function is called to poll to see if the serverSckt has a new
 * accepted connection (socket) and, if it does, return it else return -1 to indicate
 * that there was no new accepted socket.
 */
int net_duo_accept(JsNetwork *net, int serverSckt) {
  int index, i;

  if(g_nextSocketId >= (SOCKET_INVALID-1)) return -1;

  index = getServerIndexBySocketId(serverSckt);
  if(index >= 0) {
    i = allocateNewClient();
    if(i >= 0) {
      clients[i].client = TCPServer_available(servers[index].server);
      if(clients[i].client != NULL) {
        clients[i].socket_id = getNextGlobalSocketId();
        return clients[i].socket_id;
      }
    }
  }

  return -1;
}


/**
 * Receive data from the network device.
 * Returns the number of bytes received which may be 0 and <0 if there was an error.
 */
int net_duo_recv(JsNetwork *net, int sckt, void *buf, size_t len) {
  int index;

  index = getClientIndexBySocketId(sckt);
  if(index >= 0) {
    return TCPClient_read(clients[index].client, (uint8_t *)buf, len);
  }

  return 0;
}


/**
 * Send data to the partner.
 * The return is the number of bytes actually transmitted which may also be
 * 0 to indicate no bytes sent or -1 to indicate an error.
 */
int net_duo_send(JsNetwork *net, int sckt, const void *buf, size_t len) {
  int index;

  index = getClientIndexBySocketId(sckt);
  if(index >= 0) {
    return TCPClient_write(clients[index].client, (uint8_t *)buf, len);
  }

  return 0;
}


/**
 * Perform idle processing.
 * There is the possibility that we may wish to perform logic when we are idle.
 */
void net_duo_idle(JsNetwork *net) {
  // Don't echo here because it is called continuously<commit_msg>Fixes the issue that the WOULD_BLOCK error results in breaking telnet<commit_after>
/*
 * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
 *
 * Copyright (C) 2015 <NAME> <<EMAIL>>
 *
 * 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 Duo board network specific functions.
 * ----------------------------------------------------------------------------
 */

#include "jsinteractive.h"
#include "network_duo.h"
#include "socketerrors.h"

#include "tcpclient_api.h"
#include "tcpserver_api.h"
#include "wifi_api.h"


typedef struct {
  tcp_server *server;
  sock_handle_t socket_id;
}tcp_server_t;

typedef struct {
  tcp_client *client;
  sock_handle_t socket_id;
}tcp_client_t;

static tcp_server_t servers[MAX_SERVER_SOCKETS];
static tcp_client_t clients[MAX_CLIENT_SOCKETS];

static uint32_t g_nextSocketId = 0;


static uint32_t getNextGlobalSocketId(void);
static int getClientIndexBySocketId(int socketId);
static int getServerIndexBySocketId(int socketId);
static int allocateNewClient(void);
static int allocateNewServer(void);

/**
 * Get the next new global socket id.
 * \return A new socketId that is assured to be unique.
 */
static uint32_t getNextGlobalSocketId(void) {
  if(g_nextSocketId < (SOCKET_INVALID-1)) return ++g_nextSocketId;
  else return SOCKET_INVALID;
}

static int getClientIndexBySocketId(int socketId) {
  int i;
  
  if(socketId <= 0) return -1;
  
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    if(clients[i].socket_id == (uint32_t)socketId) return i;
  }
  return -1;
}

static int getServerIndexBySocketId(int socketId) {
  int i;
  
  if(socketId <= 0) return -1;
  
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    if(servers[i].socket_id == (uint32_t)socketId) return i;
  }
  return -1;
}

static int allocateNewClient(void) {
  int i;
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    if(clients[i].socket_id == SOCKET_UNUSED) return i;
  }

  return -1;
}

static int allocateNewServer(void) {
  int i;
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    if(servers[i].socket_id == SOCKET_UNUSED) return i;
  }

  return -1;
}

/**
 * Initialize the entire socket array
 */
void netInit_duo(void) {
  uint8_t i;
  for(i=0; i<MAX_SERVER_SOCKETS; i++) {
    servers[i].server = NULL;
    servers[i].socket_id = SOCKET_UNUSED;
  }
  for(i=0; i<MAX_CLIENT_SOCKETS; i++) {
    clients[i].client = NULL;
    clients[i].socket_id = SOCKET_UNUSED;
  }
}

/**
 * Define the implementation functions for the logical network functions.
 */
void netSetCallbacks_duo(JsNetwork *net) {
    net->idle          = net_duo_idle;
    net->checkError    = net_duo_checkError;
    net->createsocket  = net_duo_createSocket;
    net->closesocket   = net_duo_closeSocket;
    net->accept        = net_duo_accept;
    net->gethostbyname = net_duo_gethostbyname;
    net->recv          = net_duo_recv;
    net->send          = net_duo_send;
    // The TCP MSS is 536, we use half that 'cause otherwise we easily run out of JSvars memory
    net->chunkSize     = 536/2;
}

/**
 * Determine if there is a new client connection on the server socket.
 * This function is called to poll to see if the serverSckt has a new
 * accepted connection (socket) and, if it does, return it else return -1 to indicate
 * that there was no new accepted socket.
 */
int net_duo_accept(JsNetwork *net, int serverSckt) {
  int index, i;

  if(g_nextSocketId >= (SOCKET_INVALID-1)) return -1;

  index = getServerIndexBySocketId(serverSckt);
  if(index >= 0) {
    i = allocateNewClient();
    if(i >= 0) {
      clients[i].client = TCPServer_available(servers[index].server);
      if(clients[i].client != NULL) {
        clients[i].socket_id = getNextGlobalSocketId();
        return clients[i].socket_id;
      }
    }
  }

  return -1;
}


/**
 * Receive data from the network device.
 * Returns the number of bytes received which may be 0 and <0 if there was an error.
 */
int net_duo_recv(JsNetwork *net, int sckt, void *buf, size_t len) {
  int index;

  index = getClientIndexBySocketId(sckt);
  if(index >= 0) {
    if(TCPClient_available(clients[index].client)) {
      return TCPClient_read(clients[index].client, (uint8_t *)buf, len);
    }
  }

  return 0;
}


/**
 * Send data to the partner.
 * The return is the number of bytes actually transmitted which may also be
 * 0 to indicate no bytes sent or -1 to indicate an error.
 */
int net_duo_send(JsNetwork *net, int sckt, const void *buf, size_t len) {
  int index;

  index = getClientIndexBySocketId(sckt);
  if(index >= 0) {
    int num = TCPClient_write(clients[index].client, (uint8_t *)buf, len);
    if(num == -16){ // WICED_WOULD_BLOCK
      num = 0;
    }
    return num;
  }

  return 0;
}


/**
 * Perform idle processing.
 * There is the possibility that we may wish to perform logic when we are idle.
 */
void net_duo_idle(JsNetwork *net) {
  // Don't echo here because it is called continuously
{'fraction_non_alphanumeric': 0.13671184443134943, 'fraction_numerical': 0.011687291298369672, 'mean_word_length': 3.158023683135974, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4415571', 'n_tokens_mistral': 3539, 'n_tokens_neox': 3467, 'n_words': 996}