root/ext/interbase/ibase_events.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _php_ibase_event_free
  2. _php_ibase_free_event
  3. _php_ibase_free_event_rsrc
  4. php_ibase_events_minit
  5. _php_ibase_event_block
  6. PHP_FUNCTION
  7. _php_ibase_callback
  8. PHP_FUNCTION
  9. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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    | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl>              |
  16    +----------------------------------------------------------------------+
  17  */
  18 
  19 #ifdef HAVE_CONFIG_H
  20 #include "config.h"
  21 #endif
  22 
  23 #include "php.h"
  24 
  25 #if HAVE_IBASE
  26 
  27 #include "php_interbase.h"
  28 #include "php_ibase_includes.h"
  29 
  30 static int le_event;
  31 
  32 static void _php_ibase_event_free(char *event_buf, char *result_buf) /* {{{ */
  33 {
  34         isc_free(event_buf);
  35         isc_free(result_buf);
  36 }
  37 /* }}} */
  38 
  39 void _php_ibase_free_event(ibase_event *event TSRMLS_DC) /* {{{ */
  40 {
  41         unsigned short i;
  42 
  43         event->state = DEAD;
  44 
  45         if (event->link != NULL) {
  46                 ibase_event **node;
  47 
  48                 if (event->link->handle != NULL &&
  49                                 isc_cancel_events(IB_STATUS, &event->link->handle, &event->event_id)) {
  50                         _php_ibase_error(TSRMLS_C);
  51                 }
  52 
  53                 /* delete this event from the link struct */
  54                 for (node = &event->link->event_head; *node != event; node = &(*node)->event_next);
  55                 *node = event->event_next;
  56         }
  57 
  58         if (event->callback) {
  59                 zval_dtor(event->callback);
  60                 FREE_ZVAL(event->callback);
  61                 event->callback = NULL;
  62 
  63                 _php_ibase_event_free(event->event_buffer,event->result_buffer);
  64 
  65                 for (i = 0; i < event->event_count; ++i) {
  66                         efree(event->events[i]);
  67                 }
  68                 efree(event->events);
  69         }
  70 }
  71 /* }}} */
  72 
  73 static void _php_ibase_free_event_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
  74 {
  75         ibase_event *e = (ibase_event *) rsrc->ptr;
  76 
  77         _php_ibase_free_event(e TSRMLS_CC);
  78 
  79         efree(e);
  80 }
  81 /* }}} */
  82 
  83 void php_ibase_events_minit(INIT_FUNC_ARGS) /* {{{ */
  84 {
  85         le_event = zend_register_list_destructors_ex(_php_ibase_free_event_rsrc, NULL, 
  86             "interbase event", module_number);
  87 }
  88 /* }}} */
  89 
  90 static void _php_ibase_event_block(ibase_db_link *ib_link, unsigned short count, /* {{{ */
  91         char **events, unsigned short *l, char **event_buf, char **result_buf)
  92 {
  93         ISC_STATUS dummy_result[20];
  94         unsigned long dummy_count[15];
  95 
  96         /**
  97          * Unfortunately, there's no clean and portable way in C to pass arguments to
  98          * a variadic function if you don't know the number of arguments at compile time.
  99          * (And even if there were a way, the Interbase API doesn't provide a version of
 100          * this function that takes a va_list as an argument)
 101          *
 102          * In this case, the number of arguments is limited to 18 by the underlying API,
 103          * so we can work around it.
 104          */
 105 
 106         *l = (unsigned short) isc_event_block(event_buf, result_buf, count, events[0],
 107                 events[1], events[2], events[3], events[4], events[5], events[6], events[7],
 108                 events[8], events[9], events[10], events[11], events[12], events[13], events[14]);
 109 
 110         /**
 111          * Currently, this is the only way to correctly initialize an event buffer.
 112          * This is clearly something that should be fixed, cause the semantics of
 113          * isc_wait_for_event() indicate that it blocks until an event occurs.
 114          * If the Firebird people ever fix this, these lines should be removed,
 115          * otherwise, events will have to fire twice before ibase_wait_event() returns.
 116          */
 117 
 118         isc_wait_for_event(dummy_result, &ib_link->handle, *l, *event_buf, *result_buf);
 119         isc_event_counts(dummy_count, *l, *event_buf, *result_buf);
 120 }
 121 /* }}} */
 122 
 123 /* {{{ proto string ibase_wait_event([resource link_identifier,] string event [, string event [, ...]])
 124    Waits for any one of the passed Interbase events to be posted by the database, and returns its name */
 125 PHP_FUNCTION(ibase_wait_event)
 126 {
 127         zval ***args;
 128         ibase_db_link *ib_link;
 129         int num_args;
 130         char *event_buffer, *result_buffer, *events[15];
 131         unsigned short i = 0, event_count = 0, buffer_size;
 132         unsigned long occurred_event[15];
 133 
 134         RESET_ERRMSG;
 135 
 136         /* no more than 15 events */
 137         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 16) {
 138                 WRONG_PARAM_COUNT;
 139         }
 140 
 141         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
 142                 return;
 143         }
 144 
 145         if (Z_TYPE_PP(args[0]) == IS_RESOURCE) {
 146                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
 147                         efree(args);
 148                         RETURN_FALSE;
 149                 }
 150                 i = 1;
 151         } else {
 152                 if (ZEND_NUM_ARGS() > 15) {
 153                         efree(args);
 154                         WRONG_PARAM_COUNT;
 155                 }
 156                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
 157                         efree(args);
 158                         RETURN_FALSE;
 159                 }
 160         }
 161 
 162         for (; i < ZEND_NUM_ARGS(); ++i) {
 163                 convert_to_string_ex(args[i]);
 164                 events[event_count++] = Z_STRVAL_PP(args[i]);
 165         }
 166 
 167         /* fills the required data structure with information about the events */
 168         _php_ibase_event_block(ib_link, event_count, events, &buffer_size, &event_buffer, &result_buffer);
 169 
 170         /* now block until an event occurs */
 171         if (isc_wait_for_event(IB_STATUS, &ib_link->handle, buffer_size, event_buffer, result_buffer)) {
 172                 _php_ibase_error(TSRMLS_C);
 173                 _php_ibase_event_free(event_buffer,result_buffer);
 174                 efree(args);
 175                 RETURN_FALSE;
 176         }
 177 
 178         /* find out which event occurred */
 179         isc_event_counts(occurred_event, buffer_size, event_buffer, result_buffer);
 180         for (i = 0; i < event_count; ++i) {
 181                 if (occurred_event[i]) {
 182                         char *result = estrdup(events[i]);
 183                         _php_ibase_event_free(event_buffer,result_buffer);
 184                         efree(args);
 185                         RETURN_STRING(result,0);
 186                 }
 187         }
 188 
 189         /* If we reach this line, isc_wait_for_event() did return, but we don't know
 190            which event fired. */
 191         _php_ibase_event_free(event_buffer,result_buffer);
 192         efree(args);
 193         RETURN_FALSE;
 194 }
 195 /* }}} */
 196 
 197 static isc_callback _php_ibase_callback(ibase_event *event, /* {{{ */
 198         unsigned short buffer_size, char *result_buf)
 199 {
 200         /* this function is called asynchronously by the Interbase client library. */
 201         TSRMLS_FETCH_FROM_CTX(event->thread_ctx);
 202 
 203         /**
 204          * The callback function is called when the event is first registered and when the event
 205          * is cancelled. I consider this is a bug. By clearing event->callback first and setting
 206          * it to -1 later, we make sure nothing happens if no event was actually posted.
 207          */
 208         switch (event->state) {
 209                 unsigned short i;
 210                 unsigned long occurred_event[15];
 211                 zval event_name, link_id, return_value, *args[2];
 212 
 213                 default: /* == DEAD */
 214                         break;
 215                 case ACTIVE:
 216                         args[0] = &event_name;
 217                         args[1] = &link_id;
 218 
 219                         /* copy the updated results into the result buffer */
 220                         memcpy(event->result_buffer, result_buf, buffer_size);
 221 
 222                         INIT_ZVAL(event_name);
 223                         INIT_ZVAL(link_id);
 224                         ZVAL_RESOURCE(&link_id, event->link_res_id);
 225 
 226                         /* find out which event occurred */
 227                         isc_event_counts(occurred_event, buffer_size, event->event_buffer, event->result_buffer);
 228                         for (i = 0; i < event->event_count; ++i) {
 229                                 if (occurred_event[i]) {
 230                                         ZVAL_STRING(&event_name,event->events[i],0);
 231                                         break;
 232                                 }
 233                         }
 234 
 235                         /* call the callback provided by the user */
 236                         if (SUCCESS != call_user_function(EG(function_table), NULL,
 237                                         event->callback, &return_value, 2, args TSRMLS_CC)) {
 238                                 _php_ibase_module_error("Error calling callback %s" TSRMLS_CC, Z_STRVAL_P(event->callback));
 239                                 break;
 240                         }
 241 
 242                         if (Z_TYPE(return_value) == IS_BOOL && !Z_BVAL(return_value)) {
 243                                 event->state = DEAD;
 244                                 break;
 245                         }
 246                 case NEW:
 247                         /* re-register the event */
 248                         if (isc_que_events(IB_STATUS, &event->link->handle, &event->event_id, buffer_size,
 249                                 event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
 250 
 251                                 _php_ibase_error(TSRMLS_C);
 252                         }
 253                         event->state = ACTIVE;
 254         }
 255         return 0;
 256 }
 257 /* }}} */
 258 
 259 /* {{{ proto resource ibase_set_event_handler([resource link_identifier,] callback handler, string event [, string event [, ...]])
 260    Register the callback for handling each of the named events */
 261 PHP_FUNCTION(ibase_set_event_handler)
 262 {
 263         /**
 264          * The callback passed to this function should take an event name (string) and a
 265          * link resource id (int) as arguments. The value returned from the function is
 266          * used to determine if the event handler should remain set.
 267          */
 268         char *cb_name;
 269         zval ***args, **cb_arg;
 270         ibase_db_link *ib_link;
 271         ibase_event *event;
 272         unsigned short i = 1, buffer_size;
 273         int link_res_id, num_args;
 274 
 275         RESET_ERRMSG;
 276         
 277         /* Minimum and maximum number of arguments allowed */
 278         if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 17) {
 279                 WRONG_PARAM_COUNT;
 280         }
 281 
 282         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
 283                 return;
 284         }
 285 
 286         /* get a working link */
 287         if (Z_TYPE_PP(args[0]) != IS_STRING) {
 288                 /* resource, callback, event_1 [, ... event_15]
 289                  * No more than 15 events
 290                  */
 291                 if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 17) {
 292                         efree(args);
 293                         WRONG_PARAM_COUNT;
 294                 }
 295 
 296                 cb_arg = args[1];
 297                 i = 2;
 298 
 299                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, args[0], -1, "InterBase link", le_link, le_plink)) {
 300                         efree(args);
 301                         RETURN_FALSE;
 302                 }
 303 
 304                 convert_to_long_ex(args[0]);
 305                 link_res_id = Z_LVAL_PP(args[0]);
 306 
 307         } else {
 308                 /* callback, event_1 [, ... event_15] 
 309                  * No more than 15 events
 310                  */
 311                 if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 16) {
 312                         efree(args);
 313                         WRONG_PARAM_COUNT;
 314                 }
 315 
 316                 cb_arg = args[0];
 317 
 318                 if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link, ibase_db_link *, NULL, IBG(default_link), "InterBase link", le_link, le_plink)) {
 319                         efree(args);
 320                         RETURN_FALSE;
 321                 }
 322                 link_res_id = IBG(default_link);
 323         }
 324 
 325         /* get the callback */
 326         if (!zend_is_callable(*cb_arg, 0, &cb_name TSRMLS_CC)) {
 327                 _php_ibase_module_error("Callback argument %s is not a callable function" TSRMLS_CC, cb_name);
 328                 efree(cb_name);
 329                 efree(args);
 330                 RETURN_FALSE;
 331         }
 332         efree(cb_name);
 333 
 334         /* allocate the event resource */
 335         event = (ibase_event *) safe_emalloc(sizeof(ibase_event), 1, 0);
 336         TSRMLS_SET_CTX(event->thread_ctx);
 337         event->link_res_id = link_res_id;
 338         event->link = ib_link;
 339         event->event_count = 0;
 340         event->state = NEW;
 341         event->events = (char **) safe_emalloc(sizeof(char *),ZEND_NUM_ARGS()-i,0);
 342 
 343         ALLOC_ZVAL(event->callback);
 344         *event->callback = **cb_arg;
 345         INIT_PZVAL(event->callback);
 346         zval_copy_ctor(event->callback);
 347 
 348         for (; i < ZEND_NUM_ARGS(); ++i) {
 349                 convert_to_string_ex(args[i]);
 350                 event->events[event->event_count++] = estrdup(Z_STRVAL_PP(args[i]));
 351         }
 352 
 353         /* fills the required data structure with information about the events */
 354         _php_ibase_event_block(ib_link, event->event_count, event->events,
 355                 &buffer_size, &event->event_buffer, &event->result_buffer);
 356 
 357         /* now register the events with the Interbase API */
 358         if (isc_que_events(IB_STATUS, &ib_link->handle, &event->event_id, buffer_size,
 359                 event->event_buffer,(isc_callback)_php_ibase_callback, (void *)event)) {
 360 
 361                 _php_ibase_error(TSRMLS_C);
 362                 efree(event);
 363                 efree(args);
 364                 RETURN_FALSE;
 365         }
 366 
 367         event->event_next = ib_link->event_head;
 368         ib_link->event_head = event;
 369 
 370         ZEND_REGISTER_RESOURCE(return_value, event, le_event);
 371         zend_list_addref(Z_LVAL_P(return_value));
 372         efree(args);
 373 }
 374 /* }}} */
 375 
 376 /* {{{ proto bool ibase_free_event_handler(resource event)
 377    Frees the event handler set by ibase_set_event_handler() */
 378 PHP_FUNCTION(ibase_free_event_handler)
 379 {
 380         zval *event_arg;
 381 
 382         RESET_ERRMSG;
 383 
 384         if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &event_arg)) {
 385                 ibase_event *event;
 386 
 387                 ZEND_FETCH_RESOURCE(event, ibase_event *, &event_arg, -1, "Interbase event", le_event);
 388 
 389                 event->state = DEAD;
 390 
 391                 zend_list_delete(Z_LVAL_P(event_arg));
 392                 RETURN_TRUE;
 393         } else {
 394                 RETURN_FALSE;
 395         }
 396 }
 397 /* }}} */
 398 
 399 #endif /* HAVE_IBASE */
 400 
 401 /*
 402  * Local variables:
 403  * tab-width: 4
 404  * c-basic-offset: 4
 405  * End:
 406  * vim600: sw=4 ts=4 fdm=marker
 407  * vim<600: sw=4 ts=4
 408  */

/* [<][>][^][v][top][bottom][index][help] */