PageRenderTime 39ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/release-0.1-rc2/hive/external/service/lib/php/ext/thrift_protocol/tags/1.0.0/php_thrift_protocol.cpp

#
C++ | 361 lines | 314 code | 43 blank | 4 comment | 28 complexity | 6096c9efa1b33fbb503c66a5ccdfb5f9 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, JSON, CPL-1.0
  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #endif
  4. #include <sys/types.h>
  5. #include <netinet/in.h>
  6. #include <unistd.h>
  7. #include <endian.h>
  8. #include <byteswap.h>
  9. #if __BYTE_ORDER == __LITTLE_ENDIAN
  10. #define ntohll(x) bswap_64(x)
  11. #else
  12. #define ntohll(x) x
  13. #endif
  14. enum TType {
  15. T_STOP = 0,
  16. T_VOID = 1,
  17. T_BOOL = 2,
  18. T_BYTE = 3,
  19. T_I08 = 3,
  20. T_I16 = 6,
  21. T_I32 = 8,
  22. T_U64 = 9,
  23. T_I64 = 10,
  24. T_DOUBLE = 4,
  25. T_STRING = 11,
  26. T_UTF7 = 11,
  27. T_STRUCT = 12,
  28. T_MAP = 13,
  29. T_SET = 14,
  30. T_LIST = 15,
  31. T_UTF8 = 16,
  32. T_UTF16 = 17
  33. };
  34. #include "php.h"
  35. #include "php_thrift_protocol.h"
  36. static function_entry thrift_protocol_functions[] = {
  37. PHP_FE(thrift_protocol_binary_deserialize, NULL)
  38. {NULL, NULL, NULL}
  39. } ;
  40. zend_module_entry thrift_protocol_module_entry = {
  41. STANDARD_MODULE_HEADER,
  42. "thrift_protocol",
  43. thrift_protocol_functions,
  44. NULL,
  45. NULL,
  46. NULL,
  47. NULL,
  48. NULL,
  49. "1.0",
  50. STANDARD_MODULE_PROPERTIES
  51. };
  52. #ifdef COMPILE_DL_THRIFT_PROTOCOL
  53. ZEND_GET_MODULE(thrift_protocol)
  54. #endif
  55. class PHPTransport {
  56. public:
  57. PHPTransport(zval* _p, size_t _buffer_size = 1024) : buffer(reinterpret_cast<char*>(emalloc(_buffer_size))), buffer_remaining(0), buffer_size(_buffer_size), p(_p) {
  58. ZVAL_STRING(&funcname, "read", 0);
  59. // Get the transport for the passed protocol
  60. zval gettransport;
  61. ZVAL_STRING(&gettransport, "getTransport", 0);
  62. MAKE_STD_ZVAL(t);
  63. ZVAL_NULL(t);
  64. TSRMLS_FETCH();
  65. call_user_function(EG(function_table), &p, &gettransport, t, 0, NULL TSRMLS_CC);
  66. }
  67. ~PHPTransport() {
  68. put_back();
  69. efree(buffer);
  70. zval_ptr_dtor(&t);
  71. }
  72. void put_back() {
  73. if (buffer_remaining) {
  74. zval putbackfn;
  75. ZVAL_STRING(&putbackfn, "putBack", 0);
  76. char* newbuf = (char*)emalloc(buffer_remaining + 1);
  77. memcpy(newbuf, buffer_ptr, buffer_remaining);
  78. newbuf[buffer_remaining] = '\0';
  79. zval *args[1];
  80. MAKE_STD_ZVAL(args[0]);
  81. ZVAL_STRINGL(args[0], newbuf, buffer_remaining, 0);
  82. TSRMLS_FETCH();
  83. zval ret;
  84. call_user_function(EG(function_table), &t, &putbackfn, &ret, 1, args TSRMLS_CC);
  85. zval_ptr_dtor(args);
  86. zval_dtor(&ret);
  87. }
  88. buffer_remaining = 0;
  89. buffer_ptr = buffer;
  90. }
  91. zval* protocol() { return p; }
  92. zval* transport() { return t; }
  93. void readBytes(void* buf, size_t len) {
  94. while (len) {
  95. size_t chunk_size = MIN(len, buffer_remaining);
  96. if (chunk_size) {
  97. memcpy(buf, buffer_ptr, chunk_size);
  98. buffer_ptr = reinterpret_cast<char*>(buffer_ptr) + chunk_size;
  99. buffer_remaining -= chunk_size;
  100. buf = reinterpret_cast<char*>(buf) + chunk_size;
  101. len -= chunk_size;
  102. }
  103. if (! len) break;
  104. refill();
  105. }
  106. }
  107. protected:
  108. void refill() {
  109. assert(buffer_remaining == 0);
  110. zval retval;
  111. ZVAL_NULL(&retval);
  112. zval *args[1];
  113. MAKE_STD_ZVAL(args[0]);
  114. ZVAL_LONG(args[0], buffer_size);
  115. TSRMLS_FETCH();
  116. call_user_function(EG(function_table), &t, &funcname, &retval, 1, args TSRMLS_CC);
  117. zval_ptr_dtor(args);
  118. buffer_remaining = Z_STRLEN(retval);
  119. memcpy(buffer, Z_STRVAL(retval), buffer_remaining);
  120. zval_dtor(&retval);
  121. buffer_ptr = buffer;
  122. }
  123. char* buffer;
  124. char* buffer_ptr;
  125. size_t buffer_remaining;
  126. size_t buffer_size;
  127. zval* p;
  128. zval* t;
  129. zval funcname;
  130. };
  131. // Does not call the ctor on the object, all fields will be NULL
  132. void createObject(char* obj_typename, zval* return_value) {
  133. TSRMLS_FETCH();
  134. size_t obj_typename_len = strlen(obj_typename);
  135. zend_class_entry* ce = zend_fetch_class(obj_typename, obj_typename_len, ZEND_FETCH_CLASS_DEFAULT TSRMLS_CC);
  136. if (! ce) {
  137. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Class %s does not exist", obj_typename);
  138. RETURN_NULL();
  139. }
  140. object_and_properties_init(return_value, ce, NULL);
  141. }
  142. void binary_deserialize(long thrift_typeID, PHPTransport& transport, zval* return_value, char* structType) {
  143. Z_TYPE_P(return_value) = IS_NULL; // just in case
  144. switch (thrift_typeID) {
  145. case T_STOP:
  146. case T_VOID:
  147. RETURN_NULL();
  148. return;
  149. case T_STRUCT: {
  150. assert(structType);
  151. createObject(structType, return_value);
  152. zval retval;
  153. ZVAL_NULL(&retval);
  154. zval *args[1];
  155. args[0] = transport.protocol();
  156. zval funcname;
  157. ZVAL_STRING(&funcname, "read", 0);
  158. transport.put_back(); // return our buffer to the userland T{Framed,Buffered}Transport for reading the field headers and such
  159. TSRMLS_FETCH();
  160. call_user_function(EG(function_table), &return_value, &funcname, &retval, 1, args TSRMLS_CC);
  161. zval_dtor(&retval);
  162. return;
  163. } break;
  164. case T_BOOL: {
  165. uint8_t c;
  166. transport.readBytes(&c, 1);
  167. RETURN_BOOL(c != 0);
  168. }
  169. //case T_I08: // same numeric value as T_BYTE
  170. case T_BYTE: {
  171. uint8_t c;
  172. transport.readBytes(&c, 1);
  173. RETURN_LONG(c);
  174. }
  175. case T_I16: {
  176. uint16_t c;
  177. transport.readBytes(&c, 2);
  178. RETURN_LONG(ntohs(c));
  179. }
  180. case T_I32: {
  181. uint32_t c;
  182. transport.readBytes(&c, 4);
  183. RETURN_LONG(ntohl(c));
  184. }
  185. case T_U64:
  186. case T_I64: {
  187. uint64_t c;
  188. transport.readBytes(&c, 8);
  189. RETURN_LONG(ntohll(c));
  190. }
  191. case T_DOUBLE: {
  192. union {
  193. uint64_t c;
  194. double d;
  195. } a;
  196. transport.readBytes(&(a.c), 8);
  197. a.c = ntohll(a.c);
  198. RETURN_DOUBLE(a.d);
  199. }
  200. //case T_UTF7: // aliases T_STRING
  201. case T_UTF8:
  202. case T_UTF16:
  203. case T_STRING: {
  204. uint32_t size;
  205. transport.readBytes(&size, 4);
  206. size = ntohl(size);
  207. char* strbuf = (char*) emalloc(size + 1);
  208. if (size) {
  209. transport.readBytes(strbuf, size);
  210. }
  211. strbuf[size] = '\0';
  212. ZVAL_STRINGL(return_value, strbuf, size, 0);
  213. return;
  214. }
  215. case T_MAP: { // array of key -> value
  216. uint8_t types[2];
  217. uint32_t size;
  218. transport.readBytes(types, 2);
  219. transport.readBytes(&size, 4);
  220. size = ntohl(size);
  221. array_init(return_value);
  222. for (uint32_t s = 0; s < size; ++s) {
  223. zval *value;
  224. MAKE_STD_ZVAL(value);
  225. zval* key;
  226. MAKE_STD_ZVAL(key);
  227. binary_deserialize(types[0], transport, key, NULL);
  228. binary_deserialize(types[1], transport, value, structType);
  229. if (Z_TYPE_P(key) == IS_LONG) {
  230. zend_hash_index_update(return_value->value.ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
  231. }
  232. else {
  233. convert_to_string_ex(&key);
  234. zend_hash_update(return_value->value.ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
  235. }
  236. zval_ptr_dtor(&key);
  237. }
  238. return; // return_value already populated
  239. }
  240. case T_LIST: { // array with autogenerated numeric keys
  241. uint8_t type;
  242. uint32_t size;
  243. transport.readBytes(&type, 1);
  244. transport.readBytes(&size, 4);
  245. size = ntohl(size);
  246. array_init(return_value);
  247. for (uint32_t s = 0; s < size; ++s) {
  248. zval *value;
  249. MAKE_STD_ZVAL(value);
  250. binary_deserialize(type, transport, value, structType);
  251. zend_hash_next_index_insert(return_value->value.ht, &value, sizeof(zval *), NULL);
  252. }
  253. return;
  254. }
  255. case T_SET: { // array of key -> TRUE
  256. uint8_t type;
  257. uint32_t size;
  258. transport.readBytes(&type, 1);
  259. transport.readBytes(&size, 4);
  260. size = ntohl(size);
  261. array_init(return_value);
  262. for (uint32_t s = 0; s < size; ++s) {
  263. zval* key;
  264. zval* value;
  265. MAKE_STD_ZVAL(key);
  266. MAKE_STD_ZVAL(value);
  267. ZVAL_TRUE(value);
  268. binary_deserialize(type, transport, key, NULL);
  269. if (Z_TYPE_P(key) == IS_LONG) {
  270. zend_hash_index_update(return_value->value.ht, Z_LVAL_P(key), &value, sizeof(zval *), NULL);
  271. }
  272. else {
  273. convert_to_string_ex(&key);
  274. zend_hash_update(return_value->value.ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof(zval *), NULL);
  275. }
  276. zval_ptr_dtor(&key);
  277. }
  278. return;
  279. }
  280. default:
  281. TSRMLS_FETCH();
  282. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown thrift typeID %ld", thrift_typeID);
  283. RETURN_NULL();
  284. };
  285. assert(0); // should never get here...
  286. }
  287. PHP_FUNCTION(thrift_protocol_binary_deserialize) {
  288. int argc = ZEND_NUM_ARGS();
  289. long thrift_typeID;
  290. if (argc < 2) {
  291. WRONG_PARAM_COUNT;
  292. }
  293. zval ***args = (zval***) emalloc(argc * sizeof(zval**));
  294. zend_get_parameters_array_ex(argc, args);
  295. convert_to_long_ex(args[0]);
  296. thrift_typeID = Z_LVAL_PP(args[0]);
  297. if (Z_TYPE_PP(args[1]) != IS_OBJECT) {
  298. php_error_docref(NULL TSRMLS_CC, E_ERROR, "2nd parameter is not an object");
  299. efree(args);
  300. RETURN_NULL();
  301. }
  302. char* structType = NULL;
  303. if (argc >= 3) {
  304. if (Z_TYPE_PP(args[2]) == IS_STRING) {
  305. for (int s = 0; s < Z_STRLEN_PP(args[2]); ++s) {
  306. if (isalpha(Z_STRVAL_PP(args[2])[s])) Z_STRVAL_PP(args[2])[s] = tolower(Z_STRVAL_PP(args[2])[s]);
  307. }
  308. structType = Z_STRVAL_PP(args[2]);
  309. } else {
  310. php_error_docref(NULL TSRMLS_CC, E_ERROR, "3rd parameter (if present) must be a string");
  311. efree(args);
  312. RETURN_NULL();
  313. }
  314. }
  315. PHPTransport transport(*args[1]);
  316. binary_deserialize(thrift_typeID, transport, return_value, structType);
  317. efree(args);
  318. }