2013-12-05 08:26:21 +08:00
/****************************************************************************
2014-01-07 11:47:11 +08:00
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2013-12-05 08:26:21 +08:00
http : //www.cocos2d-x.org
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-27 10:58:36 +08:00
2013-12-05 11:33:50 +08:00
# include "CCConsole.h"
2013-11-27 10:58:36 +08:00
2013-12-04 10:46:54 +08:00
# include <thread>
2013-12-05 10:28:09 +08:00
# include <algorithm>
2014-02-09 04:46:44 +08:00
# include <functional>
# include <cctype>
# include <locale>
# include <sstream>
2013-11-27 10:58:36 +08:00
# include <stdio.h>
2014-02-13 10:40:57 +08:00
# include <stdlib.h>
2013-12-05 04:26:43 +08:00
# include <time.h>
# include <fcntl.h>
2013-12-05 16:09:38 +08:00
2014-01-04 14:40:22 +08:00
# if defined(_MSC_VER) || defined(__MINGW32__)
2013-12-05 16:09:38 +08:00
# include <io.h>
# include <WS2tcpip.h>
2014-04-11 20:07:54 +08:00
# include <Winsock2.h>
2013-12-05 16:09:38 +08:00
# define bzero(a, b) memset(a, 0, b);
# else
# include <netdb.h>
# include <unistd.h>
2013-12-05 04:26:43 +08:00
# include <arpa/inet.h>
2013-12-04 10:46:54 +08:00
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/un.h>
2014-04-10 18:31:28 +08:00
# include <sys/ioctl.h>
2013-12-05 16:09:38 +08:00
# endif
2013-11-27 10:58:36 +08:00
# include "CCDirector.h"
2013-12-04 10:46:54 +08:00
# include "CCScheduler.h"
2013-12-05 08:57:44 +08:00
# include "CCScene.h"
2014-01-11 11:04:07 +08:00
# include "CCPlatformConfig.h"
2014-01-15 12:05:17 +08:00
# include "platform/CCFileUtils.h"
2014-01-15 09:22:45 +08:00
# include "CCConfiguration.h"
# include "CCTextureCache.h"
2014-02-09 04:46:44 +08:00
# include "CCGLView.h"
2014-03-18 00:42:36 +08:00
# include "base64.h"
2013-12-05 16:09:38 +08:00
NS_CC_BEGIN
2013-11-27 10:58:36 +08:00
2014-02-14 14:54:26 +08:00
//TODO: these general utils should be in a seperate class
2014-02-09 04:46:44 +08:00
//
// Trimming functions were taken from: http://stackoverflow.com/a/217605
//
// trim from start
static std : : string & ltrim ( std : : string & s ) {
s . erase ( s . begin ( ) , std : : find_if ( s . begin ( ) , s . end ( ) , std : : not1 ( std : : ptr_fun < int , int > ( std : : isspace ) ) ) ) ;
return s ;
}
// trim from end
static std : : string & rtrim ( std : : string & s ) {
s . erase ( std : : find_if ( s . rbegin ( ) , s . rend ( ) , std : : not1 ( std : : ptr_fun < int , int > ( std : : isspace ) ) ) . base ( ) , s . end ( ) ) ;
return s ;
}
// trim from both ends
static std : : string & trim ( std : : string & s ) {
return ltrim ( rtrim ( s ) ) ;
}
2014-02-25 11:04:59 +08:00
static std : : vector < std : : string > & split ( const std : : string & s , char delim , std : : vector < std : : string > & elems ) {
2014-02-14 14:54:26 +08:00
std : : stringstream ss ( s ) ;
std : : string item ;
while ( std : : getline ( ss , item , delim ) ) {
elems . push_back ( item ) ;
}
return elems ;
}
2014-02-25 11:04:59 +08:00
static std : : vector < std : : string > split ( const std : : string & s , char delim ) {
2014-02-14 14:54:26 +08:00
std : : vector < std : : string > elems ;
split ( s , delim , elems ) ;
return elems ;
}
2014-02-25 11:04:59 +08:00
//isFloat taken from http://stackoverflow.com/questions/447206/c-isfloat-function
static bool isFloat ( std : : string myString ) {
std : : istringstream iss ( myString ) ;
float f ;
iss > > std : : noskipws > > f ; // noskipws considers leading whitespace invalid
// Check the entire string was consumed and if either failbit or badbit is set
return iss . eof ( ) & & ! iss . fail ( ) ;
}
2014-02-26 23:41:47 +08:00
2014-03-22 21:10:54 +08:00
# if CC_TARGET_PLATFORM != CC_PLATFORM_WINRT && CC_TARGET_PLATFORM != CC_PLATFORM_WP8
2013-12-05 13:51:08 +08:00
// helper free functions
// dprintf() is not defined in Android
// so we add our own 'dpritnf'
static ssize_t mydprintf ( int sock , const char * format , . . . )
{
va_list args ;
2014-01-15 09:22:45 +08:00
char buf [ 16386 ] ;
2013-12-05 13:51:08 +08:00
va_start ( args , format ) ;
vsnprintf ( buf , sizeof ( buf ) , format , args ) ;
va_end ( args ) ;
2014-02-24 12:01:04 +08:00
return send ( sock , buf , strlen ( buf ) , 0 ) ;
2013-12-05 13:51:08 +08:00
}
2014-02-11 16:57:30 +08:00
static void sendPrompt ( int fd )
{
2014-02-11 17:05:10 +08:00
const char prompt [ ] = " > " ;
2014-02-24 12:01:04 +08:00
send ( fd , prompt , sizeof ( prompt ) , 0 ) ;
2014-02-11 16:57:30 +08:00
}
2013-12-13 06:30:22 +08:00
static int printSceneGraph ( int fd , Node * node , int level )
2013-12-05 13:51:08 +08:00
{
2013-12-13 06:30:22 +08:00
int total = 1 ;
2013-12-05 13:51:08 +08:00
for ( int i = 0 ; i < level ; + + i )
2014-02-24 12:01:04 +08:00
send ( fd , " - " , 1 , 0 ) ;
2013-12-05 13:51:08 +08:00
2013-12-13 06:30:22 +08:00
mydprintf ( fd , " %s \n " , node - > getDescription ( ) . c_str ( ) ) ;
2013-12-05 13:51:08 +08:00
2013-12-05 14:07:23 +08:00
for ( const auto & child : node - > getChildren ( ) )
2013-12-13 06:30:22 +08:00
total + = printSceneGraph ( fd , child , level + 1 ) ;
return total ;
2013-12-05 13:51:08 +08:00
}
static void printSceneGraphBoot ( int fd )
{
2014-02-24 12:01:04 +08:00
send ( fd , " \n " , 1 , 0 ) ;
2013-12-05 13:51:08 +08:00
auto scene = Director : : getInstance ( ) - > getRunningScene ( ) ;
2013-12-13 06:30:22 +08:00
int total = printSceneGraph ( fd , scene , 0 ) ;
mydprintf ( fd , " Total Nodes: %d \n " , total ) ;
2014-02-11 16:57:30 +08:00
sendPrompt ( fd ) ;
2013-12-05 13:51:08 +08:00
}
2014-01-15 09:22:45 +08:00
static void printFileUtils ( int fd )
{
FileUtils * fu = FileUtils : : getInstance ( ) ;
mydprintf ( fd , " \n Search Paths: \n " ) ;
auto list = fu - > getSearchPaths ( ) ;
for ( const auto & item : list ) {
mydprintf ( fd , " %s \n " , item . c_str ( ) ) ;
}
mydprintf ( fd , " \n Resolution Order: \n " ) ;
list = fu - > getSearchResolutionsOrder ( ) ;
for ( const auto & item : list ) {
mydprintf ( fd , " %s \n " , item . c_str ( ) ) ;
}
mydprintf ( fd , " \n Writeble Path: \n " ) ;
mydprintf ( fd , " %s \n " , fu - > getWritablePath ( ) . c_str ( ) ) ;
mydprintf ( fd , " \n Full Path Cache: \n " ) ;
auto cache = fu - > getFullPathCache ( ) ;
for ( const auto & item : cache ) {
mydprintf ( fd , " %s -> %s \n " , item . first . c_str ( ) , item . second . c_str ( ) ) ;
}
2014-02-11 16:57:30 +08:00
sendPrompt ( fd ) ;
2014-01-15 09:22:45 +08:00
}
2014-03-22 21:10:54 +08:00
# endif
2014-01-15 09:22:45 +08:00
2014-01-04 14:40:22 +08:00
# if defined(__MINGW32__)
static const char * inet_ntop ( int af , const void * src , char * dst , int cnt )
{
struct sockaddr_in srcaddr ;
memset ( & srcaddr , 0 , sizeof ( struct sockaddr_in ) ) ;
memcpy ( & ( srcaddr . sin_addr ) , src , sizeof ( srcaddr . sin_addr ) ) ;
srcaddr . sin_family = af ;
if ( WSAAddressToString ( ( struct sockaddr * ) & srcaddr , sizeof ( struct sockaddr_in ) , 0 , dst , ( LPDWORD ) & cnt ) ! = 0 )
{
2014-01-09 17:48:37 +08:00
return nullptr ;
2014-01-04 14:40:22 +08:00
}
return dst ;
}
# endif
2013-12-05 13:51:08 +08:00
2014-01-11 11:04:07 +08:00
//
// Free functions to log
//
2014-01-16 03:17:21 +08:00
static void _log ( const char * format , va_list args )
2014-01-11 11:04:07 +08:00
{
char buf [ MAX_LOG_LENGTH ] ;
vsnprintf ( buf , MAX_LOG_LENGTH - 3 , format , args ) ;
strcat ( buf , " \n " ) ;
# if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
__android_log_print ( ANDROID_LOG_DEBUG , " cocos2d-x debug info " , " %s " , buf ) ;
2014-03-22 21:10:54 +08:00
# elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT || CC_TARGET_PLATFORM == CC_PLATFORM_WP8
2014-01-11 11:04:07 +08:00
WCHAR wszBuf [ MAX_LOG_LENGTH ] = { 0 } ;
2014-01-14 12:28:24 +08:00
MultiByteToWideChar ( CP_UTF8 , 0 , buf , - 1 , wszBuf , sizeof ( wszBuf ) ) ;
2014-01-11 11:04:07 +08:00
OutputDebugStringW ( wszBuf ) ;
2014-03-15 01:05:04 +08:00
WideCharToMultiByte ( CP_ACP , 0 , wszBuf , - 1 , buf , sizeof ( buf ) , NULL , FALSE ) ;
2014-02-05 00:59:56 +08:00
printf ( " %s " , buf ) ;
2014-04-15 17:10:11 +08:00
fflush ( stdout ) ;
2014-01-11 11:04:07 +08:00
# else
// Linux, Mac, iOS, etc
fprintf ( stdout , " cocos2d: %s " , buf ) ;
fflush ( stdout ) ;
# endif
2014-03-22 21:10:54 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
2014-01-11 11:04:07 +08:00
Director : : getInstance ( ) - > getConsole ( ) - > log ( buf ) ;
2014-03-22 21:10:54 +08:00
# endif
2014-01-11 11:04:07 +08:00
}
2014-01-16 03:17:21 +08:00
// XXX: Deprecated
void CCLog ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
_log ( format , args ) ;
va_end ( args ) ;
}
void log ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
_log ( format , args ) ;
va_end ( args ) ;
}
2014-01-11 11:04:07 +08:00
2014-03-22 21:10:54 +08:00
# if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)
2013-12-05 13:51:08 +08:00
//
// Console code
//
2013-11-27 10:58:36 +08:00
Console : : Console ( )
2013-12-04 10:46:54 +08:00
: _listenfd ( - 1 )
2013-11-27 10:58:36 +08:00
, _running ( false )
, _endThread ( false )
2014-01-11 09:58:54 +08:00
, _sendDebugStrings ( false )
2013-12-05 16:09:38 +08:00
{
2013-12-05 16:49:05 +08:00
// VS2012 doesn't support initializer list, so we create a new array and assign its elements to '_command'.
2013-12-05 16:09:38 +08:00
Command commands [ ] = {
2014-02-09 13:29:39 +08:00
{ " config " , " Print the Configuration object " , std : : bind ( & Console : : commandConfig , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " debugmsg " , " Whether or not to forward the debug messages on the console. Args: [on | off] " , [ & ] ( int fd , const std : : string & args ) {
2014-02-09 04:46:44 +08:00
if ( args . compare ( " on " ) = = 0 | | args . compare ( " off " ) = = 0 ) {
_sendDebugStrings = ( args . compare ( " on " ) = = 0 ) ;
} else {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " Debug message is: %s \n " , _sendDebugStrings ? " on " : " off " ) ;
2014-02-09 04:46:44 +08:00
}
2014-01-11 09:58:54 +08:00
} } ,
2014-02-09 04:46:44 +08:00
{ " exit " , " Close connection to the console " , std : : bind ( & Console : : commandExit , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-09 13:29:39 +08:00
{ " fileutils " , " Flush or print the FileUtils info. Args: [flush | ] " , std : : bind ( & Console : : commandFileUtils , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " fps " , " Turn on / off the FPS. Args: [on | off] " , [ ] ( int fd , const std : : string & args ) {
2014-02-09 04:46:44 +08:00
if ( args . compare ( " on " ) = = 0 | | args . compare ( " off " ) = = 0 ) {
bool state = ( args . compare ( " on " ) = = 0 ) ;
Director * dir = Director : : getInstance ( ) ;
Scheduler * sched = dir - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( std : : bind ( & Director : : setDisplayStats , dir , state ) ) ;
} else {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " FPS is: %s \n " , Director : : getInstance ( ) - > isDisplayStats ( ) ? " on " : " off " ) ;
2014-02-09 04:46:44 +08:00
}
2014-01-11 09:58:54 +08:00
} } ,
2014-02-09 04:46:44 +08:00
{ " help " , " Print this message " , std : : bind ( & Console : : commandHelp , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-20 11:15:29 +08:00
{ " projection " , " Change or print the current projection. Args: [2d | 3d] " , std : : bind ( & Console : : commandProjection , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " resolution " , " Change or print the window resolution. Args: [width height resolution_policy | ] " , std : : bind ( & Console : : commandResolution , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-09 13:29:39 +08:00
{ " scenegraph " , " Print the scene graph " , std : : bind ( & Console : : commandSceneGraph , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " texture " , " Flush or print the TextureCache info. Args: [flush | ] " , std : : bind ( & Console : : commandTextures , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-20 11:15:29 +08:00
{ " director " , " director commands, type -h or [director help] to list supported directives " , std : : bind ( & Console : : commandDirector , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-25 15:55:01 +08:00
{ " touch " , " simulate touch event via console, type -h or [touch help] to list supported directives " , std : : bind ( & Console : : commandTouch , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-03-18 00:42:36 +08:00
{ " upload " , " upload file. Args: [filename base64_encoded_data] " , std : : bind ( & Console : : commandUpload , this , std : : placeholders : : _1 ) } ,
2014-01-11 09:58:54 +08:00
} ;
2014-02-14 14:54:26 +08:00
;
for ( int i = 0 ; i < sizeof ( commands ) / sizeof ( commands [ 0 ] ) ; + + i )
2013-12-05 16:09:38 +08:00
{
2014-03-18 00:42:36 +08:00
_commands [ commands [ i ] . name ] = commands [ i ] ;
2013-12-05 16:09:38 +08:00
}
2014-03-15 18:13:29 +08:00
_writablePath = FileUtils : : getInstance ( ) - > getWritablePath ( ) ;
2013-12-05 09:38:11 +08:00
}
2013-11-27 10:58:36 +08:00
Console : : ~ Console ( )
{
2014-01-11 09:11:14 +08:00
stop ( ) ;
2013-11-27 10:58:36 +08:00
}
2013-12-04 10:46:54 +08:00
bool Console : : listenOnTCP ( int port )
{
2014-03-18 00:42:36 +08:00
int listenfd = - 1 , n ;
2013-12-04 10:46:54 +08:00
const int on = 1 ;
2013-12-05 10:19:51 +08:00
struct addrinfo hints , * res , * ressave ;
2013-12-04 10:46:54 +08:00
char serv [ 30 ] ;
2013-12-05 13:51:08 +08:00
snprintf ( serv , sizeof ( serv ) - 1 , " %d " , port ) ;
2013-12-04 10:46:54 +08:00
bzero ( & hints , sizeof ( struct addrinfo ) ) ;
hints . ai_flags = AI_PASSIVE ;
2013-12-05 13:51:08 +08:00
hints . ai_family = AF_INET ; // AF_UNSPEC: Do we need IPv6 ?
2013-12-04 10:46:54 +08:00
hints . ai_socktype = SOCK_STREAM ;
2013-12-05 16:09:38 +08:00
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
WSADATA wsaData ;
n = WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ;
# endif
2013-12-04 10:46:54 +08:00
if ( ( n = getaddrinfo ( NULL , serv , & hints , & res ) ) ! = 0 ) {
fprintf ( stderr , " net_listen error for %s: %s " , serv , gai_strerror ( n ) ) ;
return false ;
}
ressave = res ;
do {
listenfd = socket ( res - > ai_family , res - > ai_socktype , res - > ai_protocol ) ;
if ( listenfd < 0 )
2013-12-05 10:19:51 +08:00
continue ; /* error, try next one */
2013-12-04 10:46:54 +08:00
2013-12-05 16:09:38 +08:00
setsockopt ( listenfd , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & on , sizeof ( on ) ) ;
2013-12-04 10:46:54 +08:00
if ( bind ( listenfd , res - > ai_addr , res - > ai_addrlen ) = = 0 )
2013-12-05 10:19:51 +08:00
break ; /* success */
2013-12-04 10:46:54 +08:00
2014-02-24 16:51:08 +08:00
/* bind error, close and try next one */
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
closesocket ( listenfd ) ;
# else
close ( listenfd ) ;
# endif
2013-12-04 10:46:54 +08:00
} while ( ( res = res - > ai_next ) ! = NULL ) ;
if ( res = = NULL ) {
perror ( " net_listen: " ) ;
freeaddrinfo ( ressave ) ;
return false ;
}
2013-12-05 08:26:21 +08:00
2013-12-04 10:46:54 +08:00
listen ( listenfd , 50 ) ;
2013-12-05 08:26:21 +08:00
if ( res - > ai_family = = AF_INET ) {
char buf [ INET_ADDRSTRLEN ] = " " ;
struct sockaddr_in * sin = ( struct sockaddr_in * ) res - > ai_addr ;
2013-12-05 13:51:08 +08:00
if ( inet_ntop ( res - > ai_family , & sin - > sin_addr , buf , sizeof ( buf ) ) ! = NULL )
2014-01-11 09:58:54 +08:00
cocos2d : : log ( " Console: listening on %s : %d " , buf , ntohs ( sin - > sin_port ) ) ;
2013-12-05 13:51:08 +08:00
else
perror ( " inet_ntop " ) ;
} else if ( res - > ai_family = = AF_INET6 ) {
char buf [ INET6_ADDRSTRLEN ] = " " ;
struct sockaddr_in6 * sin = ( struct sockaddr_in6 * ) res - > ai_addr ;
if ( inet_ntop ( res - > ai_family , & sin - > sin6_addr , buf , sizeof ( buf ) ) ! = NULL )
2014-01-11 09:58:54 +08:00
cocos2d : : log ( " Console: listening on %s : %d " , buf , ntohs ( sin - > sin6_port ) ) ;
2013-12-05 08:26:21 +08:00
else
perror ( " inet_ntop " ) ;
}
2013-12-05 13:51:08 +08:00
2013-12-04 10:46:54 +08:00
freeaddrinfo ( ressave ) ;
return listenOnFileDescriptor ( listenfd ) ;
}
bool Console : : listenOnFileDescriptor ( int fd )
2013-11-27 10:58:36 +08:00
{
2014-01-11 09:11:14 +08:00
if ( _running ) {
cocos2d : : log ( " Console already started. 'stop' it before calling 'listen' again " ) ;
return false ;
}
2013-12-04 10:46:54 +08:00
_listenfd = fd ;
2013-11-27 10:58:36 +08:00
_thread = std : : thread ( std : : bind ( & Console : : loop , this ) ) ;
2013-12-04 10:46:54 +08:00
return true ;
2013-11-27 10:58:36 +08:00
}
2014-01-11 09:11:14 +08:00
void Console : : stop ( )
2013-11-27 10:58:36 +08:00
{
2013-12-04 10:46:54 +08:00
if ( _running ) {
_endThread = true ;
_thread . join ( ) ;
}
2013-11-27 10:58:36 +08:00
}
2014-02-14 14:54:26 +08:00
void Console : : addCommand ( const Command & cmd )
2013-12-05 09:38:11 +08:00
{
2014-02-14 14:54:26 +08:00
_commands [ cmd . name ] = cmd ;
2014-02-13 10:40:57 +08:00
}
2013-12-05 08:26:21 +08:00
//
// commands
//
2014-02-09 04:46:44 +08:00
void Console : : commandHelp ( int fd , const std : : string & args )
2013-12-04 10:46:54 +08:00
{
2013-12-05 08:26:21 +08:00
const char help [ ] = " \n Available commands: \n " ;
2014-02-24 12:01:04 +08:00
send ( fd , help , sizeof ( help ) , 0 ) ;
2014-02-14 14:54:26 +08:00
for ( auto it = _commands . begin ( ) ; it ! = _commands . end ( ) ; + + it )
{
auto cmd = it - > second ;
2014-04-08 18:20:06 +08:00
mydprintf ( fd , " \t %s " , cmd . name . c_str ( ) ) ;
ssize_t tabs = strlen ( cmd . name . c_str ( ) ) / 8 ;
2014-02-09 13:29:39 +08:00
tabs = 3 - tabs ;
for ( int j = 0 ; j < tabs ; j + + ) {
2014-02-14 14:54:26 +08:00
mydprintf ( fd , " \t " ) ;
2014-02-09 13:29:39 +08:00
}
2014-04-08 18:20:06 +08:00
mydprintf ( fd , " %s \n " , cmd . help . c_str ( ) ) ;
2014-02-14 14:54:26 +08:00
}
2013-12-05 08:26:21 +08:00
}
2013-12-04 10:46:54 +08:00
2014-02-09 04:46:44 +08:00
void Console : : commandExit ( int fd , const std : : string & args )
2013-12-05 08:26:21 +08:00
{
FD_CLR ( fd , & _read_set ) ;
_fds . erase ( std : : remove ( _fds . begin ( ) , _fds . end ( ) , fd ) , _fds . end ( ) ) ;
2014-02-24 16:51:08 +08:00
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
closesocket ( fd ) ;
# else
close ( fd ) ;
# endif
2013-12-05 08:26:21 +08:00
}
2014-02-09 04:46:44 +08:00
void Console : : commandSceneGraph ( int fd , const std : : string & args )
2013-12-05 08:57:44 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( std : : bind ( & printSceneGraphBoot , fd ) ) ;
}
2014-02-09 04:46:44 +08:00
void Console : : commandFileUtils ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-02-09 04:46:44 +08:00
if ( args . compare ( " flush " ) = = 0 )
{
FileUtils : : getInstance ( ) - > purgeCachedEntries ( ) ;
}
else if ( args . length ( ) = = 0 )
{
sched - > performFunctionInCocosThread ( std : : bind ( & printFileUtils , fd ) ) ;
}
else
{
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: 'flush' or nothing " , args . c_str ( ) ) ;
}
2014-01-15 09:22:45 +08:00
}
2014-02-09 04:46:44 +08:00
void Console : : commandConfig ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
2014-01-15 09:22:45 +08:00
mydprintf ( fd , " %s " , Configuration : : getInstance ( ) - > getInfo ( ) . c_str ( ) ) ;
2014-02-14 14:54:26 +08:00
sendPrompt ( fd ) ;
2014-01-15 09:22:45 +08:00
}
) ;
}
2014-02-09 04:46:44 +08:00
void Console : : commandResolution ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
2014-02-09 04:46:44 +08:00
if ( args . length ( ) = = 0 ) {
auto director = Director : : getInstance ( ) ;
Size points = director - > getWinSize ( ) ;
Size pixels = director - > getWinSizeInPixels ( ) ;
auto glview = director - > getOpenGLView ( ) ;
Size design = glview - > getDesignResolutionSize ( ) ;
ResolutionPolicy res = glview - > getResolutionPolicy ( ) ;
Rect visibleRect = glview - > getVisibleRect ( ) ;
mydprintf ( fd , " Window Size: \n "
" \t %d x %d (points) \n "
" \t %d x %d (pixels) \n "
" \t %d x %d (design resolution) \n "
" Resolution Policy: %d \n "
" Visible Rect: \n "
" \t origin: %d x %d \n "
2014-02-11 17:00:09 +08:00
" \t size: %d x %d \n " ,
2014-02-09 04:46:44 +08:00
( int ) points . width , ( int ) points . height ,
( int ) pixels . width , ( int ) pixels . height ,
( int ) design . width , ( int ) design . height ,
( int ) res ,
( int ) visibleRect . origin . x , ( int ) visibleRect . origin . y ,
( int ) visibleRect . size . width , ( int ) visibleRect . size . height
) ;
} else {
int width , height , policy ;
std : : istringstream stream ( args ) ;
stream > > width > > height > > policy ;
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
2014-02-09 04:46:44 +08:00
Director : : getInstance ( ) - > getOpenGLView ( ) - > setDesignResolutionSize ( width , height , static_cast < ResolutionPolicy > ( policy ) ) ;
} ) ;
}
}
void Console : : commandProjection ( int fd , const std : : string & args )
{
auto director = Director : : getInstance ( ) ;
Scheduler * sched = director - > getScheduler ( ) ;
if ( args . length ( ) = = 0 )
{
char buf [ 20 ] ;
auto proj = director - > getProjection ( ) ;
switch ( proj ) {
case cocos2d : : Director : : Projection : : _2D :
sprintf ( buf , " 2d " ) ;
break ;
case cocos2d : : Director : : Projection : : _3D :
sprintf ( buf , " 3d " ) ;
break ;
case cocos2d : : Director : : Projection : : CUSTOM :
sprintf ( buf , " custom " ) ;
break ;
default :
sprintf ( buf , " unknown " ) ;
break ;
}
2014-02-11 16:14:49 +08:00
mydprintf ( fd , " Current projection: %s \n " , buf ) ;
2014-02-09 04:46:44 +08:00
}
else if ( args . compare ( " 2d " ) = = 0 )
{
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
2014-02-09 04:46:44 +08:00
director - > setProjection ( Director : : Projection : : _2D ) ;
} ) ;
}
else if ( args . compare ( " 3d " ) = = 0 )
{
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
2014-02-09 04:46:44 +08:00
director - > setProjection ( Director : : Projection : : _3D ) ;
} ) ;
}
else
{
2014-02-11 16:14:49 +08:00
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: '2d' or '3d' \n " , args . c_str ( ) ) ;
2014-02-09 04:46:44 +08:00
}
}
void Console : : commandTextures ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-02-09 04:46:44 +08:00
if ( args . compare ( " flush " ) = = 0 )
{
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ ] ( ) {
2014-02-09 04:46:44 +08:00
Director : : getInstance ( ) - > getTextureCache ( ) - > removeAllTextures ( ) ;
}
) ;
}
else if ( args . length ( ) = = 0 )
{
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
2014-02-09 04:46:44 +08:00
mydprintf ( fd , " %s " , Director : : getInstance ( ) - > getTextureCache ( ) - > getCachedTextureInfo ( ) . c_str ( ) ) ;
2014-02-11 16:14:49 +08:00
sendPrompt ( fd ) ;
2014-02-09 04:46:44 +08:00
}
) ;
}
else
{
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: 'flush' or nothing " , args . c_str ( ) ) ;
2014-01-15 09:22:45 +08:00
}
}
2014-02-20 11:15:29 +08:00
void Console : : commandDirector ( int fd , const std : : string & args )
2014-02-19 11:19:29 +08:00
{
2014-02-20 11:15:29 +08:00
auto director = Director : : getInstance ( ) ;
if ( args = = " help " | | args = = " -h " )
{
const char help [ ] = " available director directives: \n "
" \t pause, pause all scheduled timers, the draw rate will be 4 FPS to reduce CPU consumption \n "
2014-03-28 13:50:06 +08:00
" \t end, exit this app. \n "
2014-02-20 11:15:29 +08:00
" \t resume, resume all scheduled timers \n "
" \t stop, Stops the animation. Nothing will be drawn. \n "
" \t start, Restart the animation again, Call this function only if [director stop] was called earlier \n " ;
2014-02-25 11:04:59 +08:00
send ( fd , help , sizeof ( help ) - 1 , 0 ) ;
2014-02-20 11:15:29 +08:00
}
else if ( args = = " pause " )
{
Scheduler * sched = director - > getScheduler ( ) ;
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ ] ( ) {
2014-02-19 11:19:29 +08:00
Director : : getInstance ( ) - > pause ( ) ;
}
) ;
2014-02-20 11:15:29 +08:00
}
else if ( args = = " resume " )
{
director - > resume ( ) ;
}
else if ( args = = " stop " )
{
Scheduler * sched = director - > getScheduler ( ) ;
2014-04-11 20:07:54 +08:00
sched - > performFunctionInCocosThread ( [ ] ( ) {
2014-02-19 11:19:29 +08:00
Director : : getInstance ( ) - > stopAnimation ( ) ;
}
) ;
2014-02-20 11:15:29 +08:00
}
else if ( args = = " start " )
{
director - > startAnimation ( ) ;
}
2014-03-28 13:40:24 +08:00
else if ( args = = " end " )
{
director - > end ( ) ;
}
2014-02-19 11:19:29 +08:00
}
2014-02-25 11:04:59 +08:00
void Console : : commandTouch ( int fd , const std : : string & args )
{
if ( args = = " help " | | args = = " -h " )
{
const char help [ ] = " available touch directives: \n "
2014-02-25 18:17:43 +08:00
" \t tap x y: simulate touch tap at (x,y) \n "
2014-02-25 11:04:59 +08:00
" \t swipe x1 y1 x2 y2: simulate touch swipe from (x1,y1) to (x2,y2). \n " ;
send ( fd , help , sizeof ( help ) - 1 , 0 ) ;
}
else
{
auto argv = split ( args , ' ' ) ;
if ( argv . size ( ) = = 0 )
{
return ;
}
2014-02-25 18:17:43 +08:00
if ( argv [ 0 ] = = " tap " )
2014-02-25 11:04:59 +08:00
{
if ( ( argv . size ( ) = = 3 ) & & ( isFloat ( argv [ 1 ] ) & & isFloat ( argv [ 2 ] ) ) )
{
2014-02-25 16:31:21 +08:00
float x = std : : atof ( argv [ 1 ] . c_str ( ) ) ;
float y = std : : atof ( argv [ 2 ] . c_str ( ) ) ;
2014-02-25 11:04:59 +08:00
2014-04-09 22:53:59 +08:00
srand ( ( unsigned ) time ( nullptr ) ) ;
2014-02-25 11:04:59 +08:00
_touchId = rand ( ) ;
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( [ & ] ( ) {
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesBegin ( 1 , & _touchId , & x , & y ) ;
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesEnd ( 1 , & _touchId , & x , & y ) ;
} ) ;
}
else
{
const char msg [ ] = " touch: invalid arguments. \n " ;
send ( fd , msg , sizeof ( msg ) - 1 , 0 ) ;
}
2014-02-25 11:47:53 +08:00
return ;
}
if ( argv [ 0 ] = = " swipe " )
{
if ( ( argv . size ( ) = = 5 )
& & ( isFloat ( argv [ 1 ] ) ) & & ( isFloat ( argv [ 2 ] ) )
& & ( isFloat ( argv [ 3 ] ) ) & & ( isFloat ( argv [ 4 ] ) ) )
{
2014-02-25 16:31:21 +08:00
float x1 = std : : atof ( argv [ 1 ] . c_str ( ) ) ;
float y1 = std : : atof ( argv [ 2 ] . c_str ( ) ) ;
float x2 = std : : atof ( argv [ 3 ] . c_str ( ) ) ;
float y2 = std : : atof ( argv [ 4 ] . c_str ( ) ) ;
2014-02-25 11:47:53 +08:00
2014-04-09 22:53:59 +08:00
srand ( ( unsigned ) time ( nullptr ) ) ;
2014-02-25 11:47:53 +08:00
_touchId = rand ( ) ;
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-02-25 15:52:37 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
float tempx = x1 , tempy = y1 ;
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesBegin ( 1 , & _touchId , & tempx , & tempy ) ;
2014-02-25 11:47:53 +08:00
} ) ;
float dx = std : : abs ( x1 - x2 ) ;
float dy = std : : abs ( y1 - y2 ) ;
2014-02-25 15:52:37 +08:00
float _x_ = x1 , _y_ = y1 ;
if ( dx > dy )
{
while ( dx > 1 )
{
if ( x1 < x2 )
{
_x_ + = 1 ;
}
if ( x1 > x2 )
{
_x_ - = 1 ;
}
if ( y1 < y2 )
{
_y_ + = dy / dx ;
}
if ( y1 > y2 )
{
_y_ - = dy / dx ;
}
sched - > performFunctionInCocosThread ( [ = ] ( ) {
float tempx = _x_ , tempy = _y_ ;
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesMove ( 1 , & _touchId , & tempx , & tempy ) ;
} ) ;
dx - = 1 ;
}
}
else
{
while ( dy > 1 )
{
if ( x1 < x2 )
{
_x_ + = dx / dy ;
}
if ( x1 > x2 )
{
_x_ - = dx / dy ;
}
if ( y1 < y2 )
{
_y_ + = 1 ;
}
if ( y1 > y2 )
{
_y_ - = 1 ;
}
sched - > performFunctionInCocosThread ( [ = ] ( ) {
float tempx = _x_ , tempy = _y_ ;
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesMove ( 1 , & _touchId , & tempx , & tempy ) ;
} ) ;
dy - = 1 ;
}
}
2014-02-25 15:59:43 +08:00
sched - > performFunctionInCocosThread ( [ = ] ( ) {
float tempx = x2 , tempy = y2 ;
Director : : getInstance ( ) - > getOpenGLView ( ) - > handleTouchesEnd ( 1 , & _touchId , & tempx , & tempy ) ;
2014-02-25 15:52:37 +08:00
} ) ;
2014-02-25 11:47:53 +08:00
}
else
{
const char msg [ ] = " touch: invalid arguments. \n " ;
send ( fd , msg , sizeof ( msg ) - 1 , 0 ) ;
}
2014-02-25 11:04:59 +08:00
}
2014-02-25 11:47:53 +08:00
2014-02-25 11:04:59 +08:00
}
}
2014-04-08 14:52:53 +08:00
static char invalid_filename_char [ ] = { ' : ' , ' / ' , ' \\ ' , ' ? ' , ' % ' , ' * ' , ' < ' , ' > ' , ' " ' , ' | ' , ' \r ' , ' \n ' , ' \t ' } ;
2014-03-18 00:42:36 +08:00
void Console : : commandUpload ( int fd )
2014-02-26 23:41:47 +08:00
{
2014-03-18 00:42:36 +08:00
ssize_t n , rc ;
char buf [ 512 ] , c ;
char * ptr = buf ;
//read file name
for ( n = 0 ; n < sizeof ( buf ) - 1 ; n + + )
2014-02-26 23:41:47 +08:00
{
2014-03-18 00:42:36 +08:00
if ( ( rc = recv ( fd , & c , 1 , 0 ) ) = = 1 )
{
2014-04-08 14:52:53 +08:00
for ( char x : invalid_filename_char )
{
if ( c = = x )
{
const char err [ ] = " upload: invalid file name! \n " ;
send ( fd , err , sizeof ( err ) , 0 ) ;
return ;
}
}
2014-03-18 00:42:36 +08:00
if ( c = = ' ' )
{
break ;
}
2014-04-08 14:52:53 +08:00
* ptr + + = c ;
2014-03-18 00:42:36 +08:00
}
else if ( rc = = 0 )
{
break ;
}
else if ( errno = = EINTR )
{
continue ;
}
else
{
break ;
}
2014-02-26 23:41:47 +08:00
}
2014-03-18 00:42:36 +08:00
* ptr = 0 ;
std : : string filepath = _writablePath + std : : string ( buf ) ;
FILE * fp = fopen ( filepath . c_str ( ) , " wb " ) ;
if ( ! fp )
2014-02-26 23:41:47 +08:00
{
2014-03-18 00:42:36 +08:00
const char err [ ] = " can't create file! \n " ;
send ( fd , err , sizeof ( err ) , 0 ) ;
return ;
2014-02-26 23:41:47 +08:00
}
2014-03-18 00:42:36 +08:00
while ( true )
2014-02-26 23:41:47 +08:00
{
2014-03-18 00:42:36 +08:00
char data [ 4 ] ;
for ( int i = 0 ; i < 4 ; i + + )
{
data [ i ] = ' = ' ;
}
bool more_data ;
readBytes ( fd , data , 4 , & more_data ) ;
if ( ! more_data )
{
break ;
}
unsigned char * decode ;
unsigned char * in = ( unsigned char * ) data ;
int dt = base64Decode ( in , 4 , & decode ) ;
for ( int i = 0 ; i < dt ; i + + )
{
fwrite ( decode + i , 1 , 1 , fp ) ;
}
free ( decode ) ;
2014-02-26 23:41:47 +08:00
}
2014-03-18 00:42:36 +08:00
fclose ( fp ) ;
}
2014-02-26 23:41:47 +08:00
2014-03-20 14:50:02 +08:00
ssize_t Console : : readBytes ( int fd , char * buffer , size_t maxlen , bool * more )
2014-03-18 00:42:36 +08:00
{
2014-04-09 23:54:40 +08:00
size_t n ;
int rc ;
2014-03-18 00:42:36 +08:00
char c , * ptr = buffer ;
* more = false ;
for ( n = 0 ; n < maxlen ; n + + ) {
if ( ( rc = recv ( fd , & c , 1 , 0 ) ) = = 1 ) {
* ptr + + = c ;
if ( c = = ' \n ' ) {
return n ;
}
} else if ( rc = = 0 ) {
return 0 ;
} else if ( errno = = EINTR ) {
continue ;
} else {
return - 1 ;
}
}
* more = true ;
return n ;
2014-02-26 23:41:47 +08:00
}
2014-03-18 00:42:36 +08:00
2013-12-05 09:38:11 +08:00
bool Console : : parseCommand ( int fd )
2013-12-05 08:26:21 +08:00
{
2014-02-18 10:32:32 +08:00
char buf [ 512 ] ;
2014-03-18 00:42:36 +08:00
bool more_data ;
auto h = readBytes ( fd , buf , 6 , & more_data ) ;
if ( h < 0 )
2014-02-14 14:54:26 +08:00
{
2013-12-05 08:26:21 +08:00
return false ;
2014-02-14 14:54:26 +08:00
}
2014-03-18 00:42:36 +08:00
if ( strncmp ( buf , " upload " , 6 ) = = 0 )
{
char c = ' \0 ' ;
recv ( fd , & c , 1 , 0 ) ;
if ( c = = ' ' )
{
commandUpload ( fd ) ;
sendPrompt ( fd ) ;
return true ;
}
else
{
2014-04-08 14:52:53 +08:00
const char err [ ] = " upload: invalid args! Type 'help' for options \n " ;
2014-03-18 00:42:36 +08:00
send ( fd , err , sizeof ( err ) , 0 ) ;
2014-04-08 14:52:53 +08:00
sendPrompt ( fd ) ;
return true ;
2014-03-18 00:42:36 +08:00
}
}
if ( ! more_data )
{
buf [ h ] = 0 ;
}
else
{
char * pb = buf + 6 ;
auto r = readline ( fd , pb , sizeof ( buf ) - 6 ) ;
if ( r < 0 )
{
const char err [ ] = " Unknown error! \n " ;
sendPrompt ( fd ) ;
send ( fd , err , sizeof ( err ) , 0 ) ;
return false ;
}
}
2014-02-14 14:54:26 +08:00
std : : string cmdLine ;
2013-12-05 08:26:21 +08:00
2014-02-14 14:54:26 +08:00
std : : vector < std : : string > args ;
2014-02-18 10:32:32 +08:00
cmdLine = std : : string ( buf ) ;
2014-02-17 23:29:09 +08:00
2014-02-14 14:54:26 +08:00
args = split ( cmdLine , ' ' ) ;
if ( args . empty ( ) )
{
2014-02-17 23:29:09 +08:00
const char err [ ] = " Unknown command. Type 'help' for options \n " ;
2014-02-24 12:01:04 +08:00
send ( fd , err , sizeof ( err ) , 0 ) ;
2014-02-17 23:29:09 +08:00
sendPrompt ( fd ) ;
2014-04-08 14:52:53 +08:00
return true ;
2013-12-05 08:26:21 +08:00
}
2013-12-05 09:38:11 +08:00
2014-02-17 23:29:09 +08:00
auto it = _commands . find ( trim ( args [ 0 ] ) ) ;
2014-02-14 14:54:26 +08:00
if ( it ! = _commands . end ( ) )
{
std : : string args2 ;
2014-04-09 23:54:40 +08:00
for ( size_t i = 1 ; i < args . size ( ) ; + + i )
2014-02-14 14:54:26 +08:00
{
if ( i > 1 )
{
args2 + = ' ' ;
2014-02-09 04:46:44 +08:00
}
2014-02-17 23:29:09 +08:00
args2 + = trim ( args [ i ] ) ;
2014-02-14 14:54:26 +08:00
2013-12-05 09:38:11 +08:00
}
2014-02-14 14:54:26 +08:00
auto cmd = it - > second ;
cmd . callback ( fd , args2 ) ;
2014-03-07 15:12:46 +08:00
} else if ( strcmp ( buf , " \r \n " ) ! = 0 ) {
const char err [ ] = " Unknown command. Type 'help' for options \n " ;
send ( fd , err , sizeof ( err ) , 0 ) ;
2014-03-05 00:07:30 +08:00
}
2013-12-05 08:26:21 +08:00
sendPrompt ( fd ) ;
return true ;
}
//
// Helpers
//
2014-02-11 16:57:30 +08:00
2013-11-27 10:58:36 +08:00
2014-03-20 14:54:09 +08:00
ssize_t Console : : readline ( int fd , char * ptr , size_t maxlen )
2013-12-03 01:57:16 +08:00
{
2014-04-09 23:54:40 +08:00
size_t n ;
int rc ;
2014-02-18 10:32:32 +08:00
char c ;
2013-12-03 01:57:16 +08:00
2014-03-18 00:42:36 +08:00
for ( n = 0 ; n < maxlen - 1 ; n + + ) {
2014-02-24 12:01:04 +08:00
if ( ( rc = recv ( fd , & c , 1 , 0 ) ) = = 1 ) {
2014-02-17 23:29:09 +08:00
* ptr + + = c ;
if ( c = = ' \n ' ) {
2013-12-05 10:19:51 +08:00
break ;
2014-02-14 14:54:26 +08:00
}
2013-12-05 10:19:51 +08:00
} else if ( rc = = 0 ) {
return 0 ;
} else if ( errno = = EINTR ) {
2013-12-03 01:57:16 +08:00
continue ;
} else {
return - 1 ;
}
2013-12-05 10:19:51 +08:00
}
2013-12-03 01:57:16 +08:00
2013-12-05 10:19:51 +08:00
* ptr = 0 ;
return n ;
2013-12-03 01:57:16 +08:00
}
2014-02-26 23:41:47 +08:00
2013-12-05 08:26:21 +08:00
void Console : : addClient ( )
2013-11-27 10:58:36 +08:00
{
2013-12-05 08:26:21 +08:00
struct sockaddr client ;
2013-12-05 10:19:51 +08:00
socklen_t client_len ;
2013-12-05 08:26:21 +08:00
/* new client */
client_len = sizeof ( client ) ;
int fd = accept ( _listenfd , ( struct sockaddr * ) & client , & client_len ) ;
// add fd to list of FD
if ( fd ! = - 1 ) {
FD_SET ( fd , & _read_set ) ;
_fds . push_back ( fd ) ;
_maxfd = std : : max ( _maxfd , fd ) ;
sendPrompt ( fd ) ;
}
}
2014-01-11 09:58:54 +08:00
void Console : : log ( const char * buf )
{
if ( _sendDebugStrings ) {
_DebugStringsMutex . lock ( ) ;
_DebugStrings . push_back ( buf ) ;
_DebugStringsMutex . unlock ( ) ;
}
}
2013-12-05 08:26:21 +08:00
//
// Main Loop
//
void Console : : loop ( )
{
fd_set copy_set ;
2013-12-05 10:19:51 +08:00
struct timeval timeout , timeout_copy ;
2013-11-27 10:58:36 +08:00
2013-12-05 08:26:21 +08:00
_running = true ;
FD_ZERO ( & _read_set ) ;
FD_SET ( _listenfd , & _read_set ) ;
2013-12-05 04:26:43 +08:00
_maxfd = _listenfd ;
2013-12-04 10:46:54 +08:00
2013-12-05 10:19:51 +08:00
timeout . tv_sec = 0 ;
2013-12-05 04:26:43 +08:00
/* 0.016 seconds. Wake up once per frame at 60PFS */
2014-02-03 06:24:58 +08:00
timeout . tv_usec = 16000 ;
2013-11-27 10:58:36 +08:00
2013-12-05 10:19:51 +08:00
while ( ! _endThread ) {
2013-11-27 10:58:36 +08:00
2013-12-05 10:19:51 +08:00
copy_set = _read_set ;
2013-12-04 10:46:54 +08:00
timeout_copy = timeout ;
2014-02-24 17:50:40 +08:00
2013-12-05 10:19:51 +08:00
int nready = select ( _maxfd + 1 , & copy_set , NULL , NULL , & timeout_copy ) ;
2013-11-27 10:58:36 +08:00
2014-01-11 09:58:54 +08:00
if ( nready = = - 1 )
{
/* error */
2013-12-05 10:19:51 +08:00
if ( errno ! = EINTR )
log ( " Abnormal error in select() \n " ) ;
continue ;
2013-12-04 10:46:54 +08:00
}
2014-01-11 09:58:54 +08:00
else if ( nready = = 0 )
{
/* timeout. do somethig ? */
2013-12-04 10:46:54 +08:00
}
2014-01-11 09:58:54 +08:00
else
{
/* new client */
if ( FD_ISSET ( _listenfd , & copy_set ) ) {
addClient ( ) ;
if ( - - nready < = 0 )
continue ;
}
2013-12-04 10:46:54 +08:00
2014-01-11 09:58:54 +08:00
/* data from client */
std : : vector < int > to_remove ;
for ( const auto & fd : _fds ) {
2014-02-26 23:41:47 +08:00
if ( FD_ISSET ( fd , & copy_set ) )
{
2014-04-10 18:31:28 +08:00
//fix Bug #4302 Test case ConsoleTest--ConsoleUploadFile crashed on Linux
//On linux, if you send data to a closed socket, the sending process will
//receive a SIGPIPE, which will cause linux system shutdown the sending process.
//Add this ioctl code to check if the socket has been closed by peer.
2014-04-11 20:07:54 +08:00
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
u_long n = 0 ;
ioctlsocket ( fd , FIONREAD , & n ) ;
# else
2014-04-10 18:31:28 +08:00
int n = 0 ;
ioctl ( fd , FIONREAD , & n ) ;
2014-04-11 20:07:54 +08:00
# endif
2014-04-10 18:31:28 +08:00
if ( n = = 0 )
{
//no data received, or fd is closed
continue ;
}
2014-04-11 20:07:54 +08:00
2014-03-18 00:42:36 +08:00
if ( ! parseCommand ( fd ) )
2014-02-26 23:41:47 +08:00
{
2014-03-18 00:42:36 +08:00
to_remove . push_back ( fd ) ;
2014-01-11 09:58:54 +08:00
}
2014-02-26 23:51:45 +08:00
if ( - - nready < = 0 )
break ;
2013-12-05 08:26:21 +08:00
}
2014-01-11 09:58:54 +08:00
}
/* remove closed conections */
for ( int fd : to_remove ) {
FD_CLR ( fd , & _read_set ) ;
_fds . erase ( std : : remove ( _fds . begin ( ) , _fds . end ( ) , fd ) , _fds . end ( ) ) ;
2013-12-04 10:46:54 +08:00
}
}
2013-12-05 08:26:21 +08:00
2014-01-11 09:58:54 +08:00
/* Any message for the remote console ? send it! */
if ( ! _DebugStrings . empty ( ) ) {
_DebugStringsMutex . lock ( ) ;
for ( const auto & str : _DebugStrings ) {
for ( const auto & fd : _fds ) {
2014-02-24 12:01:04 +08:00
send ( fd , str . c_str ( ) , str . length ( ) , 0 ) ;
2014-01-11 09:58:54 +08:00
}
}
_DebugStrings . clear ( ) ;
_DebugStringsMutex . unlock ( ) ;
2013-12-05 08:26:21 +08:00
}
2013-12-05 04:26:43 +08:00
}
// clean up: ignore stdin, stdout and stderr
for ( const auto & fd : _fds )
2014-02-24 14:24:14 +08:00
{
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
2014-02-24 14:28:19 +08:00
closesocket ( fd ) ;
2014-02-24 14:24:14 +08:00
# else
2013-12-05 04:26:43 +08:00
close ( fd ) ;
2014-02-24 14:24:14 +08:00
# endif
}
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
2014-02-24 15:05:20 +08:00
closesocket ( _listenfd ) ;
2014-02-24 14:24:14 +08:00
WSACleanup ( ) ;
# else
2013-12-05 04:26:43 +08:00
close ( _listenfd ) ;
2014-02-24 14:24:14 +08:00
# endif
2013-12-05 08:26:21 +08:00
_running = false ;
2013-11-27 10:58:36 +08:00
}
2013-12-05 16:09:38 +08:00
2014-03-22 21:10:54 +08:00
# endif /* #if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) */
2013-12-05 16:09:38 +08:00
NS_CC_END