mirror of https://github.com/axmolengine/axmol.git
Merge branch 'develop' into glview_improvements
Conflicts: samples/Lua/HelloLua/Classes/AppDelegate.cpp template/multi-platform-lua/Classes/AppDelegate.cpp
This commit is contained in:
commit
efaec7b7ec
4
AUTHORS
4
AUTHORS
|
@ -511,6 +511,7 @@ Developers:
|
|||
Lee, Jae-Hong (pyrasis)
|
||||
Maintainer of tizen port.
|
||||
localStorageGetItem crashes when column text is NULL.
|
||||
fix image bug on Android
|
||||
|
||||
lumendes
|
||||
Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386.
|
||||
|
@ -729,6 +730,9 @@ Developers:
|
|||
|
||||
pandamicro
|
||||
Exposed SAXParser to JS, it is used for parsing XML in JS.
|
||||
|
||||
hanjukim
|
||||
Fixed a bug that color and opacity settings were not applied when invoking Label::alignText.
|
||||
|
||||
Retired Core Developers:
|
||||
WenSheng Yang
|
||||
|
|
44
CHANGELOG
44
CHANGELOG
|
@ -1,4 +1,4 @@
|
|||
cocos2d-x-3.0beta2 ?.? ?
|
||||
cocos2d-x-3.0beta2 Jan.24 2014
|
||||
[All]
|
||||
[NEW] Full screen support for desktop platforms.
|
||||
[NEW] Adds performance test for EventDispatcher.
|
||||
|
@ -10,18 +10,22 @@ cocos2d-x-3.0beta2 ?.? ?
|
|||
[NEW] Label: Integrates LabelAtlas into new Label.
|
||||
[NEW] Node: Added `setGlobalZOrder()`. Useful to change the Node's render order. Node::setZOrder() -> Node::setLocalZOrder()
|
||||
[NEW] Renderer: Added BatchCommand. This command is not "batchable" with other commands, but improves performance in about 10%
|
||||
[NEW] LuaBindings: Bindings-generator supports to bind namespace for lua.
|
||||
|
||||
[FIX] Exposes SAXParser class to JS, it is used for parsing XML in JS.
|
||||
[FIX] event->stopPropagation can't work for EventListenerTouchAllAtOnce.
|
||||
[FIX] Uses unified `desktop/CCEGLView.h/cpp` for desktop platforms (windows, mac, linux).
|
||||
[FIX] Bindings-generator supports Windows again and remove dependency of LLVM since we only need binary(libclang.so/dll).
|
||||
[FIX] Removes unused files for MAC platform after using glfw3 to create opengl context.
|
||||
[FIX] Wrong arithmetic of child's position in ParallaxNode::addChild()
|
||||
[FIX] CocoStudio: TestColliderDetector in ArmatureTest can't work.
|
||||
[FIX] CocoStudio: The order of transform calculation in Skin::getNodeToWorldTransform() is incorrect.
|
||||
[FIX] Crash if file doesn't exist when using FileUtils::getStringFromFile.
|
||||
[FIX] If setting a shorter string than before while using LabelAtlas, the effect will be wrong.
|
||||
[FIX] Label: Memory leak in FontFreeType::createFontAtlas().
|
||||
[FIX] Label: Crash when using unknown characters.
|
||||
[FIX] Label: Missing line breaks and wrong alignment.
|
||||
[FIX] Label: Corrupt looking characters and incorrect spacing between characters
|
||||
[FIX] Label: Label:color and opacity settings are invalid afeter these these properties changed: 1)text content changed 2)align style changed 3)max line width limited
|
||||
[FIX] Label: Crash when using unknown characters
|
||||
[FIX] Console: log(format, va_args) is private to prevent possible resolution errors
|
||||
[FIX] Configuration: dumpInfo() -> getInfo()
|
||||
[FIX] ControlSlider doesn't support to set selected thumb sprite.
|
||||
|
@ -33,12 +37,42 @@ cocos2d-x-3.0beta2 ?.? ?
|
|||
[FIX] Renderer Performance Fix: When note using VAO, call glBufferData() instead of glBufferSubData().
|
||||
[FIX] Renderer Performance Fix: Doesn't sort z=0 elements. It also uses sort() instead of stable_sort() for z!=0.
|
||||
[FIX] Sprite: removed _hasChildren optimization. It uses !_children.empty() now which is super fast as well
|
||||
[FIX] Tests: TestCpp works with CMake on Windows.
|
||||
[FIX] Tests: Sprites Performance Test has 4 new tests
|
||||
[FIX] TextureCache: getTextureForKey and removeTextureForKey work as expected
|
||||
[FIX] TextureCache: dumpCachedTextureInfo() -> getCachedTextureInfo()
|
||||
[FIX] Websocket doesn't support send/receive data which larger than 4096 bytes.
|
||||
[FIX] Windows: There will be some compilation errors when using x64 target on Windows.
|
||||
[FIX] Object: Remove _retainCount
|
||||
[FIX] ParallaxNode: Coordinate of Sprite may be wrong after being added into ParallaxNode
|
||||
[FIX] Crash if there is not `textureFileName`section in particle plist file
|
||||
[FIX] Websocket cannot send/receive more than 4096 bytes data
|
||||
[FIX] TextureCache::addImageAsync can't load first image
|
||||
[FIX] ControlSlider: Can not set "selected thumb sprite"
|
||||
[FIX] ControlSlider: Can not set "scale ratio"
|
||||
[FIX] Crash when loading tga format image
|
||||
[FIX] Keyboard pressed events are being repeatedly fired before keyboard is released
|
||||
[Android]
|
||||
[FIX] Background music can't be resumed when back from foreground
|
||||
[FIX] ANR (Application Not Responding) appears on android 2.3 when pressing hardware button.
|
||||
[lua binding]
|
||||
[NEW] Can bind classes that have the same class names but different namesapces
|
||||
[FIX] Use EventDispatcher to update some test cases
|
||||
[FIX] sp.SkeletonAnimation:registerScriptHandler should not override cc.Node:registerScriptHandler
|
||||
[javascript binding]
|
||||
[NEW] Bind SAXParser
|
||||
[FIX] Pure JS class that wants to inherite from cc.Class will trigger an irrelevant log
|
||||
[FIX] Mac and iOS Simulator should also use SpiderMonkey which was built in RELEASE mode
|
||||
[FIX] Crash when running JSB projects on iOS device in DEBUG mode
|
||||
[FIX] Crash when Firefox connects to JSB application on Mac platform.
|
||||
[Desktop]
|
||||
[NEW] Support fullscreen
|
||||
[Linux]
|
||||
[FIX] "Testing empty labels" in LabelTest crashes.
|
||||
[Mac]
|
||||
[FIX] Removes unused files after using glfw3 to create opengl context
|
||||
[Win32]
|
||||
[FIX] Compiling error when using x64 target
|
||||
[FIX] Tests: TestCpp works with CMake
|
||||
[FIX] Bindings-generator supports Windows again and remove dependency of LLVM since it only needs binary of libclang
|
||||
|
||||
cocos2d-x-3.0beta Jan.7 2014
|
||||
[All]
|
||||
|
|
|
@ -16,11 +16,18 @@ def get_num_of_cpu():
|
|||
''' The build process can be accelerated by running multiple concurrent job processes using the -j-option.
|
||||
'''
|
||||
try:
|
||||
from numpy.distutils import cpuinfo
|
||||
return cpuinfo.cpu._getNCPUs()
|
||||
platform = sys.platform
|
||||
if platform == 'win32':
|
||||
if 'NUMBER_OF_PROCESSORS' in os.environ:
|
||||
return int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
else:
|
||||
return 1
|
||||
else:
|
||||
from numpy.distutils import cpuinfo
|
||||
return cpuinfo.cpu._getNCPUs()
|
||||
except Exception:
|
||||
print "Can't know cpuinfo, use default 1 cpu"
|
||||
return 1
|
||||
return 1
|
||||
|
||||
def check_environment_variables():
|
||||
''' Checking the environment NDK_ROOT, which will be used for building
|
||||
|
@ -253,19 +260,40 @@ def build_samples(target,ndk_build_param,android_platform,build_mode):
|
|||
if __name__ == '__main__':
|
||||
|
||||
#parse the params
|
||||
usage = """usage: %prog [options] target
|
||||
usage = """
|
||||
This script is mainy used for building samples built-in with cocos2d-x.
|
||||
|
||||
Valid targets are: [hellocpp|testcpp|simplegame|assetsmanager|hellolua|testlua|cocosdragon|crystalcraze|moonwarriors|testjavascript|watermelonwithme]
|
||||
Usage: %prog [options] target
|
||||
|
||||
You can use [all|cpp|lua|jsb], to build all, or all the C++, or all the Lua, or all the JavaScript samples respectevely."""
|
||||
Valid targets are: [hellocpp|testcpp|simplegame|assetsmanager|hellolua|testlua|cocosdragon|crystalcraze|moonwarriors|testjavascript|watermelonwithme]. You can combine them arbitrarily with a whitespace among two valid targets.
|
||||
|
||||
You can use [all|cpp|lua|jsb], to build all the samples, or all the c++ samples, or all the lua samples, or all the jsb samples respectevely.
|
||||
|
||||
cpp = ['hellocpp', 'testcpp', 'simplegame', 'assetsmanager']
|
||||
lua = ['hellolua', 'testlua']
|
||||
jsb = ['cocosdragon', 'crystalcraze', 'moonwarriors', 'testjavascript', 'watermelonwithme']
|
||||
all = cpp + lua + jsb // be careful with the all target, it may took a very long time to compile all the projects, do it under your own risk.
|
||||
|
||||
If you are new to cocos2d-x, I recommend you start with hellocpp,hellolua or testjavascript.
|
||||
|
||||
You can combine these targets like this:
|
||||
|
||||
//1. to build simplegame and assetsmanager
|
||||
python android-build.py -p 10 simplegame assetsmanager
|
||||
|
||||
//2. to build hellolua and all the jsb samples
|
||||
python android-build.py -p 19 hellolua jsb
|
||||
|
||||
Note: You should install ant to generate apk while building the andriod samples. But it is optional. You can generate apk with eclipse.
|
||||
"""
|
||||
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-n", "--ndk", dest="ndk_build_param",
|
||||
help='parameter for ndk-build')
|
||||
help='Parameter for ndk-build')
|
||||
parser.add_option("-p", "--platform", dest="android_platform",
|
||||
help='parameter for android-update.Without the parameter,the script just build dynamic library for project. Valid android-platform are:[10|11|12|13|14|15|16|17|18|19]')
|
||||
help='Parameter for android-update. Without the parameter,the script just build dynamic library for the projects. Valid android-platform are:[10|11|12|13|14|15|16|17|18|19]')
|
||||
parser.add_option("-b", "--build", dest="build_mode",
|
||||
help='the build mode for java project,debug[default] or release.Get more information,please refer to http://developer.android.com/tools/building/building-cmdline.html')
|
||||
help='The build mode for java project,debug[default] or release. Get more information,please refer to http://developer.android.com/tools/building/building-cmdline.html')
|
||||
(opts, args) = parser.parse_args()
|
||||
|
||||
if len(args) == 0:
|
||||
|
|
|
@ -1 +1 @@
|
|||
72b2e67ce3473ec4d8adf2412a9ce1d9390e0882
|
||||
99ea8c15ffe770eb2acd216155c34866bbd4a645
|
|
@ -1 +1 @@
|
|||
7a606b7819e4f2a8d7eb689a029974d84d57cf63
|
||||
c958533394964fe0c38bd60c272a0b48ec38d9d6
|
|
@ -1,8 +0,0 @@
|
|||
@echo off
|
||||
SETLOCAL
|
||||
|
||||
:start
|
||||
mkdir win32-msvc-vs2010-x86
|
||||
cd win32-msvc-vs2010-x86
|
||||
cmake -G "Visual Studio 10" ../..
|
||||
pause
|
|
@ -75,7 +75,7 @@ bool Configuration::init()
|
|||
_valueDict["cocos2d.x.compiled_with_gl_state_cache"] = Value(true);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#if COCOS2D_DEBUG
|
||||
_valueDict["cocos2d.x.build_type"] = Value("DEBUG");
|
||||
#else
|
||||
_valueDict["cocos2d.x.build_type"] = Value("RELEASE");
|
||||
|
|
|
@ -351,7 +351,7 @@ void Director::calculateDeltaTime()
|
|||
_deltaTime = MAX(0, _deltaTime);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#if COCOS2D_DEBUG
|
||||
// If we are debugging our code, prevent big delta time
|
||||
if (_deltaTime > 0.2f)
|
||||
{
|
||||
|
|
|
@ -815,7 +815,7 @@ void EventDispatcher::dispatchTouchEvent(EventTouch* event)
|
|||
if (event->isStopped())
|
||||
{
|
||||
updateListeners(event);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -85,6 +85,7 @@ void Font::setCurrentGlyphCollection(GlyphCollection glyphs, const char *customG
|
|||
|
||||
break;
|
||||
}
|
||||
_usedGlyphs = glyphs;
|
||||
}
|
||||
|
||||
const char * Font::getCurrentGlyphCollection() const
|
||||
|
@ -99,7 +100,7 @@ const char * Font::getCurrentGlyphCollection() const
|
|||
}
|
||||
}
|
||||
|
||||
unsigned short int * Font::getUTF16Text(const char *text, int &outNumLetters) const
|
||||
unsigned short* Font::getUTF16Text(const char *text, int &outNumLetters) const
|
||||
{
|
||||
unsigned short* utf16String = cc_utf8_to_utf16(text);
|
||||
|
||||
|
@ -115,7 +116,7 @@ int Font::getUTF16TextLenght(unsigned short int *text) const
|
|||
return cc_wcslen(text);
|
||||
}
|
||||
|
||||
unsigned short int * Font::trimUTF16Text(unsigned short int *text, int newBegin, int newEnd) const
|
||||
unsigned short * Font::trimUTF16Text(unsigned short int *text, int newBegin, int newEnd) const
|
||||
{
|
||||
if ( newBegin < 0 || newEnd <= 0 )
|
||||
return 0;
|
||||
|
|
|
@ -49,8 +49,8 @@ public:
|
|||
virtual int getFontMaxHeight() const { return 0; }
|
||||
|
||||
virtual int getUTF16TextLenght(unsigned short int *text) const;
|
||||
virtual unsigned short int * getUTF16Text(const char *text, int &outNumLetters) const;
|
||||
virtual unsigned short int * trimUTF16Text(unsigned short int *text, int newBegin, int newEnd) const;
|
||||
virtual unsigned short * getUTF16Text(const char *text, int &outNumLetters) const;
|
||||
virtual unsigned short * trimUTF16Text(unsigned short int *text, int newBegin, int newEnd) const;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String)
|
|||
tempDef.width = tempRect.size.width + _letterPadding;
|
||||
tempDef.height = tempRect.size.height + _letterPadding;
|
||||
tempDef.offsetX = tempRect.origin.x + offsetAdjust;
|
||||
tempDef.offsetY = tempRect.origin.y - offsetAdjust;
|
||||
tempDef.offsetY = _commonLineHeight + tempRect.origin.y - offsetAdjust;
|
||||
}
|
||||
fontDefs[utf16String[i]] = tempDef;
|
||||
}
|
||||
|
@ -238,4 +238,4 @@ const Font * FontAtlas::getFont() const
|
|||
return _font;
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
NS_CC_END
|
||||
|
|
|
@ -136,7 +136,9 @@ FontAtlas * FontFreeType::createFontAtlas()
|
|||
FontAtlas *atlas = new FontAtlas(*this);
|
||||
if (_usedGlyphs != GlyphCollection::DYNAMIC)
|
||||
{
|
||||
atlas->prepareLetterDefinitions(cc_utf8_to_utf16(getCurrentGlyphCollection()));
|
||||
unsigned short* utf16 = cc_utf8_to_utf16(getCurrentGlyphCollection());
|
||||
atlas->prepareLetterDefinitions(utf16);
|
||||
CC_SAFE_DELETE_ARRAY(utf16);
|
||||
}
|
||||
this->release();
|
||||
return atlas;
|
||||
|
|
|
@ -197,7 +197,7 @@ Label::Label(FontAtlas *atlas, TextHAlignment alignment, bool useDistanceField,b
|
|||
, _originalUTF16String(nullptr)
|
||||
, _horizontalKernings(nullptr)
|
||||
, _fontAtlas(atlas)
|
||||
, _isOpacityModifyRGB(true)
|
||||
, _isOpacityModifyRGB(false)
|
||||
, _useDistanceField(useDistanceField)
|
||||
, _useA8Shader(useA8Shader)
|
||||
, _fontSize(0)
|
||||
|
@ -471,6 +471,8 @@ void Label::alignText()
|
|||
insertQuadFromSprite(_reusedLetter,vaildIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
updateColor();
|
||||
}
|
||||
|
||||
bool Label::computeHorizontalKernings(unsigned short int *stringToRender)
|
||||
|
|
|
@ -335,7 +335,14 @@ bool LabelTextFormatter::createStringSprites(Label *theLabel)
|
|||
// If the last character processed has an xAdvance which is less that the width of the characters image, then we need
|
||||
// to adjust the width of the string to take this into account, or the character will overlap the end of the bounding
|
||||
// box
|
||||
tmpSize.width = longestLine - charAdvance + lastCharWidth;
|
||||
if(charAdvance < lastCharWidth)
|
||||
{
|
||||
tmpSize.width = longestLine - charAdvance + lastCharWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpSize.width = longestLine;
|
||||
}
|
||||
|
||||
tmpSize.height = totalHeight;
|
||||
theLabel->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize));
|
||||
|
|
|
@ -290,7 +290,7 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type)
|
|||
break;
|
||||
|
||||
case kShaderType_PositionTextureColorAlphaTest:
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_noMVP_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
|
||||
p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
|
||||
p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
|
||||
|
|
|
@ -250,8 +250,9 @@ public:
|
|||
inline void setStoringCharacters(bool storingCharacters) { _storingCharacters = storingCharacters; };
|
||||
|
||||
/// properties
|
||||
inline ValueMap getProperties() const { return _properties; };
|
||||
inline void setProperties(ValueMap properties) {
|
||||
inline const ValueMap& getProperties() const { return _properties; }
|
||||
inline ValueMap& getProperties() { return _properties; }
|
||||
inline void setProperties(const ValueMap& properties) {
|
||||
_properties = properties;
|
||||
};
|
||||
|
||||
|
|
|
@ -107,9 +107,9 @@ Color4B::Color4B(GLubyte _r, GLubyte _g, GLubyte _b, GLubyte _a)
|
|||
{}
|
||||
|
||||
Color4B::Color4B(const Color3B& color)
|
||||
: r(color.r * 255)
|
||||
, g(color.g * 255)
|
||||
, b(color.b * 255)
|
||||
: r(color.r)
|
||||
, g(color.g)
|
||||
, b(color.b)
|
||||
, a(255)
|
||||
{}
|
||||
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
################################################################################
|
||||
#
|
||||
# LINUX MAKEFILE
|
||||
#
|
||||
# Available options are:
|
||||
# - CLANG=1 : Compiles with clang instead of gcc. Clang must be in your PATH.
|
||||
# - V=1 : Enables the verbose mode.
|
||||
# - DEBUG=1 : Enables the debug mode, disable compiler optimizations.
|
||||
# - OPENAL=1 : Uses OpenAL instead of FMOD as sound engine.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
all:
|
||||
|
||||
# Remove -Wall, because it enables -Wunused-function, and this warning exists in webp.h
|
||||
# when enable c++11. I don't know why.
|
||||
# GCC 4.6 is primary platform for cocos2d v.3, because it's default compiler for Android,
|
||||
# Blackberry, some Linux distributions.It supports all important features of c++11, but have
|
||||
# no flag "-std=c++11" (which was turned on in version 4.7).
|
||||
CCFLAGS += -MMD -Wno-deprecated-declarations -fPIC
|
||||
CXXFLAGS += -MMD -Wno-deprecated-declarations -fPIC -std=gnu++0x
|
||||
|
||||
ifeq ($(CLANG), 1)
|
||||
CC := clang
|
||||
CXX := clang++
|
||||
DEFINES += -D__STRICT_ANSI__ # Allows clang 3.3 to use __float128
|
||||
else
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
CCFLAGS += -Werror
|
||||
CXXFLAGS += -Werror
|
||||
endif
|
||||
|
||||
ARFLAGS = cr
|
||||
|
||||
DEFINES += -DLINUX -DCC_KEYBOARD_SUPPORT
|
||||
|
||||
ifdef USE_BOX2D
|
||||
DEFINES += -DCC_ENABLE_BOX2D_INTEGRATION=1
|
||||
else
|
||||
DEFINES += -DCC_ENABLE_CHIPMUNK_INTEGRATION=1
|
||||
endif
|
||||
|
||||
THIS_MAKEFILE := $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
|
||||
ifndef COCOS_ROOT
|
||||
COCOS_ROOT := $(realpath $(dir $(THIS_MAKEFILE))/../..)
|
||||
endif
|
||||
COCOS_SRC = $(COCOS_ROOT)/cocos/2d
|
||||
OBJ_DIR ?= obj
|
||||
|
||||
LIB_DIR = $(COCOS_ROOT)/lib/linux
|
||||
BIN_DIR = bin
|
||||
|
||||
INCLUDES += \
|
||||
-I$(COCOS_SRC)/ \
|
||||
-I$(COCOS_SRC)/../math/kazmath/include \
|
||||
-I$(COCOS_SRC)/platform/linux \
|
||||
-I$(COCOS_SRC)/../../external/jpeg/include/linux \
|
||||
-I$(COCOS_SRC)/../../external/tiff/include/linux \
|
||||
-I$(COCOS_SRC)/../../external/webp/include/linux \
|
||||
-I$(COCOS_SRC)/../../external/tinyxml2 \
|
||||
-I$(COCOS_SRC)/../../external/unzip \
|
||||
-I$(COCOS_SRC)/../../external/glfw3/include/linux \
|
||||
-I$(COCOS_SRC)/../physics \
|
||||
-I$(COCOS_SRC)/../base \
|
||||
-I$(COCOS_SRC)/../../external/chipmunk/include/chipmunk \
|
||||
-I$(COCOS_SRC)/../../external/freetype2/include/linux \
|
||||
-I$(COCOS_SRC)/../.. \
|
||||
-I$(COCOS_SRC)/../audio/include
|
||||
|
||||
LBITS := $(shell getconf LONG_BIT)
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CCFLAGS += -g3 -O0
|
||||
CXXFLAGS += -g3 -O0
|
||||
DEFINES += -D_DEBUG -DCOCOS2D_DEBUG=1
|
||||
OBJ_DIR := $(OBJ_DIR)/debug
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
BIN_DIR := $(BIN_DIR)/debug
|
||||
else
|
||||
CCFLAGS += -O3
|
||||
CXXFLAGS += -O3
|
||||
DEFINES += -DNDEBUG
|
||||
OBJ_DIR := $(OBJ_DIR)/release
|
||||
LIB_DIR := $(LIB_DIR)/release
|
||||
BIN_DIR := $(BIN_DIR)/release
|
||||
endif
|
||||
|
||||
ifndef V
|
||||
LOG_CC = @echo " CC $@";
|
||||
LOG_CXX = @echo " CXX $@";
|
||||
LOG_AR = @echo " AR $@";
|
||||
LOG_LINK = @echo " LINK $@";
|
||||
endif
|
||||
|
||||
OBJECTS := $(SOURCES:.cpp=.o)
|
||||
OBJECTS := $(OBJECTS:.c=.o)
|
||||
OBJECTS := $(subst ../,,$(OBJECTS))
|
||||
OBJECTS := $(subst $(COCOS_ROOT)/,,$(OBJECTS))
|
||||
OBJECTS := $(addprefix $(OBJ_DIR)/, $(OBJECTS))
|
||||
DEPS = $(OBJECTS:.o=.d)
|
||||
CORE_MAKEFILE_LIST := $(MAKEFILE_LIST)
|
||||
-include $(DEPS)
|
||||
|
||||
STATICLIBS_DIR = $(COCOS_ROOT)/external
|
||||
ifeq ($(LBITS),64)
|
||||
POSTFIX = 64-bit
|
||||
else
|
||||
POSTFIX = 32-bit
|
||||
endif
|
||||
STATICLIBS = $(STATICLIBS_DIR)/freetype2/prebuilt/linux/$(POSTFIX)/libfreetype.a \
|
||||
$(STATICLIBS_DIR)/jpeg/prebuilt/linux/$(POSTFIX)/libjpeg.a \
|
||||
$(STATICLIBS_DIR)/tiff/prebuilt/linux/$(POSTFIX)/libtiff.a \
|
||||
$(STATICLIBS_DIR)/webp/prebuilt/linux/$(POSTFIX)/libwebp.a
|
||||
|
||||
ifneq ($(OPENAL),1)
|
||||
ifeq ($(LBITS),64)
|
||||
FMOD_LIBDIR = $(COCOS_ROOT)/cocos/audio/third-party/fmod/lib64/api/lib
|
||||
SHAREDLIBS += -lfmodex64
|
||||
else
|
||||
FMOD_LIBDIR = $(COCOS_ROOT)/cocos/audio/third-party/fmod/api/lib
|
||||
SHAREDLIBS += -lfmodex
|
||||
endif
|
||||
endif
|
||||
|
||||
SHAREDLIBS += -lGLEW -lfontconfig -lpthread -lGL -lpng `pkg-config --libs glfw3`
|
||||
SHAREDLIBS += -L$(FMOD_LIBDIR) -Wl,-rpath,$(abspath $(FMOD_LIBDIR))
|
||||
SHAREDLIBS += -L$(LIB_DIR) -Wl,-rpath,$(abspath $(LIB_DIR))
|
||||
|
||||
LIBS = -lrt -lz -lX11
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR)
|
||||
rm -f $(TARGET) core
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# If the parent Makefile defines $(EXECUTABLE) then define this as the target
|
||||
# and create a 'make run' rule to run the app.
|
||||
ifdef EXECUTABLE
|
||||
TARGET := $(BIN_DIR)/$(EXECUTABLE)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
run: $(TARGET)
|
||||
cd $(dir $^) && ./$(notdir $^)
|
||||
|
||||
.PHONY: run
|
||||
endif
|
|
@ -603,8 +603,7 @@ static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) {
|
|||
|
||||
static void process_input(struct android_app* app, struct android_poll_source* source) {
|
||||
AInputEvent* event = NULL;
|
||||
int processed = 0;
|
||||
while (AInputQueue_hasEvents( app->inputQueue ) && AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
|
||||
while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
|
||||
LOGV("New input event: type=%d\n", AInputEvent_getType(event));
|
||||
if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
|
||||
continue;
|
||||
|
@ -612,10 +611,6 @@ static void process_input(struct android_app* app, struct android_poll_source* s
|
|||
int32_t handled = 0;
|
||||
if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
|
||||
AInputQueue_finishEvent(app->inputQueue, event, handled);
|
||||
processed = 1;
|
||||
}
|
||||
if (processed == 0) {
|
||||
LOGE("Failure reading next input event: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
|
|
@ -450,23 +450,21 @@ static BitmapDC& sharedBitmapDC()
|
|||
}
|
||||
|
||||
bool Image::initWithString(
|
||||
const char * pText,
|
||||
int nWidth/* = 0*/,
|
||||
int nHeight/* = 0*/,
|
||||
TextAlign eAlignMask/* = kAlignCenter*/,
|
||||
const char * pFontName/* = nil*/,
|
||||
int nSize/* = 0*/)
|
||||
const char * text,
|
||||
int width/* = 0*/,
|
||||
int height/* = 0*/,
|
||||
TextAlign alignMask/* = kAlignCenter*/,
|
||||
const char * fontName/* = nil*/,
|
||||
int size/* = 0*/)
|
||||
{
|
||||
bool bRet = false;
|
||||
bool ret = false;
|
||||
do
|
||||
{
|
||||
CC_BREAK_IF(! pText);
|
||||
CC_BREAK_IF(!text || 0 == strlen(text));
|
||||
|
||||
BitmapDC &dc = sharedBitmapDC();
|
||||
|
||||
//const char* pFullFontName = FileUtils::getInstance()->fullPathFromRelativePath(pFontName);
|
||||
|
||||
CC_BREAK_IF(! dc.getBitmap(pText, nWidth, nHeight, eAlignMask, pFontName, nSize));
|
||||
CC_BREAK_IF(! dc.getBitmap(text, width, height, alignMask, fontName, size));
|
||||
|
||||
// assign the dc._data to _data in order to save time
|
||||
_data = dc._data;
|
||||
|
@ -478,13 +476,13 @@ bool Image::initWithString(
|
|||
_preMulti = true;
|
||||
_dataLen = _width * _height * 4;
|
||||
|
||||
bRet = true;
|
||||
ret = true;
|
||||
|
||||
dc.reset();
|
||||
}while (0);
|
||||
|
||||
//do nothing
|
||||
return bRet;
|
||||
return ret;
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
|
|
@ -28,14 +28,20 @@ THE SOFTWARE.
|
|||
NS_CC_BEGIN
|
||||
|
||||
AutoreleasePool::AutoreleasePool()
|
||||
:_name("")
|
||||
: _name("")
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
, _isClearing(false)
|
||||
#endif
|
||||
{
|
||||
_managedObjectArray.reserve(150);
|
||||
PoolManager::getInstance()->push(this);
|
||||
}
|
||||
|
||||
AutoreleasePool::AutoreleasePool(const std::string &name)
|
||||
:_name(name)
|
||||
: _name(name)
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
, _isClearing(false)
|
||||
#endif
|
||||
{
|
||||
_managedObjectArray.reserve(150);
|
||||
PoolManager::getInstance()->push(this);
|
||||
|
@ -56,11 +62,27 @@ void AutoreleasePool::addObject(Object* object)
|
|||
|
||||
void AutoreleasePool::clear()
|
||||
{
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
_isClearing = true;
|
||||
#endif
|
||||
for (const auto &obj : _managedObjectArray)
|
||||
{
|
||||
obj->release();
|
||||
}
|
||||
_managedObjectArray.clear();
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
_isClearing = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AutoreleasePool::contains(Object* object) const
|
||||
{
|
||||
for (const auto& obj : _managedObjectArray)
|
||||
{
|
||||
if (obj == object)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AutoreleasePool::dump()
|
||||
|
@ -89,7 +111,7 @@ PoolManager* PoolManager::getInstance()
|
|||
s_singleInstance = new PoolManager();
|
||||
// Add the first auto release pool
|
||||
s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool");
|
||||
s_singleInstance->_releasePoolStack.push(s_singleInstance->_curReleasePool);
|
||||
s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool);
|
||||
}
|
||||
return s_singleInstance;
|
||||
}
|
||||
|
@ -110,8 +132,8 @@ PoolManager::~PoolManager()
|
|||
|
||||
while (!_releasePoolStack.empty())
|
||||
{
|
||||
AutoreleasePool* pool = _releasePoolStack.top();
|
||||
_releasePoolStack.pop();
|
||||
AutoreleasePool* pool = _releasePoolStack.back();
|
||||
_releasePoolStack.pop_back();
|
||||
|
||||
delete pool;
|
||||
}
|
||||
|
@ -123,9 +145,19 @@ AutoreleasePool* PoolManager::getCurrentPool() const
|
|||
return _curReleasePool;
|
||||
}
|
||||
|
||||
bool PoolManager::isObjectInPools(Object* obj) const
|
||||
{
|
||||
for (const auto& pool : _releasePoolStack)
|
||||
{
|
||||
if (pool->contains(obj))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PoolManager::push(AutoreleasePool *pool)
|
||||
{
|
||||
_releasePoolStack.push(pool);
|
||||
_releasePoolStack.push_back(pool);
|
||||
_curReleasePool = pool;
|
||||
}
|
||||
|
||||
|
@ -134,12 +166,12 @@ void PoolManager::pop()
|
|||
// Can not pop the pool that created by engine
|
||||
CC_ASSERT(_releasePoolStack.size() >= 1);
|
||||
|
||||
_releasePoolStack.pop();
|
||||
_releasePoolStack.pop_back();
|
||||
|
||||
// Should update _curReleasePool if a temple pool is released
|
||||
if (_releasePoolStack.size() > 1)
|
||||
{
|
||||
_curReleasePool = _releasePoolStack.top();
|
||||
_curReleasePool = _releasePoolStack.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,18 @@ public:
|
|||
*/
|
||||
void clear();
|
||||
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
/**
|
||||
* Whether the pool is doing `clear` operation.
|
||||
*/
|
||||
bool isClearing() const { return _isClearing; };
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks whether the pool contains the specified object.
|
||||
*/
|
||||
bool contains(Object* object) const;
|
||||
|
||||
/**
|
||||
* Dump the objects that are put into autorelease pool. It is used for debugging.
|
||||
*
|
||||
|
@ -102,6 +114,13 @@ private:
|
|||
*/
|
||||
std::vector<Object*> _managedObjectArray;
|
||||
std::string _name;
|
||||
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
/**
|
||||
* The flag for checking whether the pool is doing `clear` operation.
|
||||
*/
|
||||
bool _isClearing;
|
||||
#endif
|
||||
};
|
||||
|
||||
class CC_DLL PoolManager
|
||||
|
@ -127,6 +146,8 @@ public:
|
|||
*/
|
||||
AutoreleasePool *getCurrentPool() const;
|
||||
|
||||
bool isObjectInPools(Object* obj) const;
|
||||
|
||||
/**
|
||||
* @js NA
|
||||
* @lua NA
|
||||
|
@ -142,7 +163,7 @@ private:
|
|||
|
||||
static PoolManager* s_singleInstance;
|
||||
|
||||
std::stack<AutoreleasePool*> _releasePoolStack;
|
||||
std::deque<AutoreleasePool*> _releasePoolStack;
|
||||
AutoreleasePool *_curReleasePool;
|
||||
};
|
||||
|
||||
|
|
|
@ -63,6 +63,53 @@ Object* Object::autorelease()
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Object::release()
|
||||
{
|
||||
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
|
||||
--_referenceCount;
|
||||
|
||||
if (_referenceCount == 0)
|
||||
{
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
auto poolManager = PoolManager::getInstance();
|
||||
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
|
||||
{
|
||||
// Trigger an assert if the reference count is 0 but the object is still in autorelease pool.
|
||||
// This happens when 'autorelease/release' were not used in pairs with 'new/retain'.
|
||||
//
|
||||
// Wrong usage (1):
|
||||
//
|
||||
// auto obj = Node::create(); // Ref = 1, but it's an autorelease object which means it was in the autorelease pool.
|
||||
// obj->autorelease(); // Wrong: If you wish to invoke autorelease several times, you should retain `obj` first.
|
||||
//
|
||||
// Wrong usage (2):
|
||||
//
|
||||
// auto obj = Node::create();
|
||||
// obj->release(); // Wrong: obj is an autorelease object, it will be released when clearing current pool.
|
||||
//
|
||||
// Correct usage (1):
|
||||
//
|
||||
// auto obj = Node::create();
|
||||
// |- new Node(); // `new` is the pair of the `autorelease` of next line
|
||||
// |- autorelease(); // The pair of `new Node`.
|
||||
//
|
||||
// obj->retain();
|
||||
// obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line.
|
||||
//
|
||||
// Correct usage (2):
|
||||
//
|
||||
// auto obj = Node::create();
|
||||
// obj->retain();
|
||||
// obj->release(); // This `release` is the pair of `retain` of previous line.
|
||||
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
|
||||
}
|
||||
#endif
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
bool Object::isSingleReference() const
|
||||
{
|
||||
return _referenceCount == 1;
|
||||
|
|
|
@ -103,14 +103,7 @@ public:
|
|||
* @see retain, autorelease
|
||||
* @js NA
|
||||
*/
|
||||
inline void release()
|
||||
{
|
||||
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
|
||||
--_referenceCount;
|
||||
|
||||
if (_referenceCount == 0)
|
||||
delete this;
|
||||
}
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Retains the ownership.
|
||||
|
|
|
@ -144,10 +144,10 @@ Node* SceneReader::createObject(const rapidjson::Value &dict, cocos2d::Node* par
|
|||
{
|
||||
gb->addComponent(com);
|
||||
}
|
||||
else
|
||||
{
|
||||
CC_SAFE_RELEASE_NULL(com);
|
||||
}
|
||||
else
|
||||
{
|
||||
com = nullptr;
|
||||
}
|
||||
}
|
||||
if(_fnSelector != nullptr)
|
||||
{
|
||||
|
|
|
@ -216,7 +216,7 @@ kmMat4 Skin::getNodeToWorldTransformAR() const
|
|||
displayTransform.mat[12] = anchorPoint.x;
|
||||
displayTransform.mat[13] = anchorPoint.y;
|
||||
|
||||
return TransformConcat(displayTransform, _bone->getArmature()->getNodeToWorldTransform());
|
||||
return TransformConcat( _bone->getArmature()->getNodeToWorldTransform(),displayTransform);
|
||||
}
|
||||
|
||||
void Skin::draw()
|
||||
|
|
|
@ -178,7 +178,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
|
|||
CCASSERT(con != nullptr, "");
|
||||
con->serialize(subDict);
|
||||
con->init();
|
||||
con->autorelease();
|
||||
_cons.pushBack(con);
|
||||
}
|
||||
|
||||
|
@ -199,7 +198,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
|
|||
}
|
||||
act->serialize(subDict);
|
||||
act->init();
|
||||
act->autorelease();
|
||||
_acts.pushBack(act);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\Microsoft SDKs\Windows\v7.1A\include;..\Include;$(EngineRoot)cocos;$(EngineRoot)external\websockets\include\win32;$(EngineRoot)external\curl\include\win32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;COCOS2D_DEBUG=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
|
|
|
@ -58,7 +58,7 @@ typedef struct PhysicsContactData
|
|||
/**
|
||||
* @brief Contact infomation. it will created automatically when two shape contact with each other. and it will destoried automatically when two shape separated.
|
||||
*/
|
||||
class PhysicsContact : Event
|
||||
class PhysicsContact : public Event
|
||||
{
|
||||
public:
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ typedef struct PhysicsRayCastInfo
|
|||
{
|
||||
PhysicsShape* shape;
|
||||
Point start;
|
||||
Point end;
|
||||
Point end; //< in lua, it's name is "ended"
|
||||
Point contact;
|
||||
Vect normal;
|
||||
float fraction;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 37451f4ec2e2d01da9286ae97952582b81d02be8
|
||||
Subproject commit 056343a701a945682fcc067812ffc41e42667486
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
#include "js_bindings_config.h"
|
||||
|
||||
#if DEBUG
|
||||
#if COCOS2D_DEBUG
|
||||
#define TRACE_DEBUGGER_SERVER(...) CCLOG(__VA_ARGS__)
|
||||
#else
|
||||
#define TRACE_DEBUGGER_SERVER(...)
|
||||
|
@ -568,7 +568,7 @@ JSBool ScriptingCore::runScript(const char *path, JSObject* global, JSContext* c
|
|||
if (script) {
|
||||
jsval rval;
|
||||
filename_script[path] = script;
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
evaluatedOK = JS_ExecuteScript(cx, global, script, &rval);
|
||||
if (JS_FALSE == evaluatedOK) {
|
||||
cocos2d::log("(evaluatedOK == JS_FALSE)");
|
||||
|
@ -704,7 +704,7 @@ JSBool ScriptingCore::dumpRoot(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
{
|
||||
// JS_DumpNamedRoots is only available on DEBUG versions of SpiderMonkey.
|
||||
// Mac and Simulator versions were compiled with DEBUG.
|
||||
#if DEBUG
|
||||
#if COCOS2D_DEBUG
|
||||
// JSContext *_cx = ScriptingCore::getInstance()->getGlobalContext();
|
||||
// JSRuntime *rt = JS_GetRuntime(_cx);
|
||||
// JS_DumpNamedRoots(rt, dumpNamedRoot, NULL);
|
||||
|
@ -1408,6 +1408,9 @@ void ScriptingCore::enableDebugger()
|
|||
JS_SetDebugMode(_cx, JS_TRUE);
|
||||
|
||||
_debugGlobal = NewGlobalObject(_cx, true);
|
||||
// Adds the debugger object to root, otherwise it may be collected by GC.
|
||||
JS_AddObjectRoot(_cx, &_debugGlobal);
|
||||
|
||||
JS_WrapObject(_cx, &_debugGlobal);
|
||||
JSAutoCompartment ac(_cx, _debugGlobal);
|
||||
// these are used in the debug program
|
||||
|
|
|
@ -651,10 +651,13 @@ cc.Class.extend = function (prop) {
|
|||
function Class() {
|
||||
// All construction is actually done in the init method
|
||||
if (!initializing) {
|
||||
if (!this.ctor)
|
||||
cc.log("No ctor function found, please set `classes_need_extend` section at `ini` file as `tools/tojs/cocos2dx.ini`");
|
||||
else
|
||||
if (!this.ctor) {
|
||||
if (this.__nativeObj)
|
||||
cc.log("No ctor function found! Please check whether `classes_need_extend` section in `ini` file like which in `tools/tojs/cocos2dx.ini`");
|
||||
}
|
||||
else {
|
||||
this.ctor.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,25 @@ LOCAL_SRC_FILES := CCLuaBridge.cpp \
|
|||
../../../../external/lua/tolua/tolua_map.c \
|
||||
../../../../external/lua/tolua/tolua_push.c \
|
||||
../../../../external/lua/tolua/tolua_to.c \
|
||||
tolua_fix.c
|
||||
tolua_fix.c \
|
||||
socket/auxiliar.c \
|
||||
socket/luasocket_buffer.c \
|
||||
socket/except.c \
|
||||
socket/inet.c \
|
||||
socket/luasocket_io.c \
|
||||
socket/luasocket.c \
|
||||
socket/mime.c \
|
||||
socket/options.c \
|
||||
socket/select.c \
|
||||
socket/serial.c \
|
||||
socket/socket_scripts.c \
|
||||
socket/tcp.c \
|
||||
socket/timeout.c \
|
||||
socket/udp.c \
|
||||
socket/unix.c \
|
||||
socket/usocket.c \
|
||||
lua_extensions.c
|
||||
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../external/lua/tolua \
|
||||
$(LOCAL_PATH)/../../auto-generated/lua-bindings \
|
||||
|
|
|
@ -31,6 +31,9 @@ extern "C" {
|
|||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "tolua_fix.h"
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
|
||||
#include "lua_extensions.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "Cocos2dxLuaLoader.h"
|
||||
|
@ -146,6 +149,9 @@ bool LuaStack::init(void)
|
|||
{NULL, NULL}
|
||||
};
|
||||
luaL_register(_state, "_G", global_functions);
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
|
||||
luaopen_lua_extensions(_state);
|
||||
#endif
|
||||
g_luaType.clear();
|
||||
register_all_cocos2dx(_state);
|
||||
register_all_cocos2dx_extension(_state);
|
||||
|
|
|
@ -1071,7 +1071,7 @@ bool luavals_variadic_to_array(lua_State* L,int argc, Array** ret)
|
|||
else if (lua_isuserdata(L, i + 2))
|
||||
{
|
||||
tolua_Error err;
|
||||
if (!tolua_isusertype(L, i + 2, "Object", 0, &err))
|
||||
if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err))
|
||||
{
|
||||
#if COCOS2D_DEBUG >=1
|
||||
luaval_to_native_err(L,"#ferror:",&err);
|
||||
|
@ -1615,7 +1615,7 @@ void physics_raycastinfo_to_luaval(lua_State* L, const PhysicsRayCastInfo& info)
|
|||
point_to_luaval(L, info.start);
|
||||
lua_rawset(L, -3); /* table[key] = value, L: table */
|
||||
|
||||
lua_pushstring(L, "end"); /* L: table key */
|
||||
lua_pushstring(L, "ended"); /* L: table key */
|
||||
point_to_luaval(L, info.end);
|
||||
lua_rawset(L, -3); /* table[key] = value, L: table */
|
||||
|
||||
|
@ -1632,6 +1632,26 @@ void physics_raycastinfo_to_luaval(lua_State* L, const PhysicsRayCastInfo& info)
|
|||
lua_rawset(L, -3); /* table[key] = value, L: table */
|
||||
}
|
||||
|
||||
void physics_contactdata_to_luaval(lua_State* L, const PhysicsContactData* data)
|
||||
{
|
||||
if (nullptr == L || nullptr == data)
|
||||
return;
|
||||
|
||||
lua_newtable(L); /* L: table */
|
||||
|
||||
lua_pushstring(L, "points");
|
||||
points_to_luaval(L, data->points, data->count);
|
||||
lua_rawset(L, -3);
|
||||
|
||||
lua_pushstring(L, "normal");
|
||||
point_to_luaval(L, data->normal);
|
||||
lua_rawset(L, -3);
|
||||
|
||||
lua_pushstring(L, "POINT_MAX");
|
||||
lua_pushnumber(L, data->POINT_MAX);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
void size_to_luaval(lua_State* L,const Size& sz)
|
||||
{
|
||||
if (NULL == L)
|
||||
|
|
|
@ -88,7 +88,7 @@ bool luavals_variadic_to_ccvector( lua_State* L, int argc, cocos2d::Vector<T>* r
|
|||
{
|
||||
tolua_Error err;
|
||||
//Undo check
|
||||
if (!tolua_isusertype(L, i + 2, "Object", 0, &err))
|
||||
if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
|
@ -205,6 +205,7 @@ extern void color4b_to_luaval(lua_State* L,const Color4B& cc);
|
|||
extern void color4f_to_luaval(lua_State* L,const Color4F& cc);
|
||||
extern void physics_material_to_luaval(lua_State* L,const PhysicsMaterial& pm);
|
||||
extern void physics_raycastinfo_to_luaval(lua_State* L, const PhysicsRayCastInfo& info);
|
||||
extern void physics_contactdata_to_luaval(lua_State* L, const PhysicsContactData* data);
|
||||
extern void affinetransform_to_luaval(lua_State* L,const AffineTransform& inValue);
|
||||
extern void fontdefinition_to_luaval(lua_State* L,const FontDefinition& inValue);
|
||||
extern void array_to_luaval(lua_State* L,Array* inValue);
|
||||
|
|
|
@ -155,6 +155,11 @@ public:
|
|||
EVENT_MOUSE_SCROLL,
|
||||
|
||||
EVENT_SPINE,
|
||||
|
||||
EVENT_PHYSICS_CONTACT_BEGIN,
|
||||
EVENT_PHYSICS_CONTACT_PRESOLVE,
|
||||
EVENT_PHYSICS_CONTACT_POSTSOLVE,
|
||||
EVENT_PHYSICS_CONTACT_SEPERATE,
|
||||
};
|
||||
|
||||
typedef int Handler;
|
||||
|
|
|
@ -96,7 +96,7 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\lua\luajit\prebuilt\win32\*.*" "$
|
|||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)..\..\..;$(EngineRoot);$(EngineRoot)cocos\editor-support;$(EngineRoot)cocos\editor-support\cocostudio;$(EngineRoot)cocos\editor-support\cocosbuilder;$(EngineRoot)cocos\audio\include;$(EngineRoot)extensions;$(EngineRoot)extensions\network;$(EngineRoot)external;$(EngineRoot)external\libwebsockets\win32\include;$(EngineRoot)external\lua\tolua;$(EngineRoot)external\lua\luajit\include;$(EngineRoot)cocos\scripting\auto-generated\lua-bindings;$(EngineRoot)cocos\gui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)..\..\..;$(EngineRoot);$(EngineRoot)cocos\editor-support;$(EngineRoot)cocos\editor-support\cocostudio;$(EngineRoot)cocos\editor-support\cocosbuilder;$(EngineRoot)cocos\editor-support\spine;$(EngineRoot)cocos\audio\include;$(EngineRoot)extensions;$(EngineRoot)extensions\network;$(EngineRoot)external;$(EngineRoot)external\libwebsockets\win32\include;$(EngineRoot)external\lua\tolua;$(EngineRoot)external\lua\luajit\include;$(EngineRoot)cocos\scripting\auto-generated\lua-bindings;$(EngineRoot)cocos\gui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;LIBLUA_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
|
@ -152,8 +152,23 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\lua\luajit\prebuilt\win32\*.*" "$
|
|||
<ClCompile Include="lua_cocos2dx_manual.cpp" />
|
||||
<ClCompile Include="lua_cocos2dx_physics_manual.cpp" />
|
||||
<ClCompile Include="lua_cocos2dx_spine_manual.cpp" />
|
||||
<ClCompile Include="lua_extensions.c" />
|
||||
<ClCompile Include="Lua_web_socket.cpp" />
|
||||
<ClCompile Include="lua_xml_http_request.cpp" />
|
||||
<ClCompile Include="socket\auxiliar.c" />
|
||||
<ClCompile Include="socket\except.c" />
|
||||
<ClCompile Include="socket\inet.c" />
|
||||
<ClCompile Include="socket\luasocket.c" />
|
||||
<ClCompile Include="socket\luasocket_buffer.c" />
|
||||
<ClCompile Include="socket\luasocket_io.c" />
|
||||
<ClCompile Include="socket\mime.c" />
|
||||
<ClCompile Include="socket\options.c" />
|
||||
<ClCompile Include="socket\select.c" />
|
||||
<ClCompile Include="socket\socket_scripts.c" />
|
||||
<ClCompile Include="socket\tcp.c" />
|
||||
<ClCompile Include="socket\timeout.c" />
|
||||
<ClCompile Include="socket\udp.c" />
|
||||
<ClCompile Include="socket\wsocket.c" />
|
||||
<ClCompile Include="tolua_fix.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -186,8 +201,24 @@ xcopy /Y /Q "$(ProjectDir)..\..\..\..\external\lua\luajit\prebuilt\win32\*.*" "$
|
|||
<ClInclude Include="lua_cocos2dx_manual.hpp" />
|
||||
<ClInclude Include="lua_cocos2dx_physics_manual.hpp" />
|
||||
<ClInclude Include="lua_cocos2dx_spine_manual.hpp" />
|
||||
<ClInclude Include="lua_extensions.h" />
|
||||
<ClInclude Include="Lua_web_socket.h" />
|
||||
<ClInclude Include="lua_xml_http_request.h" />
|
||||
<ClInclude Include="socket\auxiliar.h" />
|
||||
<ClInclude Include="socket\except.h" />
|
||||
<ClInclude Include="socket\inet.h" />
|
||||
<ClInclude Include="socket\luasocket.h" />
|
||||
<ClInclude Include="socket\luasocket_buffer.h" />
|
||||
<ClInclude Include="socket\luasocket_io.h" />
|
||||
<ClInclude Include="socket\mime.h" />
|
||||
<ClInclude Include="socket\options.h" />
|
||||
<ClInclude Include="socket\select.h" />
|
||||
<ClInclude Include="socket\socket.h" />
|
||||
<ClInclude Include="socket\socket_scripts.h" />
|
||||
<ClInclude Include="socket\tcp.h" />
|
||||
<ClInclude Include="socket\timeout.h" />
|
||||
<ClInclude Include="socket\udp.h" />
|
||||
<ClInclude Include="socket\wsocket.h" />
|
||||
<ClInclude Include="tolua_fix.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
<Filter Include="cocos2dx_support\generated">
|
||||
<UniqueIdentifier>{19f563f0-e0ff-4500-890b-1755841d4ddb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cocos2dx_support\socket">
|
||||
<UniqueIdentifier>{8815bb6e-fc9c-4cbf-b190-8b47169ed71f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\auto-generated\lua-bindings\lua_cocos2dx_auto.cpp">
|
||||
|
@ -111,6 +114,51 @@
|
|||
<ClCompile Include="..\..\auto-generated\lua-bindings\lua_cocos2dx_physics_auto.cpp">
|
||||
<Filter>cocos2dx_support\generated</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\auxiliar.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\except.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\inet.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\luasocket.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\luasocket_buffer.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\luasocket_io.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\mime.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\options.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\select.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\socket_scripts.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\tcp.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\timeout.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\udp.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="socket\wsocket.c">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="lua_extensions.c">
|
||||
<Filter>cocos2dx_support</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\auto-generated\lua-bindings\lua_cocos2dx_auto.hpp">
|
||||
|
@ -209,6 +257,54 @@
|
|||
<ClInclude Include="..\..\auto-generated\lua-bindings\lua_cocos2dx_physics_auto.hpp">
|
||||
<Filter>cocos2dx_support\generated</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\auxiliar.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\except.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\inet.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\luasocket.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\luasocket_buffer.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\luasocket_io.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\mime.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\options.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\select.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\socket.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\socket_scripts.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\tcp.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\timeout.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\udp.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="socket\wsocket.h">
|
||||
<Filter>cocos2dx_support\socket</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="lua_extensions.h">
|
||||
<Filter>cocos2dx_support</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\auto-generated\lua-bindings\lua_cocos2dx_auto_api.js">
|
||||
|
|
|
@ -1 +1 @@
|
|||
85c7400aec0f87b3851772fbdbc01bf59f5402d8
|
||||
c5f8d4a3ea721a2ecb36fe381430b7ac6fad1740
|
|
@ -900,7 +900,6 @@ int lua_cocos2dx_physics_PhysicsShape_getPolyonCenter(lua_State* tolua_S)
|
|||
if (nullptr == arg0){
|
||||
LUA_PRECONDITION( arg0, "Invalid Native Object");
|
||||
}} while (0);
|
||||
ok &= luaval_to_int32(tolua_S, 3,(int *)&arg1);
|
||||
if(!ok)
|
||||
{
|
||||
CC_SAFE_FREE(arg0);
|
||||
|
@ -1138,6 +1137,114 @@ tolua_lerror:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_cocos2dx_EventListenerPhysicsContact_registerScriptHandler(lua_State* tolua_S)
|
||||
{
|
||||
if (nullptr == tolua_S)
|
||||
return 0;
|
||||
|
||||
int argc = 0;
|
||||
EventListenerPhysicsContact* self = nullptr;
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_Error tolua_err;
|
||||
if (!tolua_isusertype(tolua_S, 1, "cc.EventListenerPhysicsContact", 0, &tolua_err)) goto tolua_lerror;
|
||||
#endif
|
||||
|
||||
self = static_cast<EventListenerPhysicsContact*>(tolua_tousertype(tolua_S,1,0));
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
if (nullptr == self) {
|
||||
tolua_error(tolua_S,"invalid 'self' in function 'tolua_cocos2dx_EventListenerPhysicsContact_registerScriptHandler'\n", nullptr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
argc = lua_gettop(tolua_S) - 1;
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
if (!toluafix_isfunction(tolua_S,2,"LUA_FUNCTION",0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S, 3, 0, &tolua_err))
|
||||
{
|
||||
goto tolua_lerror;
|
||||
}
|
||||
#endif
|
||||
LUA_FUNCTION handler = toluafix_ref_function(tolua_S,2,0);
|
||||
ScriptHandlerMgr::HandlerType type = static_cast<ScriptHandlerMgr::HandlerType>((int)tolua_tonumber(tolua_S, 3, 0));
|
||||
switch (type)
|
||||
{
|
||||
case ScriptHandlerMgr::HandlerType::EVENT_PHYSICS_CONTACT_BEGIN:
|
||||
{
|
||||
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
|
||||
|
||||
self->onContactBegin = [handler](EventCustom* event, const PhysicsContact& contact) -> bool{
|
||||
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
|
||||
stack->pushObject(event, "cc.EventCustom");
|
||||
stack->pushObject(const_cast<PhysicsContact*>(&contact), "cc.PhysicsContact");
|
||||
bool ret = stack->executeFunctionByHandler(handler, 2);
|
||||
stack->clean();
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
break;
|
||||
case ScriptHandlerMgr::HandlerType::EVENT_PHYSICS_CONTACT_PRESOLVE:
|
||||
{
|
||||
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
|
||||
|
||||
self->onContactPreSolve = [handler](EventCustom* event, const PhysicsContact& contact, const PhysicsContactPreSolve& solve) -> bool{
|
||||
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
|
||||
stack->pushObject(event, "cc.EventCustom");
|
||||
stack->pushObject(const_cast<PhysicsContact*>(&contact), "cc.PhysicsContact");
|
||||
tolua_pushusertype(stack->getLuaState(), const_cast<PhysicsContactPreSolve*>(&solve), "cc.PhysicsContactPreSolve");
|
||||
bool ret = stack->executeFunctionByHandler(handler, 3);
|
||||
stack->clean();
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
break;
|
||||
case ScriptHandlerMgr::HandlerType::EVENT_PHYSICS_CONTACT_POSTSOLVE:
|
||||
{
|
||||
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
|
||||
|
||||
self->onContactPostSolve = [handler](EventCustom* event, const PhysicsContact& contact, const PhysicsContactPostSolve& solve){
|
||||
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
|
||||
stack->pushObject(event, "cc.EventCustom");
|
||||
stack->pushObject(const_cast<PhysicsContact*>(&contact), "cc.PhysicsContact");
|
||||
tolua_pushusertype(stack->getLuaState(), const_cast<PhysicsContactPostSolve*>(&solve), "cc.PhysicsContactPostSolve");
|
||||
stack->executeFunctionByHandler(handler, 3);
|
||||
stack->clean();
|
||||
};
|
||||
}
|
||||
break;
|
||||
case ScriptHandlerMgr::HandlerType::EVENT_PHYSICS_CONTACT_SEPERATE:
|
||||
{
|
||||
ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, type);
|
||||
|
||||
self->onContactSeperate = [handler](EventCustom* event, const PhysicsContact& contact){
|
||||
LuaStack* stack = LuaEngine::getInstance()->getLuaStack();
|
||||
stack->pushObject(event, "cc.EventCustom");
|
||||
stack->pushObject(const_cast<PhysicsContact*>(&contact), "cc.PhysicsContact");
|
||||
stack->executeFunctionByHandler(handler, 2);
|
||||
stack->clean();
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CCLOG("'registerScriptHandler' has wrong number of arguments: %d, was expecting %d\n", argc, 2);
|
||||
return 0;
|
||||
|
||||
#if COCOS2D_DEBUG >= 1
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'registerScriptHandler'.",&tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int register_all_cocos2dx_physics_manual(lua_State* tolua_S)
|
||||
{
|
||||
lua_pushstring(tolua_S, "cc.PhysicsBody");
|
||||
|
@ -1254,9 +1361,16 @@ int register_all_cocos2dx_physics_manual(lua_State* tolua_S)
|
|||
lua_pushnumber(tolua_S, PhysicsWorld::DEBUGDRAW_ALL);
|
||||
lua_rawset(tolua_S,-3);
|
||||
}
|
||||
|
||||
lua_pop(tolua_S, 1);
|
||||
|
||||
lua_pushstring(tolua_S, "cc.EventListenerPhysicsContact");
|
||||
lua_rawget(tolua_S, LUA_REGISTRYINDEX);
|
||||
if (lua_istable(tolua_S,-1))
|
||||
{
|
||||
tolua_function(tolua_S, "registerScriptHandler", tolua_cocos2dx_EventListenerPhysicsContact_registerScriptHandler);
|
||||
}
|
||||
lua_pop(tolua_S, 1);
|
||||
|
||||
tolua_constant(tolua_S, "PHYSICS_INFINITY", PHYSICS_INFINITY);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -148,7 +148,7 @@ tolua_lerror:
|
|||
#endif
|
||||
}
|
||||
|
||||
int tolua_Cocos2d_CCSkeletonAnimation_registerScriptHandler00(lua_State* tolua_S)
|
||||
int tolua_Cocos2d_CCSkeletonAnimation_registerSpineEventHandler00(lua_State* tolua_S)
|
||||
{
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
|
@ -170,12 +170,12 @@ int tolua_Cocos2d_CCSkeletonAnimation_registerScriptHandler00(lua_State* tolua_S
|
|||
return 0;
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'registerScriptHandler'.",&tolua_err);
|
||||
tolua_error(tolua_S,"#ferror in function 'registerSpineEventHandler'.",&tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int tolua_Cocos2d_CCSkeletonAnimation_unregisterScriptHandler00(lua_State* tolua_S)
|
||||
int tolua_Cocos2d_CCSkeletonAnimation_unregisterSpineEventHandler00(lua_State* tolua_S)
|
||||
{
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
|
@ -322,8 +322,8 @@ static void extendCCSkeletonAnimation(lua_State* L)
|
|||
if (lua_istable(L,-1))
|
||||
{
|
||||
tolua_function(L, "create", lua_cocos2dx_CCSkeletonAnimation_createWithFile);
|
||||
tolua_function(L, "registerScriptHandler", tolua_Cocos2d_CCSkeletonAnimation_registerScriptHandler00);
|
||||
tolua_function(L, "unregisterScriptHandler", tolua_Cocos2d_CCSkeletonAnimation_unregisterScriptHandler00);
|
||||
tolua_function(L, "registerSpineEventHandler", tolua_Cocos2d_CCSkeletonAnimation_registerSpineEventHandler00);
|
||||
tolua_function(L, "unregisterSpineEventHandler", tolua_Cocos2d_CCSkeletonAnimation_unregisterSpineEventHandler00);
|
||||
tolua_function(L, "setBlendFunc", tolua_spine_SkeletoneAnimation_setBlendFunc);
|
||||
tolua_function(L, "setTimeScale", tolua_Cocos2d_CCSkeletonAnimation_setTimeScale00);
|
||||
tolua_function(L, "setDebugSlots", tolua_Cocos2d_CCSkeletonAnimation_setDebugSlots00);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
#include "lua_extensions.h"
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// socket
|
||||
#include "socket/luasocket.h"
|
||||
#include "socket/mime.h"
|
||||
#include "socket/socket_scripts.h"
|
||||
|
||||
static luaL_Reg luax_exts[] = {
|
||||
{"socket.core", luaopen_socket_core},
|
||||
{"mime.core", luaopen_mime_core},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void luaopen_lua_extensions(lua_State *L)
|
||||
{
|
||||
// load extensions
|
||||
luaL_Reg* lib = luax_exts;
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "preload");
|
||||
for (; lib->func; lib++)
|
||||
{
|
||||
lua_pushcfunction(L, lib->func);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
|
||||
// load extensions script
|
||||
luaopen_socket_scripts(L);
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef __LUA_EXTRA_H_
|
||||
#define __LUA_EXTRA_H_
|
||||
|
||||
#if defined(_USRDLL)
|
||||
#define LUA_EXTENSIONS_DLL __declspec(dllexport)
|
||||
#else /* use a DLL library */
|
||||
#define LUA_EXTENSIONS_DLL
|
||||
#endif
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
void LUA_EXTENSIONS_DLL luaopen_lua_extensions(lua_State *L);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LUA_EXTRA_H_ */
|
|
@ -0,0 +1,158 @@
|
|||
/*=========================================================================*\
|
||||
* Auxiliar routines for class hierarchy manipulation
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "auxiliar.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes the module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_open(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a new class with given methods
|
||||
* Methods whose names start with __ are passed directly to the metatable.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
|
||||
luaL_newmetatable(L, classname); /* mt */
|
||||
/* create __index table to place methods */
|
||||
lua_pushstring(L, "__index"); /* mt,"__index" */
|
||||
lua_newtable(L); /* mt,"__index",it */
|
||||
/* put class name into class metatable */
|
||||
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
|
||||
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
|
||||
lua_rawset(L, -3); /* mt,"__index",it */
|
||||
/* pass all methods that start with _ to the metatable, and all others
|
||||
* to the index table */
|
||||
for (; func->name; func++) { /* mt,"__index",it */
|
||||
lua_pushstring(L, func->name);
|
||||
lua_pushcfunction(L, func->func);
|
||||
lua_rawset(L, func->name[0] == '_' ? -5: -3);
|
||||
}
|
||||
lua_rawset(L, -3); /* mt */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Prints the value of a class in a nice way
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_tostring(lua_State *L) {
|
||||
char buf[32];
|
||||
if (!lua_getmetatable(L, 1)) goto error;
|
||||
lua_pushstring(L, "__index");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_istable(L, -1)) goto error;
|
||||
lua_pushstring(L, "class");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isstring(L, -1)) goto error;
|
||||
sprintf(buf, "%p", lua_touserdata(L, 1));
|
||||
lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
|
||||
return 1;
|
||||
error:
|
||||
lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
|
||||
lua_error(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Insert class into group
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) {
|
||||
luaL_getmetatable(L, classname);
|
||||
lua_pushstring(L, groupname);
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, -3);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Make sure argument is a boolean
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_checkboolean(lua_State *L, int objidx) {
|
||||
if (!lua_isboolean(L, objidx))
|
||||
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
|
||||
return lua_toboolean(L, objidx);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return userdata pointer if object belongs to a given class, abort with
|
||||
* error otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
|
||||
void *data = auxiliar_getclassudata(L, classname, objidx);
|
||||
if (!data) {
|
||||
char msg[45];
|
||||
sprintf(msg, "%.35s expected", classname);
|
||||
luaL_argerror(L, objidx, msg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return userdata pointer if object belongs to a given group, abort with
|
||||
* error otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
|
||||
void *data = auxiliar_getgroupudata(L, groupname, objidx);
|
||||
if (!data) {
|
||||
char msg[45];
|
||||
sprintf(msg, "%.35s expected", groupname);
|
||||
luaL_argerror(L, objidx, msg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Set object class
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
|
||||
luaL_getmetatable(L, classname);
|
||||
if (objidx < 0) objidx--;
|
||||
lua_setmetatable(L, objidx);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Get a userdata pointer if object belongs to a given group. Return NULL
|
||||
* otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
||||
if (!lua_getmetatable(L, objidx))
|
||||
return NULL;
|
||||
lua_pushstring(L, groupname);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return NULL;
|
||||
} else {
|
||||
lua_pop(L, 2);
|
||||
return lua_touserdata(L, objidx);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Get a userdata pointer if object belongs to a given class. Return NULL
|
||||
* otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
|
||||
return luaL_checkudata(L, objidx, classname);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Throws error when argument does not have correct type.
|
||||
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
|
||||
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
|
||||
luaL_typename(L, narg));
|
||||
return luaL_argerror(L, narg, msg);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef AUXILIAR_H
|
||||
#define AUXILIAR_H
|
||||
/*=========================================================================*\
|
||||
* Auxiliar routines for class hierarchy manipulation
|
||||
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
|
||||
*
|
||||
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
|
||||
* group is a name associated with a class. A class can belong to any number
|
||||
* of groups. This module provides the functionality to:
|
||||
*
|
||||
* - create new classes
|
||||
* - add classes to groups
|
||||
* - set the class of objects
|
||||
* - check if an object belongs to a given class or group
|
||||
* - get the userdata associated to objects
|
||||
* - print objects in a pretty way
|
||||
*
|
||||
* LuaSocket class names follow the convention <module>{<class>}. Modules
|
||||
* can define any number of classes and groups. The module tcp.c, for
|
||||
* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
|
||||
* the groups tcp{client,server} and tcp{any}. Module functions can then
|
||||
* perform type-checking on their arguments by either class or group.
|
||||
*
|
||||
* LuaSocket metatables define the __index metamethod as being a table. This
|
||||
* table has one field for each method supported by the class, and a field
|
||||
* "class" with the class name.
|
||||
*
|
||||
* The mapping from class name to the corresponding metatable and the
|
||||
* reverse mapping are done using lauxlib.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
int auxiliar_open(lua_State *L);
|
||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
|
||||
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
|
||||
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
|
||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
|
||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
|
||||
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
|
||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
|
||||
int auxiliar_checkboolean(lua_State *L, int objidx);
|
||||
int auxiliar_tostring(lua_State *L);
|
||||
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
|
||||
|
||||
#endif /* AUXILIAR_H */
|
|
@ -0,0 +1,97 @@
|
|||
/*=========================================================================*\
|
||||
* Simple exception support
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "except.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int global_protect(lua_State *L);
|
||||
static int global_newtry(lua_State *L);
|
||||
static int protected_(lua_State *L);
|
||||
static int finalize(lua_State *L);
|
||||
static int do_nothing(lua_State *L);
|
||||
|
||||
/* except functions */
|
||||
static luaL_Reg func[] = {
|
||||
{"newtry", global_newtry},
|
||||
{"protect", global_protect},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Try factory
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void wrap(lua_State *L) {
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L, 1);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_settable(L, -3);
|
||||
lua_insert(L, -2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
static int finalize(lua_State *L) {
|
||||
if (!lua_toboolean(L, 1)) {
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_pcall(L, 0, 0, 0);
|
||||
lua_settop(L, 2);
|
||||
wrap(L);
|
||||
lua_error(L);
|
||||
return 0;
|
||||
} else return lua_gettop(L);
|
||||
}
|
||||
|
||||
static int do_nothing(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int global_newtry(lua_State *L) {
|
||||
lua_settop(L, 1);
|
||||
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
|
||||
lua_pushcclosure(L, finalize, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Protect factory
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int unwrap(lua_State *L) {
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnumber(L, 1);
|
||||
lua_gettable(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 1;
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
static int protected_(lua_State *L) {
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_insert(L, 1);
|
||||
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
|
||||
if (unwrap(L)) return 2;
|
||||
else lua_error(L);
|
||||
return 0;
|
||||
} else return lua_gettop(L);
|
||||
}
|
||||
|
||||
static int global_protect(lua_State *L) {
|
||||
lua_pushcclosure(L, protected_, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Init module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int except_open(lua_State *L) {
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef EXCEPT_H
|
||||
#define EXCEPT_H
|
||||
/*=========================================================================*\
|
||||
* Exception control
|
||||
* LuaSocket toolkit (but completely independent from other modules)
|
||||
*
|
||||
* This provides support for simple exceptions in Lua. During the
|
||||
* development of the HTTP/FTP/SMTP support, it became aparent that
|
||||
* error checking was taking a substantial amount of the coding. These
|
||||
* function greatly simplify the task of checking errors.
|
||||
*
|
||||
* The main idea is that functions should return nil as its first return
|
||||
* value when it finds an error, and return an error message (or value)
|
||||
* following nil. In case of success, as long as the first value is not nil,
|
||||
* the other values don't matter.
|
||||
*
|
||||
* The idea is to nest function calls with the "try" function. This function
|
||||
* checks the first value, and calls "error" on the second if the first is
|
||||
* nil. Otherwise, it returns all values it received.
|
||||
*
|
||||
* The protect function returns a new function that behaves exactly like the
|
||||
* function it receives, but the new function doesn't throw exceptions: it
|
||||
* returns nil followed by the error message instead.
|
||||
*
|
||||
* With these two function, it's easy to write functions that throw
|
||||
* exceptions on error, but that don't interrupt the user script.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
int except_open(lua_State *L);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,528 @@
|
|||
/*=========================================================================*\
|
||||
* Internet domain functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "inet.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int inet_global_toip(lua_State *L);
|
||||
static int inet_global_getaddrinfo(lua_State *L);
|
||||
static int inet_global_tohostname(lua_State *L);
|
||||
static int inet_global_getnameinfo(lua_State *L);
|
||||
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
||||
static int inet_global_gethostname(lua_State *L);
|
||||
|
||||
/* DNS functions */
|
||||
static luaL_Reg func[] = {
|
||||
{ "toip", inet_global_toip},
|
||||
{ "getaddrinfo", inet_global_getaddrinfo},
|
||||
{ "tohostname", inet_global_tohostname},
|
||||
{ "getnameinfo", inet_global_getnameinfo},
|
||||
{ "gethostname", inet_global_gethostname},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
#ifdef _WINDOWS_
|
||||
/****luodx patch for windows xp start**/
|
||||
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length)
|
||||
{
|
||||
char* result = inet_ntoa(*(IN_ADDR*)src);
|
||||
if (result != NULL){
|
||||
strcpy(dest, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int win32xp_inet_pton(int family, const char* string, PVOID dest) {
|
||||
return inet_aton(string, (IN_ADDR*)dest);
|
||||
}
|
||||
/****luodx patch for windows xp end**/
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_open(lua_State *L)
|
||||
{
|
||||
lua_pushstring(L, "dns");
|
||||
lua_newtable(L);
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
lua_settable(L, -3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_gethost(const char *address, struct hostent **hp) {
|
||||
struct in_addr addr;
|
||||
if (inet_aton(address, &addr))
|
||||
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
|
||||
else
|
||||
return socket_gethostbyname(address, hp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_tohostname(lua_State *L) {
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
struct hostent *hp = NULL;
|
||||
int err = inet_gethost(address, &hp);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_hoststrerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, hp->h_name);
|
||||
inet_pushresolved(L, hp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int inet_global_getnameinfo(lua_State *L) {
|
||||
int i, ret;
|
||||
char host[1024];
|
||||
char serv[32];
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *resolved, *iter;
|
||||
const char *node = luaL_optstring(L, 1, NULL);
|
||||
const char *service = luaL_optstring(L, 2, NULL);
|
||||
|
||||
if (!(node || service))
|
||||
luaL_error(L, "You have to specify a hostname, a service, or both");
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
/* getaddrinfo must get a node and a service argument */
|
||||
ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7",
|
||||
&hints, &resolved);
|
||||
if (ret != 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_gaistrerror(ret));
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
|
||||
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host,
|
||||
node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0);
|
||||
|
||||
if (node) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, host);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
|
||||
if (service) {
|
||||
lua_pushstring(L, serv);
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_toip(lua_State *L)
|
||||
{
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
struct hostent *hp = NULL;
|
||||
int err = inet_gethost(address, &hp);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_hoststrerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
|
||||
inet_pushresolved(L, hp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int inet_optfamily(lua_State* L, int narg, const char* def)
|
||||
{
|
||||
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
|
||||
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
|
||||
|
||||
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||
}
|
||||
|
||||
int inet_optsocktype(lua_State* L, int narg, const char* def)
|
||||
{
|
||||
static const char* optname[] = { "stream", "dgram", NULL };
|
||||
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
|
||||
|
||||
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||
}
|
||||
|
||||
static int inet_global_getaddrinfo(lua_State *L)
|
||||
{
|
||||
const char *hostname = luaL_checkstring(L, 1);
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
struct addrinfo hints;
|
||||
int i = 1, ret = 0;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
|
||||
if (ret != 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_gaistrerror(ret));
|
||||
return 2;
|
||||
}
|
||||
lua_newtable(L);
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf,
|
||||
(socklen_t) sizeof(hbuf), sbuf, 0, NI_NUMERICHOST);
|
||||
lua_pushnumber(L, i);
|
||||
lua_newtable(L);
|
||||
switch (iterator->ai_family) {
|
||||
case AF_INET:
|
||||
lua_pushliteral(L, "family");
|
||||
lua_pushliteral(L, "inet");
|
||||
lua_settable(L, -3);
|
||||
break;
|
||||
case AF_INET6:
|
||||
lua_pushliteral(L, "family");
|
||||
lua_pushliteral(L, "inet6");
|
||||
lua_settable(L, -3);
|
||||
break;;
|
||||
}
|
||||
lua_pushliteral(L, "addr");
|
||||
lua_pushstring(L, hbuf);
|
||||
lua_settable(L, -3);
|
||||
lua_settable(L, -3);
|
||||
i++;
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Gets the host name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_gethostname(lua_State *L)
|
||||
{
|
||||
char name[257];
|
||||
name[256] = '\0';
|
||||
if (gethostname(name, 256) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
lua_pushstring(L, name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Retrieves socket peer name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in peer;
|
||||
socklen_t peer_len = sizeof(peer);
|
||||
char name[INET_ADDRSTRLEN];
|
||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &peer.sin_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(peer.sin_port));
|
||||
lua_pushliteral(L, "inet");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 peer;
|
||||
socklen_t peer_len = sizeof(peer);
|
||||
char name[INET6_ADDRSTRLEN];
|
||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(peer.sin6_port));
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", family);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Retrieves socket local name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in local;
|
||||
socklen_t local_len = sizeof(local);
|
||||
char name[INET_ADDRSTRLEN];
|
||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &local.sin_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(local.sin_port));
|
||||
lua_pushliteral(L, "inet");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 local;
|
||||
socklen_t local_len = sizeof(local);
|
||||
char name[INET6_ADDRSTRLEN];
|
||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &local.sin6_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(local.sin6_port));
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", family);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Passes all resolver information to Lua as a table
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
||||
{
|
||||
char **alias;
|
||||
struct in_addr **addr;
|
||||
int i, resolved;
|
||||
lua_newtable(L); resolved = lua_gettop(L);
|
||||
lua_pushstring(L, "name");
|
||||
lua_pushstring(L, hp->h_name);
|
||||
lua_settable(L, resolved);
|
||||
lua_pushstring(L, "ip");
|
||||
lua_pushstring(L, "alias");
|
||||
i = 1;
|
||||
alias = hp->h_aliases;
|
||||
lua_newtable(L);
|
||||
if (alias) {
|
||||
while (*alias) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, *alias);
|
||||
lua_settable(L, -3);
|
||||
i++; alias++;
|
||||
}
|
||||
}
|
||||
lua_settable(L, resolved);
|
||||
i = 1;
|
||||
lua_newtable(L);
|
||||
addr = (struct in_addr **) hp->h_addr_list;
|
||||
if (addr) {
|
||||
while (*addr) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, inet_ntoa(**addr));
|
||||
lua_settable(L, -3);
|
||||
i++; addr++;
|
||||
}
|
||||
}
|
||||
lua_settable(L, resolved);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to create a new inet socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trycreate(p_socket ps, int family, int type) {
|
||||
return socket_strerror(socket_create(ps, family, type, 0));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* "Disconnects" a DGRAM socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in sin;
|
||||
memset((char *) &sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_UNSPEC;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
return socket_strerror(socket_connect(ps, (SA *) &sin,
|
||||
sizeof(sin), tm));
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 sin6;
|
||||
struct in6_addr addrany = IN6ADDR_ANY_INIT;
|
||||
memset((char *) &sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_UNSPEC;
|
||||
fprintf(stderr, "disconnecting\n");
|
||||
sin6.sin6_addr = addrany;
|
||||
return socket_strerror(socket_connect(ps, (SA *) &sin6,
|
||||
sizeof(sin6), tm));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to connect to remote address (address, port)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
||||
const char *serv, p_timeout tm, struct addrinfo *connecthints)
|
||||
{
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(address, serv,
|
||||
connecthints, &resolved));
|
||||
if (err != NULL) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
timeout_markstart(tm);
|
||||
/* try connecting to remote address */
|
||||
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen, tm));
|
||||
/* if success, break out of loop */
|
||||
if (err == NULL) break;
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
/* here, if err is set, we failed */
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to accept a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm)
|
||||
{
|
||||
socklen_t len;
|
||||
t_sockaddr_storage addr;
|
||||
if (family == PF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to bind socket to (address, port)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
||||
struct addrinfo *bindhints)
|
||||
{
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
t_socket sock = *ps;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
|
||||
if (err) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
/* iterate over resolved addresses until one is good */
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
if(sock == SOCKET_INVALID) {
|
||||
err = socket_strerror(socket_create(&sock, iterator->ai_family,
|
||||
iterator->ai_socktype, iterator->ai_protocol));
|
||||
if(err)
|
||||
continue;
|
||||
}
|
||||
/* try binding to local address */
|
||||
err = socket_strerror(socket_bind(&sock,
|
||||
(SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen));
|
||||
|
||||
/* keep trying unless bind succeeded */
|
||||
if (err) {
|
||||
if(sock != *ps)
|
||||
socket_destroy(&sock);
|
||||
} else {
|
||||
/* remember what we connected to, particularly the family */
|
||||
*bindhints = *iterator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* cleanup and return error */
|
||||
freeaddrinfo(resolved);
|
||||
*ps = sock;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Some systems do not provide this so that we provide our own. It's not
|
||||
* marvelously fast, but it works just fine.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *inp)
|
||||
{
|
||||
unsigned int a = 0, b = 0, c = 0, d = 0;
|
||||
int n = 0, r;
|
||||
unsigned long int addr = 0;
|
||||
r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
|
||||
if (r == 0 || n == 0) return 0;
|
||||
cp += n;
|
||||
if (*cp) return 0;
|
||||
if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
|
||||
if (inp) {
|
||||
addr += a; addr <<= 8;
|
||||
addr += b; addr <<= 8;
|
||||
addr += c; addr <<= 8;
|
||||
addr += d;
|
||||
inp->s_addr = htonl(addr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef INET_H
|
||||
#define INET_H
|
||||
/*=========================================================================*\
|
||||
* Internet domain functions
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module implements the creation and connection of internet domain
|
||||
* sockets, on top of the socket.h interface, and the interface of with the
|
||||
* resolver.
|
||||
*
|
||||
* The function inet_aton is provided for the platforms where it is not
|
||||
* available. The module also implements the interface of the internet
|
||||
* getpeername and getsockname functions as seen by Lua programs.
|
||||
*
|
||||
* The Lua functions toip and tohostname are also implemented here.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "socket.h"
|
||||
#include "timeout.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define INET_ATON
|
||||
#endif
|
||||
|
||||
int inet_open(lua_State *L);
|
||||
|
||||
const char *inet_trycreate(p_socket ps, int family, int type);
|
||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
||||
const char *serv, p_timeout tm, struct addrinfo *connecthints);
|
||||
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
||||
struct addrinfo *bindhints);
|
||||
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
|
||||
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
|
||||
|
||||
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
|
||||
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
|
||||
|
||||
int inet_optfamily(lua_State* L, int narg, const char* def);
|
||||
int inet_optsocktype(lua_State* L, int narg, const char* def);
|
||||
|
||||
#ifdef INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *inp);
|
||||
#endif
|
||||
|
||||
#ifndef _WINDOWS_
|
||||
#define my_inet_ntop(a,b,c,d) inet_ntop(a,b,c,d)
|
||||
#define my_inet_pton(a,b,c) inet_pton(a,b,c)
|
||||
#else
|
||||
int win32xp_inet_pton(int family, const char* string, PVOID dest);
|
||||
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length);
|
||||
#define my_inet_ntop(a,b,c,d) win32xp_inet_ntop(a,b,c,d)
|
||||
#define my_inet_pton(a,b,c) win32xp_inet_pton(a,b,c)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* INET_H */
|
|
@ -0,0 +1,116 @@
|
|||
/*=========================================================================*\
|
||||
* LuaSocket toolkit
|
||||
* Networking support for the Lua language
|
||||
* Diego Nehab
|
||||
* 26/11/1999
|
||||
*
|
||||
* This library is part of an effort to progressively increase the network
|
||||
* connectivity of the Lua language. The Lua interface to networking
|
||||
* functions follows the Sockets API closely, trying to simplify all tasks
|
||||
* involved in setting up both client and server connections. The provided
|
||||
* IO routines, however, follow the Lua style, being very similar to the
|
||||
* standard Lua read and write functions.
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* Standard include files
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
||||
#include "compat-5.1.h"
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* LuaSocket includes
|
||||
\*=========================================================================*/
|
||||
#include "luasocket.h"
|
||||
#include "auxiliar.h"
|
||||
#include "except.h"
|
||||
#include "timeout.h"
|
||||
#include "luasocket_buffer.h"
|
||||
#include "inet.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "select.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Internal function prototypes
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_skip(lua_State *L);
|
||||
static int global_unload(lua_State *L);
|
||||
static int base_open(lua_State *L);
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Modules and functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const luaL_Reg mod[] = {
|
||||
{"auxiliar", auxiliar_open},
|
||||
{"except", except_open},
|
||||
{"timeout", timeout_open},
|
||||
{"buffer", buffer_open},
|
||||
{"inet", inet_open},
|
||||
{"tcp", tcp_open},
|
||||
{"udp", udp_open},
|
||||
{"select", select_open},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static luaL_Reg func[] = {
|
||||
{"skip", global_skip},
|
||||
{"__unload", global_unload},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Skip a few arguments
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_skip(lua_State *L) {
|
||||
int amount = luaL_checkint(L, 1);
|
||||
int ret = lua_gettop(L) - amount - 1;
|
||||
return ret >= 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Unloads the library
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_unload(lua_State *L) {
|
||||
(void) L;
|
||||
socket_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Setup basic stuff.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int base_open(lua_State *L) {
|
||||
if (socket_open()) {
|
||||
/* export functions (and leave namespace table on top of stack) */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
lua_pushstring(L, "_DEBUG");
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, -3);
|
||||
#endif
|
||||
/* make version string available to scripts */
|
||||
lua_pushstring(L, "_VERSION");
|
||||
lua_pushstring(L, LUASOCKET_VERSION);
|
||||
lua_rawset(L, -3);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushstring(L, "unable to initialize library");
|
||||
lua_error(L);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes all library modules.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_core(lua_State *L) {
|
||||
int i;
|
||||
base_open(L);
|
||||
for (i = 0; mod[i].name; i++) mod[i].func(L);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef LUASOCKET_H
|
||||
#define LUASOCKET_H
|
||||
/*=========================================================================*\
|
||||
* LuaSocket toolkit
|
||||
* Networking support for the Lua language
|
||||
* Diego Nehab
|
||||
* 9/11/1999
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Current socket library version
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define LUASOCKET_VERSION "LuaSocket 2.1-rc1"
|
||||
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2012 Diego Nehab"
|
||||
#define LUASOCKET_AUTHORS "Diego Nehab"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* This macro prefixes all exported API functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef LUASOCKET_API
|
||||
#define LUASOCKET_API extern
|
||||
#endif
|
||||
|
||||
#if LUA_VERSION_NUM > 501 & !( defined LUA_COMPAT_MODULE)
|
||||
# error Lua 5.2 requires LUA_COMPAT_MODULE defined for luaL_openlib
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes the library.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_core(lua_State *L);
|
||||
|
||||
#endif /* LUASOCKET_H */
|
|
@ -0,0 +1,276 @@
|
|||
/*=========================================================================*\
|
||||
* Input/Output interface for Lua programs
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "luasocket_buffer.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
|
||||
static int recvline(p_buffer buf, luaL_Buffer *b);
|
||||
static int recvall(p_buffer buf, luaL_Buffer *b);
|
||||
static int buffer_get(p_buffer buf, const char **data, size_t *count);
|
||||
static void buffer_skip(p_buffer buf, size_t count);
|
||||
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_open(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes C structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
|
||||
buf->first = buf->last = 0;
|
||||
buf->io = io;
|
||||
buf->tm = tm;
|
||||
buf->received = buf->sent = 0;
|
||||
buf->birthday = timeout_gettime();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:getstats() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
|
||||
lua_pushnumber(L, (lua_Number) buf->received);
|
||||
lua_pushnumber(L, (lua_Number) buf->sent);
|
||||
lua_pushnumber(L, timeout_gettime() - buf->birthday);
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:setstats() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
|
||||
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
|
||||
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
|
||||
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:send() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_send(lua_State *L, p_buffer buf) {
|
||||
int top = lua_gettop(L);
|
||||
int err = IO_DONE;
|
||||
size_t size = 0, sent = 0;
|
||||
const char *data = luaL_checklstring(L, 2, &size);
|
||||
long start = (long) luaL_optnumber(L, 3, 1);
|
||||
long end = (long) luaL_optnumber(L, 4, -1);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
p_timeout tm = timeout_markstart(buf->tm);
|
||||
#endif
|
||||
if (start < 0) start = (long) (size+start+1);
|
||||
if (end < 0) end = (long) (size+end+1);
|
||||
if (start < 1) start = (long) 1;
|
||||
if (end > (long) size) end = (long) size;
|
||||
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
|
||||
/* check if there was an error */
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||
} else {
|
||||
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* push time elapsed during operation as the last return value */
|
||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
||||
#endif
|
||||
return lua_gettop(L) - top;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:receive() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_receive(lua_State *L, p_buffer buf) {
|
||||
int err = IO_DONE, top = lua_gettop(L);
|
||||
luaL_Buffer b;
|
||||
size_t size;
|
||||
const char *part = luaL_optlstring(L, 3, "", &size);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
p_timeout tm = timeout_markstart(buf->tm);
|
||||
#endif
|
||||
/* initialize buffer with optional extra prefix
|
||||
* (useful for concatenating previous partial results) */
|
||||
luaL_buffinit(L, &b);
|
||||
luaL_addlstring(&b, part, size);
|
||||
/* receive new patterns */
|
||||
if (!lua_isnumber(L, 2)) {
|
||||
const char *p= luaL_optstring(L, 2, "*l");
|
||||
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
|
||||
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
|
||||
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
|
||||
/* get a fixed number of bytes (minus what was already partially
|
||||
* received) */
|
||||
} else {
|
||||
double n = lua_tonumber(L, 2);
|
||||
size_t wanted = (size_t) n;
|
||||
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
|
||||
if (size == 0 || wanted > size)
|
||||
err = recvraw(buf, wanted-size, &b);
|
||||
}
|
||||
/* check if there was an error */
|
||||
if (err != IO_DONE) {
|
||||
/* we can't push anyting in the stack before pushing the
|
||||
* contents of the buffer. this is the reason for the complication */
|
||||
luaL_pushresult(&b);
|
||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_replace(L, -4);
|
||||
} else {
|
||||
luaL_pushresult(&b);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* push time elapsed during operation as the last return value */
|
||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
||||
#endif
|
||||
return lua_gettop(L) - top;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines if there is any data in the read buffer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_isempty(p_buffer buf) {
|
||||
return buf->first >= buf->last;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sends a block of data (unbuffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define STEPSIZE 8192
|
||||
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
|
||||
p_io io = buf->io;
|
||||
p_timeout tm = buf->tm;
|
||||
size_t total = 0;
|
||||
int err = IO_DONE;
|
||||
while (total < count && err == IO_DONE) {
|
||||
size_t done = 0;
|
||||
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
|
||||
err = io->send(io->ctx, data+total, step, &done, tm);
|
||||
total += done;
|
||||
}
|
||||
*sent = total;
|
||||
buf->sent += total;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads a fixed number of bytes (buffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
size_t total = 0;
|
||||
while (err == IO_DONE) {
|
||||
size_t count; const char *data;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
count = MIN(count, wanted - total);
|
||||
luaL_addlstring(b, data, count);
|
||||
buffer_skip(buf, count);
|
||||
total += count;
|
||||
if (total >= wanted) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads everything until the connection is closed (buffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvall(p_buffer buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
size_t total = 0;
|
||||
while (err == IO_DONE) {
|
||||
const char *data; size_t count;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
total += count;
|
||||
luaL_addlstring(b, data, count);
|
||||
buffer_skip(buf, count);
|
||||
}
|
||||
if (err == IO_CLOSED) {
|
||||
if (total > 0) return IO_DONE;
|
||||
else return IO_CLOSED;
|
||||
} else return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
||||
* are not returned by the function and are discarded from the buffer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvline(p_buffer buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
while (err == IO_DONE) {
|
||||
size_t count, pos; const char *data;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
pos = 0;
|
||||
while (pos < count && data[pos] != '\n') {
|
||||
/* we ignore all \r's */
|
||||
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
|
||||
pos++;
|
||||
}
|
||||
if (pos < count) { /* found '\n' */
|
||||
buffer_skip(buf, pos+1); /* skip '\n' too */
|
||||
break; /* we are done */
|
||||
} else /* reached the end of the buffer */
|
||||
buffer_skip(buf, pos);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Skips a given number of bytes from read buffer. No data is read from the
|
||||
* transport layer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void buffer_skip(p_buffer buf, size_t count) {
|
||||
buf->received += count;
|
||||
buf->first += count;
|
||||
if (buffer_isempty(buf))
|
||||
buf->first = buf->last = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return any data available in buffer, or get more data from transport layer
|
||||
* if buffer is empty
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int buffer_get(p_buffer buf, const char **data, size_t *count) {
|
||||
int err = IO_DONE;
|
||||
p_io io = buf->io;
|
||||
p_timeout tm = buf->tm;
|
||||
if (buffer_isempty(buf)) {
|
||||
size_t got;
|
||||
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
|
||||
buf->first = 0;
|
||||
buf->last = got;
|
||||
}
|
||||
*count = buf->last - buf->first;
|
||||
*data = buf->data + buf->first;
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef BUF_H
|
||||
#define BUF_H
|
||||
/*=========================================================================*\
|
||||
* Input/Output interface for Lua programs
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* Line patterns require buffering. Reading one character at a time involves
|
||||
* too many system calls and is very slow. This module implements the
|
||||
* LuaSocket interface for input/output on connected objects, as seen by
|
||||
* Lua programs.
|
||||
*
|
||||
* Input is buffered. Output is *not* buffered because there was no simple
|
||||
* way of making sure the buffered output data would ever be sent.
|
||||
*
|
||||
* The module is built on top of the I/O abstraction defined in io.h and the
|
||||
* timeout management is done with the timeout.h interface.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "luasocket_io.h"
|
||||
#include "timeout.h"
|
||||
|
||||
/* buffer size in bytes */
|
||||
#define BUF_SIZE 8192
|
||||
|
||||
/* buffer control structure */
|
||||
typedef struct t_buffer_ {
|
||||
double birthday; /* throttle support info: creation time, */
|
||||
size_t sent, received; /* bytes sent, and bytes received */
|
||||
p_io io; /* IO driver used for this buffer */
|
||||
p_timeout tm; /* timeout management for this buffer */
|
||||
size_t first, last; /* index of first and last bytes of stored data */
|
||||
char data[BUF_SIZE]; /* storage space for buffer data */
|
||||
} t_buffer;
|
||||
typedef t_buffer *p_buffer;
|
||||
|
||||
int buffer_open(lua_State *L);
|
||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
|
||||
int buffer_meth_send(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_receive(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_getstats(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_setstats(lua_State *L, p_buffer buf);
|
||||
int buffer_isempty(p_buffer buf);
|
||||
|
||||
#endif /* BUF_H */
|
|
@ -0,0 +1,30 @@
|
|||
/*=========================================================================*\
|
||||
* Input/Output abstraction
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "luasocket_io.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes C structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) {
|
||||
io->send = send;
|
||||
io->recv = recv;
|
||||
io->error = error;
|
||||
io->ctx = ctx;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* I/O error strings
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *io_strerror(int err) {
|
||||
switch (err) {
|
||||
case IO_DONE: return NULL;
|
||||
case IO_CLOSED: return "closed";
|
||||
case IO_TIMEOUT: return "timeout";
|
||||
default: return "unknown error";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef IO_H
|
||||
#define IO_H
|
||||
/*=========================================================================*\
|
||||
* Input/Output abstraction
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module defines the interface that LuaSocket expects from the
|
||||
* transport layer for streamed input/output. The idea is that if any
|
||||
* transport implements this interface, then the buffer.c functions
|
||||
* automatically work on it.
|
||||
*
|
||||
* The module socket.h implements this interface, and thus the module tcp.h
|
||||
* is very simple.
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include "lua.h"
|
||||
|
||||
#include "timeout.h"
|
||||
|
||||
/* IO error codes */
|
||||
enum {
|
||||
IO_DONE = 0, /* operation completed successfully */
|
||||
IO_TIMEOUT = -1, /* operation timed out */
|
||||
IO_CLOSED = -2, /* the connection has been closed */
|
||||
IO_UNKNOWN = -3
|
||||
};
|
||||
|
||||
/* interface to error message function */
|
||||
typedef const char *(*p_error) (
|
||||
void *ctx, /* context needed by send */
|
||||
int err /* error code */
|
||||
);
|
||||
|
||||
/* interface to send function */
|
||||
typedef int (*p_send) (
|
||||
void *ctx, /* context needed by send */
|
||||
const char *data, /* pointer to buffer with data to send */
|
||||
size_t count, /* number of bytes to send from buffer */
|
||||
size_t *sent, /* number of bytes sent uppon return */
|
||||
p_timeout tm /* timeout control */
|
||||
);
|
||||
|
||||
/* interface to recv function */
|
||||
typedef int (*p_recv) (
|
||||
void *ctx, /* context needed by recv */
|
||||
char *data, /* pointer to buffer where data will be writen */
|
||||
size_t count, /* number of bytes to receive into buffer */
|
||||
size_t *got, /* number of bytes received uppon return */
|
||||
p_timeout tm /* timeout control */
|
||||
);
|
||||
|
||||
/* IO driver definition */
|
||||
typedef struct t_io_ {
|
||||
void *ctx; /* context needed by send/recv */
|
||||
p_send send; /* send function pointer */
|
||||
p_recv recv; /* receive function pointer */
|
||||
p_error error; /* strerror function */
|
||||
} t_io;
|
||||
typedef t_io *p_io;
|
||||
|
||||
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
|
||||
const char *io_strerror(int err);
|
||||
|
||||
#endif /* IO_H */
|
||||
|
|
@ -0,0 +1,723 @@
|
|||
/*=========================================================================*\
|
||||
* MIME support functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
||||
#include "compat-5.1.h"
|
||||
#endif
|
||||
|
||||
#include "mime.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Don't want to trust escape character constants
|
||||
\*=========================================================================*/
|
||||
typedef unsigned char UC;
|
||||
static const char CRLF[] = "\r\n";
|
||||
static const char EQCRLF[] = "=\r\n";
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int mime_global_wrp(lua_State *L);
|
||||
static int mime_global_b64(lua_State *L);
|
||||
static int mime_global_unb64(lua_State *L);
|
||||
static int mime_global_qp(lua_State *L);
|
||||
static int mime_global_unqp(lua_State *L);
|
||||
static int mime_global_qpwrp(lua_State *L);
|
||||
static int mime_global_eol(lua_State *L);
|
||||
static int mime_global_dot(lua_State *L);
|
||||
|
||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
|
||||
static void b64setup(UC *base);
|
||||
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
|
||||
static void qpsetup(UC *class, UC *unbase);
|
||||
static void qpquote(UC c, luaL_Buffer *buffer);
|
||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t qpencode(UC c, UC *input, size_t size,
|
||||
const char *marker, luaL_Buffer *buffer);
|
||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
|
||||
|
||||
/* code support functions */
|
||||
static luaL_Reg func[] = {
|
||||
{ "dot", mime_global_dot },
|
||||
{ "b64", mime_global_b64 },
|
||||
{ "eol", mime_global_eol },
|
||||
{ "qp", mime_global_qp },
|
||||
{ "qpwrp", mime_global_qpwrp },
|
||||
{ "unb64", mime_global_unb64 },
|
||||
{ "unqp", mime_global_unqp },
|
||||
{ "wrp", mime_global_wrp },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Quoted-printable globals
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static UC qpclass[256];
|
||||
static UC qpbase[] = "0123456789ABCDEF";
|
||||
static UC qpunbase[256];
|
||||
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Base64 globals
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const UC b64base[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static UC b64unbase[256];
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
MIME_API int luaopen_mime_core(lua_State *L)
|
||||
{
|
||||
luaL_openlib(L, "mime", func, 0);
|
||||
/* make version string available to scripts */
|
||||
lua_pushstring(L, "_VERSION");
|
||||
lua_pushstring(L, MIME_VERSION);
|
||||
lua_rawset(L, -3);
|
||||
/* initialize lookup tables */
|
||||
qpsetup(qpclass, qpunbase);
|
||||
b64setup(b64unbase);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
|
||||
* A, n = wrp(l, B, length)
|
||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||
* 'l' is how many bytes are left for the first line of B.
|
||||
* 'n' is the number of bytes left in the last line of A.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_wrp(lua_State *L)
|
||||
{
|
||||
size_t size = 0;
|
||||
int left = (int) luaL_checknumber(L, 1);
|
||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||
const UC *last = input + size;
|
||||
int length = (int) luaL_optnumber(L, 3, 76);
|
||||
luaL_Buffer buffer;
|
||||
/* end of input black-hole */
|
||||
if (!input) {
|
||||
/* if last line has not been terminated, add a line break */
|
||||
if (left < length) lua_pushstring(L, CRLF);
|
||||
/* otherwise, we are done */
|
||||
else lua_pushnil(L);
|
||||
lua_pushnumber(L, length);
|
||||
return 2;
|
||||
}
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last) {
|
||||
switch (*input) {
|
||||
case '\r':
|
||||
break;
|
||||
case '\n':
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
left = length;
|
||||
break;
|
||||
default:
|
||||
if (left <= 0) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, left);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Fill base64 decode map.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void b64setup(UC *unbase)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
|
||||
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
|
||||
unbase['='] = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Acumulates bytes in input buffer until 3 bytes are available.
|
||||
* Translate the 3 bytes into Base64 form and append to buffer.
|
||||
* Returns new number of bytes in buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64encode(UC c, UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
input[size++] = c;
|
||||
if (size == 3) {
|
||||
UC code[4];
|
||||
unsigned long value = 0;
|
||||
value += input[0]; value <<= 8;
|
||||
value += input[1]; value <<= 8;
|
||||
value += input[2];
|
||||
code[3] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
size = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
|
||||
* Result, if any, is appended to buffer.
|
||||
* Returns 0.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64pad(const UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
unsigned long value = 0;
|
||||
UC code[4] = {'=', '=', '=', '='};
|
||||
switch (size) {
|
||||
case 1:
|
||||
value = input[0] << 4;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
break;
|
||||
case 2:
|
||||
value = input[0]; value <<= 8;
|
||||
value |= input[1]; value <<= 2;
|
||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Acumulates bytes in input buffer until 4 bytes are available.
|
||||
* Translate the 4 bytes from Base64 form and append to buffer.
|
||||
* Returns new number of bytes in buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64decode(UC c, UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
/* ignore invalid characters */
|
||||
if (b64unbase[c] > 64) return size;
|
||||
input[size++] = c;
|
||||
/* decode atom */
|
||||
if (size == 4) {
|
||||
UC decoded[3];
|
||||
int valid, value = 0;
|
||||
value = b64unbase[input[0]]; value <<= 6;
|
||||
value |= b64unbase[input[1]]; value <<= 6;
|
||||
value |= b64unbase[input[2]]; value <<= 6;
|
||||
value |= b64unbase[input[3]];
|
||||
decoded[2] = (UC) (value & 0xff); value >>= 8;
|
||||
decoded[1] = (UC) (value & 0xff); value >>= 8;
|
||||
decoded[0] = (UC) value;
|
||||
/* take care of paddding */
|
||||
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
|
||||
luaL_addlstring(buffer, (char *) decoded, valid);
|
||||
return 0;
|
||||
/* need more data */
|
||||
} else return size;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally applies the Base64 transfer content encoding to a string
|
||||
* A, B = b64(C, D)
|
||||
* A is the encoded version of the largest prefix of C .. D that is
|
||||
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
|
||||
* The easiest thing would be to concatenate the two strings and
|
||||
* encode the result, but we can't afford that or Lua would dupplicate
|
||||
* every chunk we received.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_b64(lua_State *L)
|
||||
{
|
||||
UC atom[3];
|
||||
size_t isize = 0, asize = 0;
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of the input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = b64encode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
size_t osize = 0;
|
||||
asize = b64pad(atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
/* if the output is empty and the input is nil, return nil */
|
||||
lua_tolstring(L, -1, &osize);
|
||||
if (osize == 0) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process the second part */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = b64encode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally removes the Base64 transfer content encoding from a string
|
||||
* A, B = b64(C, D)
|
||||
* A is the encoded version of the largest prefix of C .. D that is
|
||||
* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_unb64(lua_State *L)
|
||||
{
|
||||
UC atom[4];
|
||||
size_t isize = 0, asize = 0;
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of the input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = b64decode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second is nil, we are done */
|
||||
if (!input) {
|
||||
size_t osize = 0;
|
||||
luaL_pushresult(&buffer);
|
||||
/* if the output is empty and the input is nil, return nil */
|
||||
lua_tolstring(L, -1, &osize);
|
||||
if (osize == 0) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise, process the rest of the input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = b64decode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Quoted-printable encoding scheme
|
||||
* all (except CRLF in text) can be =XX
|
||||
* CLRL in not text must be =XX=XX
|
||||
* 33 through 60 inclusive can be plain
|
||||
* 62 through 126 inclusive can be plain
|
||||
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
|
||||
* encoded lines must be no longer than 76 not counting CRLF
|
||||
* soft line-break are =CRLF
|
||||
* To encode one byte, we need to see the next two.
|
||||
* Worst case is when we see a space, and wonder if a CRLF is comming
|
||||
\*-------------------------------------------------------------------------*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Split quoted-printable characters into classes
|
||||
* Precompute reverse map for encoding
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void qpsetup(UC *cl, UC *unbase)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
|
||||
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
|
||||
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
|
||||
cl['\t'] = QP_IF_LAST;
|
||||
cl[' '] = QP_IF_LAST;
|
||||
cl['\r'] = QP_CR;
|
||||
for (i = 0; i < 256; i++) unbase[i] = 255;
|
||||
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
|
||||
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
|
||||
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
|
||||
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
|
||||
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
|
||||
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
|
||||
unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
|
||||
unbase['f'] = 15;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Output one character in form =XX
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void qpquote(UC c, luaL_Buffer *buffer)
|
||||
{
|
||||
luaL_addchar(buffer, '=');
|
||||
luaL_addchar(buffer, qpbase[c >> 4]);
|
||||
luaL_addchar(buffer, qpbase[c & 0x0F]);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accumulate characters until we are sure about how to deal with them.
|
||||
* Once we are sure, output to the buffer, in the correct form.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qpencode(UC c, UC *input, size_t size,
|
||||
const char *marker, luaL_Buffer *buffer)
|
||||
{
|
||||
input[size++] = c;
|
||||
/* deal with all characters we can have */
|
||||
while (size > 0) {
|
||||
switch (qpclass[input[0]]) {
|
||||
/* might be the CR of a CRLF sequence */
|
||||
case QP_CR:
|
||||
if (size < 2) return size;
|
||||
if (input[1] == '\n') {
|
||||
luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else qpquote(input[0], buffer);
|
||||
break;
|
||||
/* might be a space and that has to be quoted if last in line */
|
||||
case QP_IF_LAST:
|
||||
if (size < 3) return size;
|
||||
/* if it is the last, quote it and we are done */
|
||||
if (input[1] == '\r' && input[2] == '\n') {
|
||||
qpquote(input[0], buffer);
|
||||
luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else luaL_addchar(buffer, input[0]);
|
||||
break;
|
||||
/* might have to be quoted always */
|
||||
case QP_QUOTED:
|
||||
qpquote(input[0], buffer);
|
||||
break;
|
||||
/* might never have to be quoted */
|
||||
default:
|
||||
luaL_addchar(buffer, input[0]);
|
||||
break;
|
||||
}
|
||||
input[0] = input[1]; input[1] = input[2];
|
||||
size--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Deal with the final characters
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
|
||||
else qpquote(input[i], buffer);
|
||||
}
|
||||
if (size > 0) luaL_addstring(buffer, EQCRLF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally converts a string to quoted-printable
|
||||
* A, B = qp(C, D, marker)
|
||||
* Marker is the text to be used to replace CRLF sequences found in A.
|
||||
* A is the encoded version of the largest prefix of C .. D that
|
||||
* can be encoded without doubts.
|
||||
* B has the remaining bytes of C .. D, *without* encoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_qp(lua_State *L)
|
||||
{
|
||||
|
||||
size_t asize = 0, isize = 0;
|
||||
UC atom[3];
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
const char *marker = luaL_optstring(L, 3, CRLF);
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 3);
|
||||
/* process first part of input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
asize = qppad(atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process rest of input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accumulate characters until we are sure about how to deal with them.
|
||||
* Once we are sure, output the to the buffer, in the correct form.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
||||
int d;
|
||||
input[size++] = c;
|
||||
/* deal with all characters we can deal */
|
||||
switch (input[0]) {
|
||||
/* if we have an escape character */
|
||||
case '=':
|
||||
if (size < 3) return size;
|
||||
/* eliminate soft line break */
|
||||
if (input[1] == '\r' && input[2] == '\n') return 0;
|
||||
/* decode quoted representation */
|
||||
c = qpunbase[input[1]]; d = qpunbase[input[2]];
|
||||
/* if it is an invalid, do not decode */
|
||||
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
|
||||
else luaL_addchar(buffer, (char) ((c << 4) + d));
|
||||
return 0;
|
||||
case '\r':
|
||||
if (size < 2) return size;
|
||||
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
|
||||
return 0;
|
||||
default:
|
||||
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
|
||||
luaL_addchar(buffer, input[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally decodes a string in quoted-printable
|
||||
* A, B = qp(C, D)
|
||||
* A is the decoded version of the largest prefix of C .. D that
|
||||
* can be decoded without doubts.
|
||||
* B has the remaining bytes of C .. D, *without* decoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_unqp(lua_State *L)
|
||||
{
|
||||
size_t asize = 0, isize = 0;
|
||||
UC atom[3];
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = qpdecode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
luaL_pushresult(&buffer);
|
||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process rest of input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = qpdecode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally breaks a quoted-printed string into lines
|
||||
* A, n = qpwrp(l, B, length)
|
||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||
* 'l' is how many bytes are left for the first line of B.
|
||||
* 'n' is the number of bytes left in the last line of A.
|
||||
* There are two complications: lines can't be broken in the middle
|
||||
* of an encoded =XX, and there might be line breaks already
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_qpwrp(lua_State *L)
|
||||
{
|
||||
size_t size = 0;
|
||||
int left = (int) luaL_checknumber(L, 1);
|
||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||
const UC *last = input + size;
|
||||
int length = (int) luaL_optnumber(L, 3, 76);
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
if (left < length) lua_pushstring(L, EQCRLF);
|
||||
else lua_pushnil(L);
|
||||
lua_pushnumber(L, length);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last) {
|
||||
switch (*input) {
|
||||
case '\r':
|
||||
break;
|
||||
case '\n':
|
||||
left = length;
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
break;
|
||||
case '=':
|
||||
if (left <= 3) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, EQCRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
default:
|
||||
if (left <= 1) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, EQCRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, left);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Here is what we do: \n, and \r are considered candidates for line
|
||||
* break. We issue *one* new line marker if any of them is seen alone, or
|
||||
* followed by a different one. That is, \n\n and \r\r will issue two
|
||||
* end of line markers each, but \r\n, \n\r etc will only issue *one*
|
||||
* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
|
||||
* probably other more obscure conventions.
|
||||
*
|
||||
* c is the current character being processed
|
||||
* last is the previous character
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define eolcandidate(c) (c == '\r' || c == '\n')
|
||||
static int eolprocess(int c, int last, const char *marker,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
if (eolcandidate(c)) {
|
||||
if (eolcandidate(last)) {
|
||||
if (c == last) luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else {
|
||||
luaL_addstring(buffer, marker);
|
||||
return c;
|
||||
}
|
||||
} else {
|
||||
luaL_addchar(buffer, (char) c);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Converts a string to uniform EOL convention.
|
||||
* A, n = eol(o, B, marker)
|
||||
* A is the converted version of the largest prefix of B that can be
|
||||
* converted unambiguously. 'o' is the context returned by the previous
|
||||
* call. 'n' is the new context.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_eol(lua_State *L)
|
||||
{
|
||||
int ctx = luaL_checkint(L, 1);
|
||||
size_t isize = 0;
|
||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||
const char *last = input + isize;
|
||||
const char *marker = luaL_optstring(L, 3, CRLF);
|
||||
luaL_Buffer buffer;
|
||||
luaL_buffinit(L, &buffer);
|
||||
/* end of input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnumber(L, 0);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
while (input < last)
|
||||
ctx = eolprocess(*input++, ctx, marker, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, ctx);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Takes one byte and stuff it if needed.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
|
||||
{
|
||||
luaL_addchar(buffer, (char) c);
|
||||
switch (c) {
|
||||
case '\r':
|
||||
return 1;
|
||||
case '\n':
|
||||
return (state == 1)? 2: 0;
|
||||
case '.':
|
||||
if (state == 2)
|
||||
luaL_addchar(buffer, '.');
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally applies smtp stuffing to a string
|
||||
* A, n = dot(l, D)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_dot(lua_State *L)
|
||||
{
|
||||
size_t isize = 0, state = (size_t) luaL_checknumber(L, 1);
|
||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||
const char *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnumber(L, 2);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
state = dot(*input++, state, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, (lua_Number) state);
|
||||
return 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef MIME_H
|
||||
#define MIME_H
|
||||
/*=========================================================================*\
|
||||
* Core MIME support
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module provides functions to implement transfer content encodings
|
||||
* and formatting conforming to RFC 2045. It is used by mime.lua, which
|
||||
* provide a higher level interface to this functionality.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Current MIME library version
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define MIME_VERSION "MIME 1.0.3-rc1"
|
||||
#define MIME_COPYRIGHT "Copyright (C) 2004-2012 Diego Nehab"
|
||||
#define MIME_AUTHORS "Diego Nehab"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* This macro prefixes all exported API functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef MIME_API
|
||||
#define MIME_API extern
|
||||
#endif
|
||||
|
||||
MIME_API int luaopen_mime_core(lua_State *L);
|
||||
|
||||
#endif /* MIME_H */
|
|
@ -0,0 +1,262 @@
|
|||
/*=========================================================================*\
|
||||
* Common option interface
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "options.h"
|
||||
#include "inet.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions prototypes
|
||||
\*=========================================================================*/
|
||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_set(lua_State *L, p_socket ps, int level, int name,
|
||||
void *val, int len);
|
||||
static int opt_get(lua_State *L, p_socket ps, int level, int name,
|
||||
void *val, int* len);
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Calls appropriate option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unsupported option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
return opt->func(L, ps);
|
||||
}
|
||||
|
||||
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unsupported option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
return opt->func(L, ps);
|
||||
}
|
||||
|
||||
/* enables reuse of local address */
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
/* enables reuse of local port */
|
||||
int opt_set_reuseport(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||
}
|
||||
|
||||
int opt_get_reuseport(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||
}
|
||||
|
||||
/* disables the Naggle algorithm */
|
||||
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
int opt_set_keepalive(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
int opt_get_keepalive(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
int opt_set_dontroute(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
||||
}
|
||||
|
||||
int opt_set_broadcast(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
int opt_set_linger(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct linger li; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "on");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isboolean(L, -1))
|
||||
luaL_argerror(L, 3, "boolean 'on' field expected");
|
||||
li.l_onoff = (u_short) lua_toboolean(L, -1);
|
||||
lua_pushstring(L, "timeout");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isnumber(L, -1))
|
||||
luaL_argerror(L, 3, "number 'timeout' field expected");
|
||||
li.l_linger = (u_short) lua_tonumber(L, -1);
|
||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
|
||||
}
|
||||
|
||||
int opt_get_linger(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct linger li; /* obj, name */
|
||||
int len = sizeof(li);
|
||||
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
|
||||
if (err)
|
||||
return err;
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L, li.l_onoff);
|
||||
lua_setfield(L, -2, "on");
|
||||
lua_pushinteger(L, li.l_linger);
|
||||
lua_setfield(L, -2, "timeout");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
|
||||
{
|
||||
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
|
||||
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
|
||||
{
|
||||
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
|
||||
struct in_addr val;
|
||||
val.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(address, "*") && !inet_aton(address, &val))
|
||||
luaL_argerror(L, 3, "ip expected");
|
||||
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct in_addr val;
|
||||
socklen_t len = sizeof(val);
|
||||
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "getsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, inet_ntoa(val));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
||||
}
|
||||
|
||||
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
||||
}
|
||||
|
||||
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Auxiliar functions
|
||||
\*=========================================================================*/
|
||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
struct ip_mreq val; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "multiaddr");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
||||
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
||||
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||
lua_pushstring(L, "interface");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'interface' field expected");
|
||||
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(lua_tostring(L, -1), "*") &&
|
||||
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
||||
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
static
|
||||
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
|
||||
{
|
||||
socklen_t socklen = *len;
|
||||
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "getsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
*len = socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
|
||||
{
|
||||
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
int val = 0;
|
||||
int len = sizeof(val);
|
||||
int err = opt_get(L, ps, level, name, (char *) &val, &len);
|
||||
if (err)
|
||||
return err;
|
||||
lua_pushboolean(L, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
/*=========================================================================*\
|
||||
* Common option interface
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module provides a common interface to socket options, used mainly by
|
||||
* modules UDP and TCP.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* option registry */
|
||||
typedef struct t_opt {
|
||||
const char *name;
|
||||
int (*func)(lua_State *L, p_socket ps);
|
||||
} t_opt;
|
||||
typedef t_opt *p_opt;
|
||||
|
||||
/* supported options for setoption */
|
||||
int opt_set_dontroute(lua_State *L, p_socket ps);
|
||||
int opt_set_broadcast(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
|
||||
int opt_set_keepalive(lua_State *L, p_socket ps);
|
||||
int opt_set_linger(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseport(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
|
||||
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
|
||||
|
||||
/* supported options for getoption */
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
|
||||
int opt_get_keepalive(lua_State *L, p_socket ps);
|
||||
int opt_get_linger(lua_State *L, p_socket ps);
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
|
||||
|
||||
/* invokes the appropriate option handler */
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
|
||||
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
/*=========================================================================*\
|
||||
* Select implementation
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "timeout.h"
|
||||
#include "select.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static t_socket getfd(lua_State *L);
|
||||
static int dirty(lua_State *L);
|
||||
static void collect_fd(lua_State *L, int tab, int itab,
|
||||
fd_set *set, t_socket *max_fd);
|
||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
|
||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||
int itab, int tab, int start);
|
||||
static void make_assoc(lua_State *L, int tab);
|
||||
static int global_select(lua_State *L);
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"select", global_select},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int select_open(lua_State *L) {
|
||||
lua_pushstring(L, "_SETSIZE");
|
||||
lua_pushnumber(L, FD_SETSIZE);
|
||||
lua_rawset(L, -3);
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for a set of sockets until a condition is met or timeout.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_select(lua_State *L) {
|
||||
int rtab, wtab, itab, ret, ndirty;
|
||||
t_socket max_fd = SOCKET_INVALID;
|
||||
fd_set rset, wset;
|
||||
t_timeout tm;
|
||||
double t = luaL_optnumber(L, 3, -1);
|
||||
FD_ZERO(&rset); FD_ZERO(&wset);
|
||||
lua_settop(L, 3);
|
||||
lua_newtable(L); itab = lua_gettop(L);
|
||||
lua_newtable(L); rtab = lua_gettop(L);
|
||||
lua_newtable(L); wtab = lua_gettop(L);
|
||||
collect_fd(L, 1, itab, &rset, &max_fd);
|
||||
collect_fd(L, 2, itab, &wset, &max_fd);
|
||||
ndirty = check_dirty(L, 1, rtab, &rset);
|
||||
t = ndirty > 0? 0.0: t;
|
||||
timeout_init(&tm, t, -1);
|
||||
timeout_markstart(&tm);
|
||||
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
|
||||
if (ret > 0 || ndirty > 0) {
|
||||
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
||||
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
|
||||
make_assoc(L, rtab);
|
||||
make_assoc(L, wtab);
|
||||
return 2;
|
||||
} else if (ret == 0) {
|
||||
lua_pushstring(L, "timeout");
|
||||
return 3;
|
||||
} else {
|
||||
luaL_error(L, "select failed");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
static t_socket getfd(lua_State *L) {
|
||||
t_socket fd = SOCKET_INVALID;
|
||||
lua_pushstring(L, "getfd");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
if (lua_isnumber(L, -1)) {
|
||||
double numfd = lua_tonumber(L, -1);
|
||||
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int dirty(lua_State *L) {
|
||||
int is = 0;
|
||||
lua_pushstring(L, "dirty");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
is = lua_toboolean(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return is;
|
||||
}
|
||||
|
||||
static void collect_fd(lua_State *L, int tab, int itab,
|
||||
fd_set *set, t_socket *max_fd) {
|
||||
int i = 1, n = 0;
|
||||
/* nil is the same as an empty table */
|
||||
if (lua_isnil(L, tab)) return;
|
||||
/* otherwise we need it to be a table */
|
||||
luaL_checktype(L, tab, LUA_TTABLE);
|
||||
for ( ;; ) {
|
||||
t_socket fd;
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
/* getfd figures out if this is a socket */
|
||||
fd = getfd(L);
|
||||
if (fd != SOCKET_INVALID) {
|
||||
/* make sure we don't overflow the fd_set */
|
||||
#ifdef _WIN32
|
||||
if (n >= FD_SETSIZE)
|
||||
luaL_argerror(L, tab, "too many sockets");
|
||||
#else
|
||||
if (fd >= FD_SETSIZE)
|
||||
luaL_argerror(L, tab, "descriptor too large for set size");
|
||||
#endif
|
||||
FD_SET(fd, set);
|
||||
n++;
|
||||
/* keep track of the largest descriptor so far */
|
||||
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
|
||||
*max_fd = fd;
|
||||
/* make sure we can map back from descriptor to the object */
|
||||
lua_pushnumber(L, (lua_Number) fd);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, itab);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
||||
int ndirty = 0, i = 1;
|
||||
if (lua_isnil(L, tab))
|
||||
return 0;
|
||||
for ( ;; ) {
|
||||
t_socket fd;
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
fd = getfd(L);
|
||||
if (fd != SOCKET_INVALID && dirty(L)) {
|
||||
lua_pushnumber(L, ++ndirty);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, dtab);
|
||||
FD_CLR(fd, set);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
i = i + 1;
|
||||
}
|
||||
return ndirty;
|
||||
}
|
||||
|
||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||
int itab, int tab, int start) {
|
||||
t_socket fd;
|
||||
for (fd = 0; fd < max_fd; fd++) {
|
||||
if (FD_ISSET(fd, set)) {
|
||||
lua_pushnumber(L, ++start);
|
||||
lua_pushnumber(L, (lua_Number) fd);
|
||||
lua_gettable(L, itab);
|
||||
lua_settable(L, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_assoc(lua_State *L, int tab) {
|
||||
int i = 1, atab;
|
||||
lua_newtable(L); atab = lua_gettop(L);
|
||||
for ( ;; ) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, atab);
|
||||
lua_pushnumber(L, i);
|
||||
lua_settable(L, atab);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
i = i+1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef SELECT_H
|
||||
#define SELECT_H
|
||||
/*=========================================================================*\
|
||||
* Select implementation
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* Each object that can be passed to the select function has to export
|
||||
* method getfd() which returns the descriptor to be passed to the
|
||||
* underlying select function. Another method, dirty(), should return
|
||||
* true if there is data ready for reading (required for buffered input).
|
||||
\*=========================================================================*/
|
||||
|
||||
int select_open(lua_State *L);
|
||||
|
||||
#endif /* SELECT_H */
|
|
@ -0,0 +1,183 @@
|
|||
/*=========================================================================*\
|
||||
* Serial stream
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "options.h"
|
||||
#include "unix.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
/*
|
||||
Reuses userdata definition from unix.h, since it is useful for all
|
||||
stream-like objects.
|
||||
|
||||
If we stored the serial path for use in error messages or userdata
|
||||
printing, we might need our own userdata definition.
|
||||
|
||||
Group usage is semi-inherited from unix.c, but unnecessary since we
|
||||
have only one object type.
|
||||
*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
|
||||
/* serial object methods */
|
||||
static luaL_Reg serial_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"close", meth_close},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfd", meth_getfd},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"settimeout", meth_settimeout},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* our socket creation function */
|
||||
static luaL_Reg func[] = {
|
||||
{"serial", global_create},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "serial{client}", serial_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "serial{client}", "serial{any}");
|
||||
/* make sure the function ends up in the package table */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
/* return the function instead of the 'socket' table */
|
||||
lua_pushstring(L, "serial");
|
||||
lua_gettable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_send(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_receive(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_getstats(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_setstats(L, &un->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
lua_pushnumber(L, (int) un->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
socket_destroy(&un->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
return timeout_meth_settimeout(L, &un->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a serial object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_create(lua_State *L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
/* allocate unix object */
|
||||
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
|
||||
/* open serial device */
|
||||
t_socket sock = open(path, O_NOCTTY|O_RDWR);
|
||||
|
||||
/*printf("open %s on %d\n", path, sock);*/
|
||||
|
||||
if (sock < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
lua_pushnumber(L, errno);
|
||||
return 3;
|
||||
}
|
||||
/* set its type as client object */
|
||||
auxiliar_setclass(L, "serial{client}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
un->sock = sock;
|
||||
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
|
||||
(p_error) socket_ioerror, &un->sock);
|
||||
timeout_init(&un->tm, -1, -1);
|
||||
buffer_init(&un->buf, &un->io, &un->tm);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* BSD Sockets and WinSock are similar, but there are a few irritating
|
||||
* differences. Also, not all *nix platforms behave the same. This module
|
||||
* (and the associated usocket.h and wsocket.h) factor these differences and
|
||||
* creates a interface compatible with the io.h module.
|
||||
\*=========================================================================*/
|
||||
#include "luasocket_io.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Platform specific compatibilization
|
||||
\*=========================================================================*/
|
||||
#ifdef _WIN32
|
||||
#include "wsocket.h"
|
||||
#else
|
||||
#include "usocket.h"
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* The connect and accept functions accept a timeout and their
|
||||
* implementations are somewhat complicated. We chose to move
|
||||
* the timeout control into this module for these functions in
|
||||
* order to simplify the modules that use them.
|
||||
\*=========================================================================*/
|
||||
#include "timeout.h"
|
||||
|
||||
/* we are lazy... */
|
||||
typedef struct sockaddr SA;
|
||||
|
||||
/*=========================================================================*\
|
||||
* Functions bellow implement a comfortable platform independent
|
||||
* interface to sockets
|
||||
\*=========================================================================*/
|
||||
int socket_open(void);
|
||||
int socket_close(void);
|
||||
void socket_destroy(p_socket ps);
|
||||
void socket_shutdown(p_socket ps, int how);
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count,
|
||||
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
|
||||
|
||||
void socket_setnonblocking(p_socket ps);
|
||||
void socket_setblocking(p_socket ps);
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm);
|
||||
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol);
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
|
||||
int socket_listen(p_socket ps, int backlog);
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr,
|
||||
socklen_t *addr_len, p_timeout tm);
|
||||
|
||||
const char *socket_hoststrerror(int err);
|
||||
const char *socket_gaistrerror(int err);
|
||||
const char *socket_strerror(int err);
|
||||
|
||||
/* these are perfect to use with the io abstraction module
|
||||
and the buffered input module */
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm);
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||
int socket_write(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm);
|
||||
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||
const char *socket_ioerror(p_socket ps, int err);
|
||||
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp);
|
||||
|
||||
#endif /* SOCKET_H */
|
|
@ -0,0 +1 @@
|
|||
e79358cdf4b02c66a50e684543e505002bdbcc91
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/* socket_scripts.h */
|
||||
|
||||
#ifndef __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
|
||||
#define __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
void luaopen_socket_scripts(lua_State* L);
|
||||
|
||||
/*
|
||||
int luaopen_lua_m_ltn12(lua_State* L);
|
||||
int luaopen_lua_m_mime(lua_State* L);
|
||||
int luaopen_lua_m_socket_ftp(lua_State* L);
|
||||
int luaopen_lua_m_socket_headers(lua_State* L);
|
||||
int luaopen_lua_m_socket_http(lua_State* L);
|
||||
int luaopen_lua_m_socket_mbox(lua_State* L);
|
||||
int luaopen_lua_m_socket_smtp(lua_State* L);
|
||||
int luaopen_lua_m_socket_tp(lua_State* L);
|
||||
int luaopen_lua_m_socket_url(lua_State* L);
|
||||
int luaopen_lua_m_socket(lua_State* L);
|
||||
*/
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ */
|
|
@ -0,0 +1,475 @@
|
|||
/*=========================================================================*\
|
||||
* TCP object
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int global_create6(lua_State *L);
|
||||
static int global_connect(lua_State *L);
|
||||
static int meth_connect(lua_State *L);
|
||||
static int meth_listen(lua_State *L);
|
||||
static int meth_getfamily(lua_State *L);
|
||||
static int meth_bind(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
static int meth_getsockname(lua_State *L);
|
||||
static int meth_getpeername(lua_State *L);
|
||||
static int meth_shutdown(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_accept(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_getoption(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
|
||||
/* tcp object methods */
|
||||
static luaL_Reg tcp_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"accept", meth_accept},
|
||||
{"bind", meth_bind},
|
||||
{"close", meth_close},
|
||||
{"connect", meth_connect},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfamily", meth_getfamily},
|
||||
{"getfd", meth_getfd},
|
||||
{"getoption", meth_getoption},
|
||||
{"getpeername", meth_getpeername},
|
||||
{"getsockname", meth_getsockname},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"listen", meth_listen},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"setpeername", meth_connect},
|
||||
{"setsockname", meth_bind},
|
||||
{"settimeout", meth_settimeout},
|
||||
{"shutdown", meth_shutdown},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket option handlers */
|
||||
static t_opt optget[] = {
|
||||
{"keepalive", opt_get_keepalive},
|
||||
{"reuseaddr", opt_get_reuseaddr},
|
||||
{"tcp-nodelay", opt_get_tcp_nodelay},
|
||||
{"linger", opt_get_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static t_opt optset[] = {
|
||||
{"keepalive", opt_set_keepalive},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"tcp-nodelay", opt_set_tcp_nodelay},
|
||||
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||
{"linger", opt_set_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"tcp", global_create},
|
||||
{"tcp6", global_create6},
|
||||
{"connect", global_connect},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tcp_open(lua_State *L)
|
||||
{
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "tcp{master}", tcp_methods);
|
||||
auxiliar_newclass(L, "tcp{client}", tcp_methods);
|
||||
auxiliar_newclass(L, "tcp{server}", tcp_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
|
||||
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
|
||||
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
|
||||
/* define library functions */
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_send(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_receive(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_getstats(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_setstats(L, &tcp->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getoption(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return opt_meth_getoption(L, optget, &tcp->sock);
|
||||
}
|
||||
|
||||
static int meth_setoption(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &tcp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
lua_pushnumber(L, (int) tcp->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
tcp->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&tcp->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for and returns a client object attempting connection to the
|
||||
* server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_accept(lua_State *L)
|
||||
{
|
||||
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
|
||||
p_timeout tm = timeout_markstart(&server->tm);
|
||||
t_socket sock;
|
||||
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
|
||||
/* if successful, push client socket */
|
||||
if (err == NULL) {
|
||||
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
auxiliar_setclass(L, "tcp{client}", -1);
|
||||
/* initialize structure fields */
|
||||
memset(clnt, 0, sizeof(t_tcp));
|
||||
socket_setnonblocking(&sock);
|
||||
clnt->sock = sock;
|
||||
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &clnt->sock);
|
||||
timeout_init(&clnt->tm, -1, -1);
|
||||
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||
clnt->family = server->family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds an object to an address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_bind(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
const char *err;
|
||||
struct addrinfo bindhints;
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_STREAM;
|
||||
bindhints.ai_family = tcp->family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
address = strcmp(address, "*")? address: NULL;
|
||||
err = inet_trybind(&tcp->sock, address, port, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master tcp object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_connect(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
struct addrinfo connecthints;
|
||||
const char *err;
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_STREAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = tcp->family;
|
||||
timeout_markstart(&tcp->tm);
|
||||
err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints);
|
||||
/* have to set the class even if it failed due to non-blocking connects */
|
||||
auxiliar_setclass(L, "tcp{client}", 1);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
socket_destroy(&tcp->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns family as string
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfamily(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
if (tcp->family == PF_INET6) {
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushliteral(L, "inet4");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Puts the sockt in listen mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_listen(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
||||
int backlog = (int) luaL_optnumber(L, 2, 32);
|
||||
int err = socket_listen(&tcp->sock, backlog);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a server object */
|
||||
auxiliar_setclass(L, "tcp{server}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Shuts the connection down partially
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_shutdown(lua_State *L)
|
||||
{
|
||||
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
|
||||
static const char* methods[] = { "receive", "send", "both", NULL };
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
int how = luaL_checkoption(L, 2, "both", methods);
|
||||
socket_shutdown(&tcp->sock, how);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call inet methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getpeername(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return inet_meth_getpeername(L, &tcp->sock, tcp->family);
|
||||
}
|
||||
|
||||
static int meth_getsockname(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return inet_meth_getsockname(L, &tcp->sock, tcp->family);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return timeout_meth_settimeout(L, &tcp->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master tcp object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int tcp_create(lua_State *L, int family) {
|
||||
t_socket sock;
|
||||
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
|
||||
/* try to allocate a system socket */
|
||||
if (!err) {
|
||||
/* allocate tcp object */
|
||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
memset(tcp, 0, sizeof(t_tcp));
|
||||
/* set its type as master object */
|
||||
auxiliar_setclass(L, "tcp{master}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
if (family == PF_INET6) {
|
||||
int yes = 1;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(void *)&yes, sizeof(yes));
|
||||
}
|
||||
tcp->sock = sock;
|
||||
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &tcp->sock);
|
||||
timeout_init(&tcp->tm, -1, -1);
|
||||
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||
tcp->family = family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int global_create(lua_State *L) {
|
||||
return tcp_create(L, AF_INET);
|
||||
}
|
||||
|
||||
static int global_create6(lua_State *L) {
|
||||
return tcp_create(L, AF_INET6);
|
||||
}
|
||||
|
||||
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
|
||||
struct addrinfo *connecthints, p_tcp tcp) {
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
|
||||
connecthints, &resolved));
|
||||
if (err != NULL) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
/* iterate over all returned addresses trying to connect */
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
p_timeout tm = timeout_markstart(&tcp->tm);
|
||||
/* create new socket if one wasn't created by the bind stage */
|
||||
if (tcp->sock == SOCKET_INVALID) {
|
||||
err = socket_strerror(socket_create(&tcp->sock,
|
||||
iterator->ai_family, iterator->ai_socktype,
|
||||
iterator->ai_protocol));
|
||||
if (err != NULL) {
|
||||
freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
tcp->family = iterator->ai_family;
|
||||
/* all sockets initially non-blocking */
|
||||
socket_setnonblocking(&tcp->sock);
|
||||
}
|
||||
/* finally try connecting to remote address */
|
||||
err = socket_strerror(socket_connect(&tcp->sock,
|
||||
(SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen, tm));
|
||||
/* if success, break out of loop */
|
||||
if (err == NULL) break;
|
||||
}
|
||||
|
||||
freeaddrinfo(resolved);
|
||||
/* here, if err is set, we failed */
|
||||
return err;
|
||||
}
|
||||
|
||||
static int global_connect(lua_State *L) {
|
||||
const char *remoteaddr = luaL_checkstring(L, 1);
|
||||
const char *remoteserv = luaL_checkstring(L, 2);
|
||||
const char *localaddr = luaL_optstring(L, 3, NULL);
|
||||
const char *localserv = luaL_optstring(L, 4, "0");
|
||||
int family = inet_optfamily(L, 5, "unspec");
|
||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
struct addrinfo bindhints, connecthints;
|
||||
const char *err = NULL;
|
||||
/* initialize tcp structure */
|
||||
memset(tcp, 0, sizeof(t_tcp));
|
||||
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &tcp->sock);
|
||||
timeout_init(&tcp->tm, -1, -1);
|
||||
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||
tcp->sock = SOCKET_INVALID;
|
||||
/* allow user to pick local address and port */
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_STREAM;
|
||||
bindhints.ai_family = family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
if (localaddr) {
|
||||
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
tcp->family = bindhints.ai_family;
|
||||
}
|
||||
/* try to connect to remote address and port */
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_STREAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = bindhints.ai_family;
|
||||
err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
|
||||
if (err) {
|
||||
socket_destroy(&tcp->sock);
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
auxiliar_setclass(L, "tcp{client}", -1);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef TCP_H
|
||||
#define TCP_H
|
||||
/*=========================================================================*\
|
||||
* TCP object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The tcp.h module is basicly a glue that puts together modules buffer.h,
|
||||
* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET,
|
||||
* SOCK_STREAM) support.
|
||||
*
|
||||
* Three classes are defined: master, client and server. The master class is
|
||||
* a newly created tcp object, that has not been bound or connected. Server
|
||||
* objects are tcp objects bound to some local address. Client objects are
|
||||
* tcp objects either connected to some address or returned by the accept
|
||||
* method of a server object.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "luasocket_buffer.h"
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
typedef struct t_tcp_ {
|
||||
t_socket sock;
|
||||
t_io io;
|
||||
t_buffer buf;
|
||||
t_timeout tm;
|
||||
int family;
|
||||
} t_tcp;
|
||||
|
||||
typedef t_tcp *p_tcp;
|
||||
|
||||
int tcp_open(lua_State *L);
|
||||
|
||||
#endif /* TCP_H */
|
|
@ -0,0 +1,217 @@
|
|||
/*=========================================================================*\
|
||||
* Timeout management functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "timeout.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int timeout_lua_gettime(lua_State *L);
|
||||
static int timeout_lua_sleep(lua_State *L);
|
||||
|
||||
static luaL_Reg func[] = {
|
||||
{ "gettime", timeout_lua_gettime },
|
||||
{ "sleep", timeout_lua_sleep },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions.
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initialize structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void timeout_init(p_timeout tm, double block, double total) {
|
||||
tm->block = block;
|
||||
tm->total = total;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines how much time we have left for the next system call,
|
||||
* if the previous call was successful
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_get(p_timeout tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
return tm->block;
|
||||
} else {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns time since start of operation
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* start field of structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_getstart(p_timeout tm) {
|
||||
return tm->start;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines how much time we have left for the next system call,
|
||||
* if the previous call was a failure
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_getretry(p_timeout tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
double t = tm->block - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Marks the operation start time in structure
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
p_timeout timeout_markstart(p_timeout tm) {
|
||||
tm->start = timeout_gettime();
|
||||
return tm;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Gets time in s, relative to January 1, 1970 (UTC)
|
||||
* Returns
|
||||
* time in s.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
double timeout_gettime(void) {
|
||||
FILETIME ft;
|
||||
double t;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
/* Windows file time (time since January 1, 1601 (UTC)) */
|
||||
t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
|
||||
/* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */
|
||||
return (t - 11644473600.0);
|
||||
}
|
||||
#else
|
||||
double timeout_gettime(void) {
|
||||
struct timeval v;
|
||||
gettimeofday(&v, (struct timezone *) NULL);
|
||||
/* Unix Epoch time (time since January 1, 1970 (UTC)) */
|
||||
return v.tv_sec + v.tv_usec/1.0e6;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int timeout_open(lua_State *L) {
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sets timeout values for IO operations
|
||||
* Lua Input: base, time [, mode]
|
||||
* time: time out value in seconds
|
||||
* mode: "b" for block timeout, "t" for total timeout. (default: b)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
|
||||
double t = luaL_optnumber(L, 2, -1);
|
||||
const char *mode = luaL_optstring(L, 3, "b");
|
||||
switch (*mode) {
|
||||
case 'b':
|
||||
tm->block = t;
|
||||
break;
|
||||
case 'r': case 't':
|
||||
tm->total = t;
|
||||
break;
|
||||
default:
|
||||
luaL_argcheck(L, 0, 3, "invalid timeout mode");
|
||||
break;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Test support functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns the time the system has been up, in secconds.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int timeout_lua_gettime(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, timeout_gettime());
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sleep for n seconds.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
int timeout_lua_sleep(lua_State *L)
|
||||
{
|
||||
double n = luaL_checknumber(L, 1);
|
||||
if (n < 0.0) n = 0.0;
|
||||
if (n < DBL_MAX/1000.0) n *= 1000.0;
|
||||
if (n > INT_MAX) n = INT_MAX;
|
||||
Sleep((int)n);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int timeout_lua_sleep(lua_State *L)
|
||||
{
|
||||
double n = luaL_checknumber(L, 1);
|
||||
struct timespec t, r;
|
||||
if (n < 0.0) n = 0.0;
|
||||
if (n > INT_MAX) n = INT_MAX;
|
||||
t.tv_sec = (int) n;
|
||||
n -= t.tv_sec;
|
||||
t.tv_nsec = (int) (n * 1000000000);
|
||||
if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
|
||||
while (nanosleep(&t, &r) != 0) {
|
||||
t.tv_sec = r.tv_sec;
|
||||
t.tv_nsec = r.tv_nsec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef TIMEOUT_H
|
||||
#define TIMEOUT_H
|
||||
/*=========================================================================*\
|
||||
* Timeout management functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/* timeout control structure */
|
||||
typedef struct t_timeout_ {
|
||||
double block; /* maximum time for blocking calls */
|
||||
double total; /* total number of miliseconds for operation */
|
||||
double start; /* time of start of operation */
|
||||
} t_timeout;
|
||||
typedef t_timeout *p_timeout;
|
||||
|
||||
int timeout_open(lua_State *L);
|
||||
void timeout_init(p_timeout tm, double block, double total);
|
||||
double timeout_get(p_timeout tm);
|
||||
double timeout_getretry(p_timeout tm);
|
||||
p_timeout timeout_markstart(p_timeout tm);
|
||||
double timeout_getstart(p_timeout tm);
|
||||
double timeout_gettime(void);
|
||||
int timeout_meth_settimeout(lua_State *L, p_timeout tm);
|
||||
|
||||
#define timeout_iszero(tm) ((tm)->block == 0.0)
|
||||
|
||||
#endif /* TIMEOUT_H */
|
|
@ -0,0 +1,468 @@
|
|||
/*=========================================================================*\
|
||||
* UDP object
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "udp.h"
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int global_create6(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_sendto(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_receivefrom(lua_State *L);
|
||||
static int meth_getfamily(lua_State *L);
|
||||
static int meth_getsockname(lua_State *L);
|
||||
static int meth_getpeername(lua_State *L);
|
||||
static int meth_setsockname(lua_State *L);
|
||||
static int meth_setpeername(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_getoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
|
||||
/* udp object methods */
|
||||
static luaL_Reg udp_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"close", meth_close},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfamily", meth_getfamily},
|
||||
{"getfd", meth_getfd},
|
||||
{"getpeername", meth_getpeername},
|
||||
{"getsockname", meth_getsockname},
|
||||
{"receive", meth_receive},
|
||||
{"receivefrom", meth_receivefrom},
|
||||
{"send", meth_send},
|
||||
{"sendto", meth_sendto},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"getoption", meth_getoption},
|
||||
{"setpeername", meth_setpeername},
|
||||
{"setsockname", meth_setsockname},
|
||||
{"settimeout", meth_settimeout},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket options for setoption */
|
||||
static t_opt optset[] = {
|
||||
{"dontroute", opt_set_dontroute},
|
||||
{"broadcast", opt_set_broadcast},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"reuseport", opt_set_reuseport},
|
||||
{"ip-multicast-if", opt_set_ip_multicast_if},
|
||||
{"ip-multicast-ttl", opt_set_ip_multicast_ttl},
|
||||
{"ip-multicast-loop", opt_set_ip_multicast_loop},
|
||||
{"ip-add-membership", opt_set_ip_add_membership},
|
||||
{"ip-drop-membership", opt_set_ip_drop_membersip},
|
||||
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket options for getoption */
|
||||
static t_opt optget[] = {
|
||||
{"ip-multicast-if", opt_get_ip_multicast_if},
|
||||
{"ip-multicast-loop", opt_get_ip_multicast_loop},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"udp", global_create},
|
||||
{"udp6", global_create6},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int udp_open(lua_State *L)
|
||||
{
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "udp{connected}", udp_methods);
|
||||
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "udp{connected}", "udp{any}");
|
||||
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
|
||||
auxiliar_add2group(L, "udp{connected}", "select{able}");
|
||||
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
||||
/* define library functions */
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
const char *udp_strerror(int err) {
|
||||
/* a 'closed' error on an unconnected means the target address was not
|
||||
* accepted by the transport layer */
|
||||
if (err == IO_CLOSED) return "refused";
|
||||
else return socket_strerror(err);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send data through connected udp socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
||||
p_timeout tm = &udp->tm;
|
||||
size_t count, sent = 0;
|
||||
int err;
|
||||
const char *data = luaL_checklstring(L, 2, &count);
|
||||
timeout_markstart(tm);
|
||||
err = socket_send(&udp->sock, data, count, &sent, tm);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, (lua_Number) sent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send data through unconnected udp socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_sendto(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
size_t count, sent = 0;
|
||||
const char *data = luaL_checklstring(L, 2, &count);
|
||||
const char *ip = luaL_checkstring(L, 3);
|
||||
unsigned short port = (unsigned short) luaL_checknumber(L, 4);
|
||||
p_timeout tm = &udp->tm;
|
||||
int err;
|
||||
switch (udp->family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if (!my_inet_pton(AF_INET, ip, &addr.sin_addr))
|
||||
luaL_argerror(L, 3, "invalid ip address");
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
timeout_markstart(tm);
|
||||
err = socket_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm);
|
||||
break;
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if (!my_inet_pton(AF_INET6, ip, &addr.sin6_addr))
|
||||
luaL_argerror(L, 3, "invalid ip address");
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
timeout_markstart(tm);
|
||||
err = socket_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", udp->family);
|
||||
return 2;
|
||||
}
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, (lua_Number) sent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receives data from a UDP socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
char buffer[UDP_DATAGRAMSIZE];
|
||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
||||
int err;
|
||||
p_timeout tm = &udp->tm;
|
||||
count = MIN(count, sizeof(buffer));
|
||||
timeout_markstart(tm);
|
||||
err = socket_recv(&udp->sock, buffer, count, &got, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushlstring(L, buffer, got);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receives data and sender from a UDP socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_receivefrom(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
char buffer[UDP_DATAGRAMSIZE];
|
||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
||||
int err;
|
||||
p_timeout tm = &udp->tm;
|
||||
timeout_markstart(tm);
|
||||
count = MIN(count, sizeof(buffer));
|
||||
switch (udp->family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
err = socket_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err == IO_DONE) {
|
||||
char addrstr[INET_ADDRSTRLEN];
|
||||
lua_pushlstring(L, buffer, got);
|
||||
if (!my_inet_ntop(AF_INET, &addr.sin_addr,
|
||||
addrstr, sizeof(addrstr))) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "invalid source address");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, addrstr);
|
||||
lua_pushnumber(L, ntohs(addr.sin_port));
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
err = socket_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err == IO_DONE) {
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
lua_pushlstring(L, buffer, got);
|
||||
if (!my_inet_ntop(AF_INET6, &addr.sin6_addr,
|
||||
addrstr, sizeof(addrstr))) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "invalid source address");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, addrstr);
|
||||
lua_pushnumber(L, ntohs(addr.sin6_port));
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", udp->family);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns family as string
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfamily(lua_State *L)
|
||||
{
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
if (udp->family == PF_INET6) {
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushliteral(L, "inet4");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
lua_pushnumber(L, (int) udp->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
udp->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
(void) udp;
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call inet methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getpeername(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
||||
return inet_meth_getpeername(L, &udp->sock, udp->family);
|
||||
}
|
||||
|
||||
static int meth_getsockname(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return inet_meth_getsockname(L, &udp->sock, udp->family);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &udp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getoption(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return opt_meth_getoption(L, optget, &udp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return timeout_meth_settimeout(L, &udp->tm);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master udp object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setpeername(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
p_timeout tm = &udp->tm;
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
int connecting = strcmp(address, "*");
|
||||
const char *port = connecting? luaL_checkstring(L, 3): "0";
|
||||
struct addrinfo connecthints;
|
||||
const char *err;
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_DGRAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = udp->family;
|
||||
if (connecting) {
|
||||
err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
auxiliar_setclass(L, "udp{connected}", 1);
|
||||
} else {
|
||||
/* we ignore possible errors because Mac OS X always
|
||||
* returns EAFNOSUPPORT */
|
||||
inet_trydisconnect(&udp->sock, udp->family, tm);
|
||||
auxiliar_setclass(L, "udp{unconnected}", 1);
|
||||
}
|
||||
/* change class to connected or unconnected depending on address */
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
socket_destroy(&udp->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master object into a server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setsockname(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
const char *err;
|
||||
struct addrinfo bindhints;
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_DGRAM;
|
||||
bindhints.ai_family = udp->family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
err = inet_trybind(&udp->sock, address, port, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master udp object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int udp_create(lua_State *L, int family) {
|
||||
t_socket sock;
|
||||
const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
|
||||
/* try to allocate a system socket */
|
||||
if (!err) {
|
||||
/* allocate udp object */
|
||||
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
||||
auxiliar_setclass(L, "udp{unconnected}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
if (family == PF_INET6) {
|
||||
int yes = 1;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(void *)&yes, sizeof(yes));
|
||||
}
|
||||
udp->sock = sock;
|
||||
timeout_init(&udp->tm, -1, -1);
|
||||
udp->family = family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int global_create(lua_State *L) {
|
||||
return udp_create(L, AF_INET);
|
||||
}
|
||||
|
||||
static int global_create6(lua_State *L) {
|
||||
return udp_create(L, AF_INET6);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef UDP_H
|
||||
#define UDP_H
|
||||
/*=========================================================================*\
|
||||
* UDP object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The udp.h module provides LuaSocket with support for UDP protocol
|
||||
* (AF_INET, SOCK_DGRAM).
|
||||
*
|
||||
* Two classes are defined: connected and unconnected. UDP objects are
|
||||
* originally unconnected. They can be "connected" to a given address
|
||||
* with a call to the setpeername function. The same function can be used to
|
||||
* break the connection.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* can't be larger than wsocket.c MAXCHUNK!!! */
|
||||
#define UDP_DATAGRAMSIZE 8192
|
||||
|
||||
typedef struct t_udp_ {
|
||||
t_socket sock;
|
||||
t_timeout tm;
|
||||
int family;
|
||||
} t_udp;
|
||||
typedef t_udp *p_udp;
|
||||
|
||||
int udp_open(lua_State *L);
|
||||
|
||||
#endif /* UDP_H */
|
|
@ -0,0 +1,340 @@
|
|||
/*=========================================================================*\
|
||||
* Unix domain socket
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "options.h"
|
||||
#include "unix.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int meth_connect(lua_State *L);
|
||||
static int meth_listen(lua_State *L);
|
||||
static int meth_bind(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_shutdown(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_accept(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
|
||||
static const char *unix_tryconnect(p_unix un, const char *path);
|
||||
static const char *unix_trybind(p_unix un, const char *path);
|
||||
|
||||
/* unix object methods */
|
||||
static luaL_Reg unix_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"accept", meth_accept},
|
||||
{"bind", meth_bind},
|
||||
{"close", meth_close},
|
||||
{"connect", meth_connect},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfd", meth_getfd},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"listen", meth_listen},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"setpeername", meth_connect},
|
||||
{"setsockname", meth_bind},
|
||||
{"settimeout", meth_settimeout},
|
||||
{"shutdown", meth_shutdown},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket option handlers */
|
||||
static t_opt optset[] = {
|
||||
{"keepalive", opt_set_keepalive},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"linger", opt_set_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* our socket creation function */
|
||||
static luaL_Reg func[] = {
|
||||
{"unix", global_create},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int luaopen_socket_unix(lua_State *L) {
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "unix{master}", unix_methods);
|
||||
auxiliar_newclass(L, "unix{client}", unix_methods);
|
||||
auxiliar_newclass(L, "unix{server}", unix_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "unix{master}", "unix{any}");
|
||||
auxiliar_add2group(L, "unix{client}", "unix{any}");
|
||||
auxiliar_add2group(L, "unix{server}", "unix{any}");
|
||||
/* make sure the function ends up in the package table */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
/* return the function instead of the 'socket' table */
|
||||
lua_pushstring(L, "unix");
|
||||
lua_gettable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_send(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_receive(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_getstats(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_setstats(L, &un->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &un->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
lua_pushnumber(L, (int) un->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for and returns a client object attempting connection to the
|
||||
* server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_accept(lua_State *L) {
|
||||
p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
|
||||
p_timeout tm = timeout_markstart(&server->tm);
|
||||
t_socket sock;
|
||||
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
|
||||
/* if successful, push client socket */
|
||||
if (err == IO_DONE) {
|
||||
p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
auxiliar_setclass(L, "unix{client}", -1);
|
||||
/* initialize structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
clnt->sock = sock;
|
||||
io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
|
||||
(p_error) socket_ioerror, &clnt->sock);
|
||||
timeout_init(&clnt->tm, -1, -1);
|
||||
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds an object to an address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const char *unix_trybind(p_unix un, const char *path) {
|
||||
struct sockaddr_un local;
|
||||
size_t len = strlen(path);
|
||||
int err;
|
||||
if (len >= sizeof(local.sun_path)) return "path too long";
|
||||
memset(&local, 0, sizeof(local));
|
||||
strcpy(local.sun_path, path);
|
||||
local.sun_family = AF_UNIX;
|
||||
#ifdef UNIX_HAS_SUN_LEN
|
||||
local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
|
||||
+ len + 1;
|
||||
err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
|
||||
|
||||
#else
|
||||
err = socket_bind(&un->sock, (SA *) &local,
|
||||
(socklen_t)(sizeof(local.sun_family) + len));
|
||||
#endif
|
||||
if (err != IO_DONE) socket_destroy(&un->sock);
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static int meth_bind(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
const char *path = luaL_checkstring(L, 2);
|
||||
const char *err = unix_trybind(un, path);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master unix object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const char *unix_tryconnect(p_unix un, const char *path)
|
||||
{
|
||||
struct sockaddr_un remote;
|
||||
int err;
|
||||
size_t len = strlen(path);
|
||||
if (len >= sizeof(remote.sun_path)) return "path too long";
|
||||
memset(&remote, 0, sizeof(remote));
|
||||
strcpy(remote.sun_path, path);
|
||||
remote.sun_family = AF_UNIX;
|
||||
timeout_markstart(&un->tm);
|
||||
#ifdef UNIX_HAS_SUN_LEN
|
||||
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
|
||||
+ len + 1;
|
||||
err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
|
||||
#else
|
||||
err = socket_connect(&un->sock, (SA *) &remote,
|
||||
(socklen_t)(sizeof(remote.sun_family) + len), &un->tm);
|
||||
#endif
|
||||
if (err != IO_DONE) socket_destroy(&un->sock);
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static int meth_connect(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
const char *path = luaL_checkstring(L, 2);
|
||||
const char *err = unix_tryconnect(un, path);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a client object */
|
||||
auxiliar_setclass(L, "unix{client}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
socket_destroy(&un->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Puts the sockt in listen mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_listen(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
int backlog = (int) luaL_optnumber(L, 2, 32);
|
||||
int err = socket_listen(&un->sock, backlog);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a server object */
|
||||
auxiliar_setclass(L, "unix{server}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Shuts the connection down partially
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_shutdown(lua_State *L)
|
||||
{
|
||||
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
|
||||
static const char* methods[] = { "receive", "send", "both", NULL };
|
||||
p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
int how = luaL_checkoption(L, 2, "both", methods);
|
||||
socket_shutdown(&tcp->sock, how);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
return timeout_meth_settimeout(L, &un->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master unix object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_create(lua_State *L) {
|
||||
t_socket sock;
|
||||
int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
|
||||
/* try to allocate a system socket */
|
||||
if (err == IO_DONE) {
|
||||
/* allocate unix object */
|
||||
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
/* set its type as master object */
|
||||
auxiliar_setclass(L, "unix{master}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
un->sock = sock;
|
||||
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &un->sock);
|
||||
timeout_init(&un->tm, -1, -1);
|
||||
buffer_init(&un->buf, &un->io, &un->tm);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef UNIX_H
|
||||
#define UNIX_H
|
||||
/*=========================================================================*\
|
||||
* Unix domain object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module is just an example of how to extend LuaSocket with a new
|
||||
* domain.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "luasocket.h"
|
||||
#include "luasocket_buffer.h"
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
typedef struct t_unix_ {
|
||||
t_socket sock;
|
||||
t_io io;
|
||||
t_buffer buf;
|
||||
t_timeout tm;
|
||||
} t_unix;
|
||||
typedef t_unix *p_unix;
|
||||
|
||||
LUASOCKET_API int luaopen_socket_unix(lua_State *L);
|
||||
|
||||
#endif /* UNIX_H */
|
|
@ -0,0 +1,449 @@
|
|||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Unix
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The code is now interrupt-safe.
|
||||
* The penalty of calling select to avoid busy-wait is only paid when
|
||||
* the I/O call fail in the first place.
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Wait for readable/writable/connected socket with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef SOCKET_SELECT
|
||||
#include <sys/poll.h>
|
||||
|
||||
#define WAITFD_R POLLIN
|
||||
#define WAITFD_W POLLOUT
|
||||
#define WAITFD_C (POLLIN|POLLOUT)
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
struct pollfd pfd;
|
||||
pfd.fd = *ps;
|
||||
pfd.events = sw;
|
||||
pfd.revents = 0;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
do {
|
||||
int t = (int)(timeout_getretry(tm)*1e3);
|
||||
ret = poll(&pfd, 1, t >= 0? t: -1);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret == -1) return errno;
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
#else
|
||||
|
||||
#define WAITFD_R 1
|
||||
#define WAITFD_W 2
|
||||
#define WAITFD_C (WAITFD_R|WAITFD_W)
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
fd_set rfds, wfds, *rp, *wp;
|
||||
struct timeval tv, *tp;
|
||||
double t;
|
||||
if (*ps >= FD_SETSIZE) return EINVAL;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
do {
|
||||
/* must set bits within loop, because select may have modifed them */
|
||||
rp = wp = NULL;
|
||||
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; }
|
||||
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
|
||||
t = timeout_getretry(tm);
|
||||
tp = NULL;
|
||||
if (t >= 0.0) {
|
||||
tv.tv_sec = (int)t;
|
||||
tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6);
|
||||
tp = &tv;
|
||||
}
|
||||
ret = select(*ps+1, rp, wp, NULL, tp);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret == -1) return errno;
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_open(void) {
|
||||
/* instals a handler to ignore sigpipe or it will crash us */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_close(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close and inutilize socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_destroy(p_socket ps) {
|
||||
if (*ps != SOCKET_INVALID) {
|
||||
socket_setblocking(ps);
|
||||
close(*ps);
|
||||
*ps = SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select with timeout control
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm) {
|
||||
int ret;
|
||||
do {
|
||||
struct timeval tv;
|
||||
double t = timeout_getretry(tm);
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
|
||||
/* timeout = 0 means no wait */
|
||||
ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates and sets up a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol) {
|
||||
*ps = socket(domain, type, protocol);
|
||||
if (*ps != SOCKET_INVALID) return IO_DONE;
|
||||
else return errno;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (bind(*ps, addr, len) < 0) err = errno;
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_listen(p_socket ps, int backlog) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (listen(*ps, backlog)) err = errno;
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_shutdown(p_socket ps, int how) {
|
||||
socket_setblocking(ps);
|
||||
shutdown(*ps, how);
|
||||
socket_setnonblocking(ps);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Connects or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
|
||||
int err;
|
||||
/* avoid calling on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* call connect until done or failed without being interrupted */
|
||||
do if (connect(*ps, addr, len) == 0) return IO_DONE;
|
||||
while ((err = errno) == EINTR);
|
||||
/* if connection failed immediately, return error code */
|
||||
if (err != EINPROGRESS && err != EAGAIN) return err;
|
||||
/* zero timeout case optimization */
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT;
|
||||
/* wait until we have the result of the connection attempt or timeout */
|
||||
err = socket_waitfd(ps, WAITFD_C, tm);
|
||||
if (err == IO_CLOSED) {
|
||||
if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE;
|
||||
else return errno;
|
||||
} else return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int err;
|
||||
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
|
||||
err = errno;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN && err != ECONNABORTED) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
long put = (long) send(*ps, data, count, 0);
|
||||
/* if we sent anything, we are done */
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
/* EPIPE means the connection was closed */
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
/* we call was interrupted, just try again */
|
||||
if (err == EINTR) continue;
|
||||
/* if failed fatal reason, report error */
|
||||
if (err != EAGAIN) return err;
|
||||
/* wait until we can send something or we timeout */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sendto with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
|
||||
SA *addr, socklen_t len, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long put = (long) sendto(*ps, data, count, 0, addr, len);
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receive with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) recv(*ps, data, count, 0);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Recvfrom with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
|
||||
SA *addr, socklen_t *len, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) recvfrom(*ps, data, count, 0, addr, len);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Write with timeout
|
||||
*
|
||||
* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
|
||||
* with send/recv replaced with write/read. We can't just use write/read
|
||||
* in the socket version, because behaviour when size is zero is different.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_write(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
long put = (long) write(*ps, data, count);
|
||||
/* if we sent anything, we are done */
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
/* EPIPE means the connection was closed */
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
/* we call was interrupted, just try again */
|
||||
if (err == EINTR) continue;
|
||||
/* if failed fatal reason, report error */
|
||||
if (err != EAGAIN) return err;
|
||||
/* wait until we can send something or we timeout */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Read with timeout
|
||||
* See note for socket_write
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) read(*ps, data, count);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setblocking(p_socket ps) {
|
||||
int flags = fcntl(*ps, F_GETFL, 0);
|
||||
flags &= (~(O_NONBLOCK));
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into non-blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setnonblocking(p_socket ps) {
|
||||
int flags = fcntl(*ps, F_GETFL, 0);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* DNS helpers
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
|
||||
*hp = gethostbyaddr(addr, len, AF_INET);
|
||||
if (*hp) return IO_DONE;
|
||||
else if (h_errno) return h_errno;
|
||||
else if (errno) return errno;
|
||||
else return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp) {
|
||||
*hp = gethostbyname(addr);
|
||||
if (*hp) return IO_DONE;
|
||||
else if (h_errno) return h_errno;
|
||||
else if (errno) return errno;
|
||||
else return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Error translation functions
|
||||
* Make sure important error messages are standard
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *socket_hoststrerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case HOST_NOT_FOUND: return "host not found";
|
||||
default: return hstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_strerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case EADDRINUSE: return "address already in use";
|
||||
case EISCONN: return "already connected";
|
||||
case EACCES: return "permission denied";
|
||||
case ECONNREFUSED: return "connection refused";
|
||||
case ECONNABORTED: return "closed";
|
||||
case ECONNRESET: return "closed";
|
||||
case ETIMEDOUT: return "timeout";
|
||||
default: return strerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_ioerror(p_socket ps, int err) {
|
||||
(void) ps;
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
const char *socket_gaistrerror(int err) {
|
||||
if (err == 0) return NULL;
|
||||
switch (err) {
|
||||
case EAI_AGAIN: return "temporary failure in name resolution";
|
||||
case EAI_BADFLAGS: return "invalid value for ai_flags";
|
||||
#ifdef EAI_BADHINTS
|
||||
case EAI_BADHINTS: return "invalid value for hints";
|
||||
#endif
|
||||
case EAI_FAIL: return "non-recoverable failure in name resolution";
|
||||
case EAI_FAMILY: return "ai_family not supported";
|
||||
case EAI_MEMORY: return "memory allocation failure";
|
||||
case EAI_NONAME:
|
||||
return "host or service not provided, or not known";
|
||||
case EAI_OVERFLOW: return "argument buffer overflow";
|
||||
#ifdef EAI_PROTOCOL
|
||||
case EAI_PROTOCOL: return "resolved protocol is unknown";
|
||||
#endif
|
||||
case EAI_SERVICE: return "service not supported for socket type";
|
||||
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
||||
case EAI_SYSTEM: return strerror(errno);
|
||||
default: return gai_strerror(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef USOCKET_H
|
||||
#define USOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Unix
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* BSD include files
|
||||
\*=========================================================================*/
|
||||
/* error codes */
|
||||
#include <errno.h>
|
||||
/* close function */
|
||||
#include <unistd.h>
|
||||
/* fnctnl function and associated constants */
|
||||
#include <fcntl.h>
|
||||
/* struct sockaddr */
|
||||
#include <sys/types.h>
|
||||
/* socket function */
|
||||
#include <sys/socket.h>
|
||||
/* struct timeval */
|
||||
#include <sys/time.h>
|
||||
/* gethostbyname and gethostbyaddr functions */
|
||||
#include <netdb.h>
|
||||
/* sigpipe handling */
|
||||
#include <signal.h>
|
||||
/* IP stuff*/
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
/* TCP options (nagle algorithm disable) */
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#ifndef SO_REUSEPORT
|
||||
#define SO_REUSEPORT SO_REUSEADDR
|
||||
#endif
|
||||
|
||||
typedef int t_socket;
|
||||
typedef t_socket *p_socket;
|
||||
typedef struct sockaddr_storage t_sockaddr_storage;
|
||||
|
||||
#define SOCKET_INVALID (-1)
|
||||
|
||||
#endif /* USOCKET_H */
|
|
@ -0,0 +1,413 @@
|
|||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Win32
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The penalty of calling select to avoid busy-wait is only paid when
|
||||
* the I/O call fail in the first place.
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
/* WinSock doesn't have a strerror... */
|
||||
static const char *wstrerror(int err);
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_open(void) {
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 0);
|
||||
int err = WSAStartup(wVersionRequested, &wsaData );
|
||||
if (err != 0) return 0;
|
||||
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
|
||||
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_close(void) {
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Wait for readable/writable/connected socket with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define WAITFD_R 1
|
||||
#define WAITFD_W 2
|
||||
#define WAITFD_E 4
|
||||
#define WAITFD_C (WAITFD_E|WAITFD_W)
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
|
||||
struct timeval tv, *tp = NULL;
|
||||
double t;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
if (sw & WAITFD_R) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(*ps, &rfds);
|
||||
rp = &rfds;
|
||||
}
|
||||
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
|
||||
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
|
||||
if ((t = timeout_get(tm)) >= 0.0) {
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
|
||||
tp = &tv;
|
||||
}
|
||||
ret = select(0, rp, wp, ep, tp);
|
||||
if (ret == -1) return WSAGetLastError();
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select with int timeout in ms
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm) {
|
||||
struct timeval tv;
|
||||
double t = timeout_get(tm);
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
|
||||
if (n <= 0) {
|
||||
Sleep((DWORD) (1000*t));
|
||||
return 0;
|
||||
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close and inutilize socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_destroy(p_socket ps) {
|
||||
if (*ps != SOCKET_INVALID) {
|
||||
socket_setblocking(ps); /* close can take a long time on WIN32 */
|
||||
closesocket(*ps);
|
||||
*ps = SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_shutdown(p_socket ps, int how) {
|
||||
socket_setblocking(ps);
|
||||
shutdown(*ps, how);
|
||||
socket_setnonblocking(ps);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates and sets up a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol) {
|
||||
*ps = socket(domain, type, protocol);
|
||||
if (*ps != SOCKET_INVALID) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Connects or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
|
||||
int err;
|
||||
/* don't call on closed socket */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* ask system to connect */
|
||||
if (connect(*ps, addr, len) == 0) return IO_DONE;
|
||||
/* make sure the system is trying to connect */
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
|
||||
/* zero timeout case optimization */
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT;
|
||||
/* we wait until something happens */
|
||||
err = socket_waitfd(ps, WAITFD_C, tm);
|
||||
if (err == IO_CLOSED) {
|
||||
int len = sizeof(err);
|
||||
/* give windows time to set the error (yes, disgusting) */
|
||||
Sleep(10);
|
||||
/* find out why we failed */
|
||||
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
|
||||
/* we KNOW there was an error. if 'why' is 0, we will return
|
||||
* "unknown error", but it's not really our fault */
|
||||
return err > 0? err: IO_UNKNOWN;
|
||||
} else return err;
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_listen(p_socket ps, int backlog) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (listen(*ps, backlog) < 0) err = WSAGetLastError();
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
|
||||
p_timeout tm) {
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int err;
|
||||
/* try to get client socket */
|
||||
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
|
||||
/* find out why we failed */
|
||||
err = WSAGetLastError();
|
||||
/* if we failed because there was no connectoin, keep trying */
|
||||
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
|
||||
/* call select to avoid busy wait */
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send with timeout
|
||||
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
|
||||
* this can take an awful lot of time and we will end up blocked.
|
||||
* Therefore, whoever calls this function should not pass a huge buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
/* try to send something */
|
||||
int put = send(*ps, data, (int) count, 0);
|
||||
/* if we sent something, we are done */
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
/* deal with failure */
|
||||
err = WSAGetLastError();
|
||||
/* we can only proceed if there was no serious error */
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
/* avoid busy wait */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sendto with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
|
||||
SA *addr, socklen_t len, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int put = sendto(*ps, data, (int) count, 0, addr, len);
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receive with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int taken = recv(*ps, data, (int) count, 0);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Recvfrom with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
|
||||
SA *addr, socklen_t *len, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setblocking(p_socket ps) {
|
||||
u_long argp = 0;
|
||||
ioctlsocket(*ps, FIONBIO, &argp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into non-blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setnonblocking(p_socket ps) {
|
||||
u_long argp = 1;
|
||||
ioctlsocket(*ps, FIONBIO, &argp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* DNS helpers
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
|
||||
*hp = gethostbyaddr(addr, len, AF_INET);
|
||||
if (*hp) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp) {
|
||||
*hp = gethostbyname(addr);
|
||||
if (*hp) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Error translation functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *socket_hoststrerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case WSAHOST_NOT_FOUND: return "host not found";
|
||||
default: return wstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_strerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case WSAEADDRINUSE: return "address already in use";
|
||||
case WSAECONNREFUSED: return "connection refused";
|
||||
case WSAEISCONN: return "already connected";
|
||||
case WSAEACCES: return "permission denied";
|
||||
case WSAECONNABORTED: return "closed";
|
||||
case WSAECONNRESET: return "closed";
|
||||
case WSAETIMEDOUT: return "timeout";
|
||||
default: return wstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_ioerror(p_socket ps, int err) {
|
||||
(void) ps;
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static const char *wstrerror(int err) {
|
||||
switch (err) {
|
||||
case WSAEINTR: return "Interrupted function call";
|
||||
case WSAEACCES: return "Permission denied";
|
||||
case WSAEFAULT: return "Bad address";
|
||||
case WSAEINVAL: return "Invalid argument";
|
||||
case WSAEMFILE: return "Too many open files";
|
||||
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
|
||||
case WSAEINPROGRESS: return "Operation now in progress";
|
||||
case WSAEALREADY: return "Operation already in progress";
|
||||
case WSAENOTSOCK: return "Socket operation on nonsocket";
|
||||
case WSAEDESTADDRREQ: return "Destination address required";
|
||||
case WSAEMSGSIZE: return "Message too long";
|
||||
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
|
||||
case WSAENOPROTOOPT: return "Bad protocol option";
|
||||
case WSAEPROTONOSUPPORT: return "Protocol not supported";
|
||||
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
|
||||
case WSAEOPNOTSUPP: return "Operation not supported";
|
||||
case WSAEPFNOSUPPORT: return "Protocol family not supported";
|
||||
case WSAEAFNOSUPPORT:
|
||||
return "Address family not supported by protocol family";
|
||||
case WSAEADDRINUSE: return "Address already in use";
|
||||
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAENETUNREACH: return "Network is unreachable";
|
||||
case WSAENETRESET: return "Network dropped connection on reset";
|
||||
case WSAECONNABORTED: return "Software caused connection abort";
|
||||
case WSAECONNRESET: return "Connection reset by peer";
|
||||
case WSAENOBUFS: return "No buffer space available";
|
||||
case WSAEISCONN: return "Socket is already connected";
|
||||
case WSAENOTCONN: return "Socket is not connected";
|
||||
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
|
||||
case WSAETIMEDOUT: return "Connection timed out";
|
||||
case WSAECONNREFUSED: return "Connection refused";
|
||||
case WSAEHOSTDOWN: return "Host is down";
|
||||
case WSAEHOSTUNREACH: return "No route to host";
|
||||
case WSAEPROCLIM: return "Too many processes";
|
||||
case WSASYSNOTREADY: return "Network subsystem is unavailable";
|
||||
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
|
||||
case WSANOTINITIALISED:
|
||||
return "Successful WSAStartup not yet performed";
|
||||
case WSAEDISCON: return "Graceful shutdown in progress";
|
||||
case WSAHOST_NOT_FOUND: return "Host not found";
|
||||
case WSATRY_AGAIN: return "Nonauthoritative host not found";
|
||||
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
|
||||
case WSANO_DATA: return "Valid name, no data record of requested type";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_gaistrerror(int err) {
|
||||
if (err == 0) return NULL;
|
||||
switch (err) {
|
||||
case EAI_AGAIN: return "temporary failure in name resolution";
|
||||
case EAI_BADFLAGS: return "invalid value for ai_flags";
|
||||
#ifdef EAI_BADHINTS
|
||||
case EAI_BADHINTS: return "invalid value for hints";
|
||||
#endif
|
||||
case EAI_FAIL: return "non-recoverable failure in name resolution";
|
||||
case EAI_FAMILY: return "ai_family not supported";
|
||||
case EAI_MEMORY: return "memory allocation failure";
|
||||
case EAI_NONAME:
|
||||
return "host or service not provided, or not known";
|
||||
// case EAI_OVERFLOW: return "argument buffer overflow";
|
||||
#ifdef EAI_PROTOCOL
|
||||
case EAI_PROTOCOL: return "resolved protocol is unknown";
|
||||
#endif
|
||||
case EAI_SERVICE: return "service not supported for socket type";
|
||||
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
||||
// case EAI_SYSTEM: return strerror(errno);
|
||||
default: return gai_strerrorA(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef WSOCKET_H
|
||||
#define WSOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Win32
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* WinSock include files
|
||||
\*=========================================================================*/
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
typedef int socklen_t;
|
||||
typedef SOCKADDR_STORAGE t_sockaddr_storage;
|
||||
typedef SOCKET t_socket;
|
||||
typedef t_socket *p_socket;
|
||||
|
||||
#define SOCKET_INVALID (INVALID_SOCKET)
|
||||
|
||||
#ifndef SO_REUSEPORT
|
||||
#define SO_REUSEPORT SO_REUSEADDR
|
||||
#endif
|
||||
|
||||
#endif /* WSOCKET_H */
|
|
@ -343,6 +343,10 @@ cc.Handler.EVENT_MOUSE_UP = 49
|
|||
cc.Handler.EVENT_MOUSE_MOVE = 50
|
||||
cc.Handler.EVENT_MOUSE_SCROLL = 51
|
||||
cc.Handler.EVENT_SPINE = 52
|
||||
cc.Handler.EVENT_PHYSICS_CONTACT_BEGIN = 53
|
||||
cc.Handler.EVENT_PHYSICS_CONTACT_PRESOLVE = 54
|
||||
cc.Handler.EVENT_PHYSICS_CONTACT_POSTSOLVE = 55
|
||||
cc.Handler.EVENT_PHYSICS_CONTACT_SEPERATE = 56
|
||||
|
||||
cc.EVENT_UNKNOWN = 0
|
||||
cc.EVENT_TOUCH_ONE_BY_ONE = 1
|
||||
|
@ -352,8 +356,8 @@ cc.EVENT_MOUSE = 4
|
|||
cc.EVENT_ACCELERATION = 5
|
||||
cc.EVENT_CUSTOM = 6
|
||||
|
||||
cc.PHYSICSSHAPE_MATERIAL_DEFAULT = {0.0, 0.5, 0.5}
|
||||
cc.PHYSICSBODY_MATERIAL_DEFAULT = {0.1, 0.5, 0.5}
|
||||
cc.PHYSICSSHAPE_MATERIAL_DEFAULT = {density = 0.0, restitution = 0.5, friction = 0.5}
|
||||
cc.PHYSICSBODY_MATERIAL_DEFAULT = {density = 0.1, restitution = 0.5, friction = 0.5}
|
||||
cc.GLYPHCOLLECTION_DYNAMIC = 0
|
||||
cc.GLYPHCOLLECTION_NEHE = 1
|
||||
cc.GLYPHCOLLECTION_ASCII = 2
|
||||
|
@ -367,3 +371,165 @@ cc.LabelEffect =
|
|||
GLOW = 3,
|
||||
}
|
||||
|
||||
cc.KeyCode =
|
||||
{
|
||||
KEY_NONE = 0,
|
||||
KEY_PAUSE = 0x0013,
|
||||
KEY_SCROLL_LOCK = 0x1014,
|
||||
KEY_PRINT = 0x1061,
|
||||
KEY_SYSREQ = 0x106A,
|
||||
KEY_BREAK = 0x106B,
|
||||
KEY_ESCAPE = 0x001B,
|
||||
KEY_BACKSPACE = 0x0008,
|
||||
KEY_TAB = 0x0009,
|
||||
KEY_BACK_TAB = 0x0089,
|
||||
KEY_RETURN = 0x000D,
|
||||
KEY_CAPS_LOCK = 0x00E5,
|
||||
KEY_SHIFT = 0x00E1,
|
||||
KEY_CTRL = 0x00E3,
|
||||
KEY_ALT = 0x00E9,
|
||||
KEY_MENU = 0x1067,
|
||||
KEY_HYPER = 0x10ED,
|
||||
KEY_INSERT = 0x1063,
|
||||
KEY_HOME = 0x1050,
|
||||
KEY_PG_UP = 0x1055,
|
||||
KEY_DELETE = 0x10FF,
|
||||
KEY_END = 0x1057,
|
||||
KEY_PG_DOWN = 0x1056,
|
||||
KEY_LEFT_ARROW = 0x1051,
|
||||
KEY_RIGHT_ARROW = 0x1053,
|
||||
KEY_UP_ARROW = 0x1052,
|
||||
KEY_DOWN_ARROW = 0x1054,
|
||||
KEY_NUM_LOCK = 0x107F,
|
||||
KEY_KP_PLUS = 0x10AB,
|
||||
KEY_KP_MINUS = 0x10AD,
|
||||
KEY_KP_MULTIPLY = 0x10AA,
|
||||
KEY_KP_DIVIDE = 0x10AF,
|
||||
KEY_KP_ENTER = 0x108D,
|
||||
KEY_KP_HOME = 0x10B7,
|
||||
KEY_KP_UP = 0x10B8,
|
||||
KEY_KP_PG_UP = 0x10B9,
|
||||
KEY_KP_LEFT = 0x10B4,
|
||||
KEY_KP_FIVE = 0x10B5,
|
||||
KEY_KP_RIGHT = 0x10B6,
|
||||
KEY_KP_END = 0x10B1,
|
||||
KEY_KP_DOWN = 0x10B2,
|
||||
KEY_KP_PG_DOWN = 0x10B3,
|
||||
KEY_KP_INSERT = 0x10B0,
|
||||
KEY_KP_DELETE = 0x10AE,
|
||||
KEY_F1 = 0x00BE,
|
||||
KEY_F2 = 0x00BF,
|
||||
KEY_F3 = 0x00C0,
|
||||
KEY_F4 = 0x00C1,
|
||||
KEY_F5 = 0x00C2,
|
||||
KEY_F6 = 0x00C3,
|
||||
KEY_F7 = 0x00C4,
|
||||
KEY_F8 = 0x00C5,
|
||||
KEY_F9 = 0x00C6,
|
||||
KEY_F10 = 0x00C7,
|
||||
KEY_F11 = 0x00C8,
|
||||
KEY_F12 = 0x00C9,
|
||||
KEY_SPACE = ' ',
|
||||
KEY_EXCLAM = '!',
|
||||
KEY_QUOTE = '"',
|
||||
KEY_NUMBER = '#',
|
||||
KEY_DOLLAR = '$',
|
||||
KEY_PERCENT = '%',
|
||||
KEY_CIRCUMFLEX = '^',
|
||||
KEY_AMPERSAND = '&',
|
||||
KEY_APOSTROPHE = '\'',
|
||||
KEY_LEFT_PARENTHESIS = '(',
|
||||
KEY_RIGHT_PARENTHESIS = ')',
|
||||
KEY_ASTERISK = '*',
|
||||
KEY_PLUS = '+',
|
||||
KEY_COMMA = ',',
|
||||
KEY_MINUS = '-',
|
||||
KEY_PERIOD = '.',
|
||||
KEY_SLASH = '/',
|
||||
KEY_0 = '0',
|
||||
KEY_1 = '1',
|
||||
KEY_2 = '2',
|
||||
KEY_3 = '3',
|
||||
KEY_4 = '4',
|
||||
KEY_5 = '5',
|
||||
KEY_6 = '6',
|
||||
KEY_7 = '7',
|
||||
KEY_8 = '8',
|
||||
KEY_9 = '9',
|
||||
KEY_COLON = ':',
|
||||
KEY_SEMICOLON = ';',
|
||||
KEY_LESS_THAN = '<',
|
||||
KEY_EQUAL = '=',
|
||||
KEY_GREATER_THAN = '>',
|
||||
KEY_QUESTION = '?',
|
||||
KEY_AT = '@',
|
||||
KEY_CAPITAL_A = 'A',
|
||||
KEY_CAPITAL_B = 'B',
|
||||
KEY_CAPITAL_C = 'C',
|
||||
KEY_CAPITAL_D = 'D',
|
||||
KEY_CAPITAL_E = 'E',
|
||||
KEY_CAPITAL_F = 'F',
|
||||
KEY_CAPITAL_G = 'G',
|
||||
KEY_CAPITAL_H = 'H',
|
||||
KEY_CAPITAL_I = 'I',
|
||||
KEY_CAPITAL_J = 'J',
|
||||
KEY_CAPITAL_K = 'K',
|
||||
KEY_CAPITAL_L = 'L',
|
||||
KEY_CAPITAL_M = 'M',
|
||||
KEY_CAPITAL_N = 'N',
|
||||
KEY_CAPITAL_O = 'O',
|
||||
KEY_CAPITAL_P = 'P',
|
||||
KEY_CAPITAL_Q = 'Q',
|
||||
KEY_CAPITAL_R = 'R',
|
||||
KEY_CAPITAL_S = 'S',
|
||||
KEY_CAPITAL_T = 'T',
|
||||
KEY_CAPITAL_U = 'U',
|
||||
KEY_CAPITAL_V = 'V',
|
||||
KEY_CAPITAL_W = 'W',
|
||||
KEY_CAPITAL_X = 'X',
|
||||
KEY_CAPITAL_Y = 'Y',
|
||||
KEY_CAPITAL_Z = 'Z',
|
||||
KEY_LEFT_BRACKET = '[',
|
||||
KEY_BACK_SLASH = '\\',
|
||||
KEY_RIGHT_BRACKET = ']',
|
||||
KEY_UNDERSCORE = '_',
|
||||
KEY_GRAVE = '`',
|
||||
KEY_A = 'a',
|
||||
KEY_B = 'b',
|
||||
KEY_C = 'c',
|
||||
KEY_D = 'd',
|
||||
KEY_E = 'e',
|
||||
KEY_F = 'f',
|
||||
KEY_G = 'g',
|
||||
KEY_H = 'h',
|
||||
KEY_I = 'i',
|
||||
KEY_J = 'j',
|
||||
KEY_K = 'k',
|
||||
KEY_L = 'l',
|
||||
KEY_M = 'm',
|
||||
KEY_N = 'n',
|
||||
KEY_O = 'o',
|
||||
KEY_P = 'p',
|
||||
KEY_Q = 'q',
|
||||
KEY_R = 'r',
|
||||
KEY_S = 's',
|
||||
KEY_T = 't',
|
||||
KEY_U = 'u',
|
||||
KEY_V = 'v',
|
||||
KEY_W = 'w',
|
||||
KEY_X = 'x',
|
||||
KEY_Y = 'y',
|
||||
KEY_Z = 'z',
|
||||
KEY_LEFT_BRACE = '{',
|
||||
KEY_BAR = '|',
|
||||
KEY_RIGHT_BRACE = '}',
|
||||
KEY_TILDE = '~',
|
||||
KEY_EURO = 0x20AC,
|
||||
KEY_POUND = 0x00A3,
|
||||
KEY_YEN = 0x00A5,
|
||||
KEY_MIDDLE_DOT = 0x0095,
|
||||
KEY_SEARCH = 0xFFAA,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
- [`ccTypes.h`](#cctypesh)
|
||||
- [deprecated functions and global variables](#deprecated-functions-and--global-variables)
|
||||
- [Changes in the Lua bindings](#changes-in-the-lua-bindings)
|
||||
- [Use bindings-generator tool for Lua binding](#use-bindings-generator-tool-for-lua-binding)
|
||||
- [Use bindings-generator tool for lua binding](#use-bindings-generator-tool-for-lua-binding)
|
||||
- [Bind the classes with namespace to lua](#bind-the-classes-with-namespace-to-lua)
|
||||
- [Use ScriptHandlerMgr to manage the register and unregister of lua function](#use-scripthandlermgr-to-manage-the-register-and-unregister-of-lua-function)
|
||||
- [Use "cc" and "ccs" as module name](#use-cc-and-ccs-as-module-name)
|
||||
- [Deprecated funtions, tables and classes](#deprecated-funtions-tables-and-classes)
|
||||
- [Use the lua table instead of the some structs and classes binding](#use-the-lua-table-instead-of-the-some-structs-and-classes-binding)
|
||||
- [Integrate more modules into lua](#integrate-more-modules-into-lua)
|
||||
- [Known issues](#known-issues)
|
||||
|
||||
# Misc Information
|
||||
|
@ -663,9 +665,21 @@ color3B = Color3B::WHITE;
|
|||
|
||||
## Changes in the Lua bindings
|
||||
|
||||
### Use bindings-generator tool for Lua binding
|
||||
### Use bindings-generator tool for lua binding
|
||||
|
||||
Only configurating the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files
|
||||
Only have to write an ini file for a module, don't have to write a lot of .pkg files
|
||||
|
||||
### Bind the classes with namespace to lua
|
||||
|
||||
In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, `CCNode` will be changed to `cc.Node`. This modification will affect some APIs as follows:
|
||||
|
||||
| v2.x | v3.0 |
|
||||
| tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") |
|
||||
| tolua_isusertable(tolua_S,1,"CCNode",0,&tolua_err | tolua_isusertable(tolua_S,1,"cc.Node",0,&tolua_err |
|
||||
| tolua_isusertype(tolua_S,1,"CCNode",0,&tolua_err) | tolua_isusertype(tolua_S,1,"cc.Node",0,&tolua_err) |
|
||||
| toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"CCNode") | toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cc.Node") |
|
||||
| tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCFileUtils") | tolua_pushusertype(tolua_S,(void*)tolua_ret,"cc.FileUtils") |
|
||||
| tolua.cast(pChildren[i + 1], "CCNode") | tolua.cast(pChildren[i + 1], "cc.Node") |
|
||||
|
||||
### Use ScriptHandlerMgr to manage the register and unregister of Lua function
|
||||
|
||||
|
@ -686,20 +700,29 @@ In v3.0 version, we only need to add the `HandlerType` enum in the `ScriptHandle
|
|||
ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HANDLERTYPE_MENU_CLICKED)
|
||||
```
|
||||
|
||||
### Use "cc" and "ccs" as module name
|
||||
### Use "cc"、"ccs"、"ccui" and "sp" as module name
|
||||
The classes in the `cocos2d`、`cocos2d::extension`、`CocosDenshion` and `cocosbuilder` namespace were bound to lua in the `cc` module;
|
||||
The classes in the `cocos2d::gui` namespace were bound to lua in the `ccui` module;
|
||||
The classes in the `spine` namespace were bound to lua in the `sp` module;
|
||||
The classes in the `cocostudio` namespace were bound to lua in the `ccs` module.
|
||||
|
||||
The main differences in the script are as follows:
|
||||
```lua
|
||||
// v2.x
|
||||
CCSprite:create(s_pPathGrossini)
|
||||
CCEaseIn:create(createSimpleMoveBy(), 2.5)
|
||||
|
||||
UILayout:create()
|
||||
CCArmature:create("bear")
|
||||
|
||||
ImageView:create()
|
||||
|
||||
// v3.0
|
||||
cc.Director:getInstance():getWinSize()
|
||||
cc.EaseIn:create(createSimpleMoveBy(), 2.5)
|
||||
|
||||
ccs.UILayer:create()
|
||||
ccs.Armature:create("bear")
|
||||
|
||||
ccui.ImageView:create()
|
||||
```
|
||||
|
||||
### Deprecated funtions, tables and classes
|
||||
|
@ -735,6 +758,24 @@ local color4B = cc.c4b(0,0,0,0)
|
|||
|
||||
Through the funtions of the LuaBasicConversion file,they can be converted the Lua table when they are as a parameter in the bindings generator.
|
||||
|
||||
### Integrate more modules into lua
|
||||
In the version 3.0,more modules were bound to lua,specific as follows:
|
||||
|
||||
```
|
||||
1.physics
|
||||
2.spine
|
||||
3.XMLHttpRequest
|
||||
```
|
||||
The XMLHttpRequest and physics are in the "cc" module,and the spine is in the "sp" module.
|
||||
The related test cases located in:
|
||||
|
||||
```
|
||||
physics ---> TestLua/PhysicsTest
|
||||
spine ---> TestLua/SpineTest
|
||||
XMLHttpRequest ---> TestLua/XMLHttpRequestTest
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Known issues
|
||||
|
||||
|
|
|
@ -38,9 +38,6 @@ LOCAL_WHOLE_STATIC_LIBRARIES += libwebsockets_static
|
|||
|
||||
LOCAL_CXXFLAGS += -fexceptions
|
||||
|
||||
LOCAL_CFLAGS += -DCC_ENABLE_CHIPMUNK_INTEGRATION=1
|
||||
LOCAL_EXPORT_CFLAGS += -DCC_ENABLE_CHIPMUNK_INTEGRATION=1
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
|
||||
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. \
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
#include "GUI/CCEditBox/CCEditBox.h"
|
||||
|
||||
// Physics integration
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION
|
||||
#include "physics-nodes/CCPhysicsDebugNode.h"
|
||||
#include "physics-nodes/CCPhysicsSprite.h"
|
||||
#endif
|
||||
|
||||
#include "assets-manager/AssetsManager.h"
|
||||
|
||||
|
|
|
@ -22,10 +22,13 @@
|
|||
#include "CCPhysicsDebugNode.h"
|
||||
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
#include "chipmunk.h"
|
||||
#endif
|
||||
|
||||
#include "ccTypes.h"
|
||||
#include "CCGeometry.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
@ -34,6 +37,7 @@
|
|||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
/*
|
||||
IMPORTANT - READ ME!
|
||||
|
||||
|
@ -174,6 +178,7 @@ static void DrawConstraint(cpConstraint *constraint, DrawNode *renderer)
|
|||
// printf("Cannot draw constraint\n");
|
||||
}
|
||||
}
|
||||
#endif // #if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
|
||||
// implementation of PhysicsDebugNode
|
||||
|
||||
|
@ -183,16 +188,17 @@ void PhysicsDebugNode::draw()
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
cpSpaceEachShape(_spacePtr, (cpSpaceShapeIteratorFunc)DrawShape, this);
|
||||
cpSpaceEachConstraint(_spacePtr, (cpSpaceConstraintIteratorFunc)DrawConstraint, this);
|
||||
|
||||
DrawNode::draw();
|
||||
DrawNode::clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
PhysicsDebugNode::PhysicsDebugNode()
|
||||
: _spacePtr(NULL)
|
||||
: _spacePtr(nullptr)
|
||||
{}
|
||||
|
||||
PhysicsDebugNode* PhysicsDebugNode::create(cpSpace *space)
|
||||
|
@ -201,9 +207,11 @@ PhysicsDebugNode* PhysicsDebugNode::create(cpSpace *space)
|
|||
if (node)
|
||||
{
|
||||
node->init();
|
||||
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
node->_spacePtr = space;
|
||||
|
||||
#else
|
||||
CCASSERT(false, "CC_ENABLE_CHIPMUNK_INTEGRATION was not enabled!");
|
||||
#endif
|
||||
node->autorelease();
|
||||
}
|
||||
else
|
||||
|
@ -220,14 +228,21 @@ PhysicsDebugNode::~PhysicsDebugNode()
|
|||
|
||||
cpSpace* PhysicsDebugNode::getSpace() const
|
||||
{
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
return _spacePtr;
|
||||
#else
|
||||
CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhysicsDebugNode::setSpace(cpSpace *space)
|
||||
{
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
_spacePtr = space;
|
||||
#else
|
||||
CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif // CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
|
|
|
@ -24,12 +24,9 @@
|
|||
#define __PHYSICSNODES_DEBUGNODE_H__
|
||||
|
||||
#include "extensions/ExtensionMacros.h"
|
||||
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
|
||||
#include "CCDrawNode.h"
|
||||
|
||||
#include "chipmunk.h"
|
||||
struct cpSpace;
|
||||
|
||||
NS_CC_EXT_BEGIN
|
||||
|
||||
|
@ -73,6 +70,4 @@ protected:
|
|||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif // CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
|
||||
#endif // __PHYSICSNODES_DEBUGNODE_H__
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#if (CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION)
|
||||
|
||||
#include "CCPhysicsSprite.h"
|
||||
|
||||
|
@ -37,8 +36,8 @@ NS_CC_EXT_BEGIN
|
|||
|
||||
PhysicsSprite::PhysicsSprite()
|
||||
: _ignoreBodyRotation(false)
|
||||
, _CPBody(NULL)
|
||||
, _pB2Body(NULL)
|
||||
, _CPBody(nullptr)
|
||||
, _pB2Body(nullptr)
|
||||
, _PTMRatio(0.0f)
|
||||
{}
|
||||
|
||||
|
@ -195,77 +194,64 @@ float PhysicsSprite::getPositionY() const
|
|||
// Chipmunk only
|
||||
//
|
||||
|
||||
|
||||
|
||||
cpBody* PhysicsSprite::getCPBody() const
|
||||
{
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
|
||||
cpBody* PhysicsSprite::getCPBody() const
|
||||
{
|
||||
return _CPBody;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setCPBody(cpBody *pBody)
|
||||
{
|
||||
_CPBody = pBody;
|
||||
}
|
||||
|
||||
b2Body* PhysicsSprite::getB2Body() const
|
||||
{
|
||||
CCASSERT(false, "Can't call box2d methods when Chipmunk is enabled");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setB2Body(b2Body *pBody)
|
||||
{
|
||||
CCASSERT(false, "Can't call box2d methods when Chipmunk is enabled");
|
||||
}
|
||||
|
||||
float PhysicsSprite::getPTMRatio() const
|
||||
{
|
||||
CCASSERT(false, "Can't call box2d methods when Chipmunk is enabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setPTMRatio(float fRatio)
|
||||
{
|
||||
CCASSERT(false, "Can't call box2d methods when Chipmunk is enabled");
|
||||
}
|
||||
|
||||
//
|
||||
// Box2d only
|
||||
//
|
||||
#elif CC_ENABLE_BOX2D_INTEGRATION
|
||||
|
||||
b2Body* PhysicsSprite::getB2Body() const
|
||||
{
|
||||
return _pB2Body;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setB2Body(b2Body *pBody)
|
||||
{
|
||||
_pB2Body = pBody;
|
||||
}
|
||||
|
||||
float PhysicsSprite::getPTMRatio() const
|
||||
{
|
||||
return _PTMRatio;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setPTMRatio(float fRatio)
|
||||
{
|
||||
_PTMRatio = fRatio;
|
||||
}
|
||||
|
||||
cpBody* PhysicsSprite::getCPBody() const
|
||||
{
|
||||
CCASSERT(false, "Can't call Chipmunk methods when Box2d is enabled");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PhysicsSprite::setCPBody(cpBody *pBody)
|
||||
{
|
||||
CCASSERT(false, "Can't call Chipmunk methods when Box2d is enabled");
|
||||
}
|
||||
|
||||
#else
|
||||
CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhysicsSprite::setCPBody(cpBody *pBody)
|
||||
{
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
_CPBody = pBody;
|
||||
#else
|
||||
CCASSERT(false, "Can't call chipmunk methods when Chipmunk is disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
b2Body* PhysicsSprite::getB2Body() const
|
||||
{
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
return _pB2Body;
|
||||
#else
|
||||
CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhysicsSprite::setB2Body(b2Body *pBody)
|
||||
{
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
_pB2Body = pBody;
|
||||
#else
|
||||
CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
float PhysicsSprite::getPTMRatio() const
|
||||
{
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
return _PTMRatio;
|
||||
#else
|
||||
CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PhysicsSprite::setPTMRatio(float fRatio)
|
||||
{
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
_PTMRatio = fRatio;
|
||||
#else
|
||||
CCASSERT(false, "Can't call box2d methods when Box2d is disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Common to Box2d and Chipmunk
|
||||
|
@ -398,13 +384,17 @@ const kmMat4& PhysicsSprite::getNodeToParentTransform() const
|
|||
}
|
||||
|
||||
// Rot, Translate Matrix
|
||||
_transform = AffineTransformMake( c * _scaleX, s * _scaleX,
|
||||
-s * _scaleY, c * _scaleY,
|
||||
x, y );
|
||||
|
||||
kmScalar mat[] = { (kmScalar)c * _scaleX, (kmScalar)s * _scaleX, 0, 0,
|
||||
(kmScalar)-s * _scaleY, (kmScalar)c * _scaleY, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
x, y, 0, 1};
|
||||
|
||||
|
||||
kmMat4Fill(&_transform, mat);
|
||||
|
||||
return _transform;
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_CC_EXT_END
|
||||
#endif //(CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#if (CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION)
|
||||
|
||||
#ifndef __PHYSICSNODES_CCPHYSICSSPRITE_H__
|
||||
#define __PHYSICSNODES_CCPHYSICSSPRITE_H__
|
||||
|
@ -127,11 +126,8 @@ protected:
|
|||
// box2d specific
|
||||
b2Body *_pB2Body;
|
||||
float _PTMRatio;
|
||||
|
||||
|
||||
};
|
||||
|
||||
NS_CC_EXT_END
|
||||
|
||||
#endif // __PHYSICSNODES_CCPHYSICSSPRITE_H__
|
||||
#endif //(CC_ENABLE_CHIPMUNK_INTEGRATION || CC_ENABLE_BOX2D_INTEGRATION)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
/* Define to 1 if SpiderMonkey should support the ability to perform
|
||||
entirely too much GC. */
|
||||
#define JS_GC_ZEAL 1
|
||||
/* #undef JS_GC_ZEAL */
|
||||
|
||||
/* Define to 1 if the <endian.h> header is present and
|
||||
useable. See jscpucfg.h. */
|
||||
|
|
|
@ -1 +1 @@
|
|||
1267f1437ae315da4c23e0fc5e7e3f70b4b3c8e2
|
||||
1541255b60cd30b2a7f3424c2ef7b1f85f8474b7
|
|
@ -1 +1 @@
|
|||
2385a209e3aa59896599e079658d761fd2985c9a
|
||||
b49342959d039cb5961a5874f38ac882feadaf82
|
|
@ -0,0 +1,20 @@
|
|||
LuaSocket 2.0.2 license
|
||||
Copyright © 2004-2007 Diego Nehab
|
||||
|
||||
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.
|
2
plugin
2
plugin
|
@ -1 +1 @@
|
|||
Subproject commit 47efb364e3b037ed7d9e529c1c2697582fa00c95
|
||||
Subproject commit 9c95a240d705507f4d33eda7435ea52da321c0d2
|
|
@ -142,6 +142,8 @@ bool UpdateLayer::init()
|
|||
{
|
||||
Layer::init();
|
||||
|
||||
createDownloadedDir();
|
||||
|
||||
/** Creates assets manager */
|
||||
pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip",
|
||||
"https://raw.github.com/minggo/AssetsManagerTest/master/version",
|
||||
|
@ -151,8 +153,6 @@ bool UpdateLayer::init()
|
|||
addChild(pAssetsManager);
|
||||
pAssetsManager->release();
|
||||
|
||||
createDownloadedDir();
|
||||
|
||||
auto size = Director::getInstance()->getWinSize();
|
||||
|
||||
pItemReset = MenuItemFont::create("reset", CC_CALLBACK_1(UpdateLayer::reset,this));
|
||||
|
|
|
@ -17,9 +17,12 @@ Box2DTestLayer::Box2DTestLayer()
|
|||
, world(NULL)
|
||||
{
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
setTouchEnabled( true );
|
||||
setAccelerometerEnabled( true );
|
||||
|
||||
auto dispatcher = Director::getInstance()->getEventDispatcher();
|
||||
|
||||
auto touchListener = EventListenerTouchAllAtOnce::create();
|
||||
touchListener->onTouchesEnded = CC_CALLBACK_2(Box2DTestLayer::onTouchesEnded, this);
|
||||
dispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
|
||||
|
||||
// init physics
|
||||
this->initPhysics();
|
||||
// create reset button
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
void update(float dt);
|
||||
void onTouchesEnded(const std::vector<Touch*>& touches, Event* event);
|
||||
|
||||
//CREATE_NODE(Box2DTestLayer);
|
||||
#if CC_ENABLE_BOX2D_INTEGRATION
|
||||
protected:
|
||||
kmMat4 _modelViewMV;
|
||||
|
|
|
@ -85,15 +85,16 @@ void ChipmunkTestLayer::toggleDebugCallback(Object* sender)
|
|||
|
||||
ChipmunkTestLayer::~ChipmunkTestLayer()
|
||||
{
|
||||
#if CC_ENABLE_CHIPMUNK_INTEGRATION
|
||||
// manually Free rogue shapes
|
||||
for( int i=0;i<4;i++) {
|
||||
cpShapeFree( _walls[i] );
|
||||
}
|
||||
|
||||
cpSpaceFree( _space );
|
||||
|
||||
Device::setAccelerometerEnabled(false);
|
||||
|
||||
Device::setAccelerometerEnabled(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::initPhysics()
|
||||
|
|
|
@ -419,7 +419,11 @@ Atlas3::Atlas3()
|
|||
label2->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label2->setColor( Color3B::RED );
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->runAction( repeat->clone() );
|
||||
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
|
||||
TintTo::create(1, 0, 255, 0),
|
||||
TintTo::create(1, 0, 0, 255),
|
||||
NULL);
|
||||
label2->runAction( RepeatForever::create(tint) );
|
||||
|
||||
auto label3 = LabelBMFont::create("Test", "fonts/bitmapFontTest2.fnt");
|
||||
// testing anchors
|
||||
|
|
|
@ -68,7 +68,9 @@ static std::function<Layer*()> createFunctions[] =
|
|||
CL(LabelTTFDistanceField),
|
||||
CL(LabelTTFDistanceFieldEffect),
|
||||
CL(LabelCharMapTest),
|
||||
CL(LabelCrashTest)
|
||||
CL(LabelCharMapColorTest),
|
||||
CL(LabelCrashTest),
|
||||
CL(LabelTTFOldNew)
|
||||
};
|
||||
|
||||
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
|
||||
|
@ -164,17 +166,17 @@ LabelTTFAlignmentNew::LabelTTFAlignmentNew()
|
|||
|
||||
auto ttf0 = Label::createWithTTF(config,"Alignment 0\nnew line",TextHAlignment::LEFT);
|
||||
ttf0->setPosition(Point(s.width/2,(s.height/6)*2 - 30));
|
||||
ttf0->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf0->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf0);
|
||||
|
||||
auto ttf1 = Label::createWithTTF(config,"Alignment 1\nnew line",TextHAlignment::CENTER);
|
||||
ttf1->setPosition(Point(s.width/2,(s.height/6)*3 - 30));
|
||||
ttf1->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf1);
|
||||
|
||||
auto ttf2 = Label::createWithTTF(config,"Alignment 2\nnew line",TextHAlignment::RIGHT);
|
||||
ttf2->setPosition(Point(s.width/2,(s.height/6)*4 - 30));
|
||||
ttf2->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf2);
|
||||
}
|
||||
|
||||
|
@ -206,10 +208,14 @@ LabelFNTColorAndOpacity::LabelFNTColorAndOpacity()
|
|||
label1->runAction(repeat);
|
||||
|
||||
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
|
||||
label2->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label2->setColor( Color3B::RED );
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->runAction( repeat->clone() );
|
||||
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
|
||||
TintTo::create(1, 0, 255, 0),
|
||||
TintTo::create(1, 0, 0, 255),
|
||||
NULL);
|
||||
label2->runAction( RepeatForever::create(tint) );
|
||||
|
||||
auto label3 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
|
||||
label3->setAnchorPoint( Point(1,1) );
|
||||
|
@ -259,7 +265,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
|
|||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
|
||||
auto BChar = (Sprite*) label->getLetter(0);
|
||||
|
@ -293,6 +299,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
|
|||
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest.fnt", "00.0");
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setPosition( Point(s.width/2.0f, 80) );
|
||||
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
auto lastChar = (Sprite*) label2->getLetter(3);
|
||||
lastChar->runAction( rot_4ever->clone() );
|
||||
|
@ -348,7 +355,7 @@ LabelFNTPadding::LabelFNTPadding()
|
|||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
}
|
||||
|
||||
std::string LabelFNTPadding::title() const
|
||||
|
@ -369,17 +376,17 @@ LabelFNTOffset::LabelFNTOffset()
|
|||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "FaFeFiFoFu");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2+50) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) ) ;
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE ) ;
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "fafefifofu");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "aeiou");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2-50) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
}
|
||||
|
||||
std::string LabelFNTOffset::title() const
|
||||
|
@ -401,18 +408,18 @@ LabelFNTColor::LabelFNTColor()
|
|||
label->setColor( Color3B::BLUE );
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Red");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, 2*s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label->setColor( Color3B::RED );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Green");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, 3*s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label->setColor( Color3B::GREEN );
|
||||
label->setString("Green");
|
||||
}
|
||||
|
@ -441,7 +448,7 @@ LabelFNTHundredLabels::LabelFNTHundredLabels()
|
|||
|
||||
auto p = Point( CCRANDOM_0_1() * s.width, CCRANDOM_0_1() * s.height);
|
||||
label->setPosition( p );
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,7 +477,7 @@ LabelFNTMultiLine::LabelFNTMultiLine()
|
|||
|
||||
// Center
|
||||
auto label2 = Label::createWithBMFont( "fonts/bitmapFontTest3.fnt", "Multi line\nCenter");
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
|
||||
s= label2->getContentSize();
|
||||
|
@ -502,20 +509,24 @@ std::string LabelFNTMultiLine::subtitle() const
|
|||
LabelFNTandTTFEmpty::LabelFNTandTTFEmpty()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
float delta = s.height/4;
|
||||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest3.fnt", "", TextHAlignment::CENTER, s.width);
|
||||
addChild(label1, 0, kTagBitmapAtlas1);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setPosition(Point(s.width/2, delta));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, s.height - 100));
|
||||
|
||||
// LabelTTF
|
||||
TTFConfig ttfConfig("fonts/arial.ttf",48);
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"", TextHAlignment::CENTER,s.width);
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setPosition(Point(s.width/2, delta * 2));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, s.height / 2));
|
||||
|
||||
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3, 0, kTagBitmapAtlas3);
|
||||
label3->setPosition(Point(s.width/2, 100));
|
||||
|
||||
schedule(schedule_selector(LabelFNTandTTFEmpty::updateStrings), 1.0f);
|
||||
|
||||
|
@ -526,11 +537,13 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
|
|||
{
|
||||
auto label1 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas1) );
|
||||
auto label2 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas2) );
|
||||
auto label3 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas3) );
|
||||
|
||||
if( ! setEmpty )
|
||||
{
|
||||
label1->setString("not empty");
|
||||
label2->setString("not empty");
|
||||
label3->setString("hi");
|
||||
|
||||
setEmpty = true;
|
||||
}
|
||||
|
@ -538,6 +551,7 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
|
|||
{
|
||||
label1->setString("");
|
||||
label2->setString("");
|
||||
label3->setString("");
|
||||
|
||||
setEmpty = false;
|
||||
}
|
||||
|
@ -550,7 +564,7 @@ std::string LabelFNTandTTFEmpty::title() const
|
|||
|
||||
std::string LabelFNTandTTFEmpty::subtitle() const
|
||||
{
|
||||
return "2 empty labels: new Label + .FNT and new Label + .TTF";
|
||||
return "3 empty labels: new Label + FNT/TTF/CharMap";
|
||||
}
|
||||
|
||||
LabelFNTRetina::LabelFNTRetina()
|
||||
|
@ -559,7 +573,7 @@ LabelFNTRetina::LabelFNTRetina()
|
|||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/konqa32.fnt", "TESTING RETINA DISPLAY");
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -583,7 +597,7 @@ LabelFNTGlyphDesigner::LabelFNTGlyphDesigner()
|
|||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/futura-48.fnt", "Testing Glyph Designer");
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -605,7 +619,7 @@ LabelTTFUnicodeChinese::LabelTTFUnicodeChinese()
|
|||
// like "Error 3 error C2146: syntax error : missing ')' before identifier 'label'";
|
||||
TTFConfig ttfConfig("fonts/wt021.ttf",55,GlyphCollection::CUSTOM, "美好的一天啊");
|
||||
auto label = Label::createWithTTF(ttfConfig,"美好的一天啊", TextHAlignment::CENTER, size.width);
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label->setPosition(Point(size.width / 2, size.height /2));
|
||||
this->addChild(label);
|
||||
}
|
||||
|
@ -624,7 +638,7 @@ LabelFNTUnicodeChinese::LabelFNTUnicodeChinese()
|
|||
{
|
||||
auto size = Director::getInstance()->getWinSize();
|
||||
auto label = Label::createWithBMFont("fonts/bitmapFontChinese.fnt", "中国");
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label->setPosition(Point(size.width / 2, size.height /2));
|
||||
this->addChild(label);
|
||||
}
|
||||
|
@ -673,7 +687,7 @@ LabelFNTMultiLineAlignment::LabelFNTMultiLineAlignment()
|
|||
|
||||
// create and initialize a Label
|
||||
this->_labelShouldRetain = Label::createWithBMFont("fonts/markerFelt.fnt", LongSentencesExample, TextHAlignment::CENTER, size.width/1.5);
|
||||
this->_labelShouldRetain->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
this->_labelShouldRetain->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->_labelShouldRetain->retain();
|
||||
|
||||
this->_arrowsBarShouldRetain = Sprite::create("Images/arrowsBar.png");
|
||||
|
@ -857,22 +871,22 @@ LabelFNTUNICODELanguages::LabelFNTUNICODELanguages()
|
|||
|
||||
auto label1 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", spanish, TextHAlignment::CENTER, 200);
|
||||
addChild(label1);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, s.height/5*3));
|
||||
|
||||
auto label2 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", chinese);
|
||||
addChild(label2);
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, s.height/5*2.5));
|
||||
|
||||
auto label3 = Label::createWithBMFont("fonts/arial-26-en-ru.fnt", russian);
|
||||
addChild(label3);
|
||||
label3->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label3->setPosition(Point(s.width/2, s.height/5*2));
|
||||
|
||||
auto label4 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", japanese);
|
||||
addChild(label4);
|
||||
label4->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label4->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label4->setPosition(Point(s.width/2, s.height/5*1.5));
|
||||
}
|
||||
|
||||
|
@ -895,7 +909,7 @@ LabelFNTBounds::LabelFNTBounds()
|
|||
|
||||
// LabelBMFont
|
||||
label1 = Label::createWithBMFont("fonts/boundsTestFont.fnt", "Testing Glyph Designer", TextHAlignment::CENTER, s.width);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -972,21 +986,21 @@ LabelTTFColor::LabelTTFColor()
|
|||
auto label1 = Label::createWithTTF(ttfConfig,"Green", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/5 * 1.5) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
// Red
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Red", TextHAlignment::CENTER, size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height/5 * 2.0) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
// Blue
|
||||
auto label3 = Label::createWithTTF(ttfConfig,"Blue", TextHAlignment::CENTER, size.width);
|
||||
label3->setPosition( Point(size.width/2, size.height/5 * 2.5) );
|
||||
label3->setColor( Color3B::BLUE );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3);
|
||||
}
|
||||
|
||||
|
@ -1006,7 +1020,7 @@ LabelTTFDynamicAlignment::LabelTTFDynamicAlignment()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 45);
|
||||
_label = Label::createWithTTF(ttfConfig,LongSentencesExample, TextHAlignment::CENTER, size.width);
|
||||
_label->setPosition( Point(size.width/2, size.height/2) );
|
||||
_label->setAnchorPoint(Point(0.5, 0.5));
|
||||
_label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
|
||||
auto menu = Menu::create(
|
||||
MenuItemFont::create("Left", CC_CALLBACK_1(LabelTTFDynamicAlignment::setAlignmentLeft, this)),
|
||||
|
@ -1078,13 +1092,13 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
|
|||
// Spanish
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Buen día, ¿cómo te llamas?", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, vSize - (vStep * 4.5)) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
// German
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"In welcher Straße haben Sie gelebt?", TextHAlignment::CENTER,size.width);
|
||||
label2->setPosition( Point(size.width/2, vSize - (vStep * 5.5)) );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
// chinese
|
||||
|
@ -1093,7 +1107,7 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
|
|||
ttfConfig.customGlyphs = chinese.c_str();
|
||||
auto label3 = Label::createWithTTF(ttfConfig,chinese, TextHAlignment::CENTER,size.width);
|
||||
label3->setPosition( Point(size.width/2, vSize - (vStep * 6.5)) );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3);
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1144,7 @@ LabelTTFFontsTestNew::LabelTTFFontsTestNew()
|
|||
label->setPosition( Point(size.width/2, ((size.height * 0.6)/arraysize(ttfpaths) * i) + (size.height/5)));
|
||||
addChild(label);
|
||||
|
||||
label->setAnchorPoint(Point(0.5, 0.5));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
} else {
|
||||
log("ERROR: Cannot load: %s", ttfpaths[i]);
|
||||
}
|
||||
|
@ -1153,7 +1167,7 @@ LabelBMFontTestNew::LabelBMFontTestNew()
|
|||
|
||||
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Hello World, this is testing the new Label using fnt file", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
}
|
||||
|
||||
|
@ -1173,9 +1187,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
|
||||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setPosition( Point(size.width/2, size.height * 0.6f) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
auto action = Sequence::create(
|
||||
|
@ -1186,9 +1200,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
|
|||
label1->runAction(RepeatForever::create(action));
|
||||
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height/5) );
|
||||
label2->setPosition( Point(size.width/2, size.height * 0.3f) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
}
|
||||
|
@ -1213,23 +1227,23 @@ LabelTTFDistanceFieldEffect::LabelTTFDistanceFieldEffect()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
|
||||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Glow", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height*0.5) );
|
||||
label1->setPosition( Point(size.width/2, size.height*0.65) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setLabelEffect(LabelEffect::GLOW,Color3B::YELLOW);
|
||||
addChild(label1);
|
||||
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Outline", TextHAlignment::CENTER, size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height*0.375) );
|
||||
label2->setPosition( Point(size.width/2, size.height*0.5) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setLabelEffect(LabelEffect::OUTLINE,Color3B::BLUE);
|
||||
addChild(label2);
|
||||
|
||||
auto label3 = Label::createWithTTF(ttfConfig,"Shadow", TextHAlignment::CENTER, size.width);
|
||||
label3->setPosition( Point(size.width/2, size.height*0.25f) );
|
||||
label3->setPosition( Point(size.width/2, size.height*0.35f) );
|
||||
label3->setColor( Color3B::RED );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label3->setLabelEffect(LabelEffect::SHADOW,Color3B::BLACK);
|
||||
addChild(label3);
|
||||
|
||||
|
@ -1256,14 +1270,9 @@ LabelCharMapTest::LabelCharMapTest()
|
|||
|
||||
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.plist");
|
||||
addChild(label2, 0, kTagSprite2);
|
||||
label2->setPosition( Point(10,160) );
|
||||
label2->setPosition( Point(10,200) );
|
||||
label2->setOpacity( 32 );
|
||||
|
||||
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
label3->setString("123 Test");
|
||||
addChild(label3, 0, kTagSprite3);
|
||||
label3->setPosition( Point(10,220) );
|
||||
|
||||
schedule(schedule_selector(LabelCharMapTest::step));
|
||||
}
|
||||
|
||||
|
@ -1291,6 +1300,63 @@ std::string LabelCharMapTest::subtitle() const
|
|||
return "Updating label should be fast.";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// LabelCharMapColorTest
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
LabelCharMapColorTest::LabelCharMapColorTest()
|
||||
{
|
||||
auto label1 = Label::createWithCharMap( "fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
addChild(label1, 0, kTagSprite1);
|
||||
label1->setPosition( Point(10,100) );
|
||||
label1->setOpacity( 200 );
|
||||
|
||||
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
addChild(label2, 0, kTagSprite2);
|
||||
label2->setPosition( Point(10,200) );
|
||||
label2->setColor( Color3B::RED );
|
||||
|
||||
auto fade = FadeOut::create(1.0f);
|
||||
auto fade_in = fade->reverse();
|
||||
auto cb = CallFunc::create(CC_CALLBACK_0(LabelCharMapColorTest::actionFinishCallback, this));
|
||||
auto seq = Sequence::create(fade, fade_in, cb, NULL);
|
||||
auto repeat = RepeatForever::create( seq );
|
||||
label2->runAction( repeat );
|
||||
|
||||
_time = 0;
|
||||
|
||||
schedule( schedule_selector(LabelCharMapColorTest::step) ); //:@selector(step:)];
|
||||
}
|
||||
|
||||
void LabelCharMapColorTest::actionFinishCallback()
|
||||
{
|
||||
CCLOG("Action finished");
|
||||
}
|
||||
|
||||
void LabelCharMapColorTest::step(float dt)
|
||||
{
|
||||
_time += dt;
|
||||
char string[12] = {0};
|
||||
sprintf(string, "%2.2f Test", _time);
|
||||
auto label1 = (Label*)getChildByTag(kTagSprite1);
|
||||
label1->setString(string);
|
||||
|
||||
auto label2 = (Label*)getChildByTag(kTagSprite2);
|
||||
sprintf(string, "%d", (int)_time);
|
||||
label2->setString( string );
|
||||
}
|
||||
|
||||
std::string LabelCharMapColorTest::title() const
|
||||
{
|
||||
return "New Label + CharMap";
|
||||
}
|
||||
|
||||
std::string LabelCharMapColorTest::subtitle() const
|
||||
{
|
||||
return "Opacity + Color should work at the same time";
|
||||
}
|
||||
|
||||
LabelCrashTest::LabelCrashTest()
|
||||
{
|
||||
auto size = Director::getInstance()->getWinSize();
|
||||
|
@ -1299,7 +1365,7 @@ LabelCrashTest::LabelCrashTest()
|
|||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Test崩溃123", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
}
|
||||
|
||||
|
@ -1312,3 +1378,63 @@ std::string LabelCrashTest::subtitle() const
|
|||
{
|
||||
return "Not crash and show [Test123] when using unknown character.";
|
||||
}
|
||||
|
||||
LabelTTFOldNew::LabelTTFOldNew()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
float delta = s.height/4;
|
||||
|
||||
auto label1 = LabelTTF::create("Cocos2d-x Label Test", "arial", 24);
|
||||
addChild(label1, 0, kTagBitmapAtlas1);
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, delta * 2));
|
||||
label1->setColor(Color3B::RED);
|
||||
|
||||
TTFConfig ttfConfig("fonts/arial.ttf", 48);
|
||||
auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test");
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, delta * 2));
|
||||
}
|
||||
|
||||
void LabelTTFOldNew::onDraw()
|
||||
{
|
||||
kmMat4 oldMat;
|
||||
kmGLGetMatrix(KM_GL_MODELVIEW, &oldMat);
|
||||
kmGLLoadMatrix(&_modelViewTransform);
|
||||
|
||||
auto label1 = (Label*)getChildByTag(kTagBitmapAtlas2);
|
||||
auto labelSize = label1->getContentSize();
|
||||
auto origin = Director::getInstance()->getWinSize();
|
||||
|
||||
origin.width = origin.width / 2 - (labelSize.width / 2);
|
||||
origin.height = origin.height / 2 - (labelSize.height / 2);
|
||||
|
||||
Point vertices[4]=
|
||||
{
|
||||
Point(origin.width, origin.height),
|
||||
Point(labelSize.width + origin.width, origin.height),
|
||||
Point(labelSize.width + origin.width, labelSize.height + origin.height),
|
||||
Point(origin.width, labelSize.height + origin.height)
|
||||
};
|
||||
DrawPrimitives::drawPoly(vertices, 4, true);
|
||||
|
||||
kmGLLoadMatrix(&oldMat);
|
||||
}
|
||||
|
||||
void LabelTTFOldNew::draw()
|
||||
{
|
||||
_renderCmd.init(_globalZOrder);
|
||||
_renderCmd.func = CC_CALLBACK_0(LabelTTFOldNew::onDraw, this);
|
||||
Director::getInstance()->getRenderer()->addCommand(&_renderCmd);
|
||||
}
|
||||
|
||||
std::string LabelTTFOldNew::title() const
|
||||
{
|
||||
return "New / Old TTF";
|
||||
}
|
||||
|
||||
std::string LabelTTFOldNew::subtitle() const
|
||||
{
|
||||
return "Comparison between old(red) and new(white) TTF label";
|
||||
}
|
||||
|
|
|
@ -363,6 +363,23 @@ private:
|
|||
float _time;
|
||||
};
|
||||
|
||||
class LabelCharMapColorTest : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(LabelCharMapColorTest);
|
||||
|
||||
LabelCharMapColorTest();
|
||||
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
|
||||
void step(float dt);
|
||||
void actionFinishCallback();
|
||||
|
||||
private:
|
||||
float _time;
|
||||
};
|
||||
|
||||
class LabelCrashTest : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
|
@ -374,6 +391,22 @@ public:
|
|||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class LabelTTFOldNew : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(LabelTTFOldNew);
|
||||
|
||||
LabelTTFOldNew();
|
||||
|
||||
virtual void draw() override;
|
||||
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
protected:
|
||||
CustomCommand _renderCmd;
|
||||
void onDraw();
|
||||
};
|
||||
|
||||
// we don't support linebreak mode
|
||||
|
||||
#endif
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue