Espruino/libs/network/wiznet/network_wiznet.c
mgg1010 1b42053c4e Hopefully fix repeated GET problem
Previously, if we issued http GET more than once every 30 seconds, the second GET would timeout.  It seems this is because the code was using the same fixed port for src and dest - both were 80.  Probably this caused a problem if the second GET happened before the first had closed
2014-05-09 23:44:27 +01:00

181 lines
6.3 KiB
C

/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 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/.
*
* ----------------------------------------------------------------------------
* Implementation of JsNetwork for WIZnet devices
* ----------------------------------------------------------------------------
*/
#include "jsinteractive.h"
#include "network.h"
#include "network_wiznet.h"
#define INVALID_SOCKET ((SOCKET)(-1))
#define SOCKET_ERROR (-1)
#include "wiznet/Ethernet/socket.h"
typedef struct sockaddr_in sockaddr_in;
#define closesocket(SOCK) close(SOCK)
#define MSG_NOSIGNAL 0x4000 /* don't raise SIGPIPE */ // IGNORED ANYWAY!
#define send(sock,ptr,len,flags) send(sock,(uint8_t*)(ptr),len) // throw away last arg of send
#define recv(sock,ptr,len,flags) recv(sock,(uint8_t*)(ptr),len) // throw away last arg of send
// name resolution
#include "wiznet/DNS/dns.h"
extern uint8_t Server_IP_Addr[4];
unsigned short wiznetSocketPorts[8];
unsigned char wiznetSocketAsServerClient = 0;
#define WIZNET_SERVER_CLIENT 256 // sockets are only 0-255 so this is masked out
uint8_t net_wiznet_getFreeSocket() {
unsigned int i;
for (i=0;i<8;i++)
if (getSn_SR(i) == SOCK_CLOSED) // it's free!
return (uint8_t)i;
jsError("No free sockets found\n");
// out of range will probably just make it error out
return 8;
}
/// Get an IP address from a name. Sets out_ip_addr to 0 on failure
void net_wiznet_gethostbyname(JsNetwork *net, char * hostName, unsigned long* out_ip_addr) {
NOT_USED(net);
if (dns_query(0, net_wiznet_getFreeSocket(), (uint8_t*)hostName) == 1) {
*out_ip_addr = *(unsigned long*)&Server_IP_Addr[0];
}
}
/// Called on idle. Do any checks required for this device
void net_wiznet_idle(JsNetwork *net) {
NOT_USED(net);
}
/// Call just before returning to idle loop. This checks for errors and tries to recover. Returns true if no errors.
bool net_wiznet_checkError(JsNetwork *net) {
NOT_USED(net);
bool hadErrors = false;
return hadErrors;
}
/// if host=0, creates a server otherwise creates a client (and automatically connects). Returns >=0 on success
int net_wiznet_createsocket(JsNetwork *net, unsigned long host, unsigned short port) {
NOT_USED(net);
int sckt = -1;
if (host!=0) { // ------------------------------------------------- host (=client)
//mgg1010 - added random source port - seems to solve problem of repeated GET failing
sckt = socket(net_wiznet_getFreeSocket(), Sn_MR_TCP, (rand() & 32767) + 2000, 0); // we set nonblocking later
if (sckt<0) return sckt; // error
int res = connect((uint8_t)sckt,(uint8_t*)&host, port);
// now we set nonblocking - so that connect waited for the connection
uint8_t ctl = SOCK_IO_NONBLOCK;
ctlsocket((uint8_t)sckt, CS_SET_IOMODE, &ctl);
if (res == SOCKET_ERROR) {
jsError("Connect failed (err %d)\n", res );
}
} else { // ------------------------------------------------- no host (=server)
sckt = socket(net_wiznet_getFreeSocket(), Sn_MR_TCP, port, SF_IO_NONBLOCK);
listen((uint8_t)sckt);
}
wiznetSocketPorts[sckt&7] = port;
//jsiConsolePrintf("Created socket %d\n", sckt);
return sckt;
}
/// destroys the given socket
void net_wiznet_closesocket(JsNetwork *net, int sckt) {
NOT_USED(net);
// try and close gracefully
disconnect((uint8_t)sckt);
JsSysTime timeout = jshGetSystemTime()+jshGetTimeFromMilliseconds(1000);
uint8_t status;
while ((status=getSn_SR((uint8_t)sckt)) != SOCK_CLOSED &&
jshGetSystemTime()<timeout) ;
// if that didn't work, force it
if (status != SOCK_CLOSED)
closesocket((uint8_t)sckt);
// Wiznet is a bit strange in that it uses the same socket for server and client
if (sckt & WIZNET_SERVER_CLIENT) {
// so it's just closed, but put it into 'listen' mode again
sckt = socket((uint8_t)sckt, Sn_MR_TCP, wiznetSocketPorts[sckt&7], SF_IO_NONBLOCK);
listen((uint8_t)sckt);
// Be sure to mark it as not a client socket any more
wiznetSocketAsServerClient = wiznetSocketAsServerClient & (unsigned char)~(1<<(sckt&7));
}
}
/// If the given server socket can accept a connection, return it (or return < 0)
int net_wiznet_accept(JsNetwork *net, int sckt) {
NOT_USED(net);
// On WIZnet the same server socket is reused for clients - keep track so we don't get confused
// and try and allocate a new HTTP Server Client
if (wiznetSocketAsServerClient & (1<<sckt))
return -1;
/* CC3000/WIZnet works a different way - we set accept as nonblocking,
* and then we just call it and see if it works or not...
*/
// we have a client waiting to connect... try to connect and see what happens
// WIZnet's implementation doesn't use accept, it uses listen
int status = getSn_SR((uint8_t)sckt);
if (status == SOCK_ESTABLISHED) {
wiznetSocketAsServerClient = wiznetSocketAsServerClient | (unsigned char)(1<<sckt); // mark that it's now being used as a client socket
return ((int)sckt) | WIZNET_SERVER_CLIENT; // we deal with the client on the same socket (we use the flag so we know that it really is different!)
}
return -1;
}
/// Receive data if possible. returns nBytes on success, 0 on no data, or -1 on failure
int net_wiznet_recv(JsNetwork *net, int sckt, void *buf, size_t len) {
NOT_USED(net);
int num = 0;
if (getSn_SR(sckt)!=SOCK_LISTEN) {
// receive data - if none available it'll just return SOCK_BUSY
num = (int)recv((uint8_t)sckt,buf,(uint16_t)len,0);
if (num==SOCK_BUSY) num=0;
}
if (jspIsInterrupted()) return -1;
return num;
}
/// Send data if possible. returns nBytes on success, 0 on no data, or -1 on failure
int net_wiznet_send(JsNetwork *net, int sckt, const void *buf, size_t len) {
NOT_USED(net);
int r = (int)send((uint8_t)sckt, buf, (uint16_t)len, MSG_NOSIGNAL);
if (jspIsInterrupted()) return -1;
return r;
}
void netSetCallbacks_wiznet(JsNetwork *net) {
net->idle = net_wiznet_idle;
net->checkError = net_wiznet_checkError;
net->createsocket = net_wiznet_createsocket;
net->closesocket = net_wiznet_closesocket;
net->accept = net_wiznet_accept;
net->gethostbyname = net_wiznet_gethostbyname;
net->recv = net_wiznet_recv;
net->send = net_wiznet_send;
}