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:
Ricardo Quesada 2014-01-27 10:52:35 -08:00
commit efaec7b7ec
157 changed files with 11149 additions and 1197 deletions

View File

@ -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

View File

@ -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]

View File

@ -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:

View File

@ -1 +1 @@
72b2e67ce3473ec4d8adf2412a9ce1d9390e0882
99ea8c15ffe770eb2acd216155c34866bbd4a645

View File

@ -1 +1 @@
7a606b7819e4f2a8d7eb689a029974d84d57cf63
c958533394964fe0c38bd60c272a0b48ec38d9d6

View File

@ -1,8 +0,0 @@
@echo off
SETLOCAL
:start
mkdir win32-msvc-vs2010-x86
cd win32-msvc-vs2010-x86
cmake -G "Visual Studio 10" ../..
pause

View File

@ -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");

View File

@ -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)
{

View File

@ -815,7 +815,7 @@ void EventDispatcher::dispatchTouchEvent(EventTouch* event)
if (event->isStopped())
{
updateListeners(event);
return false;
return true;
}
return false;

View File

@ -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;

View File

@ -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:

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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));

View File

@ -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);

View File

@ -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;
};

View File

@ -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)
{}

View File

@ -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

View File

@ -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));
}
}
/**

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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.

View File

@ -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)
{

View File

@ -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()

View File

@ -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);
}

View File

@ -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>

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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 \

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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>

View File

@ -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">

View File

@ -1 +1 @@
85c7400aec0f87b3851772fbdbc01bf59f5402d8
c5f8d4a3ea721a2ecb36fe381430b7ac6fad1740

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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";
}
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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));
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -0,0 +1 @@
e79358cdf4b02c66a50e684543e505002bdbcc91

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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 */

View File

@ -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,
};

View File

@ -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

View File

@ -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)/.. \

View File

@ -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"

View File

@ -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

View File

@ -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__

View File

@ -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)

View File

@ -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)

View File

@ -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. */

View File

@ -1 +1 @@
1267f1437ae315da4c23e0fc5e7e3f70b4b3c8e2
1541255b60cd30b2a7f3424c2ef7b1f85f8474b7

View File

@ -1 +1 @@
2385a209e3aa59896599e079658d761fd2985c9a
b49342959d039cb5961a5874f38ac882feadaf82

View File

@ -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

@ -1 +1 @@
Subproject commit 47efb364e3b037ed7d9e529c1c2697582fa00c95
Subproject commit 9c95a240d705507f4d33eda7435ea52da321c0d2

View File

@ -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));

View File

@ -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

View File

@ -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;

View File

@ -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()

View File

@ -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

View File

@ -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";
}

View File

@ -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