diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Components/wac_network | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Components/wac_network')
71 files changed, 7857 insertions, 0 deletions
diff --git a/Src/Components/wac_network/Headers.cpp b/Src/Components/wac_network/Headers.cpp new file mode 100644 index 00000000..bf95a7b4 --- /dev/null +++ b/Src/Components/wac_network/Headers.cpp @@ -0,0 +1,120 @@ +#include "foundation/error.h" +#include "foundation/types.h" + +#include "headers.h" +#include "netinc.h" + +#include <stdlib.h> +#include <string.h> + +JNL_Headers::JNL_Headers() +{ + m_recvheaders = NULL; + m_recvheaders_size = 0; +} + +JNL_Headers::~JNL_Headers() +{ + if ( m_recvheaders ) + free( m_recvheaders ); +} + +void JNL_Headers::Reset() +{ + if ( m_recvheaders ) + free( m_recvheaders ); + + m_recvheaders = NULL; + m_recvheaders_size = 0; +} + +const char *JNL_Headers::GetAllHeaders() +{ + // double null terminated, null delimited list + if ( m_recvheaders ) + return m_recvheaders; + else + return "\0\0"; +} + +const char *JNL_Headers::GetHeader( const char *headername ) +{ + char *ret = NULL; + + if ( headername[ 0 ] == 0 || !m_recvheaders ) + return NULL; + + size_t headername_size = strlen( headername ); + + char *buf = (char *)malloc( headername_size + 2 ); + strcpy( buf, headername ); + + if ( buf[ headername_size - 1 ] != ':' ) + { + buf[ headername_size++ ] = ':'; + buf[ headername_size ] = 0; + } + + char *p = m_recvheaders; + while ( p && *p ) + { + if ( !strncasecmp( buf, p, headername_size ) ) + { + ret = p + headername_size; + while ( ret && *ret && *ret == ' ' ) + ret++; + + break; + } + + p += strlen( p ) + 1; + } + + free( buf ); + + return ret; +} + +int JNL_Headers::Add( const char *buf ) +{ + if ( !m_recvheaders ) + { + m_recvheaders_size = strlen( buf ) + 1; + if ( m_recvheaders_size == 0 || m_recvheaders_size == (size_t)-1 ) // check for overflow + { + return NErr_OutOfMemory; + } + + m_recvheaders = (char *)malloc( m_recvheaders_size + 1 ); + if ( m_recvheaders ) + { + strcpy( m_recvheaders, buf ); // safe because we malloc'd specifically above + m_recvheaders[ m_recvheaders_size ] = 0; + } + else + { + return NErr_OutOfMemory; + } + } + else + { + size_t oldsize = m_recvheaders_size; + m_recvheaders_size += strlen( buf ) + 1; + if ( m_recvheaders_size + 1 < oldsize ) // check for overflow + { + return NErr_OutOfMemory; + } + + char *n = (char *)realloc( m_recvheaders, m_recvheaders_size + 1 ); + if ( !n ) + { + return NErr_OutOfMemory; + } + + strcpy( n + oldsize, buf ); // safe because we malloc specifially for the size + n[ m_recvheaders_size ] = 0; // double null terminate + m_recvheaders = n; + } + + return NErr_Success; +} diff --git a/Src/Components/wac_network/Headers.h b/Src/Components/wac_network/Headers.h new file mode 100644 index 00000000..0365737b --- /dev/null +++ b/Src/Components/wac_network/Headers.h @@ -0,0 +1,22 @@ +#ifndef NULLSOFT_WAC_NETWORK_HEADERS_H +#define NULLSOFT_WAC_NETWORK_HEADERS_H + +// TODO: benski> change this to use a smarter data structure. +// this initial implementation is known to work, however +class JNL_Headers +{ +public: + JNL_Headers(); + ~JNL_Headers(); + + const char *GetAllHeaders(); + const char *GetHeader( const char *header_name ); + int Add( const char *buf ); + void Reset(); + +private: + char *m_recvheaders; + size_t m_recvheaders_size; +}; + +#endif // !NULLSOFT_WAC_NETWORK_HEADERS_H diff --git a/Src/Components/wac_network/ServiceBuild.h b/Src/Components/wac_network/ServiceBuild.h new file mode 100644 index 00000000..6b12c5c1 --- /dev/null +++ b/Src/Components/wac_network/ServiceBuild.h @@ -0,0 +1,28 @@ +#ifndef NULLSOFT_WAC_NETWORK_SERVICEBUILD_H +#define NULLSOFT_WAC_NETWORK_SERVICEBUILD_H + +template <class api_T> +static void ServiceBuild( api_T *&p_api_t, GUID p_factoryGUID_t ) +{ + if ( WASABI_API_SVC ) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( p_factoryGUID_t ); + if ( factory ) + p_api_t = reinterpret_cast<api_T *>( factory->getInterface() ); + } +} + +template <class api_T> +static void ServiceRelease( api_T *p_api_t, GUID p_factoryGUID_t ) +{ + if ( WASABI_API_SVC && p_api_t ) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( p_factoryGUID_t ); + if ( factory ) + factory->releaseInterface( p_api_t ); + } + + p_api_t = NULL; +} + +#endif // !NULLSOFT_WAC_NETWORK_SERVICEBUILD_H diff --git a/Src/Components/wac_network/api__wac_network.h b/Src/Components/wac_network/api__wac_network.h new file mode 100644 index 00000000..47fe39b9 --- /dev/null +++ b/Src/Components/wac_network/api__wac_network.h @@ -0,0 +1,25 @@ +#ifndef NULLSOFT_WAC_NETWORK_API_H +#define NULLSOFT_WAC_NETWORK_API_H + +#include "netinc.h" +#include "wac_network_dns.h" + +wa::Components::WAC_Network_AsyncDNS *GetGlobalDNS(); +void DestroyGlobalDNS(); + +#include "api/service/api_service.h" + +#include "api/application/api_application.h" +#define WASABI_API_APP applicationApi + +#include "../Agave/Config/api_config.h" + +#include "../nu/threadpool/api_threadpool.h" +extern api_threadpool *threadPoolApi; +#define WASABI_API_THREADPOOL threadPoolApi + +#include "api/syscb/api_syscb.h" +#define WASABI_API_SYSCB sysCallbackApi + +#endif // !NULLSOFT_WAC_NETWORK_API_H + diff --git a/Src/Components/wac_network/main.cpp b/Src/Components/wac_network/main.cpp new file mode 100644 index 00000000..ee516805 --- /dev/null +++ b/Src/Components/wac_network/main.cpp @@ -0,0 +1,210 @@ +#include "main.h" + +//#include "wac_network_connection_factory.h" +#include "ServiceBuild.h" + +#include <openssl/ssl.h> + +#include "bfc/platform/export.h" + + + +#include "netinc.h" +#include "api__wac_network.h" + +#include "wac_network_http_receiver_factory.h" +#include "wac_network_connection_factory.h" +#include "wac_network_ssl_connection_factory.h" +#include "wac_network_dns_factory.h" +#include "wac_network_web_server_factory.h" +#include "util.h" + +#include "api/syscb/api_syscb.h" +#include "wac_network_ssl_connection.h" + +#include <openssl/ssl.h> + +#include "bfc/platform/export.h" +#include "../nu/nonewthrow.c" + + +JNL_HTTPGetFactory HTTPGetService; +JNL_ConnectionFactory connectionService; +JNL_AsyncDNSFactory dnsService; +JNL_WebServFactory webserverService; + + + + +api_service *WASABI_API_SVC = Q_NULLPTR; +api_application *WASABI_API_APP = Q_NULLPTR; +api_config *AGAVE_API_CONFIG = Q_NULLPTR; +api_threadpool *WASABI_API_THREADPOOL = Q_NULLPTR; +api_syscb *WASABI_API_SYSCB = Q_NULLPTR; + + +static wa::Components::WAC_Network_AsyncDNS *global_dns = NULL; + +wa::Components::WAC_Network_AsyncDNS *GetGlobalDNS() +{ + if ( !global_dns ) + { + if ( JNL::open_socketlib() ) + return NULL; + + global_dns = new wa::Components::WAC_Network_AsyncDNS; + } + + return global_dns; +} + +void DestroyGlobalDNS() +{ + if ( global_dns ) + { + delete global_dns; + global_dns = NULL; + + JNL::close_socketlib(); + } +} + + +#ifdef USE_SSL +#include <wincrypt.h> +#include <openssl/rand.h> + +static HCRYPTPROV GetKeySet() +{ + HCRYPTPROV hCryptProv; + LPCWSTR UserName = L"WinampKeyContainer"; // name of the key container + + if ( CryptAcquireContext( + &hCryptProv, // handle to the CSP + UserName, // container name + NULL, // use the default provider + PROV_RSA_FULL, // provider type + 0 ) ) // flag values + { + return hCryptProv; + } + else if ( CryptAcquireContext( + &hCryptProv, + UserName, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET ) ) + { + return hCryptProv; + } + else + return 0; + +} + +JNL_SSL_ConnectionFactory sslConnectionService; + +void InitSSL() +{ + SSL_load_error_strings(); + SSL_library_init(); + + HCRYPTPROV hCryptProv = GetKeySet(); + if ( hCryptProv ) + { + BYTE pbData[ 8 * sizeof( unsigned long ) ] = { 0 }; + if ( CryptGenRandom( hCryptProv, 8 * sizeof( unsigned long ), pbData ) ) + { + RAND_seed( pbData, 16 ); + } + + CryptReleaseContext( hCryptProv, 0 ); + } + + sslContext = SSL_CTX_new( SSLv23_client_method() ); + + SSL_CTX_set_verify( sslContext, SSL_VERIFY_NONE, NULL ); + // SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF); +} + +void QuitSSL() +{ + SSL_CTX_free( sslContext ); +} + +#endif // !USE_SSL + + + +wa::Components::WAC_Network _wac_network; + + +void wa::Components::WAC_Network::RegisterServices( api_service *p_service ) +{ + WASABI_API_SVC = p_service; + + ServiceBuild( WASABI_API_SYSCB, syscbApiServiceGuid ); + ServiceBuild( WASABI_API_APP, applicationApiServiceGuid ); + ServiceBuild( AGAVE_API_CONFIG, AgaveConfigGUID ); + ServiceBuild( WASABI_API_THREADPOOL, ThreadPoolGUID ); + + + WASABI_API_SVC->service_register( &HTTPGetService ); + WASABI_API_SVC->service_register( &connectionService ); + +#ifdef USE_SSL + WASABI_API_SVC->service_register( &sslConnectionService ); +#endif + + WASABI_API_SVC->service_register( &dnsService ); + WASABI_API_SVC->service_register( &webserverService ); + //dlMgrFactory.Register( &dlMgr ); +} + +void wa::Components::WAC_Network::DeregisterServices( api_service *p_service ) +{ + Q_UNUSED( p_service ) + + ServiceRelease( WASABI_API_SYSCB, syscbApiServiceGuid ); + + ServiceRelease( WASABI_API_APP, applicationApiServiceGuid ); + ServiceRelease( AGAVE_API_CONFIG, AgaveConfigGUID ); + + + //dlMgr.Kill(); + //dlMgrFactory.Deregister(); + DestroyGlobalDNS(); + p_service->service_deregister( &HTTPGetService ); + p_service->service_deregister( &connectionService ); + +#ifdef USE_SSL + p_service->service_deregister( &sslConnectionService ); +#endif + + p_service->service_deregister( &dnsService ); + +#ifdef USE_SSL + QuitSSL(); +#endif + + ServiceRelease( WASABI_API_THREADPOOL, ThreadPoolGUID ); +} + + +extern "C" WAC_NETWORK_EXPORT ifc_wa5component * GetWinamp5SystemComponent() +{ + return &_wac_network; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_Network +START_DISPATCH; +VCB( API_WA5COMPONENT_REGISTERSERVICES, RegisterServices ) +CB( API_WA5COMPONENT_REGISTERSERVICES_SAFE_MODE, RegisterServicesSafeModeOk ) +VCB( API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices ) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_network/main.h b/Src/Components/wac_network/main.h new file mode 100644 index 00000000..aade5ffd --- /dev/null +++ b/Src/Components/wac_network/main.h @@ -0,0 +1,34 @@ +#ifndef NULLSOFT_WAC_NETWORK_MAIN_H +#define NULLSOFT_WAC_NETWORK_MAIN_H + +#include <QtCore> + +#include "wac_network_global.h" + +#include "api__wac_network.h" +//#include "ServiceBuild.h" + + +#include "../Agave/Component/ifc_wa5component.h" + +namespace wa +{ + namespace Components + { + class WAC_Network : public ifc_wa5component + { + public: + WAC_Network() {} + + void RegisterServices( api_service *service ); + int RegisterServicesSafeModeOk() { return 1; } + + void DeregisterServices( api_service *service ); + + protected: + RECVS_DISPATCH; + }; + } +} + +#endif // !NULLSOFT_WAC_NETWORK_MAIN_H
\ No newline at end of file diff --git a/Src/Components/wac_network/netinc.h b/Src/Components/wac_network/netinc.h new file mode 100644 index 00000000..d2892bc2 --- /dev/null +++ b/Src/Components/wac_network/netinc.h @@ -0,0 +1,86 @@ +/* +** JNetLib +** Copyright (C) 2000-2006 Nullsoft, Inc. +** Author: Justin Frankel +** File: netinc.h - network includes and portability defines (used internally) +** License: see jnetlib.h +*/ + +#ifndef NULLSOFT_WAC_NETWORK_NETINC_H +#define NULLSOFT_WAC_NETWORK_NETINC_H + +#ifdef _WIN32 + +//#include <time.h> +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <winsock2.h> +#include <Ws2tcpip.h> +#include <wspiapi.h> + +#include "..\replicant\foundation\types.h" + +#define strtoull(x,y,z) _strtoui64(x,y,z) +#define strcasecmp(x,y) _stricmp(x,y) +#define strcasecmpn(x,y, count) _strnicmp(x,y,count) +#define strncasecmp(x,y, count) _strnicmp(x,y,count) +#define HTONS(val) ((((unsigned short) (val) & (unsigned short) 0x00ffU) << 8) | (((unsigned short) (val) & (unsigned short) 0xff00U) >> 8)) +#define ERRNO (WSAGetLastError()) +#define SET_SOCK_BLOCK(s,block) { unsigned long __i=block?0:1; ioctlsocket(s,FIONBIO,&__i); } + +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEWOULDBLOCK + +#else +#define EWOULDBLOCK EWOULDBLOCK +#define EINPROGRESS EINPROGRESS +#ifndef THREAD_SAFE +#define THREAD_SAFE +#endif +#ifndef _REENTRANT +#define _REENTRANT +#endif +#include <pthread.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + + +#define ERRNO errno +#define closesocket(s) close(s) +#define SET_SOCK_BLOCK(s,block) { int __flags; if ((__flags = fcntl(s, F_GETFL, 0)) != -1) { if (!block) __flags |= O_NONBLOCK; else __flags &= ~O_NONBLOCK; fcntl(s, F_SETFL, __flags); } } + +#define _stricmp(x,y) strcasecmp(x,y) +#define _strnicmp(x,y,z) strncasecmp(x,y,z) +#define wsprintf sprintf +typedef int SOCKET; + +#endif // !_WIN32 + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#ifndef INADDR_ANY +#define INADDR_ANY 0 +#endif + +#ifndef SHUT_RDWR +#define SHUT_RDWR 2 +#endif + +#endif //!NULLSOFT_WAC_NETWORK_NETINC_H diff --git a/Src/Components/wac_network/resource.h b/Src/Components/wac_network/resource.h new file mode 100644 index 00000000..528c5d4a --- /dev/null +++ b/Src/Components/wac_network/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by wac_network.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Components/wac_network/resources/curtainProgress.png b/Src/Components/wac_network/resources/curtainProgress.png new file mode 100644 index 00000000..5dd024ac --- /dev/null +++ b/Src/Components/wac_network/resources/curtainProgress.png @@ -0,0 +1,5 @@ +‰PNG
+ +IHDRDñYÍG¿ïçüŽ‚§…˜ØüÕùÖ~v«î„pJѧ-ޤç”Ìã¯<µßwCÑÄÙ¬Wî÷ýç"˜/\š*çßÿ{øóñõú̃…†þÿ~bNS‹33¾Û(Ÿ…½®ql^~ÉõeŠà¹—Rþðñ6§èóéÛAÈæR%£ë +Ù:gÔ>ù¤=îû§¸Pn©§Y'PÔűEínG½ì6ŸUy‚ ˆÄCÖæðÂeOL%ŠÉERùg&1+q¶üoªË**3‡Gn~íÚÑ–öl®'.˜ãMN@(jŽŸÊ½¹h6¾œh¤òš %ãÿÙºyâB9Ÿƒ‹ºDG@l|hØìܹŘgK²nÆ–)š¬>8Ã9Õ¿TP«*_¸¶@On˜”CÄúLÓx+r!¶öEÿš_ô2r”§¼ýñŸBäÃàúÂ;ýnŒ† J¥º–ü ¯¹q…®þf¿ÇTK¿¸û +ú¯U×(J>Énw…ßUÁ}ð3ÜzÿöÄ7³û1övbN§YwÝØ˜ÚÂ@ÏBˆ¨gùBwï0pG#Ïqƒæ†èGc-Ö¥¬=Éï¹¼»ÛÀ…=x6p:V½VRh4hk£a‡
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/menuArrow.png b/Src/Components/wac_network/resources/menuArrow.png Binary files differnew file mode 100644 index 00000000..769a1e07 --- /dev/null +++ b/Src/Components/wac_network/resources/menuArrow.png diff --git a/Src/Components/wac_network/resources/pages/dnsError.htm b/Src/Components/wac_network/resources/pages/dnsError.htm new file mode 100644 index 00000000..7ffa7a2a --- /dev/null +++ b/Src/Components/wac_network/resources/pages/dnsError.htm @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>Winamp Online Services Error Page</title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + <meta http-equiv="Content-Style-Type" content="text/css" /> + <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/> + <script src="./errorPageStrings.js"></script> + <script src="./errorPageFunctions.js"></script> +</head> +<body> +<!-- Container --> +<div id="errorContainer"> + <!-- Icon --> + <div id="errorIcon"></div> + <!-- Error Body --> + <div id="errorBody"> + <!-- Error Title --> + <div id="errorTitle"><h1 id="errorTitleText"><noscript>An Error Has Occurred</noscript></h1></div> + <!-- Error Code --> + <div id="errorCode"><noscript>HTTP - Error</noscript></div> + <!-- Error Description --> + <div id="errorDesc"><p id="errorDescText"><noscript>An error has occurred. We would show you more but your browser does not support javascript.</noscript></p></div> + <!-- Error Options --> + <div id="errorTryAgain"><a href="javascript:tryagain();">Try Again</a></div> + <div id="errorMore"><a href="javascript:togglemore();">More</a></div> + <!-- Additional Info --> + <div id="errorMoreInfo"> + <table> + <tr><td nowrap>Service name:</td><td><script language=javascript>document.write(unescape(geturlparams('servicename')));</script></td></tr> + <tr><td nowrap>Error code:</td><td><script language=javascript>document.write(geterrorhex());</script></td></tr> + <tr><td nowrap>Url:</td><td><script language=javascript>document.write(unescape(geturlparams('url')));</script></td></tr> + <tr><td nowrap>Service id:</td><td><script language=javascript>document.write(geturlparams('svcid'));</script></td></tr> + <tr><td nowrap>Client id:</td><td><script language=javascript>document.write(geturlparams('uniqueid'));</script></td></tr> + </table> + </div> + </div> +</div> +<script language=javascript> +window.onload = function(){populatepage();}; +</script> +</body> +</html>
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/errorIcon.png b/Src/Components/wac_network/resources/pages/errorIcon.png Binary files differnew file mode 100644 index 00000000..969f5069 --- /dev/null +++ b/Src/Components/wac_network/resources/pages/errorIcon.png diff --git a/Src/Components/wac_network/resources/pages/errorPageFunctions.js b/Src/Components/wac_network/resources/pages/errorPageFunctions.js new file mode 100644 index 00000000..315476a2 --- /dev/null +++ b/Src/Components/wac_network/resources/pages/errorPageFunctions.js @@ -0,0 +1,288 @@ +function geturlparams( key ) +{ + key = key.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); + var regexS = "[\\#&]"+key+"=([^&#]*)"; + var regex = new RegExp( regexS ); + var results = regex.exec( window.location.href ); + if( results == null ) + return ""; + else + return results[1]; +} +function geterrorhex() +{ + var signedInt=geturlparams('errorcode'); + return "0x" + CvtI32(signedInt).toUpperCase(); +} +function bitStr(N, bits) +{ + var S = "", Q + while (bits--) { S = (Q=N%2) + S ; N = (N-Q)/2 } + return S; +} +function hex(N, bits) +{ + return (0x10000 + N).toString(16).substring(5-bits) +} +function Four(d, c, b, a, bits) +{ + return hex(d, bits) + hex(c, bits) + hex(b, bits) + hex(a, bits) +} +function CvtI32(F) +{ + var X = F |0, a, b, c, d + var ba = bitStr(a = X & 0xFF, 8) + var bb = bitStr(b = X >> 8 & 0xFF, 8) + var bc = bitStr(c = X >> 16 & 0xFF, 8) + var bd = bitStr(d = X >> 24 & 0xFF, 8) + var hex = Four(d, c, b, a, 2) + return hex; +} +function tryagain() +{ + window.location.replace(unescape(geturlparams('url'))); +} +function togglemore() +{ + var display=document.getElementById("errorMoreInfo").style.display; + if (display == "block") { + document.getElementById("errorMoreInfo").style.display="none"; + } + else { + document.getElementById("errorMoreInfo").style.display="block"; + } +} +function populatepage() +{ + var errorcode = parseInt(geturlparams('errorcode')); + switch (errorcode) + { + case 404: + var errorTitle = errorTitle404; + var errorCode = errorCode404; + var errorDescription = errorDescription404; + break; + case 403: + var errorTitle = errorTitle403; + var errorCode = errorCode403; + var errorDescription = errorDescription403; + break; + case 500: + var errorTitle = errorTitle500; + var errorCode = errorCode500; + var errorDescription = errorDescription500; + break; + case 503: + var errorTitle = errorTitle503; + var errorCode = errorCode503; + var errorDescription = errorDescription503; + break; + case 502: + var errorTitle = errorTitle502; + var errorCode = errorCode502; + var errorDescription = errorDescription502; + break; + case 501: + var errorTitle = errorTitle501; + var errorCode = errorCode501; + var errorDescription = errorDescription501; + break; + case 504: + var errorTitle = errorTitle504; + var errorCode = errorCode504; + var errorDescription = errorDescription504; + break; + case 505: + var errorTitle = errorTitle505; + var errorCode = errorCode505; + var errorDescription = errorDescription505; + break; + case 400: + var errorTitle = errorTitle400; + var errorCode = errorCode400; + var errorDescription = errorDescription400; + break; + case 401: + var errorTitle = errorTitle401; + var errorCode = errorCode401; + var errorDescription = errorDescription401; + break; + case 402: + var errorTitle = errorTitle402; + var errorCode = errorCode402; + var errorDescription = errorDescription402; + break; + case 405: + var errorTitle = errorTitle405; + var errorCode = errorCode405; + var errorDescription = errorDescription405; + break; + case 406: + var errorTitle = errorTitle406; + var errorCode = errorCode406; + var errorDescription = errorDescription406; + break; + case 407: + var errorTitle = errorTitle407; + var errorCode = errorCode407; + var errorDescription = errorDescription407; + break; + case 408: + var errorTitle = errorTitle408; + var errorCode = errorCode408; + var errorDescription = errorDescription408; + break; + case 409: + var errorTitle = errorTitle409; + var errorCode = errorCode409; + var errorDescription = errorDescription409; + break; + case 410: + var errorTitle = errorTitle410; + var errorCode = errorCode410; + var errorDescription = errorDescription410; + break; + case 411: + var errorTitle = errorTitle411; + var errorCode = errorCode411; + var errorDescription = errorDescription411; + break; + case 413: + var errorTitle = errorTitle413; + var errorCode = errorCode413; + var errorDescription = errorDescription413; + break; + case 414: + var errorTitle = errorTitle414; + var errorCode = errorCode414; + var errorDescription = errorDescription414; + break; + case 415: + var errorTitle = errorTitle415; + var errorCode = errorCode415; + var errorDescription = errorDescription415; + break; + case -2146697214: + var errorTitle = errorTitle800c0002; + var errorCode = errorCode800c0002; + var errorDescription = errorDescription800c0002; + break; + case -2146697213: + var errorTitle = errorTitle800c0003; + var errorCode = errorCode800c0003; + var errorDescription = errorDescription800c0003; + break; + case -2146697212: + var errorTitle = errorTitle800c0004; + var errorCode = errorCode800c0004; + var errorDescription = errorDescription800c0004; + break; + case -2146697211: + var errorTitle = errorTitle800c0005; + var errorCode = errorCode800c0005; + var errorDescription = errorDescription800c0005; + break; + case -2146697210: + var errorTitle = errorTitle800c0006; + var errorCode = errorCode800c0006; + var errorDescription = errorDescription800c0006; + break; + case -2146697209: + var errorTitle = errorTitle800c0007; + var errorCode = errorCode800c0007; + var errorDescription = errorDescription800c0007; + break; + case -2146697208: + var errorTitle = errorTitle800c0008; + var errorCode = errorCode800c0008; + var errorDescription = errorDescription800c0008; + break; + case -2146697207: + var errorTitle = errorTitle800c0009; + var errorCode = errorCode800c0009; + var errorDescription = errorDescription800c0009; + break; + case -2146697206: + var errorTitle = errorTitle800c000a; + var errorCode = errorCode800c000a; + var errorDescription = errorDescription800c000a; + break; + case -2146697205: + var errorTitle = errorTitle800c000b; + var errorCode = errorCode800c000b; + var errorDescription = errorDescription800c000b; + break; + case -2146697204: + var errorTitle = errorTitle800c000c; + var errorCode = errorCode800c000c; + var errorDescription = errorDescription800c000c; + break; + case -2146697203: + var errorTitle = errorTitle800c000d; + var errorCode = errorCode800c000d; + var errorDescription = errorDescription800c000d; + break; + case -2146697202: + var errorTitle = errorTitle800c000e; + var errorCode = errorCode800c000e; + var errorDescription = errorDescription800c000e; + break; + case -2146697201: + var errorTitle = errorTitle800c000f; + var errorCode = errorCode800c000f; + var errorDescription = errorDescription800c000f; + break; + case -2146697200: + var errorTitle = errorTitle800c0010; + var errorCode = errorCode800c0010; + var errorDescription = errorDescription800c0010; + break; + case -2146697196: + var errorTitle = errorTitle800c0014; + var errorCode = errorCode800c0014; + var errorDescription = errorDescription800c0014; + break; + case -2146697195: + var errorTitle = errorTitle800c0015; + var errorCode = errorCode800c0015; + var errorDescription = errorDescription800c0015; + break; + case -2146697194: + var errorTitle = errorTitle800c0016; + var errorCode = errorCode800c0016; + var errorDescription = errorDescription800c0016; + break; + case -2146697193: + var errorTitle = errorTitle800c0017; + var errorCode = errorCode800c0017; + var errorDescription = errorDescription800c0017; + break; + case -2146697192: + var errorTitle = errorTitle800c0018; + var errorCode = errorCode800c0018; + var errorDescription = errorDescription800c0018; + break; + case -2146697960: + var errorTitle = errorTitle800c0100; + var errorCode = errorCode800c0100; + var errorDescription = errorDescription800c0100; + break; + case -2146696704: + var errorTitle = errorTitle800c0200; + var errorCode = errorCode800c0200; + var errorDescription = errorDescription800c0200; + break; + case -2146696448: + var errorTitle = errorTitle800c0300; + var errorCode = errorCode800c0300; + var errorDescription = errorDescription800c0300; + break; + default: + var errorTitle = errorTitleUnknown; + var errorCode = errorCodeUnknown; + var errorDescription = errorDescriptionUnknown; + } + document.getElementById("errorTitleText").innerHTML = errorTitle; + document.getElementById("errorCode").innerHTML = errorCode; + document.getElementById("errorDescText").innerHTML = errorDescription; +}
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/errorPageStrings.js b/Src/Components/wac_network/resources/pages/errorPageStrings.js new file mode 100644 index 00000000..f011d690 --- /dev/null +++ b/Src/Components/wac_network/resources/pages/errorPageStrings.js @@ -0,0 +1,138 @@ +var errorTitleUnknown = "An Unknown Error has occurred"; +var errorCodeUnknown = "Unknown Error"; +var errorDescriptionUnknown = "Winamp has received an unknown error from the Online Service."; +var errorTitle400 = "Bad Request"; +var errorCode400 = "HTTP 400 - Bad Request"; +var errorDescription400 = "The request to the Online Service has not been properly formatted, there is likely a syntax error in the URL or elsewhere in the request. This is most likely due to an error in the Online Services code."; +var errorTitle401 = "Request is Unauthorized"; +var errorCode401 = "HTTP 401 - Unauthorized"; +var errorDescription401 = "The Online Service has made a request that requires HTTP authentication, and the request was not authorized by the server."; +var errorTitle402 = "Payment Required"; +var errorCode402 = "HTTP 402 - Payment Required"; +var errorDescription402 = "The Online Service submitted a request that was not authorized, because payment is required."; +var errorTitle403 = "Access has been denied"; +var errorCode403 = "HTTP 403 - Forbidden"; +var errorDescription403 = "Winamp was able to connect to the server for this Online Service, however the service has returned an error indicating that you do not have access to the page. This may be caused by a problem with the webserver configuration or other problem with the Online Service."; +var errorTitle404 = "The page cannot be found"; +var errorCode404 = "HTTP 404 - File Not Found"; +var errorDescription404 = "Winamp was able to connect to the server for this Online Service, however the service has returned an error indicating that the page requested can not be found. This may be caused by a broken link, or other problem with the Online Service."; +var errorTitle405 = "The requested method is not allowed"; +var errorCode405 = "HTTP 405 - Method Not Allowed"; +var errorDescription405 = "The request method specified by the online service is not allowed by the server, this is likely due to a server misconfiguration, or an attempt by the online service to use a webservice in a way it does not allow"; +var errorTitle406 = "The response is not acceptable"; +var errorCode406 = "HTTP 406 - Not Acceptable"; +var errorDescription406 = "The Online Service has made a request to a webserver, and the webserver is not able to respond in a format that the request has stated to be acceptable."; +var errorTitle407 = "Proxy authentication is required"; +var errorCode407 = "HTTP 407 - Proxy Authentication Required"; +var errorDescription407 = "The Online Service has made a request to a proxy server, and the proxy server requires that the request be authenticated."; +var errorTitle408 = "The request had timed out"; +var errorCode408 = "HTTP 408 - Request Timeout"; +var errorDescription408 = "Winamp did not send a request issued by the Online Service within the length of time that the Online Service would wait for the request."; +var errorTitle409 = "A conflict has occurred"; +var errorCode409 = "HTTP 409 - Conflict"; +var errorDescription409 = "The Online Service has made a request to a server where a conflicting request has been made."; +var errorTitle410 = "The requested page is gone"; +var errorCode410 = "HTTP 410 - Gone"; +var errorDescription410 = "The page requested by the Online Service is gone. Permanently. No forwarding address is known"; +var errorTitle411 = "Request length must be specified"; +var errorCode411 = "HTTP 411 - Length Required"; +var errorDescription411 = "The Online Service has made a request to a server that requires that the request specify the length of the request, and the Online Service has not specified the length."; +var errorTitle413 = "The request is too large"; +var errorCode413 = "HTTP 413 - Request Entity Too Large"; +var errorDescription413 = "The Online Service has submitted a request to a webserver that has been refused because the request is too large."; +var errorTitle414 = "The request is too large"; +var errorCode414 = "HTTP 414 - Request-URI Too Long"; +var errorDescription414 = "The Online Service has made a request to a server that has been refused because the request URI is too long, this is likely due to an problem with the Online Service adding too many query parameters."; +var errorTitle415 = "The media type is not supported"; +var errorCode415 = "HTTP 415 - Unsupported Media Type"; +var errorDescription415 = "The Online Service has made a request to a resource on a server that is being refused because the request is not in a format that is supported for the request method being used."; +var errorTitle500 = "An internal server error has occured"; +var errorCode500 = "HTTP 500 - Internal Server Error"; +var errorDescription500 = "The Online Service has made a request to a server that has encountered an error preventing the completion of the response."; +var errorTitle501 = "Method not implemented"; +var errorCode501 = "HTTP 501 - Not Implemented"; +var errorDescription501 = "The Online Service has made a request to a server using a request method that the server does not support."; +var errorTitle502 = "Bad response from proxy"; +var errorCode502 = "HTTP 502 - Bad Gateway"; +var errorDescription502 = "The Online Service has made a request to a server acting as a proxy or a gateway. The server has not received a valid response."; +var errorTitle503 = "The service is currently unavailable"; +var errorCode503 = "HTTP 503 - Service Unavailable"; +var errorDescription503 = "The Online Service has made a request to a server that is currently unable to service the request. This may be temporary due to the server current load."; +var errorTitle504 = "The proxy has timed out."; +var errorCode504 = "HTTP 504 - Gateway Timeout"; +var errorDescription504 = "The Online Service has made a request to a server acting as a proxy, and this server has not received a timely response."; +var errorTitle505 = "The HTTP version is not supported"; +var errorCode505 = "HTTP 505 - HTTP Version Not Supported"; +var errorDescription505 = "Winamp has made a request to the Online Service in an HTTP version not supported by the Online Service. This is either a server configuration problem with the Online Service, or you may need to change your browser's HTTP protocol settings."; + +var errorDnsDescription = "The request for the Online Service has returned a resource not found error from your browser, please ensure that you are connected to the Internet."; + +var errorTitle800c0005 = "The server or proxy was not found."; +var errorCode800c0005 = "Resource Not Found"; +var errorDescription800c0005 = "The request for the Online Service has returned a resource not found error from your browser, please ensure that you are connected to the Internet."; +var errorTitle800c000f = "Unable to load data from the server."; +var errorCode800c000f = "Cannot Load Data"; +var errorDescription800c000f = errorDnsDescription; +var errorTitle800c0002 = "The URL could not be parsed."; +var errorCode800c0002 = "Invalid URL"; +var errorDescription800c0002 = errorDnsDescription; +var errorTitle800c0003 = "No Internet session was established."; +var errorCode800c0003 = "No Session Found"; +var errorDescription800c0003 = errorDnsDescription; +var errorTitle800c0004 = "The attempt to connect to the Internet has failed."; +var errorCode800c0004 = "Unable To Connect"; +var errorDescription800c0004 = errorDnsDescription; +var errorTitle800c0006 = "Requested object was not found."; +var errorCode800c0006 = "Object Not Found"; +var errorDescription800c0006 = errorDnsDescription; +var errorTitle800c0007 = "Requested data is not available."; +var errorCode800c0007 = "Data Not Available"; +var errorDescription800c0007 = errorDnsDescription; +var errorTitle800c0008 = "The download has failed (the connection was interrupted)."; +var errorCode800c0008 = "Download Failed"; +var errorDescription800c0008 = errorDnsDescription; +var errorTitle800c0009 = "Authentication is needed to access the object."; +var errorCode800c0009 = "Authentication Required"; +var errorDescription800c0009 = errorDnsDescription; +var errorTitle800c000a = "Required media not available or valid."; +var errorCode800c000a = "No Valid Media"; +var errorDescription800c000a = errorDnsDescription; +var errorTitle800c000b = "The Internet connection has timed out."; +var errorCode800c000b = "Connection Timeout"; +var errorDescription800c000b = errorDnsDescription; +var errorTitle800c000c = "Request is invalid."; +var errorCode800c000c = "Invalid Request"; +var errorDescription800c000c = errorDnsDescription; +var errorTitle800c000d = "Protocol is not recognized."; +var errorCode800c000d = "Unknown Protocol"; +var errorDescription800c000d = errorDnsDescription; +var errorTitle800c000e = "Navigation request has encountered a security issue."; +var errorCode800c000e = "Security Problem"; +var errorDescription800c000e = errorDnsDescription; +var errorTitle800c0010 = "Unable to create an instance of the object."; +var errorCode800c0010 = "Cannot Instantiate Object"; +var errorDescription800c0010 = errorDnsDescription; +var errorTitle800c0014 = "Attempt to redirect the navigation failed."; +var errorCode800c0014 = "Redirect Failed"; +var errorDescription800c0014 = errorDnsDescription; +var errorTitle800c0015 = "The request is being redirected to a directory."; +var errorCode800c0015 = "Redirect To Directory"; +var errorDescription800c0015 = errorDnsDescription; +var errorTitle800c0016 = "The requested resource could not be locked."; +var errorCode800c0016 = "Cannot Lock Request"; +var errorDescription800c0016 = errorDnsDescription; +var errorTitle800c0017 = "Reissue request with extended binding."; +var errorCode800c0017 = "Use Extend Binding"; +var errorDescription800c0017 = errorDnsDescription; +var errorTitle800c0018 = "Binding was terminated."; +var errorCode800c0018 = "Terminated Bind"; +var errorDescription800c0018 = errorDnsDescription; +var errorTitle800c0100 = "The component download was declined by the user."; +var errorCode800c0100 = "Download Declined"; +var errorDescription800c0100 = errorDnsDescription; +var errorTitle800c0200 = "Result is dispatched."; +var errorCode800c0200 = "Result Dispatched"; +var errorDescription800c0200 = errorDnsDescription; +var errorTitle800c0300 = "Cannot replace a protected System File Protection (SFP) file."; +var errorCode800c0300 = "Cannot Replace SFP File "; +var errorDescription800c0300 = errorDnsDescription;
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/httpError.htm b/Src/Components/wac_network/resources/pages/httpError.htm new file mode 100644 index 00000000..f89a1927 --- /dev/null +++ b/Src/Components/wac_network/resources/pages/httpError.htm @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>Winamp Online Services Error Page</title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + <meta http-equiv="Content-Style-Type" content="text/css" /> + <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/> + <script src="./errorPageStrings.js"></script> + <script src="./errorPageFunctions.js"></script> +</head> +<body> +<!-- Container --> +<div id="errorContainer"> + <!-- Icon --> + <div id="errorIcon"></div> + <!-- Error Body --> + <div id="errorBody"> + <!-- Error Title --> + <div id="errorTitle"><h1 id="errorTitleText"><noscript>An Error Has Occurred</noscript></h1></div> + <!-- Error Code --> + <div id="errorCode"><noscript>HTTP - Error</noscript></div> + <!-- Error Description --> + <div id="errorDesc"><p id="errorDescText"><noscript>An error has occurred. We would show you more but your browser does not support javascript.</noscript></p></div> + <!-- Error Options --> + <div id="errorTryAgain"><a href="javascript:tryagain();">Try Again</a></div> + <div id="errorMore"><a href="javascript:togglemore();">More</a></div> + <!-- Additional Info --> + <div id="errorMoreInfo"> + <table> + <tr><td nowrap>Service name:</td><td><script language=javascript>document.write(unescape(geturlparams('servicename')));</script></td></tr> + <tr><td nowrap>Error code:</td><td><script language=javascript>document.write(geturlparams('errorcode'));</script></td></tr> + <tr><td nowrap>Url:</td><td><script language=javascript>document.write(unescape(geturlparams('url')));</script></td></tr> + <tr><td nowrap>Service id:</td><td><script language=javascript>document.write(geturlparams('svcid'));</script></td></tr> + <tr><td nowrap>Client id:</td><td><script language=javascript>document.write(geturlparams('uniqueid'));</script></td></tr> + </table> + </div> + </div> +</div> +<script language=javascript> +window.onload = function(){populatepage();}; +</script> +</body> +</html>
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/inetDisabled.htm b/Src/Components/wac_network/resources/pages/inetDisabled.htm new file mode 100644 index 00000000..70e20f59 --- /dev/null +++ b/Src/Components/wac_network/resources/pages/inetDisabled.htm @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>Winamp Online Services Error Page</title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + <meta http-equiv="Content-Style-Type" content="text/css" /> + <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/> +</head> +<body> +<!-- Container --> +<div id="errorContainer"> + <!-- Icon --> + <div id="errorIcon"></div> + <!-- Error Body --> + <div id="errorBody"> + <!-- Error Title --> + <div id="errorTitle"><h1 id="errorTitleText">Internet Access Is Currently Disabled</h1></div> + <!-- Error Code --> + <div id="errorCode"><noscript>Internet Access Is Currently Disabled</noscript></div> + <!-- Error Description --> + <div id="errorDesc"><p id="errorDescText">Winamp has been configured to not access the internet which is why you are seeing this page.<br><br>If this is not intended or you would like to re-enable Winamp's internet access, this can be done by going to <b>Preferences</b> -> <b>General Preferences</b> -> Change '<b>Internet Connection Settings</b>' to a setting other than '<b>Not connected to the internet</b>' and then refresh this page.</p></div> + </div> +</div> +</body> +</html>
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/navCancel.htm b/Src/Components/wac_network/resources/pages/navCancel.htm new file mode 100644 index 00000000..2c81143f --- /dev/null +++ b/Src/Components/wac_network/resources/pages/navCancel.htm @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>Winamp Online Services Error Page</title> + <meta http-equiv="content-type" content="text/html;charset=utf-8" /> + <meta http-equiv="Content-Style-Type" content="text/css" /> + <link rel="stylesheet" href="./winampError.css" type="text/css" media="all"/> +</head> +<body> +<!-- Container --> +<div id="errorContainer"> + <!-- Icon --> + <div id="errorIcon"></div> + <!-- Error Body --> + <div id="errorBody"> + <!-- Error Title --> + <div id="errorTitle"><h1 id="errorTitleText">Action Cancelled</h1></div> + <!-- Error Code --> + <div id="errorCode"><noscript>Action Cancelled</noscript></div> + <!-- Error Description --> + <div id="errorDesc"><p id="errorDescText">Navigation to the page has been cancelled.</p></div> + </div> +</div> +</body> +</html>
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/pages/winampError.css b/Src/Components/wac_network/resources/pages/winampError.css new file mode 100644 index 00000000..0bf0dbae --- /dev/null +++ b/Src/Components/wac_network/resources/pages/winampError.css @@ -0,0 +1,64 @@ +a { + text-decoration: none; +} +body { + font: message-box; +} +h1 { + font-size: 150%; +} +#errorContainer { + position: relative; + margin: 1.6em auto; + max-width: 42em; + min-width: 34em; + left: 15px; + width:70%; + _width: 420px; +} +#errorBody { + position:relative; +} +#errorIcon { + position:relative; + top: 53px; + left: -56px; + height:39px; + width:40px; + background-image:url(./errorIcon.png); + _background-image: none; +} +#errorTitleText { + position:relative; + top: 10px; +} +#errorTitle { + position: relative; + text-align: left; + display:inline-block; + border-bottom: ridge 1px; +} +#errorCode { + position: relative; + text-align:right; + margin-bottom: -.5em; +} +#errorDesc { + position: relative; + margin-bottom: -.5em; +} +#errorTryAgain { + position: relative; + text-align: left; + top: 1.2em; +} +#errorMore { + position: relative; + text-align:right; + border-bottom: ridge 1px; + padding-bottom: .2em; +} +#errorMoreInfo { + position:relative; + display: none; +}
\ No newline at end of file diff --git a/Src/Components/wac_network/resources/serviceIcon.png b/Src/Components/wac_network/resources/serviceIcon.png Binary files differnew file mode 100644 index 00000000..b644c91c --- /dev/null +++ b/Src/Components/wac_network/resources/serviceIcon.png diff --git a/Src/Components/wac_network/resources/toolbarAddress.png b/Src/Components/wac_network/resources/toolbarAddress.png Binary files differnew file mode 100644 index 00000000..94b55912 --- /dev/null +++ b/Src/Components/wac_network/resources/toolbarAddress.png diff --git a/Src/Components/wac_network/resources/toolbarLarge.png b/Src/Components/wac_network/resources/toolbarLarge.png Binary files differnew file mode 100644 index 00000000..cf4c8abc --- /dev/null +++ b/Src/Components/wac_network/resources/toolbarLarge.png diff --git a/Src/Components/wac_network/resources/toolbarProgress.png b/Src/Components/wac_network/resources/toolbarProgress.png Binary files differnew file mode 100644 index 00000000..c252e884 --- /dev/null +++ b/Src/Components/wac_network/resources/toolbarProgress.png diff --git a/Src/Components/wac_network/util.cpp b/Src/Components/wac_network/util.cpp new file mode 100644 index 00000000..77493cf8 --- /dev/null +++ b/Src/Components/wac_network/util.cpp @@ -0,0 +1,211 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: util.cpp - JNL implementation of basic network utilities +** License: see jnetlib.h +*/ + +#include "netinc.h" +#include "util.h" +#include "foundation\error.h" + +#ifdef USE_SSL +#include "wac_network_ssl_connection.h" + +#ifdef _WIN32 +#include <wincrypt.h> +#endif // !_WIN32 + +#include <openssl/rand.h> + +#ifdef _WIN32 +static HCRYPTPROV GetKeySet() +{ + HCRYPTPROV hCryptProv; + LPCWSTR UserName = L"WinampKeyContainer"; // name of the key container + + if ( CryptAcquireContext( + &hCryptProv, // handle to the CSP + UserName, // container name + NULL, // use the default provider + PROV_RSA_FULL, // provider type + 0 ) ) // flag values + { + return hCryptProv; + } + else if ( CryptAcquireContext( + &hCryptProv, + UserName, + NULL, + PROV_RSA_FULL, + CRYPT_NEWKEYSET ) ) + { + return hCryptProv; + } + else + return 0; +} +#endif + +static void InitSSL() +{ + SSL_load_error_strings(); + SSL_library_init(); + +#ifdef _WIN32 + HCRYPTPROV hCryptProv = GetKeySet(); + if ( hCryptProv ) + { + BYTE pbData[ 8 * sizeof( unsigned long ) ] = { 0 }; + if ( CryptGenRandom( hCryptProv, 8 * sizeof( unsigned long ), pbData ) ) + { + RAND_seed( pbData, 16 ); + } + CryptReleaseContext( hCryptProv, 0 ); + } +#endif + + // sslContext = SSL_CTX_new(SSLv23_client_method()); + // SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); + + // SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF); +} +static int open_ssl_initted = 0; +#endif + +static int was_initted = 0; + +int JNL::open_socketlib() +{ +#ifdef _WIN32 + if ( !was_initted ) + { + WSADATA wsaData = { 0 }; + if ( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) ) + { + return NErr_Error; + } + } +#endif // !_WIN32 + +#ifdef USE_SSL + if ( !open_ssl_initted ) + { + InitSSL(); + open_ssl_initted = 1; + } +#endif // !USE_SSL + + return NErr_Success; +} + +void JNL::close_socketlib() +{ +#ifdef _WIN32 + if ( was_initted ) + { + WSACleanup(); + } +#ifdef USE_SSL + // TODO need to do some reference counting to free this correctly + //SSL_CTX_free(sslContext); +#endif // !USE_SSL +#endif // !_WIN32 +} + +static char *jnl_strndup( const char *str, size_t n ) +{ + char *o = (char *)calloc( n + 1, sizeof( char ) ); + if ( !o ) + return 0; + + strncpy( o, str, n ); + o[ n ] = 0; + + return o; +} + +int JNL::parse_url( const char *url, char **prot, char **host, unsigned short *port, char **req, char **lp ) +{ + free( *prot ); *prot = 0; + free( *host ); *host = 0; + free( *req ); *req = 0; + free( *lp ); *lp = 0; + *port = 0; + + const char *p; + const char *protocol = strstr( url, "://" ); + if ( protocol ) + { + *prot = jnl_strndup( url, protocol - url ); + p = protocol + 3; + } + else + { + p = url; + } + + while ( p && *p && *p == '/' ) p++; // skip extra / + + size_t end = strcspn( p, "@/" ); + + // check for username + if ( p[ end ] == '@' ) + { + *lp = jnl_strndup( p, end ); + p = p + end + 1; + end = strcspn( p, "[:/" ); + } + + if ( p[ 0 ] == '[' ) // IPv6 style address + { + p++; + const char *ipv6_end = strchr( p, ']' ); + if ( !ipv6_end ) + return NErr_Malformed; + + *host = jnl_strndup( p, ipv6_end - p ); + p = ipv6_end + 1; + } + else + { + end = strcspn( p, ":/" ); + *host = jnl_strndup( p, end ); + p += end; + } + + // is there a port number? + if ( p[ 0 ] == ':' ) + { + char *new_end; + *port = (unsigned short)strtoul( p + 1, &new_end, 10 ); + p = new_end; + } + + if ( p[ 0 ] ) + { + // benski> this is here to workaround a bug with YP and NSV streams + if ( !strcmp( p, ";stream.nsv" ) ) + return NErr_Success; + + *req = _strdup( p ); + } + + return NErr_Success; +} + + +#if 0 +unsigned long JNL::ipstr_to_addr( const char *cp ) +{ + return inet_addr( cp ); +} + +void JNL::addr_to_ipstr( unsigned long addr, char *host, int maxhostlen ) +{ + in_addr a; a.s_addr = addr; + sprintf( host, /*maxhostlen,*/ "%u.%u.%u.%u", a.S_un.S_un_b.s_b1, a.S_un.S_un_b.s_b2, a.S_un.S_un_b.s_b3, a.S_un.S_un_b.s_b4 ); + //char *p=::inet_ntoa(a); strncpy(host,p?p:"",maxhostlen); +} +#endif
\ No newline at end of file diff --git a/Src/Components/wac_network/util.h b/Src/Components/wac_network/util.h new file mode 100644 index 00000000..6fe3c496 --- /dev/null +++ b/Src/Components/wac_network/util.h @@ -0,0 +1,42 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: util.h - JNL interface for basic network utilities +** License: see jnetlib.h +** +** routines you may be interested in: +** JNL::open_socketlib(); +** opens the socket library. Call this once before using any network +** code. If you create a new thread, call this again. Only really an +** issue for Win32 support, but use it anyway for portability/ +** +** JNL::close_Socketlib(); +** closes the socketlib. Call this when you're done with the network, +** after all your JNetLib objects have been destroyed. +** +** unsigned long JNL::ipstr_to_addr(const char *cp); +** gives you the integer representation of a ip address in dotted +** decimal form. +** +** JNL::addr_to_ipstr(unsigned long addr, char *host, int maxhostlen); +** gives you the dotted decimal notation of an integer ip address. +** +*/ + +#ifndef NULLSOFT_WAC_NETWORK_UTIL_H +#define NULLSOFT_WAC_NETWORK_UTIL_H + +class JNL +{ + public: + static int open_socketlib(); + static void close_socketlib(); + + static unsigned long ipstr_to_addr( const char *cp ); + static void addr_to_ipstr( unsigned long addr, char *host, int maxhostlen ); + + static int parse_url( const char *url, char **prot, char **host, unsigned short *port, char **req, char **lp ); +}; + +#endif //!NULLSOFT_WAC_NETWORK_UTIL_H diff --git a/Src/Components/wac_network/version.rc2 b/Src/Components/wac_network/version.rc2 new file mode 100644 index 00000000..b813f83c --- /dev/null +++ b/Src/Components/wac_network/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,0,0 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp 5.x System Component" + VALUE "FileVersion", STR_WINAMP_PRODUCTVER + VALUE "InternalName", "wac_network.w5s" + VALUE "LegalCopyright", "Copyright © 2007-2022 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "wac_network.w5s" + VALUE "ProductName", "Winamp Network Service" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Components/wac_network/wac_network.h b/Src/Components/wac_network/wac_network.h new file mode 100644 index 00000000..71feb369 --- /dev/null +++ b/Src/Components/wac_network/wac_network.h @@ -0,0 +1,48 @@ +/* +** JNetLib +** Copyright (C) 2000-2006 Nullsoft, Inc. +** Author: Justin Frankel +** File: jnetlib.h - JNL main include file (not really necessary). +** +** For documentation, look at the following files: +** Generic network initialization: netinc.h +** DNS: asyncdns.h +** TCP connections: connection.h +** HTTP GET connections: wac_network_http_receiver.h +** TCP listen: wac_network_web_server_listen.h +** +** license: +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#ifndef NULLSOFT_WAC_NETWORK_H +#define NULLSOFT_WAC_NETWORK_H + +#include "netinc.h" +#include "util.h" + +#include <time.h> + +#include "wac_network_dns.h" +#include "wac_network_connection.h" +#include "wac_network_http_receiver.h" +#include "wac_network_http_server.h" +#include "wac_network_web_server_listen.h" + +#endif //!NULLSOFT_WAC_NETWORK_H diff --git a/Src/Components/wac_network/wac_network.rc b/Src/Components/wac_network/wac_network.rc new file mode 100644 index 00000000..fcff7711 --- /dev/null +++ b/Src/Components/wac_network/wac_network.rc @@ -0,0 +1,76 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Components/wac_network/wac_network.vcxproj b/Src/Components/wac_network/wac_network.vcxproj new file mode 100644 index 00000000..53ca29d5 --- /dev/null +++ b/Src/Components/wac_network/wac_network.vcxproj @@ -0,0 +1,387 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{2C4D81A7-D8C3-4D7B-8DA1-1522C73EF9F3}</ProjectGuid> + <Keyword>QtVS_v304</Keyword> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0.19041.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">10.0.19041.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0.19041.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)'=='Release|x64'">10.0.19041.0</WindowsTargetPlatformVersion> + <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + <WholeProgramOptimization>true</WholeProgramOptimization> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')"> + <Import Project="$(QtMsBuild)\qt_defaults.props" /> + </ImportGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;widgets;concurrent</QtModules> + <QtBuildConfig>debug</QtBuildConfig> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;widgets;concurrent;webview</QtModules> + <QtBuildConfig>debug</QtBuildConfig> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;widgets;concurrent</QtModules> + <QtBuildConfig>release</QtBuildConfig> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;widgets;concurrent;webview</QtModules> + <QtBuildConfig>release</QtBuildConfig> + </PropertyGroup> + <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')"> + <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." /> + </Target> + <ImportGroup Label="ExtensionSettings" /> + <ImportGroup Label="Shared" /> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'"> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <StringPooling>true</StringPooling> + <FunctionLevelLinking> + </FunctionLevelLinking> + <DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies> + <OptimizeReferences> + </OptimizeReferences> + <EnableCOMDATFolding> + </EnableCOMDATFolding> + <IgnoreAllDefaultLibraries> + </IgnoreAllDefaultLibraries> + <LinkTimeCodeGeneration> + </LinkTimeCodeGeneration> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <StringPooling>true</StringPooling> + <FunctionLevelLinking> + </FunctionLevelLinking> + <DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + <OptimizeReferences>true</OptimizeReferences> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <SupportJustMyCode>false</SupportJustMyCode> + <DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <SupportJustMyCode>false</SupportJustMyCode> + <DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Vcpkg"> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir /> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Vcpkg"> + <VcpkgUseStatic>false</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir /> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnabled>true</VcpkgEnabled> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAC_NETWORK_LIB;USE_SSL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WAC_NETWORK_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>None</DebugInformationFormat> + <Optimization>MinSpace</Optimization> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_SSL;WAC_NETWORK_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>false</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>None</DebugInformationFormat> + <Optimization>MinSpace</Optimization> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WAC_NETWORK_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>false</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\nu\RingBuffer.cpp" /> + <ClCompile Include="wac_network_connection_api.cpp" /> + <ClCompile Include="wac_network_dns_api.cpp" /> + <ClCompile Include="wac_network_http_receiver_api.cpp" /> + <ClCompile Include="wac_network_http_server_api.cpp" /> + <ClCompile Include="wac_network_onconncb_api.cpp" /> + <ClCompile Include="wac_network_page_generator_api.cpp" /> + <ClCompile Include="wac_network_web_server_api.cpp" /> + <ClCompile Include="wac_network_dns.cpp" /> + <ClCompile Include="wac_network_connection.cpp" /> + <ClCompile Include="Headers.cpp" /> + <ClCompile Include="wac_network_http_receiver.cpp" /> + <ClCompile Include="wac_network_http_server.cpp" /> + <ClCompile Include="wac_network_web_server_listen.cpp" /> + <ClCompile Include="wac_network_ssl_connection.cpp" /> + <ClCompile Include="util.cpp" /> + <ClCompile Include="wac_network_dns_factory.cpp" /> + <ClCompile Include="wac_network_http_receiver_factory.cpp" /> + <ClCompile Include="wac_network_http_server_factory.cpp" /> + <ClCompile Include="wac_network_ssl_connection_factory.cpp" /> + <ClCompile Include="wac_network_web_server_factory.cpp" /> + <ClCompile Include="wac_network_web_server.cpp" /> + <ClInclude Include="wac_network_connection_api.h" /> + <ClInclude Include="wac_network_dns_api.h" /> + <ClInclude Include="wac_network_http_receiver_api.h" /> + <ClInclude Include="wac_network_http_server_api.h" /> + <ClInclude Include="wac_network_onconncb_api.h" /> + <ClInclude Include="wac_network_page_generator_api.h" /> + <ClInclude Include="wac_network_web_server_api.h" /> + <ClInclude Include="api__wac_network.h" /> + <ClInclude Include="wac_network_dns.h" /> + <ClInclude Include="wac_network_connection.h" /> + <ClInclude Include="Headers.h" /> + <ClInclude Include="wac_network_http_receiver.h" /> + <ClInclude Include="wac_network_http_server.h" /> + <ClInclude Include="wac_network_web_server_listen.h" /> + <ClInclude Include="netinc.h" /> + <ClInclude Include="ServiceBuild.h" /> + <ClInclude Include="wac_network_ssl_connection.h" /> + <ClInclude Include="util.h" /> + <ClInclude Include="wac_network.h" /> + <ClInclude Include="wac_network_connection_factory.h" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="wac_network_global.h" /> + <ClInclude Include="main.h" /> + <ClCompile Include="wac_network_connection_factory.cpp" /> + <ClCompile Include="main.cpp" /> + <ClInclude Include="wac_network_dns_factory.h" /> + <ClInclude Include="wac_network_http_receiver_factory.h" /> + <ClInclude Include="wac_network_http_server_factory.h" /> + <ClInclude Include="wac_network_ssl_connection_factory.h" /> + <ClInclude Include="wac_network_web_server_factory.h" /> + <ClInclude Include="wac_network_web_server.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="wac_network.rc" /> + </ItemGroup> + <ItemGroup> + <None Include="version.rc2" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"> + <Import Project="$(QtMsBuild)\qt.targets" /> + </ImportGroup> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network.vcxproj.filters b/Src/Components/wac_network/wac_network.vcxproj.filters new file mode 100644 index 00000000..edb1d2a4 --- /dev/null +++ b/Src/Components/wac_network/wac_network.vcxproj.filters @@ -0,0 +1,251 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Form Files"> + <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier> + <Extensions>ui</Extensions> + </Filter> + <Filter Include="WAC_Network objects"> + <UniqueIdentifier>{7c3b93ee-aa47-40c6-95ad-e4afcd39d3d4}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Connection"> + <UniqueIdentifier>{ca35cd6a-dc64-43ca-bfee-ad2cf0120441}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\DNS"> + <UniqueIdentifier>{4deadf48-881f-4f00-b669-a3a077876b55}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Receiver"> + <UniqueIdentifier>{15fc15ab-935f-48bc-9189-e91b505ea9a9}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Server"> + <UniqueIdentifier>{f25ad28a-4456-4d23-af2b-4adc9024d51e}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\UDPConnection"> + <UniqueIdentifier>{f7113691-5b0b-4dcb-9dea-886d6d190881}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Web Server"> + <UniqueIdentifier>{ff90b68d-efba-4f10-93f2-fb80e6914598}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Connection\Header Files"> + <UniqueIdentifier>{06efca75-980f-4e94-8167-eac0bee8e4da}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Connection\Source Files"> + <UniqueIdentifier>{c673ac45-6d54-4f49-b929-e1711381f80a}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\DNS\Header Files"> + <UniqueIdentifier>{05d9e8c6-75cb-4bad-a57e-201b1e3e9395}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\DNS\Source Files"> + <UniqueIdentifier>{2540b583-f949-45cc-b16d-a8503f68c9e6}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Receiver\Header Files"> + <UniqueIdentifier>{c2f99250-dce7-46e2-a6b7-764c7f91bafb}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Receiver\Source Files"> + <UniqueIdentifier>{13edb61c-1a45-465b-9e15-38a239e1856b}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Server\Header Files"> + <UniqueIdentifier>{8ff797fd-bd42-4adc-8085-e0fce9da0a1d}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\HTTP Server\Source Files"> + <UniqueIdentifier>{9e55efae-2529-4cdf-8e6d-c54beef6e110}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Web Server\Header Files"> + <UniqueIdentifier>{ad2b1c56-21b5-4706-933b-cd844db4c03f}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\Web Server\Source Files"> + <UniqueIdentifier>{dd64aa09-a6f6-4d61-a51d-e3b8377bf6be}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\UDPConnection\Header Files"> + <UniqueIdentifier>{494d20c6-2df8-4b83-8eb0-59973bf83d9e}</UniqueIdentifier> + </Filter> + <Filter Include="WAC_Network objects\UDPConnection\Source Files"> + <UniqueIdentifier>{26d1af8a-8e2c-4778-9dc1-319e662a4d0f}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_global.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClCompile Include="util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Headers.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\..\nu\RingBuffer.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_connection_factory.cpp"> + <Filter>WAC_Network objects\Connection\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_ssl_connection_factory.cpp"> + <Filter>WAC_Network objects\Connection\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_connection.cpp"> + <Filter>WAC_Network objects\Connection\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_ssl_connection.cpp"> + <Filter>WAC_Network objects\Connection\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_connection_api.cpp"> + <Filter>WAC_Network objects\Connection\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_dns_factory.cpp"> + <Filter>WAC_Network objects\DNS\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_dns.cpp"> + <Filter>WAC_Network objects\DNS\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_dns_api.cpp"> + <Filter>WAC_Network objects\DNS\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_receiver_factory.cpp"> + <Filter>WAC_Network objects\HTTP Receiver\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_receiver.cpp"> + <Filter>WAC_Network objects\HTTP Receiver\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_receiver_api.cpp"> + <Filter>WAC_Network objects\HTTP Receiver\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_server_factory.cpp"> + <Filter>WAC_Network objects\HTTP Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_server.cpp"> + <Filter>WAC_Network objects\HTTP Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_http_server_api.cpp"> + <Filter>WAC_Network objects\HTTP Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_web_server_factory.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_web_server_listen.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_web_server.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_onconncb_api.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_page_generator_api.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + <ClCompile Include="wac_network_web_server_api.cpp"> + <Filter>WAC_Network objects\Web Server\Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ServiceBuild.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="api__wac_network.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="util.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="netinc.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Headers.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_ssl_connection_factory.h"> + <Filter>WAC_Network objects\Connection\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_connection_factory.h"> + <Filter>WAC_Network objects\Connection\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_connection.h"> + <Filter>WAC_Network objects\Connection\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_ssl_connection.h"> + <Filter>WAC_Network objects\Connection\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_connection_api.h"> + <Filter>WAC_Network objects\Connection\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_dns_factory.h"> + <Filter>WAC_Network objects\DNS\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_dns.h"> + <Filter>WAC_Network objects\DNS\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_dns_api.h"> + <Filter>WAC_Network objects\DNS\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_receiver_factory.h"> + <Filter>WAC_Network objects\HTTP Receiver\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_receiver_api.h"> + <Filter>WAC_Network objects\HTTP Receiver\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_server_factory.h"> + <Filter>WAC_Network objects\HTTP Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_server.h"> + <Filter>WAC_Network objects\HTTP Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_server_api.h"> + <Filter>WAC_Network objects\HTTP Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_web_server_factory.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_web_server_listen.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_web_server.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_onconncb_api.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_page_generator_api.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_web_server_api.h"> + <Filter>WAC_Network objects\Web Server\Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_network_http_receiver.h"> + <Filter>WAC_Network objects\HTTP Receiver\Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="wac_network.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <None Include="version.rc2"> + <Filter>Resource Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_connection.cpp b/Src/Components/wac_network/wac_network_connection.cpp new file mode 100644 index 00000000..fd4559f2 --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection.cpp @@ -0,0 +1,561 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: connection.cpp - JNL TCP connection implementation +** License: see jnetlib.h +*/ + +#include "netinc.h" +#include "util.h" + +#include "wac_network_connection.h" +#include "wac_network_dns.h" + +#include "foundation\error.h" + +#include "../nu/strsafe.h" +#pragma intrinsic(memcpy, memset) + +WAC_Network_Connection::WAC_Network_Connection() +{ + init(); +} + +WAC_Network_Connection::WAC_Network_Connection( api_dns *dns, size_t sendbufsize, size_t recvbufsize ) +{ + init(); + open( dns, sendbufsize, recvbufsize ); +} + + +void WAC_Network_Connection::init() +{ + m_errorstr = 0; + address = 0; + m_dns = NULL; + m_dns_owned = false; + m_socket = -1; + m_remote_port = 0; + m_state = STATE_NOCONNECTION; + m_host[ 0 ] = 0; + saddr = 0; +} + +WAC_Network_Connection::~WAC_Network_Connection() +{ + /* + ** Joshua Teitelbaum 1/27/2006 + ** virtualization for ssl, calling socket_shtudown() + */ + socket_shutdown(); + + if ( !saddr ) // free it if it was passed to us (by JNL_Listen, presumably) + free( address ); // TODO: change this if we ever do round-robin DNS connecting or in any way change how we handle 'address' + + if ( m_dns_owned ) + delete static_cast<wa::Components::WAC_Network_AsyncDNS *>( m_dns ); +} + +void WAC_Network_Connection::set_dns( api_dns *dns ) +{ + if ( m_dns_owned ) + delete static_cast<wa::Components::WAC_Network_AsyncDNS *>( m_dns ); + + m_dns = dns; + m_dns_owned = false; +} + +void WAC_Network_Connection::open( api_dns *dns, size_t sendbufsize, size_t recvbufsize ) +{ + if ( dns != API_DNS_AUTODNS && dns ) + { + m_dns = dns; + m_dns_owned = false; + } + else if ( !m_dns ) + { + m_dns = new wa::Components::WAC_Network_AsyncDNS; + m_dns_owned = true; + } + + recv_buffer.reserve( recvbufsize ); + send_buffer.reserve( sendbufsize ); +} + +void WAC_Network_Connection::connect( SOCKET s, sockaddr *addr, socklen_t length ) +{ + close( 1 ); + m_socket = s; + address = (sockaddr *)malloc( length ); + memcpy( address, addr, length ); + + m_remote_port = 0; + if ( m_socket != -1 ) + { + SET_SOCK_BLOCK( m_socket, 0 ); + m_state = STATE_CONNECTED; + } + else + { + m_errorstr = _strdup( "invalid socket passed to connect" ); + m_state = STATE_ERROR; + } + +} + +void WAC_Network_Connection::connect( const char *hostname, int port ) +{ + close( 1 ); + m_remote_port = (unsigned short)port; + +#ifdef _WIN32 + lstrcpynA( m_host, hostname, sizeof( m_host ) ); +#elif defined(__APPLE__) + strlcpy( m_host, hostname, sizeof( m_host ) ); +#else + strncpy( m_host, hostname, sizeof( m_host ) - 1 ); + m_host[ sizeof( m_host ) - 1 ] = 0; +#endif + + + //memset(&m_saddr,0,sizeof(m_saddr)); + if ( !m_host[ 0 ] ) + { + m_errorstr = _strdup( "empty hostname" ); + m_state = STATE_ERROR; + } + else + { + m_state = STATE_RESOLVING; + } +} + +/* +** Joshua Teitelbaum 1/27/2006 +** socket_shutdown +** virtualization for ssl +*/ +/* Virtual */ +void WAC_Network_Connection::socket_shutdown() +{ + if ( m_socket >= 0 ) + { + ::shutdown( m_socket, SHUT_RDWR ); + ::closesocket( m_socket ); + + m_socket = -1; + } +} +/* +** Joshua Teitelbaum 1/27/2006 +** socket_recv +** virtualization for ssl +*/ +/* Virtual */ +ssize_t WAC_Network_Connection::socket_recv( char *buf, size_t len, int options ) +{ + return ::recv( m_socket, buf, (int)len, options ); +} +/* +** Joshua Teitelbaum 1/27/2006 +** socket_send +** virtualization for ssl +*/ +/* Virtual */ +ssize_t WAC_Network_Connection::socket_send( const char *buf, size_t len, int options ) +{ + return ::send( m_socket, buf, (int)len, options ); +} + +int WAC_Network_Connection::socket_connect() +{ + return ::connect( m_socket, saddr->ai_addr, (int)saddr->ai_addrlen ); +} + +void WAC_Network_Connection::run( size_t max_send_bytes, size_t max_recv_bytes, size_t *bytes_sent, size_t *bytes_rcvd ) +{ + socklen_t socket_buffer_size = 0; + socklen_t socket_buffer_size_len = sizeof( socket_buffer_size ); + socklen_t send_buffer_size; + socklen_t recv_buffer_size; + + size_t bytes_allowed_to_send = ( max_send_bytes == (size_t)-1 ) ? send_buffer.size() : max_send_bytes; + size_t bytes_allowed_to_recv = ( max_recv_bytes == (size_t)-1 ) ? recv_buffer.avail() : max_recv_bytes; + + if ( bytes_sent ) + *bytes_sent = 0; + + if ( bytes_rcvd ) + *bytes_rcvd = 0; + + switch ( m_state ) + { + case STATE_RESOLVING: + if ( saddr == 0 ) + { + int a = m_dns->resolve( m_host, m_remote_port, &saddr, SOCK_STREAM ); + if ( !a ) + { + m_state = STATE_RESOLVED; + } + else if ( a == 1 ) + { + m_state = STATE_RESOLVING; + break; + } + else + { + m_errorstr = _strdup( "resolving hostname" ); + m_state = STATE_ERROR; + + return; + } + } + // fall through + case STATE_RESOLVED: + m_socket = ::socket( saddr->ai_family, saddr->ai_socktype, saddr->ai_protocol ); + if ( m_socket == -1 ) + { + m_errorstr = _strdup( "creating socket" ); + m_state = STATE_ERROR; + } + else + { + SET_SOCK_BLOCK( m_socket, 0 ); + } + + socket_buffer_size = 0; + socket_buffer_size_len = sizeof( socket_buffer_size ); + getsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char *)&socket_buffer_size, &socket_buffer_size_len ); + send_buffer_size = (int)( send_buffer.avail() + send_buffer.size() ); + if ( send_buffer_size > 65536 ) + send_buffer_size = 65536; + if ( socket_buffer_size < send_buffer_size ) + setsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char *)&send_buffer_size, sizeof( send_buffer_size ) ); + getsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char *)&socket_buffer_size, &socket_buffer_size_len ); + + getsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&socket_buffer_size, &socket_buffer_size_len ); + recv_buffer_size = (int)recv_buffer.avail(); + if ( recv_buffer_size > 65536 ) + recv_buffer_size = 65536; + if ( socket_buffer_size < recv_buffer_size ) + setsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&recv_buffer_size, sizeof( recv_buffer_size ) ); + getsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char *)&socket_buffer_size, &socket_buffer_size_len ); + + /* + ** Joshua Teitelbaum 1/27/2006 + ** virtualization for ssl + */ + if ( !socket_connect() ) + { + address = saddr->ai_addr; + m_state = STATE_CONNECTED; + + on_socket_connected(); + } + else if ( ERRNO != EINPROGRESS ) + { + m_errorstr = _strdup( "Connecting to host" ); + m_state = STATE_ERROR; + } + else + { + m_state = STATE_CONNECTING; + } + break; + case STATE_CONNECTING: + { + fd_set f[ 3 ]; + FD_ZERO( &f[ 0 ] ); + FD_ZERO( &f[ 1 ] ); + FD_ZERO( &f[ 2 ] ); + FD_SET( m_socket, &f[ 0 ] ); + FD_SET( m_socket, &f[ 1 ] ); + FD_SET( m_socket, &f[ 2 ] ); + struct timeval tv; + memset( &tv, 0, sizeof( tv ) ); + if ( select( (int)m_socket + 1, &f[ 0 ], &f[ 1 ], &f[ 2 ], &tv ) == -1 ) + { + m_errorstr = _strdup( "Connecting to host (calling select())" ); + m_state = STATE_ERROR; + } + else if ( FD_ISSET( m_socket, &f[ 1 ] ) ) + { + m_state = STATE_CONNECTED; + on_socket_connected(); + } + else if ( FD_ISSET( m_socket, &f[ 2 ] ) ) + { + m_errorstr = _strdup( "Connecting to host" ); + m_state = STATE_ERROR; + } + } + break; + case STATE_CONNECTED: + case STATE_CLOSING: + /* --- send --- */ + { + size_t sent = send_buffer.drain( this, bytes_allowed_to_send ); + if ( bytes_sent ) + *bytes_sent += sent; + + if ( m_state == STATE_CLOSED ) + break; + + /* --- receive --- */ + size_t received = recv_buffer.fill( this, bytes_allowed_to_recv ); + if ( bytes_rcvd ) + *bytes_rcvd += received; + } + + if ( m_state == STATE_CLOSING ) + { + if ( send_buffer.empty() ) m_state = STATE_CLOSED; + } + break; + default: + break; + } +} + +void WAC_Network_Connection::on_socket_connected( void ) +{ + return; +} + +void WAC_Network_Connection::close( int quick ) +{ + if ( quick || m_state == STATE_RESOLVING || m_state == STATE_CONNECTING ) + { + m_state = STATE_CLOSED; + /* + ** Joshua Teitelbaum 1/27/2006 + ** virualization for ssl + */ + socket_shutdown(); + + m_socket = -1; + + recv_buffer.clear(); + send_buffer.clear(); + + m_remote_port = 0; + m_host[ 0 ] = 0; + //memset(&m_saddr,0,sizeof(m_saddr)); + } + else + { + if ( m_state == STATE_CONNECTED ) + m_state = STATE_CLOSING; + } +} + +size_t WAC_Network_Connection::send_bytes_in_queue( void ) +{ + return send_buffer.size(); +} + +size_t WAC_Network_Connection::send_bytes_available( void ) +{ + return send_buffer.avail(); +} + +int WAC_Network_Connection::send( const void *data, size_t length ) +{ + if ( length > send_bytes_available() ) + return -1; + + send_buffer.write( data, length ); + return 0; +} + +int WAC_Network_Connection::send_string( const char *line ) +{ + return send( line, strlen( line ) ); +} + +size_t WAC_Network_Connection::recv_bytes_available( void ) +{ + return recv_buffer.size(); +} + +size_t WAC_Network_Connection::peek_bytes( void *data, size_t maxlength ) +{ + if ( data ) + return recv_buffer.peek( data, maxlength ); + else + return min( maxlength, recv_bytes_available() ); +} + +size_t WAC_Network_Connection::recv_bytes( void *data, size_t maxlength ) +{ + if ( data ) + return recv_buffer.read( data, maxlength ); + else + return recv_buffer.advance( maxlength ); +} + +int WAC_Network_Connection::recv_lines_available( void ) +{ + int l = (int)recv_bytes_available(); + int lcount = 0; + int lastch = 0; + + for ( int pos = 0; pos < l; pos++ ) + { + char t; + if ( recv_buffer.at( pos, &t, 1 ) != 1 ) + return lcount; + + if ( ( t == '\r' || t == '\n' ) && ( ( lastch != '\r' && lastch != '\n' ) || lastch == t ) ) + lcount++; + + lastch = t; + } + + return lcount; +} + +int WAC_Network_Connection::recv_line( char *line, size_t maxlength ) +{ + while ( maxlength-- ) + { + char t; + if ( recv_buffer.read( &t, 1 ) == 0 ) + { + *line = 0; + return 0; + } + + if ( t == '\r' || t == '\n' ) + { + char r; + if ( recv_buffer.peek( &r, 1 ) != 0 ) + { + if ( ( r == '\r' || r == '\n' ) && r != t ) + recv_buffer.advance( 1 ); + } + + *line = 0; + return 0; + + } + + *line++ = t; + } + + return 1; +} + +unsigned long WAC_Network_Connection::get_interface( void ) +{ + if ( m_socket == -1 ) + return 0; + + struct sockaddr_in sin; + memset( &sin, 0, sizeof( sin ) ); + socklen_t len = sizeof( sin ); + + if ( ::getsockname( m_socket, (struct sockaddr *)&sin, &len ) ) + return 0; + + return (unsigned long)sin.sin_addr.s_addr; +} + +unsigned long WAC_Network_Connection::get_remote() +{ + // TODO: IPv6 + if ( address ) + { + sockaddr_in *ipv4 = (sockaddr_in *)address; + return ipv4->sin_addr.s_addr; + } + + return 0; + +} + +unsigned short WAC_Network_Connection::get_remote_port() +{ + return m_remote_port; +} + +/* RingBuffer client function */ +size_t WAC_Network_Connection::Read( void *dest, size_t len ) +{ + if ( !len ) + return 0; + + int res = (int)socket_recv( (char *)dest, len, 0 ); + + if ( res == 0 || ( res < 0 && ERRNO != EWOULDBLOCK ) ) + { + m_state = STATE_CLOSED; + return 0; + } + + if ( res > 0 ) + return res; + else + return 0; +} + +/* RingBuffer client function */ +size_t WAC_Network_Connection::Write( const void *dest, size_t len ) +{ + if ( !len ) + return 0; + + int res = (int)socket_send( (const char *)dest, len, 0 ); + + if ( res == -1 && ERRNO != EWOULDBLOCK ) + { + return 0; + // m_state=STATE_CLOSED; + } + + if ( res > 0 ) + return res; + else + return 0; +} + +int WAC_Network_Connection::set_recv_buffer_size( size_t new_buffer_size ) +{ + return recv_buffer.expand( new_buffer_size ); +} + +void WAC_Network_Connection::reuse() +{ + if ( m_state == STATE_CLOSED ) + { + m_state = STATE_CONNECTED; + recv_buffer.clear(); + } +} + +#define CBCLASS WAC_Network_Connection +START_DISPATCH; +VCB( API_CONNECTION_OPEN, open ) +case API_CONNECTION_CONNECT: connect( *(char **)( params[ 0 ] ), *(int *)( params[ 1 ] ) ); return 1; +VCB( API_CONNECTION_RUN, run ) +CB( API_CONNECTION_GETSTATE, get_state ) +CB( API_CONNECTION_GETERROR, get_errstr ) +VCB( API_CONNECTION_CLOSE, close ) +VCB( API_CONNECTION_FLUSHSEND, flush_send ) +CB( API_CONNECTION_GETSENDBYTESINQUEUE, send_bytes_in_queue ) +CB( API_CONNECTION_GETSENDBYTESAVAILABLE, send_bytes_available ) +CB( API_CONNECTION_SEND, send ) +CB( API_CONNECTION_SENDBYTES, send_bytes ) +CB( API_CONNECTION_SENDSTRING, send_string ) +CB( API_CONNECTION_GETRECEIVEBYTESAVAILABLE, recv_bytes_available ) +CB( API_CONNECTION_RECEIVEBYTES, recv_bytes ) +CB( API_CONNECTION_GETRECEIVELINESAVAILABLE, recv_lines_available ) +CB( API_CONNECTION_RECEIVELINE, recv_line ) +CB( API_CONNECTION_PEEKBYTES, peek_bytes ) +CB( API_CONNECTION_GETINTERFACE, get_interface ) +CB( API_CONNECTION_GETREMOTEADDRESS, get_remote ) +CB( API_CONNECTION_GETREMOTEPORT, get_remote_port ) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_network/wac_network_connection.h b/Src/Components/wac_network/wac_network_connection.h new file mode 100644 index 00000000..85191eca --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection.h @@ -0,0 +1,182 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: connection.h - JNL TCP connection interface +** License: see jnetlib.h +** +** Usage: +** 1. Create a WAC_Network_Connection object, optionally specifying a wa::Components::WAC_Network_AsyncDNS +** object to use (or NULL for none, or WAC_NETWORK_CONNECTION_AUTODNS for auto), +** and the send and receive buffer sizes. +** 2. Call connect() to have it connect to a host/port (the hostname will be +** resolved if possible). +** 3. call run() with the maximum send/recv amounts, and optionally parameters +** so you can tell how much has been send/received. You want to do this a lot, while: +** 4. check get_state() to check the state of the connection. The states are: +** WAC_Network_Connection::STATE_ERROR +** - an error has occured on the connection. the connection has closed, +** and you can no longer write to the socket (there still might be +** data in the receive buffer - use recv_bytes_available()). +** WAC_Network_Connection::STATE_NOCONNECTION +** - no connection has been made yet. call connect() already! :) +** WAC_Network_Connection::STATE_RESOLVING +** - the connection is still waiting for a JNL_AsycnDNS to resolve the +** host. +** WAC_Network_Connection::STATE_CONNECTING +** - the asynchronous call to connect() is still running. +** WAC_Network_Connection::STATE_CONNECTED +** - the connection has connected, all is well. +** WAC_Network_Connection::STATE_CLOSING +** - the connection is closing. This happens after a call to close, +** without the quick parameter set. This means that the connection +** will close once the data in the send buffer is sent (data could +** still be being received when it would be closed). After it is +** closed, the state will transition to: +** WAC_Network_Connection::STATE_CLOSED +** - the connection has closed, generally without error. There still +** might be data in the receieve buffer, use recv_bytes_available(). +** 5. Use send() and send_string() to send data. You can use +** send_bytes_in_queue() to see how much has yet to go out, or +** send_bytes_available() to see how much you can write. If you use send() +** or send_string() and not enough room is available, both functions will +** return error ( < 0) +** 6. Use recv() and recv_line() to get data. If you want to see how much data +** there is, use recv_bytes_available() and recv_lines_available(). If you +** call recv() and not enough data is available, recv() will return how much +** data was actually read. See comments at the function defs. +** +** 7. To close, call close(1) for a quick close, or close() for a close that will +** make the socket close after sending all the data sent. +** +** 8. delete ye' ol' object. +*/ + +#ifndef NULLSOFT_WAC_NETWORK_CONNECTION_H +#define NULLSOFT_WAC_NETWORK_CONNECTION_H + +#include "netinc.h" + +#include "wac_network_dns.h" +#include "wac_network_dns_api.h" + +#include "wac_network_connection_api.h" + +#include "../nu/RingBuffer.h" + +#include <stddef.h> + +#if defined(_MSC_VER) && (_MSC_VER < 1200) +typedef int intptr_t; +#endif + +class WAC_Network_Connection : public api_connection, private Filler, private Drainer +{ +public: + typedef enum + { + STATE_ERROR = CONNECTION_STATE_ERROR, + STATE_NOCONNECTION = CONNECTION_STATE_NOCONNECTION, + STATE_RESOLVING = CONNECTION_STATE_RESOLVING, + STATE_CONNECTING = CONNECTION_STATE_CONNECTING, + STATE_CONNECTED = CONNECTION_STATE_CONNECTED, + STATE_CLOSING = CONNECTION_STATE_CLOSING, + STATE_CLOSED = CONNECTION_STATE_CLOSED, + STATE_RESOLVED = CONNECTION_STATE_RESOLVED, + } state; + + /* + ** Joshua Teitelbaum, 1/27/2006 adding virtual + */ + WAC_Network_Connection(); + WAC_Network_Connection( api_dns *dns, size_t sendbufsize, size_t recvbufsize ); + virtual ~WAC_Network_Connection(); + + void open( api_dns *dns = API_DNS_AUTODNS, size_t sendbufsize = 8192, size_t recvbufsize = 8192 ); + void connect( const char *hostname, int port ); + virtual void connect( SOCKET sock, sockaddr *addr, socklen_t length /* of addr */ ); // used by the listen object, usually not needed by users. + int set_recv_buffer_size( size_t new_buffer_size ); + /* + ** Joshua Teitelbaum 2/2/2006 + ** Need to make this virtual to ensure SSL can init properly + */ + virtual void run( size_t max_send_bytes = -1, size_t max_recv_bytes = -1, size_t *bytes_sent = NULL, size_t *bytes_rcvd = NULL ); + int get_state() + { + return m_state; + } + char *get_errstr() + { + return m_errorstr; + } + + void close( int quick = 0 ); + void flush_send( void ) + { + send_buffer.clear(); + } + + size_t send_bytes_in_queue( void ); + size_t send_bytes_available( void ); + int send( const void *data, size_t length ); // returns -1 if not enough room + inline int send_bytes( const void *data, size_t length ) + { + return send( data, length ); + } + int send_string( const char *line ); // returns -1 if not enough room + + size_t recv_bytes_available( void ); + size_t recv_bytes( void *data, size_t maxlength ); // returns actual bytes read + unsigned int recv_int( void ); + int recv_lines_available( void ); + int recv_line( char *line, size_t maxlength ); // returns 0 if the line was terminated with a \r or \n, 1 if not. + // (i.e. if you specify maxlength=10, and the line is 12 bytes long + // it will return 1. or if there is no \r or \n and that's all the data + // the connection has.) + size_t peek_bytes( void *data, size_t maxlength ); // returns bytes peeked + + unsigned long get_interface( void ); // this returns the interface the connection is on + unsigned long get_remote( void ); // remote host ip. + unsigned short get_remote_port( void ); // this returns the remote port of connection + void set_dns( api_dns *dns ); + void reuse(); + +protected: + SOCKET m_socket; + unsigned short m_remote_port; + + RingBuffer recv_buffer; + RingBuffer send_buffer; + + addrinfo *saddr; + sockaddr *address; + + char m_host[ 256 ]; + + api_dns *m_dns; + bool m_dns_owned; + + state m_state; + char *m_errorstr; + + /* + ** Joshua Teitelbaum 1/27/2006 Adding new BSD socket analogues for SSL compatibility + */ + virtual void socket_shutdown(); + virtual ssize_t socket_recv( char *buf, size_t len, int options ); + virtual ssize_t socket_send( const char *buf, size_t len, int options ); + virtual int socket_connect(); + virtual void on_socket_connected(); + +private: + void init(); // constructor helper function + + // functions for RingBuffer + size_t Read( void *dest, size_t len ) override; + size_t Write( const void *dest, size_t len ) override; + +protected: + RECVS_DISPATCH; +}; + +#endif //!NULLSOFT_WAC_NETWORK_CONNECTION_H diff --git a/Src/Components/wac_network/wac_network_connection_api.cpp b/Src/Components/wac_network/wac_network_connection_api.cpp new file mode 100644 index 00000000..1e163192 --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection_api.cpp @@ -0,0 +1 @@ +#include "wac_network_connection_api.h" diff --git a/Src/Components/wac_network/wac_network_connection_api.h b/Src/Components/wac_network/wac_network_connection_api.h new file mode 100644 index 00000000..65323401 --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection_api.h @@ -0,0 +1,193 @@ +#ifndef NULLSOFT_COMPONENT_WAC_NETWORK_CONNECTION_H +#define NULLSOFT_COMPONENT_WAC_NETWORK_CONNECTION_H + +#define PACKET_SIZE 16384 + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#include "wac_network_dns_api.h" + +enum +{ + CONNECTION_STATE_ERROR, + CONNECTION_STATE_NOCONNECTION, + CONNECTION_STATE_RESOLVING, + CONNECTION_STATE_CONNECTING, + CONNECTION_STATE_CONNECTED, + CONNECTION_STATE_CLOSING, + CONNECTION_STATE_CLOSED, + CONNECTION_STATE_RESOLVED, // happens after RESOLVING, but going here for compatability +}; + +class api_dns; + +class NOVTABLE api_connection : public Dispatchable +{ +protected: + api_connection() {} + ~api_connection() {} + +public: + DISPATCH_CODES + { + API_CONNECTION_OPEN = 10, + API_CONNECTION_CONNECT = 20, + API_CONNECTION_RUN = 30, + API_CONNECTION_GETSTATE = 40, + API_CONNECTION_GETERROR = 50, + API_CONNECTION_CLOSE = 60, + API_CONNECTION_FLUSHSEND = 70, + API_CONNECTION_GETSENDBYTESINQUEUE = 80, + API_CONNECTION_GETSENDBYTESAVAILABLE = 90, + API_CONNECTION_SEND = 100, + API_CONNECTION_SENDBYTES = 110, + API_CONNECTION_SENDSTRING = 120, + API_CONNECTION_GETRECEIVEBYTESAVAILABLE = 130, + API_CONNECTION_RECEIVEBYTES = 140, +// API_CONNECTION_RECEIVEINTEGER = 150, + API_CONNECTION_GETRECEIVELINESAVAILABLE = 160, + API_CONNECTION_RECEIVELINE = 170, + API_CONNECTION_PEEKBYTES = 180, + API_CONNECTION_GETINTERFACE = 190, + API_CONNECTION_GETREMOTEADDRESS = 200, + API_CONNECTION_GETREMOTEPORT = 210, + }; + + void Open( api_dns *dns = API_DNS_AUTODNS, size_t sendbufsize = 8192, size_t recvbufsize = 8192 ); + void connect( char *hostname, int port ); + void run( int max_send_bytes = -1, int max_recv_bytes = -1, int *bytes_sent = NULL, int *bytes_rcvd = NULL ); + int get_state(); + char *GetError(); + void Close( int quick = 0 ); + void FlushSend( void ); + + size_t GetSendBytesInQueue( void ); + size_t GetSendBytesAvailable( void ); + + int send( const void *data, int length ); // returns -1 if not enough room + int SendString( const char *line ); // returns -1 if not enough room + + size_t GetReceiveBytesAvailable( void ); + size_t recv_bytes( void *data, size_t maxlength ); // returns actual bytes read + + int GetReceiveLinesAvailable( void ); + int ReceiveLine( char *line, int maxlength ); // returns 0 if the line was terminated with a \r or \n, 1 if not. + // (i.e. if you specify maxlength=10, and the line is 12 bytes long + // it will return 1. or if there is no \r or \n and that's all the data + // the connection has.) + + size_t PeekBytes( void *data, size_t maxlength ); // returns bytes peeked + + unsigned long GetInterface( void ); // this returns the interface the connection is on + unsigned long GetRemoteAddress( void ); // remote host ip. + short GetRemotePort( void ); // this returns the remote port of connection +}; + + +inline void api_connection::Open( api_dns *dns, size_t sendbufsize, size_t recvbufsize ) +{ + _voidcall( API_CONNECTION_OPEN, dns, sendbufsize, recvbufsize ); +} + +inline void api_connection::connect( char *hostname, int port ) +{ + _voidcall( API_CONNECTION_CONNECT, hostname, port ); +} + +inline void api_connection::run( int max_send_bytes, int max_recv_bytes, int *bytes_sent, int *bytes_rcvd ) +{ + _voidcall( API_CONNECTION_RUN, max_send_bytes, max_recv_bytes, bytes_sent, bytes_rcvd ); +} + +inline int api_connection::get_state() +{ + return _call( API_CONNECTION_GETSTATE, (int)0 ); +} + +inline char *api_connection::GetError() +{ + return _call( API_CONNECTION_GETERROR, (char *)NULL ); +} + +inline void api_connection::Close( int quick ) +{ + _voidcall( API_CONNECTION_CLOSE, quick ); +} + +inline void api_connection::FlushSend( void ) +{ + _voidcall( API_CONNECTION_FLUSHSEND ); +} + +inline size_t api_connection::GetSendBytesInQueue( void ) +{ + return _call( API_CONNECTION_GETSENDBYTESINQUEUE, (size_t)0 ); +} + +inline size_t api_connection::GetSendBytesAvailable( void ) +{ + return _call( API_CONNECTION_GETSENDBYTESAVAILABLE, (size_t)0 ); +} + +inline int api_connection::send( const void *data, int length ) +{ + return _call( API_CONNECTION_SEND, (int)0, data, length ); +} + +inline int api_connection::SendString( const char *line ) +{ + return _call( API_CONNECTION_SENDSTRING, (int)0, line ); +} + +inline size_t api_connection::GetReceiveBytesAvailable( void ) +{ + return _call( API_CONNECTION_GETRECEIVEBYTESAVAILABLE, (size_t)0 ); +} + +inline size_t api_connection::recv_bytes( void *data, size_t maxlength ) +{ + return _call( API_CONNECTION_RECEIVEBYTES, (size_t)0, data, maxlength ); +} + + +inline int api_connection::GetReceiveLinesAvailable( void ) +{ + return _call( API_CONNECTION_GETRECEIVELINESAVAILABLE, (int)0 ); +} + +inline int api_connection::ReceiveLine( char *line, int maxlength ) +{ + return _call( API_CONNECTION_RECEIVELINE, (int)0, line, maxlength ); +} + +inline size_t api_connection::PeekBytes( void *data, size_t maxlength ) +{ + return _call( API_CONNECTION_PEEKBYTES, (size_t)0, data, maxlength ); +} + +inline unsigned long api_connection::GetInterface( void ) +{ + return _call( API_CONNECTION_GETINTERFACE, (unsigned long)0 ); +} + +inline unsigned long api_connection::GetRemoteAddress( void ) +{ + return _call( API_CONNECTION_GETREMOTEADDRESS, (unsigned long)0 ); +} + +inline short api_connection::GetRemotePort( void ) +{ + return _call( API_CONNECTION_GETREMOTEPORT, (short)0 ); +} + +// {049E1B1E-56DF-46e0-B88F-E7E319F131DD} +static const GUID connectionFactoryGUID = +{ 0x49e1b1e, 0x56df, 0x46e0, { 0xb8, 0x8f, 0xe7, 0xe3, 0x19, 0xf1, 0x31, 0xdd } }; + +// {8F0B5D22-699B-486b-B39D-650E5B09C1F1} +static const GUID sslConnectionFactoryGUID = +{ 0x8f0b5d22, 0x699b, 0x486b, { 0xb3, 0x9d, 0x65, 0xe, 0x5b, 0x9, 0xc1, 0xf1 } }; + +#endif // !NULLSOFT_COMPONENT_WAC_NETWORK_CONNECTION_H + diff --git a/Src/Components/wac_network/wac_network_connection_factory.cpp b/Src/Components/wac_network/wac_network_connection_factory.cpp new file mode 100644 index 00000000..9788975e --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection_factory.cpp @@ -0,0 +1,90 @@ +#define GUID_EQUALS_DEFINED + +#include <QtGlobal> + +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_ssl_connection.h" +#include "wac_network_connection_factory.h" + + +static const std::string _serviceName = "Connection Service"; +static const std::string _testString = "wac_connection"; + + +FOURCC JNL_ConnectionFactory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *JNL_ConnectionFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID JNL_ConnectionFactory::GetGUID() +{ + return connectionFactoryGUID; +} + +void *JNL_ConnectionFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + WAC_Network_Connection *conn = new WAC_Network_Connection; + conn->set_dns( GetGlobalDNS() ); + + api_connection *ifc = static_cast<api_connection *>( conn ); + + // if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; +} + +int JNL_ConnectionFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_ConnectionFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_connection *connection = static_cast<api_connection *>( ifc ); + WAC_Network_Connection *jnl_connection = static_cast<WAC_Network_Connection *>( connection ); + + delete jnl_connection; + + JNL::close_socketlib(); + + return 1; +} + +const char *JNL_ConnectionFactory::GetTestString() +{ + return _testString.c_str(); +} + +int JNL_ConnectionFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS JNL_ConnectionFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; diff --git a/Src/Components/wac_network/wac_network_connection_factory.h b/Src/Components/wac_network/wac_network_connection_factory.h new file mode 100644 index 00000000..c56a8053 --- /dev/null +++ b/Src/Components/wac_network/wac_network_connection_factory.h @@ -0,0 +1,62 @@ +#ifndef NULLSOFT_FACTORY_WAC_NETWORK_CONNECTION_H +#define NULLSOFT_FACTORY_WAC_NETWORK_CONNECTION_H + +#include <string> + +#include "api/service/services.h" +#include "api/service/waservicefactory.h" + + +class JNL_ConnectionFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + const char *GetTestString(); + + void *GetInterface( int global_lock ); + int ReleaseInterface( void *ifc ); + + int SupportNonLockingInterface(); + int ServiceNotify( int msg, int param1, int param2 ); + +protected: + RECVS_DISPATCH; +}; + + +// +//namespace wa +//{ +// namespace Components +// { +// class WAC_ConnectionFactory : public waServiceFactory +// { +// //public: +// ////WAC_ConnectionFactory() {} +// ////~WAC_ConnectionFactory() {} +// +// //FOURCC GetServiceType(); +// //const char *GetServiceName(); +// //const char *GetTestString(); +// //GUID GetGUID(); +// +// //void *GetInterface( int p_global_lock ); +// //int ReleaseInterface( void *p_ifc ); +// +// //int SupportNonLockingInterface(); +// //int ServiceNotify( int p_msg, int p_param1, int p_param2 ); +// +// +// //HRESULT Register( api_service *p_service ); +// //HRESULT Unregister( api_service *p_service ); +// +// +// //protected: +// //RECVS_DISPATCH; +// }; +// } +//} + +#endif // !NULLSOFT_FACTORY_WAC_NETWORK_CONNECTION_H
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_dns.cpp b/Src/Components/wac_network/wac_network_dns.cpp new file mode 100644 index 00000000..ce0b3992 --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns.cpp @@ -0,0 +1,277 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: asyncdns.cpp - JNL portable asynchronous DNS implementation +** License: see jnetlib.h +*/ + +#include "netinc.h" +#include "util.h" + +#include "wac_network_dns.h" + +#include <time.h> + +#ifdef _WIN32 +#include <strsafe.h> +#endif + +enum +{ + MODE_RESOLVE = 0, + MODE_REVERSE = 1, +}; + + +struct cache_entry +{ + time_t last_used; // timestamp. + bool resolved; + int mode; // 1=reverse + unsigned short port; + char hostname[ 256 ]; + addrinfo *addr; + int sockettype; +}; + +wa::Components::WAC_Network_AsyncDNS::WAC_Network_AsyncDNS( int max_cache_entries ) +{ + m_thread_kill = 1; + m_thread = 0; + m_cache_size = max_cache_entries; + m_cache = (cache_entry *)malloc( sizeof( cache_entry ) * m_cache_size ); + + if ( m_cache ) + memset( m_cache, 0, sizeof( cache_entry ) * m_cache_size ); + else + m_cache_size = 0; +} + +wa::Components::WAC_Network_AsyncDNS::~WAC_Network_AsyncDNS() +{ + m_thread_kill = 1; + +#ifdef _WIN32 + if ( m_thread ) + { + WaitForSingleObject( m_thread, INFINITE ); + CloseHandle( m_thread ); + } +#else + if ( m_thread ) + { + void *p; + pthread_join( m_thread, &p ); + } +#endif//!_WIN32 + + // free all the addrinfo stuff + for ( int x = 0; x < m_cache_size; x++ ) + { + if ( m_cache[ x ].addr ) + freeaddrinfo( m_cache[ x ].addr ); + } + + free( m_cache ); +} + +int wa::Components::WAC_Network_AsyncDNS::resolvenow( const char *hostname, unsigned short port, addrinfo **addr, int sockettype ) +{ + addrinfo hints; + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = PF_UNSPEC; + + if ( hostname ) + hints.ai_flags = AI_NUMERICHOST; + else + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; + + hints.ai_socktype = sockettype; + + char portString[ 32 ] = { 0 }; + sprintf( portString, "%u", (unsigned int)port ); + + if ( getaddrinfo( hostname, portString, &hints, addr ) == 0 ) + { + return 0; + } + else + { + hints.ai_flags = 0; + if ( getaddrinfo( hostname, portString, &hints, addr ) == 0 ) + return 0; + else + return -1; + } +} + +#ifdef _WIN32 +unsigned long WINAPI wa::Components::WAC_Network_AsyncDNS::_threadfunc( LPVOID _d ) +#else +unsigned int WAC_Network_AsyncDNS::_threadfunc( void *_d ) +#endif +{ + int nowinsock = JNL::open_socketlib(); + wa::Components::WAC_Network_AsyncDNS *_this = (WAC_Network_AsyncDNS *)_d; + int x; + for ( x = 0; x < _this->m_cache_size && !_this->m_thread_kill; x++ ) + { + if ( _this->m_cache[ x ].last_used && !_this->m_cache[ x ].resolved ) + { + if ( !nowinsock ) + { + if ( _this->m_cache[ x ].mode == 0 ) + { + addrinfo *res = 0; + if ( resolvenow( _this->m_cache[ x ].hostname, _this->m_cache[ x ].port, &res, _this->m_cache[ x ].sockettype ) == 0 ) + { + _this->m_cache[ x ].addr = res; + } + else + { + _this->m_cache[ x ].addr = 0; //INADDR_NONE; + } + } + else if ( _this->m_cache[ x ].mode == 1 ) + { + /* + hostent *ent; + // TODO: replace with getnameinfo for IPv6 + ent=gethostbyaddr((const char *)&_this->m_cache[x].addr,4,AF_INET); + if (ent) + lstrcpyn(_this->m_cache[x].hostname, ent->h_name, 256); + else + _this->m_cache[x].hostname[0]=0; + */ + } + + _this->m_cache[ x ].resolved = true; + } + else + { + if ( _this->m_cache[ x ].mode == 0 ) + { + _this->m_cache[ x ].addr = 0;//INADDR_NONE; + _this->m_cache[ x ].resolved = true; + } + else if ( _this->m_cache[ x ].mode == 1 ) + { + _this->m_cache[ x ].hostname[ 0 ] = 0; + _this->m_cache[ x ].resolved = true; + } + } + } + } + + if ( !nowinsock ) + JNL::close_socketlib(); + + _this->m_thread_kill = 1; + + return 0; +} + +int wa::Components::WAC_Network_AsyncDNS::resolve( const char *hostname, unsigned short port, addrinfo **addr, int sockettype ) +{ + // return 0 on success, 1 on wait, -1 on unresolvable + int x; + + for ( x = 0; x < m_cache_size; x++ ) + { + if ( !strcasecmp( m_cache[ x ].hostname, hostname ) && port == m_cache[ x ].port && m_cache[ x ].mode == 0 && m_cache[ x ].sockettype == sockettype ) + { + m_cache[ x ].last_used = time( 0 ); + if ( m_cache[ x ].resolved ) + { + if ( m_cache[ x ].addr == 0 )//INADDR_NONE) + { + return DNS_RESOLVE_UNRESOLVABLE; + } + + *addr = m_cache[ x ].addr; + return DNS_RESOLVE_SUCCESS; + } + + makesurethreadisrunning(); + return DNS_RESOLVE_WAIT; + } + } + + // add to resolve list + int oi = -1; + for ( x = 0; x < m_cache_size; x++ ) + { + if ( !m_cache[ x ].last_used ) + { + oi = x; + break; + } + + if ( ( oi == -1 || m_cache[ x ].last_used < m_cache[ oi ].last_used ) && m_cache[ x ].resolved ) + { + oi = x; + } + } + + if ( oi == -1 ) + { + return DNS_RESOLVE_UNRESOLVABLE; + } + +#ifdef _WIN32 + StringCchCopyA( m_cache[ oi ].hostname, 256, hostname ); +#elif defined(__APPLE__) + strlcpy( m_cache[ oi ].hostname, hostname, 255 ); +#else + strncpy( m_cache[ oi ].hostname, hostname, 255 ); + m_cache[ oi ].hostname[ 255 ] = 0; +#endif + + m_cache[ oi ].port = port; + m_cache[ oi ].mode = 0; + m_cache[ oi ].addr = 0;//INADDR_NONE; + m_cache[ oi ].resolved = false; + m_cache[ oi ].last_used = time( 0 ); + m_cache[ oi ].sockettype = sockettype; + + makesurethreadisrunning(); + + return DNS_RESOLVE_WAIT; +} + +void wa::Components::WAC_Network_AsyncDNS::makesurethreadisrunning( void ) +{ + if ( m_thread_kill ) + { +#ifdef _WIN32 + if ( m_thread ) + { + WaitForSingleObject( m_thread, INFINITE ); + CloseHandle( m_thread ); + } + DWORD id; + m_thread_kill = 0; + m_thread = CreateThread( NULL, 0, _threadfunc, (LPVOID)this, 0, &id ); + if ( !m_thread ) + { +#else + if ( m_thread ) + { + void *p; + pthread_join( m_thread, &p ); + } + m_thread_kill = 0; + if ( pthread_create( &m_thread, NULL, ( void *( * ) ( void * ) )_threadfunc, (void *)this ) != 0 ) + { +#endif + m_thread_kill = 1; + } + } + } + +#define CBCLASS wa::Components::WAC_Network_AsyncDNS +START_DISPATCH; +CB( API_DNS_RESOLVE, resolve ); +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_network/wac_network_dns.h b/Src/Components/wac_network/wac_network_dns.h new file mode 100644 index 00000000..2195d19f --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns.h @@ -0,0 +1,76 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: asyncdns.h - JNL portable asynchronous DNS interface +** License: see jnetlib.h +** +** Usage: +** 1. Create wa::Components::WAC_Network_AsyncDNS object, optionally with the number of cache entries. +** 2. call resolve() to resolve a hostname into an address. The return value of +** resolve is 0 on success (host successfully resolved), 1 on wait (meaning +** try calling resolve() with the same hostname in a few hundred milliseconds +** or so), or -1 on error (i.e. the host can't resolve). +** 3. call reverse() to do reverse dns (ala resolve()). +** 4. enjoy. +*/ + +#ifndef NULLSOFT_WAC_NETWORK_ASYNCDNS_H +#define NULLSOFT_WAC_NETWORK_ASYNCDNS_H + +#include "netinc.h" + +#include "wac_network_dns_api.h" + +struct cache_entry; + +//#define JNL_AUTODNS ((wa::Components::WAC_Network_AsyncDNS *)-1) +//enum +//{ +// DNS_RESOLVE_UNRESOLVABLE = -1, +// DNS_RESOLVE_SUCCESS = 0, +// DNS_RESOLVE_WAIT = 1, +//}; +// +//enum +//{ +// DNS_REVERSE_UNRESOLVABLE = -1, +// DNS_REVERSE_SUCCESS = 0, +// DNS_REVERSE_WAIT = 1, +//}; + +namespace wa +{ + namespace Components + { + class WAC_Network_AsyncDNS : public api_dns + { + public: + WAC_Network_AsyncDNS( int max_cache_entries = 64 ); + ~WAC_Network_AsyncDNS(); + + int resolve( const char *hostname, unsigned short port, addrinfo **addr, int sockettype ); // return 0 on success, 1 on wait, -1 on unresolvable + static int resolvenow( const char *hostname, unsigned short port, addrinfo **addr, int sockettype ); // return 0 on success, -1 on unresolvable + + private: + cache_entry *m_cache; + int m_cache_size; + volatile int m_thread_kill; + +#ifdef _WIN32 + HANDLE m_thread; + static unsigned long WINAPI _threadfunc( LPVOID _d ); +#else + pthread_t m_thread; + static unsigned int _threadfunc( void *_d ); +#endif + + void makesurethreadisrunning( void ); + + protected: + RECVS_DISPATCH; + }; + } +} + +#endif //!NULLSOFT_WAC_NETWORK_ASYNCDNS_H diff --git a/Src/Components/wac_network/wac_network_dns_api.cpp b/Src/Components/wac_network/wac_network_dns_api.cpp new file mode 100644 index 00000000..f321fcdc --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns_api.cpp @@ -0,0 +1 @@ +#include "wac_network_dns_api.h" diff --git a/Src/Components/wac_network/wac_network_dns_api.h b/Src/Components/wac_network/wac_network_dns_api.h new file mode 100644 index 00000000..e1579506 --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns_api.h @@ -0,0 +1,52 @@ +#ifndef NULLSOFT_COMPONENT_WAC_NETWORK_DNS_H +#define NULLSOFT_COMPONENT_WAC_NETWORK_DNS_H + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#define API_DNS_AUTODNS ((api_dns *)-1) + +enum +{ + DNS_RESOLVE_UNRESOLVABLE = -1, + DNS_RESOLVE_SUCCESS = 0, + DNS_RESOLVE_WAIT = 1, +}; + +enum +{ + DNS_REVERSE_UNRESOLVABLE = -1, + DNS_REVERSE_SUCCESS = 0, + DNS_REVERSE_WAIT = 1, +}; + +struct addrinfo; + +class NOVTABLE api_dns : public Dispatchable +{ +protected: + api_dns() {} + ~api_dns() {} + +public: + DISPATCH_CODES + { + API_DNS_RESOLVE = 11, + API_DNS_REVERSE = 20, + }; + + int resolve( char *hostname, short port, addrinfo **addr, int sockettype ); // see DNS_RESOLVE_* for return values +}; + +inline int api_dns::resolve( char *hostname, short port, addrinfo **addr, int sockettype ) +{ + return _call( API_DNS_RESOLVE, (int)DNS_RESOLVE_UNRESOLVABLE, hostname, port, addr, sockettype ); +} + + +// {F0435E72-5A1A-4d57-A9E2-3FDC421C1010} +static const GUID dnsFactoryGUID = +{ 0xf0435e72, 0x5a1a, 0x4d57, { 0xa9, 0xe2, 0x3f, 0xdc, 0x42, 0x1c, 0x10, 0x10 } }; + + +#endif // !NULLSOFT_COMPONENT_WAC_NETWORK_DNS_H
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_dns_connection.h b/Src/Components/wac_network/wac_network_dns_connection.h new file mode 100644 index 00000000..a6b1344b --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns_connection.h @@ -0,0 +1,21 @@ +#ifndef NULLSOFT_WAC_NETWORK_H +#define NULLSOFT_WAC_NETWORK_H + +#include "../../Agave/Component/ifc_wa5component.h" + + +class wac_network : public ifc_wa5component +{ +public: + wac_network(); + + void RegisterServices( api_service *service ); + int RegisterServicesSafeModeOk(); + + void DeregisterServices( api_service *service ); + +protected: + RECVS_DISPATCH; +}; + +#endif // !NULLSOFT_WAC_NETWORK_H diff --git a/Src/Components/wac_network/wac_network_dns_factory.cpp b/Src/Components/wac_network/wac_network_dns_factory.cpp new file mode 100644 index 00000000..05d596e7 --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns_factory.cpp @@ -0,0 +1,78 @@ +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_dns.h" +#include "wac_network_dns_factory.h" + + +static const std::string _serviceName = "Asynchronous DNS Service"; + + +FOURCC JNL_AsyncDNSFactory::GetServiceType() +{ + return WaSvc::UNIQUE; +} + +const char *JNL_AsyncDNSFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID JNL_AsyncDNSFactory::GetGUID() +{ + return dnsFactoryGUID; +} + +void *JNL_AsyncDNSFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + api_dns *ifc = GetGlobalDNS(); + + // if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; +} + +int JNL_AsyncDNSFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_AsyncDNSFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + + JNL::close_socketlib(); + + return 1; +} + +const char *JNL_AsyncDNSFactory::GetTestString() +{ + return NULL; +} + +int JNL_AsyncDNSFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS JNL_AsyncDNSFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; diff --git a/Src/Components/wac_network/wac_network_dns_factory.h b/Src/Components/wac_network/wac_network_dns_factory.h new file mode 100644 index 00000000..dd29387f --- /dev/null +++ b/Src/Components/wac_network/wac_network_dns_factory.h @@ -0,0 +1,26 @@ +#ifndef NULLSOFT_FACTORY_WAC_NETWORK_DNS_H +#define NULLSOFT_FACTORY_WAC_NETWORK_DNS_H + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +class JNL_AsyncDNSFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + void *GetInterface( int global_lock ); + int SupportNonLockingInterface(); + int ReleaseInterface( void *ifc ); + const char *GetTestString(); + int ServiceNotify( int msg, int param1, int param2 ); + +protected: + RECVS_DISPATCH; +}; + +#endif // !NULLSOFT_FACTORY_WAC_NETWORK_DNS_H + diff --git a/Src/Components/wac_network/wac_network_global.h b/Src/Components/wac_network/wac_network_global.h new file mode 100644 index 00000000..34a7bf74 --- /dev/null +++ b/Src/Components/wac_network/wac_network_global.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_WAC_NETWORK_GLOBAL_H +#define NULLSOFT_WAC_NETWORK_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifndef BUILD_STATIC +# if defined(WAC_NETWORK_LIB) +# define WAC_NETWORK_EXPORT Q_DECL_EXPORT +# else +# define WAC_NETWORK_EXPORT Q_DECL_IMPORT +# endif +#else +# define WAC_NETWORK_EXPORT +#endif + +#endif // !NULLSOFT_WAC_NETWORK_GLOBAL_H
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_receiver.cpp b/Src/Components/wac_network/wac_network_http_receiver.cpp new file mode 100644 index 00000000..575ea5f0 --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver.cpp @@ -0,0 +1,902 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: httpget.cpp - JNL HTTP GET implementation +** License: see jnetlib.h +*/ + +#include "netinc.h" +#include "util.h" + +#include "wac_network_http_receiver.h" + +#ifdef USE_SSL +#include "wac_network_ssl_connection.h" +#endif + +#include <stdio.h> + +#pragma intrinsic(memcpy) + +#include "../nu/strsafe.h" +#include "nu/AutoLock.h" + +#include "..\WAT\WAT.h" + +char *wa::Components::WAC_Network_HTTPGet::g_proxy = 0; + +static nu::LockGuard proxy_guard; + +char *wa::Components::WAC_Network_HTTPGet::get_proxy() +{ + nu::AutoLock auto_lock( proxy_guard ); + + if ( g_proxy ) + return _strdup( g_proxy ); + else + return 0; +} + +void wa::Components::WAC_Network_HTTPGet::set_proxy( const char *p_proxy ) +{ + nu::AutoLock auto_lock( proxy_guard ); + + free( g_proxy ); + + if ( p_proxy ) + g_proxy = _strdup( p_proxy ); + else + g_proxy = 0; +} + +wa::Components::WAC_Network_HTTPGet::WAC_Network_HTTPGet( api_dns *p_dns, size_t p_recvbufsize, const char *p_proxy ) +{ + JNL::open_socketlib(); + + reinit(); + + open( p_dns, p_recvbufsize, p_proxy ); +} + +wa::Components::WAC_Network_HTTPGet::~WAC_Network_HTTPGet() +{ + deinit(); + + free( m_sendheaders ); + free( m_http_proxylpinfo ); + free( m_http_proxyhost ); +} + +void wa::Components::WAC_Network_HTTPGet::open( api_dns *p_dns, size_t p_recvbufsize, const char *p_proxy ) +{ + m_recvbufsize = p_recvbufsize; + if ( p_dns != API_DNS_AUTODNS ) + m_dns = p_dns; + + if ( p_proxy ) + { + char *p = _strdup( p_proxy ); + if ( p ) + { + char *r = NULL; + do_parse_url( p, &m_http_proxyhost, &m_http_proxyport, &r, &m_http_proxylpinfo ); + + free( r ); + free( p ); + } + } +} + +void wa::Components::WAC_Network_HTTPGet::reinit() +{ + m_errstr = 0; + m_recvheaders = NULL; + m_recvheaders_size = 0; + m_http_state = 0; + m_http_port = 0; + m_http_url = 0; + m_reply = 0; + m_http_host = NULL; + m_http_lpinfo = NULL; + m_http_request = NULL; + m_http_content_type = NULL; +} + +void wa::Components::WAC_Network_HTTPGet::deinit( bool p_full ) +{ + if ( !persistent || p_full || ( m_con && m_con->get_state() == WAC_Network_Connection::STATE_ERROR ) ) + { + delete m_con; + m_con = NULL; + } + + free( m_recvheaders ); + free( m_http_url ); + free( m_http_host ); + free( m_http_lpinfo ); + free( m_http_request ); + + if ( m_http_content_type ) + free( m_http_content_type ); + + free( m_errstr ); + free( m_reply ); + + if ( zlibStream ) + inflateEnd( zlibStream ); + + free( zlibStream ); + zlibStream = 0; + + reinit(); +} + +void wa::Components::WAC_Network_HTTPGet::set_sendbufsize( size_t p_sendbufsize ) +{ + m_sendbufsize = p_sendbufsize; +} + +int wa::Components::WAC_Network_HTTPGet::set_recv_buffer_size( size_t p_new_buffer_size ) +{ + if ( m_con ) + { + int ret = m_con->set_recv_buffer_size( p_new_buffer_size ); + if ( ret == NErr_NoAction )// this will get returned if new_buffer_size is smaller than existing. + return NErr_Success; + else if ( ret != NErr_Success ) + return ret; + } + + m_recvbufsize = p_new_buffer_size; + + return NErr_Success; +} + +void wa::Components::WAC_Network_HTTPGet::addheader( const char *header ) +{ + if ( strstr( header, "\r" ) || strstr( header, "\n" ) ) + return; + + if ( !m_sendheaders ) + { + size_t len = strlen( header ) + 3; + + m_sendheaders = (char *)malloc( len ); + if ( m_sendheaders ) + { + char *itr = m_sendheaders; + StringCchCopyExA( itr, len, header, &itr, &len, 0 ); + StringCchCatExA( itr, len, "\r\n", &itr, &len, 0 ); + } + } + else + { + size_t len = strlen( header ) + strlen( m_sendheaders ) + 1 + 2; + char *t = (char *)malloc( len ); + if ( t ) + { + char *newHeaders = t; + StringCchCopyExA( t, len, m_sendheaders, &t, &len, 0 ); + StringCchCatExA( t, len, header, &t, &len, 0 ); + StringCchCatExA( t, len, "\r\n", &t, &len, 0 ); + + free( m_sendheaders ); + + m_sendheaders = newHeaders; + } + } +} + +void wa::Components::WAC_Network_HTTPGet::addheadervalue( const char *header, const char *value ) +{ + size_t additional = strlen( header ) + 2 + strlen( value ) + 2 + 1; + if ( !m_sendheaders ) + { + m_sendheaders = (char *)malloc( additional ); + if ( m_sendheaders ) + { + char *p = m_sendheaders; + StringCchCopyExA( p, additional, header, &p, &additional, 0 ); + StringCchCatExA( p, additional, ": ", &p, &additional, 0 ); + StringCchCatExA( p, additional, value, &p, &additional, 0 ); + StringCchCatExA( p, additional, "\r\n", &p, &additional, 0 ); + } + } + else + { + size_t alloc_len = strlen( m_sendheaders ) + additional; + char *t = (char *)malloc( alloc_len ); + if ( t ) + { + char *p = t; + StringCchCopyExA( p, alloc_len, m_sendheaders, &p, &alloc_len, 0 ); + StringCchCatExA( p, alloc_len, header, &p, &alloc_len, 0 ); + StringCchCatExA( p, alloc_len, ": ", &p, &alloc_len, 0 ); + StringCchCatExA( p, alloc_len, value, &p, &alloc_len, 0 ); + StringCchCatExA( p, alloc_len, "\r\n", &p, &alloc_len, 0 ); + free( m_sendheaders ); + m_sendheaders = t; + } + } +} + +void wa::Components::WAC_Network_HTTPGet::do_encode_mimestr( char *in, char *out ) +{ + char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int shift = 0; + int accum = 0; + + while ( in && *in ) + { + if ( *in ) + { + accum <<= 8; + shift += 8; + accum |= *in++; + } + while ( shift >= 6 ) + { + shift -= 6; + *out++ = alphabet[ ( accum >> shift ) & 0x3F ]; + } + } + + if ( shift == 4 ) + { + *out++ = alphabet[ ( accum & 0xF ) << 2 ]; + *out++ = '='; + } + else if ( shift == 2 ) + { + *out++ = alphabet[ ( accum & 0x3 ) << 4 ]; + *out++ = '='; + *out++ = '='; + } + + *out++ = 0; +} + + +void wa::Components::WAC_Network_HTTPGet::connect( const char *url, int ver, const char *requestmethod ) +{ + deinit( false ); + m_http_url = _strdup( url ); + do_parse_url( m_http_url, &m_http_host, &m_http_port, &m_http_request, &m_http_lpinfo ); + + if ( !m_http_host || !m_http_host[ 0 ] || !m_http_port ) + { + m_http_state = -1; + seterrstr( "invalid URL" ); + + return; + } + + size_t sendbufferlen = 0; + + if ( !m_http_proxyhost || !m_http_proxyhost[ 0 ] ) + sendbufferlen += strlen( requestmethod ) + 1 /* GET */ + strlen( m_http_request ) + 9 /* HTTP/1.0 */ + 2; + else + { + sendbufferlen += strlen( requestmethod ) + 1 /* GET */ + strlen( m_http_url ) + 9 /* HTTP/1.0 */ + 2; + if ( m_http_proxylpinfo && m_http_proxylpinfo[ 0 ] ) + sendbufferlen += 58 + strlen( m_http_proxylpinfo ) * 2; // being safe here + } + + sendbufferlen += 5 /* Host: */ + strlen( m_http_host ) + 2; + if ( m_http_port != 80 ) + sendbufferlen += 6; + + if ( m_http_lpinfo && m_http_lpinfo[ 0 ] ) + sendbufferlen += 46 + strlen( m_http_lpinfo ) * 2; // being safe here + + if ( m_sendheaders ) + sendbufferlen += strlen( m_sendheaders ); + + size_t strLen = sendbufferlen + 1024; + char *str = (char *)calloc( strLen, sizeof( char ) ); + char *connectString = str; + if ( !str ) + { + seterrstr( "error allocating memory" ); + m_http_state = -1; + } + + if ( !m_http_proxyhost || !m_http_proxyhost[ 0 ] ) + { + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "%s %s HTTP/1.%d\r\n", requestmethod, m_http_request, ver % 10 ); + } + else + { + char *myp = NULL; + if ( strncasecmp( m_http_url, "uvox://", 7 ) == 0 ) + { + myp = m_http_url + 7; + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "%s http: //%s HTTP/1.%d\r\n", requestmethod, myp, ver % 10 ); + } + else if ( strncasecmp( m_http_url, "unsv://", 7 ) == 0 ) + { + myp = m_http_url + 7; + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "%s http: //%s HTTP/1.%d\r\n", requestmethod, myp, ver % 10 ); + } + else if ( strncasecmp( m_http_url, "uasf://", 7 ) == 0 ) + { + myp = m_http_url + 7; + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "%s http: //%s HTTP/1.%d\r\n", requestmethod, myp, ver % 10 ); + } + else + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "%s %s HTTP/1.%d\r\n", requestmethod, m_http_url, ver % 10 ); + } + + if ( ver % 10 == 1 ) + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "Connection: close\r\n" ); + + if ( m_http_port == 80 ) + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "Host: %s\r\n", m_http_host ); + else + StringCchPrintfExA( str, strLen, &str, &strLen, 0, "Host: %s:%d\r\n", m_http_host, m_http_port ); + + if ( m_http_lpinfo && m_http_lpinfo[ 0 ] ) + { + StringCchCatExA( str, strLen, "Authorization: Basic ", &str, &strLen, 0 ); + do_encode_mimestr( m_http_lpinfo, str ); + StringCchCatExA( str, strLen, "\r\n", &str, &strLen, 0 ); + } + + if ( m_http_proxylpinfo && m_http_proxylpinfo[ 0 ] ) + { + StringCchCatExA( str, strLen, "Proxy-Authorization: Basic ", &str, &strLen, 0 ); + do_encode_mimestr( m_http_proxylpinfo, str ); + StringCchCatExA( str, strLen, "\r\n", &str, &strLen, 0 ); + } + + if ( allowCompression ) + StringCchCatExA( str, strLen, "Accept-Encoding: compress, gzip\r\n", &str, &strLen, 0 ); + + if ( m_sendheaders ) + StringCchCatExA( str, strLen, m_sendheaders, &str, &strLen, 0 ); + + StringCchCatExA( str, strLen, "\r\n", &str, &strLen, 0 ); + + int a = (int)m_recvbufsize; + if ( a < 4096 ) + a = 4096; + + if ( !m_con ) + { + //m_con=new WAC_Network_Connection(m_dns,strlen(str)+4,a); + /* + ** Joshua Teitelbaum delta 1/15/2006 + */ +#ifdef USE_SSL + /* + ** Joshua Teitelbaum 1/27/2006 + ** Check for secure + */ + if ( !_strnicmp( m_http_url, "https:", strlen( "https:" ) ) ) + { + size_t send_buffer_size = strlen( connectString ) + 4; + if ( send_buffer_size < 8192 ) + send_buffer_size = 8192; + + send_buffer_size += m_sendbufsize; + + if ( m_sendbufsize == 0 && !strcmp( requestmethod, "POST" ) ) + send_buffer_size += 8192; // some extra room for posting data if it wasn't explicitly defined + + m_con = new JNL_SSL_Connection( NULL, m_dns, send_buffer_size, a ); + } + else + { +#endif + size_t send_buffer_size = strlen( connectString ) + 4 + m_sendbufsize; + if ( m_sendbufsize == 0 && !strcmp( requestmethod, "POST" ) ) + send_buffer_size += 8192; // some extra room for posting data if it wasn't explicitly defined + + m_con = new WAC_Network_Connection( m_dns, send_buffer_size, a ); +#ifdef USE_SSL + } +#endif + if ( m_con ) + { + if ( !m_http_proxyhost || !m_http_proxyhost[ 0 ] ) + m_con->connect( m_http_host, m_http_port ); + else + m_con->connect( m_http_proxyhost, m_http_proxyport ); + + m_con->send_string( connectString ); + } + else + { + m_http_state = -1; + seterrstr( "could not create connection object" ); + } + } + else + { + m_con->reuse(); + m_con->send_string( connectString ); + } + + free( connectString ); +} + +void wa::Components::WAC_Network_HTTPGet::do_parse_url( const char *url, char **host, unsigned short *port, char **req, char **lp ) +{ + char *l_port = 0; + + JNL::parse_url( url, &l_port, host, port, req, lp ); + if ( !*port ) + { + if ( l_port ) + { + addrinfo *res; + + addrinfo hints; + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = 0; + hints.ai_socktype = SOCK_STREAM; + + if ( getaddrinfo( 0, l_port, &hints, &res ) == 0 ) + { + if ( res->ai_family == AF_INET ) + *port = htons( ( (sockaddr_in *)res->ai_addr )->sin_port ); + else if ( res->ai_family == AF_INET6 ) + *port = htons( ( (sockaddr_in6 *)res->ai_addr )->sin6_port ); + else // wtf? + *port = 80; + } + else + *port = 80; + } + else + *port = 80; + } + + if ( l_port ) + free( l_port ); + + if ( !*req ) + *req = _strdup( "/" ); +} + +const char *wa::Components::WAC_Network_HTTPGet::getallheaders() +{ + // double null terminated, null delimited list + if ( m_recvheaders ) + return m_recvheaders; + else + return "\0\0"; +} + +char *wa::Components::WAC_Network_HTTPGet::getheader( const char *headername ) +{ + char *ret = NULL; + if ( headername[ 0 ] == 0 || !m_recvheaders ) + return NULL; + + size_t headername_size = strlen( headername ); + char *buf = (char *)malloc( headername_size + 2 ); + +#ifdef _WIN32 + StringCchCopyA( buf, headername_size + 2, headername ); +#elif defined(__APPLE__) + strlcpy( buf, headername, headername_size + 2 ); +#else + strncpy( buf, headername, headername_size + 1 ); + buf[ headername_size + 1 ] = 0; +#endif + + if ( buf[ headername_size - 1 ] != ':' ) + { + buf[ headername_size++ ] = ':'; + buf[ headername_size ] = 0; + } + + char *p = m_recvheaders; + while ( p && *p ) + { + if ( !strncasecmp( buf, p, headername_size ) ) + { + ret = p + headername_size; + + while ( ret && *ret && *ret == ' ' ) + ret++; + + break; + } + + p += strlen( p ) + 1; + } + + free( buf ); + + return ret; +} + +int wa::Components::WAC_Network_HTTPGet::run() +{ + int cnt = 0; + if ( m_http_state == -1 || !m_con ) + return HTTPRECEIVER_RUN_ERROR; // error + + +run_again: + m_con->run(); + + if ( m_con->get_state() == WAC_Network_Connection::STATE_ERROR ) + { + seterrstr( m_con->get_errstr() ); + + return HTTPRECEIVER_RUN_ERROR; + } + + if ( m_con->get_state() == WAC_Network_Connection::STATE_CLOSED ) + return HTTPRECEIVER_RUN_CONNECTION_CLOSED; + + if ( m_http_state == 0 ) // connected, waiting for reply + { + if ( m_con->recv_lines_available() > 0 ) + { + char buf[ 4096 ] = { 0 }; + m_con->recv_line( buf, 4096 ); + buf[ 4095 ] = 0; + + if ( m_reply && getreplycode() == 100 ) + { + free( m_reply ); + m_reply = 0; + goto run_again; + } + + m_reply = _strdup( buf ); + int code = getreplycode(); + if ( code >= 200 && code <= 206 ) + m_http_state = 2; // proceed to read headers normally + else if ( code == 301 || code == 302 || code == 303 || code == 307 ) + { + m_http_state = 1; // redirect city + } + else if ( code != 100 ) // in case of HTTP 100 Continue code, we'll keep looping + { + if ( accept_all_reply_codes ) + { + m_http_state = 2; // proceed to read headers normally + } + else + { + seterrstr( buf ); + m_http_state = -1; + + return HTTPRECEIVER_RUN_ERROR; + } + } + + cnt = 0; + } + else if ( !cnt++ ) + goto run_again; + } + + if ( m_http_state == 1 ) // redirect + { + char *loc = 0; + while ( m_con->recv_lines_available() > 0 ) + { + char buf[ 4096 ] = { 0 }; + m_con->recv_line( buf, 4096 ); + buf[ 4095 ] = 0; + + if ( !buf[ 0 ] ) + { + if ( !loc ) + { + m_http_state = -1; + return HTTPRECEIVER_RUN_ERROR; + } + else + break; + } + + if ( !strncasecmp( buf, "Location:", 9 ) ) + { + char *p = buf + 9; + while ( p && *p && *p == ' ' ) p++; + if ( p && *p ) + { + // TODO need to make this match the request type + loc = _strdup( p ); + } + } + } + + if ( loc ) + { + connect( loc, 1 ); + free( loc ); + + return HTTPRECEIVER_RUN_OK; + } + } + + /* ----- read headers ----- */ + if ( m_http_state == 2 ) + { + if ( !cnt++ && m_con->recv_lines_available() < 1 ) + goto run_again; + + while ( m_con->recv_lines_available() > 0 ) + { + char buf[ 8192 ] = { 0 }; + m_con->recv_line( buf, 8192 ); + buf[ 8191 ] = 0; + + if ( !buf[ 0 ] ) + { + const char *compression = getheader( "Content-Encoding" ); + if ( compression && !strcmp( compression, "gzip" ) ) + { + zlibStream = (z_stream *)malloc( sizeof( z_stream ) ); + zlibStream->next_in = Z_NULL; + zlibStream->avail_in = Z_NULL; + zlibStream->next_out = Z_NULL; + zlibStream->avail_out = Z_NULL; + zlibStream->zalloc = (alloc_func)0; + zlibStream->zfree = (free_func)0; + zlibStream->opaque = 0; + + int z_err = inflateInit2( zlibStream, 15 + 16 /* +16 for gzip */ ); + if ( z_err != Z_OK ) + { + free( zlibStream ); + zlibStream = 0; + } + } + else + { + if ( zlibStream ) + { + free( zlibStream ); + zlibStream = 0; + } + } + + m_http_state = 3; + + break; + } + + if ( !m_recvheaders ) + { + m_recvheaders_size = strlen( buf ) + 1; + if ( m_recvheaders_size == 0 || m_recvheaders_size == (size_t)-1 ) // check for overflow + { + m_http_state = -1; + return HTTPRECEIVER_RUN_ERROR; + } + + m_recvheaders = (char *)malloc( m_recvheaders_size + 1 ); + if ( m_recvheaders ) + { + strcpy( m_recvheaders, buf ); // safe because we malloc'd specifically above + m_recvheaders[ m_recvheaders_size ] = 0; + } + else + { + m_http_state = -1; + return HTTPRECEIVER_RUN_ERROR; + } + } + else + { + size_t oldsize = m_recvheaders_size; + m_recvheaders_size += strlen( buf ) + 1; + if ( m_recvheaders_size + 1 < oldsize ) // check for overflow + { + m_http_state = -1; + return HTTPRECEIVER_RUN_ERROR; + } + + char *n = (char *)realloc( m_recvheaders, m_recvheaders_size + 1 ); + if ( !n ) + { + m_http_state = -1; + return HTTPRECEIVER_RUN_ERROR; + } + + strcpy( n + oldsize, buf ); // safe because we malloc specifially for the size + n[ m_recvheaders_size ] = 0; // double null terminate + m_recvheaders = n; + } + } + } + + return HTTPRECEIVER_RUN_OK; +} + +int wa::Components::WAC_Network_HTTPGet::get_status() // returns 0 if connecting, 1 if reading headers, 2 if reading content, -1 if error. +{ + if ( m_http_state < 0 ) + return HTTPRECEIVER_STATUS_ERROR; + + if ( m_http_state < 2 ) + return HTTPRECEIVER_STATUS_CONNECTING; + + if ( m_http_state == 2 ) + return HTTPRECEIVER_STATUS_READING_HEADERS; + + if ( m_http_state == 3 ) + return HTTPRECEIVER_STATUS_READING_CONTENT; + + return HTTPRECEIVER_STATUS_ERROR; +} + +int wa::Components::WAC_Network_HTTPGet::getreplycode() // returns 0 if none yet, otherwise returns http reply code. +{ + if ( !m_reply ) + return 0; + + char *p = m_reply; + + while ( p && *p && *p != ' ' ) + p++; // skip over HTTP/x.x + + if ( !p || !*p ) + return 0; + + return atoi( ++p ); +} + +size_t wa::Components::WAC_Network_HTTPGet::bytes_available() +{ + if ( m_con && m_http_state == 3 ) + return m_con->recv_bytes_available(); + + return 0; +} + +size_t wa::Components::WAC_Network_HTTPGet::get_bytes( char *buf, size_t len ) +{ + if ( m_con && m_http_state == 3 ) + { + if ( zlibStream ) + { + // TODO: benski> we need to pick a better buffer size + // either alloca() and use the passed in length + // or malloc a buffer based on the constructor-initted buffer size + char temp[ 8192 ] = { 0 }; + int size = (int)m_con->peek_bytes( temp, 8192 ); + if ( size ) + { + zlibStream->next_in = reinterpret_cast<Bytef *>( temp ); + zlibStream->avail_in = (uInt)size; + zlibStream->next_out = reinterpret_cast<Bytef *>( buf ); + zlibStream->avail_out = (uInt)len; + + int zlib_err = inflate( zlibStream, Z_SYNC_FLUSH ); + + if ( zlib_err == Z_OK || zlib_err == Z_STREAM_END ) + { + m_con->recv_bytes( 0, size - zlibStream->avail_in ); // since we only peeked above + return len - zlibStream->avail_out; + } + else + return 0; // TODO: should we do something else here? + } + } + else + return m_con->recv_bytes( buf, len ); + } + + return 0; +} + +size_t wa::Components::WAC_Network_HTTPGet::peek_bytes( char *buf, size_t len ) +{ + if ( m_con && m_http_state == 3 ) + { + if ( zlibStream ) + return 0; // TODO: benski> how are we going to do peek_bytes, since the inflater saves state? + else + return m_con->peek_bytes( buf, len ); + } + + return 0; +} + +uint64_t wa::Components::WAC_Network_HTTPGet::content_length() +{ + const char *p = getheader( "Content-Length" ); + if ( p && *p ) + return strtoull( p, 0, 10 ); + else + { + // TODO need to check this further for reliability! + // Helps to handle responses without content-length + if ( m_recvheaders_size > 0 && bytes_available() > 0 ) + return bytes_available() - m_recvheaders_size; + } + return 0; +} + +void wa::Components::WAC_Network_HTTPGet::seterrstr( const char *str ) +{ + if ( m_errstr ) + free( m_errstr ); + + m_errstr = _strdup( str ); +} + +void wa::Components::WAC_Network_HTTPGet::AllowCompression() +{ + allowCompression = true; +} + +void wa::Components::WAC_Network_HTTPGet::reset_headers() +{ + if ( m_sendheaders ) + { + free( m_sendheaders ); + m_sendheaders = 0; + } +} + +void wa::Components::WAC_Network_HTTPGet::set_accept_all_reply_codes() +{ + accept_all_reply_codes = true; +} + +void wa::Components::WAC_Network_HTTPGet::set_persistent() +{ + persistent = true; +} + + +size_t wa::Components::WAC_Network_HTTPGet::AddRef() +{ + return this->_reference_count.fetch_add( 1 ); +} + +size_t wa::Components::WAC_Network_HTTPGet::Release() +{ + std::size_t l_reference_count = this->_reference_count.fetch_sub( 1 ); + if ( l_reference_count == 0 ) + delete this; + + return l_reference_count; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_Network_HTTPGet +START_DISPATCH; +CB( ADDREF, AddRef ) +CB( RELEASE, Release ) +VCB( API_HTTPRECEIVER_OPEN, open ) +VCB( API_HTTPRECEIVER_ADDHEADER, addheader ) +VCB( API_HTTPRECEIVER_ADDHEADERVALUE, addheadervalue ) +VCB( API_HTTPRECEIVER_CONNECT, connect ) +CB( API_HTTPRECEIVER_RUN, run ) +CB( API_HTTPRECEIVER_GETSTATUS, get_status ) +CB( API_HTTPRECEIVER_GETBYTESAVAILABLE, bytes_available ) +CB( API_HTTPRECEIVER_GETBYTES, get_bytes ) +CB( API_HTTPRECEIVER_PEEKBYTES, peek_bytes ) +CB( API_HTTPRECEIVER_GETHEADER, getheader ) +CB( API_HTTPRECEIVER_GETCONTENTLENGTH, content_length ) +CB( API_HTTPRECEIVER_GETALLHEADERS, getallheaders ) +CB( API_HTTPRECEIVER_GETREPLYCODE, getreplycode ) +CB( API_HTTPRECEIVER_GETREPLY, getreply ) +CB( API_HTTPRECEIVER_GETERROR, geterrorstr ) +CB( API_HTTPRECEIVER_GETCONNECTION, get_con ) +VCB( API_HTTPRECEIVER_ALLOW_COMPRESSION, AllowCompression ) +VCB( API_HTTPRECEIVER_RESET_HEADERS, reset_headers ) +CB( API_HTTPRECEIVER_GET_URL, get_url ) +VCB( API_HTTPRECEIVER_SET_SENDBUFSIZE, set_sendbufsize ) +VCB( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES, set_accept_all_reply_codes ) +VCB( API_HTTPRECEIVER_SET_PERSISTENT, set_persistent ) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_network/wac_network_http_receiver.h b/Src/Components/wac_network/wac_network_http_receiver.h new file mode 100644 index 00000000..70a22dd4 --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver.h @@ -0,0 +1,166 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: httpget.h - JNL interface for doing HTTP GETs. +** License: see jnetlib.h +** +** Usage: +** 1. Create a WAC_Network_HTTPGet object, optionally specifying a wa::Components::WAC_Network_AsyncDNS +** object to use (or NULL for none, or WAC_NETWORK_CONNECTION_AUTODNS for auto), +** and the receive buffer size, and a string specifying proxy (or NULL +** for none). See note on proxy string below. +** 2. call addheader() to add whatever headers you want. It is recommended to +** add at least the following two: +** addheader("User-Agent:MyApp (Mozilla)"); +*/// addheader("Accept:*/*"); +/* ( the comment weirdness is there so I Can do the star-slash :) +** 3. Call connect() with the URL you wish to GET (see URL string note below) +** 4. Call run() once in a while, checking to see if it returns -1 +** (if it does return -1, call geterrorstr() to see what the error is). +** (if it returns 1, no big deal, the connection has closed). +** 5. While you're at it, you can call bytes_available() to see if any data +** from the http stream is available, or getheader() to see if any headers +** are available, or getreply() to see the HTTP reply, or getallheaders() +** to get a double null terminated, null delimited list of headers returned. +** 6. If you want to read from the stream, call get_bytes (which returns how much +** was actually read). +** 7. content_length() is a helper function that uses getheader() to check the +** content-length header. +** 8. Delete ye' ol' object when done. +** +** Proxy String: +** should be in the format of host:port, or user@host:port, or +** user:password@host:port. if port is not specified, 80 is assumed. +** URL String: +** should be in the format of http://user:pass@host:port/requestwhatever +** note that user, pass, port, and /requestwhatever are all optional :) +** note that also, http:// is really not important. if you do poo:// +** or even leave out the http:// altogether, it will still work. +*/ + +#ifndef NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H +#define NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H + +#include <atomic> + +#include <QtCore> + +#include <zlib.h> + + +#include "wac_network_connection.h" + +#include "wac_network_http_receiver_api.h" + +#include "foundation/error.h" + +//#define WAC_NETWORK_CONNECTION_AUTODNS API_DNS_AUTODNS + +namespace wa +{ + namespace Components + { + class WAC_Network_HTTPGet : public api_httpreceiver + { + public: + WAC_Network_HTTPGet( api_dns *p_dns = API_DNS_AUTODNS, size_t p_recvbufsize = PACKET_SIZE, const char *p_proxy = NULL ); + ~WAC_Network_HTTPGet(); + + void open( api_dns *p_dns = API_DNS_AUTODNS, size_t p_recvbufsize = PACKET_SIZE, const char *p_proxy = NULL ); + + void set_sendbufsize( size_t p_sendbufsize = PACKET_SIZE ); // call if you're going to POST or do any kind of bidirectional communications + int set_recv_buffer_size( size_t p_new_buffer_size ); + + void addheader( const char *header ); + void addheadervalue( const char *header, const char *value ); + + void connect( const char *url, int ver = 0, const char *requestmethod = "GET" ); + + int run(); // returns: 0 if all is OK. -1 if error (call geterrorstr()). 1 if connection closed. + + int get_status(); // returns 0 if connecting, 1 if reading headers, 2 if reading content, -1 if error. + + const char *getallheaders(); // double null terminated, null delimited list + char *getheader( const char *headername ); + + const char *getreply() { return m_reply; } + int getreplycode(); // returns 0 if none yet, otherwise returns http reply code. + + const char *geterrorstr() { return m_errstr; } + + size_t bytes_available(); + size_t get_bytes( char *buf, size_t len ); + size_t peek_bytes( char *buf, size_t len ); + + uint64_t content_length(); + + api_connection *get_con() { return m_con; } + + void AllowCompression(); + void reset_headers(); + + const char *get_url() { return m_http_url; } + + void set_accept_all_reply_codes(); // call this if you want to retrieve content even though a 404 (etc) was returned + void set_persistent(); + static void set_proxy( const char *p_proxy ); + + protected: + static char *get_proxy(); + void reinit(); + void deinit( bool p_full = true ); + void seterrstr( const char *str ); + + void do_parse_url( const char *url, char **host, unsigned short *port, char **req, char **lp ); + void do_encode_mimestr( char *in, char *out ); + + size_t AddRef(); + size_t Release(); + + + api_dns *m_dns = API_DNS_AUTODNS; + WAC_Network_Connection *m_con = NULL; + size_t m_recvbufsize = 0; + + int m_http_state; + + unsigned short m_http_port; + char *m_http_url; + char *m_http_host; + char *m_http_lpinfo; + char *m_http_request; + char *m_http_content_type; + + char *m_http_proxylpinfo = 0; + char *m_http_proxyhost = 0; + unsigned short m_http_proxyport = 0; + + char *m_sendheaders = 0; + char *m_recvheaders; + size_t m_recvheaders_size = 0; + char *m_reply; + + char *m_errstr; + bool allowCompression = false; + + size_t m_sendbufsize = 0; + + /* gzip stuff */ + z_stream *zlibStream = 0; + + bool accept_all_reply_codes = false; + bool persistent = false; + + static char *g_proxy; + + protected: + RECVS_DISPATCH; + + private: + volatile std::atomic<std::size_t> _reference_count = 1; + }; + } +} + +#endif //!NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H diff --git a/Src/Components/wac_network/wac_network_http_receiver_api.cpp b/Src/Components/wac_network/wac_network_http_receiver_api.cpp new file mode 100644 index 00000000..691bd2b9 --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver_api.cpp @@ -0,0 +1 @@ +#include "wac_network_http_receiver_api.h" diff --git a/Src/Components/wac_network/wac_network_http_receiver_api.h b/Src/Components/wac_network/wac_network_http_receiver_api.h new file mode 100644 index 00000000..7249700b --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver_api.h @@ -0,0 +1,233 @@ +#pragma once +#ifndef __WASABI_API_HTTPGETH +#define __WASABI_API_HTTPGETH + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#include "wac_network_dns_api.h" +#include "wac_network_connection_api.h" + +enum +{ + HTTPRECEIVER_STATUS_ERROR = -1, + HTTPRECEIVER_STATUS_CONNECTING = 0, + HTTPRECEIVER_STATUS_READING_HEADERS = 1, + HTTPRECEIVER_STATUS_READING_CONTENT = 2, +}; + +enum +{ + HTTPRECEIVER_RUN_ERROR = -1, + HTTPRECEIVER_RUN_OK = 0, + HTTPRECEIVER_RUN_CONNECTION_CLOSED = 1, +}; + + +class NOVTABLE api_httpreceiver : public Dispatchable +{ +protected: + api_httpreceiver() {} + ~api_httpreceiver() {} + +public: + void open( api_dns *dns = API_DNS_AUTODNS, size_t recvbufsize = PACKET_SIZE, const char *proxy = NULL ); + + void addheader( const char *header ); + void AddHeaderValue( const char *header, const char *value ); + void reset_headers(); + + char *getheader( char *headername ); + const char *getallheaders(); // double null terminated, null delimited list + + void connect( const char *url, int ver = 0, const char *requestmethod = "GET" ); + + int run(); // see HTTPRECEIVER_RUN_* enum for return values + int get_status(); // see HTTPRECEIVER_STATUS_* enum for return values + + int bytes_available(); + int get_bytes( void *buf, int len ); + int peek_bytes( void *buf, int len ); + + uint64_t content_length(); + + int getreplycode(); // returns 0 if none yet, otherwise returns http reply code. + const char *GetReply(); + + const char *geterrorstr(); + + api_connection *GetConnection(); + + void AllowCompression(); + const char *get_url(); // might not be the same as what you passed in if a redirect happened + + void set_sendbufsize( int sendbufsize = PACKET_SIZE ); // call if you're going to POST or do any kind of bidirectional communications + void set_accept_all_reply_codes(); + void set_persistent(); + + DISPATCH_CODES + { + API_HTTPRECEIVER_OPEN = 10, + + API_HTTPRECEIVER_ADDHEADER = 20, + API_HTTPRECEIVER_ADDHEADERVALUE = 30, + + API_HTTPRECEIVER_CONNECT = 40, + + API_HTTPRECEIVER_RUN = 50, + API_HTTPRECEIVER_GETSTATUS = 60, + + API_HTTPRECEIVER_GETBYTESAVAILABLE = 70, + API_HTTPRECEIVER_GETBYTES = 80, + API_HTTPRECEIVER_PEEKBYTES = 90, + + API_HTTPRECEIVER_GETHEADER = 100, + API_HTTPRECEIVER_GETCONTENTLENGTH = 110, + API_HTTPRECEIVER_GETALLHEADERS = 120, + + API_HTTPRECEIVER_GETREPLYCODE = 130, + API_HTTPRECEIVER_GETREPLY = 140, + + API_HTTPRECEIVER_GETERROR = 150, + API_HTTPRECEIVER_GETCONNECTION = 160, + + API_HTTPRECEIVER_ALLOW_COMPRESSION = 170, + + API_HTTPRECEIVER_RESET_HEADERS = 180, + + API_HTTPRECEIVER_GET_URL = 190, + + API_HTTPRECEIVER_SET_SENDBUFSIZE = 200, + API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES = 210, + API_HTTPRECEIVER_SET_PERSISTENT = 220, + }; + +}; + +inline void api_httpreceiver::open( api_dns *dns, size_t recvbufsize, const char *proxy ) +{ + _voidcall( API_HTTPRECEIVER_OPEN, dns, recvbufsize, proxy ); +} + + +inline void api_httpreceiver::addheader( const char *header ) +{ + _voidcall( API_HTTPRECEIVER_ADDHEADER, header ); +} + +inline void api_httpreceiver::AddHeaderValue( const char *header, const char *value ) +{ + _voidcall( API_HTTPRECEIVER_ADDHEADERVALUE, header, value ); +} + +inline void api_httpreceiver::reset_headers() +{ + _voidcall( API_HTTPRECEIVER_RESET_HEADERS ); +} + + +inline char *api_httpreceiver::getheader( char *headername ) +{ + return _call( API_HTTPRECEIVER_GETHEADER, (char *)NULL, headername ); +} + +inline const char *api_httpreceiver::getallheaders() +{ + return _call( API_HTTPRECEIVER_GETALLHEADERS, (const char *)NULL ); +} + + +inline void api_httpreceiver::connect( const char *url, int ver, const char *requestmethod ) +{ + _voidcall( API_HTTPRECEIVER_CONNECT, url, ver, requestmethod ); +} + + +inline int api_httpreceiver::run() +{ + return _call( API_HTTPRECEIVER_RUN, (int)HTTPRECEIVER_RUN_ERROR ); +} + +inline int api_httpreceiver::get_status() +{ + return _call( API_HTTPRECEIVER_GETSTATUS, (int)HTTPRECEIVER_STATUS_ERROR ); +} + + +inline int api_httpreceiver::bytes_available() +{ + return _call( API_HTTPRECEIVER_GETBYTESAVAILABLE, (int)0 ); +} + +inline int api_httpreceiver::get_bytes( void *buf, int len ) +{ + return _call( API_HTTPRECEIVER_GETBYTES, (int)0, buf, len ); +} + +inline int api_httpreceiver::peek_bytes( void *buf, int len ) +{ + return _call( API_HTTPRECEIVER_PEEKBYTES, (int)0, buf, len ); +} + + +inline uint64_t api_httpreceiver::content_length() +{ + return _call( API_HTTPRECEIVER_GETCONTENTLENGTH, (uint64_t)0 ); +} + + +inline int api_httpreceiver::getreplycode() +{ + return _call( API_HTTPRECEIVER_GETREPLYCODE, 0 ); +} + +inline const char *api_httpreceiver::GetReply() +{ + return _call( API_HTTPRECEIVER_GETREPLY, (const char *)NULL ); +} + + +inline const char *api_httpreceiver::geterrorstr() +{ + return _call( API_HTTPRECEIVER_GETERROR, (const char *)NULL ); +} + + +inline api_connection *api_httpreceiver::GetConnection() +{ + return _call( API_HTTPRECEIVER_GETCONNECTION, (api_connection *)NULL ); +} + + +inline void api_httpreceiver::AllowCompression() +{ + _voidcall( API_HTTPRECEIVER_ALLOW_COMPRESSION ); +} + +inline const char *api_httpreceiver::get_url() +{ + return _call( API_HTTPRECEIVER_GET_URL, (const char *)0 ); +} + + +inline void api_httpreceiver::set_sendbufsize( int sendbufsize ) +{ + _voidcall( API_HTTPRECEIVER_SET_SENDBUFSIZE, sendbufsize ); +} + +inline void api_httpreceiver::set_accept_all_reply_codes() +{ + _voidcall( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES ); +} + +inline void api_httpreceiver::set_persistent() +{ + _voidcall( API_HTTPRECEIVER_SET_PERSISTENT ); +} + +// {12475CD9-1BA3-4665-B395-F87DBF31E30F} +static const GUID httpreceiverGUID = +{ 0x12475cd9, 0x1ba3, 0x4665, { 0xb3, 0x95, 0xf8, 0x7d, 0xbf, 0x31, 0xe3, 0xf } }; + + +#endif
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_receiver_factory.cpp b/Src/Components/wac_network/wac_network_http_receiver_factory.cpp new file mode 100644 index 00000000..491ee89a --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver_factory.cpp @@ -0,0 +1,81 @@ +#define GUID_EQUALS_DEFINED + +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_http_receiver.h" +#include "wac_network_http_receiver_api.h" +#include "wac_network_http_receiver_factory.h" + + +static const std::string _serviceName = "HTTPGet Service"; + + +FOURCC JNL_HTTPGetFactory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *JNL_HTTPGetFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID JNL_HTTPGetFactory::GetGUID() +{ + return httpreceiverGUID; +} + +void *JNL_HTTPGetFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + api_httpreceiver *ifc = new wa::Components::WAC_Network_HTTPGet( GetGlobalDNS() ); + + JNL::close_socketlib(); // new JNL_HTTPGet will call open_socketlib also, so we can release now + + // if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; +} + +int JNL_HTTPGetFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_HTTPGetFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_httpreceiver *httpget = static_cast<api_httpreceiver *>( ifc ); + if ( httpget ) + httpget->Release(); + + return 1; +} + +const char *JNL_HTTPGetFactory::GetTestString() +{ + return NULL; +} + +int JNL_HTTPGetFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + +#define CBCLASS JNL_HTTPGetFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_receiver_factory.h b/Src/Components/wac_network/wac_network_http_receiver_factory.h new file mode 100644 index 00000000..998f56cf --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_receiver_factory.h @@ -0,0 +1,27 @@ +#ifndef NULLSOFT_HTTPGET_FACTORYH +#define NULLSOFT_HTTPGET_FACTORYH + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +class JNL_HTTPGetFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + + void *GetInterface( int global_lock ); + int SupportNonLockingInterface(); + int ReleaseInterface( void *ifc ); + + const char *GetTestString(); + int ServiceNotify( int msg, int param1, int param2 ); + +protected: + RECVS_DISPATCH; +}; + +#endif //!NULLSOFT_HTTPGET_FACTORYH
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_server.cpp b/Src/Components/wac_network/wac_network_http_server.cpp new file mode 100644 index 00000000..d7158e45 --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server.cpp @@ -0,0 +1,291 @@ +/* +** JNetLib +** Copyright (C) 2001 Nullsoft, Inc. +** Author: Justin Frankel +** File: wac_network_http_server.cpp - JNL HTTP GET/POST serving implementation +** License: see jnetlib.h +** +** This class just manages the http reply/sending, not where the data +** comes from, etc. +*/ + +#include "netinc.h" +#include "util.h" + +#include "wac_network_http_server.h" + +/* + States for m_state: + -1 error (connection closed, etc) + 0 not read request yet. + 1 reading headers + 2 headers read, have not sent reply + 3 sent reply + 4 closed +*/ + +wa::Components::WAC_Network_HTTP_Server::WAC_Network_HTTP_Server( WAC_Network_Connection *con ) +{ + m_con = con; + m_state = 0; + m_reply_headers = 0; + m_reply_string = 0; + m_recv_request = 0; + m_errstr = 0; + m_reply_ready = 0; + m_method = 0; + http_ver = 0; + keep_alive = 0; +} + +wa::Components::WAC_Network_HTTP_Server::~WAC_Network_HTTP_Server() +{ + free( m_recv_request ); + free( m_reply_string ); + free( m_reply_headers ); + free( m_errstr ); + free( m_method ); + + m_con->Release(); +} + +static size_t strlen_whitespace( const char *str ) +{ + size_t size = 0; + while ( str && *str && *str != ' ' && *str != '\r' && *str != '\n' ) + { + str++; + size++; + } + + return size; +} + +int wa::Components::WAC_Network_HTTP_Server::run() +{ // returns: < 0 on error, 0 on connection close, 1 if reading request, 2 if reply not sent, 3 if reply sent, sending data. + int cnt = 0; +run_again: + m_con->run(); + if ( m_con->get_state() == WAC_Network_Connection::STATE_ERROR ) + { + seterrstr( m_con->get_errstr() ); + return -1; + } + + if ( m_con->get_state() == WAC_Network_Connection::STATE_CLOSED ) + return 4; + + if ( m_state == 0 ) + { + if ( m_con->recv_lines_available() > 0 ) + { + char *buf = (char *)malloc( m_con->recv_bytes_available() - 1 ); + m_con->recv_line( buf, m_con->recv_bytes_available() - 1 ); + free( m_recv_request ); + m_recv_request = (char *)malloc( strlen( buf ) + 2 ); + strcpy( m_recv_request, buf ); + m_recv_request[ strlen( m_recv_request ) + 1 ] = 0; + + free( buf ); + buf = m_recv_request; + + while ( buf && *buf ) + buf++; + + while ( buf >= m_recv_request && *buf != ' ' ) + buf--; + + if ( strncmp( buf + 1, "HTTP", 4 ) )// || strncmp(m_recv_request,"GET ",3)) + { + seterrstr( "malformed HTTP request" ); + m_state = -1; + } + else + { + http_ver = atoi( buf + 8 ); + + size_t method_len = strlen_whitespace( m_recv_request ); + m_method = (char *)malloc( method_len + 1 ); + memcpy( m_method, m_recv_request, method_len ); + m_method[ method_len ] = 0; + + m_state = 1; + cnt = 0; + if ( buf >= m_recv_request ) + buf[ 0 ] = buf[ 1 ] = 0; + + buf = strstr( m_recv_request, "?" ); + if ( buf ) + { + *buf++ = 0; // change &'s into 0s now. + char *t = buf; + int stat = 1; + while ( t && *t ) + { + if ( *t == '&' && !stat ) + { + stat = 1; + *t = 0; + } + else + stat = 0; + + t++; + } + } + } + } + else if ( !cnt++ ) + goto run_again; + } + if ( m_state == 1 ) + { + if ( !cnt++ && m_con->recv_lines_available() < 1 ) + goto run_again; + + while ( m_con->recv_lines_available() > 0 ) + { + char buf[ 4096 ] = { 0 }; + m_con->recv_line( buf, 4096 ); + if ( !buf[ 0 ] ) + { + m_state = 2; + break; + } + + recvheaders.Add( buf ); + } + } + if ( m_state == 2 ) + { + if ( m_reply_ready ) + { + // send reply + m_con->send_string( (char *)( m_reply_string ? m_reply_string : "HTTP/1.1 200 OK" ) ); + m_con->send_string( "\r\n" ); + + if ( m_reply_headers ) + m_con->send_string( m_reply_headers ); + + m_con->send_string( "\r\n" ); + m_state = 3; + } + } + if ( m_state == 3 ) + { + // nothing. + } + + return m_state; +} + +const char *wa::Components::WAC_Network_HTTP_Server::get_request_file() +{ + // file portion of http request + if ( !m_recv_request ) + return NULL; + + char *t = m_recv_request; + while ( t && *t && *t != ' ' ) + t++; + + if ( !t || !*t ) + return NULL; + + while ( t && *t && *t == ' ' ) + t++; + + return t; +} + +const char *wa::Components::WAC_Network_HTTP_Server::get_request_parm( const char *parmname ) // parameter portion (after ?) +{ + const char *t = m_recv_request; + while ( t && *t ) t++; + if ( t ) t++; + while ( t && *t ) + { + while ( t && *t && *t == '&' ) t++; + if ( !_strnicmp( t, parmname, strlen( parmname ) ) && t[ strlen( parmname ) ] == '=' ) + { + return t + strlen( parmname ) + 1; + } + + t += strlen( t ) + 1; + } + + return NULL; +} + +const char *wa::Components::WAC_Network_HTTP_Server::getheader( const char *headername ) +{ + return recvheaders.GetHeader( headername ); +} + +void wa::Components::WAC_Network_HTTP_Server::set_reply_string( const char *reply_string ) // should be HTTP/1.1 OK or the like +{ + free( m_reply_string ); + m_reply_string = (char *)malloc( strlen( reply_string ) + 1 ); + strcpy( m_reply_string, reply_string ); +} + +void wa::Components::WAC_Network_HTTP_Server::add_reply_header( const char *header ) // "Connection: close" for example +{ + // if they've specified a content-length, then we can keep alive an HTTP/1.1 connection + if ( !keep_alive && http_ver == 1 && !_strnicmp( header, "Content-Length", 14 ) ) + keep_alive = 1; + + if ( m_reply_headers ) + { + char *tmp = (char *)malloc( strlen( m_reply_headers ) + strlen( header ) + 3 ); + strcpy( tmp, m_reply_headers ); + strcat( tmp, header ); + strcat( tmp, "\r\n" ); + + free( m_reply_headers ); + m_reply_headers = tmp; + } + else + { + m_reply_headers = (char *)malloc( strlen( header ) + 3 ); + strcpy( m_reply_headers, header ); + strcat( m_reply_headers, "\r\n" ); + } +} + +void wa::Components::WAC_Network_HTTP_Server::reset() +{ + free( m_recv_request ); m_recv_request = 0; + free( m_reply_string ); m_reply_string = 0; + free( m_reply_headers ); m_reply_headers = 0; + free( m_errstr ); m_errstr = 0; + free( m_method ); m_method = 0; + + m_reply_ready = 0; + m_state = 0; + keep_alive = 0; +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_Network_HTTP_Server + +START_DISPATCH; +CB( API_HTTPSERV_RUN, run ); +CB( API_HTTPSERV_GETERRSTR, geterrorstr ); +CB( API_HTTPSERV_GETREQUESTFILE, get_request_file ); +CB( API_HTTPSERV_GETREQUESTPARM, get_request_parm ); +CB( API_HTTPSERV_GETALLHEADERS, getallheaders ); +CB( API_HTTPSERV_GETHEADER, getheader ); +VCB( API_HTTPSERV_SETREPLYSTR, set_reply_string ); +VCB( API_HTTPSERV_SETREPLYHEADER, set_reply_header ); +VCB( API_HTTPSERV_SENDREPLY, send_reply ); +CB( API_HTTPSERV_BYTESINQUEUE, bytes_inqueue ); +CB( API_HTTPSERV_BYTESCANSEND, bytes_cansend ); +VCB( API_HTTPSERV_WRITEBYTES, write_bytes ); +VCB( API_HTTPSERV_CLOSE, close ); +CB( API_HTTPSERV_GETCON, get_con ); +CB( API_HTTPSERV_GETMETHOD, get_method ); +END_DISPATCH; diff --git a/Src/Components/wac_network/wac_network_http_server.h b/Src/Components/wac_network/wac_network_http_server.h new file mode 100644 index 00000000..839ed87f --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server.h @@ -0,0 +1,83 @@ +/* +** JNetLib +** Copyright (C) 2001 Nullsoft, Inc. +** Author: Justin Frankel +** File: wac_network_http_server.h - JNL interface for doing HTTP GET/POST serving. +** License: see jnetlib.h +** This class just manages the http reply/sending, not where the data +** comes from, etc. +** for a mini-web server see wac_network_web_server.h +*/ + +#ifndef NULLSOFT_WAC_NETWORK_HTTP_SERVER_H +#define NULLSOFT_WAC_NETWORK_HTTP_SERVER_H + +#include "headers.h" + +#include "wac_network_http_server_api.h" + +#include "wac_network_connection.h" + +namespace wa +{ + namespace Components + { + class WAC_Network_HTTP_Server : public api_httpserv + { + public: + WAC_Network_HTTP_Server( WAC_Network_Connection *con = NULL ); + ~WAC_Network_HTTP_Server(); + + int run(); // returns: < 0 on error, 0 on request not read yet, 1 if reading headers, 2 if reply not sent, 3 if reply sent, sending data. 4 on connection closed. + + const char *geterrorstr() { return m_errstr; } + + // use these when state returned by run() is 2 + const char *get_request_file(); // file portion of http request + const char *get_request_parm( const char *parmname ); // parameter portion (after ?) + const char *getallheaders() { return recvheaders.GetAllHeaders(); } // double null terminated, null delimited list + const char *getheader( const char *headername ); + const char *get_method() { return m_method; } + + void set_reply_string( const char *reply_string ); // should be HTTP/1.1 OK or the like + void add_reply_header( const char *header ); // i.e. "content-size: 12345" + + void send_reply() { m_reply_ready = 1; } // send reply, state will advance to 3. + + ////////// sending data /////////////// + int bytes_inqueue() { if ( m_state == 3 || m_state == -1 || m_state == 4 ) return (int)m_con->send_bytes_in_queue(); else return 0; } + int bytes_cansend() { if ( m_state == 3 ) return (int)m_con->send_bytes_available(); else return 0; } + void write_bytes( char *bytes, int length ) { m_con->send( bytes, length ); } + + void close( int quick ) { m_con->close( quick ); m_state = 4; } + + api_connection *get_con() { return m_con; } + + void reset(); // prepare for another request on the same connection (HTTP/1.1) + + int get_http_version() { return http_ver; } + int get_keep_alive() { return keep_alive; } + + protected: + void seterrstr( const char *str ) { if ( m_errstr ) free( m_errstr ); m_errstr = _strdup( str ); } + + int m_reply_ready; + int m_state; + int http_ver; + int keep_alive; + + char *m_errstr; + char *m_reply_headers; + char *m_reply_string; + JNL_Headers recvheaders; + char *m_recv_request; // either double-null terminated, or may contain parameters after first null. + char *m_method; + + WAC_Network_Connection *m_con; + + RECVS_DISPATCH; + }; + } +} + +#endif //!NULLSOFT_WAC_NETWORK_HTTP_SERVER_H diff --git a/Src/Components/wac_network/wac_network_http_server_api.cpp b/Src/Components/wac_network/wac_network_http_server_api.cpp new file mode 100644 index 00000000..0a250649 --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server_api.cpp @@ -0,0 +1 @@ +#include "wac_network_http_server_api.h"
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_server_api.h b/Src/Components/wac_network/wac_network_http_server_api.h new file mode 100644 index 00000000..9866ab6c --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server_api.h @@ -0,0 +1,135 @@ +#ifndef __API_HTTPSERV_H_ +#define __API_HTTPSERV_H_ + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#include "wac_network_connection_api.h" + +class api_httpserv : public Dispatchable +{ +protected: + api_httpserv() {} + ~api_httpserv() {} + +public: + DISPATCH_CODES + { + API_HTTPSERV_RUN = 10, + API_HTTPSERV_GETERRSTR = 20, + API_HTTPSERV_GETREQUESTFILE = 30, + API_HTTPSERV_GETREQUESTPARM = 40, + API_HTTPSERV_GETALLHEADERS = 50, + API_HTTPSERV_GETHEADER = 60, + API_HTTPSERV_SETREPLYSTR = 70, + API_HTTPSERV_SETREPLYHEADER = 80, + API_HTTPSERV_SENDREPLY = 90, + API_HTTPSERV_BYTESINQUEUE = 100, + API_HTTPSERV_BYTESCANSEND = 110, + API_HTTPSERV_WRITEBYTES = 120, + API_HTTPSERV_CLOSE = 130, + API_HTTPSERV_GETCON = 140, + API_HTTPSERV_GETMETHOD = 150, + }; + + int run(); + char *geterrorstr(); + char *get_request_file(); + char *get_request_parm( char *parmname ); + char *getallheaders(); + char *getheader( char *headername ); + + void set_reply_string( char *reply_string ); + void set_reply_header( char *header ); + void send_reply(); + + int bytes_inqueue(); + int bytes_cansend(); + + void write_bytes( char *bytes, int length ); + void close( int quick ); + + api_connection *get_con(); + const char *get_method(); // GET or POST or HEAD or whatnot +}; + +inline int api_httpserv::run() +{ + return _call( API_HTTPSERV_RUN, (int)0 ); +} + +inline char *api_httpserv::geterrorstr() +{ + return _call( API_HTTPSERV_GETERRSTR, (char *)NULL ); +} + +inline char *api_httpserv::get_request_file() +{ + return _call( API_HTTPSERV_GETREQUESTFILE, (char *)NULL ); +} + +inline char *api_httpserv::get_request_parm( char *parmname ) +{ + return _call( API_HTTPSERV_GETREQUESTPARM, (char *)NULL, parmname ); +} + +inline char *api_httpserv::getallheaders() +{ + return _call( API_HTTPSERV_GETALLHEADERS, (char *)NULL ); +} + +inline char *api_httpserv::getheader( char *headername ) +{ + return _call( API_HTTPSERV_GETHEADER, (char *)NULL, headername ); +} + +inline void api_httpserv::set_reply_string( char *reply_string ) +{ + _voidcall( API_HTTPSERV_SETREPLYSTR, reply_string ); +} + +inline void api_httpserv::set_reply_header( char *header ) +{ + _voidcall( API_HTTPSERV_SETREPLYHEADER, header ); +} + +inline void api_httpserv::send_reply() +{ + _voidcall( API_HTTPSERV_SENDREPLY ); +} + +inline int api_httpserv::bytes_inqueue() +{ + return _call( API_HTTPSERV_BYTESINQUEUE, (int)0 ); +} + +inline int api_httpserv::bytes_cansend() +{ + return _call( API_HTTPSERV_BYTESCANSEND, (int)0 ); +} + +inline void api_httpserv::write_bytes( char *bytes, int length ) +{ + _voidcall( API_HTTPSERV_WRITEBYTES, bytes, length ); +} + +inline void api_httpserv::close( int quick ) +{ + _voidcall( API_HTTPSERV_CLOSE, quick ); +} + +inline api_connection *api_httpserv::get_con() +{ + return _call( API_HTTPSERV_GETCON, (api_connection *)NULL ); +} + +inline const char *api_httpserv::get_method() +{ + return _call( API_HTTPSERV_GETMETHOD, (const char *)0 ); +} + +// {105ADFDC-0D82-44f0-AA52-FB911401A04C} +static const GUID httpservGUID = +{ 0x105adfdc, 0xd82, 0x44f0, { 0xaa, 0x52, 0xfb, 0x91, 0x14, 0x1, 0xa0, 0x4c } }; + +#endif
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_http_server_factory.cpp b/Src/Components/wac_network/wac_network_http_server_factory.cpp new file mode 100644 index 00000000..16d3a83b --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server_factory.cpp @@ -0,0 +1,87 @@ +#define GUID_EQUALS_DEFINED + +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_http_server.h" +#include "wac_network_http_server_api.h" +#include "wac_network_http_server_factory.h" + + +static const std::string _serviceName = "HTTPServ Service"; + + +FOURCC JNL_HttpServFactory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *JNL_HttpServFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID JNL_HttpServFactory::GetGUID() +{ + return httpservGUID; +} + +void *JNL_HttpServFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + api_httpserv *ifc = new wa::Components::WAC_Network_HTTP_Server; + + //if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + + return ifc; + +} + +int JNL_HttpServFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_HttpServFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_httpserv *httpserv = static_cast<api_httpserv *>( ifc ); + wa::Components::WAC_Network_HTTP_Server *jnl_httpserv = static_cast<wa::Components::WAC_Network_HTTP_Server *>( httpserv ); + + delete jnl_httpserv; + + JNL::close_socketlib(); + + return 1; +} + +const char *JNL_HttpServFactory::GetTestString() +{ + return NULL; +} + +int JNL_HttpServFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif +#define CBCLASS JNL_HttpServFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; diff --git a/Src/Components/wac_network/wac_network_http_server_factory.h b/Src/Components/wac_network/wac_network_http_server_factory.h new file mode 100644 index 00000000..49b3ba1c --- /dev/null +++ b/Src/Components/wac_network/wac_network_http_server_factory.h @@ -0,0 +1,27 @@ +#ifndef NULLSOFT_HTTPSERV_FACTORYH +#define NULLSOFT_HTTPSERV_FACTORYH + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +class JNL_HttpServFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + + void *GetInterface( int global_lock ); + int SupportNonLockingInterface(); + int ReleaseInterface( void *ifc ); + + const char *GetTestString(); + int ServiceNotify( int msg, int param1, int param2 ); + +protected: + RECVS_DISPATCH; +}; + +#endif
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_onconncb_api.cpp b/Src/Components/wac_network/wac_network_onconncb_api.cpp new file mode 100644 index 00000000..156ae47c --- /dev/null +++ b/Src/Components/wac_network/wac_network_onconncb_api.cpp @@ -0,0 +1 @@ +#include "wac_network_onconncb_api.h" diff --git a/Src/Components/wac_network/wac_network_onconncb_api.h b/Src/Components/wac_network/wac_network_onconncb_api.h new file mode 100644 index 00000000..e7bd0db8 --- /dev/null +++ b/Src/Components/wac_network/wac_network_onconncb_api.h @@ -0,0 +1,43 @@ +#ifndef __WASABI_API_WEBSERV_ONCONNCB_H +#define __WASABI_API_WEBSERV_ONCONNCB_H + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" +//#include "listen.h" + +class api_webserv; +class api_pagegenerator; +class api_httpserv; + +class JNL_Listen; + +class api_onconncb : public Dispatchable +{ +protected: + api_onconncb() {} + ~api_onconncb() {} + + public: + api_pagegenerator *onConnection( api_httpserv *serv, int port ); + void destroyConnection( api_pagegenerator *conn ); + + DISPATCH_CODES + { + API_ONCONNCB_ONCONNECTION = 10, + API_ONCONNCB_DESTROYCONNECTION = 20, + }; + + api_webserv *caller = NULL; +}; + +inline api_pagegenerator *api_onconncb::onConnection( api_httpserv *serv, int port ) +{ + return _call( API_ONCONNCB_ONCONNECTION, (api_pagegenerator *)0, serv, port ); +} + +inline void api_onconncb::destroyConnection( api_pagegenerator *connection ) +{ + _voidcall( API_ONCONNCB_DESTROYCONNECTION, connection ); +} + +#endif // !__WASABI_API_WEBSERV_ONCONNCB_H diff --git a/Src/Components/wac_network/wac_network_page_generator_api.cpp b/Src/Components/wac_network/wac_network_page_generator_api.cpp new file mode 100644 index 00000000..5423eea8 --- /dev/null +++ b/Src/Components/wac_network/wac_network_page_generator_api.cpp @@ -0,0 +1 @@ +#include "wac_network_page_generator_api.h" diff --git a/Src/Components/wac_network/wac_network_page_generator_api.h b/Src/Components/wac_network/wac_network_page_generator_api.h new file mode 100644 index 00000000..250946bf --- /dev/null +++ b/Src/Components/wac_network/wac_network_page_generator_api.h @@ -0,0 +1,36 @@ +#ifndef NULLSOFT_API_PAGEGENERATOR_H +#define NULLSOFT_API_PAGEGENERATOR_H + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +class NOVTABLE api_pagegenerator : public Dispatchable +{ +protected: + api_pagegenerator() {} + ~api_pagegenerator() {} + +public: + DISPATCH_CODES + { + API_PAGEGENERATOR_GETDATA = 10, + API_PAGEGENERATOR_ISNONBLOCKING = 20, + }; + + int GetData( char *buf, int size ); + int IsNonBlocking(); + //void destruct(); +}; + +inline int api_pagegenerator::GetData( char *buf, int size ) +{ + return _call( API_PAGEGENERATOR_GETDATA, (int)0, buf, size ); +} + +inline int api_pagegenerator::IsNonBlocking() +{ + return _call( API_PAGEGENERATOR_ISNONBLOCKING, (int)0 ); +} + +#endif // !NULLSOFT_API_PAGEGENERATOR_H + diff --git a/Src/Components/wac_network/wac_network_ssl_connection.cpp b/Src/Components/wac_network/wac_network_ssl_connection.cpp new file mode 100644 index 00000000..fb03cf8e --- /dev/null +++ b/Src/Components/wac_network/wac_network_ssl_connection.cpp @@ -0,0 +1,329 @@ +//#ifdef USE_SSL +//#include "netinc.h" +//#include "util.h" +//#include "connection.h" +#include "wac_network_ssl_connection.h" + +SSL_CTX *sslContext = 0; + +#ifdef _DEBUG + +extern "C" void apps_ssl_info_callback( const SSL * s, int where, int ret ) +{ + /* + ** DEBUG INFO HERE + */ +} +#endif + +/* +** Well, you should probably change this based on like... +** well, you're level of trust heh +** For now, this basically trusts all certs :) +** +*/ +#if 0 +extern "C" int verify_callback( int ok, X509_STORE_CTX * ctx ) +{ + /* For certificate verification */ + int verify_depth = 0; + int verify_error = X509_V_OK; + + char buf[ 1024 ] = { 0 }; + X509 *err_cert = X509_STORE_CTX_get_current_cert( ctx ); + int err = X509_STORE_CTX_get_error( ctx ); + int depth = X509_STORE_CTX_get_error_depth( ctx ); + X509_NAME_oneline( X509_get_subject_name( err_cert ), buf, sizeof( buf ) ); + + if ( !ok ) + { + if ( verify_depth >= depth ) + { + ok = 1; + verify_error = X509_V_OK; + } + else + { + ok = 0; + verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; + } + } + switch ( ctx->error ) + { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + X509_NAME_oneline( X509_get_issuer_name( ctx->current_cert ), buf, sizeof( buf ) ); + break; + + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + break; + + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + break; + } + return ok; +} +#endif + +JNL_SSL_Connection::JNL_SSL_Connection() : forceConnect( false ), m_ssl( 0 ), m_bsslinit( false ), m_bcontextowned( true ) +{ + m_bsslinit = true; +} + + +JNL_SSL_Connection::JNL_SSL_Connection( SSL *pssl, api_dns *dns, size_t sendbufsize, size_t recvbufsize ) : WAC_Network_Connection( dns, sendbufsize, recvbufsize ), forceConnect( false ) +{ + m_ssl = pssl; + m_bsslinit = false; + + if ( m_ssl ) + { + m_bcontextowned = false; + } + else + { + m_bcontextowned = true; + } + + if ( m_bcontextowned == false ) + { + return; + } + + m_bsslinit = true; + + + /* See the SSL states in our own callback */ +#ifdef _DEBUG + // SSL_CTX_set_info_callback(m_app_ctx, apps_ssl_info_callback); +#endif + + /* Set the certificate verification callback */ + //SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER, verify_callback); + + /* Not sure what this does */ + //SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_CLIENT); + + return; +} + +int JNL_SSL_Connection::socket_connect() +{ + int retval; + + if ( m_bcontextowned == false ) + { + /* + ** WTF? + */ + return -1; + } + if ( m_ssl != NULL ) + { + return -1; + } + + retval = WAC_Network_Connection::socket_connect(); + + if ( retval != 0 ) + { + if ( ERRNO != EINPROGRESS ) + { + return retval; // benski> if the underlying socket hasn't connected yet, then we can't start the SSL connection + /* + ** Joshua Teitelbaum 3/2/2006 + ** Fatal error here + */ + } + } + + // moved from InitSSL() as no need to create this unless + // we're actually going to use it which helps slow loads + if ( !sslContext ) + { + sslContext = SSL_CTX_new( SSLv23_client_method() ); + if ( sslContext ) + { + SSL_CTX_set_verify( sslContext, SSL_VERIFY_NONE, NULL ); + } + else + { + return -1; + } + } + + m_ssl = SSL_new( sslContext ); + + if ( m_ssl == NULL ) + { + return -1; + } + + /* Tell that we are in connect mode */ + SSL_set_connect_state( m_ssl ); + + /* Set socket descriptor with the socket we already have open */ + if ( SSL_set_fd( m_ssl, m_socket ) != 0 ) + return -1; + + return retval; +} + +void JNL_SSL_Connection::socket_shutdown() +{ + if ( m_ssl ) + SSL_shutdown( m_ssl ); + + WAC_Network_Connection::socket_shutdown(); + + if ( m_ssl ) + { + SSL_free( m_ssl ); + m_ssl = NULL; + } + + return; +} + +void JNL_SSL_Connection::run( size_t max_send_bytes, size_t max_recv_bytes, size_t *bytes_sent, size_t *bytes_rcvd ) +{ + if ( !m_bsslinit ) + { + int rval = SSL_accept( m_ssl ); + if ( rval == -1 ) + { + int e = SSL_get_error( m_ssl, rval ); + + if ( !( ( e == SSL_ERROR_WANT_READ ) || ( e == SSL_ERROR_WANT_WRITE ) ) ) + { + m_state = STATE_ERROR; + } + + return; + } + else + { + m_bsslinit = true; + } + } + + /** + ** benski - march 2, 2006 + **if the underlying socket didn't connected yet, we need to try the SSL connection again + */ + if ( forceConnect ) + { + if ( init_ssl_connection() == false ) + { + return; + } + } + + WAC_Network_Connection::run( max_send_bytes, max_recv_bytes, bytes_sent, bytes_rcvd ); +} + +/* +** init_ssl_connection: +** Returns true, meaning can continue +** Else, cannot continue with underlying run +** side effects: +** sets forceConnect +*/ +bool JNL_SSL_Connection::init_ssl_connection() +{ + if ( m_ssl == NULL ) + { + /* + ** WTF? + ** cascade up. + */ + return true; + } + + int retval = SSL_connect( m_ssl ); + + if ( retval < 0 ) + { + int err = SSL_get_error( m_ssl, retval ); + + switch ( err ) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_CONNECT: + forceConnect = true; + break; + // fall through + default: // TODO: benski> MOST other errors are OK, (especially "want read" and "want write", but we need to think through all the scenarios here + forceConnect = false; + } + } + else if ( retval ) + { + /* + ** success + */ + forceConnect = false; + } + + /* + ** If retval == 0 + ** socket is closed, or serious error occurred. + ** cascade up. + */ + + return forceConnect == false; +} + +void JNL_SSL_Connection::on_socket_connected( void ) +{ + init_ssl_connection(); +} + +void JNL_SSL_Connection::connect( SOCKET s, sockaddr *addr, socklen_t length ) +{ + /* + ** Joshua Teitelbaum 2/01/2006 + ** No need to close + ** This is the reason for divergence as well as setting + ** the connect state + */ + + m_socket = s; + address = (sockaddr *)malloc( length ); + memcpy( address, addr, length ); + + m_remote_port = 0; + if ( m_socket != -1 ) + { + SET_SOCK_BLOCK( m_socket, 0 ); + m_state = STATE_CONNECTED; + SSL_set_fd( m_ssl, m_socket ); + } + else + { + m_errorstr = _strdup( "invalid socket passed to connect" ); + m_state = STATE_ERROR; + } +} + +ssize_t JNL_SSL_Connection::socket_recv( char *buf, size_t len, int options ) +{ + return SSL_read( m_ssl, buf, (int)len ); +} + +ssize_t JNL_SSL_Connection::socket_send( const char *buf, size_t len, int options ) +{ + return SSL_write( m_ssl, buf, (int)len ); +} + +JNL_SSL_Connection::~JNL_SSL_Connection() +{ + if ( m_ssl ) + { + SSL_free( m_ssl ); + m_ssl = NULL; + } +} +//#endif
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_ssl_connection.h b/Src/Components/wac_network/wac_network_ssl_connection.h new file mode 100644 index 00000000..803e24b4 --- /dev/null +++ b/Src/Components/wac_network/wac_network_ssl_connection.h @@ -0,0 +1,62 @@ +/* +** JNetLib +** Copyright (C) 2000-2006 CockOS, Inc. +** Author: Justin Frankel, Joshua Teitelbaum +** File: sslconnection.h - JNL SSL TCP connection interface +** License: see jnetlib.h +*/ + +#ifndef NULLSOFT_WAC_NETWORK_SSL_CONNECTION_H +#define NULLSOFT_WAC_NETWORK_SSL_CONNECTION_H + +#include "netinc.h" +#include "util.h" + +#include "wac_network_connection.h" + +/* +** AUTOLINK WITH THESE GUYS NOT IN PROJECT HEH HEH :) +** Build and go, for you :) +*/ + +#include <openssl/ssl.h> + +class JNL_SSL_Connection : public WAC_Network_Connection +{ +protected: + SSL *m_ssl; + bool m_bcontextowned; + bool m_bsslinit; + +public: + JNL_SSL_Connection(); + JNL_SSL_Connection( SSL *pssl, api_dns *dns, size_t sendbufsize, size_t recvbufsize ); + virtual ~JNL_SSL_Connection(); + + virtual void connect( SOCKET sock, sockaddr *addr, socklen_t length /* of addr */ ); // used by the listen object, usually not needed by users. + virtual void run( size_t max_send_bytes = -1, size_t max_recv_bytes = -1, size_t *bytes_sent = NULL, size_t *bytes_rcvd = NULL ); + + /* + ** Joshua Teitelbaum 1/27/2006 Adding new BSD socket analogues for SSL compatibility + */ +protected: + virtual void socket_shutdown(); + virtual ssize_t socket_recv( char *buf, size_t len, int options ); + virtual ssize_t socket_send( const char *buf, size_t len, int options ); + virtual int socket_connect(); + virtual void on_socket_connected(); + /* + ** init_ssl_connection: + ** returns true if can continue onwards (could be error, in which case + ** we want the error to cascade through). + ** Else, false if connection was not made, and we have to call this + ** again. + */ + bool init_ssl_connection(); + + bool forceConnect; +}; + +extern SSL_CTX *sslContext; + +#endif //!NULLSOFT_WAC_NETWORK_SSL_CONNECTION_H diff --git a/Src/Components/wac_network/wac_network_ssl_connection_factory.cpp b/Src/Components/wac_network/wac_network_ssl_connection_factory.cpp new file mode 100644 index 00000000..5f4e485a --- /dev/null +++ b/Src/Components/wac_network/wac_network_ssl_connection_factory.cpp @@ -0,0 +1,91 @@ +#ifdef USE_SSL +#define GUID_EQUALS_DEFINED + +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_ssl_connection.h" +#include "wac_network_ssl_connection_factory.h" + + +static const std::string _serviceName = "SSL Connection Service"; +static const std::string _testString = "wac_ssl_connection"; + + +FOURCC JNL_SSL_ConnectionFactory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *JNL_SSL_ConnectionFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + + +GUID JNL_SSL_ConnectionFactory::GetGUID() +{ + return sslConnectionFactoryGUID; +} + +const char *JNL_SSL_ConnectionFactory::GetTestString() +{ + return _testString.c_str(); +} + + +void *JNL_SSL_ConnectionFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + JNL_SSL_Connection *conn = new JNL_SSL_Connection; + conn->set_dns( GetGlobalDNS() ); + + api_connection *ifc = static_cast<api_connection *>( conn ); + + // if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; +} + +int JNL_SSL_ConnectionFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_connection *connection = static_cast<api_connection *>( ifc ); + JNL_SSL_Connection *jnl_connection = static_cast<JNL_SSL_Connection *>( connection ); + + delete jnl_connection; + + JNL::close_socketlib(); + + return 1; +} + + +int JNL_SSL_ConnectionFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_SSL_ConnectionFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + +#define CBCLASS JNL_SSL_ConnectionFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; +#undef CBCLASS + +#endif // !USE_SSL
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_ssl_connection_factory.h b/Src/Components/wac_network/wac_network_ssl_connection_factory.h new file mode 100644 index 00000000..7684ea31 --- /dev/null +++ b/Src/Components/wac_network/wac_network_ssl_connection_factory.h @@ -0,0 +1,27 @@ +#ifndef NULLSOFT_FACTORY_WAC_NETWORK_SSLCONNECTION_H +#define NULLSOFT_FACTORY_WAC_NETWORK_SSLCONNECTION_H + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +class JNL_SSL_ConnectionFactory : public waServiceFactory +{ + public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + const char *GetTestString(); + + void *GetInterface( int global_lock ); + int ReleaseInterface( void *ifc ); + + int SupportNonLockingInterface(); + int ServiceNotify( int msg, int param1, int param2 ); + + protected: + RECVS_DISPATCH; +}; + +#endif // !NULLSOFT_FACTORY_WAC_NETWORK_SSLCONNECTION_H diff --git a/Src/Components/wac_network/wac_network_web_server.cpp b/Src/Components/wac_network/wac_network_web_server.cpp new file mode 100644 index 00000000..b8998770 --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server.cpp @@ -0,0 +1,745 @@ +/* +** JNetLib +** Copyright (C) 2000-2003 Nullsoft, Inc. +** Author: Justin Frankel +** File: wac_network_web_server.cpp - Generic simple webserver baseclass +** License: see jnetlib.h +** see test.cpp for an example of how to use this class +*/ + +#include "wac_network_web_server.h" +#include <zlib.h> +#include "../nu/strsafe.h" + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +class WS_ItemList +{ + public: + WS_ItemList() + { + m_size = 0; m_list = 0; + } + ~WS_ItemList() + { + ::free( m_list ); + } + + void *Add( void *i ); + void *Get( int w ); + void Del( int idx ); + + int GetSize( void ) + { + return m_size; + } + + protected: + void **m_list; + int m_size; +}; + +class WS_conInst +{ + public: + WS_conInst( WAC_Network_Connection *c, JNL_Listen *l, int which_port ); + ~WS_conInst(); + + void close(); + // these will be used by WebServerBaseClass::onConnection yay + wa::Components::WAC_Network_HTTP_Server m_serv; + api_pagegenerator *m_pagegen; + api_onconncb *connCb; + JNL_Listen *m_listener; + int m_port; // port this came in on + time_t m_connect_time; + + z_stream *zlibStream; +}; + + + +void *WS_ItemList::Add( void *i ) +{ + if ( !m_list || !( m_size & 31 ) ) + m_list = ( void ** )::realloc( m_list, sizeof( void * ) * ( m_size + 32 ) ); + + m_list[ m_size++ ] = i; + + return i; +} + +void *WS_ItemList::Get( int w ) +{ + if ( w >= 0 && w < m_size ) + return m_list[ w ]; + + return NULL; +} + +void WS_ItemList::Del( int idx ) +{ + if ( m_list && idx >= 0 && idx < m_size ) + { + m_size--; + if ( idx != m_size ) + ::memcpy( m_list + idx, m_list + idx + 1, sizeof( void * ) * ( m_size - idx ) ); + + if ( !( m_size & 31 ) && m_size ) // resize down + { + m_list = ( void ** )::realloc( m_list, sizeof( void * ) * m_size ); + } + } +} + + +WS_conInst::WS_conInst( WAC_Network_Connection *c, JNL_Listen *l, int which_port ) : m_serv( c ), m_listener( l ), m_port( which_port ), connCb( 0 ) +{ + zlibStream = 0; + m_pagegen = 0; + time( &m_connect_time ); +} + +WS_conInst::~WS_conInst() +{ + if ( connCb && m_pagegen ) + connCb->destroyConnection( m_pagegen ); + + if ( zlibStream ) + deflateEnd( zlibStream ); + + free( zlibStream ); +} + +void WS_conInst::close() +{ + if ( connCb && m_pagegen ) + connCb->destroyConnection( m_pagegen ); + + m_pagegen = 0; + + if ( zlibStream ) + deflateEnd( zlibStream ); + + free( zlibStream ); + zlibStream = 0; + + time( &m_connect_time ); +} + + + + +WebServerBaseClass::~WebServerBaseClass() +{ + int x; + for ( x = 0; x < m_connections->GetSize(); x++ ) + { + delete (WS_conInst *)m_connections->Get( x ); + } + + delete m_connections; + + for ( x = 0; x < m_listeners->GetSize(); x++ ) + { + delete (JNL_Listen *)m_listeners->Get( x ); + } + + delete m_listeners; +} + +WebServerBaseClass::WebServerBaseClass() +{ + allowCompression = false; + m_connections = new WS_ItemList; + m_listeners = new WS_ItemList; + m_listener_rot = 0; + m_timeout_s = 15; + m_max_con = 100; + extraDeflateBuffer = NULL; + extraDeflateBufferSize = 0; + extraDeflateBufferUsed = 0; + connectionCallback = NULL; +} + +void WebServerBaseClass::initForFactory() +{ + if ( m_connections ) + { + for ( int x = 0; x < m_connections->GetSize(); x++ ) + delete (WS_conInst *)m_connections->Get( x ); + + delete m_connections; + } + + if ( m_listeners ) + { + for ( int x = 0; x < m_listeners->GetSize(); x++ ) + delete (JNL_Listen *)m_listeners->Get( x ); + + delete m_listeners; + } + + m_connections = new WS_ItemList; + m_listeners = new WS_ItemList; + m_listener_rot = 0; + m_timeout_s = 15; + m_max_con = 100; +} + + +void WebServerBaseClass::setMaxConnections( int max_con ) +{ + m_max_con = max_con; +} + +void WebServerBaseClass::setRequestTimeout( int timeout_s ) +{ + m_timeout_s = timeout_s; +} + +void WebServerBaseClass::AllowCompression() +{ + allowCompression = true; +} + +int WebServerBaseClass::addListenPort( int port, unsigned long which_interface ) +{ + removeListenPort( port ); + + sockaddr_in address; + memset( &address, 0, sizeof( address ) ); + address.sin_family = AF_INET; + address.sin_port = htons( (unsigned short)port ); + address.sin_addr.s_addr = which_interface ? which_interface : INADDR_ANY; + + JNL_Listen *p = new JNL_Listen(); + p->Initialize( port, (sockaddr *)&address, PF_INET ); + m_listeners->Add( (void *)p ); + + if ( p->is_error() ) + return -1; + + return 0; +} + +void WebServerBaseClass::removeListenPort( int port ) +{ + for ( int x = 0; x < m_listeners->GetSize(); x++ ) + { + JNL_Listen *p = (JNL_Listen *)m_listeners->Get( x ); + if ( p->get_port() == port ) + { + delete p; + m_listeners->Del( x ); + + break; + } + } +} + +void WebServerBaseClass::removeListenIdx( int idx ) +{ + if ( idx >= 0 && idx < m_listeners->GetSize() ) + { + JNL_Listen *p = (JNL_Listen *)m_listeners->Get( idx ); + delete p; + + m_listeners->Del( idx ); + } +} + +int WebServerBaseClass::getListenPort( int idx, int *err ) +{ + JNL_Listen *p = (JNL_Listen *)m_listeners->Get( idx ); + if ( p ) + { + if ( err ) + *err = p->is_error(); + + return p->get_port(); + } + + return 0; +} + +void WebServerBaseClass::attachConnection( WAC_Network_Connection *con, JNL_Listen *listener ) +{ + m_connections->Add( ( void * )new WS_conInst( con, listener, listener->get_port() ) ); +} + +void WebServerBaseClass::run( void ) +{ + int nl; + if ( m_connections->GetSize() < m_max_con && ( nl = m_listeners->GetSize() ) ) + { + JNL_Listen *l = (JNL_Listen *)m_listeners->Get( m_listener_rot++ % nl ); + + WAC_Network_Connection *c = l->get_connect( PACKET_SIZE, PACKET_SIZE ); + if ( c ) + attachConnection( c, l ); + } + + for ( int x = 0; x < m_connections->GetSize(); x++ ) + { + WS_conInst *this_con = (WS_conInst *)m_connections->Get( x ); + switch ( run_connection( this_con ) ) + { + case RUN_CONNECTION_DONE: + { + bool keep_alive = false; + if ( this_con->m_serv.get_keep_alive() ) + { + const char *connection_status = this_con->m_serv.getheader( "Connection" ); + if ( !connection_status || _stricmp( connection_status, "close" ) ) + keep_alive = true; + } + + if ( !keep_alive ) + { + delete this_con; + m_connections->Del( x-- ); + } + else + { + this_con->close(); + this_con->m_serv.reset(); + } + } + break; + case RUN_CONNECTION_ERROR: + case RUN_CONNECTION_TIMEOUT: + delete this_con; + m_connections->Del( x-- ); + break; + } + } +} + +void WebServerBaseClass::SetConnectionCallback( api_onconncb *_connectionCallback ) +{ + _connectionCallback->caller = this; + connectionCallback = _connectionCallback; +} + +void WebServerBaseClass::deflatehelper( WS_conInst *con, char *buf, int l, bool flush ) +{ + char temp[ 8192 ] = { 0 }; + con->zlibStream->next_in = (Bytef *)buf; + con->zlibStream->avail_in = l; + con->zlibStream->avail_out = 0; + + int sent = 0; + if ( flush ) + l = con->m_serv.bytes_cansend(); + + while ( ( !flush && con->zlibStream->avail_in ) || ( flush && !con->zlibStream->avail_out ) ) + { + con->zlibStream->next_out = (Bytef *)temp; + con->zlibStream->avail_out = 8192; + int r = deflate( con->zlibStream, flush ? Z_FINISH : Z_NO_FLUSH ); // TODO: if avail_in != 0, we might have to use Z_SYNC_FLUSH instead + if ( sent + 8192 - (int)con->zlibStream->avail_out > l ) + { + if ( !extraDeflateBuffer ) + { + extraDeflateBufferSize = 8192 - con->zlibStream->avail_out; + extraDeflateBuffer = (char *)malloc( extraDeflateBufferSize ); + memcpy( extraDeflateBuffer, temp, extraDeflateBufferSize ); + } + else + { + // TODO need to sort out this to handle realloc failures... + extraDeflateBuffer = (char *)realloc( extraDeflateBuffer, extraDeflateBufferSize + 8192 - con->zlibStream->avail_out ); + memcpy( extraDeflateBuffer + extraDeflateBufferSize, temp, 8192 - con->zlibStream->avail_out ); + extraDeflateBufferSize += 8192 - con->zlibStream->avail_out; + } + } + else + { + con->m_serv.write_bytes( temp, 8192 - con->zlibStream->avail_out ); + sent += 8192 - con->zlibStream->avail_out; + } + + if ( r != Z_OK ) + break; + } +} + +int WebServerBaseClass::run_connection( WS_conInst *con ) +{ + // TODO: add a Run() method to WC_conInst, passing in connectionCallback + int s = con->m_serv.run(); + if ( s < 0 ) + { + // m_serv.geterrorstr() + return RUN_CONNECTION_ERROR; + } + + if ( s < 2 ) + { + // return 1 if we timed out + if ( time( NULL ) - con->m_connect_time > m_timeout_s ) + return RUN_CONNECTION_TIMEOUT; + else + return RUN_CONNECTION_CONTINUE; + } + + if ( s < 3 ) + { + con->connCb = connectionCallback; + con->m_pagegen = connectionCallback->onConnection( &con->m_serv, con->m_port ); + + const char *compression0 = allowCompression ? con->m_serv.getheader( "Accept-Encoding" ) : 0; + if ( compression0 ) + { + // the compression0 string is a comma (and possibly space) separated list of acceptable formats + char *compression = _strdup( compression0 ); + bool supportsGzip = false, supportsDeflate = false; + size_t l = strlen( compression ); + char *p = compression; + while ( p && *p ) + { + if ( *p == ' ' || *p == ',' ) *p = 0; p++; + } + + for ( char *q = compression; q < compression + l; q++ ) + { + if ( !_stricmp( q, "deflate" ) ) + { + supportsDeflate = true; + q += 7; + } + + if ( !_stricmp( q, "gzip" ) ) + { + supportsGzip = true; + q += 4; + } + } + + free( compression ); + + int windowBits = 0; + + if ( supportsGzip ) + { + windowBits = 15 + 16; /* +16 for gzip */ + compression = _strdup( "gzip" ); + } + else if ( supportsDeflate ) + { + windowBits = 15; + compression = _strdup( "deflate" ); + } + + if ( windowBits ) + { + con->zlibStream = (z_stream *)malloc( sizeof( z_stream ) ); + con->zlibStream->next_in = Z_NULL; + con->zlibStream->avail_in = Z_NULL; + con->zlibStream->next_out = Z_NULL; + con->zlibStream->avail_out = Z_NULL; + con->zlibStream->zalloc = (alloc_func)0; + con->zlibStream->zfree = (free_func)0; + con->zlibStream->opaque = 0; + + int z_err = deflateInit2( con->zlibStream, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + 15 + 16 /* +16 for gzip */, + 8, + Z_DEFAULT_STRATEGY ); + + if ( z_err != Z_OK ) + { + free( con->zlibStream ); + con->zlibStream = 0; + } + + char temp_header[ 1024 ] = "Content-Encoding:"; + StringCchCatA( temp_header, 1024, compression ); + con->m_serv.set_reply_header( temp_header ); + } + } + + return RUN_CONNECTION_CONTINUE; + } + + if ( s < 4 ) + { + if ( !con->m_pagegen ) + { + return con->m_serv.bytes_inqueue() ? RUN_CONNECTION_CONTINUE : RUN_CONNECTION_DONE; + } + + int l = con->m_serv.bytes_cansend(); + if ( l > 0 ) + { + if ( con->zlibStream && extraDeflateBufferSize ) + { + int len = MIN( extraDeflateBufferSize - extraDeflateBufferUsed, l ); + con->m_serv.write_bytes( extraDeflateBuffer + extraDeflateBufferUsed, len ); + extraDeflateBufferUsed += len; + if ( extraDeflateBufferUsed == extraDeflateBufferSize ) + { + extraDeflateBufferUsed = 0; + extraDeflateBufferSize = 0; + + free( extraDeflateBuffer ); + extraDeflateBuffer = NULL; + } + + l -= len; + if ( l == 0 ) + return con->m_serv.bytes_inqueue() ? RUN_CONNECTION_CONTINUE : RUN_CONNECTION_DONE; + } + + char buf[ PACKET_SIZE ] = { 0 }; + if ( l > sizeof( buf ) ) + l = sizeof( buf ); + + l = con->m_pagegen->GetData( buf, l ); + if ( l < ( con->m_pagegen->IsNonBlocking() ? 0 : 1 ) ) // if nonblocking, this is l < 0, otherwise it's l<1 + { + if ( con->zlibStream ) + { + deflatehelper( con, 0, 0, true ); + /* + char temp[8192] = {0}; + con->zlibStream->next_in = 0; + con->zlibStream->avail_in = 0; + con->zlibStream->avail_out = 0; + while(!con->zlibStream->avail_out) + { + con->zlibStream->next_out = (Bytef *)temp; + con->zlibStream->avail_out = 8192; + int r = deflate(con->zlibStream, Z_FINISH); + con->m_serv.write_bytes(temp, 8192 - con->zlibStream->avail_out); + if(r != Z_OK) break; + }*/ + } + + return con->m_serv.bytes_inqueue() ? RUN_CONNECTION_CONTINUE : RUN_CONNECTION_DONE; + } + + if ( l > 0 ) + { + if ( con->zlibStream ) + deflatehelper( con, buf, l, false ); + else + con->m_serv.write_bytes( buf, l ); + } + } + + return RUN_CONNECTION_CONTINUE; + } + + return RUN_CONNECTION_DONE; // we're done by this point +} + +void WebServerBaseClass::url_encode( char *in, char *out, int max_out ) +{ + while ( in && *in && max_out > 4 ) + { + if ( ( *in >= 'A' && *in <= 'Z' ) || + ( *in >= 'a' && *in <= 'z' ) || + ( *in >= '0' && *in <= '9' ) || *in == '.' || *in == '_' || *in == '-' ) + { + *out++ = *in++; + max_out--; + } + else + { + int i = *in++; + *out++ = '%'; + + int b = ( i >> 4 ) & 15; + if ( b < 10 ) + *out++ = '0' + b; + else + *out++ = 'A' + b - 10; + + b = i & 15; + if ( b < 10 ) + *out++ = '0' + b; + else + *out++ = 'A' + b - 10; + + max_out -= 3; + + } + } + + *out = 0; +} + +void WebServerBaseClass::url_decode( char *in, char *out, int maxlen ) +{ + while ( in && *in && maxlen > 1 ) + { + if ( *in == '+' ) + { + in++; + *out++ = ' '; + } + else if ( *in == '%' && in[ 1 ] != '%' && in[ 1 ] ) + { + int a = 0; + int b = 0; + for ( b = 0; b < 2; b++ ) + { + int r = in[ 1 + b ]; + if ( r >= '0' && r <= '9' ) + r -= '0'; + else if ( r >= 'a' && r <= 'z' ) + r -= 'a' - 10; + else if ( r >= 'A' && r <= 'Z' ) + r -= 'A' - 10; + else + break; + + a *= 16; + a += r; + } + + if ( b < 2 ) + *out++ = *in++; + else + { + *out++ = a; + in += 3; + } + } + else + *out++ = *in++; + + maxlen--; + } + + *out = 0; +} + +void WebServerBaseClass::base64decode( char *src, char *dest, int destsize ) +{ + int accum = 0; + int nbits = 0; + while ( src && *src ) + { + int x = 0; + char c = *src++; + if ( c >= 'A' && c <= 'Z' ) + x = c - 'A'; + else if ( c >= 'a' && c <= 'z' ) + x = c - 'a' + 26; + else if ( c >= '0' && c <= '9' ) + x = c - '0' + 52; + else if ( c == '+' ) + x = 62; + else if ( c == '/' ) + x = 63; + else + break; + + accum <<= 6; + accum |= x; + nbits += 6; + + while ( nbits >= 8 ) + { + if ( --destsize <= 0 ) + break; + + nbits -= 8; + *dest++ = (char)( ( accum >> nbits ) & 0xff ); + } + } + + *dest = 0; +} + +void WebServerBaseClass::base64encode( char *in, char *out ) +{ + char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + int shift = 0; + int accum = 0; + + while ( in && *in ) + { + if ( *in ) + { + accum <<= 8; + shift += 8; + accum |= *in++; + } + + while ( shift >= 6 ) + { + shift -= 6; + *out++ = alphabet[ ( accum >> shift ) & 0x3F ]; + } + } + + if ( shift == 4 ) + { + *out++ = alphabet[ ( accum & 0xF ) << 2 ]; + *out++ = '='; + } + else if ( shift == 2 ) + { + *out++ = alphabet[ ( accum & 0x3 ) << 4 ]; + *out++ = '='; + *out++ = '='; + } + + *out++ = 0; +} + +int WebServerBaseClass::parseAuth( char *auth_header, char *out, int out_len ) //returns 0 on unknown auth, 1 on basic +{ + char *authstr = auth_header; + *out = 0; + if ( !auth_header || !*auth_header ) + return 0; + + while ( authstr && *authstr && *authstr == ' ' ) + { + authstr++; + } + + if ( _strnicmp( authstr, "basic ", 6 ) ) + return 0; + + authstr += 6; + + while ( authstr && *authstr && *authstr == ' ' ) + authstr++; + + base64decode( authstr, out, out_len ); + + return 1; +} + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS WebServerBaseClass +START_DISPATCH +VCB( API_WEBSERV_RUN, run ) +VCB( API_WEBSERV_SETMAXCONNECTIONS, setMaxConnections ) +VCB( API_WEBSERV_SETREQUESTTIMEOUT, setRequestTimeout ) +CB( API_WEBSERV_ADDLISTENPORT, addListenPort ) +CB( API_WEBSERV_GETLISTENPORT, getListenPort ) +VCB( API_WEBSERV_REMOVELISTENPORT, removeListenPort ) +VCB( API_WEBSERV_REMOVELISTENIDX, removeListenIdx ) +VCB( API_WEBSERV_ATTACHCONNECTION, attachConnection ) +VCB( API_WEBSERV_URLENCODE, wasabi_url_encode ) +VCB( API_WEBSERV_URLDECODE, wasabi_url_decode ) +VCB( API_WEBSERV_BASE64ENCODE, wasabi_base64encode ) +VCB( API_WEBSERV_BASE64DECODE, wasabi_base64decode ) +CB( API_WEBSERV_PARSEAUTH, wasabi_parseAuth ) +VCB( API_WEBSERV_SETCONNECTIONCB, SetConnectionCallback ); +VCB( API_WEBSERV_ALLOWCOMPRESSION, AllowCompression ) +END_DISPATCH
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_web_server.h b/Src/Components/wac_network/wac_network_web_server.h new file mode 100644 index 00000000..4831f7a7 --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server.h @@ -0,0 +1,180 @@ +/* +** JNetLib +** Copyright (C) 2003 Nullsoft, Inc. +** Author: Justin Frankel +** File: wac_network_web_server.h - Generic simple webserver baseclass +** License: see jnetlib.h +** +** You can derive your object from WebServerBaseClass to do simple web serving. Example: + + class wwwServer : public WebServerBaseClass + { + public: + wwwServer() { } + virtual IPageGenerator *onConnection(wa::Components::WAC_Network_HTTP_Server *serv, int port) + { + serv->set_reply_header("Server:jnetlib_test/0.0"); + if (!strcmp(serv->get_request_file(),"/")) + { + serv->set_reply_string("HTTP/1.1 200 OK"); + serv->set_reply_header("Content-Type:text/html"); + serv->send_reply(); + + return new MemPageGenerator(_strdup("Test Web Server v0.0")); + } + else + { + serv->set_reply_string("HTTP/1.1 404 NOT FOUND"); + serv->send_reply(); + return 0; // no data + } + } + }; + + + wwwServer foo; + foo.addListenPort(8080); + while (1) + { + foo.run(); + Sleep(10); + } + + You will also need to derive from the IPageGenerator interface to provide a data stream, here is an + example of MemPageGenerator: + + class MemPageGenerator : public IPageGenerator + { + public: + virtual ~MemPageGenerator() { free(m_buf); } + MemPageGenerator(char *buf, int buf_len=-1) { m_buf=buf; if (buf_len >= 0) m_buf_size=buf_len; else m_buf_size=strlen(buf); m_buf_pos=0; } + virtual int GetData(char *buf, int size) // return 0 when done + { + int a=m_buf_size-m_buf_pos; + if (a < size) size=a; + memcpy(buf,m_buf+m_buf_pos,size); + m_buf_pos+=size; + return size; + } + + private: + char *m_buf; + int m_buf_size; + int m_buf_pos; + }; + + +** +*/ + + +#ifndef NULLSOFT_WAC_NETWORK_WEB_SERVER_H +#define NULLSOFT_WAC_NETWORK_WEB_SERVER_H + +#include "netinc.h" + +#include "wac_network.h" + +#include "wac_network_web_server_api.h" +#include "wac_network_page_generator_api.h" + + +class WS_ItemList; +class WS_conInst; + +class WebServerBaseClass : public api_webserv +{ +public: + WebServerBaseClass(); + virtual ~WebServerBaseClass(); + + void initForFactory(); //calls constructor in factory + + + void SetConnectionCallback( api_onconncb *_connectionCallback ); + void AllowCompression(); + + // stuff for setting limits/timeouts + void setMaxConnections( int max_con ); + void setRequestTimeout( int timeout_s ); + + // stuff for setting listener port + int addListenPort( int port, unsigned long which_interface = 0 ); // TODO: add Protocol Family as parameter + int getListenPort( int idx, int *err = 0 ); + void removeListenPort( int port ); + void removeListenIdx( int idx ); + + // call this a lot :) + void run( void ); + + // if you want to manually attach a connection, use this: + // you need to specify the port it came in on so the web server can build + // links. + void attachConnection( WAC_Network_Connection *con, JNL_Listen *listener ); + + // these functions are called for external use through wasabi + // so that static properties will work correctly + void wasabi_url_encode( char *in, char *out, int max_out ) + { + url_encode( in, out, max_out ); + } + void wasabi_url_decode( char *in, char *out, int maxlen ) + { + url_decode( in, out, maxlen ); + } + + void wasabi_base64decode( char *src, char *dest, int destsize ) + { + base64decode( src, dest, destsize ); + } + void wasabi_base64encode( char *src, char *dest ) + { + base64encode( src, dest ); + } + int wasabi_parseAuth( char *auth_header, char *out, int out_len ) + { + return parseAuth( auth_header, out, out_len ); + } + + // stats getting functions + + // these can be used externally, as well as are used by the web server + static void url_encode( char *in, char *out, int max_out ); + static void url_decode( char *in, char *out, int maxlen ); + + static void base64decode( char *src, char *dest, int destsize ); + static void base64encode( char *in, char *out ); + + static int parseAuth( char *auth_header, char *out, int out_len );//returns 0 on unknown auth, 1 on basic + +protected: + RECVS_DISPATCH; + +private: + enum + { + RUN_CONNECTION_CONTINUE = 0, + RUN_CONNECTION_DONE = 1, + RUN_CONNECTION_ERROR = 2, + RUN_CONNECTION_TIMEOUT = 3, + }; + + int run_connection( WS_conInst *con ); + + int m_timeout_s; + int m_max_con; + + WS_ItemList *m_listeners; + int m_listener_rot; + WS_ItemList *m_connections; + api_onconncb *connectionCallback; + + bool allowCompression; + char *extraDeflateBuffer; + int extraDeflateBufferSize; + int extraDeflateBufferUsed; + + void deflatehelper( WS_conInst *con, char *buf, int l, bool flush ); +}; + +#endif //!NULLSOFT_WAC_NETWORK_WEB_SERVER_H
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_web_server_api.cpp b/Src/Components/wac_network/wac_network_web_server_api.cpp new file mode 100644 index 00000000..76dc175b --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_api.cpp @@ -0,0 +1 @@ +#include "wac_network_web_server_api.h" diff --git a/Src/Components/wac_network/wac_network_web_server_api.h b/Src/Components/wac_network/wac_network_web_server_api.h new file mode 100644 index 00000000..1ef5843c --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_api.h @@ -0,0 +1,145 @@ +#ifndef __WASABI_API_WEBSERV_H +#define __WASABI_API_WEBSERV_H + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#include "wac_network_dns_api.h" +#include "wac_network_onconncb_api.h" + +class IPageGenerator; +class api_onconncb; +class WAC_Network_Connection; + +class NOVTABLE api_webserv : public Dispatchable +{ +protected: + api_webserv() {} + ~api_webserv() {} + +public: + DISPATCH_CODES + { + API_WEBSERV_RUN = 10, + API_WEBSERV_SETMAXCONNECTIONS = 20, + API_WEBSERV_SETREQUESTTIMEOUT = 30, + API_WEBSERV_ADDLISTENPORT = 40, + API_WEBSERV_GETLISTENPORT = 50, + API_WEBSERV_REMOVELISTENPORT = 60, + API_WEBSERV_REMOVELISTENIDX = 70, + API_WEBSERV_ATTACHCONNECTION = 80, + API_WEBSERV_URLENCODE = 100, + API_WEBSERV_URLDECODE = 110, + API_WEBSERV_BASE64ENCODE = 120, + API_WEBSERV_BASE64DECODE = 130, + API_WEBSERV_PARSEAUTH = 140, + API_WEBSERV_SETCONNECTIONCB = 150, + API_WEBSERV_ALLOWCOMPRESSION = 160, + }; + + //to make onConnection method derivable across dlls, user must make their own api_onconncb and make their own onConnection method + void SetConnectionCallback( api_onconncb *newConnectionCallback ); + void AllowCompression(); + void run( void ); + + void setMaxConnections( int max_con ); + void setRequestTimeout( int timeout_s ); + + int addListenPort( int port, unsigned long which_interface = 0 ); // TODO: add Protocol Family as parameter + int getListenPort( int idx, int *err = 0 ); + + void removeListenPort( int port ); + void removeListenIdx( int idx ); + + void attachConnection( WAC_Network_Connection *con, int port ); + + void url_encode( char *in, char *out, int max_out ); + void url_decode( char *in, char *out, int maxlen ); + + void base64decode( char *src, char *dest, int destsize ); + void base64encode( char *in, char *out ); + + int parseAuth( char *auth_header, char *out, int out_len ); +}; + + +inline void api_webserv::run( void ) +{ + _voidcall( API_WEBSERV_RUN ); +} + +inline void api_webserv::setMaxConnections( int max_con ) +{ + _voidcall( API_WEBSERV_SETMAXCONNECTIONS, max_con ); +} + +inline void api_webserv::setRequestTimeout( int timeout_s ) +{ + _voidcall( API_WEBSERV_SETREQUESTTIMEOUT, timeout_s ); +} + +inline void api_webserv::AllowCompression() +{ + _voidcall( API_WEBSERV_ALLOWCOMPRESSION ); +} + +inline int api_webserv::addListenPort( int port, unsigned long which_interface ) +{ + return _call( API_WEBSERV_ADDLISTENPORT, (int)0, port, which_interface ); +} + +inline int api_webserv::getListenPort( int idx, int *err ) +{ + return _call( API_WEBSERV_GETLISTENPORT, (int)0, idx, err ); +} + +inline void api_webserv::removeListenPort( int port ) +{ + _voidcall( API_WEBSERV_REMOVELISTENPORT, port ); +} + +inline void api_webserv::removeListenIdx( int idx ) +{ + _voidcall( API_WEBSERV_REMOVELISTENIDX, idx ); +} + +inline void api_webserv::attachConnection( WAC_Network_Connection *con, int port ) +{ + _voidcall( API_WEBSERV_ATTACHCONNECTION, con, port ); +} + +inline void api_webserv::url_encode( char *in, char *out, int max_out ) +{ + _voidcall( API_WEBSERV_URLENCODE, in, out, max_out ); +} + +inline void api_webserv::url_decode( char *in, char *out, int maxlen ) +{ + _voidcall( API_WEBSERV_URLDECODE, in, out, maxlen ); +} + +inline void api_webserv::base64decode( char *src, char *dest, int destsize ) +{ + _voidcall( API_WEBSERV_BASE64DECODE, src, dest, destsize ); +} + +inline void api_webserv::base64encode( char *in, char *out ) +{ + _voidcall( API_WEBSERV_BASE64ENCODE, in, out ); +} + +inline int api_webserv::parseAuth( char *auth_header, char *out, int out_len ) +{ + return _call( API_WEBSERV_PARSEAUTH, (int)0, auth_header, out, out_len ); +} + +inline void api_webserv::SetConnectionCallback( api_onconncb *newConnectionCallback ) +{ + _voidcall( API_WEBSERV_SETCONNECTIONCB, newConnectionCallback ); +} + +// {A8880018-C62A-4f58-8B43-F424C9C01787} +static const GUID webservGUID = +{ 0xa8880018, 0xc62a, 0x4f58, { 0x8b, 0x43, 0xf4, 0x24, 0xc9, 0xc0, 0x17, 0x87 } }; + +#endif // !__WASABI_API_WEBSERV_H
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_web_server_factory.cpp b/Src/Components/wac_network/wac_network_web_server_factory.cpp new file mode 100644 index 00000000..d2ae64fc --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_factory.cpp @@ -0,0 +1,87 @@ +#define GUID_EQUALS_DEFINED + +#include "util.h" + +#include "api__wac_network.h" + +#include "wac_network_web_server.h" +#include "wac_network_web_server_api.h" +#include "wac_network_web_server_factory.h" + + +static const std::string _serviceName = "WebServ Service"; + + +FOURCC JNL_WebServFactory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *JNL_WebServFactory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID JNL_WebServFactory::GetGUID() +{ + return webservGUID; +} + +const char *JNL_WebServFactory::GetTestString() +{ + return NULL; +} + + +void *JNL_WebServFactory::GetInterface( int global_lock ) +{ + if ( JNL::open_socketlib() ) + return NULL; + + api_webserv *ifc = new WebServerBaseClass; + + //if (global_lock) + // WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; +} + +int JNL_WebServFactory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_webserv *webserv = static_cast<api_webserv *>( ifc ); + WebServerBaseClass *jnl_webserv = static_cast<WebServerBaseClass *>( webserv ); + delete jnl_webserv; + + JNL::close_socketlib(); + + return 1; +} + + +int JNL_WebServFactory::SupportNonLockingInterface() +{ + return 1; +} + +int JNL_WebServFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS JNL_WebServFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; diff --git a/Src/Components/wac_network/wac_network_web_server_factory.h b/Src/Components/wac_network/wac_network_web_server_factory.h new file mode 100644 index 00000000..577e15a1 --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_factory.h @@ -0,0 +1,27 @@ +#ifndef NULLSOFT_WEBSERV_FACTORY_H +#define NULLSOFT_WEBSERV_FACTORY_H + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +class JNL_WebServFactory : public waServiceFactory +{ +public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + const char *GetTestString(); + + void *GetInterface( int global_lock ); + int ReleaseInterface( void *ifc ); + + int SupportNonLockingInterface(); + int ServiceNotify( int msg, int param1, int param2 ); + +protected: + RECVS_DISPATCH; +}; + +#endif // !NULLSOFT_WEBSERV_FACTORY_H diff --git a/Src/Components/wac_network/wac_network_web_server_listen.cpp b/Src/Components/wac_network/wac_network_web_server_listen.cpp new file mode 100644 index 00000000..43f860c6 --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_listen.cpp @@ -0,0 +1,141 @@ +/* +** JNetLib +** Copyright (C) 2000-2013 Nullsoft, Inc. +** Author: Justin Frankel, Ben Allison +** File: listen.cpp - JNL TCP listen implementation +** License: see jnetlib.h +*/ + +#include "foundation/error.h" + +#include "netinc.h" +#include "util.h" + +#include "wac_network_web_server_listen.h" + + +JNL_Listen::JNL_Listen() +{ + m_port = 0; + m_socket = -1; +} + +int JNL_Listen::Initialize( unsigned short port, sockaddr *which_interface, int family ) +{ + m_port = port; + + char portString[ 32 ] = { 0 }; + sprintf( portString, "%d", (int)port ); + + addrinfo *res; + + addrinfo hints; + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; + hints.ai_addr = which_interface ? which_interface : INADDR_ANY; + + if ( getaddrinfo( NULL, portString, &hints, &res ) == 0 ) + { + int ret = Initialize( res, 0 ); + freeaddrinfo( res ); + + return ret; + } + else + { + return NErr_Error; + } +} + +int JNL_Listen::Initialize( addrinfo *address, size_t index ) +{ + addrinfo *res = address; + + while ( index-- ) + { + res = res->ai_next; + if ( !res ) + return NErr_EndOfEnumeration; + } + + m_socket = ::socket( res->ai_family, res->ai_socktype, res->ai_protocol ); + if ( m_socket < 0 ) + { + freeaddrinfo( res ); + return NErr_Error; + } + else + { + SET_SOCK_BLOCK( m_socket, 0 ); + +#ifndef _WIN32 + int bflag = 1; + setsockopt( m_socket, SOL_SOCKET, SO_REUSEADDR, &bflag, sizeof( bflag ) ); +#endif + + if ( ::bind( m_socket, res->ai_addr, (int)res->ai_addrlen ) ) + { + closesocket( m_socket ); + m_socket = -1; + + return NErr_Error; + } + else if ( ::listen( m_socket, 8 ) == -1 ) + { + closesocket( m_socket ); + m_socket = -1; + + return NErr_Error; + } + } + + return NErr_Success; +} + +JNL_Listen::~JNL_Listen() +{ + if ( m_socket >= 0 ) + { + closesocket( m_socket ); + } +} + +WAC_Network_Connection *JNL_Listen::get_connect( size_t sendbufsize, size_t recvbufsize ) +{ + if ( m_socket < 0 ) + return NULL; + + sockaddr_storage saddr; + socklen_t length = sizeof( saddr ); + + SOCKET s = accept( m_socket, (sockaddr *)&saddr, &length ); + if ( s != -1 ) + { + WAC_Network_Connection *c = new WAC_Network_Connection( NULL, sendbufsize, recvbufsize ); + c->connect( s, (sockaddr *)&saddr, length ); + + return c; + } + + return NULL; +} + +socklen_t JNL_Listen::get_address( sockaddr *address, socklen_t *address_len ) +{ + return getsockname( m_socket, address, address_len ); +} + +unsigned short JNL_Listen::get_port() +{ + if ( !m_port ) + { + sockaddr_in address; + socklen_t namelen = sizeof( address ); + if ( getsockname( m_socket, (sockaddr *)&address, &namelen ) == 0 ) + m_port = ntohs( address.sin_port ); + } + + return m_port; +}
\ No newline at end of file diff --git a/Src/Components/wac_network/wac_network_web_server_listen.h b/Src/Components/wac_network/wac_network_web_server_listen.h new file mode 100644 index 00000000..2ee9bc9c --- /dev/null +++ b/Src/Components/wac_network/wac_network_web_server_listen.h @@ -0,0 +1,43 @@ +/* +** JNetLib +** Copyright (C) 2000-2007 Nullsoft, Inc. +** Author: Justin Frankel +** File: wac_network_web_server_listen.h - JNL interface for opening a TCP listen +** License: see jnetlib.h +** +** Usage: +** 1. create a JNL_Listen object with the port and (optionally) the interface +** to listen on. +** 2. call get_connect() to get any new connections (optionally specifying what +** buffer sizes the connection should be created with) +** 3. check is_error() to see if an error has occured +** 4. call port() if you forget what port the listener is on. +** +*/ + +#ifndef NULLSOFT_WAC_NETWORK_WEB_SERVER_LISTEN_H +#define NULLSOFT_WAC_NETWORK_WEB_SERVER_LISTEN_H + +#include "wac_network_connection.h" + +class JNL_Listen +{ +public: + JNL_Listen(); + ~JNL_Listen(); + + int Initialize( unsigned short port, sockaddr *which_interface = 0, int family = PF_UNSPEC ); + int Initialize( struct addrinfo *address, size_t index ); + + WAC_Network_Connection *get_connect( size_t sendbufsize = 8192, size_t recvbufsize = 8192 ); + unsigned short get_port(); + int is_error( void ) { return ( m_socket < 0 ); } + + socklen_t get_address( sockaddr *address, socklen_t *address_len ); + +protected: + SOCKET m_socket; + unsigned short m_port; +}; + +#endif //!NULLSOFT_WAC_NETWORK_WEB_SERVER_LISTEN_H |