mirror of https://github.com/axmolengine/axmol.git
Merge branch 'develop' into glview_improvements
This commit is contained in:
commit
8c62fcb7ba
4
AUTHORS
4
AUTHORS
|
@ -511,6 +511,7 @@ Developers:
|
|||
Lee, Jae-Hong (pyrasis)
|
||||
Maintainer of tizen port.
|
||||
localStorageGetItem crashes when column text is NULL.
|
||||
fix image bug on Android
|
||||
|
||||
lumendes
|
||||
Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386.
|
||||
|
@ -729,6 +730,9 @@ Developers:
|
|||
|
||||
pandamicro
|
||||
Exposed SAXParser to JS, it is used for parsing XML in JS.
|
||||
|
||||
hanjukim
|
||||
Fixed a bug that color and opacity settings were not applied when invoking Label::alignText.
|
||||
|
||||
Retired Core Developers:
|
||||
WenSheng Yang
|
||||
|
|
|
@ -12,16 +12,19 @@ cocos2d-x-3.0beta2 ?.? ?
|
|||
[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] Uses EventDispatcher to access event in LUA testcase.
|
||||
[FIX] Exposes SAXParser class to JS, it is used for parsing XML in JS.
|
||||
[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: Crash when using unknown characters.
|
||||
[FIX] Label: Missing line breaks and wrong alignment.
|
||||
[FIX] Label: Color and opacity settings aren't applied when invoking Label::alignText.
|
||||
[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.
|
||||
|
|
|
@ -1 +1 @@
|
|||
72b2e67ce3473ec4d8adf2412a9ce1d9390e0882
|
||||
c6e696abdf3766882e2926f4366f33e849b8fc90
|
|
@ -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
|
||||
|
|
|
@ -471,6 +471,8 @@ void Label::alignText()
|
|||
insertQuadFromSprite(_reusedLetter,vaildIndex++);
|
||||
}
|
||||
}
|
||||
|
||||
updateColor();
|
||||
}
|
||||
|
||||
bool Label::computeHorizontalKernings(unsigned short int *stringToRender)
|
||||
|
|
|
@ -335,7 +335,14 @@ bool LabelTextFormatter::createStringSprites(Label *theLabel)
|
|||
// If the last character processed has an xAdvance which is less that the width of the characters image, then we need
|
||||
// to adjust the width of the string to take this into account, or the character will overlap the end of the bounding
|
||||
// box
|
||||
tmpSize.width = longestLine - charAdvance + lastCharWidth;
|
||||
if(charAdvance < lastCharWidth)
|
||||
{
|
||||
tmpSize.width = longestLine - charAdvance + lastCharWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpSize.width = longestLine;
|
||||
}
|
||||
|
||||
tmpSize.height = totalHeight;
|
||||
theLabel->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize));
|
||||
|
|
|
@ -290,7 +290,7 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type)
|
|||
break;
|
||||
|
||||
case kShaderType_PositionTextureColorAlphaTest:
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_noMVP_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag);
|
||||
|
||||
p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
|
||||
p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);
|
||||
|
|
|
@ -250,8 +250,9 @@ public:
|
|||
inline void setStoringCharacters(bool storingCharacters) { _storingCharacters = storingCharacters; };
|
||||
|
||||
/// properties
|
||||
inline ValueMap getProperties() const { return _properties; };
|
||||
inline void setProperties(ValueMap properties) {
|
||||
inline const ValueMap& getProperties() const { return _properties; }
|
||||
inline ValueMap& getProperties() { return _properties; }
|
||||
inline void setProperties(const ValueMap& properties) {
|
||||
_properties = properties;
|
||||
};
|
||||
|
||||
|
|
|
@ -107,9 +107,9 @@ Color4B::Color4B(GLubyte _r, GLubyte _g, GLubyte _b, GLubyte _a)
|
|||
{}
|
||||
|
||||
Color4B::Color4B(const Color3B& color)
|
||||
: r(color.r * 255)
|
||||
, g(color.g * 255)
|
||||
, b(color.b * 255)
|
||||
: r(color.r)
|
||||
, g(color.g)
|
||||
, b(color.b)
|
||||
, a(255)
|
||||
{}
|
||||
|
||||
|
|
|
@ -28,14 +28,20 @@ THE SOFTWARE.
|
|||
NS_CC_BEGIN
|
||||
|
||||
AutoreleasePool::AutoreleasePool()
|
||||
:_name("")
|
||||
: _name("")
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
, _isClearing(false)
|
||||
#endif
|
||||
{
|
||||
_managedObjectArray.reserve(150);
|
||||
PoolManager::getInstance()->push(this);
|
||||
}
|
||||
|
||||
AutoreleasePool::AutoreleasePool(const std::string &name)
|
||||
:_name(name)
|
||||
: _name(name)
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
, _isClearing(false)
|
||||
#endif
|
||||
{
|
||||
_managedObjectArray.reserve(150);
|
||||
PoolManager::getInstance()->push(this);
|
||||
|
@ -56,11 +62,27 @@ void AutoreleasePool::addObject(Object* object)
|
|||
|
||||
void AutoreleasePool::clear()
|
||||
{
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
_isClearing = true;
|
||||
#endif
|
||||
for (const auto &obj : _managedObjectArray)
|
||||
{
|
||||
obj->release();
|
||||
}
|
||||
_managedObjectArray.clear();
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
_isClearing = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AutoreleasePool::contains(Object* object) const
|
||||
{
|
||||
for (const auto& obj : _managedObjectArray)
|
||||
{
|
||||
if (obj == object)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AutoreleasePool::dump()
|
||||
|
@ -89,7 +111,7 @@ PoolManager* PoolManager::getInstance()
|
|||
s_singleInstance = new PoolManager();
|
||||
// Add the first auto release pool
|
||||
s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool");
|
||||
s_singleInstance->_releasePoolStack.push(s_singleInstance->_curReleasePool);
|
||||
s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool);
|
||||
}
|
||||
return s_singleInstance;
|
||||
}
|
||||
|
@ -110,8 +132,8 @@ PoolManager::~PoolManager()
|
|||
|
||||
while (!_releasePoolStack.empty())
|
||||
{
|
||||
AutoreleasePool* pool = _releasePoolStack.top();
|
||||
_releasePoolStack.pop();
|
||||
AutoreleasePool* pool = _releasePoolStack.back();
|
||||
_releasePoolStack.pop_back();
|
||||
|
||||
delete pool;
|
||||
}
|
||||
|
@ -123,9 +145,19 @@ AutoreleasePool* PoolManager::getCurrentPool() const
|
|||
return _curReleasePool;
|
||||
}
|
||||
|
||||
bool PoolManager::isObjectInPools(Object* obj) const
|
||||
{
|
||||
for (const auto& pool : _releasePoolStack)
|
||||
{
|
||||
if (pool->contains(obj))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PoolManager::push(AutoreleasePool *pool)
|
||||
{
|
||||
_releasePoolStack.push(pool);
|
||||
_releasePoolStack.push_back(pool);
|
||||
_curReleasePool = pool;
|
||||
}
|
||||
|
||||
|
@ -134,12 +166,12 @@ void PoolManager::pop()
|
|||
// Can not pop the pool that created by engine
|
||||
CC_ASSERT(_releasePoolStack.size() >= 1);
|
||||
|
||||
_releasePoolStack.pop();
|
||||
_releasePoolStack.pop_back();
|
||||
|
||||
// Should update _curReleasePool if a temple pool is released
|
||||
if (_releasePoolStack.size() > 1)
|
||||
{
|
||||
_curReleasePool = _releasePoolStack.top();
|
||||
_curReleasePool = _releasePoolStack.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,18 @@ public:
|
|||
*/
|
||||
void clear();
|
||||
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
/**
|
||||
* Whether the pool is doing `clear` operation.
|
||||
*/
|
||||
bool isClearing() const { return _isClearing; };
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks whether the pool contains the specified object.
|
||||
*/
|
||||
bool contains(Object* object) const;
|
||||
|
||||
/**
|
||||
* Dump the objects that are put into autorelease pool. It is used for debugging.
|
||||
*
|
||||
|
@ -102,6 +114,13 @@ private:
|
|||
*/
|
||||
std::vector<Object*> _managedObjectArray;
|
||||
std::string _name;
|
||||
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
/**
|
||||
* The flag for checking whether the pool is doing `clear` operation.
|
||||
*/
|
||||
bool _isClearing;
|
||||
#endif
|
||||
};
|
||||
|
||||
class CC_DLL PoolManager
|
||||
|
@ -127,6 +146,8 @@ public:
|
|||
*/
|
||||
AutoreleasePool *getCurrentPool() const;
|
||||
|
||||
bool isObjectInPools(Object* obj) const;
|
||||
|
||||
/**
|
||||
* @js NA
|
||||
* @lua NA
|
||||
|
@ -142,7 +163,7 @@ private:
|
|||
|
||||
static PoolManager* s_singleInstance;
|
||||
|
||||
std::stack<AutoreleasePool*> _releasePoolStack;
|
||||
std::deque<AutoreleasePool*> _releasePoolStack;
|
||||
AutoreleasePool *_curReleasePool;
|
||||
};
|
||||
|
||||
|
|
|
@ -63,6 +63,52 @@ Object* Object::autorelease()
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
void Object::release()
|
||||
{
|
||||
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
|
||||
--_referenceCount;
|
||||
|
||||
if (_referenceCount == 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.");
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool Object::isSingleReference() const
|
||||
{
|
||||
return _referenceCount == 1;
|
||||
|
|
|
@ -103,15 +103,16 @@ public:
|
|||
* @see retain, autorelease
|
||||
* @js NA
|
||||
*/
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
void release();
|
||||
#else
|
||||
inline void release()
|
||||
{
|
||||
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
|
||||
--_referenceCount;
|
||||
|
||||
if (_referenceCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
#endif
|
||||
/**
|
||||
* Retains the ownership.
|
||||
*
|
||||
|
|
|
@ -144,10 +144,10 @@ Node* SceneReader::createObject(const rapidjson::Value &dict, cocos2d::Node* par
|
|||
{
|
||||
gb->addComponent(com);
|
||||
}
|
||||
else
|
||||
{
|
||||
CC_SAFE_RELEASE_NULL(com);
|
||||
}
|
||||
else
|
||||
{
|
||||
com = nullptr;
|
||||
}
|
||||
}
|
||||
if(_fnSelector != nullptr)
|
||||
{
|
||||
|
|
|
@ -216,7 +216,7 @@ kmMat4 Skin::getNodeToWorldTransformAR() const
|
|||
displayTransform.mat[12] = anchorPoint.x;
|
||||
displayTransform.mat[13] = anchorPoint.y;
|
||||
|
||||
return TransformConcat(displayTransform, _bone->getArmature()->getNodeToWorldTransform());
|
||||
return TransformConcat( _bone->getArmature()->getNodeToWorldTransform(),displayTransform);
|
||||
}
|
||||
|
||||
void Skin::draw()
|
||||
|
|
|
@ -178,7 +178,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
|
|||
CCASSERT(con != nullptr, "");
|
||||
con->serialize(subDict);
|
||||
con->init();
|
||||
con->autorelease();
|
||||
_cons.pushBack(con);
|
||||
}
|
||||
|
||||
|
@ -199,7 +198,6 @@ void TriggerObj::serialize(const rapidjson::Value &val)
|
|||
}
|
||||
act->serialize(subDict);
|
||||
act->init();
|
||||
act->autorelease();
|
||||
_acts.pushBack(act);
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 37451f4ec2e2d01da9286ae97952582b81d02be8
|
||||
Subproject commit e8828b9aa8b1bfdf08bc3c077ec2cc1ebd9b9c82
|
|
@ -37,7 +37,25 @@ LOCAL_SRC_FILES := CCLuaBridge.cpp \
|
|||
../../../../external/lua/tolua/tolua_map.c \
|
||||
../../../../external/lua/tolua/tolua_push.c \
|
||||
../../../../external/lua/tolua/tolua_to.c \
|
||||
tolua_fix.c
|
||||
tolua_fix.c \
|
||||
socket/auxiliar.c \
|
||||
socket/luasocket_buffer.c \
|
||||
socket/except.c \
|
||||
socket/inet.c \
|
||||
socket/luasocket_io.c \
|
||||
socket/luasocket.c \
|
||||
socket/mime.c \
|
||||
socket/options.c \
|
||||
socket/select.c \
|
||||
socket/serial.c \
|
||||
socket/socket_scripts.c \
|
||||
socket/tcp.c \
|
||||
socket/timeout.c \
|
||||
socket/udp.c \
|
||||
socket/unix.c \
|
||||
socket/usocket.c \
|
||||
lua_extensions.c
|
||||
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../external/lua/tolua \
|
||||
$(LOCAL_PATH)/../../auto-generated/lua-bindings \
|
||||
|
|
|
@ -31,6 +31,9 @@ extern "C" {
|
|||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include "tolua_fix.h"
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#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)
|
||||
luaopen_lua_extensions(_state);
|
||||
#endif
|
||||
g_luaType.clear();
|
||||
register_all_cocos2dx(_state);
|
||||
register_all_cocos2dx_extension(_state);
|
||||
|
|
|
@ -1071,7 +1071,7 @@ bool luavals_variadic_to_array(lua_State* L,int argc, Array** ret)
|
|||
else if (lua_isuserdata(L, i + 2))
|
||||
{
|
||||
tolua_Error err;
|
||||
if (!tolua_isusertype(L, i + 2, "Object", 0, &err))
|
||||
if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err))
|
||||
{
|
||||
#if COCOS2D_DEBUG >=1
|
||||
luaval_to_native_err(L,"#ferror:",&err);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
#include "lua_extensions.h"
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// socket
|
||||
#include "socket/luasocket.h"
|
||||
#include "socket/mime.h"
|
||||
#include "socket/socket_scripts.h"
|
||||
|
||||
static luaL_Reg luax_exts[] = {
|
||||
{"socket.core", luaopen_socket_core},
|
||||
{"mime.core", luaopen_mime_core},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
void luaopen_lua_extensions(lua_State *L)
|
||||
{
|
||||
// load extensions
|
||||
luaL_Reg* lib = luax_exts;
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "preload");
|
||||
for (; lib->func; lib++)
|
||||
{
|
||||
lua_pushcfunction(L, lib->func);
|
||||
lua_setfield(L, -2, lib->name);
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
|
||||
// load extensions script
|
||||
luaopen_socket_scripts(L);
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
#ifndef __LUA_EXTRA_H_
|
||||
#define __LUA_EXTRA_H_
|
||||
|
||||
#if defined(_USRDLL)
|
||||
#define LUA_EXTENSIONS_DLL __declspec(dllexport)
|
||||
#else /* use a DLL library */
|
||||
#define LUA_EXTENSIONS_DLL
|
||||
#endif
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
void LUA_EXTENSIONS_DLL luaopen_lua_extensions(lua_State *L);
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LUA_EXTRA_H_ */
|
|
@ -0,0 +1,158 @@
|
|||
/*=========================================================================*\
|
||||
* Auxiliar routines for class hierarchy manipulation
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "auxiliar.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes the module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_open(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a new class with given methods
|
||||
* Methods whose names start with __ are passed directly to the metatable.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
|
||||
luaL_newmetatable(L, classname); /* mt */
|
||||
/* create __index table to place methods */
|
||||
lua_pushstring(L, "__index"); /* mt,"__index" */
|
||||
lua_newtable(L); /* mt,"__index",it */
|
||||
/* put class name into class metatable */
|
||||
lua_pushstring(L, "class"); /* mt,"__index",it,"class" */
|
||||
lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */
|
||||
lua_rawset(L, -3); /* mt,"__index",it */
|
||||
/* pass all methods that start with _ to the metatable, and all others
|
||||
* to the index table */
|
||||
for (; func->name; func++) { /* mt,"__index",it */
|
||||
lua_pushstring(L, func->name);
|
||||
lua_pushcfunction(L, func->func);
|
||||
lua_rawset(L, func->name[0] == '_' ? -5: -3);
|
||||
}
|
||||
lua_rawset(L, -3); /* mt */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Prints the value of a class in a nice way
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_tostring(lua_State *L) {
|
||||
char buf[32];
|
||||
if (!lua_getmetatable(L, 1)) goto error;
|
||||
lua_pushstring(L, "__index");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_istable(L, -1)) goto error;
|
||||
lua_pushstring(L, "class");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isstring(L, -1)) goto error;
|
||||
sprintf(buf, "%p", lua_touserdata(L, 1));
|
||||
lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf);
|
||||
return 1;
|
||||
error:
|
||||
lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'");
|
||||
lua_error(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Insert class into group
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) {
|
||||
luaL_getmetatable(L, classname);
|
||||
lua_pushstring(L, groupname);
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, -3);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Make sure argument is a boolean
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_checkboolean(lua_State *L, int objidx) {
|
||||
if (!lua_isboolean(L, objidx))
|
||||
auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN));
|
||||
return lua_toboolean(L, objidx);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return userdata pointer if object belongs to a given class, abort with
|
||||
* error otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
|
||||
void *data = auxiliar_getclassudata(L, classname, objidx);
|
||||
if (!data) {
|
||||
char msg[45];
|
||||
sprintf(msg, "%.35s expected", classname);
|
||||
luaL_argerror(L, objidx, msg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return userdata pointer if object belongs to a given group, abort with
|
||||
* error otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
|
||||
void *data = auxiliar_getgroupudata(L, groupname, objidx);
|
||||
if (!data) {
|
||||
char msg[45];
|
||||
sprintf(msg, "%.35s expected", groupname);
|
||||
luaL_argerror(L, objidx, msg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Set object class
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
|
||||
luaL_getmetatable(L, classname);
|
||||
if (objidx < 0) objidx--;
|
||||
lua_setmetatable(L, objidx);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Get a userdata pointer if object belongs to a given group. Return NULL
|
||||
* otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
|
||||
if (!lua_getmetatable(L, objidx))
|
||||
return NULL;
|
||||
lua_pushstring(L, groupname);
|
||||
lua_rawget(L, -2);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 2);
|
||||
return NULL;
|
||||
} else {
|
||||
lua_pop(L, 2);
|
||||
return lua_touserdata(L, objidx);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Get a userdata pointer if object belongs to a given class. Return NULL
|
||||
* otherwise
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
|
||||
return luaL_checkudata(L, objidx, classname);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Throws error when argument does not have correct type.
|
||||
* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
|
||||
const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
|
||||
luaL_typename(L, narg));
|
||||
return luaL_argerror(L, narg, msg);
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef AUXILIAR_H
|
||||
#define AUXILIAR_H
|
||||
/*=========================================================================*\
|
||||
* Auxiliar routines for class hierarchy manipulation
|
||||
* LuaSocket toolkit (but completely independent of other LuaSocket modules)
|
||||
*
|
||||
* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
|
||||
* group is a name associated with a class. A class can belong to any number
|
||||
* of groups. This module provides the functionality to:
|
||||
*
|
||||
* - create new classes
|
||||
* - add classes to groups
|
||||
* - set the class of objects
|
||||
* - check if an object belongs to a given class or group
|
||||
* - get the userdata associated to objects
|
||||
* - print objects in a pretty way
|
||||
*
|
||||
* LuaSocket class names follow the convention <module>{<class>}. Modules
|
||||
* can define any number of classes and groups. The module tcp.c, for
|
||||
* example, defines the classes tcp{master}, tcp{client} and tcp{server} and
|
||||
* the groups tcp{client,server} and tcp{any}. Module functions can then
|
||||
* perform type-checking on their arguments by either class or group.
|
||||
*
|
||||
* LuaSocket metatables define the __index metamethod as being a table. This
|
||||
* table has one field for each method supported by the class, and a field
|
||||
* "class" with the class name.
|
||||
*
|
||||
* The mapping from class name to the corresponding metatable and the
|
||||
* reverse mapping are done using lauxlib.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
int auxiliar_open(lua_State *L);
|
||||
void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
|
||||
void auxiliar_add2group(lua_State *L, const char *classname, const char *group);
|
||||
void auxiliar_setclass(lua_State *L, const char *classname, int objidx);
|
||||
void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx);
|
||||
void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx);
|
||||
void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx);
|
||||
void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx);
|
||||
int auxiliar_checkboolean(lua_State *L, int objidx);
|
||||
int auxiliar_tostring(lua_State *L);
|
||||
int auxiliar_typeerror(lua_State *L, int narg, const char *tname);
|
||||
|
||||
#endif /* AUXILIAR_H */
|
|
@ -0,0 +1,97 @@
|
|||
/*=========================================================================*\
|
||||
* Simple exception support
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "except.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int global_protect(lua_State *L);
|
||||
static int global_newtry(lua_State *L);
|
||||
static int protected_(lua_State *L);
|
||||
static int finalize(lua_State *L);
|
||||
static int do_nothing(lua_State *L);
|
||||
|
||||
/* except functions */
|
||||
static luaL_Reg func[] = {
|
||||
{"newtry", global_newtry},
|
||||
{"protect", global_protect},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Try factory
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void wrap(lua_State *L) {
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L, 1);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_settable(L, -3);
|
||||
lua_insert(L, -2);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
static int finalize(lua_State *L) {
|
||||
if (!lua_toboolean(L, 1)) {
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_pcall(L, 0, 0, 0);
|
||||
lua_settop(L, 2);
|
||||
wrap(L);
|
||||
lua_error(L);
|
||||
return 0;
|
||||
} else return lua_gettop(L);
|
||||
}
|
||||
|
||||
static int do_nothing(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int global_newtry(lua_State *L) {
|
||||
lua_settop(L, 1);
|
||||
if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
|
||||
lua_pushcclosure(L, finalize, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Protect factory
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int unwrap(lua_State *L) {
|
||||
if (lua_istable(L, -1)) {
|
||||
lua_pushnumber(L, 1);
|
||||
lua_gettable(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 1;
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
static int protected_(lua_State *L) {
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_insert(L, 1);
|
||||
if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
|
||||
if (unwrap(L)) return 2;
|
||||
else lua_error(L);
|
||||
return 0;
|
||||
} else return lua_gettop(L);
|
||||
}
|
||||
|
||||
static int global_protect(lua_State *L) {
|
||||
lua_pushcclosure(L, protected_, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Init module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int except_open(lua_State *L) {
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef EXCEPT_H
|
||||
#define EXCEPT_H
|
||||
/*=========================================================================*\
|
||||
* Exception control
|
||||
* LuaSocket toolkit (but completely independent from other modules)
|
||||
*
|
||||
* This provides support for simple exceptions in Lua. During the
|
||||
* development of the HTTP/FTP/SMTP support, it became aparent that
|
||||
* error checking was taking a substantial amount of the coding. These
|
||||
* function greatly simplify the task of checking errors.
|
||||
*
|
||||
* The main idea is that functions should return nil as its first return
|
||||
* value when it finds an error, and return an error message (or value)
|
||||
* following nil. In case of success, as long as the first value is not nil,
|
||||
* the other values don't matter.
|
||||
*
|
||||
* The idea is to nest function calls with the "try" function. This function
|
||||
* checks the first value, and calls "error" on the second if the first is
|
||||
* nil. Otherwise, it returns all values it received.
|
||||
*
|
||||
* The protect function returns a new function that behaves exactly like the
|
||||
* function it receives, but the new function doesn't throw exceptions: it
|
||||
* returns nil followed by the error message instead.
|
||||
*
|
||||
* With these two function, it's easy to write functions that throw
|
||||
* exceptions on error, but that don't interrupt the user script.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
int except_open(lua_State *L);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,528 @@
|
|||
/*=========================================================================*\
|
||||
* Internet domain functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "inet.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int inet_global_toip(lua_State *L);
|
||||
static int inet_global_getaddrinfo(lua_State *L);
|
||||
static int inet_global_tohostname(lua_State *L);
|
||||
static int inet_global_getnameinfo(lua_State *L);
|
||||
static void inet_pushresolved(lua_State *L, struct hostent *hp);
|
||||
static int inet_global_gethostname(lua_State *L);
|
||||
|
||||
/* DNS functions */
|
||||
static luaL_Reg func[] = {
|
||||
{ "toip", inet_global_toip},
|
||||
{ "getaddrinfo", inet_global_getaddrinfo},
|
||||
{ "tohostname", inet_global_tohostname},
|
||||
{ "getnameinfo", inet_global_getnameinfo},
|
||||
{ "gethostname", inet_global_gethostname},
|
||||
{ NULL, NULL}
|
||||
};
|
||||
|
||||
#ifdef _WINDOWS_
|
||||
/****luodx patch for windows xp start**/
|
||||
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length)
|
||||
{
|
||||
char* result = inet_ntoa(*(IN_ADDR*)src);
|
||||
if (result != NULL){
|
||||
strcpy(dest, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int win32xp_inet_pton(int family, const char* string, PVOID dest) {
|
||||
return inet_aton(string, (IN_ADDR*)dest);
|
||||
}
|
||||
/****luodx patch for windows xp end**/
|
||||
#endif
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_open(lua_State *L)
|
||||
{
|
||||
lua_pushstring(L, "dns");
|
||||
lua_newtable(L);
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
lua_settable(L, -3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_gethost(const char *address, struct hostent **hp) {
|
||||
struct in_addr addr;
|
||||
if (inet_aton(address, &addr))
|
||||
return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp);
|
||||
else
|
||||
return socket_gethostbyname(address, hp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_tohostname(lua_State *L) {
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
struct hostent *hp = NULL;
|
||||
int err = inet_gethost(address, &hp);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_hoststrerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, hp->h_name);
|
||||
inet_pushresolved(L, hp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int inet_global_getnameinfo(lua_State *L) {
|
||||
int i, ret;
|
||||
char host[1024];
|
||||
char serv[32];
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *resolved, *iter;
|
||||
const char *node = luaL_optstring(L, 1, NULL);
|
||||
const char *service = luaL_optstring(L, 2, NULL);
|
||||
|
||||
if (!(node || service))
|
||||
luaL_error(L, "You have to specify a hostname, a service, or both");
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
|
||||
/* getaddrinfo must get a node and a service argument */
|
||||
ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7",
|
||||
&hints, &resolved);
|
||||
if (ret != 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_gaistrerror(ret));
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
|
||||
getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host,
|
||||
node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0);
|
||||
|
||||
if (node) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, host);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
|
||||
if (service) {
|
||||
lua_pushstring(L, serv);
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns all information provided by the resolver given a host name
|
||||
* or ip address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_toip(lua_State *L)
|
||||
{
|
||||
const char *address = luaL_checkstring(L, 1);
|
||||
struct hostent *hp = NULL;
|
||||
int err = inet_gethost(address, &hp);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_hoststrerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr)));
|
||||
inet_pushresolved(L, hp);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int inet_optfamily(lua_State* L, int narg, const char* def)
|
||||
{
|
||||
static const char* optname[] = { "unspec", "inet", "inet6", NULL };
|
||||
static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
|
||||
|
||||
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||
}
|
||||
|
||||
int inet_optsocktype(lua_State* L, int narg, const char* def)
|
||||
{
|
||||
static const char* optname[] = { "stream", "dgram", NULL };
|
||||
static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 };
|
||||
|
||||
return optvalue[luaL_checkoption(L, narg, def, optname)];
|
||||
}
|
||||
|
||||
static int inet_global_getaddrinfo(lua_State *L)
|
||||
{
|
||||
const char *hostname = luaL_checkstring(L, 1);
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
struct addrinfo hints;
|
||||
int i = 1, ret = 0;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
ret = getaddrinfo(hostname, NULL, &hints, &resolved);
|
||||
if (ret != 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_gaistrerror(ret));
|
||||
return 2;
|
||||
}
|
||||
lua_newtable(L);
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
|
||||
getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf,
|
||||
(socklen_t) sizeof(hbuf), sbuf, 0, NI_NUMERICHOST);
|
||||
lua_pushnumber(L, i);
|
||||
lua_newtable(L);
|
||||
switch (iterator->ai_family) {
|
||||
case AF_INET:
|
||||
lua_pushliteral(L, "family");
|
||||
lua_pushliteral(L, "inet");
|
||||
lua_settable(L, -3);
|
||||
break;
|
||||
case AF_INET6:
|
||||
lua_pushliteral(L, "family");
|
||||
lua_pushliteral(L, "inet6");
|
||||
lua_settable(L, -3);
|
||||
break;;
|
||||
}
|
||||
lua_pushliteral(L, "addr");
|
||||
lua_pushstring(L, hbuf);
|
||||
lua_settable(L, -3);
|
||||
lua_settable(L, -3);
|
||||
i++;
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Gets the host name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int inet_global_gethostname(lua_State *L)
|
||||
{
|
||||
char name[257];
|
||||
name[256] = '\0';
|
||||
if (gethostname(name, 256) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
lua_pushstring(L, name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Retrieves socket peer name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in peer;
|
||||
socklen_t peer_len = sizeof(peer);
|
||||
char name[INET_ADDRSTRLEN];
|
||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &peer.sin_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(peer.sin_port));
|
||||
lua_pushliteral(L, "inet");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 peer;
|
||||
socklen_t peer_len = sizeof(peer);
|
||||
char name[INET6_ADDRSTRLEN];
|
||||
if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &peer.sin6_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(peer.sin6_port));
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", family);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Retrieves socket local name
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in local;
|
||||
socklen_t local_len = sizeof(local);
|
||||
char name[INET_ADDRSTRLEN];
|
||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &local.sin_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(local.sin_port));
|
||||
lua_pushliteral(L, "inet");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 local;
|
||||
socklen_t local_len = sizeof(local);
|
||||
char name[INET6_ADDRSTRLEN];
|
||||
if (getsockname(*ps, (SA *) &local, &local_len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
return 2;
|
||||
} else {
|
||||
my_inet_ntop(family, &local.sin6_addr, name, sizeof(name));
|
||||
lua_pushstring(L, name);
|
||||
lua_pushnumber(L, ntohs(local.sin6_port));
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", family);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Passes all resolver information to Lua as a table
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
||||
{
|
||||
char **alias;
|
||||
struct in_addr **addr;
|
||||
int i, resolved;
|
||||
lua_newtable(L); resolved = lua_gettop(L);
|
||||
lua_pushstring(L, "name");
|
||||
lua_pushstring(L, hp->h_name);
|
||||
lua_settable(L, resolved);
|
||||
lua_pushstring(L, "ip");
|
||||
lua_pushstring(L, "alias");
|
||||
i = 1;
|
||||
alias = hp->h_aliases;
|
||||
lua_newtable(L);
|
||||
if (alias) {
|
||||
while (*alias) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, *alias);
|
||||
lua_settable(L, -3);
|
||||
i++; alias++;
|
||||
}
|
||||
}
|
||||
lua_settable(L, resolved);
|
||||
i = 1;
|
||||
lua_newtable(L);
|
||||
addr = (struct in_addr **) hp->h_addr_list;
|
||||
if (addr) {
|
||||
while (*addr) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushstring(L, inet_ntoa(**addr));
|
||||
lua_settable(L, -3);
|
||||
i++; addr++;
|
||||
}
|
||||
}
|
||||
lua_settable(L, resolved);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to create a new inet socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trycreate(p_socket ps, int family, int type) {
|
||||
return socket_strerror(socket_create(ps, family, type, 0));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* "Disconnects" a DGRAM socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in sin;
|
||||
memset((char *) &sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_UNSPEC;
|
||||
sin.sin_addr.s_addr = INADDR_ANY;
|
||||
return socket_strerror(socket_connect(ps, (SA *) &sin,
|
||||
sizeof(sin), tm));
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 sin6;
|
||||
struct in6_addr addrany = IN6ADDR_ANY_INIT;
|
||||
memset((char *) &sin6, 0, sizeof(sin6));
|
||||
sin6.sin6_family = AF_UNSPEC;
|
||||
fprintf(stderr, "disconnecting\n");
|
||||
sin6.sin6_addr = addrany;
|
||||
return socket_strerror(socket_connect(ps, (SA *) &sin6,
|
||||
sizeof(sin6), tm));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to connect to remote address (address, port)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
||||
const char *serv, p_timeout tm, struct addrinfo *connecthints)
|
||||
{
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(address, serv,
|
||||
connecthints, &resolved));
|
||||
if (err != NULL) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
timeout_markstart(tm);
|
||||
/* try connecting to remote address */
|
||||
err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen, tm));
|
||||
/* if success, break out of loop */
|
||||
if (err == NULL) break;
|
||||
}
|
||||
freeaddrinfo(resolved);
|
||||
/* here, if err is set, we failed */
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to accept a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm)
|
||||
{
|
||||
socklen_t len;
|
||||
t_sockaddr_storage addr;
|
||||
if (family == PF_INET6) {
|
||||
len = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to bind socket to (address, port)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
||||
struct addrinfo *bindhints)
|
||||
{
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
t_socket sock = *ps;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved));
|
||||
if (err) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
/* iterate over resolved addresses until one is good */
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
if(sock == SOCKET_INVALID) {
|
||||
err = socket_strerror(socket_create(&sock, iterator->ai_family,
|
||||
iterator->ai_socktype, iterator->ai_protocol));
|
||||
if(err)
|
||||
continue;
|
||||
}
|
||||
/* try binding to local address */
|
||||
err = socket_strerror(socket_bind(&sock,
|
||||
(SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen));
|
||||
|
||||
/* keep trying unless bind succeeded */
|
||||
if (err) {
|
||||
if(sock != *ps)
|
||||
socket_destroy(&sock);
|
||||
} else {
|
||||
/* remember what we connected to, particularly the family */
|
||||
*bindhints = *iterator;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* cleanup and return error */
|
||||
freeaddrinfo(resolved);
|
||||
*ps = sock;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Some systems do not provide this so that we provide our own. It's not
|
||||
* marvelously fast, but it works just fine.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *inp)
|
||||
{
|
||||
unsigned int a = 0, b = 0, c = 0, d = 0;
|
||||
int n = 0, r;
|
||||
unsigned long int addr = 0;
|
||||
r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
|
||||
if (r == 0 || n == 0) return 0;
|
||||
cp += n;
|
||||
if (*cp) return 0;
|
||||
if (a > 255 || b > 255 || c > 255 || d > 255) return 0;
|
||||
if (inp) {
|
||||
addr += a; addr <<= 8;
|
||||
addr += b; addr <<= 8;
|
||||
addr += c; addr <<= 8;
|
||||
addr += d;
|
||||
inp->s_addr = htonl(addr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef INET_H
|
||||
#define INET_H
|
||||
/*=========================================================================*\
|
||||
* Internet domain functions
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module implements the creation and connection of internet domain
|
||||
* sockets, on top of the socket.h interface, and the interface of with the
|
||||
* resolver.
|
||||
*
|
||||
* The function inet_aton is provided for the platforms where it is not
|
||||
* available. The module also implements the interface of the internet
|
||||
* getpeername and getsockname functions as seen by Lua programs.
|
||||
*
|
||||
* The Lua functions toip and tohostname are also implemented here.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "socket.h"
|
||||
#include "timeout.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define INET_ATON
|
||||
#endif
|
||||
|
||||
int inet_open(lua_State *L);
|
||||
|
||||
const char *inet_trycreate(p_socket ps, int family, int type);
|
||||
const char *inet_tryconnect(p_socket ps, const char *address,
|
||||
const char *serv, p_timeout tm, struct addrinfo *connecthints);
|
||||
const char *inet_trybind(p_socket ps, const char *address, const char *serv,
|
||||
struct addrinfo *bindhints);
|
||||
const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
|
||||
const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
|
||||
|
||||
int inet_meth_getpeername(lua_State *L, p_socket ps, int family);
|
||||
int inet_meth_getsockname(lua_State *L, p_socket ps, int family);
|
||||
|
||||
int inet_optfamily(lua_State* L, int narg, const char* def);
|
||||
int inet_optsocktype(lua_State* L, int narg, const char* def);
|
||||
|
||||
#ifdef INET_ATON
|
||||
int inet_aton(const char *cp, struct in_addr *inp);
|
||||
#endif
|
||||
|
||||
#ifndef _WINDOWS_
|
||||
#define my_inet_ntop(a,b,c,d) inet_ntop(a,b,c,d)
|
||||
#define my_inet_pton(a,b,c) inet_pton(a,b,c)
|
||||
#else
|
||||
int win32xp_inet_pton(int family, const char* string, PVOID dest);
|
||||
char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length);
|
||||
#define my_inet_ntop(a,b,c,d) win32xp_inet_ntop(a,b,c,d)
|
||||
#define my_inet_pton(a,b,c) win32xp_inet_pton(a,b,c)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* INET_H */
|
|
@ -0,0 +1,116 @@
|
|||
/*=========================================================================*\
|
||||
* LuaSocket toolkit
|
||||
* Networking support for the Lua language
|
||||
* Diego Nehab
|
||||
* 26/11/1999
|
||||
*
|
||||
* This library is part of an effort to progressively increase the network
|
||||
* connectivity of the Lua language. The Lua interface to networking
|
||||
* functions follows the Sockets API closely, trying to simplify all tasks
|
||||
* involved in setting up both client and server connections. The provided
|
||||
* IO routines, however, follow the Lua style, being very similar to the
|
||||
* standard Lua read and write functions.
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* Standard include files
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
||||
#include "compat-5.1.h"
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* LuaSocket includes
|
||||
\*=========================================================================*/
|
||||
#include "luasocket.h"
|
||||
#include "auxiliar.h"
|
||||
#include "except.h"
|
||||
#include "timeout.h"
|
||||
#include "luasocket_buffer.h"
|
||||
#include "inet.h"
|
||||
#include "tcp.h"
|
||||
#include "udp.h"
|
||||
#include "select.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Internal function prototypes
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_skip(lua_State *L);
|
||||
static int global_unload(lua_State *L);
|
||||
static int base_open(lua_State *L);
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Modules and functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const luaL_Reg mod[] = {
|
||||
{"auxiliar", auxiliar_open},
|
||||
{"except", except_open},
|
||||
{"timeout", timeout_open},
|
||||
{"buffer", buffer_open},
|
||||
{"inet", inet_open},
|
||||
{"tcp", tcp_open},
|
||||
{"udp", udp_open},
|
||||
{"select", select_open},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static luaL_Reg func[] = {
|
||||
{"skip", global_skip},
|
||||
{"__unload", global_unload},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Skip a few arguments
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_skip(lua_State *L) {
|
||||
int amount = luaL_checkint(L, 1);
|
||||
int ret = lua_gettop(L) - amount - 1;
|
||||
return ret >= 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Unloads the library
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_unload(lua_State *L) {
|
||||
(void) L;
|
||||
socket_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Setup basic stuff.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int base_open(lua_State *L) {
|
||||
if (socket_open()) {
|
||||
/* export functions (and leave namespace table on top of stack) */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
lua_pushstring(L, "_DEBUG");
|
||||
lua_pushboolean(L, 1);
|
||||
lua_rawset(L, -3);
|
||||
#endif
|
||||
/* make version string available to scripts */
|
||||
lua_pushstring(L, "_VERSION");
|
||||
lua_pushstring(L, LUASOCKET_VERSION);
|
||||
lua_rawset(L, -3);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushstring(L, "unable to initialize library");
|
||||
lua_error(L);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes all library modules.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_core(lua_State *L) {
|
||||
int i;
|
||||
base_open(L);
|
||||
for (i = 0; mod[i].name; i++) mod[i].func(L);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef LUASOCKET_H
|
||||
#define LUASOCKET_H
|
||||
/*=========================================================================*\
|
||||
* LuaSocket toolkit
|
||||
* Networking support for the Lua language
|
||||
* Diego Nehab
|
||||
* 9/11/1999
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Current socket library version
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define LUASOCKET_VERSION "LuaSocket 2.1-rc1"
|
||||
#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2012 Diego Nehab"
|
||||
#define LUASOCKET_AUTHORS "Diego Nehab"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* This macro prefixes all exported API functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef LUASOCKET_API
|
||||
#define LUASOCKET_API extern
|
||||
#endif
|
||||
|
||||
#if LUA_VERSION_NUM > 501 & !( defined LUA_COMPAT_MODULE)
|
||||
# error Lua 5.2 requires LUA_COMPAT_MODULE defined for luaL_openlib
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes the library.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_core(lua_State *L);
|
||||
|
||||
#endif /* LUASOCKET_H */
|
|
@ -0,0 +1,276 @@
|
|||
/*=========================================================================*\
|
||||
* Input/Output interface for Lua programs
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "luasocket_buffer.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b);
|
||||
static int recvline(p_buffer buf, luaL_Buffer *b);
|
||||
static int recvall(p_buffer buf, luaL_Buffer *b);
|
||||
static int buffer_get(p_buffer buf, const char **data, size_t *count);
|
||||
static void buffer_skip(p_buffer buf, size_t count);
|
||||
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent);
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_open(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes C structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
|
||||
buf->first = buf->last = 0;
|
||||
buf->io = io;
|
||||
buf->tm = tm;
|
||||
buf->received = buf->sent = 0;
|
||||
buf->birthday = timeout_gettime();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:getstats() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_getstats(lua_State *L, p_buffer buf) {
|
||||
lua_pushnumber(L, (lua_Number) buf->received);
|
||||
lua_pushnumber(L, (lua_Number) buf->sent);
|
||||
lua_pushnumber(L, timeout_gettime() - buf->birthday);
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:setstats() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_setstats(lua_State *L, p_buffer buf) {
|
||||
buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
|
||||
buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
|
||||
if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:send() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_send(lua_State *L, p_buffer buf) {
|
||||
int top = lua_gettop(L);
|
||||
int err = IO_DONE;
|
||||
size_t size = 0, sent = 0;
|
||||
const char *data = luaL_checklstring(L, 2, &size);
|
||||
long start = (long) luaL_optnumber(L, 3, 1);
|
||||
long end = (long) luaL_optnumber(L, 4, -1);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
p_timeout tm = timeout_markstart(buf->tm);
|
||||
#endif
|
||||
if (start < 0) start = (long) (size+start+1);
|
||||
if (end < 0) end = (long) (size+end+1);
|
||||
if (start < 1) start = (long) 1;
|
||||
if (end > (long) size) end = (long) size;
|
||||
if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent);
|
||||
/* check if there was an error */
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||
} else {
|
||||
lua_pushnumber(L, (lua_Number) (sent+start-1));
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* push time elapsed during operation as the last return value */
|
||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
||||
#endif
|
||||
return lua_gettop(L) - top;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* object:receive() interface
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_meth_receive(lua_State *L, p_buffer buf) {
|
||||
int err = IO_DONE, top = lua_gettop(L);
|
||||
luaL_Buffer b;
|
||||
size_t size;
|
||||
const char *part = luaL_optlstring(L, 3, "", &size);
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
p_timeout tm = timeout_markstart(buf->tm);
|
||||
#endif
|
||||
/* initialize buffer with optional extra prefix
|
||||
* (useful for concatenating previous partial results) */
|
||||
luaL_buffinit(L, &b);
|
||||
luaL_addlstring(&b, part, size);
|
||||
/* receive new patterns */
|
||||
if (!lua_isnumber(L, 2)) {
|
||||
const char *p= luaL_optstring(L, 2, "*l");
|
||||
if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
|
||||
else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
|
||||
else luaL_argcheck(L, 0, 2, "invalid receive pattern");
|
||||
/* get a fixed number of bytes (minus what was already partially
|
||||
* received) */
|
||||
} else {
|
||||
double n = lua_tonumber(L, 2);
|
||||
size_t wanted = (size_t) n;
|
||||
luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
|
||||
if (size == 0 || wanted > size)
|
||||
err = recvraw(buf, wanted-size, &b);
|
||||
}
|
||||
/* check if there was an error */
|
||||
if (err != IO_DONE) {
|
||||
/* we can't push anyting in the stack before pushing the
|
||||
* contents of the buffer. this is the reason for the complication */
|
||||
luaL_pushresult(&b);
|
||||
lua_pushstring(L, buf->io->error(buf->io->ctx, err));
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_replace(L, -4);
|
||||
} else {
|
||||
luaL_pushresult(&b);
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* push time elapsed during operation as the last return value */
|
||||
lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
|
||||
#endif
|
||||
return lua_gettop(L) - top;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines if there is any data in the read buffer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buffer_isempty(p_buffer buf) {
|
||||
return buf->first >= buf->last;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sends a block of data (unbuffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define STEPSIZE 8192
|
||||
static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) {
|
||||
p_io io = buf->io;
|
||||
p_timeout tm = buf->tm;
|
||||
size_t total = 0;
|
||||
int err = IO_DONE;
|
||||
while (total < count && err == IO_DONE) {
|
||||
size_t done = 0;
|
||||
size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE;
|
||||
err = io->send(io->ctx, data+total, step, &done, tm);
|
||||
total += done;
|
||||
}
|
||||
*sent = total;
|
||||
buf->sent += total;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads a fixed number of bytes (buffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
size_t total = 0;
|
||||
while (err == IO_DONE) {
|
||||
size_t count; const char *data;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
count = MIN(count, wanted - total);
|
||||
luaL_addlstring(b, data, count);
|
||||
buffer_skip(buf, count);
|
||||
total += count;
|
||||
if (total >= wanted) break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads everything until the connection is closed (buffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvall(p_buffer buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
size_t total = 0;
|
||||
while (err == IO_DONE) {
|
||||
const char *data; size_t count;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
total += count;
|
||||
luaL_addlstring(b, data, count);
|
||||
buffer_skip(buf, count);
|
||||
}
|
||||
if (err == IO_CLOSED) {
|
||||
if (total > 0) return IO_DONE;
|
||||
else return IO_CLOSED;
|
||||
} else return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
||||
* are not returned by the function and are discarded from the buffer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int recvline(p_buffer buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
while (err == IO_DONE) {
|
||||
size_t count, pos; const char *data;
|
||||
err = buffer_get(buf, &data, &count);
|
||||
pos = 0;
|
||||
while (pos < count && data[pos] != '\n') {
|
||||
/* we ignore all \r's */
|
||||
if (data[pos] != '\r') luaL_addchar(b, data[pos]);
|
||||
pos++;
|
||||
}
|
||||
if (pos < count) { /* found '\n' */
|
||||
buffer_skip(buf, pos+1); /* skip '\n' too */
|
||||
break; /* we are done */
|
||||
} else /* reached the end of the buffer */
|
||||
buffer_skip(buf, pos);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Skips a given number of bytes from read buffer. No data is read from the
|
||||
* transport layer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void buffer_skip(p_buffer buf, size_t count) {
|
||||
buf->received += count;
|
||||
buf->first += count;
|
||||
if (buffer_isempty(buf))
|
||||
buf->first = buf->last = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return any data available in buffer, or get more data from transport layer
|
||||
* if buffer is empty
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int buffer_get(p_buffer buf, const char **data, size_t *count) {
|
||||
int err = IO_DONE;
|
||||
p_io io = buf->io;
|
||||
p_timeout tm = buf->tm;
|
||||
if (buffer_isempty(buf)) {
|
||||
size_t got;
|
||||
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
|
||||
buf->first = 0;
|
||||
buf->last = got;
|
||||
}
|
||||
*count = buf->last - buf->first;
|
||||
*data = buf->data + buf->first;
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef BUF_H
|
||||
#define BUF_H
|
||||
/*=========================================================================*\
|
||||
* Input/Output interface for Lua programs
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* Line patterns require buffering. Reading one character at a time involves
|
||||
* too many system calls and is very slow. This module implements the
|
||||
* LuaSocket interface for input/output on connected objects, as seen by
|
||||
* Lua programs.
|
||||
*
|
||||
* Input is buffered. Output is *not* buffered because there was no simple
|
||||
* way of making sure the buffered output data would ever be sent.
|
||||
*
|
||||
* The module is built on top of the I/O abstraction defined in io.h and the
|
||||
* timeout management is done with the timeout.h interface.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "luasocket_io.h"
|
||||
#include "timeout.h"
|
||||
|
||||
/* buffer size in bytes */
|
||||
#define BUF_SIZE 8192
|
||||
|
||||
/* buffer control structure */
|
||||
typedef struct t_buffer_ {
|
||||
double birthday; /* throttle support info: creation time, */
|
||||
size_t sent, received; /* bytes sent, and bytes received */
|
||||
p_io io; /* IO driver used for this buffer */
|
||||
p_timeout tm; /* timeout management for this buffer */
|
||||
size_t first, last; /* index of first and last bytes of stored data */
|
||||
char data[BUF_SIZE]; /* storage space for buffer data */
|
||||
} t_buffer;
|
||||
typedef t_buffer *p_buffer;
|
||||
|
||||
int buffer_open(lua_State *L);
|
||||
void buffer_init(p_buffer buf, p_io io, p_timeout tm);
|
||||
int buffer_meth_send(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_receive(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_getstats(lua_State *L, p_buffer buf);
|
||||
int buffer_meth_setstats(lua_State *L, p_buffer buf);
|
||||
int buffer_isempty(p_buffer buf);
|
||||
|
||||
#endif /* BUF_H */
|
|
@ -0,0 +1,30 @@
|
|||
/*=========================================================================*\
|
||||
* Input/Output abstraction
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "luasocket_io.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes C structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) {
|
||||
io->send = send;
|
||||
io->recv = recv;
|
||||
io->error = error;
|
||||
io->ctx = ctx;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* I/O error strings
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *io_strerror(int err) {
|
||||
switch (err) {
|
||||
case IO_DONE: return NULL;
|
||||
case IO_CLOSED: return "closed";
|
||||
case IO_TIMEOUT: return "timeout";
|
||||
default: return "unknown error";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef IO_H
|
||||
#define IO_H
|
||||
/*=========================================================================*\
|
||||
* Input/Output abstraction
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module defines the interface that LuaSocket expects from the
|
||||
* transport layer for streamed input/output. The idea is that if any
|
||||
* transport implements this interface, then the buffer.c functions
|
||||
* automatically work on it.
|
||||
*
|
||||
* The module socket.h implements this interface, and thus the module tcp.h
|
||||
* is very simple.
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include "lua.h"
|
||||
|
||||
#include "timeout.h"
|
||||
|
||||
/* IO error codes */
|
||||
enum {
|
||||
IO_DONE = 0, /* operation completed successfully */
|
||||
IO_TIMEOUT = -1, /* operation timed out */
|
||||
IO_CLOSED = -2, /* the connection has been closed */
|
||||
IO_UNKNOWN = -3
|
||||
};
|
||||
|
||||
/* interface to error message function */
|
||||
typedef const char *(*p_error) (
|
||||
void *ctx, /* context needed by send */
|
||||
int err /* error code */
|
||||
);
|
||||
|
||||
/* interface to send function */
|
||||
typedef int (*p_send) (
|
||||
void *ctx, /* context needed by send */
|
||||
const char *data, /* pointer to buffer with data to send */
|
||||
size_t count, /* number of bytes to send from buffer */
|
||||
size_t *sent, /* number of bytes sent uppon return */
|
||||
p_timeout tm /* timeout control */
|
||||
);
|
||||
|
||||
/* interface to recv function */
|
||||
typedef int (*p_recv) (
|
||||
void *ctx, /* context needed by recv */
|
||||
char *data, /* pointer to buffer where data will be writen */
|
||||
size_t count, /* number of bytes to receive into buffer */
|
||||
size_t *got, /* number of bytes received uppon return */
|
||||
p_timeout tm /* timeout control */
|
||||
);
|
||||
|
||||
/* IO driver definition */
|
||||
typedef struct t_io_ {
|
||||
void *ctx; /* context needed by send/recv */
|
||||
p_send send; /* send function pointer */
|
||||
p_recv recv; /* receive function pointer */
|
||||
p_error error; /* strerror function */
|
||||
} t_io;
|
||||
typedef t_io *p_io;
|
||||
|
||||
void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx);
|
||||
const char *io_strerror(int err);
|
||||
|
||||
#endif /* IO_H */
|
||||
|
|
@ -0,0 +1,723 @@
|
|||
/*=========================================================================*\
|
||||
* MIME support functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
|
||||
#include "compat-5.1.h"
|
||||
#endif
|
||||
|
||||
#include "mime.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Don't want to trust escape character constants
|
||||
\*=========================================================================*/
|
||||
typedef unsigned char UC;
|
||||
static const char CRLF[] = "\r\n";
|
||||
static const char EQCRLF[] = "=\r\n";
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static int mime_global_wrp(lua_State *L);
|
||||
static int mime_global_b64(lua_State *L);
|
||||
static int mime_global_unb64(lua_State *L);
|
||||
static int mime_global_qp(lua_State *L);
|
||||
static int mime_global_unqp(lua_State *L);
|
||||
static int mime_global_qpwrp(lua_State *L);
|
||||
static int mime_global_eol(lua_State *L);
|
||||
static int mime_global_dot(lua_State *L);
|
||||
|
||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer);
|
||||
static void b64setup(UC *base);
|
||||
static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
|
||||
static void qpsetup(UC *class, UC *unbase);
|
||||
static void qpquote(UC c, luaL_Buffer *buffer);
|
||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
|
||||
static size_t qpencode(UC c, UC *input, size_t size,
|
||||
const char *marker, luaL_Buffer *buffer);
|
||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
|
||||
|
||||
/* code support functions */
|
||||
static luaL_Reg func[] = {
|
||||
{ "dot", mime_global_dot },
|
||||
{ "b64", mime_global_b64 },
|
||||
{ "eol", mime_global_eol },
|
||||
{ "qp", mime_global_qp },
|
||||
{ "qpwrp", mime_global_qpwrp },
|
||||
{ "unb64", mime_global_unb64 },
|
||||
{ "unqp", mime_global_unqp },
|
||||
{ "wrp", mime_global_wrp },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Quoted-printable globals
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static UC qpclass[256];
|
||||
static UC qpbase[] = "0123456789ABCDEF";
|
||||
static UC qpunbase[256];
|
||||
enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Base64 globals
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const UC b64base[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static UC b64unbase[256];
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
MIME_API int luaopen_mime_core(lua_State *L)
|
||||
{
|
||||
luaL_openlib(L, "mime", func, 0);
|
||||
/* make version string available to scripts */
|
||||
lua_pushstring(L, "_VERSION");
|
||||
lua_pushstring(L, MIME_VERSION);
|
||||
lua_rawset(L, -3);
|
||||
/* initialize lookup tables */
|
||||
qpsetup(qpclass, qpunbase);
|
||||
b64setup(b64unbase);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementaly breaks a string into lines. The string can have CRLF breaks.
|
||||
* A, n = wrp(l, B, length)
|
||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||
* 'l' is how many bytes are left for the first line of B.
|
||||
* 'n' is the number of bytes left in the last line of A.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_wrp(lua_State *L)
|
||||
{
|
||||
size_t size = 0;
|
||||
int left = (int) luaL_checknumber(L, 1);
|
||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||
const UC *last = input + size;
|
||||
int length = (int) luaL_optnumber(L, 3, 76);
|
||||
luaL_Buffer buffer;
|
||||
/* end of input black-hole */
|
||||
if (!input) {
|
||||
/* if last line has not been terminated, add a line break */
|
||||
if (left < length) lua_pushstring(L, CRLF);
|
||||
/* otherwise, we are done */
|
||||
else lua_pushnil(L);
|
||||
lua_pushnumber(L, length);
|
||||
return 2;
|
||||
}
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last) {
|
||||
switch (*input) {
|
||||
case '\r':
|
||||
break;
|
||||
case '\n':
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
left = length;
|
||||
break;
|
||||
default:
|
||||
if (left <= 0) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, left);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Fill base64 decode map.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void b64setup(UC *unbase)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
|
||||
for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i;
|
||||
unbase['='] = 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Acumulates bytes in input buffer until 3 bytes are available.
|
||||
* Translate the 3 bytes into Base64 form and append to buffer.
|
||||
* Returns new number of bytes in buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64encode(UC c, UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
input[size++] = c;
|
||||
if (size == 3) {
|
||||
UC code[4];
|
||||
unsigned long value = 0;
|
||||
value += input[0]; value <<= 8;
|
||||
value += input[1]; value <<= 8;
|
||||
value += input[2];
|
||||
code[3] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
size = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Encodes the Base64 last 1 or 2 bytes and adds padding '='
|
||||
* Result, if any, is appended to buffer.
|
||||
* Returns 0.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64pad(const UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
unsigned long value = 0;
|
||||
UC code[4] = {'=', '=', '=', '='};
|
||||
switch (size) {
|
||||
case 1:
|
||||
value = input[0] << 4;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
break;
|
||||
case 2:
|
||||
value = input[0]; value <<= 8;
|
||||
value |= input[1]; value <<= 2;
|
||||
code[2] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[1] = b64base[value & 0x3f]; value >>= 6;
|
||||
code[0] = b64base[value];
|
||||
luaL_addlstring(buffer, (char *) code, 4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Acumulates bytes in input buffer until 4 bytes are available.
|
||||
* Translate the 4 bytes from Base64 form and append to buffer.
|
||||
* Returns new number of bytes in buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t b64decode(UC c, UC *input, size_t size,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
/* ignore invalid characters */
|
||||
if (b64unbase[c] > 64) return size;
|
||||
input[size++] = c;
|
||||
/* decode atom */
|
||||
if (size == 4) {
|
||||
UC decoded[3];
|
||||
int valid, value = 0;
|
||||
value = b64unbase[input[0]]; value <<= 6;
|
||||
value |= b64unbase[input[1]]; value <<= 6;
|
||||
value |= b64unbase[input[2]]; value <<= 6;
|
||||
value |= b64unbase[input[3]];
|
||||
decoded[2] = (UC) (value & 0xff); value >>= 8;
|
||||
decoded[1] = (UC) (value & 0xff); value >>= 8;
|
||||
decoded[0] = (UC) value;
|
||||
/* take care of paddding */
|
||||
valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
|
||||
luaL_addlstring(buffer, (char *) decoded, valid);
|
||||
return 0;
|
||||
/* need more data */
|
||||
} else return size;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally applies the Base64 transfer content encoding to a string
|
||||
* A, B = b64(C, D)
|
||||
* A is the encoded version of the largest prefix of C .. D that is
|
||||
* divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
|
||||
* The easiest thing would be to concatenate the two strings and
|
||||
* encode the result, but we can't afford that or Lua would dupplicate
|
||||
* every chunk we received.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_b64(lua_State *L)
|
||||
{
|
||||
UC atom[3];
|
||||
size_t isize = 0, asize = 0;
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of the input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = b64encode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
size_t osize = 0;
|
||||
asize = b64pad(atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
/* if the output is empty and the input is nil, return nil */
|
||||
lua_tolstring(L, -1, &osize);
|
||||
if (osize == 0) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process the second part */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = b64encode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally removes the Base64 transfer content encoding from a string
|
||||
* A, B = b64(C, D)
|
||||
* A is the encoded version of the largest prefix of C .. D that is
|
||||
* divisible by 4. B has the remaining bytes of C .. D, *without* encoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_unb64(lua_State *L)
|
||||
{
|
||||
UC atom[4];
|
||||
size_t isize = 0, asize = 0;
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of the input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = b64decode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second is nil, we are done */
|
||||
if (!input) {
|
||||
size_t osize = 0;
|
||||
luaL_pushresult(&buffer);
|
||||
/* if the output is empty and the input is nil, return nil */
|
||||
lua_tolstring(L, -1, &osize);
|
||||
if (osize == 0) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise, process the rest of the input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = b64decode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Quoted-printable encoding scheme
|
||||
* all (except CRLF in text) can be =XX
|
||||
* CLRL in not text must be =XX=XX
|
||||
* 33 through 60 inclusive can be plain
|
||||
* 62 through 126 inclusive can be plain
|
||||
* 9 and 32 can be plain, unless in the end of a line, where must be =XX
|
||||
* encoded lines must be no longer than 76 not counting CRLF
|
||||
* soft line-break are =CRLF
|
||||
* To encode one byte, we need to see the next two.
|
||||
* Worst case is when we see a space, and wonder if a CRLF is comming
|
||||
\*-------------------------------------------------------------------------*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Split quoted-printable characters into classes
|
||||
* Precompute reverse map for encoding
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void qpsetup(UC *cl, UC *unbase)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
|
||||
for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
|
||||
for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
|
||||
cl['\t'] = QP_IF_LAST;
|
||||
cl[' '] = QP_IF_LAST;
|
||||
cl['\r'] = QP_CR;
|
||||
for (i = 0; i < 256; i++) unbase[i] = 255;
|
||||
unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2;
|
||||
unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5;
|
||||
unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8;
|
||||
unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10;
|
||||
unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12;
|
||||
unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13;
|
||||
unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15;
|
||||
unbase['f'] = 15;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Output one character in form =XX
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static void qpquote(UC c, luaL_Buffer *buffer)
|
||||
{
|
||||
luaL_addchar(buffer, '=');
|
||||
luaL_addchar(buffer, qpbase[c >> 4]);
|
||||
luaL_addchar(buffer, qpbase[c & 0x0F]);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accumulate characters until we are sure about how to deal with them.
|
||||
* Once we are sure, output to the buffer, in the correct form.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qpencode(UC c, UC *input, size_t size,
|
||||
const char *marker, luaL_Buffer *buffer)
|
||||
{
|
||||
input[size++] = c;
|
||||
/* deal with all characters we can have */
|
||||
while (size > 0) {
|
||||
switch (qpclass[input[0]]) {
|
||||
/* might be the CR of a CRLF sequence */
|
||||
case QP_CR:
|
||||
if (size < 2) return size;
|
||||
if (input[1] == '\n') {
|
||||
luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else qpquote(input[0], buffer);
|
||||
break;
|
||||
/* might be a space and that has to be quoted if last in line */
|
||||
case QP_IF_LAST:
|
||||
if (size < 3) return size;
|
||||
/* if it is the last, quote it and we are done */
|
||||
if (input[1] == '\r' && input[2] == '\n') {
|
||||
qpquote(input[0], buffer);
|
||||
luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else luaL_addchar(buffer, input[0]);
|
||||
break;
|
||||
/* might have to be quoted always */
|
||||
case QP_QUOTED:
|
||||
qpquote(input[0], buffer);
|
||||
break;
|
||||
/* might never have to be quoted */
|
||||
default:
|
||||
luaL_addchar(buffer, input[0]);
|
||||
break;
|
||||
}
|
||||
input[0] = input[1]; input[1] = input[2];
|
||||
size--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Deal with the final characters
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]);
|
||||
else qpquote(input[i], buffer);
|
||||
}
|
||||
if (size > 0) luaL_addstring(buffer, EQCRLF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally converts a string to quoted-printable
|
||||
* A, B = qp(C, D, marker)
|
||||
* Marker is the text to be used to replace CRLF sequences found in A.
|
||||
* A is the encoded version of the largest prefix of C .. D that
|
||||
* can be encoded without doubts.
|
||||
* B has the remaining bytes of C .. D, *without* encoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_qp(lua_State *L)
|
||||
{
|
||||
|
||||
size_t asize = 0, isize = 0;
|
||||
UC atom[3];
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
const char *marker = luaL_optstring(L, 3, CRLF);
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 3);
|
||||
/* process first part of input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
asize = qppad(atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process rest of input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = qpencode(*input++, atom, asize, marker, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accumulate characters until we are sure about how to deal with them.
|
||||
* Once we are sure, output the to the buffer, in the correct form.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
|
||||
int d;
|
||||
input[size++] = c;
|
||||
/* deal with all characters we can deal */
|
||||
switch (input[0]) {
|
||||
/* if we have an escape character */
|
||||
case '=':
|
||||
if (size < 3) return size;
|
||||
/* eliminate soft line break */
|
||||
if (input[1] == '\r' && input[2] == '\n') return 0;
|
||||
/* decode quoted representation */
|
||||
c = qpunbase[input[1]]; d = qpunbase[input[2]];
|
||||
/* if it is an invalid, do not decode */
|
||||
if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3);
|
||||
else luaL_addchar(buffer, (char) ((c << 4) + d));
|
||||
return 0;
|
||||
case '\r':
|
||||
if (size < 2) return size;
|
||||
if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
|
||||
return 0;
|
||||
default:
|
||||
if (input[0] == '\t' || (input[0] > 31 && input[0] < 127))
|
||||
luaL_addchar(buffer, input[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally decodes a string in quoted-printable
|
||||
* A, B = qp(C, D)
|
||||
* A is the decoded version of the largest prefix of C .. D that
|
||||
* can be decoded without doubts.
|
||||
* B has the remaining bytes of C .. D, *without* decoding.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_unqp(lua_State *L)
|
||||
{
|
||||
size_t asize = 0, isize = 0;
|
||||
UC atom[3];
|
||||
const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
|
||||
const UC *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* make sure we don't confuse buffer stuff with arguments */
|
||||
lua_settop(L, 2);
|
||||
/* process first part of input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
asize = qpdecode(*input++, atom, asize, &buffer);
|
||||
input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
|
||||
/* if second part is nil, we are done */
|
||||
if (!input) {
|
||||
luaL_pushresult(&buffer);
|
||||
if (!(*lua_tostring(L, -1))) lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
return 2;
|
||||
}
|
||||
/* otherwise process rest of input */
|
||||
last = input + isize;
|
||||
while (input < last)
|
||||
asize = qpdecode(*input++, atom, asize, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushlstring(L, (char *) atom, asize);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally breaks a quoted-printed string into lines
|
||||
* A, n = qpwrp(l, B, length)
|
||||
* A is a copy of B, broken into lines of at most 'length' bytes.
|
||||
* 'l' is how many bytes are left for the first line of B.
|
||||
* 'n' is the number of bytes left in the last line of A.
|
||||
* There are two complications: lines can't be broken in the middle
|
||||
* of an encoded =XX, and there might be line breaks already
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_qpwrp(lua_State *L)
|
||||
{
|
||||
size_t size = 0;
|
||||
int left = (int) luaL_checknumber(L, 1);
|
||||
const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
|
||||
const UC *last = input + size;
|
||||
int length = (int) luaL_optnumber(L, 3, 76);
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
if (left < length) lua_pushstring(L, EQCRLF);
|
||||
else lua_pushnil(L);
|
||||
lua_pushnumber(L, length);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last) {
|
||||
switch (*input) {
|
||||
case '\r':
|
||||
break;
|
||||
case '\n':
|
||||
left = length;
|
||||
luaL_addstring(&buffer, CRLF);
|
||||
break;
|
||||
case '=':
|
||||
if (left <= 3) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, EQCRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
default:
|
||||
if (left <= 1) {
|
||||
left = length;
|
||||
luaL_addstring(&buffer, EQCRLF);
|
||||
}
|
||||
luaL_addchar(&buffer, *input);
|
||||
left--;
|
||||
break;
|
||||
}
|
||||
input++;
|
||||
}
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, left);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Here is what we do: \n, and \r are considered candidates for line
|
||||
* break. We issue *one* new line marker if any of them is seen alone, or
|
||||
* followed by a different one. That is, \n\n and \r\r will issue two
|
||||
* end of line markers each, but \r\n, \n\r etc will only issue *one*
|
||||
* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as
|
||||
* probably other more obscure conventions.
|
||||
*
|
||||
* c is the current character being processed
|
||||
* last is the previous character
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define eolcandidate(c) (c == '\r' || c == '\n')
|
||||
static int eolprocess(int c, int last, const char *marker,
|
||||
luaL_Buffer *buffer)
|
||||
{
|
||||
if (eolcandidate(c)) {
|
||||
if (eolcandidate(last)) {
|
||||
if (c == last) luaL_addstring(buffer, marker);
|
||||
return 0;
|
||||
} else {
|
||||
luaL_addstring(buffer, marker);
|
||||
return c;
|
||||
}
|
||||
} else {
|
||||
luaL_addchar(buffer, (char) c);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Converts a string to uniform EOL convention.
|
||||
* A, n = eol(o, B, marker)
|
||||
* A is the converted version of the largest prefix of B that can be
|
||||
* converted unambiguously. 'o' is the context returned by the previous
|
||||
* call. 'n' is the new context.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_eol(lua_State *L)
|
||||
{
|
||||
int ctx = luaL_checkint(L, 1);
|
||||
size_t isize = 0;
|
||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||
const char *last = input + isize;
|
||||
const char *marker = luaL_optstring(L, 3, CRLF);
|
||||
luaL_Buffer buffer;
|
||||
luaL_buffinit(L, &buffer);
|
||||
/* end of input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnumber(L, 0);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
while (input < last)
|
||||
ctx = eolprocess(*input++, ctx, marker, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, ctx);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Takes one byte and stuff it if needed.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static size_t dot(int c, size_t state, luaL_Buffer *buffer)
|
||||
{
|
||||
luaL_addchar(buffer, (char) c);
|
||||
switch (c) {
|
||||
case '\r':
|
||||
return 1;
|
||||
case '\n':
|
||||
return (state == 1)? 2: 0;
|
||||
case '.':
|
||||
if (state == 2)
|
||||
luaL_addchar(buffer, '.');
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Incrementally applies smtp stuffing to a string
|
||||
* A, n = dot(l, D)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int mime_global_dot(lua_State *L)
|
||||
{
|
||||
size_t isize = 0, state = (size_t) luaL_checknumber(L, 1);
|
||||
const char *input = luaL_optlstring(L, 2, NULL, &isize);
|
||||
const char *last = input + isize;
|
||||
luaL_Buffer buffer;
|
||||
/* end-of-input blackhole */
|
||||
if (!input) {
|
||||
lua_pushnil(L);
|
||||
lua_pushnumber(L, 2);
|
||||
return 2;
|
||||
}
|
||||
/* process all input */
|
||||
luaL_buffinit(L, &buffer);
|
||||
while (input < last)
|
||||
state = dot(*input++, state, &buffer);
|
||||
luaL_pushresult(&buffer);
|
||||
lua_pushnumber(L, (lua_Number) state);
|
||||
return 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef MIME_H
|
||||
#define MIME_H
|
||||
/*=========================================================================*\
|
||||
* Core MIME support
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module provides functions to implement transfer content encodings
|
||||
* and formatting conforming to RFC 2045. It is used by mime.lua, which
|
||||
* provide a higher level interface to this functionality.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Current MIME library version
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define MIME_VERSION "MIME 1.0.3-rc1"
|
||||
#define MIME_COPYRIGHT "Copyright (C) 2004-2012 Diego Nehab"
|
||||
#define MIME_AUTHORS "Diego Nehab"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* This macro prefixes all exported API functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef MIME_API
|
||||
#define MIME_API extern
|
||||
#endif
|
||||
|
||||
MIME_API int luaopen_mime_core(lua_State *L);
|
||||
|
||||
#endif /* MIME_H */
|
|
@ -0,0 +1,262 @@
|
|||
/*=========================================================================*\
|
||||
* Common option interface
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "options.h"
|
||||
#include "inet.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions prototypes
|
||||
\*=========================================================================*/
|
||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
|
||||
static int opt_set(lua_State *L, p_socket ps, int level, int name,
|
||||
void *val, int len);
|
||||
static int opt_get(lua_State *L, p_socket ps, int level, int name,
|
||||
void *val, int* len);
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Calls appropriate option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unsupported option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
return opt->func(L, ps);
|
||||
}
|
||||
|
||||
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unsupported option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
return opt->func(L, ps);
|
||||
}
|
||||
|
||||
/* enables reuse of local address */
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
/* enables reuse of local port */
|
||||
int opt_set_reuseport(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||
}
|
||||
|
||||
int opt_get_reuseport(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
|
||||
}
|
||||
|
||||
/* disables the Naggle algorithm */
|
||||
int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
int opt_set_keepalive(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
int opt_get_keepalive(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
int opt_set_dontroute(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
||||
}
|
||||
|
||||
int opt_set_broadcast(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
int opt_set_linger(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct linger li; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "on");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isboolean(L, -1))
|
||||
luaL_argerror(L, 3, "boolean 'on' field expected");
|
||||
li.l_onoff = (u_short) lua_toboolean(L, -1);
|
||||
lua_pushstring(L, "timeout");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isnumber(L, -1))
|
||||
luaL_argerror(L, 3, "number 'timeout' field expected");
|
||||
li.l_linger = (u_short) lua_tonumber(L, -1);
|
||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
|
||||
}
|
||||
|
||||
int opt_get_linger(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct linger li; /* obj, name */
|
||||
int len = sizeof(li);
|
||||
int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len);
|
||||
if (err)
|
||||
return err;
|
||||
lua_newtable(L);
|
||||
lua_pushboolean(L, li.l_onoff);
|
||||
lua_setfield(L, -2, "on");
|
||||
lua_pushinteger(L, li.l_linger);
|
||||
lua_setfield(L, -2, "timeout");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps)
|
||||
{
|
||||
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
|
||||
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
|
||||
{
|
||||
const char *address = luaL_checkstring(L, 3); /* obj, name, ip */
|
||||
struct in_addr val;
|
||||
val.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(address, "*") && !inet_aton(address, &val))
|
||||
luaL_argerror(L, 3, "ip expected");
|
||||
return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
(char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
int opt_get_ip_multicast_if(lua_State *L, p_socket ps)
|
||||
{
|
||||
struct in_addr val;
|
||||
socklen_t len = sizeof(val);
|
||||
if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "getsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, inet_ntoa(val));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int opt_set_ip_add_membership(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
||||
}
|
||||
|
||||
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
||||
}
|
||||
|
||||
int opt_set_ip6_v6only(lua_State *L, p_socket ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Auxiliar functions
|
||||
\*=========================================================================*/
|
||||
static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
struct ip_mreq val; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "multiaddr");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
||||
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
||||
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||
lua_pushstring(L, "interface");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'interface' field expected");
|
||||
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(lua_tostring(L, -1), "*") &&
|
||||
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
||||
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
static
|
||||
int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
|
||||
{
|
||||
socklen_t socklen = *len;
|
||||
if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "getsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
*len = socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
|
||||
{
|
||||
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
int val = 0;
|
||||
int len = sizeof(val);
|
||||
int err = opt_get(L, ps, level, name, (char *) &val, &len);
|
||||
if (err)
|
||||
return err;
|
||||
lua_pushboolean(L, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
|
||||
{
|
||||
int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
/*=========================================================================*\
|
||||
* Common option interface
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module provides a common interface to socket options, used mainly by
|
||||
* modules UDP and TCP.
|
||||
\*=========================================================================*/
|
||||
|
||||
#include "lua.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* option registry */
|
||||
typedef struct t_opt {
|
||||
const char *name;
|
||||
int (*func)(lua_State *L, p_socket ps);
|
||||
} t_opt;
|
||||
typedef t_opt *p_opt;
|
||||
|
||||
/* supported options for setoption */
|
||||
int opt_set_dontroute(lua_State *L, p_socket ps);
|
||||
int opt_set_broadcast(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
|
||||
int opt_set_keepalive(lua_State *L, p_socket ps);
|
||||
int opt_set_linger(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_set_reuseport(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_if(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_add_membership(lua_State *L, p_socket ps);
|
||||
int opt_set_ip_drop_membersip(lua_State *L, p_socket ps);
|
||||
int opt_set_ip6_v6only(lua_State *L, p_socket ps);
|
||||
|
||||
/* supported options for getoption */
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
|
||||
int opt_get_keepalive(lua_State *L, p_socket ps);
|
||||
int opt_get_linger(lua_State *L, p_socket ps);
|
||||
int opt_get_reuseaddr(lua_State *L, p_socket ps);
|
||||
int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
|
||||
int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
|
||||
|
||||
/* invokes the appropriate option handler */
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
|
||||
int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,216 @@
|
|||
/*=========================================================================*\
|
||||
* Select implementation
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "socket.h"
|
||||
#include "timeout.h"
|
||||
#include "select.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes.
|
||||
\*=========================================================================*/
|
||||
static t_socket getfd(lua_State *L);
|
||||
static int dirty(lua_State *L);
|
||||
static void collect_fd(lua_State *L, int tab, int itab,
|
||||
fd_set *set, t_socket *max_fd);
|
||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
|
||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||
int itab, int tab, int start);
|
||||
static void make_assoc(lua_State *L, int tab);
|
||||
static int global_select(lua_State *L);
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"select", global_select},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int select_open(lua_State *L) {
|
||||
lua_pushstring(L, "_SETSIZE");
|
||||
lua_pushnumber(L, FD_SETSIZE);
|
||||
lua_rawset(L, -3);
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Global Lua functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for a set of sockets until a condition is met or timeout.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_select(lua_State *L) {
|
||||
int rtab, wtab, itab, ret, ndirty;
|
||||
t_socket max_fd = SOCKET_INVALID;
|
||||
fd_set rset, wset;
|
||||
t_timeout tm;
|
||||
double t = luaL_optnumber(L, 3, -1);
|
||||
FD_ZERO(&rset); FD_ZERO(&wset);
|
||||
lua_settop(L, 3);
|
||||
lua_newtable(L); itab = lua_gettop(L);
|
||||
lua_newtable(L); rtab = lua_gettop(L);
|
||||
lua_newtable(L); wtab = lua_gettop(L);
|
||||
collect_fd(L, 1, itab, &rset, &max_fd);
|
||||
collect_fd(L, 2, itab, &wset, &max_fd);
|
||||
ndirty = check_dirty(L, 1, rtab, &rset);
|
||||
t = ndirty > 0? 0.0: t;
|
||||
timeout_init(&tm, t, -1);
|
||||
timeout_markstart(&tm);
|
||||
ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
|
||||
if (ret > 0 || ndirty > 0) {
|
||||
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
||||
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
|
||||
make_assoc(L, rtab);
|
||||
make_assoc(L, wtab);
|
||||
return 2;
|
||||
} else if (ret == 0) {
|
||||
lua_pushstring(L, "timeout");
|
||||
return 3;
|
||||
} else {
|
||||
luaL_error(L, "select failed");
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal functions
|
||||
\*=========================================================================*/
|
||||
static t_socket getfd(lua_State *L) {
|
||||
t_socket fd = SOCKET_INVALID;
|
||||
lua_pushstring(L, "getfd");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
if (lua_isnumber(L, -1)) {
|
||||
double numfd = lua_tonumber(L, -1);
|
||||
fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int dirty(lua_State *L) {
|
||||
int is = 0;
|
||||
lua_pushstring(L, "dirty");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
is = lua_toboolean(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
return is;
|
||||
}
|
||||
|
||||
static void collect_fd(lua_State *L, int tab, int itab,
|
||||
fd_set *set, t_socket *max_fd) {
|
||||
int i = 1, n = 0;
|
||||
/* nil is the same as an empty table */
|
||||
if (lua_isnil(L, tab)) return;
|
||||
/* otherwise we need it to be a table */
|
||||
luaL_checktype(L, tab, LUA_TTABLE);
|
||||
for ( ;; ) {
|
||||
t_socket fd;
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
/* getfd figures out if this is a socket */
|
||||
fd = getfd(L);
|
||||
if (fd != SOCKET_INVALID) {
|
||||
/* make sure we don't overflow the fd_set */
|
||||
#ifdef _WIN32
|
||||
if (n >= FD_SETSIZE)
|
||||
luaL_argerror(L, tab, "too many sockets");
|
||||
#else
|
||||
if (fd >= FD_SETSIZE)
|
||||
luaL_argerror(L, tab, "descriptor too large for set size");
|
||||
#endif
|
||||
FD_SET(fd, set);
|
||||
n++;
|
||||
/* keep track of the largest descriptor so far */
|
||||
if (*max_fd == SOCKET_INVALID || *max_fd < fd)
|
||||
*max_fd = fd;
|
||||
/* make sure we can map back from descriptor to the object */
|
||||
lua_pushnumber(L, (lua_Number) fd);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, itab);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
|
||||
int ndirty = 0, i = 1;
|
||||
if (lua_isnil(L, tab))
|
||||
return 0;
|
||||
for ( ;; ) {
|
||||
t_socket fd;
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
fd = getfd(L);
|
||||
if (fd != SOCKET_INVALID && dirty(L)) {
|
||||
lua_pushnumber(L, ++ndirty);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, dtab);
|
||||
FD_CLR(fd, set);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
i = i + 1;
|
||||
}
|
||||
return ndirty;
|
||||
}
|
||||
|
||||
static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
|
||||
int itab, int tab, int start) {
|
||||
t_socket fd;
|
||||
for (fd = 0; fd < max_fd; fd++) {
|
||||
if (FD_ISSET(fd, set)) {
|
||||
lua_pushnumber(L, ++start);
|
||||
lua_pushnumber(L, (lua_Number) fd);
|
||||
lua_gettable(L, itab);
|
||||
lua_settable(L, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void make_assoc(lua_State *L, int tab) {
|
||||
int i = 1, atab;
|
||||
lua_newtable(L); atab = lua_gettop(L);
|
||||
for ( ;; ) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_gettable(L, tab);
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_pushnumber(L, i);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, atab);
|
||||
lua_pushnumber(L, i);
|
||||
lua_settable(L, atab);
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
break;
|
||||
}
|
||||
i = i+1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef SELECT_H
|
||||
#define SELECT_H
|
||||
/*=========================================================================*\
|
||||
* Select implementation
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* Each object that can be passed to the select function has to export
|
||||
* method getfd() which returns the descriptor to be passed to the
|
||||
* underlying select function. Another method, dirty(), should return
|
||||
* true if there is data ready for reading (required for buffered input).
|
||||
\*=========================================================================*/
|
||||
|
||||
int select_open(lua_State *L);
|
||||
|
||||
#endif /* SELECT_H */
|
|
@ -0,0 +1,183 @@
|
|||
/*=========================================================================*\
|
||||
* Serial stream
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "options.h"
|
||||
#include "unix.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
/*
|
||||
Reuses userdata definition from unix.h, since it is useful for all
|
||||
stream-like objects.
|
||||
|
||||
If we stored the serial path for use in error messages or userdata
|
||||
printing, we might need our own userdata definition.
|
||||
|
||||
Group usage is semi-inherited from unix.c, but unnecessary since we
|
||||
have only one object type.
|
||||
*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
|
||||
/* serial object methods */
|
||||
static luaL_Reg serial_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"close", meth_close},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfd", meth_getfd},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"settimeout", meth_settimeout},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* our socket creation function */
|
||||
static luaL_Reg func[] = {
|
||||
{"serial", global_create},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "serial{client}", serial_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "serial{client}", "serial{any}");
|
||||
/* make sure the function ends up in the package table */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
/* return the function instead of the 'socket' table */
|
||||
lua_pushstring(L, "serial");
|
||||
lua_gettable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_send(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_receive(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_getstats(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1);
|
||||
return buffer_meth_setstats(L, &un->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
lua_pushnumber(L, (int) un->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
socket_destroy(&un->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
|
||||
return timeout_meth_settimeout(L, &un->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a serial object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_create(lua_State *L) {
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
/* allocate unix object */
|
||||
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
|
||||
/* open serial device */
|
||||
t_socket sock = open(path, O_NOCTTY|O_RDWR);
|
||||
|
||||
/*printf("open %s on %d\n", path, sock);*/
|
||||
|
||||
if (sock < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(errno));
|
||||
lua_pushnumber(L, errno);
|
||||
return 3;
|
||||
}
|
||||
/* set its type as client object */
|
||||
auxiliar_setclass(L, "serial{client}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
un->sock = sock;
|
||||
io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
|
||||
(p_error) socket_ioerror, &un->sock);
|
||||
timeout_init(&un->tm, -1, -1);
|
||||
buffer_init(&un->buf, &un->io, &un->tm);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* BSD Sockets and WinSock are similar, but there are a few irritating
|
||||
* differences. Also, not all *nix platforms behave the same. This module
|
||||
* (and the associated usocket.h and wsocket.h) factor these differences and
|
||||
* creates a interface compatible with the io.h module.
|
||||
\*=========================================================================*/
|
||||
#include "luasocket_io.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Platform specific compatibilization
|
||||
\*=========================================================================*/
|
||||
#ifdef _WIN32
|
||||
#include "wsocket.h"
|
||||
#else
|
||||
#include "usocket.h"
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* The connect and accept functions accept a timeout and their
|
||||
* implementations are somewhat complicated. We chose to move
|
||||
* the timeout control into this module for these functions in
|
||||
* order to simplify the modules that use them.
|
||||
\*=========================================================================*/
|
||||
#include "timeout.h"
|
||||
|
||||
/* we are lazy... */
|
||||
typedef struct sockaddr SA;
|
||||
|
||||
/*=========================================================================*\
|
||||
* Functions bellow implement a comfortable platform independent
|
||||
* interface to sockets
|
||||
\*=========================================================================*/
|
||||
int socket_open(void);
|
||||
int socket_close(void);
|
||||
void socket_destroy(p_socket ps);
|
||||
void socket_shutdown(p_socket ps, int how);
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count,
|
||||
size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm);
|
||||
|
||||
void socket_setnonblocking(p_socket ps);
|
||||
void socket_setblocking(p_socket ps);
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm);
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm);
|
||||
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm);
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol);
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t addr_len);
|
||||
int socket_listen(p_socket ps, int backlog);
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr,
|
||||
socklen_t *addr_len, p_timeout tm);
|
||||
|
||||
const char *socket_hoststrerror(int err);
|
||||
const char *socket_gaistrerror(int err);
|
||||
const char *socket_strerror(int err);
|
||||
|
||||
/* these are perfect to use with the io abstraction module
|
||||
and the buffered input module */
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm);
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||
int socket_write(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm);
|
||||
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm);
|
||||
const char *socket_ioerror(p_socket ps, int err);
|
||||
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp);
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp);
|
||||
|
||||
#endif /* SOCKET_H */
|
|
@ -0,0 +1 @@
|
|||
e79358cdf4b02c66a50e684543e505002bdbcc91
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/* socket_scripts.h */
|
||||
|
||||
#ifndef __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
|
||||
#define __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_
|
||||
|
||||
#if __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
void luaopen_socket_scripts(lua_State* L);
|
||||
|
||||
/*
|
||||
int luaopen_lua_m_ltn12(lua_State* L);
|
||||
int luaopen_lua_m_mime(lua_State* L);
|
||||
int luaopen_lua_m_socket_ftp(lua_State* L);
|
||||
int luaopen_lua_m_socket_headers(lua_State* L);
|
||||
int luaopen_lua_m_socket_http(lua_State* L);
|
||||
int luaopen_lua_m_socket_mbox(lua_State* L);
|
||||
int luaopen_lua_m_socket_smtp(lua_State* L);
|
||||
int luaopen_lua_m_socket_tp(lua_State* L);
|
||||
int luaopen_lua_m_socket_url(lua_State* L);
|
||||
int luaopen_lua_m_socket(lua_State* L);
|
||||
*/
|
||||
|
||||
#if __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ */
|
|
@ -0,0 +1,475 @@
|
|||
/*=========================================================================*\
|
||||
* TCP object
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int global_create6(lua_State *L);
|
||||
static int global_connect(lua_State *L);
|
||||
static int meth_connect(lua_State *L);
|
||||
static int meth_listen(lua_State *L);
|
||||
static int meth_getfamily(lua_State *L);
|
||||
static int meth_bind(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
static int meth_getsockname(lua_State *L);
|
||||
static int meth_getpeername(lua_State *L);
|
||||
static int meth_shutdown(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_accept(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_getoption(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
|
||||
/* tcp object methods */
|
||||
static luaL_Reg tcp_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"accept", meth_accept},
|
||||
{"bind", meth_bind},
|
||||
{"close", meth_close},
|
||||
{"connect", meth_connect},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfamily", meth_getfamily},
|
||||
{"getfd", meth_getfd},
|
||||
{"getoption", meth_getoption},
|
||||
{"getpeername", meth_getpeername},
|
||||
{"getsockname", meth_getsockname},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"listen", meth_listen},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"setpeername", meth_connect},
|
||||
{"setsockname", meth_bind},
|
||||
{"settimeout", meth_settimeout},
|
||||
{"shutdown", meth_shutdown},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket option handlers */
|
||||
static t_opt optget[] = {
|
||||
{"keepalive", opt_get_keepalive},
|
||||
{"reuseaddr", opt_get_reuseaddr},
|
||||
{"tcp-nodelay", opt_get_tcp_nodelay},
|
||||
{"linger", opt_get_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static t_opt optset[] = {
|
||||
{"keepalive", opt_set_keepalive},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"tcp-nodelay", opt_set_tcp_nodelay},
|
||||
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||
{"linger", opt_set_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"tcp", global_create},
|
||||
{"tcp6", global_create6},
|
||||
{"connect", global_connect},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tcp_open(lua_State *L)
|
||||
{
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "tcp{master}", tcp_methods);
|
||||
auxiliar_newclass(L, "tcp{client}", tcp_methods);
|
||||
auxiliar_newclass(L, "tcp{server}", tcp_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "tcp{master}", "tcp{any}");
|
||||
auxiliar_add2group(L, "tcp{client}", "tcp{any}");
|
||||
auxiliar_add2group(L, "tcp{server}", "tcp{any}");
|
||||
/* define library functions */
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_send(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_receive(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_getstats(L, &tcp->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
return buffer_meth_setstats(L, &tcp->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getoption(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return opt_meth_getoption(L, optget, &tcp->sock);
|
||||
}
|
||||
|
||||
static int meth_setoption(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &tcp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
lua_pushnumber(L, (int) tcp->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
tcp->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&tcp->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for and returns a client object attempting connection to the
|
||||
* server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_accept(lua_State *L)
|
||||
{
|
||||
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
|
||||
p_timeout tm = timeout_markstart(&server->tm);
|
||||
t_socket sock;
|
||||
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
|
||||
/* if successful, push client socket */
|
||||
if (err == NULL) {
|
||||
p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
auxiliar_setclass(L, "tcp{client}", -1);
|
||||
/* initialize structure fields */
|
||||
memset(clnt, 0, sizeof(t_tcp));
|
||||
socket_setnonblocking(&sock);
|
||||
clnt->sock = sock;
|
||||
io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &clnt->sock);
|
||||
timeout_init(&clnt->tm, -1, -1);
|
||||
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||
clnt->family = server->family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds an object to an address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_bind(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
const char *err;
|
||||
struct addrinfo bindhints;
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_STREAM;
|
||||
bindhints.ai_family = tcp->family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
address = strcmp(address, "*")? address: NULL;
|
||||
err = inet_trybind(&tcp->sock, address, port, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master tcp object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_connect(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
struct addrinfo connecthints;
|
||||
const char *err;
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_STREAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = tcp->family;
|
||||
timeout_markstart(&tcp->tm);
|
||||
err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints);
|
||||
/* have to set the class even if it failed due to non-blocking connects */
|
||||
auxiliar_setclass(L, "tcp{client}", 1);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
socket_destroy(&tcp->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns family as string
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfamily(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
if (tcp->family == PF_INET6) {
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushliteral(L, "inet4");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Puts the sockt in listen mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_listen(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
|
||||
int backlog = (int) luaL_optnumber(L, 2, 32);
|
||||
int err = socket_listen(&tcp->sock, backlog);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a server object */
|
||||
auxiliar_setclass(L, "tcp{server}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Shuts the connection down partially
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_shutdown(lua_State *L)
|
||||
{
|
||||
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
|
||||
static const char* methods[] = { "receive", "send", "both", NULL };
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1);
|
||||
int how = luaL_checkoption(L, 2, "both", methods);
|
||||
socket_shutdown(&tcp->sock, how);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call inet methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getpeername(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return inet_meth_getpeername(L, &tcp->sock, tcp->family);
|
||||
}
|
||||
|
||||
static int meth_getsockname(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return inet_meth_getsockname(L, &tcp->sock, tcp->family);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
|
||||
return timeout_meth_settimeout(L, &tcp->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master tcp object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int tcp_create(lua_State *L, int family) {
|
||||
t_socket sock;
|
||||
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
|
||||
/* try to allocate a system socket */
|
||||
if (!err) {
|
||||
/* allocate tcp object */
|
||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
memset(tcp, 0, sizeof(t_tcp));
|
||||
/* set its type as master object */
|
||||
auxiliar_setclass(L, "tcp{master}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
if (family == PF_INET6) {
|
||||
int yes = 1;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(void *)&yes, sizeof(yes));
|
||||
}
|
||||
tcp->sock = sock;
|
||||
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &tcp->sock);
|
||||
timeout_init(&tcp->tm, -1, -1);
|
||||
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||
tcp->family = family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int global_create(lua_State *L) {
|
||||
return tcp_create(L, AF_INET);
|
||||
}
|
||||
|
||||
static int global_create6(lua_State *L) {
|
||||
return tcp_create(L, AF_INET6);
|
||||
}
|
||||
|
||||
static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
|
||||
struct addrinfo *connecthints, p_tcp tcp) {
|
||||
struct addrinfo *iterator = NULL, *resolved = NULL;
|
||||
const char *err = NULL;
|
||||
/* try resolving */
|
||||
err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
|
||||
connecthints, &resolved));
|
||||
if (err != NULL) {
|
||||
if (resolved) freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
/* iterate over all returned addresses trying to connect */
|
||||
for (iterator = resolved; iterator; iterator = iterator->ai_next) {
|
||||
p_timeout tm = timeout_markstart(&tcp->tm);
|
||||
/* create new socket if one wasn't created by the bind stage */
|
||||
if (tcp->sock == SOCKET_INVALID) {
|
||||
err = socket_strerror(socket_create(&tcp->sock,
|
||||
iterator->ai_family, iterator->ai_socktype,
|
||||
iterator->ai_protocol));
|
||||
if (err != NULL) {
|
||||
freeaddrinfo(resolved);
|
||||
return err;
|
||||
}
|
||||
tcp->family = iterator->ai_family;
|
||||
/* all sockets initially non-blocking */
|
||||
socket_setnonblocking(&tcp->sock);
|
||||
}
|
||||
/* finally try connecting to remote address */
|
||||
err = socket_strerror(socket_connect(&tcp->sock,
|
||||
(SA *) iterator->ai_addr,
|
||||
(socklen_t) iterator->ai_addrlen, tm));
|
||||
/* if success, break out of loop */
|
||||
if (err == NULL) break;
|
||||
}
|
||||
|
||||
freeaddrinfo(resolved);
|
||||
/* here, if err is set, we failed */
|
||||
return err;
|
||||
}
|
||||
|
||||
static int global_connect(lua_State *L) {
|
||||
const char *remoteaddr = luaL_checkstring(L, 1);
|
||||
const char *remoteserv = luaL_checkstring(L, 2);
|
||||
const char *localaddr = luaL_optstring(L, 3, NULL);
|
||||
const char *localserv = luaL_optstring(L, 4, "0");
|
||||
int family = inet_optfamily(L, 5, "unspec");
|
||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||
struct addrinfo bindhints, connecthints;
|
||||
const char *err = NULL;
|
||||
/* initialize tcp structure */
|
||||
memset(tcp, 0, sizeof(t_tcp));
|
||||
io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &tcp->sock);
|
||||
timeout_init(&tcp->tm, -1, -1);
|
||||
buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||
tcp->sock = SOCKET_INVALID;
|
||||
/* allow user to pick local address and port */
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_STREAM;
|
||||
bindhints.ai_family = family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
if (localaddr) {
|
||||
err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
tcp->family = bindhints.ai_family;
|
||||
}
|
||||
/* try to connect to remote address and port */
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_STREAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = bindhints.ai_family;
|
||||
err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp);
|
||||
if (err) {
|
||||
socket_destroy(&tcp->sock);
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
auxiliar_setclass(L, "tcp{client}", -1);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef TCP_H
|
||||
#define TCP_H
|
||||
/*=========================================================================*\
|
||||
* TCP object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The tcp.h module is basicly a glue that puts together modules buffer.h,
|
||||
* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET,
|
||||
* SOCK_STREAM) support.
|
||||
*
|
||||
* Three classes are defined: master, client and server. The master class is
|
||||
* a newly created tcp object, that has not been bound or connected. Server
|
||||
* objects are tcp objects bound to some local address. Client objects are
|
||||
* tcp objects either connected to some address or returned by the accept
|
||||
* method of a server object.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "luasocket_buffer.h"
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
typedef struct t_tcp_ {
|
||||
t_socket sock;
|
||||
t_io io;
|
||||
t_buffer buf;
|
||||
t_timeout tm;
|
||||
int family;
|
||||
} t_tcp;
|
||||
|
||||
typedef t_tcp *p_tcp;
|
||||
|
||||
int tcp_open(lua_State *L);
|
||||
|
||||
#endif /* TCP_H */
|
|
@ -0,0 +1,217 @@
|
|||
/*=========================================================================*\
|
||||
* Timeout management functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "timeout.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int timeout_lua_gettime(lua_State *L);
|
||||
static int timeout_lua_sleep(lua_State *L);
|
||||
|
||||
static luaL_Reg func[] = {
|
||||
{ "gettime", timeout_lua_gettime },
|
||||
{ "sleep", timeout_lua_sleep },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions.
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initialize structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void timeout_init(p_timeout tm, double block, double total) {
|
||||
tm->block = block;
|
||||
tm->total = total;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines how much time we have left for the next system call,
|
||||
* if the previous call was successful
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_get(p_timeout tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
return tm->block;
|
||||
} else {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns time since start of operation
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* start field of structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_getstart(p_timeout tm) {
|
||||
return tm->start;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Determines how much time we have left for the next system call,
|
||||
* if the previous call was a failure
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
double timeout_getretry(p_timeout tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
double t = tm->block - timeout_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else {
|
||||
double t = tm->total - timeout_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Marks the operation start time in structure
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
p_timeout timeout_markstart(p_timeout tm) {
|
||||
tm->start = timeout_gettime();
|
||||
return tm;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Gets time in s, relative to January 1, 1970 (UTC)
|
||||
* Returns
|
||||
* time in s.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
double timeout_gettime(void) {
|
||||
FILETIME ft;
|
||||
double t;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
/* Windows file time (time since January 1, 1601 (UTC)) */
|
||||
t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
|
||||
/* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */
|
||||
return (t - 11644473600.0);
|
||||
}
|
||||
#else
|
||||
double timeout_gettime(void) {
|
||||
struct timeval v;
|
||||
gettimeofday(&v, (struct timezone *) NULL);
|
||||
/* Unix Epoch time (time since January 1, 1970 (UTC)) */
|
||||
return v.tv_sec + v.tv_usec/1.0e6;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int timeout_open(lua_State *L) {
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sets timeout values for IO operations
|
||||
* Lua Input: base, time [, mode]
|
||||
* time: time out value in seconds
|
||||
* mode: "b" for block timeout, "t" for total timeout. (default: b)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
|
||||
double t = luaL_optnumber(L, 2, -1);
|
||||
const char *mode = luaL_optstring(L, 3, "b");
|
||||
switch (*mode) {
|
||||
case 'b':
|
||||
tm->block = t;
|
||||
break;
|
||||
case 'r': case 't':
|
||||
tm->total = t;
|
||||
break;
|
||||
default:
|
||||
luaL_argcheck(L, 0, 3, "invalid timeout mode");
|
||||
break;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Test support functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns the time the system has been up, in secconds.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int timeout_lua_gettime(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, timeout_gettime());
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sleep for n seconds.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
int timeout_lua_sleep(lua_State *L)
|
||||
{
|
||||
double n = luaL_checknumber(L, 1);
|
||||
if (n < 0.0) n = 0.0;
|
||||
if (n < DBL_MAX/1000.0) n *= 1000.0;
|
||||
if (n > INT_MAX) n = INT_MAX;
|
||||
Sleep((int)n);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int timeout_lua_sleep(lua_State *L)
|
||||
{
|
||||
double n = luaL_checknumber(L, 1);
|
||||
struct timespec t, r;
|
||||
if (n < 0.0) n = 0.0;
|
||||
if (n > INT_MAX) n = INT_MAX;
|
||||
t.tv_sec = (int) n;
|
||||
n -= t.tv_sec;
|
||||
t.tv_nsec = (int) (n * 1000000000);
|
||||
if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999;
|
||||
while (nanosleep(&t, &r) != 0) {
|
||||
t.tv_sec = r.tv_sec;
|
||||
t.tv_nsec = r.tv_nsec;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef TIMEOUT_H
|
||||
#define TIMEOUT_H
|
||||
/*=========================================================================*\
|
||||
* Timeout management functions
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
/* timeout control structure */
|
||||
typedef struct t_timeout_ {
|
||||
double block; /* maximum time for blocking calls */
|
||||
double total; /* total number of miliseconds for operation */
|
||||
double start; /* time of start of operation */
|
||||
} t_timeout;
|
||||
typedef t_timeout *p_timeout;
|
||||
|
||||
int timeout_open(lua_State *L);
|
||||
void timeout_init(p_timeout tm, double block, double total);
|
||||
double timeout_get(p_timeout tm);
|
||||
double timeout_getretry(p_timeout tm);
|
||||
p_timeout timeout_markstart(p_timeout tm);
|
||||
double timeout_getstart(p_timeout tm);
|
||||
double timeout_gettime(void);
|
||||
int timeout_meth_settimeout(lua_State *L, p_timeout tm);
|
||||
|
||||
#define timeout_iszero(tm) ((tm)->block == 0.0)
|
||||
|
||||
#endif /* TIMEOUT_H */
|
|
@ -0,0 +1,468 @@
|
|||
/*=========================================================================*\
|
||||
* UDP object
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "udp.h"
|
||||
|
||||
/* min and max macros */
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? x : y)
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? x : y)
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int global_create6(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_sendto(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_receivefrom(lua_State *L);
|
||||
static int meth_getfamily(lua_State *L);
|
||||
static int meth_getsockname(lua_State *L);
|
||||
static int meth_getpeername(lua_State *L);
|
||||
static int meth_setsockname(lua_State *L);
|
||||
static int meth_setpeername(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_getoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
|
||||
/* udp object methods */
|
||||
static luaL_Reg udp_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"close", meth_close},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfamily", meth_getfamily},
|
||||
{"getfd", meth_getfd},
|
||||
{"getpeername", meth_getpeername},
|
||||
{"getsockname", meth_getsockname},
|
||||
{"receive", meth_receive},
|
||||
{"receivefrom", meth_receivefrom},
|
||||
{"send", meth_send},
|
||||
{"sendto", meth_sendto},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"getoption", meth_getoption},
|
||||
{"setpeername", meth_setpeername},
|
||||
{"setsockname", meth_setsockname},
|
||||
{"settimeout", meth_settimeout},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket options for setoption */
|
||||
static t_opt optset[] = {
|
||||
{"dontroute", opt_set_dontroute},
|
||||
{"broadcast", opt_set_broadcast},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"reuseport", opt_set_reuseport},
|
||||
{"ip-multicast-if", opt_set_ip_multicast_if},
|
||||
{"ip-multicast-ttl", opt_set_ip_multicast_ttl},
|
||||
{"ip-multicast-loop", opt_set_ip_multicast_loop},
|
||||
{"ip-add-membership", opt_set_ip_add_membership},
|
||||
{"ip-drop-membership", opt_set_ip_drop_membersip},
|
||||
{"ipv6-v6only", opt_set_ip6_v6only},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket options for getoption */
|
||||
static t_opt optget[] = {
|
||||
{"ip-multicast-if", opt_get_ip_multicast_if},
|
||||
{"ip-multicast-loop", opt_get_ip_multicast_loop},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* functions in library namespace */
|
||||
static luaL_Reg func[] = {
|
||||
{"udp", global_create},
|
||||
{"udp6", global_create6},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int udp_open(lua_State *L)
|
||||
{
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "udp{connected}", udp_methods);
|
||||
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "udp{connected}", "udp{any}");
|
||||
auxiliar_add2group(L, "udp{unconnected}", "udp{any}");
|
||||
auxiliar_add2group(L, "udp{connected}", "select{able}");
|
||||
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
|
||||
/* define library functions */
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
const char *udp_strerror(int err) {
|
||||
/* a 'closed' error on an unconnected means the target address was not
|
||||
* accepted by the transport layer */
|
||||
if (err == IO_CLOSED) return "refused";
|
||||
else return socket_strerror(err);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send data through connected udp socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
||||
p_timeout tm = &udp->tm;
|
||||
size_t count, sent = 0;
|
||||
int err;
|
||||
const char *data = luaL_checklstring(L, 2, &count);
|
||||
timeout_markstart(tm);
|
||||
err = socket_send(&udp->sock, data, count, &sent, tm);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, (lua_Number) sent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send data through unconnected udp socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_sendto(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
size_t count, sent = 0;
|
||||
const char *data = luaL_checklstring(L, 2, &count);
|
||||
const char *ip = luaL_checkstring(L, 3);
|
||||
unsigned short port = (unsigned short) luaL_checknumber(L, 4);
|
||||
p_timeout tm = &udp->tm;
|
||||
int err;
|
||||
switch (udp->family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if (!my_inet_pton(AF_INET, ip, &addr.sin_addr))
|
||||
luaL_argerror(L, 3, "invalid ip address");
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
timeout_markstart(tm);
|
||||
err = socket_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm);
|
||||
break;
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if (!my_inet_pton(AF_INET6, ip, &addr.sin6_addr))
|
||||
luaL_argerror(L, 3, "invalid ip address");
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_port = htons(port);
|
||||
timeout_markstart(tm);
|
||||
err = socket_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", udp->family);
|
||||
return 2;
|
||||
}
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, (lua_Number) sent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receives data from a UDP socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
char buffer[UDP_DATAGRAMSIZE];
|
||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
||||
int err;
|
||||
p_timeout tm = &udp->tm;
|
||||
count = MIN(count, sizeof(buffer));
|
||||
timeout_markstart(tm);
|
||||
err = socket_recv(&udp->sock, buffer, count, &got, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
lua_pushlstring(L, buffer, got);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receives data and sender from a UDP socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_receivefrom(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
char buffer[UDP_DATAGRAMSIZE];
|
||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
||||
int err;
|
||||
p_timeout tm = &udp->tm;
|
||||
timeout_markstart(tm);
|
||||
count = MIN(count, sizeof(buffer));
|
||||
switch (udp->family) {
|
||||
case PF_INET: {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
err = socket_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err == IO_DONE) {
|
||||
char addrstr[INET_ADDRSTRLEN];
|
||||
lua_pushlstring(L, buffer, got);
|
||||
if (!my_inet_ntop(AF_INET, &addr.sin_addr,
|
||||
addrstr, sizeof(addrstr))) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "invalid source address");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, addrstr);
|
||||
lua_pushnumber(L, ntohs(addr.sin_port));
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PF_INET6: {
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
err = socket_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm);
|
||||
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
|
||||
if (err == IO_CLOSED)
|
||||
err = IO_DONE;
|
||||
if (err == IO_DONE) {
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
lua_pushlstring(L, buffer, got);
|
||||
if (!my_inet_ntop(AF_INET6, &addr.sin6_addr,
|
||||
addrstr, sizeof(addrstr))) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "invalid source address");
|
||||
return 2;
|
||||
}
|
||||
lua_pushstring(L, addrstr);
|
||||
lua_pushnumber(L, ntohs(addr.sin6_port));
|
||||
return 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unknown family %d", udp->family);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, udp_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Returns family as string
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfamily(lua_State *L)
|
||||
{
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
if (udp->family == PF_INET6) {
|
||||
lua_pushliteral(L, "inet6");
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushliteral(L, "inet4");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
lua_pushnumber(L, (int) udp->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
udp->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
(void) udp;
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call inet methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getpeername(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1);
|
||||
return inet_meth_getpeername(L, &udp->sock, udp->family);
|
||||
}
|
||||
|
||||
static int meth_getsockname(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return inet_meth_getsockname(L, &udp->sock, udp->family);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &udp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getoption(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return opt_meth_getoption(L, optget, &udp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
return timeout_meth_settimeout(L, &udp->tm);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master udp object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setpeername(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
p_timeout tm = &udp->tm;
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
int connecting = strcmp(address, "*");
|
||||
const char *port = connecting? luaL_checkstring(L, 3): "0";
|
||||
struct addrinfo connecthints;
|
||||
const char *err;
|
||||
memset(&connecthints, 0, sizeof(connecthints));
|
||||
connecthints.ai_socktype = SOCK_DGRAM;
|
||||
/* make sure we try to connect only to the same family */
|
||||
connecthints.ai_family = udp->family;
|
||||
if (connecting) {
|
||||
err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
auxiliar_setclass(L, "udp{connected}", 1);
|
||||
} else {
|
||||
/* we ignore possible errors because Mac OS X always
|
||||
* returns EAFNOSUPPORT */
|
||||
inet_trydisconnect(&udp->sock, udp->family, tm);
|
||||
auxiliar_setclass(L, "udp{unconnected}", 1);
|
||||
}
|
||||
/* change class to connected or unconnected depending on address */
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
|
||||
socket_destroy(&udp->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master object into a server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setsockname(lua_State *L) {
|
||||
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
const char *port = luaL_checkstring(L, 3);
|
||||
const char *err;
|
||||
struct addrinfo bindhints;
|
||||
memset(&bindhints, 0, sizeof(bindhints));
|
||||
bindhints.ai_socktype = SOCK_DGRAM;
|
||||
bindhints.ai_family = udp->family;
|
||||
bindhints.ai_flags = AI_PASSIVE;
|
||||
err = inet_trybind(&udp->sock, address, port, &bindhints);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master udp object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int udp_create(lua_State *L, int family) {
|
||||
t_socket sock;
|
||||
const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
|
||||
/* try to allocate a system socket */
|
||||
if (!err) {
|
||||
/* allocate udp object */
|
||||
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
||||
auxiliar_setclass(L, "udp{unconnected}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
if (family == PF_INET6) {
|
||||
int yes = 1;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
(void *)&yes, sizeof(yes));
|
||||
}
|
||||
udp->sock = sock;
|
||||
timeout_init(&udp->tm, -1, -1);
|
||||
udp->family = family;
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static int global_create(lua_State *L) {
|
||||
return udp_create(L, AF_INET);
|
||||
}
|
||||
|
||||
static int global_create6(lua_State *L) {
|
||||
return udp_create(L, AF_INET6);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef UDP_H
|
||||
#define UDP_H
|
||||
/*=========================================================================*\
|
||||
* UDP object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The udp.h module provides LuaSocket with support for UDP protocol
|
||||
* (AF_INET, SOCK_DGRAM).
|
||||
*
|
||||
* Two classes are defined: connected and unconnected. UDP objects are
|
||||
* originally unconnected. They can be "connected" to a given address
|
||||
* with a call to the setpeername function. The same function can be used to
|
||||
* break the connection.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* can't be larger than wsocket.c MAXCHUNK!!! */
|
||||
#define UDP_DATAGRAMSIZE 8192
|
||||
|
||||
typedef struct t_udp_ {
|
||||
t_socket sock;
|
||||
t_timeout tm;
|
||||
int family;
|
||||
} t_udp;
|
||||
typedef t_udp *p_udp;
|
||||
|
||||
int udp_open(lua_State *L);
|
||||
|
||||
#endif /* UDP_H */
|
|
@ -0,0 +1,340 @@
|
|||
/*=========================================================================*\
|
||||
* Unix domain socket
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "options.h"
|
||||
#include "unix.h"
|
||||
#include <sys/un.h>
|
||||
|
||||
/*=========================================================================*\
|
||||
* Internal function prototypes
|
||||
\*=========================================================================*/
|
||||
static int global_create(lua_State *L);
|
||||
static int meth_connect(lua_State *L);
|
||||
static int meth_listen(lua_State *L);
|
||||
static int meth_bind(lua_State *L);
|
||||
static int meth_send(lua_State *L);
|
||||
static int meth_shutdown(lua_State *L);
|
||||
static int meth_receive(lua_State *L);
|
||||
static int meth_accept(lua_State *L);
|
||||
static int meth_close(lua_State *L);
|
||||
static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_getfd(lua_State *L);
|
||||
static int meth_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int meth_getstats(lua_State *L);
|
||||
static int meth_setstats(lua_State *L);
|
||||
|
||||
static const char *unix_tryconnect(p_unix un, const char *path);
|
||||
static const char *unix_trybind(p_unix un, const char *path);
|
||||
|
||||
/* unix object methods */
|
||||
static luaL_Reg unix_methods[] = {
|
||||
{"__gc", meth_close},
|
||||
{"__tostring", auxiliar_tostring},
|
||||
{"accept", meth_accept},
|
||||
{"bind", meth_bind},
|
||||
{"close", meth_close},
|
||||
{"connect", meth_connect},
|
||||
{"dirty", meth_dirty},
|
||||
{"getfd", meth_getfd},
|
||||
{"getstats", meth_getstats},
|
||||
{"setstats", meth_setstats},
|
||||
{"listen", meth_listen},
|
||||
{"receive", meth_receive},
|
||||
{"send", meth_send},
|
||||
{"setfd", meth_setfd},
|
||||
{"setoption", meth_setoption},
|
||||
{"setpeername", meth_connect},
|
||||
{"setsockname", meth_bind},
|
||||
{"settimeout", meth_settimeout},
|
||||
{"shutdown", meth_shutdown},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* socket option handlers */
|
||||
static t_opt optset[] = {
|
||||
{"keepalive", opt_set_keepalive},
|
||||
{"reuseaddr", opt_set_reuseaddr},
|
||||
{"linger", opt_set_linger},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* our socket creation function */
|
||||
static luaL_Reg func[] = {
|
||||
{"unix", global_create},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int luaopen_socket_unix(lua_State *L) {
|
||||
/* create classes */
|
||||
auxiliar_newclass(L, "unix{master}", unix_methods);
|
||||
auxiliar_newclass(L, "unix{client}", unix_methods);
|
||||
auxiliar_newclass(L, "unix{server}", unix_methods);
|
||||
/* create class groups */
|
||||
auxiliar_add2group(L, "unix{master}", "unix{any}");
|
||||
auxiliar_add2group(L, "unix{client}", "unix{any}");
|
||||
auxiliar_add2group(L, "unix{server}", "unix{any}");
|
||||
/* make sure the function ends up in the package table */
|
||||
luaL_openlib(L, "socket", func, 0);
|
||||
/* return the function instead of the 'socket' table */
|
||||
lua_pushstring(L, "unix");
|
||||
lua_gettable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Lua methods
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call buffered IO methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_send(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_send(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_receive(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_receive(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_getstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_getstats(L, &un->buf);
|
||||
}
|
||||
|
||||
static int meth_setstats(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
return buffer_meth_setstats(L, &un->buf);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
return opt_meth_setoption(L, optset, &un->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select support methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_getfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
lua_pushnumber(L, (int) un->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||
static int meth_setfd(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
un->sock = (t_socket) luaL_checknumber(L, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meth_dirty(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
lua_pushboolean(L, !buffer_isempty(&un->buf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Waits for and returns a client object attempting connection to the
|
||||
* server object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_accept(lua_State *L) {
|
||||
p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
|
||||
p_timeout tm = timeout_markstart(&server->tm);
|
||||
t_socket sock;
|
||||
int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
|
||||
/* if successful, push client socket */
|
||||
if (err == IO_DONE) {
|
||||
p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
auxiliar_setclass(L, "unix{client}", -1);
|
||||
/* initialize structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
clnt->sock = sock;
|
||||
io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
|
||||
(p_error) socket_ioerror, &clnt->sock);
|
||||
timeout_init(&clnt->tm, -1, -1);
|
||||
buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds an object to an address
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const char *unix_trybind(p_unix un, const char *path) {
|
||||
struct sockaddr_un local;
|
||||
size_t len = strlen(path);
|
||||
int err;
|
||||
if (len >= sizeof(local.sun_path)) return "path too long";
|
||||
memset(&local, 0, sizeof(local));
|
||||
strcpy(local.sun_path, path);
|
||||
local.sun_family = AF_UNIX;
|
||||
#ifdef UNIX_HAS_SUN_LEN
|
||||
local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
|
||||
+ len + 1;
|
||||
err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
|
||||
|
||||
#else
|
||||
err = socket_bind(&un->sock, (SA *) &local,
|
||||
(socklen_t)(sizeof(local.sun_family) + len));
|
||||
#endif
|
||||
if (err != IO_DONE) socket_destroy(&un->sock);
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static int meth_bind(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
const char *path = luaL_checkstring(L, 2);
|
||||
const char *err = unix_trybind(un, path);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Turns a master unix object into a client object.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static const char *unix_tryconnect(p_unix un, const char *path)
|
||||
{
|
||||
struct sockaddr_un remote;
|
||||
int err;
|
||||
size_t len = strlen(path);
|
||||
if (len >= sizeof(remote.sun_path)) return "path too long";
|
||||
memset(&remote, 0, sizeof(remote));
|
||||
strcpy(remote.sun_path, path);
|
||||
remote.sun_family = AF_UNIX;
|
||||
timeout_markstart(&un->tm);
|
||||
#ifdef UNIX_HAS_SUN_LEN
|
||||
remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
|
||||
+ len + 1;
|
||||
err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
|
||||
#else
|
||||
err = socket_connect(&un->sock, (SA *) &remote,
|
||||
(socklen_t)(sizeof(remote.sun_family) + len), &un->tm);
|
||||
#endif
|
||||
if (err != IO_DONE) socket_destroy(&un->sock);
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static int meth_connect(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
const char *path = luaL_checkstring(L, 2);
|
||||
const char *err = unix_tryconnect(un, path);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a client object */
|
||||
auxiliar_setclass(L, "unix{client}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Closes socket used by object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_close(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
socket_destroy(&un->sock);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Puts the sockt in listen mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_listen(lua_State *L)
|
||||
{
|
||||
p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
|
||||
int backlog = (int) luaL_optnumber(L, 2, 32);
|
||||
int err = socket_listen(&un->sock, backlog);
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
/* turn master object into a server object */
|
||||
auxiliar_setclass(L, "unix{server}", 1);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Shuts the connection down partially
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_shutdown(lua_State *L)
|
||||
{
|
||||
/* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
|
||||
static const char* methods[] = { "receive", "send", "both", NULL };
|
||||
p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
|
||||
int how = luaL_checkoption(L, 2, "both", methods);
|
||||
socket_shutdown(&tcp->sock, how);
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Just call tm methods
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_settimeout(lua_State *L) {
|
||||
p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
|
||||
return timeout_meth_settimeout(L, &un->tm);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Library functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates a master unix object
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_create(lua_State *L) {
|
||||
t_socket sock;
|
||||
int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
|
||||
/* try to allocate a system socket */
|
||||
if (err == IO_DONE) {
|
||||
/* allocate unix object */
|
||||
p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
|
||||
/* set its type as master object */
|
||||
auxiliar_setclass(L, "unix{master}", -1);
|
||||
/* initialize remaining structure fields */
|
||||
socket_setnonblocking(&sock);
|
||||
un->sock = sock;
|
||||
io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
|
||||
(p_error) socket_ioerror, &un->sock);
|
||||
timeout_init(&un->tm, -1, -1);
|
||||
buffer_init(&un->buf, &un->io, &un->tm);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, socket_strerror(err));
|
||||
return 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef UNIX_H
|
||||
#define UNIX_H
|
||||
/*=========================================================================*\
|
||||
* Unix domain object
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* This module is just an example of how to extend LuaSocket with a new
|
||||
* domain.
|
||||
\*=========================================================================*/
|
||||
#include "lua.h"
|
||||
#include "luasocket.h"
|
||||
#include "luasocket_buffer.h"
|
||||
#include "timeout.h"
|
||||
#include "socket.h"
|
||||
|
||||
typedef struct t_unix_ {
|
||||
t_socket sock;
|
||||
t_io io;
|
||||
t_buffer buf;
|
||||
t_timeout tm;
|
||||
} t_unix;
|
||||
typedef t_unix *p_unix;
|
||||
|
||||
LUASOCKET_API int luaopen_socket_unix(lua_State *L);
|
||||
|
||||
#endif /* UNIX_H */
|
|
@ -0,0 +1,449 @@
|
|||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Unix
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The code is now interrupt-safe.
|
||||
* The penalty of calling select to avoid busy-wait is only paid when
|
||||
* the I/O call fail in the first place.
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Wait for readable/writable/connected socket with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifndef SOCKET_SELECT
|
||||
#include <sys/poll.h>
|
||||
|
||||
#define WAITFD_R POLLIN
|
||||
#define WAITFD_W POLLOUT
|
||||
#define WAITFD_C (POLLIN|POLLOUT)
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
struct pollfd pfd;
|
||||
pfd.fd = *ps;
|
||||
pfd.events = sw;
|
||||
pfd.revents = 0;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
do {
|
||||
int t = (int)(timeout_getretry(tm)*1e3);
|
||||
ret = poll(&pfd, 1, t >= 0? t: -1);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret == -1) return errno;
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
#else
|
||||
|
||||
#define WAITFD_R 1
|
||||
#define WAITFD_W 2
|
||||
#define WAITFD_C (WAITFD_R|WAITFD_W)
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
fd_set rfds, wfds, *rp, *wp;
|
||||
struct timeval tv, *tp;
|
||||
double t;
|
||||
if (*ps >= FD_SETSIZE) return EINVAL;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
do {
|
||||
/* must set bits within loop, because select may have modifed them */
|
||||
rp = wp = NULL;
|
||||
if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; }
|
||||
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
|
||||
t = timeout_getretry(tm);
|
||||
tp = NULL;
|
||||
if (t >= 0.0) {
|
||||
tv.tv_sec = (int)t;
|
||||
tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6);
|
||||
tp = &tv;
|
||||
}
|
||||
ret = select(*ps+1, rp, wp, NULL, tp);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
if (ret == -1) return errno;
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_open(void) {
|
||||
/* instals a handler to ignore sigpipe or it will crash us */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_close(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close and inutilize socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_destroy(p_socket ps) {
|
||||
if (*ps != SOCKET_INVALID) {
|
||||
socket_setblocking(ps);
|
||||
close(*ps);
|
||||
*ps = SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select with timeout control
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm) {
|
||||
int ret;
|
||||
do {
|
||||
struct timeval tv;
|
||||
double t = timeout_getretry(tm);
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
|
||||
/* timeout = 0 means no wait */
|
||||
ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates and sets up a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol) {
|
||||
*ps = socket(domain, type, protocol);
|
||||
if (*ps != SOCKET_INVALID) return IO_DONE;
|
||||
else return errno;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (bind(*ps, addr, len) < 0) err = errno;
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_listen(p_socket ps, int backlog) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (listen(*ps, backlog)) err = errno;
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_shutdown(p_socket ps, int how) {
|
||||
socket_setblocking(ps);
|
||||
shutdown(*ps, how);
|
||||
socket_setnonblocking(ps);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Connects or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
|
||||
int err;
|
||||
/* avoid calling on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* call connect until done or failed without being interrupted */
|
||||
do if (connect(*ps, addr, len) == 0) return IO_DONE;
|
||||
while ((err = errno) == EINTR);
|
||||
/* if connection failed immediately, return error code */
|
||||
if (err != EINPROGRESS && err != EAGAIN) return err;
|
||||
/* zero timeout case optimization */
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT;
|
||||
/* wait until we have the result of the connection attempt or timeout */
|
||||
err = socket_waitfd(ps, WAITFD_C, tm);
|
||||
if (err == IO_CLOSED) {
|
||||
if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE;
|
||||
else return errno;
|
||||
} else return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int err;
|
||||
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
|
||||
err = errno;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN && err != ECONNABORTED) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
long put = (long) send(*ps, data, count, 0);
|
||||
/* if we sent anything, we are done */
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
/* EPIPE means the connection was closed */
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
/* we call was interrupted, just try again */
|
||||
if (err == EINTR) continue;
|
||||
/* if failed fatal reason, report error */
|
||||
if (err != EAGAIN) return err;
|
||||
/* wait until we can send something or we timeout */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sendto with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
|
||||
SA *addr, socklen_t len, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long put = (long) sendto(*ps, data, count, 0, addr, len);
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receive with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) recv(*ps, data, count, 0);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Recvfrom with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
|
||||
SA *addr, socklen_t *len, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) recvfrom(*ps, data, count, 0, addr, len);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Write with timeout
|
||||
*
|
||||
* socket_read and socket_write are cut-n-paste of socket_send and socket_recv,
|
||||
* with send/recv replaced with write/read. We can't just use write/read
|
||||
* in the socket version, because behaviour when size is zero is different.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_write(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
long put = (long) write(*ps, data, count);
|
||||
/* if we sent anything, we are done */
|
||||
if (put >= 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
/* EPIPE means the connection was closed */
|
||||
if (err == EPIPE) return IO_CLOSED;
|
||||
/* we call was interrupted, just try again */
|
||||
if (err == EINTR) continue;
|
||||
/* if failed fatal reason, report error */
|
||||
if (err != EAGAIN) return err;
|
||||
/* wait until we can send something or we timeout */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
/* can't reach here */
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Read with timeout
|
||||
* See note for socket_write
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
long taken = (long) read(*ps, data, count);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = errno;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (err == EINTR) continue;
|
||||
if (err != EAGAIN) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setblocking(p_socket ps) {
|
||||
int flags = fcntl(*ps, F_GETFL, 0);
|
||||
flags &= (~(O_NONBLOCK));
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into non-blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setnonblocking(p_socket ps) {
|
||||
int flags = fcntl(*ps, F_GETFL, 0);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* DNS helpers
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
|
||||
*hp = gethostbyaddr(addr, len, AF_INET);
|
||||
if (*hp) return IO_DONE;
|
||||
else if (h_errno) return h_errno;
|
||||
else if (errno) return errno;
|
||||
else return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp) {
|
||||
*hp = gethostbyname(addr);
|
||||
if (*hp) return IO_DONE;
|
||||
else if (h_errno) return h_errno;
|
||||
else if (errno) return errno;
|
||||
else return IO_UNKNOWN;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Error translation functions
|
||||
* Make sure important error messages are standard
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *socket_hoststrerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case HOST_NOT_FOUND: return "host not found";
|
||||
default: return hstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_strerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case EADDRINUSE: return "address already in use";
|
||||
case EISCONN: return "already connected";
|
||||
case EACCES: return "permission denied";
|
||||
case ECONNREFUSED: return "connection refused";
|
||||
case ECONNABORTED: return "closed";
|
||||
case ECONNRESET: return "closed";
|
||||
case ETIMEDOUT: return "timeout";
|
||||
default: return strerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_ioerror(p_socket ps, int err) {
|
||||
(void) ps;
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
const char *socket_gaistrerror(int err) {
|
||||
if (err == 0) return NULL;
|
||||
switch (err) {
|
||||
case EAI_AGAIN: return "temporary failure in name resolution";
|
||||
case EAI_BADFLAGS: return "invalid value for ai_flags";
|
||||
#ifdef EAI_BADHINTS
|
||||
case EAI_BADHINTS: return "invalid value for hints";
|
||||
#endif
|
||||
case EAI_FAIL: return "non-recoverable failure in name resolution";
|
||||
case EAI_FAMILY: return "ai_family not supported";
|
||||
case EAI_MEMORY: return "memory allocation failure";
|
||||
case EAI_NONAME:
|
||||
return "host or service not provided, or not known";
|
||||
case EAI_OVERFLOW: return "argument buffer overflow";
|
||||
#ifdef EAI_PROTOCOL
|
||||
case EAI_PROTOCOL: return "resolved protocol is unknown";
|
||||
#endif
|
||||
case EAI_SERVICE: return "service not supported for socket type";
|
||||
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
||||
case EAI_SYSTEM: return strerror(errno);
|
||||
default: return gai_strerror(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef USOCKET_H
|
||||
#define USOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Unix
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* BSD include files
|
||||
\*=========================================================================*/
|
||||
/* error codes */
|
||||
#include <errno.h>
|
||||
/* close function */
|
||||
#include <unistd.h>
|
||||
/* fnctnl function and associated constants */
|
||||
#include <fcntl.h>
|
||||
/* struct sockaddr */
|
||||
#include <sys/types.h>
|
||||
/* socket function */
|
||||
#include <sys/socket.h>
|
||||
/* struct timeval */
|
||||
#include <sys/time.h>
|
||||
/* gethostbyname and gethostbyaddr functions */
|
||||
#include <netdb.h>
|
||||
/* sigpipe handling */
|
||||
#include <signal.h>
|
||||
/* IP stuff*/
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
/* TCP options (nagle algorithm disable) */
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#ifndef SO_REUSEPORT
|
||||
#define SO_REUSEPORT SO_REUSEADDR
|
||||
#endif
|
||||
|
||||
typedef int t_socket;
|
||||
typedef t_socket *p_socket;
|
||||
typedef struct sockaddr_storage t_sockaddr_storage;
|
||||
|
||||
#define SOCKET_INVALID (-1)
|
||||
|
||||
#endif /* USOCKET_H */
|
|
@ -0,0 +1,413 @@
|
|||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Win32
|
||||
* LuaSocket toolkit
|
||||
*
|
||||
* The penalty of calling select to avoid busy-wait is only paid when
|
||||
* the I/O call fail in the first place.
|
||||
\*=========================================================================*/
|
||||
#include <string.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
/* WinSock doesn't have a strerror... */
|
||||
static const char *wstrerror(int err);
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_open(void) {
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(2, 0);
|
||||
int err = WSAStartup(wVersionRequested, &wsaData );
|
||||
if (err != 0) return 0;
|
||||
if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
|
||||
(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_close(void) {
|
||||
WSACleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Wait for readable/writable/connected socket with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#define WAITFD_R 1
|
||||
#define WAITFD_W 2
|
||||
#define WAITFD_E 4
|
||||
#define WAITFD_C (WAITFD_E|WAITFD_W)
|
||||
|
||||
int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
|
||||
int ret;
|
||||
fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
|
||||
struct timeval tv, *tp = NULL;
|
||||
double t;
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
|
||||
if (sw & WAITFD_R) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(*ps, &rfds);
|
||||
rp = &rfds;
|
||||
}
|
||||
if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
|
||||
if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
|
||||
if ((t = timeout_get(tm)) >= 0.0) {
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
|
||||
tp = &tv;
|
||||
}
|
||||
ret = select(0, rp, wp, ep, tp);
|
||||
if (ret == -1) return WSAGetLastError();
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
|
||||
return IO_DONE;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Select with int timeout in ms
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||||
p_timeout tm) {
|
||||
struct timeval tv;
|
||||
double t = timeout_get(tm);
|
||||
tv.tv_sec = (int) t;
|
||||
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
|
||||
if (n <= 0) {
|
||||
Sleep((DWORD) (1000*t));
|
||||
return 0;
|
||||
} else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close and inutilize socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_destroy(p_socket ps) {
|
||||
if (*ps != SOCKET_INVALID) {
|
||||
socket_setblocking(ps); /* close can take a long time on WIN32 */
|
||||
closesocket(*ps);
|
||||
*ps = SOCKET_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_shutdown(p_socket ps, int how) {
|
||||
socket_setblocking(ps);
|
||||
shutdown(*ps, how);
|
||||
socket_setnonblocking(ps);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates and sets up a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_create(p_socket ps, int domain, int type, int protocol) {
|
||||
*ps = socket(domain, type, protocol);
|
||||
if (*ps != SOCKET_INVALID) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Connects or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
|
||||
int err;
|
||||
/* don't call on closed socket */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* ask system to connect */
|
||||
if (connect(*ps, addr, len) == 0) return IO_DONE;
|
||||
/* make sure the system is trying to connect */
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
|
||||
/* zero timeout case optimization */
|
||||
if (timeout_iszero(tm)) return IO_TIMEOUT;
|
||||
/* we wait until something happens */
|
||||
err = socket_waitfd(ps, WAITFD_C, tm);
|
||||
if (err == IO_CLOSED) {
|
||||
int len = sizeof(err);
|
||||
/* give windows time to set the error (yes, disgusting) */
|
||||
Sleep(10);
|
||||
/* find out why we failed */
|
||||
getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
|
||||
/* we KNOW there was an error. if 'why' is 0, we will return
|
||||
* "unknown error", but it's not really our fault */
|
||||
return err > 0? err: IO_UNKNOWN;
|
||||
} else return err;
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_bind(p_socket ps, SA *addr, socklen_t len) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
*
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_listen(p_socket ps, int backlog) {
|
||||
int err = IO_DONE;
|
||||
socket_setblocking(ps);
|
||||
if (listen(*ps, backlog) < 0) err = WSAGetLastError();
|
||||
socket_setnonblocking(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
|
||||
p_timeout tm) {
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int err;
|
||||
/* try to get client socket */
|
||||
if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
|
||||
/* find out why we failed */
|
||||
err = WSAGetLastError();
|
||||
/* if we failed because there was no connectoin, keep trying */
|
||||
if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
|
||||
/* call select to avoid busy wait */
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send with timeout
|
||||
* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
|
||||
* this can take an awful lot of time and we will end up blocked.
|
||||
* Therefore, whoever calls this function should not pass a huge buffer.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_send(p_socket ps, const char *data, size_t count,
|
||||
size_t *sent, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
/* try to send something */
|
||||
int put = send(*ps, data, (int) count, 0);
|
||||
/* if we sent something, we are done */
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
/* deal with failure */
|
||||
err = WSAGetLastError();
|
||||
/* we can only proceed if there was no serious error */
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
/* avoid busy wait */
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sendto with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
|
||||
SA *addr, socklen_t len, p_timeout tm)
|
||||
{
|
||||
int err;
|
||||
*sent = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int put = sendto(*ps, data, (int) count, 0, addr, len);
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Receive with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int taken = recv(*ps, data, (int) count, 0);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Recvfrom with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
|
||||
SA *addr, socklen_t *len, p_timeout tm) {
|
||||
int err;
|
||||
*got = 0;
|
||||
if (*ps == SOCKET_INVALID) return IO_CLOSED;
|
||||
for ( ;; ) {
|
||||
int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) return err;
|
||||
if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setblocking(p_socket ps) {
|
||||
u_long argp = 0;
|
||||
ioctlsocket(*ps, FIONBIO, &argp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into non-blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void socket_setnonblocking(p_socket ps) {
|
||||
u_long argp = 1;
|
||||
ioctlsocket(*ps, FIONBIO, &argp);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* DNS helpers
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
|
||||
*hp = gethostbyaddr(addr, len, AF_INET);
|
||||
if (*hp) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
int socket_gethostbyname(const char *addr, struct hostent **hp) {
|
||||
*hp = gethostbyname(addr);
|
||||
if (*hp) return IO_DONE;
|
||||
else return WSAGetLastError();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Error translation functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *socket_hoststrerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case WSAHOST_NOT_FOUND: return "host not found";
|
||||
default: return wstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_strerror(int err) {
|
||||
if (err <= 0) return io_strerror(err);
|
||||
switch (err) {
|
||||
case WSAEADDRINUSE: return "address already in use";
|
||||
case WSAECONNREFUSED: return "connection refused";
|
||||
case WSAEISCONN: return "already connected";
|
||||
case WSAEACCES: return "permission denied";
|
||||
case WSAECONNABORTED: return "closed";
|
||||
case WSAECONNRESET: return "closed";
|
||||
case WSAETIMEDOUT: return "timeout";
|
||||
default: return wstrerror(err);
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_ioerror(p_socket ps, int err) {
|
||||
(void) ps;
|
||||
return socket_strerror(err);
|
||||
}
|
||||
|
||||
static const char *wstrerror(int err) {
|
||||
switch (err) {
|
||||
case WSAEINTR: return "Interrupted function call";
|
||||
case WSAEACCES: return "Permission denied";
|
||||
case WSAEFAULT: return "Bad address";
|
||||
case WSAEINVAL: return "Invalid argument";
|
||||
case WSAEMFILE: return "Too many open files";
|
||||
case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
|
||||
case WSAEINPROGRESS: return "Operation now in progress";
|
||||
case WSAEALREADY: return "Operation already in progress";
|
||||
case WSAENOTSOCK: return "Socket operation on nonsocket";
|
||||
case WSAEDESTADDRREQ: return "Destination address required";
|
||||
case WSAEMSGSIZE: return "Message too long";
|
||||
case WSAEPROTOTYPE: return "Protocol wrong type for socket";
|
||||
case WSAENOPROTOOPT: return "Bad protocol option";
|
||||
case WSAEPROTONOSUPPORT: return "Protocol not supported";
|
||||
case WSAESOCKTNOSUPPORT: return "Socket type not supported";
|
||||
case WSAEOPNOTSUPP: return "Operation not supported";
|
||||
case WSAEPFNOSUPPORT: return "Protocol family not supported";
|
||||
case WSAEAFNOSUPPORT:
|
||||
return "Address family not supported by protocol family";
|
||||
case WSAEADDRINUSE: return "Address already in use";
|
||||
case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
|
||||
case WSAENETDOWN: return "Network is down";
|
||||
case WSAENETUNREACH: return "Network is unreachable";
|
||||
case WSAENETRESET: return "Network dropped connection on reset";
|
||||
case WSAECONNABORTED: return "Software caused connection abort";
|
||||
case WSAECONNRESET: return "Connection reset by peer";
|
||||
case WSAENOBUFS: return "No buffer space available";
|
||||
case WSAEISCONN: return "Socket is already connected";
|
||||
case WSAENOTCONN: return "Socket is not connected";
|
||||
case WSAESHUTDOWN: return "Cannot send after socket shutdown";
|
||||
case WSAETIMEDOUT: return "Connection timed out";
|
||||
case WSAECONNREFUSED: return "Connection refused";
|
||||
case WSAEHOSTDOWN: return "Host is down";
|
||||
case WSAEHOSTUNREACH: return "No route to host";
|
||||
case WSAEPROCLIM: return "Too many processes";
|
||||
case WSASYSNOTREADY: return "Network subsystem is unavailable";
|
||||
case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
|
||||
case WSANOTINITIALISED:
|
||||
return "Successful WSAStartup not yet performed";
|
||||
case WSAEDISCON: return "Graceful shutdown in progress";
|
||||
case WSAHOST_NOT_FOUND: return "Host not found";
|
||||
case WSATRY_AGAIN: return "Nonauthoritative host not found";
|
||||
case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
|
||||
case WSANO_DATA: return "Valid name, no data record of requested type";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
const char *socket_gaistrerror(int err) {
|
||||
if (err == 0) return NULL;
|
||||
switch (err) {
|
||||
case EAI_AGAIN: return "temporary failure in name resolution";
|
||||
case EAI_BADFLAGS: return "invalid value for ai_flags";
|
||||
#ifdef EAI_BADHINTS
|
||||
case EAI_BADHINTS: return "invalid value for hints";
|
||||
#endif
|
||||
case EAI_FAIL: return "non-recoverable failure in name resolution";
|
||||
case EAI_FAMILY: return "ai_family not supported";
|
||||
case EAI_MEMORY: return "memory allocation failure";
|
||||
case EAI_NONAME:
|
||||
return "host or service not provided, or not known";
|
||||
// case EAI_OVERFLOW: return "argument buffer overflow";
|
||||
#ifdef EAI_PROTOCOL
|
||||
case EAI_PROTOCOL: return "resolved protocol is unknown";
|
||||
#endif
|
||||
case EAI_SERVICE: return "service not supported for socket type";
|
||||
case EAI_SOCKTYPE: return "ai_socktype not supported";
|
||||
// case EAI_SYSTEM: return strerror(errno);
|
||||
default: return gai_strerrorA(err);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef WSOCKET_H
|
||||
#define WSOCKET_H
|
||||
/*=========================================================================*\
|
||||
* Socket compatibilization module for Win32
|
||||
* LuaSocket toolkit
|
||||
\*=========================================================================*/
|
||||
|
||||
/*=========================================================================*\
|
||||
* WinSock include files
|
||||
\*=========================================================================*/
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
typedef int socklen_t;
|
||||
typedef SOCKADDR_STORAGE t_sockaddr_storage;
|
||||
typedef SOCKET t_socket;
|
||||
typedef t_socket *p_socket;
|
||||
|
||||
#define SOCKET_INVALID (INVALID_SOCKET)
|
||||
|
||||
#ifndef SO_REUSEPORT
|
||||
#define SO_REUSEPORT SO_REUSEADDR
|
||||
#endif
|
||||
|
||||
#endif /* WSOCKET_H */
|
|
@ -367,3 +367,165 @@ cc.LabelEffect =
|
|||
GLOW = 3,
|
||||
}
|
||||
|
||||
cc.KeyCode =
|
||||
{
|
||||
KEY_NONE = 0,
|
||||
KEY_PAUSE = 0x0013,
|
||||
KEY_SCROLL_LOCK = 0x1014,
|
||||
KEY_PRINT = 0x1061,
|
||||
KEY_SYSREQ = 0x106A,
|
||||
KEY_BREAK = 0x106B,
|
||||
KEY_ESCAPE = 0x001B,
|
||||
KEY_BACKSPACE = 0x0008,
|
||||
KEY_TAB = 0x0009,
|
||||
KEY_BACK_TAB = 0x0089,
|
||||
KEY_RETURN = 0x000D,
|
||||
KEY_CAPS_LOCK = 0x00E5,
|
||||
KEY_SHIFT = 0x00E1,
|
||||
KEY_CTRL = 0x00E3,
|
||||
KEY_ALT = 0x00E9,
|
||||
KEY_MENU = 0x1067,
|
||||
KEY_HYPER = 0x10ED,
|
||||
KEY_INSERT = 0x1063,
|
||||
KEY_HOME = 0x1050,
|
||||
KEY_PG_UP = 0x1055,
|
||||
KEY_DELETE = 0x10FF,
|
||||
KEY_END = 0x1057,
|
||||
KEY_PG_DOWN = 0x1056,
|
||||
KEY_LEFT_ARROW = 0x1051,
|
||||
KEY_RIGHT_ARROW = 0x1053,
|
||||
KEY_UP_ARROW = 0x1052,
|
||||
KEY_DOWN_ARROW = 0x1054,
|
||||
KEY_NUM_LOCK = 0x107F,
|
||||
KEY_KP_PLUS = 0x10AB,
|
||||
KEY_KP_MINUS = 0x10AD,
|
||||
KEY_KP_MULTIPLY = 0x10AA,
|
||||
KEY_KP_DIVIDE = 0x10AF,
|
||||
KEY_KP_ENTER = 0x108D,
|
||||
KEY_KP_HOME = 0x10B7,
|
||||
KEY_KP_UP = 0x10B8,
|
||||
KEY_KP_PG_UP = 0x10B9,
|
||||
KEY_KP_LEFT = 0x10B4,
|
||||
KEY_KP_FIVE = 0x10B5,
|
||||
KEY_KP_RIGHT = 0x10B6,
|
||||
KEY_KP_END = 0x10B1,
|
||||
KEY_KP_DOWN = 0x10B2,
|
||||
KEY_KP_PG_DOWN = 0x10B3,
|
||||
KEY_KP_INSERT = 0x10B0,
|
||||
KEY_KP_DELETE = 0x10AE,
|
||||
KEY_F1 = 0x00BE,
|
||||
KEY_F2 = 0x00BF,
|
||||
KEY_F3 = 0x00C0,
|
||||
KEY_F4 = 0x00C1,
|
||||
KEY_F5 = 0x00C2,
|
||||
KEY_F6 = 0x00C3,
|
||||
KEY_F7 = 0x00C4,
|
||||
KEY_F8 = 0x00C5,
|
||||
KEY_F9 = 0x00C6,
|
||||
KEY_F10 = 0x00C7,
|
||||
KEY_F11 = 0x00C8,
|
||||
KEY_F12 = 0x00C9,
|
||||
KEY_SPACE = ' ',
|
||||
KEY_EXCLAM = '!',
|
||||
KEY_QUOTE = '"',
|
||||
KEY_NUMBER = '#',
|
||||
KEY_DOLLAR = '$',
|
||||
KEY_PERCENT = '%',
|
||||
KEY_CIRCUMFLEX = '^',
|
||||
KEY_AMPERSAND = '&',
|
||||
KEY_APOSTROPHE = '\'',
|
||||
KEY_LEFT_PARENTHESIS = '(',
|
||||
KEY_RIGHT_PARENTHESIS = ')',
|
||||
KEY_ASTERISK = '*',
|
||||
KEY_PLUS = '+',
|
||||
KEY_COMMA = ',',
|
||||
KEY_MINUS = '-',
|
||||
KEY_PERIOD = '.',
|
||||
KEY_SLASH = '/',
|
||||
KEY_0 = '0',
|
||||
KEY_1 = '1',
|
||||
KEY_2 = '2',
|
||||
KEY_3 = '3',
|
||||
KEY_4 = '4',
|
||||
KEY_5 = '5',
|
||||
KEY_6 = '6',
|
||||
KEY_7 = '7',
|
||||
KEY_8 = '8',
|
||||
KEY_9 = '9',
|
||||
KEY_COLON = ':',
|
||||
KEY_SEMICOLON = ';',
|
||||
KEY_LESS_THAN = '<',
|
||||
KEY_EQUAL = '=',
|
||||
KEY_GREATER_THAN = '>',
|
||||
KEY_QUESTION = '?',
|
||||
KEY_AT = '@',
|
||||
KEY_CAPITAL_A = 'A',
|
||||
KEY_CAPITAL_B = 'B',
|
||||
KEY_CAPITAL_C = 'C',
|
||||
KEY_CAPITAL_D = 'D',
|
||||
KEY_CAPITAL_E = 'E',
|
||||
KEY_CAPITAL_F = 'F',
|
||||
KEY_CAPITAL_G = 'G',
|
||||
KEY_CAPITAL_H = 'H',
|
||||
KEY_CAPITAL_I = 'I',
|
||||
KEY_CAPITAL_J = 'J',
|
||||
KEY_CAPITAL_K = 'K',
|
||||
KEY_CAPITAL_L = 'L',
|
||||
KEY_CAPITAL_M = 'M',
|
||||
KEY_CAPITAL_N = 'N',
|
||||
KEY_CAPITAL_O = 'O',
|
||||
KEY_CAPITAL_P = 'P',
|
||||
KEY_CAPITAL_Q = 'Q',
|
||||
KEY_CAPITAL_R = 'R',
|
||||
KEY_CAPITAL_S = 'S',
|
||||
KEY_CAPITAL_T = 'T',
|
||||
KEY_CAPITAL_U = 'U',
|
||||
KEY_CAPITAL_V = 'V',
|
||||
KEY_CAPITAL_W = 'W',
|
||||
KEY_CAPITAL_X = 'X',
|
||||
KEY_CAPITAL_Y = 'Y',
|
||||
KEY_CAPITAL_Z = 'Z',
|
||||
KEY_LEFT_BRACKET = '[',
|
||||
KEY_BACK_SLASH = '\\',
|
||||
KEY_RIGHT_BRACKET = ']',
|
||||
KEY_UNDERSCORE = '_',
|
||||
KEY_GRAVE = '`',
|
||||
KEY_A = 'a',
|
||||
KEY_B = 'b',
|
||||
KEY_C = 'c',
|
||||
KEY_D = 'd',
|
||||
KEY_E = 'e',
|
||||
KEY_F = 'f',
|
||||
KEY_G = 'g',
|
||||
KEY_H = 'h',
|
||||
KEY_I = 'i',
|
||||
KEY_J = 'j',
|
||||
KEY_K = 'k',
|
||||
KEY_L = 'l',
|
||||
KEY_M = 'm',
|
||||
KEY_N = 'n',
|
||||
KEY_O = 'o',
|
||||
KEY_P = 'p',
|
||||
KEY_Q = 'q',
|
||||
KEY_R = 'r',
|
||||
KEY_S = 's',
|
||||
KEY_T = 't',
|
||||
KEY_U = 'u',
|
||||
KEY_V = 'v',
|
||||
KEY_W = 'w',
|
||||
KEY_X = 'x',
|
||||
KEY_Y = 'y',
|
||||
KEY_Z = 'z',
|
||||
KEY_LEFT_BRACE = '{',
|
||||
KEY_BAR = '|',
|
||||
KEY_RIGHT_BRACE = '}',
|
||||
KEY_TILDE = '~',
|
||||
KEY_EURO = 0x20AC,
|
||||
KEY_POUND = 0x00A3,
|
||||
KEY_YEN = 0x00A5,
|
||||
KEY_MIDDLE_DOT = 0x0095,
|
||||
KEY_SEARCH = 0xFFAA,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
- [`ccTypes.h`](#cctypesh)
|
||||
- [deprecated functions and global variables](#deprecated-functions-and--global-variables)
|
||||
- [Changes in the Lua bindings](#changes-in-the-lua-bindings)
|
||||
- [Use bindings-generator tool for Lua binding](#use-bindings-generator-tool-for-lua-binding)
|
||||
- [Use bindings-generator tool for lua binding](#use-bindings-generator-tool-for-lua-binding)
|
||||
- [Bind the classes with namespace to lua](#bind-the-classes-with-namespace-to-lua)
|
||||
- [Use ScriptHandlerMgr to manage the register and unregister of lua function](#use-scripthandlermgr-to-manage-the-register-and-unregister-of-lua-function)
|
||||
- [Use "cc" and "ccs" as module name](#use-cc-and-ccs-as-module-name)
|
||||
- [Deprecated funtions, tables and classes](#deprecated-funtions-tables-and-classes)
|
||||
- [Use the lua table instead of the some structs and classes binding](#use-the-lua-table-instead-of-the-some-structs-and-classes-binding)
|
||||
- [Integrate more modules into lua](#integrate-more-modules-into-lua)
|
||||
- [Known issues](#known-issues)
|
||||
|
||||
# Misc Information
|
||||
|
@ -663,9 +665,21 @@ color3B = Color3B::WHITE;
|
|||
|
||||
## Changes in the Lua bindings
|
||||
|
||||
### Use bindings-generator tool for Lua binding
|
||||
### Use bindings-generator tool for lua binding
|
||||
|
||||
Only configurating the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files
|
||||
Only have to write an ini file for a module, don't have to write a lot of .pkg files
|
||||
|
||||
### Bind the classes with namespace to lua
|
||||
|
||||
In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, `CCNode` will be changed to `cc.Node`. This modification will affect some APIs as follows:
|
||||
|
||||
| v2.x | v3.0 |
|
||||
| tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") |
|
||||
| tolua_isusertable(tolua_S,1,"CCNode",0,&tolua_err | tolua_isusertable(tolua_S,1,"cc.Node",0,&tolua_err |
|
||||
| tolua_isusertype(tolua_S,1,"CCNode",0,&tolua_err) | tolua_isusertype(tolua_S,1,"cc.Node",0,&tolua_err) |
|
||||
| toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"CCNode") | toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cc.Node") |
|
||||
| tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCFileUtils") | tolua_pushusertype(tolua_S,(void*)tolua_ret,"cc.FileUtils") |
|
||||
| tolua.cast(pChildren[i + 1], "CCNode") | tolua.cast(pChildren[i + 1], "cc.Node") |
|
||||
|
||||
### Use ScriptHandlerMgr to manage the register and unregister of Lua function
|
||||
|
||||
|
@ -686,20 +700,29 @@ In v3.0 version, we only need to add the `HandlerType` enum in the `ScriptHandle
|
|||
ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HANDLERTYPE_MENU_CLICKED)
|
||||
```
|
||||
|
||||
### Use "cc" and "ccs" as module name
|
||||
### Use "cc"、"ccs"、"ccui" and "sp" as module name
|
||||
The classes in the `cocos2d`、`cocos2d::extension`、`CocosDenshion` and `cocosbuilder` namespace were bound to lua in the `cc` module;
|
||||
The classes in the `cocos2d::gui` namespace were bound to lua in the `ccui` module;
|
||||
The classes in the `spine` namespace were bound to lua in the `sp` module;
|
||||
The classes in the `cocostudio` namespace were bound to lua in the `ccs` module.
|
||||
|
||||
The main differences in the script are as follows:
|
||||
```lua
|
||||
// v2.x
|
||||
CCSprite:create(s_pPathGrossini)
|
||||
CCEaseIn:create(createSimpleMoveBy(), 2.5)
|
||||
|
||||
UILayout:create()
|
||||
CCArmature:create("bear")
|
||||
|
||||
ImageView:create()
|
||||
|
||||
// v3.0
|
||||
cc.Director:getInstance():getWinSize()
|
||||
cc.EaseIn:create(createSimpleMoveBy(), 2.5)
|
||||
|
||||
ccs.UILayer:create()
|
||||
ccs.Armature:create("bear")
|
||||
|
||||
ccui.ImageView:create()
|
||||
```
|
||||
|
||||
### Deprecated funtions, tables and classes
|
||||
|
@ -735,6 +758,24 @@ local color4B = cc.c4b(0,0,0,0)
|
|||
|
||||
Through the funtions of the LuaBasicConversion file,they can be converted the Lua table when they are as a parameter in the bindings generator.
|
||||
|
||||
### Integrate more modules into lua
|
||||
In the version 3.0,more modules were bound to lua,specific as follows:
|
||||
|
||||
```
|
||||
1.physics
|
||||
2.spine
|
||||
3.XMLHttpRequest
|
||||
```
|
||||
The XMLHttpRequest and physics are in the "cc" module,and the spine is in the "sp" module.
|
||||
The related test cases located in:
|
||||
|
||||
```
|
||||
physics ---> TestLua/PhysicsTest
|
||||
spine ---> TestLua/SpineTest
|
||||
XMLHttpRequest ---> TestLua/XMLHttpRequestTest
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Known issues
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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));
|
||||
|
|
|
@ -419,7 +419,11 @@ Atlas3::Atlas3()
|
|||
label2->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label2->setColor( Color3B::RED );
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->runAction( repeat->clone() );
|
||||
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
|
||||
TintTo::create(1, 0, 255, 0),
|
||||
TintTo::create(1, 0, 0, 255),
|
||||
NULL);
|
||||
label2->runAction( RepeatForever::create(tint) );
|
||||
|
||||
auto label3 = LabelBMFont::create("Test", "fonts/bitmapFontTest2.fnt");
|
||||
// testing anchors
|
||||
|
|
|
@ -68,7 +68,9 @@ static std::function<Layer*()> createFunctions[] =
|
|||
CL(LabelTTFDistanceField),
|
||||
CL(LabelTTFDistanceFieldEffect),
|
||||
CL(LabelCharMapTest),
|
||||
CL(LabelCrashTest)
|
||||
CL(LabelCharMapColorTest),
|
||||
CL(LabelCrashTest),
|
||||
CL(LabelTTFOldNew)
|
||||
};
|
||||
|
||||
#define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0]))
|
||||
|
@ -164,17 +166,17 @@ LabelTTFAlignmentNew::LabelTTFAlignmentNew()
|
|||
|
||||
auto ttf0 = Label::createWithTTF(config,"Alignment 0\nnew line",TextHAlignment::LEFT);
|
||||
ttf0->setPosition(Point(s.width/2,(s.height/6)*2 - 30));
|
||||
ttf0->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf0->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf0);
|
||||
|
||||
auto ttf1 = Label::createWithTTF(config,"Alignment 1\nnew line",TextHAlignment::CENTER);
|
||||
ttf1->setPosition(Point(s.width/2,(s.height/6)*3 - 30));
|
||||
ttf1->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf1);
|
||||
|
||||
auto ttf2 = Label::createWithTTF(config,"Alignment 2\nnew line",TextHAlignment::RIGHT);
|
||||
ttf2->setPosition(Point(s.width/2,(s.height/6)*4 - 30));
|
||||
ttf2->setAnchorPoint(Point(0.5f,0.5f));
|
||||
ttf2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->addChild(ttf2);
|
||||
}
|
||||
|
||||
|
@ -206,10 +208,14 @@ LabelFNTColorAndOpacity::LabelFNTColorAndOpacity()
|
|||
label1->runAction(repeat);
|
||||
|
||||
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
|
||||
label2->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label2->setColor( Color3B::RED );
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->runAction( repeat->clone() );
|
||||
auto tint = Sequence::create(TintTo::create(1, 255, 0, 0),
|
||||
TintTo::create(1, 0, 255, 0),
|
||||
TintTo::create(1, 0, 0, 255),
|
||||
NULL);
|
||||
label2->runAction( RepeatForever::create(tint) );
|
||||
|
||||
auto label3 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test");
|
||||
label3->setAnchorPoint( Point(1,1) );
|
||||
|
@ -259,7 +265,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
|
|||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
|
||||
auto BChar = (Sprite*) label->getLetter(0);
|
||||
|
@ -293,6 +299,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions()
|
|||
auto label2 = Label::createWithBMFont("fonts/bitmapFontTest.fnt", "00.0");
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setPosition( Point(s.width/2.0f, 80) );
|
||||
label2->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
auto lastChar = (Sprite*) label2->getLetter(3);
|
||||
lastChar->runAction( rot_4ever->clone() );
|
||||
|
@ -348,7 +355,7 @@ LabelFNTPadding::LabelFNTPadding()
|
|||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
}
|
||||
|
||||
std::string LabelFNTPadding::title() const
|
||||
|
@ -369,17 +376,17 @@ LabelFNTOffset::LabelFNTOffset()
|
|||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "FaFeFiFoFu");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2+50) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) ) ;
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE ) ;
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "fafefifofu");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "aeiou");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/2-50) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
}
|
||||
|
||||
std::string LabelFNTOffset::title() const
|
||||
|
@ -401,18 +408,18 @@ LabelFNTColor::LabelFNTColor()
|
|||
label->setColor( Color3B::BLUE );
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Red");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, 2*s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label->setColor( Color3B::RED );
|
||||
|
||||
label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Green");
|
||||
addChild(label);
|
||||
label->setPosition( Point(s.width/2, 3*s.height/4) );
|
||||
label->setAnchorPoint( Point(0.5f, 0.5f) );
|
||||
label->setAnchorPoint( Point::ANCHOR_MIDDLE );
|
||||
label->setColor( Color3B::GREEN );
|
||||
label->setString("Green");
|
||||
}
|
||||
|
@ -441,7 +448,7 @@ LabelFNTHundredLabels::LabelFNTHundredLabels()
|
|||
|
||||
auto p = Point( CCRANDOM_0_1() * s.width, CCRANDOM_0_1() * s.height);
|
||||
label->setPosition( p );
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,7 +477,7 @@ LabelFNTMultiLine::LabelFNTMultiLine()
|
|||
|
||||
// Center
|
||||
auto label2 = Label::createWithBMFont( "fonts/bitmapFontTest3.fnt", "Multi line\nCenter");
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
|
||||
s= label2->getContentSize();
|
||||
|
@ -502,20 +509,24 @@ std::string LabelFNTMultiLine::subtitle() const
|
|||
LabelFNTandTTFEmpty::LabelFNTandTTFEmpty()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
float delta = s.height/4;
|
||||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest3.fnt", "", TextHAlignment::CENTER, s.width);
|
||||
addChild(label1, 0, kTagBitmapAtlas1);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setPosition(Point(s.width/2, delta));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, s.height - 100));
|
||||
|
||||
// LabelTTF
|
||||
TTFConfig ttfConfig("fonts/arial.ttf",48);
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"", TextHAlignment::CENTER,s.width);
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setPosition(Point(s.width/2, delta * 2));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, s.height / 2));
|
||||
|
||||
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3, 0, kTagBitmapAtlas3);
|
||||
label3->setPosition(Point(s.width/2, 100));
|
||||
|
||||
schedule(schedule_selector(LabelFNTandTTFEmpty::updateStrings), 1.0f);
|
||||
|
||||
|
@ -526,11 +537,13 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
|
|||
{
|
||||
auto label1 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas1) );
|
||||
auto label2 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas2) );
|
||||
auto label3 = static_cast<Label*>( getChildByTag(kTagBitmapAtlas3) );
|
||||
|
||||
if( ! setEmpty )
|
||||
{
|
||||
label1->setString("not empty");
|
||||
label2->setString("not empty");
|
||||
label3->setString("hi");
|
||||
|
||||
setEmpty = true;
|
||||
}
|
||||
|
@ -538,6 +551,7 @@ void LabelFNTandTTFEmpty::updateStrings(float dt)
|
|||
{
|
||||
label1->setString("");
|
||||
label2->setString("");
|
||||
label3->setString("");
|
||||
|
||||
setEmpty = false;
|
||||
}
|
||||
|
@ -550,7 +564,7 @@ std::string LabelFNTandTTFEmpty::title() const
|
|||
|
||||
std::string LabelFNTandTTFEmpty::subtitle() const
|
||||
{
|
||||
return "2 empty labels: new Label + .FNT and new Label + .TTF";
|
||||
return "3 empty labels: new Label + FNT/TTF/CharMap";
|
||||
}
|
||||
|
||||
LabelFNTRetina::LabelFNTRetina()
|
||||
|
@ -559,7 +573,7 @@ LabelFNTRetina::LabelFNTRetina()
|
|||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/konqa32.fnt", "TESTING RETINA DISPLAY");
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -583,7 +597,7 @@ LabelFNTGlyphDesigner::LabelFNTGlyphDesigner()
|
|||
|
||||
// LabelBMFont
|
||||
auto label1 = Label::createWithBMFont("fonts/futura-48.fnt", "Testing Glyph Designer");
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -605,7 +619,7 @@ LabelTTFUnicodeChinese::LabelTTFUnicodeChinese()
|
|||
// like "Error 3 error C2146: syntax error : missing ')' before identifier 'label'";
|
||||
TTFConfig ttfConfig("fonts/wt021.ttf",55,GlyphCollection::CUSTOM, "美好的一天啊");
|
||||
auto label = Label::createWithTTF(ttfConfig,"美好的一天啊", TextHAlignment::CENTER, size.width);
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label->setPosition(Point(size.width / 2, size.height /2));
|
||||
this->addChild(label);
|
||||
}
|
||||
|
@ -624,7 +638,7 @@ LabelFNTUnicodeChinese::LabelFNTUnicodeChinese()
|
|||
{
|
||||
auto size = Director::getInstance()->getWinSize();
|
||||
auto label = Label::createWithBMFont("fonts/bitmapFontChinese.fnt", "中国");
|
||||
label->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label->setPosition(Point(size.width / 2, size.height /2));
|
||||
this->addChild(label);
|
||||
}
|
||||
|
@ -673,7 +687,7 @@ LabelFNTMultiLineAlignment::LabelFNTMultiLineAlignment()
|
|||
|
||||
// create and initialize a Label
|
||||
this->_labelShouldRetain = Label::createWithBMFont("fonts/markerFelt.fnt", LongSentencesExample, TextHAlignment::CENTER, size.width/1.5);
|
||||
this->_labelShouldRetain->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
this->_labelShouldRetain->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
this->_labelShouldRetain->retain();
|
||||
|
||||
this->_arrowsBarShouldRetain = Sprite::create("Images/arrowsBar.png");
|
||||
|
@ -857,22 +871,22 @@ LabelFNTUNICODELanguages::LabelFNTUNICODELanguages()
|
|||
|
||||
auto label1 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", spanish, TextHAlignment::CENTER, 200);
|
||||
addChild(label1);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, s.height/5*3));
|
||||
|
||||
auto label2 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", chinese);
|
||||
addChild(label2);
|
||||
label2->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, s.height/5*2.5));
|
||||
|
||||
auto label3 = Label::createWithBMFont("fonts/arial-26-en-ru.fnt", russian);
|
||||
addChild(label3);
|
||||
label3->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label3->setPosition(Point(s.width/2, s.height/5*2));
|
||||
|
||||
auto label4 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", japanese);
|
||||
addChild(label4);
|
||||
label4->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label4->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label4->setPosition(Point(s.width/2, s.height/5*1.5));
|
||||
}
|
||||
|
||||
|
@ -895,7 +909,7 @@ LabelFNTBounds::LabelFNTBounds()
|
|||
|
||||
// LabelBMFont
|
||||
label1 = Label::createWithBMFont("fonts/boundsTestFont.fnt", "Testing Glyph Designer", TextHAlignment::CENTER, s.width);
|
||||
label1->setAnchorPoint(Point(0.5f, 0.5f));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
label1->setPosition(Point(s.width/2, s.height/2));
|
||||
}
|
||||
|
@ -972,21 +986,21 @@ LabelTTFColor::LabelTTFColor()
|
|||
auto label1 = Label::createWithTTF(ttfConfig,"Green", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/5 * 1.5) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
// Red
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Red", TextHAlignment::CENTER, size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height/5 * 2.0) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
// Blue
|
||||
auto label3 = Label::createWithTTF(ttfConfig,"Blue", TextHAlignment::CENTER, size.width);
|
||||
label3->setPosition( Point(size.width/2, size.height/5 * 2.5) );
|
||||
label3->setColor( Color3B::BLUE );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3);
|
||||
}
|
||||
|
||||
|
@ -1006,7 +1020,7 @@ LabelTTFDynamicAlignment::LabelTTFDynamicAlignment()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 45);
|
||||
_label = Label::createWithTTF(ttfConfig,LongSentencesExample, TextHAlignment::CENTER, size.width);
|
||||
_label->setPosition( Point(size.width/2, size.height/2) );
|
||||
_label->setAnchorPoint(Point(0.5, 0.5));
|
||||
_label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
|
||||
auto menu = Menu::create(
|
||||
MenuItemFont::create("Left", CC_CALLBACK_1(LabelTTFDynamicAlignment::setAlignmentLeft, this)),
|
||||
|
@ -1078,13 +1092,13 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
|
|||
// Spanish
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Buen día, ¿cómo te llamas?", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, vSize - (vStep * 4.5)) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
// German
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"In welcher Straße haben Sie gelebt?", TextHAlignment::CENTER,size.width);
|
||||
label2->setPosition( Point(size.width/2, vSize - (vStep * 5.5)) );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
// chinese
|
||||
|
@ -1093,7 +1107,7 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew()
|
|||
ttfConfig.customGlyphs = chinese.c_str();
|
||||
auto label3 = Label::createWithTTF(ttfConfig,chinese, TextHAlignment::CENTER,size.width);
|
||||
label3->setPosition( Point(size.width/2, vSize - (vStep * 6.5)) );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label3);
|
||||
}
|
||||
|
||||
|
@ -1130,7 +1144,7 @@ LabelTTFFontsTestNew::LabelTTFFontsTestNew()
|
|||
label->setPosition( Point(size.width/2, ((size.height * 0.6)/arraysize(ttfpaths) * i) + (size.height/5)));
|
||||
addChild(label);
|
||||
|
||||
label->setAnchorPoint(Point(0.5, 0.5));
|
||||
label->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
} else {
|
||||
log("ERROR: Cannot load: %s", ttfpaths[i]);
|
||||
}
|
||||
|
@ -1153,7 +1167,7 @@ LabelBMFontTestNew::LabelBMFontTestNew()
|
|||
|
||||
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Hello World, this is testing the new Label using fnt file", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
}
|
||||
|
||||
|
@ -1173,9 +1187,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
|
||||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setPosition( Point(size.width/2, size.height * 0.6f) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
|
||||
auto action = Sequence::create(
|
||||
|
@ -1186,9 +1200,9 @@ LabelTTFDistanceField::LabelTTFDistanceField()
|
|||
label1->runAction(RepeatForever::create(action));
|
||||
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height/5) );
|
||||
label2->setPosition( Point(size.width/2, size.height * 0.3f) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label2);
|
||||
|
||||
}
|
||||
|
@ -1213,23 +1227,23 @@ LabelTTFDistanceFieldEffect::LabelTTFDistanceFieldEffect()
|
|||
TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true);
|
||||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Glow", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height*0.5) );
|
||||
label1->setPosition( Point(size.width/2, size.height*0.65) );
|
||||
label1->setColor( Color3B::GREEN );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setLabelEffect(LabelEffect::GLOW,Color3B::YELLOW);
|
||||
addChild(label1);
|
||||
|
||||
auto label2 = Label::createWithTTF(ttfConfig,"Outline", TextHAlignment::CENTER, size.width);
|
||||
label2->setPosition( Point(size.width/2, size.height*0.375) );
|
||||
label2->setPosition( Point(size.width/2, size.height*0.5) );
|
||||
label2->setColor( Color3B::RED );
|
||||
label2->setAnchorPoint(Point(0.5, 0.5));
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setLabelEffect(LabelEffect::OUTLINE,Color3B::BLUE);
|
||||
addChild(label2);
|
||||
|
||||
auto label3 = Label::createWithTTF(ttfConfig,"Shadow", TextHAlignment::CENTER, size.width);
|
||||
label3->setPosition( Point(size.width/2, size.height*0.25f) );
|
||||
label3->setPosition( Point(size.width/2, size.height*0.35f) );
|
||||
label3->setColor( Color3B::RED );
|
||||
label3->setAnchorPoint(Point(0.5, 0.5));
|
||||
label3->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label3->setLabelEffect(LabelEffect::SHADOW,Color3B::BLACK);
|
||||
addChild(label3);
|
||||
|
||||
|
@ -1256,14 +1270,9 @@ LabelCharMapTest::LabelCharMapTest()
|
|||
|
||||
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.plist");
|
||||
addChild(label2, 0, kTagSprite2);
|
||||
label2->setPosition( Point(10,160) );
|
||||
label2->setPosition( Point(10,200) );
|
||||
label2->setOpacity( 32 );
|
||||
|
||||
auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
label3->setString("123 Test");
|
||||
addChild(label3, 0, kTagSprite3);
|
||||
label3->setPosition( Point(10,220) );
|
||||
|
||||
schedule(schedule_selector(LabelCharMapTest::step));
|
||||
}
|
||||
|
||||
|
@ -1291,6 +1300,63 @@ std::string LabelCharMapTest::subtitle() const
|
|||
return "Updating label should be fast.";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// LabelCharMapColorTest
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
LabelCharMapColorTest::LabelCharMapColorTest()
|
||||
{
|
||||
auto label1 = Label::createWithCharMap( "fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
addChild(label1, 0, kTagSprite1);
|
||||
label1->setPosition( Point(10,100) );
|
||||
label1->setOpacity( 200 );
|
||||
|
||||
auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');
|
||||
addChild(label2, 0, kTagSprite2);
|
||||
label2->setPosition( Point(10,200) );
|
||||
label2->setColor( Color3B::RED );
|
||||
|
||||
auto fade = FadeOut::create(1.0f);
|
||||
auto fade_in = fade->reverse();
|
||||
auto cb = CallFunc::create(CC_CALLBACK_0(LabelCharMapColorTest::actionFinishCallback, this));
|
||||
auto seq = Sequence::create(fade, fade_in, cb, NULL);
|
||||
auto repeat = RepeatForever::create( seq );
|
||||
label2->runAction( repeat );
|
||||
|
||||
_time = 0;
|
||||
|
||||
schedule( schedule_selector(LabelCharMapColorTest::step) ); //:@selector(step:)];
|
||||
}
|
||||
|
||||
void LabelCharMapColorTest::actionFinishCallback()
|
||||
{
|
||||
CCLOG("Action finished");
|
||||
}
|
||||
|
||||
void LabelCharMapColorTest::step(float dt)
|
||||
{
|
||||
_time += dt;
|
||||
char string[12] = {0};
|
||||
sprintf(string, "%2.2f Test", _time);
|
||||
auto label1 = (Label*)getChildByTag(kTagSprite1);
|
||||
label1->setString(string);
|
||||
|
||||
auto label2 = (Label*)getChildByTag(kTagSprite2);
|
||||
sprintf(string, "%d", (int)_time);
|
||||
label2->setString( string );
|
||||
}
|
||||
|
||||
std::string LabelCharMapColorTest::title() const
|
||||
{
|
||||
return "New Label + CharMap";
|
||||
}
|
||||
|
||||
std::string LabelCharMapColorTest::subtitle() const
|
||||
{
|
||||
return "Opacity + Color should work at the same time";
|
||||
}
|
||||
|
||||
LabelCrashTest::LabelCrashTest()
|
||||
{
|
||||
auto size = Director::getInstance()->getWinSize();
|
||||
|
@ -1299,7 +1365,7 @@ LabelCrashTest::LabelCrashTest()
|
|||
|
||||
auto label1 = Label::createWithTTF(ttfConfig,"Test崩溃123", TextHAlignment::CENTER, size.width);
|
||||
label1->setPosition( Point(size.width/2, size.height/2) );
|
||||
label1->setAnchorPoint(Point(0.5, 0.5));
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
addChild(label1);
|
||||
}
|
||||
|
||||
|
@ -1312,3 +1378,63 @@ std::string LabelCrashTest::subtitle() const
|
|||
{
|
||||
return "Not crash and show [Test123] when using unknown character.";
|
||||
}
|
||||
|
||||
LabelTTFOldNew::LabelTTFOldNew()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
float delta = s.height/4;
|
||||
|
||||
auto label1 = LabelTTF::create("Cocos2d-x Label Test", "arial", 24);
|
||||
addChild(label1, 0, kTagBitmapAtlas1);
|
||||
label1->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label1->setPosition(Point(s.width/2, delta * 2));
|
||||
label1->setColor(Color3B::RED);
|
||||
|
||||
TTFConfig ttfConfig("fonts/arial.ttf", 48);
|
||||
auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test");
|
||||
addChild(label2, 0, kTagBitmapAtlas2);
|
||||
label2->setAnchorPoint(Point::ANCHOR_MIDDLE);
|
||||
label2->setPosition(Point(s.width/2, delta * 2));
|
||||
}
|
||||
|
||||
void LabelTTFOldNew::onDraw()
|
||||
{
|
||||
kmMat4 oldMat;
|
||||
kmGLGetMatrix(KM_GL_MODELVIEW, &oldMat);
|
||||
kmGLLoadMatrix(&_modelViewTransform);
|
||||
|
||||
auto label1 = (Label*)getChildByTag(kTagBitmapAtlas2);
|
||||
auto labelSize = label1->getContentSize();
|
||||
auto origin = Director::getInstance()->getWinSize();
|
||||
|
||||
origin.width = origin.width / 2 - (labelSize.width / 2);
|
||||
origin.height = origin.height / 2 - (labelSize.height / 2);
|
||||
|
||||
Point vertices[4]=
|
||||
{
|
||||
Point(origin.width, origin.height),
|
||||
Point(labelSize.width + origin.width, origin.height),
|
||||
Point(labelSize.width + origin.width, labelSize.height + origin.height),
|
||||
Point(origin.width, labelSize.height + origin.height)
|
||||
};
|
||||
DrawPrimitives::drawPoly(vertices, 4, true);
|
||||
|
||||
kmGLLoadMatrix(&oldMat);
|
||||
}
|
||||
|
||||
void LabelTTFOldNew::draw()
|
||||
{
|
||||
_renderCmd.init(_globalZOrder);
|
||||
_renderCmd.func = CC_CALLBACK_0(LabelTTFOldNew::onDraw, this);
|
||||
Director::getInstance()->getRenderer()->addCommand(&_renderCmd);
|
||||
}
|
||||
|
||||
std::string LabelTTFOldNew::title() const
|
||||
{
|
||||
return "New / Old TTF";
|
||||
}
|
||||
|
||||
std::string LabelTTFOldNew::subtitle() const
|
||||
{
|
||||
return "Comparison between old(red) and new(white) TTF label";
|
||||
}
|
||||
|
|
|
@ -363,6 +363,23 @@ private:
|
|||
float _time;
|
||||
};
|
||||
|
||||
class LabelCharMapColorTest : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(LabelCharMapColorTest);
|
||||
|
||||
LabelCharMapColorTest();
|
||||
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
|
||||
void step(float dt);
|
||||
void actionFinishCallback();
|
||||
|
||||
private:
|
||||
float _time;
|
||||
};
|
||||
|
||||
class LabelCrashTest : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
|
@ -374,6 +391,22 @@ public:
|
|||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class LabelTTFOldNew : public AtlasDemoNew
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(LabelTTFOldNew);
|
||||
|
||||
LabelTTFOldNew();
|
||||
|
||||
virtual void draw() override;
|
||||
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
protected:
|
||||
CustomCommand _renderCmd;
|
||||
void onDraw();
|
||||
};
|
||||
|
||||
// we don't support linebreak mode
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,7 +63,9 @@ static std::function<Layer*()> createFunctions[] =
|
|||
CL(NodeToWorld3D),
|
||||
CL(SchedulerTest1),
|
||||
CL(CameraOrbitTest),
|
||||
CL(CameraZoomTest),
|
||||
//Camera has been removed from CCNode
|
||||
//todo add new feature to support it
|
||||
//CL(CameraZoomTest),
|
||||
CL(ConvertToNode),
|
||||
CL(NodeOpaqueTest),
|
||||
CL(NodeNonOpaqueTest),
|
||||
|
|
|
@ -292,6 +292,7 @@ void NodeDeallocTest::update(float dt)
|
|||
|
||||
for( int i=0; i<quantityOfNodes; ++i) {
|
||||
nodes[i] = Node::create();
|
||||
nodes[i]->retain();
|
||||
}
|
||||
|
||||
CC_PROFILER_START(this->profilerName());
|
||||
|
|
|
@ -85,6 +85,8 @@ void TextureTest::performTestsPNG(const char* filename)
|
|||
struct timeval now;
|
||||
Texture2D *texture;
|
||||
auto cache = Director::getInstance()->getTextureCache();
|
||||
|
||||
Texture2D::PixelFormat defaultFormat = Texture2D::getDefaultAlphaPixelFormat();
|
||||
|
||||
log("RGBA 8888");
|
||||
Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA8888);
|
||||
|
@ -125,6 +127,8 @@ void TextureTest::performTestsPNG(const char* filename)
|
|||
else
|
||||
log(" ERROR");
|
||||
cache->removeTexture(texture);
|
||||
|
||||
Texture2D::setDefaultAlphaPixelFormat(defaultFormat);
|
||||
}
|
||||
|
||||
void TextureTest::performTests()
|
||||
|
|
|
@ -160,7 +160,7 @@ void SchedulerPauseResume::onEnter()
|
|||
|
||||
schedule(schedule_selector(SchedulerPauseResume::tick1), 0.5f);
|
||||
schedule(schedule_selector(SchedulerPauseResume::tick2), 0.5f);
|
||||
schedule(schedule_selector(SchedulerPauseResume::pause), 0.5f);
|
||||
schedule(schedule_selector(SchedulerPauseResume::pause), 3.0f);
|
||||
}
|
||||
|
||||
void SchedulerPauseResume::tick1(float dt)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#Do now ignore Marmalade icf files
|
||||
!*.icf
|
|
@ -0,0 +1 @@
|
|||
aec1c0a8c8068377fddca5ddd32084d8c3c3c419
|
|
@ -103,43 +103,39 @@ local function main()
|
|||
|
||||
-- handing touch events
|
||||
local touchBeginPoint = nil
|
||||
|
||||
local function onTouchBegan(x, y)
|
||||
cclog("onTouchBegan: %0.2f, %0.2f", x, y)
|
||||
touchBeginPoint = {x = x, y = y}
|
||||
local function onTouchBegan(touch, event)
|
||||
local location = touch:getLocation()
|
||||
cclog("onTouchBegan: %0.2f, %0.2f", location.x, location.y)
|
||||
touchBeginPoint = {x = location.x, y = location.y}
|
||||
spriteDog.isPaused = true
|
||||
-- CCTOUCHBEGAN event must return true
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchMoved(x, y)
|
||||
cclog("onTouchMoved: %0.2f, %0.2f", x, y)
|
||||
local function onTouchMoved(touch, event)
|
||||
local location = touch:getLocation()
|
||||
cclog("onTouchMoved: %0.2f, %0.2f", location.x, location.y)
|
||||
if touchBeginPoint then
|
||||
local cx, cy = layerFarm:getPosition()
|
||||
layerFarm:setPosition(cx + x - touchBeginPoint.x,
|
||||
cy + y - touchBeginPoint.y)
|
||||
touchBeginPoint = {x = x, y = y}
|
||||
layerFarm:setPosition(cx + location.x - touchBeginPoint.x,
|
||||
cy + location.y - touchBeginPoint.y)
|
||||
touchBeginPoint = {x = location.x, y = location.y}
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchEnded(x, y)
|
||||
cclog("onTouchEnded: %0.2f, %0.2f", x, y)
|
||||
local function onTouchEnded(touch, event)
|
||||
local location = touch:getLocation()
|
||||
cclog("onTouchEnded: %0.2f, %0.2f", location.x, location.y)
|
||||
touchBeginPoint = nil
|
||||
spriteDog.isPaused = false
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x, y)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(x, y)
|
||||
else
|
||||
return onTouchEnded(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
layerFarm:registerScriptTouchHandler(onTouch)
|
||||
layerFarm:setTouchEnabled(true)
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
|
||||
local eventDispatcher = layerFarm:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layerFarm)
|
||||
|
||||
return layerFarm
|
||||
end
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,4 +31,5 @@
|
|||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:xlargeScreens="true"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
|
|
|
@ -5,54 +5,60 @@ local function AccelerometerMainLayer()
|
|||
end
|
||||
local layer = cc.Layer:create()
|
||||
|
||||
layer:setAccelerometerEnabled(true)
|
||||
local function onEnter()
|
||||
layer:setAccelerometerEnabled(true)
|
||||
|
||||
local label = cc.LabelTTF:create(title(), "Arial", 32)
|
||||
layer:addChild(label, 1)
|
||||
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
|
||||
local label = cc.LabelTTF:create(title(), "Arial", 32)
|
||||
layer:addChild(label, 1)
|
||||
label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) )
|
||||
|
||||
local ball = cc.Sprite:create("Images/ball.png")
|
||||
ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
|
||||
layer:addChild(ball)
|
||||
local ball = cc.Sprite:create("Images/ball.png")
|
||||
ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y))
|
||||
layer:addChild(ball)
|
||||
|
||||
ball:retain()
|
||||
|
||||
local function didAccelerate(x,y,z,timestamp)
|
||||
local function accelerometerListener(event,x,y,z,timestamp)
|
||||
local target = event:getCurrentTarget()
|
||||
local ballSize = target:getContentSize()
|
||||
local ptNowX,ptNowY = target:getPosition()
|
||||
ptNowX = ptNowX + x * 9.81
|
||||
ptNowY = ptNowY + y * 9.81
|
||||
|
||||
if nil == ball then
|
||||
return
|
||||
end
|
||||
|
||||
local director = cc.Director:getInstance()
|
||||
local szBall = ball:getContentSize()
|
||||
local ptNowX,ptNowY = ball:getPosition()
|
||||
local ptTemp = director:convertToUI(cc.p(ptNowX,ptNowY))
|
||||
|
||||
ptTemp.x = ptTemp.x + x * 9.81
|
||||
ptTemp.y = ptTemp.y - y * 9.81
|
||||
|
||||
local ptNext = director:convertToGL(cc.p(ptTemp.x,ptTemp.y))
|
||||
|
||||
local minX = math.floor(VisibleRect:left().x + szBall.width / 2.0)
|
||||
local maxX = math.floor(VisibleRect:right().x - szBall.width / 2.0)
|
||||
if ptNext.x < minX then
|
||||
ptNext.x = minX
|
||||
elseif ptNext.x > maxX then
|
||||
ptNext.x = maxX
|
||||
end
|
||||
local minX = math.floor(VisibleRect:left().x + ballSize.width / 2.0)
|
||||
local maxX = math.floor(VisibleRect:right().x - ballSize.width / 2.0)
|
||||
if ptNowX < minX then
|
||||
ptNowX = minX
|
||||
elseif ptNowX > maxX then
|
||||
ptNowX = maxX
|
||||
end
|
||||
|
||||
local minY = math.floor(VisibleRect:bottom().y + szBall.height / 2.0)
|
||||
local maxY = math.floor(VisibleRect:top().y - szBall.height / 2.0)
|
||||
if ptNext.y < minY then
|
||||
ptNext.y = minY
|
||||
elseif ptNext.y > maxY then
|
||||
ptNext.y = maxY
|
||||
end
|
||||
|
||||
ball:setPosition(cc.p(ptNext.x , ptNext.y))
|
||||
local minY = math.floor(VisibleRect:bottom().y + ballSize.height / 2.0)
|
||||
local maxY = math.floor(VisibleRect:top().y - ballSize.height / 2.0)
|
||||
if ptNowY < minY then
|
||||
ptNowY = minY
|
||||
elseif ptNowY > maxY then
|
||||
ptNowY = maxY
|
||||
end
|
||||
|
||||
target:setPosition(cc.p(ptNowX , ptNowY))
|
||||
end
|
||||
|
||||
local listerner = cc.EventListenerAcceleration:create(accelerometerListener)
|
||||
layer:getEventDispatcher():addEventListenerWithSceneGraphPriority(listerner,ball)
|
||||
end
|
||||
|
||||
layer:registerScriptAccelerateHandler(didAccelerate)
|
||||
|
||||
local function onExit()
|
||||
layer:setAccelerometerEnabled(false)
|
||||
end
|
||||
|
||||
local function onNodeEvent(event)
|
||||
if "enter" == event then
|
||||
onEnter()
|
||||
elseif "exit" == event then
|
||||
onExit()
|
||||
end
|
||||
end
|
||||
|
||||
layer:registerScriptHandler(onNodeEvent)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
local MAX_COUNT = 9;
|
||||
local LINE_SPACE = 40;
|
||||
local kItemTagBasic = 5432;
|
||||
local MAX_COUNT = 9
|
||||
local LINE_SPACE = 40
|
||||
local kItemTagBasic = 5432
|
||||
|
||||
local Winsize = cc.Director:getInstance():getWinSize();
|
||||
local Winsize = cc.Director:getInstance():getWinSize()
|
||||
|
||||
local testNames = {
|
||||
"Bug-350",
|
||||
|
@ -18,8 +18,8 @@ local testNames = {
|
|||
|
||||
local function CreateBugsTestBackMenuItem(pLayer)
|
||||
cc.MenuItemFont:setFontName("Arial")
|
||||
cc.MenuItemFont:setFontSize(24);
|
||||
local pMenuItemFont = cc.MenuItemFont:create("Back");
|
||||
cc.MenuItemFont:setFontSize(24)
|
||||
local pMenuItemFont = cc.MenuItemFont:create("Back")
|
||||
pMenuItemFont:setPosition(cc.p(VisibleRect:rightBottom().x - 50, VisibleRect:rightBottom().y + 25))
|
||||
local function menuCallback()
|
||||
local pScene = BugsTestMain()
|
||||
|
@ -37,9 +37,9 @@ end
|
|||
--BugTest350
|
||||
local function BugTest350()
|
||||
local pLayer = cc.Layer:create()
|
||||
local pBackground = cc.Sprite:create("Hello.png");
|
||||
pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2));
|
||||
pLayer:addChild(pBackground);
|
||||
local pBackground = cc.Sprite:create("Hello.png")
|
||||
pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
|
||||
pLayer:addChild(pBackground)
|
||||
return pLayer
|
||||
end
|
||||
|
||||
|
@ -55,7 +55,7 @@ local function BugTest422()
|
|||
print(strLog)
|
||||
end
|
||||
|
||||
pResetLayer:removeChild(pNode, false);
|
||||
pResetLayer:removeChild(pNode, false)
|
||||
|
||||
local function menuCallback(tag,pMenuItem)
|
||||
if nil ~= pMenuItem then
|
||||
|
@ -64,7 +64,7 @@ local function BugTest422()
|
|||
end
|
||||
end
|
||||
cc.MenuItemFont:setFontName("Arial")
|
||||
cc.MenuItemFont:setFontSize(24);
|
||||
cc.MenuItemFont:setFontSize(24)
|
||||
local pMenuItem1 = cc.MenuItemFont:create("One")
|
||||
pMenuItem1:registerScriptTapHandler(menuCallback)
|
||||
local pMenuItem2 = cc.MenuItemFont:create("Two")
|
||||
|
@ -90,15 +90,15 @@ local function BugTest458()
|
|||
|
||||
local function InitQuestionContainerSprite(pSprite)
|
||||
--Add label
|
||||
local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12);
|
||||
pLabel:setTag(100);
|
||||
local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12)
|
||||
pLabel:setTag(100)
|
||||
|
||||
--Add the background
|
||||
local pCorner = cc.Sprite:create("Images/bugs/corner.png");
|
||||
local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2);
|
||||
local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2);
|
||||
local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight);
|
||||
pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2));
|
||||
local pCorner = cc.Sprite:create("Images/bugs/corner.png")
|
||||
local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2)
|
||||
local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2)
|
||||
local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight)
|
||||
pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2))
|
||||
--First button is blue,Second is red,Used for testing - change later
|
||||
if (0 == nColorFlag) then
|
||||
pLabel:setColor(cc.c3b(0,0,255))
|
||||
|
@ -106,53 +106,53 @@ local function BugTest458()
|
|||
print("Color changed")
|
||||
pLabel:setColor(cc.c3b(255,0,0))
|
||||
end
|
||||
nColorFlag = nColorFlag + 1;
|
||||
pSprite:addChild(pColorLayer);
|
||||
nColorFlag = nColorFlag + 1
|
||||
pSprite:addChild(pColorLayer)
|
||||
|
||||
pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2)));
|
||||
pSprite:addChild(pCorner);
|
||||
pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2)))
|
||||
pSprite:addChild(pCorner)
|
||||
|
||||
local nX,nY = pCorner:getPosition()
|
||||
local pCorner2 = cc.Sprite:create("Images/bugs/corner.png");
|
||||
pCorner2:setPosition(cc.p(-nX, nY));
|
||||
pCorner2:setFlipX(true);
|
||||
pSprite:addChild(pCorner2);
|
||||
local pCorner2 = cc.Sprite:create("Images/bugs/corner.png")
|
||||
pCorner2:setPosition(cc.p(-nX, nY))
|
||||
pCorner2:setFlipX(true)
|
||||
pSprite:addChild(pCorner2)
|
||||
|
||||
local pCorner3 = cc.Sprite:create("Images/bugs/corner.png");
|
||||
pCorner3:setPosition(cc.p(nX, -nY));
|
||||
pCorner3:setFlipY(true);
|
||||
pSprite:addChild(pCorner3);
|
||||
local pCorner3 = cc.Sprite:create("Images/bugs/corner.png")
|
||||
pCorner3:setPosition(cc.p(nX, -nY))
|
||||
pCorner3:setFlipY(true)
|
||||
pSprite:addChild(pCorner3)
|
||||
|
||||
local pCorner4 = cc.Sprite:create("Images/bugs/corner.png");
|
||||
pCorner4:setPosition(cc.p(-nX, -nY));
|
||||
pCorner4:setFlipX(true);
|
||||
pCorner4:setFlipY(true);
|
||||
pSprite:addChild(pCorner4);
|
||||
local pCorner4 = cc.Sprite:create("Images/bugs/corner.png")
|
||||
pCorner4:setPosition(cc.p(-nX, -nY))
|
||||
pCorner4:setFlipX(true)
|
||||
pCorner4:setFlipY(true)
|
||||
pSprite:addChild(pCorner4)
|
||||
|
||||
local pEdge = cc.Sprite:create("Images/bugs/edge.png");
|
||||
pEdge:setScaleX(nWidth);
|
||||
pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY));
|
||||
pSprite:addChild(pEdge);
|
||||
local pEdge = cc.Sprite:create("Images/bugs/edge.png")
|
||||
pEdge:setScaleX(nWidth)
|
||||
pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY))
|
||||
pSprite:addChild(pEdge)
|
||||
|
||||
local pEdge2 = cc.Sprite:create("Images/bugs/edge.png");
|
||||
pEdge2:setScaleX(nWidth);
|
||||
pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY));
|
||||
pEdge2:setFlipY(true);
|
||||
pSprite:addChild(pEdge2);
|
||||
local pEdge2 = cc.Sprite:create("Images/bugs/edge.png")
|
||||
pEdge2:setScaleX(nWidth)
|
||||
pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY))
|
||||
pEdge2:setFlipY(true)
|
||||
pSprite:addChild(pEdge2)
|
||||
|
||||
local pEdge3 = cc.Sprite:create("Images/bugs/edge.png");
|
||||
pEdge3:setRotation(90);
|
||||
pEdge3:setScaleX(nHeight);
|
||||
pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)));
|
||||
pSprite:addChild(pEdge3);
|
||||
local pEdge3 = cc.Sprite:create("Images/bugs/edge.png")
|
||||
pEdge3:setRotation(90)
|
||||
pEdge3:setScaleX(nHeight)
|
||||
pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)))
|
||||
pSprite:addChild(pEdge3)
|
||||
|
||||
local pEdge4 = cc.Sprite:create("Images/bugs/edge.png");
|
||||
pEdge4:setRotation(270);
|
||||
pEdge4:setScaleX(nHeight);
|
||||
pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)));
|
||||
pSprite:addChild(pEdge4);
|
||||
local pEdge4 = cc.Sprite:create("Images/bugs/edge.png")
|
||||
pEdge4:setRotation(270)
|
||||
pEdge4:setScaleX(nHeight)
|
||||
pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2)))
|
||||
pSprite:addChild(pEdge4)
|
||||
|
||||
pSprite:addChild(pLabel);
|
||||
pSprite:addChild(pLabel)
|
||||
end
|
||||
|
||||
local pQuestion1 = cc.Sprite:create()
|
||||
|
@ -165,19 +165,19 @@ local function BugTest458()
|
|||
end
|
||||
local pMenuItemSprite = cc.MenuItemSprite:create(pQuestion1,pQuestion2)
|
||||
pMenuItemSprite:registerScriptTapHandler(menuCallback)
|
||||
local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100);
|
||||
-- question->release();
|
||||
-- question2->release();
|
||||
local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100)
|
||||
-- question->release()
|
||||
-- question2->release()
|
||||
|
||||
local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100);
|
||||
local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2);
|
||||
local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100)
|
||||
local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2)
|
||||
pMenuItemSprite2:registerScriptTapHandler(menuCallback)
|
||||
local pMenu = cc.Menu:create(pMenuItemSprite, pMenuItemSprite2)
|
||||
pMenu:alignItemsVerticallyWithPadding(100);
|
||||
pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
|
||||
pMenu:alignItemsVerticallyWithPadding(100)
|
||||
pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
|
||||
|
||||
-- add the label as a child to this Layer
|
||||
pLayer:addChild(pMenu);
|
||||
pLayer:addChild(pMenu)
|
||||
|
||||
return pLayer
|
||||
end
|
||||
|
@ -189,21 +189,21 @@ local BugTest624_2_entry = nil
|
|||
local function BugTest624()
|
||||
local pLayer = cc.Layer:create()
|
||||
|
||||
local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36);
|
||||
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
|
||||
pLayer:addChild(pLabel);
|
||||
pLayer:setAccelerometerEnabled(true);
|
||||
-- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f);
|
||||
local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36)
|
||||
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
|
||||
pLayer:addChild(pLabel)
|
||||
pLayer:setAccelerometerEnabled(true)
|
||||
-- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f)
|
||||
|
||||
local function BugTest624_SwitchLayer()
|
||||
local scheduler = cc.Director:getInstance():getScheduler()
|
||||
scheduler:unscheduleScriptEntry(BugTest624_entry)
|
||||
|
||||
local pScene = cc.Scene:create();
|
||||
local pScene = cc.Scene:create()
|
||||
local pNewPlayer = BugTest624_2()
|
||||
CreateBugsTestBackMenuItem(pNewPlayer)
|
||||
pScene:addChild(pNewPlayer);
|
||||
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255)));
|
||||
pScene:addChild(pNewPlayer)
|
||||
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255)))
|
||||
end
|
||||
|
||||
|
||||
|
@ -228,20 +228,20 @@ end
|
|||
function BugTest624_2()
|
||||
local pLayer = cc.Layer:create()
|
||||
|
||||
local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36);
|
||||
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2));
|
||||
pLayer:addChild(pLabel);
|
||||
pLayer:setAccelerometerEnabled(true);
|
||||
local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36)
|
||||
pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2))
|
||||
pLayer:addChild(pLabel)
|
||||
pLayer:setAccelerometerEnabled(true)
|
||||
|
||||
local function BugTest624_2_SwitchLayer()
|
||||
local scheduler = cc.Director:getInstance():getScheduler()
|
||||
scheduler:unscheduleScriptEntry(BugTest624_2_entry)
|
||||
|
||||
local pScene = cc.Scene:create();
|
||||
local pScene = cc.Scene:create()
|
||||
local pNewPlayer = BugTest624()
|
||||
CreateBugsTestBackMenuItem(pNewPlayer)
|
||||
pScene:addChild(pNewPlayer);
|
||||
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0)));
|
||||
pScene:addChild(pNewPlayer)
|
||||
cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0)))
|
||||
end
|
||||
|
||||
local function BugTest624_2_OnEnterOrExit(tag)
|
||||
|
@ -294,65 +294,58 @@ end
|
|||
|
||||
--BugTest914
|
||||
local function BugTest914()
|
||||
local pLayer = cc.Layer:create()
|
||||
local layer = cc.Layer:create()
|
||||
|
||||
pLayer:setTouchEnabled(true);
|
||||
|
||||
local pLayerColor = nil
|
||||
local layerColor = nil
|
||||
|
||||
for i = 0, 4 do
|
||||
pLayerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255))
|
||||
pLayerColor:setContentSize(cc.size(i*100, i*100));
|
||||
pLayerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
|
||||
pLayerColor:setAnchorPoint(cc.p(0.5, 0.5));
|
||||
pLayerColor:ignoreAnchorPointForPosition(false);
|
||||
pLayer:addChild(pLayerColor, -1-i);
|
||||
layerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255))
|
||||
layerColor:setContentSize(cc.size(i*100, i*100))
|
||||
layerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
|
||||
layerColor:setAnchorPoint(cc.p(0.5, 0.5))
|
||||
layerColor:ignoreAnchorPointForPosition(false)
|
||||
layer:addChild(layerColor, -1-i)
|
||||
end
|
||||
|
||||
--create and initialize a Label
|
||||
local function restart()
|
||||
local pScene = cc.Scene:create()
|
||||
local pLayer = BugTest914()
|
||||
CreateBugsTestBackMenuItem(pLayer)
|
||||
pScene:addChild(pLayer);
|
||||
cc.Director:getInstance():replaceScene(pScene)
|
||||
local scene = cc.Scene:create()
|
||||
local newLayer = BugTest914()
|
||||
CreateBugsTestBackMenuItem(newLayer)
|
||||
scene:addChild(newLayer)
|
||||
cc.Director:getInstance():replaceScene(scene)
|
||||
end
|
||||
|
||||
local label = cc.LabelTTF:create("Hello World", "Marker Felt", 64)
|
||||
--position the label on the center of the screen
|
||||
label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 ));
|
||||
pLayer:addChild(label);
|
||||
label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 ))
|
||||
layer:addChild(label)
|
||||
|
||||
local item1 = cc.MenuItemFont:create("restart")
|
||||
item1:registerScriptTapHandler(restart)
|
||||
--Bug914Layer::restart));
|
||||
|
||||
local menu = cc.Menu:create()
|
||||
menu:addChild(item1)
|
||||
menu:alignItemsVertically()
|
||||
menu:setPosition(cc.p(Winsize.width/2, 100))
|
||||
pLayer:addChild(menu)
|
||||
layer:addChild(menu)
|
||||
|
||||
-- handling touch events
|
||||
local function onTouchMoved(tableArray)
|
||||
local nCount = table.getn(tableArray)
|
||||
nCount = math.floor(nCount / 3)
|
||||
print(nCount)
|
||||
local function onTouchMoved(touches, event)
|
||||
local count = table.getn(touches)
|
||||
print("Number of touches: ",count)
|
||||
end
|
||||
local function onTouchBegan(tableArray)
|
||||
onTouchMoved(tableArray)
|
||||
local function onTouchBegan(touches, event)
|
||||
onTouchMoved(touches, event)
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
|
||||
local function onTouch(eventType,tableArray)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(tableArray)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(tableArray)
|
||||
end
|
||||
end
|
||||
pLayer:registerScriptTouchHandler(onTouch,true)
|
||||
return pLayer
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
||||
--BugTest1159
|
||||
|
@ -372,25 +365,25 @@ local function BugTest1159()
|
|||
local seq = cc.Sequence:create(cc.MoveTo:create(1.0, cc.p(1024.0, 384.0)), cc.MoveTo:create(1.0, cc.p(0.0, 384.0)))
|
||||
sprite_a:runAction(cc.RepeatForever:create(seq))
|
||||
|
||||
local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400);
|
||||
local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400)
|
||||
sprite_b:setAnchorPoint(cc.p(0.5, 0.5))
|
||||
sprite_b:ignoreAnchorPointForPosition(false);
|
||||
sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2));
|
||||
pLayer:addChild(sprite_b);
|
||||
sprite_b:ignoreAnchorPointForPosition(false)
|
||||
sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2))
|
||||
pLayer:addChild(sprite_b)
|
||||
|
||||
local function menuCallback()
|
||||
local pScene = cc.Scene:create()
|
||||
local pLayer = BugTest1159()
|
||||
CreateBugsTestBackMenuItem(pLayer)
|
||||
pScene:addChild(pLayer);
|
||||
pScene:addChild(pLayer)
|
||||
cc.Director:getInstance():replaceScene(cc.TransitionPageTurn:create(1.0, pScene, false))
|
||||
end
|
||||
local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24));
|
||||
local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24))
|
||||
label:registerScriptTapHandler(menuCallback)
|
||||
local menu = cc.Menu:create();
|
||||
local menu = cc.Menu:create()
|
||||
menu:addChild(label)
|
||||
menu:setPosition(cc.p(Winsize.width - 200.0, 50.0));
|
||||
pLayer:addChild(menu);
|
||||
menu:setPosition(cc.p(Winsize.width - 200.0, 50.0))
|
||||
pLayer:addChild(menu)
|
||||
|
||||
local function onNodeEvent(event)
|
||||
if event == "exit" then
|
||||
|
@ -436,7 +429,7 @@ local function BugTest1174()
|
|||
local bRet = false
|
||||
|
||||
print("Test1 - Start")
|
||||
local i = 0;
|
||||
local i = 0
|
||||
for i = 0, 9999 do
|
||||
--[[
|
||||
A|b
|
||||
|
@ -490,12 +483,12 @@ local function BugTest1174()
|
|||
--------
|
||||
print("Test2 - Start")
|
||||
|
||||
p1 = cc.p(220,480);
|
||||
p2 = cc.p(304,325);
|
||||
p3 = cc.p(264,416);
|
||||
p4 = cc.p(186,416);
|
||||
s = 0.0;
|
||||
t = 0.0;
|
||||
p1 = cc.p(220,480)
|
||||
p2 = cc.p(304,325)
|
||||
p3 = cc.p(264,416)
|
||||
p4 = cc.p(186,416)
|
||||
s = 0.0
|
||||
t = 0.0
|
||||
bRet,s,t = cc.pIsLineIntersect( p1, p2, p3, p4, s, t)
|
||||
if true == bRet then
|
||||
check_for_error(p1, p2, p3, p4, s, t)
|
||||
|
@ -515,7 +508,7 @@ local function BugTest1174()
|
|||
-- c | d
|
||||
local ax = math.random() * -500
|
||||
local ay = math.random() * 500
|
||||
p1 = cc.p(ax,ay);
|
||||
p1 = cc.p(ax,ay)
|
||||
-- a | b
|
||||
-- -----
|
||||
-- c | D
|
||||
|
@ -579,7 +572,7 @@ end
|
|||
|
||||
|
||||
local function BugsTestMainLayer()
|
||||
local ret = cc.Layer:create();
|
||||
local ret = cc.Layer:create()
|
||||
|
||||
--menu callback
|
||||
local function menuCallback(tag, pMenuItem)
|
||||
|
@ -591,8 +584,8 @@ local function BugsTestMainLayer()
|
|||
end
|
||||
|
||||
-- add menu items for tests
|
||||
local pItemMenu = cc.Menu:create();
|
||||
local nTestCount = table.getn(testNames);
|
||||
local pItemMenu = cc.Menu:create()
|
||||
local nTestCount = table.getn(testNames)
|
||||
|
||||
local i = 1
|
||||
for i = 1, nTestCount do
|
||||
|
@ -605,19 +598,15 @@ local function BugsTestMainLayer()
|
|||
|
||||
pItemMenu:setPosition(cc.p(0, 0))
|
||||
ret:addChild(pItemMenu)
|
||||
ret:setTouchEnabled(true)
|
||||
|
||||
-- handling touch events
|
||||
local ptBeginPos = {x = 0, y = 0}
|
||||
local ptCurPos = {x = 0, y = 0}
|
||||
local function onTouchBegan(x, y)
|
||||
ptBeginPos = {x = x, y = y}
|
||||
-- cc.TOUCHBEGAN event must return true
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchMoved(x, y)
|
||||
local nMoveY = y - ptBeginPos.y
|
||||
|
||||
-- handling touch events
|
||||
local function onTouchMoved(touches, event)
|
||||
local touchLocation = touches[1]:getLocation()
|
||||
local nMoveY = touchLocation.y - ptBeginPos.y
|
||||
local curPosx, curPosy = pItemMenu:getPosition()
|
||||
local nextPosy = curPosy + nMoveY
|
||||
if nextPosy < 0 then
|
||||
|
@ -631,26 +620,25 @@ local function BugsTestMainLayer()
|
|||
end
|
||||
|
||||
pItemMenu:setPosition(curPosx, nextPosy)
|
||||
ptBeginPos = {x = x, y = y}
|
||||
ptBeginPos = touchLocation
|
||||
ptCurPos = {x = curPosx, y = nextPosy}
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x, y)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(x, y)
|
||||
end
|
||||
local function onTouchBegan(touches, event)
|
||||
ptBeginPos = touches[1]:getLocation()
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
|
||||
ret:registerScriptTouchHandler(onTouch)
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
|
||||
return ret
|
||||
end
|
||||
function BugsTestMain()
|
||||
cclog("BugsTestMain");
|
||||
local scene = cc.Scene:create();
|
||||
scene:addChild(BugsTestMainLayer());
|
||||
scene:addChild(CreateBackMenuItem());
|
||||
return scene;
|
||||
cclog("BugsTestMain")
|
||||
local scene = cc.Scene:create()
|
||||
scene:addChild(BugsTestMainLayer())
|
||||
scene:addChild(CreateBackMenuItem())
|
||||
return scene
|
||||
end
|
||||
|
|
|
@ -17,13 +17,20 @@ local function initWithLayer()
|
|||
cc.FadeIn:create(1),
|
||||
cc.FadeOut:create(1))))
|
||||
|
||||
local function onTouchEnded(x, y)
|
||||
local function onTouchBegan(touch, event)
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchEnded(touch, event)
|
||||
|
||||
local location = touch:getLocation()
|
||||
|
||||
local s = layer:getChildByTag(kTagSprite)
|
||||
s:stopAllActions()
|
||||
s:runAction(cc.MoveTo:create(1, cc.p(x, y)))
|
||||
s:runAction(cc.MoveTo:create(1, cc.p(location.x, location.y)))
|
||||
local posX, posY = s:getPosition()
|
||||
local o = x - posX
|
||||
local a = y - posY
|
||||
local o = location.x - posX
|
||||
local a = location.y - posY
|
||||
local at = math.atan(o / a) / math.pi * 180.0
|
||||
|
||||
if a < 0 then
|
||||
|
@ -36,16 +43,11 @@ local function initWithLayer()
|
|||
s:runAction(cc.RotateTo:create(1, at))
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
elseif eventType == "ended" then
|
||||
return onTouchEnded(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(onTouch)
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
|
|
@ -812,7 +812,6 @@ function TestParticleDisplay.extend(target)
|
|||
end
|
||||
|
||||
function TestParticleDisplay:onEnter()
|
||||
self:setTouchEnabled(true)
|
||||
self.animationID = 0
|
||||
|
||||
self.armature = ccs.Armature:create("robot")
|
||||
|
@ -840,19 +839,17 @@ function TestParticleDisplay:onEnter()
|
|||
bone:setScale(1.2)
|
||||
self.armature:addBone(bone, "bady-a30")
|
||||
|
||||
local function onTouchBegan(x, y)
|
||||
-- handling touch events
|
||||
local function onTouchEnded(touches, event)
|
||||
self.animationID = (self.animationID + 1) % self.armature:getAnimation():getMovementCount()
|
||||
self.armature:getAnimation():playWithIndex(self.animationID)
|
||||
return false
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x,y)
|
||||
end
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
self:registerScriptTouchHandler(onTouch)
|
||||
local eventDispatcher = self:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
|
||||
end
|
||||
|
||||
function TestParticleDisplay.create()
|
||||
|
@ -889,7 +886,6 @@ function TestUseMutiplePicture.extend(target)
|
|||
end
|
||||
|
||||
function TestUseMutiplePicture:onEnter()
|
||||
self:setTouchEnabled(true)
|
||||
self.displayIndex = 1
|
||||
|
||||
self.armature = ccs.Armature:create("Knight_f/Knight")
|
||||
|
@ -915,19 +911,17 @@ function TestUseMutiplePicture:onEnter()
|
|||
self.armature:getBone("weapon"):addDisplay(skin, i - 1)
|
||||
end
|
||||
|
||||
local function onTouchBegan(x, y)
|
||||
-- handling touch events
|
||||
local function onTouchEnded(touches, event)
|
||||
self.displayIndex = (self.displayIndex + 1) % (table.getn(weapon) - 1)
|
||||
self.armature:getBone("weapon"):changeDisplayWithIndex(self.displayIndex, true)
|
||||
return false
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x,y)
|
||||
end
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
self:registerScriptTouchHandler(onTouch)
|
||||
local eventDispatcher = self:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
|
||||
end
|
||||
|
||||
function TestUseMutiplePicture.create()
|
||||
|
@ -1012,7 +1006,6 @@ function TestArmatureNesting.extend(target)
|
|||
end
|
||||
|
||||
function TestArmatureNesting:onEnter()
|
||||
self:setTouchEnabled(true)
|
||||
self.weaponIndex = 0
|
||||
|
||||
self.armature = ccs.Armature:create("cyborg")
|
||||
|
@ -1022,20 +1015,18 @@ function TestArmatureNesting:onEnter()
|
|||
self.armature:getAnimation():setSpeedScale(0.4)
|
||||
self:addChild(self.armature)
|
||||
|
||||
local function onTouchBegan(x, y)
|
||||
-- handling touch events
|
||||
local function onTouchEnded(touches, event)
|
||||
self.weaponIndex = (self.weaponIndex + 1) % 4
|
||||
self.armature:getBone("armInside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex)
|
||||
self.armature:getBone("armOutside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex)
|
||||
return false
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x,y)
|
||||
end
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
self:registerScriptTouchHandler(onTouch)
|
||||
local eventDispatcher = self:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
|
||||
end
|
||||
|
||||
function TestArmatureNesting.create()
|
||||
|
@ -1131,30 +1122,26 @@ function TestArmatureNesting2.extend(target)
|
|||
end
|
||||
|
||||
function TestArmatureNesting2:onEnter()
|
||||
|
||||
self:setTouchEnabled(true)
|
||||
|
||||
local function onTouchesEnded(tableArray)
|
||||
local x,y = tableArray[1],tableArray[2]
|
||||
-- handling touch events
|
||||
local function onTouchEnded(touches, event)
|
||||
local location = touches[1]:getLocation()
|
||||
local armature = self._hero._mount and self._hero._mount or self._hero
|
||||
if x < armature:getPositionX() then
|
||||
if location.x < armature:getPositionX() then
|
||||
armature:setScaleX(-1)
|
||||
else
|
||||
armature:setScaleX(1)
|
||||
end
|
||||
|
||||
local move = cc.MoveTo:create(2, cc.p(x,y))
|
||||
local move = cc.MoveTo:create(2, location)
|
||||
armature:stopAllActions()
|
||||
armature:runAction(cc.Sequence:create(move))
|
||||
end
|
||||
|
||||
local function onTouch(eventType, tableArray)
|
||||
if eventType == "ended" then
|
||||
return onTouchesEnded(tableArray)
|
||||
end
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
self:registerScriptTouchHandler(onTouch,true)
|
||||
local eventDispatcher = self:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)
|
||||
|
||||
local function changeMountCallback(sender)
|
||||
self._hero:stopAllActions()
|
||||
|
|
|
@ -108,7 +108,6 @@ local function CocosDenshionTest()
|
|||
m_pItmeMenu:setContentSize(cc.size(VisibleRect:getVisibleRect().width, (m_nTestCount + 1) * LINE_SPACE))
|
||||
m_pItmeMenu:setPosition(cc.p(0, 0))
|
||||
ret:addChild(m_pItmeMenu)
|
||||
ret:setTouchEnabled(true)
|
||||
|
||||
-- preload background music and effect
|
||||
AudioEngine.preloadMusic( MUSIC_FILE )
|
||||
|
@ -159,7 +158,46 @@ local function CocosDenshionTest()
|
|||
end
|
||||
end
|
||||
|
||||
ret:registerScriptTouchHandler(onTouchEvent)
|
||||
local function onTouchBegan(touch, event)
|
||||
local location = touch:getLocation()
|
||||
prev.x = location.x
|
||||
prev.y = location.y
|
||||
m_tBeginPos = location
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchMoved(touch, event)
|
||||
local location = touch:getLocation()
|
||||
local touchLocation = location
|
||||
local nMoveY = touchLocation.y - m_tBeginPos.y
|
||||
local curPosX, curPosY = m_pItmeMenu:getPosition()
|
||||
local curPos = cc.p(curPosX, curPosY)
|
||||
local nextPos = cc.p(curPos.x, curPos.y + nMoveY)
|
||||
|
||||
if nextPos.y < 0.0 then
|
||||
m_pItmeMenu:setPosition(cc.p(0, 0))
|
||||
end
|
||||
|
||||
if nextPos.y > ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height) then
|
||||
m_pItmeMenu:setPosition(cc.p(0, ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height)))
|
||||
end
|
||||
|
||||
m_pItmeMenu:setPosition(nextPos)
|
||||
m_tBeginPos.x = touchLocation.x
|
||||
m_tBeginPos.y = touchLocation.y
|
||||
|
||||
prev.x = location.x
|
||||
prev.y = location.y
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:setSwallowTouches(true)
|
||||
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
|
|
|
@ -1239,14 +1239,15 @@ local function ExtensionsMainLayer()
|
|||
layer:addChild(menu)
|
||||
|
||||
-- handling touch events
|
||||
local beginPos = {x = 0, y = 0}
|
||||
local function onTouchBegan(x, y)
|
||||
beginPos = {x = x, y = y}
|
||||
return true
|
||||
local beginPos = {x = 0, y = 0}
|
||||
local function onTouchesBegan(touches, event)
|
||||
beginPos = touches[1]:getLocation()
|
||||
end
|
||||
|
||||
local function onTouchMoved(x, y)
|
||||
local nMoveY = y - beginPos.y
|
||||
local function onTouchesMoved(touches, event)
|
||||
local location = touches[1]:getLocation()
|
||||
|
||||
local nMoveY = location.y - beginPos.y
|
||||
local curPosx, curPosy = menu:getPosition()
|
||||
local nextPosy = curPosy + nMoveY
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
|
@ -1261,20 +1262,15 @@ local function ExtensionsMainLayer()
|
|||
end
|
||||
|
||||
menu:setPosition(curPosx, nextPosy)
|
||||
beginPos = {x = x, y = y}
|
||||
beginPos = {x = location.x, y = location.y}
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x, y)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(x, y)
|
||||
end
|
||||
end
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
|
||||
layer:registerScriptTouchHandler(onTouch)
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
|
|
@ -1,31 +1,42 @@
|
|||
local function KeypadMainLayer()
|
||||
local pLayer = cc.Layer:create()
|
||||
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local label = cc.LabelTTF:create("Keypad Test", "Arial", 28)
|
||||
pLayer:addChild(label, 0)
|
||||
label:setPosition( cc.p(s.width/2, s.height-50) )
|
||||
local layer = cc.Layer:create()
|
||||
|
||||
pLayer:setKeypadEnabled(true)
|
||||
local function onEnter()
|
||||
print("come in")
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local label = cc.LabelTTF:create("Keypad Test", "Arial", 28)
|
||||
layer:addChild(label, 0)
|
||||
label:setPosition(cc.p(s.width/2, s.height-50))
|
||||
|
||||
-- create a label to display the tip string
|
||||
local pLabelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22)
|
||||
pLabelTip:setPosition(cc.p(s.width / 2, s.height / 2))
|
||||
pLayer:addChild(pLabelTip, 0)
|
||||
|
||||
pLabelTip:retain()
|
||||
|
||||
local function KeypadHandler(strEvent)
|
||||
if "backClicked" == strEvent then
|
||||
pLabelTip:setString("BACK clicked!");
|
||||
elseif "menuClicked" == strEvent then
|
||||
pLabelTip:setString("MENU clicked!");
|
||||
end
|
||||
local labelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22)
|
||||
labelTip:setPosition(cc.p(s.width / 2, s.height / 2))
|
||||
layer:addChild(labelTip, 0)
|
||||
|
||||
local function onKeyReleased(keyCode, event)
|
||||
local label = event:getCurrentTarget()
|
||||
if keyCode == cc.KeyCode.KEY_BACKSPACE then
|
||||
label:setString("BACK clicked!")
|
||||
elseif keyCode == cc.KeyCode.KEY_MENU then
|
||||
label:setString("MENU clicked!")
|
||||
end
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerKeyboard:create()
|
||||
listener:registerScriptHandler(onKeyReleased, cc.Handler.EVENT_KEYBOARD_RELEASED )
|
||||
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, labelTip)
|
||||
end
|
||||
|
||||
pLayer:registerScriptKeypadHandler(KeypadHandler)
|
||||
|
||||
return pLayer
|
||||
|
||||
local function onNodeEvent(event)
|
||||
if event == "enter" then
|
||||
onEnter()
|
||||
end
|
||||
end
|
||||
|
||||
layer:registerScriptHandler(onNodeEvent)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -992,8 +992,6 @@ function BitmapFontMultiLineAlignment.create()
|
|||
local layer = cc.Layer:create()
|
||||
Helper.initWithLayer(layer)
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
|
||||
-- ask director the the window size
|
||||
local size = cc.Director:getInstance():getWinSize()
|
||||
|
||||
|
@ -1068,7 +1066,44 @@ function BitmapFontMultiLineAlignment.create()
|
|||
layer:addChild(stringMenu)
|
||||
layer:addChild(alignmentMenu)
|
||||
layer:registerScriptHandler(BitmapFontMultiLineAlignment.onNodeEvent)
|
||||
layer:registerScriptTouchHandler(BitmapFontMultiLineAlignment.onTouchEvent)
|
||||
|
||||
local function onTouchesBegan(touches, event)
|
||||
local location = touches[1]:getLocationInView()
|
||||
if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), location) then
|
||||
BitmapFontMultiLineAlignment._drag = true
|
||||
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchesMoved(touches, event)
|
||||
if BitmapFontMultiLine._drag == false then
|
||||
return
|
||||
end
|
||||
local location = touches[1]:getLocationInView()
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
|
||||
BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY())
|
||||
|
||||
local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
|
||||
|
||||
BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
|
||||
end
|
||||
|
||||
local function onTouchesEnded(touch, event)
|
||||
BitmapFontMultiLineAlignment._drag = false
|
||||
BitmapFontMultiLineAlignment.snapArrowsToEdge()
|
||||
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
||||
|
@ -1118,35 +1153,6 @@ function BitmapFontMultiLineAlignment.alignmentChanged(tag, sender)
|
|||
BitmapFontMultiLineAlignment.snapArrowsToEdge()
|
||||
end
|
||||
|
||||
function BitmapFontMultiLineAlignment.onTouchEvent(eventType, x, y)
|
||||
-- cclog("type:"..eventType.."["..x..","..y.."]")
|
||||
if eventType == "began" then
|
||||
if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then
|
||||
BitmapFontMultiLineAlignment._drag = true
|
||||
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
|
||||
return true
|
||||
end
|
||||
elseif eventType == "ended" then
|
||||
BitmapFontMultiLineAlignment._drag = false
|
||||
BitmapFontMultiLineAlignment.snapArrowsToEdge()
|
||||
BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
|
||||
elseif eventType == "moved" then
|
||||
if BitmapFontMultiLine._drag == false then
|
||||
return
|
||||
end
|
||||
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
|
||||
BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY())
|
||||
|
||||
local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
|
||||
|
||||
BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function BitmapFontMultiLineAlignment.snapArrowsToEdge()
|
||||
BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX() + BitmapFontMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionY()
|
||||
|
|
|
@ -596,9 +596,6 @@ local LabelFNTMultiLineAlignment = {
|
|||
function LabelFNTMultiLineAlignment.create()
|
||||
local layer = cc.Layer:create()
|
||||
Helper.initWithLayer(layer)
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
|
||||
-- ask director the the window size
|
||||
local size = cc.Director:getInstance():getWinSize()
|
||||
|
||||
|
@ -674,7 +671,46 @@ function LabelFNTMultiLineAlignment.create()
|
|||
layer:addChild(stringMenu)
|
||||
layer:addChild(alignmentMenu)
|
||||
layer:registerScriptHandler(LabelFNTMultiLineAlignment.onNodeEvent)
|
||||
layer:registerScriptTouchHandler(LabelFNTMultiLineAlignment.onTouchEvent)
|
||||
|
||||
local function onTouchesBegan(touches, event)
|
||||
local location = touches[1]:getLocationInView()
|
||||
if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(location.x, location.y)) then
|
||||
LabelFNTMultiLineAlignment._drag = true
|
||||
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchesMoved(touches, event)
|
||||
if LabelFNTMultiLineAlignment._drag == false then
|
||||
return
|
||||
end
|
||||
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
local location = touches[1]:getLocationInView()
|
||||
|
||||
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
|
||||
LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY())
|
||||
|
||||
local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
|
||||
|
||||
LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
|
||||
end
|
||||
|
||||
local function onTouchesEnded(touch, event)
|
||||
LabelFNTMultiLineAlignment._drag = false
|
||||
LabelFNTMultiLineAlignment.snapArrowsToEdge()
|
||||
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
|
||||
|
@ -724,35 +760,6 @@ function LabelFNTMultiLineAlignment.alignmentChanged(tag, sender)
|
|||
LabelFNTMultiLineAlignment.snapArrowsToEdge()
|
||||
end
|
||||
|
||||
function LabelFNTMultiLineAlignment.onTouchEvent(eventType, x, y)
|
||||
-- cclog("type:"..eventType.."["..x..","..y.."]")
|
||||
if eventType == "began" then
|
||||
if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then
|
||||
LabelFNTMultiLineAlignment._drag = true
|
||||
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true)
|
||||
return true
|
||||
end
|
||||
elseif eventType == "ended" then
|
||||
LabelFNTMultiLineAlignment._drag = false
|
||||
LabelFNTMultiLineAlignment.snapArrowsToEdge()
|
||||
LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false)
|
||||
elseif eventType == "moved" then
|
||||
if LabelFNTMultiLineAlignment._drag == false then
|
||||
return
|
||||
end
|
||||
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width),
|
||||
LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY())
|
||||
|
||||
local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2
|
||||
|
||||
LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function LabelFNTMultiLineAlignment.snapArrowsToEdge()
|
||||
LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition(
|
||||
LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX() + LabelFNTMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionY()
|
||||
|
|
|
@ -302,8 +302,6 @@ end
|
|||
local function LayerTest1()
|
||||
local ret = createLayerDemoLayer("ColorLayer resize (tap & move)")
|
||||
|
||||
ret:setTouchEnabled(true)
|
||||
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local layer = cc.LayerColor:create( cc.c4b(0xFF, 0x00, 0x00, 0x80), 200, 200)
|
||||
|
||||
|
@ -321,15 +319,23 @@ local function LayerTest1()
|
|||
l:setContentSize( newSize )
|
||||
end
|
||||
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
updateSize(x, y)
|
||||
return true
|
||||
else
|
||||
updateSize(x, y)
|
||||
end
|
||||
local function onTouchesMoved(touches, event)
|
||||
local touchLocation = touches[1]:getLocation()
|
||||
|
||||
updateSize(touchLocation.x, touchLocation.y)
|
||||
end
|
||||
ret:registerScriptTouchHandler(onTouchEvent)
|
||||
|
||||
local function onTouchesBegan(touches, event)
|
||||
onTouchesMoved(touches, event)
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
|
@ -430,8 +436,6 @@ local function LayerGradient()
|
|||
local layer1 = cc.LayerGradient:create(cc.c4b(255,0,0,255), cc.c4b(0,255,0,255), cc.p(0.9, 0.9))
|
||||
ret:addChild(layer1, 0, kTagLayer)
|
||||
|
||||
ret:setTouchEnabled(true)
|
||||
|
||||
local label1 = cc.LabelTTF:create("Compressed Interpolation: Enabled", "Marker Felt", 26)
|
||||
local label2 = cc.LabelTTF:create("Compressed Interpolation: Disabled", "Marker Felt", 26)
|
||||
local item1 = cc.MenuItemLabel:create(label1)
|
||||
|
@ -452,22 +456,23 @@ local function LayerGradient()
|
|||
local s = cc.Director:getInstance():getWinSize()
|
||||
menu:setPosition(cc.p(s.width / 2, 100))
|
||||
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local start = cc.p(x, y)
|
||||
local movingPos = cc.p(s.width/2,s.height/2)
|
||||
local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y)
|
||||
diff = cc.pNormalize(diff)
|
||||
local function onTouchesMoved(touches, event)
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local start = touches[1]:getLocation()
|
||||
local movingPos = cc.p(s.width/2,s.height/2)
|
||||
local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y)
|
||||
diff = cc.pNormalize(diff)
|
||||
|
||||
local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient")
|
||||
gradient:setVector(diff)
|
||||
end
|
||||
local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient")
|
||||
gradient:setVector(diff)
|
||||
end
|
||||
|
||||
ret:registerScriptTouchHandler(onTouchEvent)
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@ local function MenuLayerMainMenu()
|
|||
local m_disabledItem = nil
|
||||
|
||||
local ret = cc.Layer:create()
|
||||
ret:setTouchEnabled(true)
|
||||
ret:setTouchMode(cc.TOUCHES_ONE_BY_ONE )
|
||||
|
||||
-- Font Item
|
||||
local spriteNormal = cc.Sprite:create(s_MenuItem, cc.rect(0,23*2,115,23))
|
||||
|
@ -542,32 +540,32 @@ local function RemoveMenuItemWhenMove()
|
|||
|
||||
menu:setPosition(cc.p(s.width/2, s.height/2))
|
||||
|
||||
ret:setTouchEnabled(true)
|
||||
--[[
|
||||
local function onTouchBegan(touch, event)
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchMoved(touch, event)
|
||||
if item ~= nil then
|
||||
item:removeFromParent(true)
|
||||
--item:release()
|
||||
--item = nil
|
||||
end
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithFixedPriority(listener, -129)
|
||||
|
||||
local function onNodeEvent(event)
|
||||
if event == "enter" then
|
||||
cc.Director:getInstance():getTouchDispatcher():addTargetedDelegate(ret, -129, false)
|
||||
elseif event == "exit" then
|
||||
-- item:release()
|
||||
if event == "exit" then
|
||||
ret:getEventDispatcher():removeEventListener(listener)
|
||||
end
|
||||
end
|
||||
|
||||
ret:registerScriptHandler(onNodeEvent)
|
||||
]]--
|
||||
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
if item ~= nil then
|
||||
item:removeFromParent(true)
|
||||
--item:release()
|
||||
--item = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ret:registerScriptTouchHandler(onTouchEvent,false,-129,false)
|
||||
return ret
|
||||
end
|
||||
|
||||
|
|
|
@ -106,28 +106,17 @@ local function MotionStreakTest2()
|
|||
|
||||
streak:setPosition(cc.p(s.width / 2, s.height / 2))
|
||||
|
||||
local function onTouchMoved(x, y)
|
||||
if firstTick == true then
|
||||
firstTick = false
|
||||
return
|
||||
end
|
||||
|
||||
streak:setPosition(cc.p(x, y))
|
||||
local function onTouchesMoved(touches, event)
|
||||
streak:setPosition( touches[1]:getLocation() )
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
firstTick = true
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(onTouch)
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
Helper.titleLabel:setString("MotionStreak test")
|
||||
|
||||
return layer
|
||||
end
|
||||
|
||||
|
|
|
@ -569,27 +569,25 @@ local function ConvertToNode()
|
|||
ConvertToNode_layer:addChild(sprite, i)
|
||||
end
|
||||
|
||||
local function onTouchEnded(x, y)
|
||||
for i = 0, 2 do
|
||||
local node = ConvertToNode_layer:getChildByTag(100 + i)
|
||||
local p1, p2
|
||||
p1 = node:convertToNodeSpaceAR(cc.p(x, y))
|
||||
p2 = node:convertToNodeSpace(cc.p(x, y))
|
||||
local function onTouchesEnded(touches, event)
|
||||
local count = table.getn(touches)
|
||||
for i = 1, count do
|
||||
local location = touches[i]:getLocation()
|
||||
for j = 1,3 do
|
||||
local node = ConvertToNode_layer:getChildByTag(100 + i - 1)
|
||||
local p1, p2
|
||||
p1 = node:convertToNodeSpaceAR(location)
|
||||
p2 = node:convertToNodeSpace(location)
|
||||
|
||||
cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y)
|
||||
cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
elseif eventType == "ended" then
|
||||
return onTouchEnded(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
ConvertToNode_layer:setTouchEnabled(true)
|
||||
ConvertToNode_layer:registerScriptTouchHandler(onTouch)
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
local eventDispatcher = ConvertToNode_layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ConvertToNode_layer)
|
||||
|
||||
Helper.titleLabel:setString("Convert To Node Space")
|
||||
Helper.subtitleLabel:setString("testing convertToNodeSpace / AR. Touch and see console")
|
||||
|
|
|
@ -83,7 +83,6 @@ end
|
|||
|
||||
local function Parallax2()
|
||||
local ret = createParallaxLayer("Parallax: drag screen")
|
||||
ret:setTouchEnabled( true )
|
||||
|
||||
-- Top Layer, a simple image
|
||||
local cocosImage = cc.Sprite:create(s_Power)
|
||||
|
@ -126,25 +125,19 @@ local function Parallax2()
|
|||
-- top image is moved at a ratio of 3.0x, 2.5y
|
||||
voidNode:addChild( cocosImage, 2, cc.p(3.0,2.5), cc.p(200,1000) )
|
||||
ret:addChild(voidNode, 0, kTagNode)
|
||||
local prev = {x = 0, y = 0}
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
local node = ret:getChildByTag(kTagNode)
|
||||
local newX = node:getPositionX()
|
||||
local newY = node:getPositionY()
|
||||
local diffX = x - prev.x
|
||||
local diffY = y - prev.y
|
||||
|
||||
node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) )
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
end
|
||||
local function onTouchesMoved(touches, event)
|
||||
local diff = touches[1]:getDelta()
|
||||
|
||||
local node = ret:getChildByTag(kTagNode)
|
||||
local currentPosX, currentPosY = node:getPosition()
|
||||
node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y))
|
||||
end
|
||||
ret:registerScriptTouchHandler(onTouchEvent)
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
|
|
@ -147,28 +147,34 @@ local function getBaseLayer()
|
|||
local seq = cc.Sequence:create(move, move_back)
|
||||
background:runAction(cc.RepeatForever:create(seq))
|
||||
|
||||
local function onTouchEnded(x, y)
|
||||
local pos = cc.p(0, 0)
|
||||
if background ~= nil then
|
||||
pos = background:convertToWorldSpace(cc.p(0, 0))
|
||||
end
|
||||
local function onTouchesEnded(touches, event)
|
||||
local location = touches[1]:getLocation()
|
||||
local pos = cc.p(0, 0)
|
||||
if background ~= nil then
|
||||
pos = background:convertToWorldSpace(cc.p(0, 0))
|
||||
end
|
||||
|
||||
if emitter ~= nil then
|
||||
local newPos = cc.pSub(cc.p(x, y), pos)
|
||||
emitter:setPosition(newPos.x, newPos.y)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return true
|
||||
else
|
||||
return onTouchEnded(x, y)
|
||||
if emitter ~= nil then
|
||||
local newPos = cc.pSub(location, pos)
|
||||
emitter:setPosition(newPos.x, newPos.y)
|
||||
end
|
||||
end
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(onTouch)
|
||||
local function onTouchesBegan(touches, event)
|
||||
onTouchesEnded(touches, event);
|
||||
end
|
||||
|
||||
local function onTouchesMoved(touches, event)
|
||||
onTouchesEnded(touches, event);
|
||||
end
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
layer:registerScriptHandler(baseLayer_onEnterOrExit)
|
||||
|
||||
return layer
|
||||
|
|
|
@ -1353,6 +1353,9 @@ local function runTextureTest()
|
|||
local time
|
||||
local pTexture = nil
|
||||
local pCache = cc.Director:getInstance():getTextureCache()
|
||||
|
||||
local pDefaultFormat = cc.Texture2D:getDefaultAlphaPixelFormat();
|
||||
|
||||
print("RGBA 8888")
|
||||
cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
|
||||
pTexture = pCache:addImage(strFileName)
|
||||
|
@ -1397,6 +1400,8 @@ local function runTextureTest()
|
|||
print(" ERROR")
|
||||
end
|
||||
pCache:removeTexture(pTexture)
|
||||
|
||||
cc.Texture2D:setDefaultAlphaPixelFormat(pDefaultFormat)
|
||||
end
|
||||
local function PerformTests()
|
||||
print("--------")
|
||||
|
@ -1548,48 +1553,37 @@ local function runTouchesTest()
|
|||
end
|
||||
|
||||
-- handling touch events
|
||||
local function onTouchBegan(tableArray)
|
||||
if 0 == nCurCase then
|
||||
nNumberOfTouchesB = nNumberOfTouchesB + 1
|
||||
elseif 1 == nCurCase then
|
||||
nNumberOfTouchesB = nNumberOfTouchesB + table.getn(tableArray)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchMoved(tableArray)
|
||||
if 0 == nCurCase then
|
||||
nNumberOfTouchesM = nNumberOfTouchesM + 1
|
||||
elseif 1 == nCurCase then
|
||||
nNumberOfTouchesM = nNumberOfTouchesM + table.getn(tableArray)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchEnded(tableArray)
|
||||
if 0 == nCurCase then
|
||||
nNumberOfTouchesE = nNumberOfTouchesE + 1
|
||||
elseif 1 == nCurCase then
|
||||
nNumberOfTouchesE = nNumberOfTouchesE + table.getn(tableArray)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTouchCancelled(tableArray)
|
||||
if 0 == nCurCase then
|
||||
nNumberOfTouchesC = nNumberOfTouchesC + 1
|
||||
elseif 1 == nCurCase then
|
||||
nNumberOfTouchesC = nNumberOfTouchesC + table.getn(tableArray)
|
||||
end
|
||||
local function onTouchEnded(touch, event)
|
||||
nNumberOfTouchesE = nNumberOfTouchesE + 1
|
||||
end
|
||||
|
||||
local function onTouch(eventType,tableArray)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(tableArray)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(tableArray)
|
||||
elseif eventType == "ended" then
|
||||
return onTouchEnded(tableArray)
|
||||
elseif eventType == "cancelled" then
|
||||
return onTouchCancelled(tableArray)
|
||||
end
|
||||
local function onTouchBegan(touch, event)
|
||||
nNumberOfTouchesB = nNumberOfTouchesB + 1
|
||||
end
|
||||
|
||||
local function onTouchMoved(touch, event)
|
||||
nNumberOfTouchesM = nNumberOfTouchesM + 1
|
||||
end
|
||||
|
||||
local function onTouchCancelled(touch, event)
|
||||
nNumberOfTouchesC = nNumberOfTouchesC + 1
|
||||
end
|
||||
|
||||
|
||||
local function onTouchesEnded(touches, event)
|
||||
nNumberOfTouchesE = nNumberOfTouchesE + table.getn(touches)
|
||||
end
|
||||
|
||||
local function onTouchesBegan(touches, event)
|
||||
nNumberOfTouchesB = nNumberOfTouchesB + table.getn(touches)
|
||||
end
|
||||
|
||||
local function onTouchesMoved(touches, event)
|
||||
nNumberOfTouchesM = nNumberOfTouchesM + table.getn(touches)
|
||||
end
|
||||
|
||||
local function onTouchesCancelled(touches, event)
|
||||
nNumberOfTouchesC= nNumberOfTouchesC + table.getn(touches)
|
||||
end
|
||||
|
||||
local function InitLayer()
|
||||
|
@ -1617,9 +1611,24 @@ local function runTouchesTest()
|
|||
nNumberOfTouchesM = 0
|
||||
nNumberOfTouchesE = 0
|
||||
nNumberOfTouchesC = 0
|
||||
pLayer:setTouchEnabled(true)
|
||||
|
||||
pLayer:registerScriptTouchHandler(onTouch,true)
|
||||
|
||||
if 0 == nCurCase then
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
|
||||
listener:registerScriptHandler(onTouchCancelled,cc.Handler.EVENT_TOUCH_CANCELLED )
|
||||
local eventDispatcher = pLayer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer)
|
||||
elseif 1 == nCurCase then
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN )
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
listener:registerScriptHandler(onTouchesCancelled,cc.Handler.EVENT_TOUCHES_CANCELLED )
|
||||
local eventDispatcher = pLayer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer)
|
||||
end
|
||||
end
|
||||
|
||||
function ShowCurrentTest()
|
||||
|
|
|
@ -8,22 +8,21 @@ local function RenderTextureSave()
|
|||
local ret = createTestLayer("Touch the screen",
|
||||
"Press 'Save Image' to create an snapshot of the render texture")
|
||||
local s = cc.Director:getInstance():getWinSize()
|
||||
local m_pTarget = nil
|
||||
local m_pBrush = nil
|
||||
local m_pTarget = nil
|
||||
local target = nil
|
||||
local counter = 0
|
||||
local brushes = {}
|
||||
local function clearImage(tag, pSender)
|
||||
m_pTarget:clear(math.random(), math.random(), math.random(), math.random())
|
||||
target:clear(math.random(), math.random(), math.random(), math.random())
|
||||
end
|
||||
|
||||
local function saveImage(tag, pSender)
|
||||
local png = string.format("image-%d.png", counter)
|
||||
local jpg = string.format("image-%d.jpg", counter)
|
||||
|
||||
m_pTarget:saveToFile(png, cc.IMAGE_FORMAT_PNG)
|
||||
m_pTarget:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG)
|
||||
target:saveToFile(png, cc.IMAGE_FORMAT_PNG)
|
||||
target:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG)
|
||||
|
||||
local pImage = m_pTarget:newImage()
|
||||
local pImage = target:newImage()
|
||||
|
||||
local tex = cc.Director:getInstance():getTextureCache():addUIImage(pImage, png)
|
||||
|
||||
|
@ -42,8 +41,7 @@ local function RenderTextureSave()
|
|||
|
||||
local function onNodeEvent(event)
|
||||
if event == "exit" then
|
||||
m_pBrush:release()
|
||||
m_pTarget:release()
|
||||
target:release()
|
||||
cc.Director:getInstance():getTextureCache():removeUnusedTextures()
|
||||
end
|
||||
end
|
||||
|
@ -51,69 +49,58 @@ local function RenderTextureSave()
|
|||
ret:registerScriptHandler(onNodeEvent)
|
||||
|
||||
-- create a render texture, this is what we are going to draw into
|
||||
m_pTarget = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
|
||||
m_pTarget:retain()
|
||||
m_pTarget:setPosition(cc.p(s.width / 2, s.height / 2))
|
||||
target = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
|
||||
target:retain()
|
||||
target:setPosition(cc.p(s.width / 2, s.height / 2))
|
||||
|
||||
-- note that the render texture is a cc.Node, and contains a sprite of its texture for convience,
|
||||
-- so we can just parent it to the scene like any other cc.Node
|
||||
ret:addChild(m_pTarget, -1)
|
||||
ret:addChild(target, -1)
|
||||
|
||||
-- create a brush image to draw into the texture with
|
||||
m_pBrush = cc.Sprite:create("Images/fire.png")
|
||||
m_pBrush:retain()
|
||||
m_pBrush:setColor(cc.c3b(255, 0, 0))
|
||||
m_pBrush:setOpacity(20)
|
||||
local function onTouchesMoved(touches, event)
|
||||
local start = touches[1]:getLocation()
|
||||
local ended = touches[1]:getPreviousLocation()
|
||||
|
||||
target:begin()
|
||||
|
||||
local prev = {x = 0, y = 0}
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
local diffX = x - prev.x
|
||||
local diffY = y - prev.y
|
||||
local distance = cc.pGetDistance(start, ended)
|
||||
if distance > 1 then
|
||||
brushes = {}
|
||||
local d = distance
|
||||
local i = 0
|
||||
|
||||
local startP = cc.p(x, y)
|
||||
local endP = cc.p(prev.x, prev.y)
|
||||
|
||||
-- begin drawing to the render texture
|
||||
m_pTarget:begin()
|
||||
|
||||
-- for extra points, we'll draw this smoothly from the last position and vary the sprite's
|
||||
-- scale/rotation/offset
|
||||
local distance = cc.pGetDistance(startP, endP)
|
||||
if distance > 1 then
|
||||
local d = distance
|
||||
local i = 0
|
||||
for i = 0, d-1 do
|
||||
local difx = endP.x - startP.x
|
||||
local dify = endP.y - startP.y
|
||||
local delta = i / distance
|
||||
m_pBrush:setPosition(cc.p(startP.x + (difx * delta), startP.y + (dify * delta)))
|
||||
m_pBrush:setRotation(math.random(0, 359))
|
||||
local r = math.random(0, 49) / 50.0 + 0.25
|
||||
m_pBrush:setScale(r)
|
||||
|
||||
-- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why.
|
||||
m_pBrush:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255))
|
||||
-- Call visit to draw the brush, don't call draw..
|
||||
m_pBrush:visit()
|
||||
end
|
||||
for i = 0,d -1 do
|
||||
-- create a brush image to draw into the texture with
|
||||
local sprite = cc.Sprite:create("Images/fire.png")
|
||||
sprite:setColor(cc.c3b(255, 0, 0))
|
||||
sprite:setOpacity(20)
|
||||
brushes[i + 1] = sprite
|
||||
end
|
||||
|
||||
-- finish drawing and return context back to the screen
|
||||
m_pTarget:endToLua()
|
||||
for i = 0,d -1 do
|
||||
local difx = ended.x - start.x
|
||||
local dify = ended.y - start.y
|
||||
local delta = i / distance
|
||||
brushes[i + 1]:setPosition(cc.p(start.x + (difx * delta), start.y + (dify * delta)))
|
||||
brushes[i + 1]:setRotation(math.random(0, 359))
|
||||
local r = math.random(0, 49) / 50.0 + 0.25
|
||||
brushes[i + 1]:setScale(r)
|
||||
|
||||
-- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why.
|
||||
brushes[i + 1]:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255))
|
||||
-- Call visit to draw the brush, don't call draw..
|
||||
brushes[i + 1]:visit()
|
||||
end
|
||||
end
|
||||
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
-- finish drawing and return context back to the screen
|
||||
target:endToLua()
|
||||
end
|
||||
|
||||
ret:setTouchEnabled(true)
|
||||
ret:registerScriptTouchHandler(onTouchEvent)
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
local eventDispatcher = ret:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret)
|
||||
-- Save Image menu
|
||||
cc.MenuItemFont:setFontSize(16)
|
||||
local item1 = cc.MenuItemFont:create("Save Image")
|
||||
|
|
|
@ -55,12 +55,10 @@ function Sprite1.addNewSpriteWithCoords(layer, point)
|
|||
sprite:runAction( cc.RepeatForever:create(seq) )
|
||||
end
|
||||
|
||||
function Sprite1.onTouch(event, x, y)
|
||||
if event == "began" then
|
||||
return true
|
||||
elseif event == "ended" then
|
||||
Sprite1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y))
|
||||
return true
|
||||
function Sprite1.onTouchesEnd(touches, event)
|
||||
for i = 1,table.getn(touches) do
|
||||
local location = touches[i]:getLocation()
|
||||
Sprite1.addNewSpriteWithCoords(Helper.currentLayer, location)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,8 +67,11 @@ function Sprite1.create()
|
|||
local layer = cc.Layer:create()
|
||||
Helper.initWithLayer(layer)
|
||||
Sprite1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2))
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(Sprite1.onTouch)
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
Helper.titleLabel:setString("Sprite (tap screen)")
|
||||
|
||||
|
@ -115,12 +116,10 @@ function SpriteBatchNode1.addNewSpriteWithCoords(layer, point)
|
|||
sprite:runAction( cc.RepeatForever:create(seq) )
|
||||
end
|
||||
|
||||
function SpriteBatchNode1.onTouch(event, x, y)
|
||||
if event == "began" then
|
||||
return true
|
||||
elseif event == "ended" then
|
||||
SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y))
|
||||
return true
|
||||
function SpriteBatchNode1.onTouchesEnd(touches,event)
|
||||
for i = 1,table.getn(touches) do
|
||||
local location = touches[i]:getLocation()
|
||||
SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, location)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -132,8 +131,10 @@ function SpriteBatchNode1.create()
|
|||
|
||||
SpriteBatchNode1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2))
|
||||
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(SpriteBatchNode1.onTouch)
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
Helper.titleLabel:setString("SpriteBatchNode (tap screen)")
|
||||
|
||||
|
|
|
@ -12,26 +12,18 @@ local function createTileDemoLayer(title, subtitle)
|
|||
Helper.titleLabel:setString(titleStr)
|
||||
Helper.subtitleLabel:setString(subTitleStr)
|
||||
|
||||
local prev = {x = 0, y = 0}
|
||||
local function onTouchEvent(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
return true
|
||||
elseif eventType == "moved" then
|
||||
local node = layer:getChildByTag(kTagTileMap)
|
||||
local newX = node:getPositionX()
|
||||
local newY = node:getPositionY()
|
||||
local diffX = x - prev.x
|
||||
local diffY = y - prev.y
|
||||
|
||||
node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) )
|
||||
prev.x = x
|
||||
prev.y = y
|
||||
end
|
||||
local function onTouchesMoved(touches, event )
|
||||
local diff = touches[1]:getDelta()
|
||||
local node = layer:getChildByTag(kTagTileMap)
|
||||
local currentPosX, currentPosY= node:getPosition()
|
||||
node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y))
|
||||
end
|
||||
layer:setTouchEnabled(true)
|
||||
layer:registerScriptTouchHandler(onTouchEvent)
|
||||
|
||||
local listener = cc.EventListenerTouchAllAtOnce:create()
|
||||
listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED )
|
||||
local eventDispatcher = layer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer)
|
||||
|
||||
return layer
|
||||
end
|
||||
--------------------------------------------------------------------
|
||||
|
|
|
@ -170,14 +170,15 @@ function CreateTestMenu()
|
|||
menuLayer:addChild(MainMenu)
|
||||
|
||||
-- handling touch events
|
||||
local function onTouchBegan(x, y)
|
||||
BeginPos = {x = x, y = y}
|
||||
local function onTouchBegan(touch, event)
|
||||
BeginPos = touch:getLocation()
|
||||
-- CCTOUCHBEGAN event must return true
|
||||
return true
|
||||
end
|
||||
|
||||
local function onTouchMoved(x, y)
|
||||
local nMoveY = y - BeginPos.y
|
||||
local function onTouchMoved(touch, event)
|
||||
local location = touch:getLocation()
|
||||
local nMoveY = location.y - BeginPos.y
|
||||
local curPosx, curPosy = MainMenu:getPosition()
|
||||
local nextPosy = curPosy + nMoveY
|
||||
local winSize = cc.Director:getInstance():getWinSize()
|
||||
|
@ -192,20 +193,15 @@ function CreateTestMenu()
|
|||
end
|
||||
|
||||
MainMenu:setPosition(curPosx, nextPosy)
|
||||
BeginPos = {x = x, y = y}
|
||||
BeginPos = {x = location.x, y = location.y}
|
||||
CurPos = {x = curPosx, y = nextPosy}
|
||||
end
|
||||
|
||||
local function onTouch(eventType, x, y)
|
||||
if eventType == "began" then
|
||||
return onTouchBegan(x, y)
|
||||
elseif eventType == "moved" then
|
||||
return onTouchMoved(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
menuLayer:setTouchEnabled(true)
|
||||
menuLayer:registerScriptTouchHandler(onTouch)
|
||||
local listener = cc.EventListenerTouchOneByOne:create()
|
||||
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
|
||||
listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
|
||||
local eventDispatcher = menuLayer:getEventDispatcher()
|
||||
eventDispatcher:addEventListenerWithSceneGraphPriority(listener, menuLayer)
|
||||
|
||||
return menuLayer
|
||||
end
|
||||
|
|
|
@ -53,26 +53,6 @@ bool AppDelegate::applicationDidFinishLaunching()
|
|||
return true;
|
||||
}
|
||||
|
||||
void handle_signal(int signal) {
|
||||
static int internal_state = 0;
|
||||
ScriptingCore* sc = ScriptingCore::getInstance();
|
||||
// should start everything back
|
||||
Director* director = Director::getInstance();
|
||||
if (director->getRunningScene()) {
|
||||
director->popToRootScene();
|
||||
} else {
|
||||
PoolManager::sharedPoolManager()->finalize();
|
||||
if (internal_state == 0) {
|
||||
//sc->dumpRoot(NULL, 0, NULL);
|
||||
sc->start();
|
||||
internal_state = 1;
|
||||
} else {
|
||||
sc->runScript("hello.js");
|
||||
internal_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
|
||||
void AppDelegate::applicationDidEnterBackground()
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef _APP_DELEGATE_H_
|
||||
#define _APP_DELEGATE_H_
|
||||
|
||||
#include "CCApplication.h"
|
||||
#include "cocos2d.h"
|
||||
/**
|
||||
@brief The cocos2d Application.
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import requests
|
|||
import sys
|
||||
import traceback
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
#set Jenkins build description using submitDescription to mock browser behavior
|
||||
#TODO: need to set parent build description
|
||||
|
@ -58,7 +59,7 @@ def main():
|
|||
jenkins_url = os.environ['JENKINS_URL']
|
||||
job_name = os.environ['JOB_NAME'].split('/')[0]
|
||||
build_number = os.environ['BUILD_NUMBER']
|
||||
target_url = jenkins_url + 'job/' + job_name + '/' + build_number
|
||||
target_url = jenkins_url + 'job/' + job_name + '/' + build_number + '/'
|
||||
|
||||
set_description(pr_desc, target_url)
|
||||
|
||||
|
@ -113,7 +114,7 @@ def main():
|
|||
elif(platform.system() == 'Windows'):
|
||||
os.chdir("tools/jenkins-scripts")
|
||||
os.system("gen_jsb_win32.bat")
|
||||
os.chdir("../..)
|
||||
os.chdir("../..")
|
||||
|
||||
#make temp dir
|
||||
print "current dir is" + os.environ['WORKSPACE']
|
||||
|
@ -142,8 +143,12 @@ def main():
|
|||
#TODO: add ios build
|
||||
#TODO: add mac build
|
||||
#TODO: add win32 build
|
||||
node_name = os.environ['NODE_NAME']
|
||||
if(branch == 'develop'):
|
||||
ret = os.system("python build/android-build.py -n -j10 all")
|
||||
if(node_name == 'android_mac') or (node_name == 'android_win7'):
|
||||
ret = os.system("python build/android-build.py -n -j10 all")
|
||||
elif(node_name == 'win32_win7'):
|
||||
ret = subprocess.call('"%VS110COMNTOOLS%..\IDE\devenv.com" "build\cocos2d-win32.vc2012.sln" /Build "Debug|Win32"', shell=True)
|
||||
elif(branch == 'master'):
|
||||
ret = os.system("samples/Cpp/TestCpp/proj.android/build_native.sh")
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@ rename_functions = SpriteFrameCache::[addSpriteFramesWithFile=addSpriteFrames ge
|
|||
LayerGradient::[initWithColor=init],
|
||||
LayerColor::[initWithColor=init],
|
||||
GLProgram::[initWithVertexShaderByteArray=initWithString initWithVertexShaderFilename=init programLog=getProgramLog setUniformLocationWith1i=setUniformLocationI32],
|
||||
Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder],
|
||||
Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder setLocalZOrder=setZOrder],
|
||||
LabelAtlas::[create=_create],
|
||||
Sprite::[initWithFile=init],
|
||||
SpriteBatchNode::[initWithFile=init removeAllChildrenWithCleanup=removeAllChildren],
|
||||
|
|
Loading…
Reference in New Issue