THRIFT-4386 Add Lua 5.3/5.4 support
Clint: lua
Patch: Thomas Bruggink

This closes #3012
diff --git a/lib/lua/src/luabitwise.c b/lib/lua/src/luabitwise.c
index 2e07e17..ea9110a 100644
--- a/lib/lua/src/luabitwise.c
+++ b/lib/lua/src/luabitwise.c
@@ -27,6 +27,13 @@
   return 1;
 }
 
+static int l_unot(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  a = ~a;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
 static int l_xor(lua_State *L) {
   int a = luaL_checkinteger(L, 1);
   int b = luaL_checkinteger(L, 2);
@@ -35,6 +42,15 @@
   return 1;
 }
 
+static int l_uxor(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  unsigned int b = luaL_checkinteger(L, 2);
+  a ^= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
+
 static int l_and(lua_State *L) {
   int a = luaL_checkinteger(L, 1);
   int b = luaL_checkinteger(L, 2);
@@ -43,6 +59,14 @@
   return 1;
 }
 
+static int l_uand(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  unsigned int b = luaL_checkinteger(L, 2);
+  a &= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
 static int l_or(lua_State *L) {
   int a = luaL_checkinteger(L, 1);
   int b = luaL_checkinteger(L, 2);
@@ -51,6 +75,14 @@
   return 1;
 }
 
+static int l_uor(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  unsigned int b = luaL_checkinteger(L, 2);
+  a |= b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
 static int l_shiftr(lua_State *L) {
   int a = luaL_checkinteger(L, 1);
   int b = luaL_checkinteger(L, 2);
@@ -59,6 +91,14 @@
   return 1;
 }
 
+static int l_ushiftr(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  unsigned int b = luaL_checkinteger(L, 2);
+  a = a >> b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
 static int l_shiftl(lua_State *L) {
   int a = luaL_checkinteger(L, 1);
   int b = luaL_checkinteger(L, 2);
@@ -67,17 +107,36 @@
   return 1;
 }
 
+static int l_ushiftl(lua_State *L) {
+  unsigned int a = luaL_checkinteger(L, 1);
+  unsigned int b = luaL_checkinteger(L, 2);
+  a = a << b;
+  lua_pushnumber(L, a);
+  return 1;
+}
+
 static const struct luaL_Reg funcs[] = {
   {"band", l_and},
+  {"buand", l_uand},
   {"bor", l_or},
+  {"buor", l_uor},
   {"bxor", l_xor},
+  {"buxor", l_uxor},
   {"bnot", l_not},
+  {"bunot", l_unot},
   {"shiftl", l_shiftl},
+  {"ushiftl", l_ushiftl},
   {"shiftr", l_shiftr},
+  {"ushiftr", l_ushiftr},
   {NULL, NULL}
 };
 
 int luaopen_libluabitwise(lua_State *L) {
+#if LUA_VERSION_NUM >= 502
+    lua_newtable(L);
+    luaL_setfuncs(L, funcs, 0);
+#else
   luaL_register(L, "libluabitwise", funcs);
+#endif
   return 1;
 }
diff --git a/lib/lua/src/luabpack.c b/lib/lua/src/luabpack.c
index 077b6aa..cdfb72a 100644
--- a/lib/lua/src/luabpack.c
+++ b/lib/lua/src/luabpack.c
@@ -45,6 +45,7 @@
  *  c - Signed Byte
  *  s - Signed Short
  *  i - Signed Int
+ *  I - Unsigned Int
  *  l - Signed Long
  *  d - Double
  */
@@ -72,6 +73,12 @@
       luaL_addlstring(&buf, (void*)&data, sizeof(data));
       break;
     }
+    case 'I': {
+      uint32_t data = luaL_checkinteger(L, 2);
+      data = (uint32_t)htonl(data);
+      luaL_addlstring(&buf, (void*)&data, sizeof(data));
+      break;
+    }
     case 'l': {
       int64_t data = lualongnumber_checklong(L, 2);
       data = (int64_t)T_htonll(data);
@@ -97,6 +104,7 @@
  *  C - Unsigned Byte
  *  s - Signed Short
  *  i - Signed Int
+ *  I - Unsigned Int
  *  l - Signed Long
  *  d - Double
  */
@@ -144,6 +152,17 @@
       lua_pushnumber(L, val);
       break;
     }
+    /**
+     * unpack unsigned Int.
+     */
+    case 'I': {
+      uint32_t val;
+      luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+      memcpy(&val, data, sizeof(val));
+      val = (uint32_t)ntohl(val);
+      lua_pushnumber(L, val);
+      break;
+    }
     case 'l': {
       int64_t val;
       luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
@@ -303,6 +322,11 @@
 };
 
 int luaopen_libluabpack(lua_State *L) {
+#if LUA_VERSION_NUM >= 502
+    lua_newtable(L);
+    luaL_setfuncs(L, lua_bpack, 0);
+#else
   luaL_register(L, "libluabpack", lua_bpack);
+#endif
   return 1;
 }
diff --git a/lib/lua/src/lualongnumber.c b/lib/lua/src/lualongnumber.c
index 9001e4a..91df70a 100644
--- a/lib/lua/src/lualongnumber.c
+++ b/lib/lua/src/lualongnumber.c
@@ -223,6 +223,11 @@
   lua_pop(L, 1);
   set_methods(L, LONG_NUM_TYPE, methods);
 
+#if LUA_VERSION_NUM >= 502
+    lua_newtable(L);
+    luaL_setfuncs(L, funcs, 0);
+#else
   luaL_register(L, "liblualongnumber", funcs);
+#endif
   return 1;
 }
diff --git a/lib/lua/src/luasocket.c b/lib/lua/src/luasocket.c
index 6f63d3d..07524ab 100644
--- a/lib/lua/src/luasocket.c
+++ b/lib/lua/src/luasocket.c
@@ -185,8 +185,12 @@
   set_methods(L, SOCKET_GENERIC, methods_generic);
   set_methods(L, SOCKET_CLIENT, methods_client);
   set_methods(L, SOCKET_SERVER, methods_server);
-
+#if LUA_VERSION_NUM >= 502
+    lua_newtable(L);
+    luaL_setfuncs(L, funcs_luasocket, 0);
+#else
   luaL_register(L, "luasocket", funcs_luasocket);
+#endif
   return 1;
 }
 
diff --git a/lib/lua/src/usocket.c b/lib/lua/src/usocket.c
index 21c0bac..27103a0 100644
--- a/lib/lua/src/usocket.c
+++ b/lib/lua/src/usocket.c
@@ -205,21 +205,35 @@
   return socket_wait(sock, WAIT_MODE_C, timeout);
 }
 
+#define SEND_RETRY_COUNT 5
 T_ERRCODE socket_send(
   p_socket sock, const char *data, size_t len, int timeout) {
   int err, put = 0;
   if (*sock < 0) {
     return CLOSED;
   }
-  do {
-    put = send(*sock, data, len, 0);
-    if (put > 0) {
-      return SUCCESS;
-    }
-  } while ((err = errno) == EINTR);
+  for(int i = 0; i < SEND_RETRY_COUNT; i++) {
+    do {
+      size_t l = len - put;
+      put = send(*sock, data + put, l, 0);
+      if (put > 0) {
+        if(put == l) {
+          return SUCCESS;
+        }
+        // Not all data was delivered, we need to try again.
+        err = EAGAIN;
+        break;
+      }
+    } while ((err = errno) == EINTR);
 
-  if (err == EAGAIN) {
-    return socket_wait(sock, WAIT_MODE_W, timeout);
+    if (err == EAGAIN) {
+      err = socket_wait(sock, WAIT_MODE_W, timeout);
+      // Check if the socket is available again and try to resend.
+      if(err == SUCCESS) {
+        continue;
+      }
+    }
+    break;
   }
 
   return err;