Annotation of embedaddon/php/ext/interbase/ibase_events.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>