PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/php-pecl-amqp-1.0.3/amqp-1.0.3/amqp_channel.c

#
C | 477 lines | 285 code | 102 blank | 90 comment | 36 complexity | 4b8c340a3cdde6a3ecf5c393feee56a4 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2007 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Alexandre Kalendarev akalend@mail.ru Copyright (c) 2009-2010 |
  16. | Lead: |
  17. | - Pieter de Zwart |
  18. | Maintainers: |
  19. | - Brad Rodriguez |
  20. | - Jonathan Tansavatdi |
  21. +----------------------------------------------------------------------+
  22. */
  23. /* $Id: amqp_channel.c 318036 2011-10-11 20:30:46Z pdezwart $ */
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #endif
  27. #include "php.h"
  28. #include "php_ini.h"
  29. #include "ext/standard/info.h"
  30. #include "zend_exceptions.h"
  31. #include <stdint.h>
  32. #include <signal.h>
  33. #include <amqp.h>
  34. #include <amqp_framing.h>
  35. #include <unistd.h>
  36. #include "php_amqp.h"
  37. #include "amqp_connection.h"
  38. #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
  39. HashTable *amqp_channel_object_get_debug_info(zval *object, int *is_temp TSRMLS_DC) {
  40. zval *value;
  41. /* Get the envelope object from which to read */
  42. amqp_channel_object *channel = (amqp_channel_object *)zend_object_store_get_object(object TSRMLS_CC);
  43. /* Super magic make shit work variable. Seriously though, without this using print_r and/or var_dump will either cause memory leak or crash. */
  44. *is_temp = 1;
  45. /* Keep the first number matching the number of entries in this table*/
  46. ALLOC_HASHTABLE(channel->debug_info);
  47. ZEND_INIT_SYMTABLE_EX(channel->debug_info, 3 + 1, 0);
  48. /* Start adding values */
  49. MAKE_STD_ZVAL(value);
  50. ZVAL_LONG(value, channel->channel_id);
  51. zend_hash_add(channel->debug_info, "channel_id", strlen("channel_id") + 1, &value, sizeof(zval *), NULL);
  52. MAKE_STD_ZVAL(value);
  53. ZVAL_LONG(value, channel->prefetch_count);
  54. zend_hash_add(channel->debug_info, "prefetch_count", strlen("prefetch_count") + 1, &value, sizeof(zval *), NULL);
  55. MAKE_STD_ZVAL(value);
  56. ZVAL_LONG(value, channel->prefetch_size);
  57. zend_hash_add(channel->debug_info, "prefetch_size", strlen("prefetch_size") + 1, &value, sizeof(zval *), NULL);
  58. /* Start adding values */
  59. return channel->debug_info;
  60. }
  61. #endif
  62. void amqp_channel_dtor(void *object TSRMLS_DC)
  63. {
  64. amqp_channel_object *channel = (amqp_channel_object*)object;
  65. amqp_connection_object *connection;
  66. connection = AMQP_GET_CONNECTION(channel);
  67. remove_channel_from_connection(connection, channel);
  68. /* Destroy the connection storage */
  69. if (channel->connection) {
  70. zval_ptr_dtor(&channel->connection);
  71. }
  72. zend_object_std_dtor(&channel->zo TSRMLS_CC);
  73. efree(object);
  74. }
  75. zend_object_value amqp_channel_ctor(zend_class_entry *ce TSRMLS_DC)
  76. {
  77. zend_object_value new_value;
  78. amqp_channel_object *channel = (amqp_channel_object*)emalloc(sizeof(amqp_channel_object));
  79. memset(channel, 0, sizeof(amqp_channel_object));
  80. zend_object_std_init(&channel->zo, ce TSRMLS_CC);
  81. new_value.handle = zend_objects_store_put(
  82. channel,
  83. (zend_objects_store_dtor_t)zend_objects_destroy_object,
  84. (zend_objects_free_object_storage_t)amqp_channel_dtor,
  85. NULL TSRMLS_CC
  86. );
  87. #if 0 && PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
  88. zend_object_handlers *handlers;
  89. handlers = zend_get_std_object_handlers();
  90. handlers->get_debug_info = amqp_channel_object_get_debug_info;
  91. new_value.handlers = handlers;
  92. #else
  93. new_value.handlers = zend_get_std_object_handlers();
  94. #endif
  95. return new_value;
  96. }
  97. /* {{{ proto AMQPChannel::__construct(AMQPConnection obj)
  98. */
  99. PHP_METHOD(amqp_channel_class, __construct)
  100. {
  101. zval *id;
  102. zval *connObj = NULL;
  103. amqp_channel_object *channel;
  104. amqp_connection_object *connection;
  105. amqp_rpc_reply_t res;
  106. /* Parse out the method parameters */
  107. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "OO", &id, amqp_channel_class_entry, &connObj, amqp_connection_class_entry) == FAILURE) {
  108. return;
  109. }
  110. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  111. channel->connection = connObj;
  112. Z_ADDREF_P(connObj);
  113. /* Set the prefetch count */
  114. channel->prefetch_count = INI_INT("amqp.prefetch_count");
  115. /* Pull out and verify the connection */
  116. connection = AMQP_GET_CONNECTION(channel);
  117. AMQP_VERIFY_CONNECTION(connection, "Could not create channel.");
  118. /* Figure out what the next available channel is on this connection */
  119. channel->channel_id = get_next_available_channel(connection, channel);
  120. /* Check that we got a valid channel */
  121. if (channel->channel_id < 0) {
  122. zend_throw_exception(amqp_channel_exception_class_entry, "Could not create channel. Connection has no open channel slots remaining.", 0 TSRMLS_CC);
  123. return;
  124. }
  125. /* Open up the channel for use */
  126. amqp_channel_open(connection->connection_resource->connection_state, channel->channel_id);
  127. res = (amqp_rpc_reply_t)amqp_get_rpc_reply(connection->connection_resource->connection_state);
  128. if (res.reply_type != AMQP_RESPONSE_NORMAL) {
  129. char str[256];
  130. char ** pstr = (char **) &str;
  131. amqp_error(res, pstr);
  132. zend_throw_exception(amqp_channel_exception_class_entry, *pstr, 0 TSRMLS_CC);
  133. return;
  134. }
  135. channel->is_connected = '\1';
  136. /* Set the prefetch count: */
  137. amqp_basic_qos(
  138. connection->connection_resource->connection_state,
  139. channel->channel_id,
  140. 0, /* prefetch window size */
  141. channel->prefetch_count, /* prefetch message count */
  142. 0 /* global flag */
  143. );
  144. }
  145. /* }}} */
  146. /* {{{ proto amqp::isConnected()
  147. check amqp channel */
  148. PHP_METHOD(amqp_channel_class, isConnected)
  149. {
  150. zval *id;
  151. amqp_channel_object *channel;
  152. /* Try to pull amqp object out of method params */
  153. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, amqp_channel_class_entry) == FAILURE) {
  154. return;
  155. }
  156. /* Get the channel object out of the store */
  157. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  158. /* If the channel_connect is 1, we have a channel */
  159. if (channel->is_connected == '\1') {
  160. RETURN_TRUE;
  161. }
  162. /* We have no channel */
  163. RETURN_FALSE;
  164. }
  165. /* }}} */
  166. /* {{{ proto amqp::setPrefetchCount(long count)
  167. set the number of prefetches */
  168. PHP_METHOD(amqp_channel_class, setPrefetchCount)
  169. {
  170. zval *id;
  171. amqp_channel_object *channel;
  172. amqp_connection_object *connection;
  173. long prefetch_count;
  174. /* Get the vhost from the method params */
  175. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &id, amqp_channel_class_entry, &prefetch_count) == FAILURE) {
  176. return;
  177. }
  178. /* Get the channel object out of the store */
  179. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  180. /* Set the prefetch count - the implication is to disable the size */
  181. channel->prefetch_count = prefetch_count;
  182. channel->prefetch_size = 0;
  183. connection = AMQP_GET_CONNECTION(channel);
  184. AMQP_VERIFY_CONNECTION(connection, "Could not set prefetch count.");
  185. /* If we are already connected, set the new prefetch count */
  186. if (channel->is_connected) {
  187. amqp_basic_qos(
  188. connection->connection_resource->connection_state,
  189. channel->channel_id,
  190. channel->prefetch_size,
  191. channel->prefetch_count,
  192. 0
  193. );
  194. }
  195. RETURN_TRUE;
  196. }
  197. /* }}} */
  198. /* {{{ proto amqp::setPrefetchSize(long size)
  199. set the number of prefetches */
  200. PHP_METHOD(amqp_channel_class, setPrefetchSize)
  201. {
  202. zval *id;
  203. amqp_channel_object *channel;
  204. amqp_connection_object *connection;
  205. long prefetch_size;
  206. /* Get the vhost from the method params */
  207. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &id, amqp_channel_class_entry, &prefetch_size) == FAILURE) {
  208. return;
  209. }
  210. /* Get the channel object out of the store */
  211. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  212. /* Set the prefetch size - the implication is to disable the count */
  213. channel->prefetch_count = 0;
  214. channel->prefetch_size = prefetch_size;
  215. connection = AMQP_GET_CONNECTION(channel);
  216. AMQP_VERIFY_CONNECTION(connection, "Could not set prefetch size.");
  217. /* If we are already connected, set the new prefetch count */
  218. if (channel->is_connected) {
  219. amqp_basic_qos(
  220. connection->connection_resource->connection_state,
  221. channel->channel_id,
  222. channel->prefetch_size,
  223. channel->prefetch_count,
  224. 0
  225. );
  226. }
  227. RETURN_TRUE;
  228. }
  229. /* }}} */
  230. /* {{{ proto amqp::qos(long size, long count)
  231. set the number of prefetches */
  232. PHP_METHOD(amqp_channel_class, qos)
  233. {
  234. zval *id;
  235. amqp_channel_object *channel;
  236. amqp_connection_object *connection;
  237. long prefetch_size;
  238. long prefetch_count;
  239. /* Get the vhost from the method params */
  240. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll", &id, amqp_channel_class_entry, &prefetch_size, &prefetch_count) == FAILURE) {
  241. return;
  242. }
  243. /* Get the channel object out of the store */
  244. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  245. /* Set the prefetch size - the implication is to disable the count */
  246. channel->prefetch_size = prefetch_size;
  247. channel->prefetch_count = prefetch_count;
  248. connection = AMQP_GET_CONNECTION(channel);
  249. AMQP_VERIFY_CONNECTION(connection, "Could not set qos parameters.");
  250. /* If we are already connected, set the new prefetch count */
  251. if (channel->is_connected) {
  252. amqp_basic_qos(
  253. connection->connection_resource->connection_state,
  254. channel->channel_id,
  255. channel->prefetch_size,
  256. channel->prefetch_count,
  257. 0 /* Global flag - whether this change should affect every channel */
  258. );
  259. }
  260. RETURN_TRUE;
  261. }
  262. /* }}} */
  263. /* {{{ proto amqp::startTransaction()
  264. start a transaction on the given channel */
  265. PHP_METHOD(amqp_channel_class, startTransaction)
  266. {
  267. zval *id;
  268. amqp_channel_object *channel;
  269. amqp_connection_object *connection;
  270. /* Get the vhost from the method params */
  271. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, amqp_channel_class_entry) == FAILURE) {
  272. return;
  273. }
  274. /* Get the channel object out of the store */
  275. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  276. connection = AMQP_GET_CONNECTION(channel);
  277. AMQP_VERIFY_CONNECTION(connection, "Could not start the transaction.");
  278. amqp_tx_select_t s;
  279. amqp_method_number_t select_ok = AMQP_TX_SELECT_OK_METHOD;
  280. amqp_rpc_reply_t res = (amqp_rpc_reply_t) amqp_simple_rpc(
  281. connection->connection_resource->connection_state,
  282. channel->channel_id,
  283. AMQP_TX_SELECT_METHOD,
  284. &select_ok,
  285. &s
  286. );
  287. if (res.reply_type != AMQP_RESPONSE_NORMAL) {
  288. char str[256];
  289. char **pstr = (char **)&str;
  290. amqp_error(res, pstr);
  291. channel->is_connected = 0;
  292. zend_throw_exception(amqp_channel_exception_class_entry, *pstr, 0 TSRMLS_CC);
  293. return;
  294. }
  295. RETURN_TRUE;
  296. }
  297. /* }}} */
  298. /* {{{ proto amqp::startTransaction()
  299. start a transaction on the given channel */
  300. PHP_METHOD(amqp_channel_class, commitTransaction)
  301. {
  302. zval *id;
  303. amqp_channel_object *channel;
  304. amqp_connection_object *connection;
  305. /* Get the vhost from the method params */
  306. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, amqp_channel_class_entry) == FAILURE) {
  307. return;
  308. }
  309. /* Get the channel object out of the store */
  310. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  311. connection = AMQP_GET_CONNECTION(channel);
  312. AMQP_VERIFY_CONNECTION(connection, "Could not start the transaction.");
  313. amqp_tx_commit_t s;
  314. amqp_method_number_t commit_ok = AMQP_TX_COMMIT_OK_METHOD;
  315. amqp_rpc_reply_t res = (amqp_rpc_reply_t) amqp_simple_rpc(
  316. connection->connection_resource->connection_state,
  317. channel->channel_id,
  318. AMQP_TX_COMMIT_METHOD,
  319. &commit_ok,
  320. &s
  321. );
  322. if (res.reply_type != AMQP_RESPONSE_NORMAL) {
  323. char str[256];
  324. char **pstr = (char **)&str;
  325. amqp_error(res, pstr);
  326. channel->is_connected = 0;
  327. zend_throw_exception(amqp_channel_exception_class_entry, *pstr, 0 TSRMLS_CC);
  328. return;
  329. }
  330. RETURN_TRUE;
  331. }
  332. /* }}} */
  333. /* {{{ proto amqp::startTransaction()
  334. start a transaction on the given channel */
  335. PHP_METHOD(amqp_channel_class, rollbackTransaction)
  336. {
  337. zval *id;
  338. amqp_channel_object *channel;
  339. amqp_connection_object *connection;
  340. /* Get the vhost from the method params */
  341. if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &id, amqp_channel_class_entry) == FAILURE) {
  342. return;
  343. }
  344. /* Get the channel object out of the store */
  345. channel = (amqp_channel_object *)zend_object_store_get_object(id TSRMLS_CC);
  346. connection = AMQP_GET_CONNECTION(channel);
  347. AMQP_VERIFY_CONNECTION(connection, "Could not start the transaction.");
  348. amqp_tx_rollback_t s;
  349. amqp_method_number_t rollback_ok = AMQP_TX_ROLLBACK_OK_METHOD;
  350. amqp_rpc_reply_t res = (amqp_rpc_reply_t) amqp_simple_rpc(
  351. connection->connection_resource->connection_state,
  352. channel->channel_id,
  353. AMQP_TX_ROLLBACK_METHOD,
  354. &rollback_ok,
  355. &s
  356. );
  357. if (res.reply_type != AMQP_RESPONSE_NORMAL) {
  358. char str[256];
  359. char **pstr = (char **)&str;
  360. amqp_error(res, pstr);
  361. channel->is_connected = 0;
  362. zend_throw_exception(amqp_channel_exception_class_entry, *pstr, 0 TSRMLS_CC);
  363. return;
  364. }
  365. RETURN_TRUE;
  366. }
  367. /* }}} */
  368. /*
  369. *Local variables:
  370. *tab-width: 4
  371. *c-basic-offset: 4
  372. *End:
  373. *vim600: noet sw=4 ts=4 fdm=marker
  374. *vim<600: noet sw=4 ts=4
  375. */