Files
ninlight-w600/sdk/Src/App/httpclient/HTTPClientWrapper.c
Michael Sauer 1b0501179d build: W600-SDK importiert, Firmware-Build und Hello am EVK
Docker-Build mit gcc-arm-none-eabi 4.9-2014q4 (statt Homebrew-Cask) verwendet,
Dockerfile/tools/docker.sh dafür aus Task 13 vorgezogen. cmake/sdk.cmake schont
gcc 4.9 (kennt -fcommon/-Wno-error=... nicht). Zwei zusätzliche SDK-Stubs
(EarlyInit, pre_gpio_config) in src/sys/sdk_stubs.c ergänzt, siehe sdk/PATCHES.md.
2026-09-11 12:52:26 +02:00

755 lines
19 KiB
C

#include "lwip/arch.h"
#include "HTTPClientWrapper.h"
#include "random.h"
#include "wm_osal.h"
#include "wm_sockets.h"
#include "lwip/sockets.h"
#include "wm_debug.h"
#include "HTTPClient.h"
#if TLS_CONFIG_HTTP_CLIENT
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : Stdc: HTTPWrapperIsAscii
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : Same as stdc: isascii
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperIsAscii(int c)
{
return (!(c & ~0177));
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : Stdc: HTTPWrapperToUpper
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : Convert character to uppercase.
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperToUpper(int c)
{
// -32
if(HTTPWrapperIsAscii(c) > 0)
{
if(c >= 97 && c <= 122)
{
return (c - 32);
}
}
return c;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : Stdc: HTTPWrapperToLower
// Last updated : 13/06/2006
// Author Name : Eitan Michaelson
// Notes : Convert character to lowercase.
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperToLower(int c)
{
// +32
if(HTTPWrapperIsAscii(c) > 0)
{
if(c >= 65 && c <= 90)
{
return (c + 32);
}
}
return c;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : Stdc: isalpha
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : returns nonzero if c is a particular representation of an alphabetic character
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperIsAlpha(int c)
{
if(HTTPWrapperIsAscii(c) > 0)
{
if( (c >= 97 && c <= 122) || (c >= 65 && c <= 90))
{
return c;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : Stdc: isalnum
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : returns nonzero if c is a particular representation of an alphanumeric character
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperIsAlNum(int c)
{
if(HTTPWrapperIsAscii(c) > 0)
{
if(HTTPWrapperIsAlpha(c) > 0)
{
return c;
}
if( c >= 48 && c <= 57)
{
return c;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_itoa
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : same as stdc itoa() // hmm.. allmost the same
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
char* HTTPWrapperItoa(char *s,int a)
{
unsigned int b;
if(a > 2147483647)
{
return 0; // overflow
}
if (a < 0) b = -a, *s++ = '-';
else b = a;
for(;a;a=a/10) s++;
for(*s='\0';b;b=b/10) *--s=b%10+'0';
return s;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_ShutDown
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : Handles parameter changes in the socket shutdown() function in AMT
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperShutDown (int s,int how)
{
return shutdown(s,how);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_GetSocketError
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : WSAGetLastError Wrapper (Win32 Specific)
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperGetSocketError (int s)
{
return errno;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_GetRandomeNumber
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : GetRandom number for Win32 & AMT
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void HTTPWrapperInitRandomeNumber()
{
srand((unsigned int)tls_os_get_time());
}
int HTTPWrapperGetRandomeNumber()
{
int num;
num = (int)(((double) rand()/ ((double)RAND_MAX+1)) * 16);
return num;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_GetRTC
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : Get uptime under Win32 & AMT
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
long HTTPWrapperGetUpTime()
{
long lTime = 0;
lTime = tls_os_get_time();
return lTime;
}
#endif //TLS_CONFIG_HTTP_CLIENT
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Section : HTTPWrapper_GetHostByName
// Last updated : 15/05/2005
// Author Name : Eitan Michaelson
// Notes : gethostbyname for Win32 (supports the AMT edition of the function)
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned long HTTPWrapperGetHostByName(char *name,unsigned long *address)
{
HTTP_HOSTNET *HostEntry;
int iPos = 0, iLen = 0,iNumPos = 0,iDots =0;
long iIPElement;
char c = 0;
char Num[4];
int iHostType = 0; // 0 : numeric IP
// Check if the name is an IP or host
iLen = strlen(name);
for(iPos = 0; iPos <= iLen;iPos++)
{
c = name[iPos];
if((c >= 48 && c <= 57) || (c == '.') )
{
// c is numeric or dot
if(c != '.')
{
// c is numeric
if(iNumPos > 3)
{
iHostType++;
break;
}
Num[iNumPos] = c;
Num[iNumPos + 1] = 0;
iNumPos ++;
}
else
{
iNumPos = 0;
iDots++;
iIPElement = atol(Num);
if(iIPElement > 256 || iDots > 3)
{
return 0; // error invalid IP
}
}
}
else
{
break; // this is an alpha numeric address type
}
}
if(c == 0 && iHostType == 0 && iDots == 3)
{
iIPElement = atol(Num);
if(iIPElement > 256)
{
return 0; // error invalid IP
}
}
else
{
iHostType++;
}
if(iHostType > 0)
{
HostEntry = gethostbyname(name);
if(HostEntry)
{
*(address) = *((u_long*)HostEntry->h_addr_list[0]);
//*(address) = (unsigned long)HostEntry->h_addr_list[0];
return 1; // Error
}
else
{
return 0; // OK
}
}
else // numeric address - no need for DNS resolve
{
*(address) = inet_addr(name);
return 1;
}
}
#if TLS_CONFIG_HTTP_CLIENT_SECURE
#define ALLOW_ANON_CONNECTIONS 1
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int HTTPWrapperSSLNegotiate(HTTP_SESSION_HANDLE pSession,int s,const struct sockaddr *name,int namelen,char *hostname)
{
return 0;
}
#if 1
#if 0
#define PSLL_PRT printf
#else
#define PSLL_PRT(x, ...)
#endif
/************************ memory manage ************************/
void *platform_malloc(uint32_t size)
{
return tls_mem_alloc(size);
}
void platform_free(void *ptr)
{
tls_mem_free(ptr);
}
/************************ mutex manage ************************/
void *platform_mutex_init(void)
{
tls_os_sem_t *mutex = NULL;
tls_os_sem_create(&mutex,1);
return mutex;
}
void platform_mutex_lock(void *mutex)
{
tls_os_sem_acquire(mutex,0);
}
void platform_mutex_unlock(void *mutex)
{
tls_os_sem_release(mutex);
}
void platform_mutex_destroy(void *mutex)
{
if (!mutex)
return;
tls_os_sem_delete(mutex);
}
static int ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len )
{
return random_get_bytes( output, output_len );
}
static void my_debug( void *ctx, int level, const char *str )
{
PSLL_PRT("%s", str);
}
static int net_is_blocking( void )
{
switch( errno )
{
#if defined EAGAIN
case EAGAIN:
#endif
#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
return( 1 );
}
return( 0 );
}
static int net_recv( void *ctx, unsigned char *buf, size_t len )
{
int ret;
int skt = (int)(long) ctx;
#if 0
fd_set read_set;
struct timeval tv;
FD_ZERO(&read_set);
FD_SET(skt, &read_set);
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = select(skt + 1, &read_set, NULL, NULL, &tv);
if (ret > 0)
{
if (FD_ISSET(skt, &read_set))
{
#endif
ret = recv( skt, buf, len, 0);
if( ret < 0 )
{
if( net_is_blocking() != 0 )
return( POLARSSL_ERR_NET_WANT_READ );
if( errno == EPIPE || errno == ECONNRESET )
return( POLARSSL_ERR_NET_CONN_RESET );
if( errno == EINTR )
return( POLARSSL_ERR_NET_WANT_READ );
return( POLARSSL_ERR_NET_RECV_FAILED );
}
#if 0
FD_CLR(skt, &read_set);
}
else
{
PSLL_PRT("\r\n\r\nssl select no\r\n\r\n");
}
}
else if (0 == ret)
{
PSLL_PRT("\r\n\r\nssl recv timeout\r\n\r\n");
}
else
{
PSLL_PRT("\r\n\r\nssl select error\r\n\r\n");
}
#endif
return ret;
}
/*
* Write at most 'len' characters
*/
static int net_send( void *ctx, const unsigned char *buf, size_t len )
{
int ret = send( (long) ctx, buf, len, 0);
if( ret < 0 )
{
if( net_is_blocking() != 0 )
return( POLARSSL_ERR_NET_WANT_WRITE );
if( errno == EPIPE || errno == ECONNRESET )
return( POLARSSL_ERR_NET_CONN_RESET );
if( errno == EINTR )
return( POLARSSL_ERR_NET_WANT_WRITE );
return( POLARSSL_ERR_NET_SEND_FAILED );
}
return( ret );
}
void *platform_ssl_connect(void *tcp_fd,
const char *server_cert,
int server_cert_len)
{
int ret;
ssl_context *ssl;
ssl_session *ssn;
x509_cert *cacert = NULL;
ssl = platform_malloc(sizeof(ssl_context));
if (!ssl)
return NULL;
ssn = platform_malloc(sizeof(ssl_session));
if (!ssn)
{
platform_free(ssl);
return NULL;
}
if (server_cert)
{
cacert = platform_malloc(sizeof(x509_cert));
if (!cacert)
{
platform_free(ssl);
platform_free(ssn);
return NULL;
}
memset(cacert, 0, sizeof(x509_cert));
ret = x509parse_crt(cacert, (unsigned char *) server_cert, server_cert_len);
if( ret != 0 )
{
PSLL_PRT( " failed\n ! x509parse_crt returned %d\n\n", ret );
platform_free(ssl);
platform_free(ssn);
if(cacert)
platform_free(cacert);
return NULL;
}
}
memset(ssl, 0, sizeof(ssl_context));
if( ( ret = ssl_init( ssl ) ) != 0 )
{
PSLL_PRT( " failed\n ! ssl_init returned %d\n\n", ret );
if(cacert)
x509_free( cacert );
platform_free(ssl);
platform_free(ssn);
if(cacert)
platform_free(cacert);
return NULL;
}
ssl_set_endpoint( ssl, SSL_IS_CLIENT );
if (server_cert)
ssl_set_authmode( ssl, SSL_VERIFY_REQUIRED );
else
ssl_set_authmode( ssl, SSL_VERIFY_NONE );
ssl_set_rng( ssl, ctr_drbg_random, NULL );
ssl_set_dbg( ssl, my_debug, NULL);
ssl_set_bio( ssl, net_recv, tcp_fd, net_send, tcp_fd );
ssl_set_ciphersuites( ssl, ssl_default_ciphersuites );
memset(ssn, 0, sizeof(ssl_session));
ssl_set_session( ssl, 1, 600, ssn );
if (server_cert)
ssl_set_ca_chain( ssl, cacert, NULL, NULL);
while( ( ret = ssl_handshake( ssl ) ) != 0 )
{
if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
{
PSLL_PRT( " failed\n ! ssl_handshake returned %d\n\n", ret );
goto fail;
}
PSLL_PRT("INFO: ssl_handshake returned %d\n\n", ret);
}
if (server_cert)
{
if( ( ret = ssl_get_verify_result( ssl ) ) != 0 )
{
PSLL_PRT( "Verifying peer X.509 certificate failed\n" );
if( ( ret & BADCERT_EXPIRED ) != 0 )
PSLL_PRT( " ! server certificate has expired\n" );
if( ( ret & BADCERT_REVOKED ) != 0 )
PSLL_PRT( " ! server certificate has been revoked\n" );
if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
PSLL_PRT( " ! CN mismatch \n");
if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
PSLL_PRT( " ! self-signed or not signed by a trusted CA\n" );
PSLL_PRT( "\n" );
ssl_close_notify( ssl );
goto fail;
}
else
{
PSLL_PRT( "Verifying X.509 certificate pass.\n" );
}
}
//ssl->read_lock = platform_mutex_init();
ssl->write_lock = platform_mutex_init();
//printf("ssl read/write lock 0x%p/0x%p\n", ssl->read_lock, ssl->write_lock);
PSLL_PRT("ssl rdwr lock 0x%p\n", ssl->write_lock);
return ssl;
fail:
if(cacert)
x509_free( cacert );
ssl_free( ssl );
platform_free(ssl);
platform_free(ssn);
if(cacert)
platform_free(cacert);
return NULL;
}
int platform_ssl_close(void *ssl)
{
ssl_context *sslt = (ssl_context *)ssl;
platform_mutex_lock(sslt->write_lock);
ssl_close_notify( sslt );
x509_free( sslt->ca_chain );
platform_free(sslt->ca_chain);
platform_free(sslt->session);
platform_mutex_unlock(sslt->write_lock);
platform_mutex_destroy(sslt->write_lock);
//platform_mutex_destroy(sslt->read_lock);
ssl_free(sslt);
platform_free(sslt);
return 0;
}
int platform_ssl_send(void *ssl, const char *buf, int len)
{
int ret;
ssl_context *sslt = (ssl_context *)ssl;
platform_mutex_lock(sslt->write_lock);
while( ( ret = ssl_write( sslt, (u8 *)buf, len ) ) <= 0 )
{
if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
{
PSLL_PRT( " failed\n ! ssl_write returned %d, errno %d\n", ret , errno);
break;
}
}
platform_mutex_unlock(sslt->write_lock);
return ret;
}
int platform_ssl_recv(void *ssl, char *buf, int len)
{
int ret;
ssl_context *sslt = (ssl_context *)ssl;
platform_mutex_lock(sslt->write_lock);
//platform_mutex_lock(sslt->read_lock);
do
{
ret = ssl_read( sslt, (u8 *)buf, len );
if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE )
continue;
//if( ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY )
// break;
if( ret < 0 )
{
PSLL_PRT( "failed\n ! ssl_read returned %d, errno %d\n", ret , errno);
break;
}
else if( ret == 0 )
{
PSLL_PRT("\n\nEOF, errno %d\n\n", errno);
break;
}
else
{
//PSLL_PRT( " %d bytes read\n\n%s", ret, (char *) buf );
break;
}
} while(1);
platform_mutex_unlock(sslt->write_lock);
//platform_mutex_unlock(sslt->read_lock);
//PSLL_PRT(" <== platform_ssl_recv ret %d\n", ret);
return ret;
}
int HTTPWrapperSSLConnect(tls_ssl_t **ssl_p,int fd,const struct sockaddr *name,int namelen,char *hostname)
{
int rc;
tls_ssl_t *ssl = NULL;
if(name)
{
char *host_ip = inet_ntoa(((struct sockaddr_in*)name)->sin_addr);
rc = connect(fd, // Socket
name, // Server address
sizeof(struct sockaddr));
if(rc)
{
TLS_DBGPRT_ERR("host_ip=%s\n", host_ip);
TLS_DBGPRT_ERR("Connection Failed: %d. Exiting\n", rc);
return rc;
}
}
ssl = platform_ssl_connect((void *)fd, NULL, 0);
if(ssl == NULL)
return -1;
*ssl_p = ssl;
return 0;
}
int HTTPWrapperSSLSend(tls_ssl_t *ssl, int s,char *sndbuf, int len,int flags)
{
return platform_ssl_send(ssl, sndbuf, len);
}
int HTTPWrapperSSLRecv(tls_ssl_t *ssl,int s,char *buf, int len,int flags)
{
int ret = platform_ssl_recv(ssl, buf, len);
if(ssl->in_msglen > 0)
return SOCKET_SSL_MORE_DATA;
return ret;
}
int HTTPWrapperSSLRecvPending(tls_ssl_t *ssl)
{
return ssl_get_bytes_avail(ssl);
}
int HTTPWrapperSSLClose(tls_ssl_t *ssl, int s)
{
if(ssl == NULL)
return 0;
return platform_ssl_close(ssl);
}
#endif //TLS_CONFIG_USE_POLARSSL
#endif //TLS_CONFIG_HTTP_CLIENT_SECURE