cvs: php4 /ext/ircg ircg.c

From: Date: Thu, 23 May 2002 16:56:40 +0000
Subject: cvs: php4 /ext/ircg ircg.c
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-12063@lists.php.net to get a copy of this message
sas Thu May 23 12:56:40 2002 EDT Modified files: /php4/ext/ircg ircg.c Log: Revamped timeout handling to be more consistent; it disconnects users which are not associated with a stream window within 3 minutes. Improved the id generator, so that it becomes more unlikely that two or more consecutive runs/instances will yield the same ids. Improved error message collecting to run at constant time intervals. Added a facility which aims at ensuring that the extension does not shutdown(2) unrelated sockets. This has been disabled for now, because of lack of extensive testing. The current time is now easily accessible through a wrapper function. This replaces the ugly #ifdefs spread through the code. IRCG does not generate "Pragma: no-cache" headers anymore. Additionally, ircg_set_current() will not cause the HTTP header to be sent, so you can add/change headers afterwards. And some cleanup.

Index: php4/ext/ircg/ircg.c diff -u php4/ext/ircg/ircg.c:1.129 php4/ext/ircg/ircg.c:1.130 --- php4/ext/ircg/ircg.c:1.129 Fri Mar 8 07:43:10 2002 +++ php4/ext/ircg/ircg.c Thu May 23 12:56:36 2002 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: ircg.c,v 1.129 2002/03/08 12:43:10 sas Exp $ */ +/* $Id: ircg.c,v 1.130 2002/05/23 16:56:36 sas Exp $ */ /* {{{ includes */ @@ -33,6 +33,7 @@ #include "php_ircg.h" #include "ext/standard/html.h" +#include "ext/standard/php_lcg.h" #include "ext/standard/php_smart_str.h" #include "ext/standard/info.h" #include "ext/standard/basic_functions.h" @@ -53,7 +54,6 @@ #include <arpa/inet.h> #endif -#define IRCG_ERROR_MSG_GC_INTERVAL 50 /* }}} */ @@ -164,9 +164,11 @@ irconn_t conn; smart_str buffer; time_t login; - int buffer_count; int fd; int irconn_id; +#if 0 + struct sockaddr_in sin; /* address of stream conn */ +#endif php_fmt_msgs_t *fmt_msgs; irc_write_buf wb; HashTable ctcp_msgs; @@ -323,6 +325,28 @@ /* }}} */ + +static int is_my_conn(php_irconn_t *conn) +{ +#if 0 + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + + if (getpeername(conn->fd, &sin, &len)) { + if (errno == EBADF || errno == ENOTSOCK || errno == ENOTCONN) + return 0; + else + /* closing a connection is better than leaking fds */ + return 1; + } + + if (sin.sin_addr.s_addr == conn->sin.sin_addr.s_addr + && sin.sin_port == conn->sin.sin_port) +#endif + return 1; + return 0; +} + /* {{{ quit_handler */ static void quit_handler(irconn_t *c, void *dummy) @@ -334,7 +358,8 @@ zend_hash_index_del(&h_fd2irconn, conn->fd); if (conn->file_fd == -1) irc_write_buf_del(&conn->wb); - shutdown(conn->fd, 2); + if (is_my_conn(conn)) + shutdown(conn->fd, 2); } if (conn->file_fd != -1) { smart_str m = {0}; @@ -351,7 +376,7 @@ zend_hash_index_del(&h_irconn, conn->irconn_id); zend_hash_destroy(&conn->ctcp_msgs); - if (conn->buffer.c) smart_str_free_ex(&conn->buffer, 1); + smart_str_free_ex(&conn->buffer, 1); #ifdef IRCG_PENDING_URL if (conn->od_port) { @@ -565,6 +590,7 @@ case '%': NEW_TOKEN(C_PERCENT, v) = 0; break; default: /* ignore invalid combinations */ + break; } p = q + 1; /* skip last format character */ } while (p < pe); @@ -673,11 +699,20 @@ #define ADD_HEADER(a) sapi_add_header(a, sizeof(a) - 1, 1) +/* + * The request shutdown will trigger this automatically. + * Because there is no ctx switch during the whole HTTP + * request, it is safe to delay this operation. + */ + +#if 0 static void msg_http_start(php_irconn_t *conn TSRMLS_DC) { - ADD_HEADER("Pragma: no-cache"); sapi_send_headers(TSRMLS_C); } +#else +#define msg_http_start (void) +#endif static void http_closed_connection(int fd) { @@ -694,6 +729,25 @@ /* }}} */ +static time_t ircg_now(void) +{ + struct timeval now; + +#if IRCG_API_VERSION >= 20010601 + if (ircg_now_time_t != (time_t) 0) + return ircg_now_time_t; + else +#endif + gettimeofday(&now, NULL); + + return now.tv_sec; +} + +#define GC_INTVL 60 +#define WINDOW_TIMEOUT (3 * 60) + +static const char timeout_message[] = "Timed out waiting for streaming window"; + /* {{{ Message-delivery */ static void msg_accum_send(php_irconn_t *conn, smart_str *msg) { @@ -703,32 +757,19 @@ if (conn->file_fd != -1) { write(conn->file_fd, msg->c, msg->len); - smart_str_free_ex(msg, 1); - return; + goto done; } switch (conn->fd) { case -2: /* Connection was finished */ - smart_str_free_ex(msg, 1); - break; + goto done; case -1: /* No message window yet. Buffer */ - if (conn->buffer_count++ > 10) { - struct timeval now; - - smart_str_free_ex(msg, 1); -#if IRCG_API_VERSION >= 20010601 - if (ircg_now_time_t != (time_t) 0) - now.tv_sec = ircg_now_time_t; - else -#endif - gettimeofday(&now, NULL); - if ((now.tv_sec - conn->login) > 30) - irc_disconnect(&conn->conn, "Timed out waiting for window"); - return; + if ((ircg_now() - conn->login) > WINDOW_TIMEOUT) { + irc_disconnect(&conn->conn, timeout_message); + goto done; } smart_str_append_ex(&conn->buffer, msg, 1); - smart_str_free_ex(msg, 1); - break; + goto done; default: #if IRCG_API_VERSION - 0 >= 20010601 if ((n = irc_write_buf_append_ex(&conn->wb, msg, 0))) { @@ -757,14 +798,20 @@ irc_disconnect(&conn->conn, reason); } + return; #elif IRCG_API_VERSION - 0 >= 20010302 - irc_write_buf_append_ex(&conn->wb, msg, 0); + irc_write_buf_append_ex(&conn->wb, msg, 0); /* no copy */ + return; #else irc_write_buf_append(&conn->wb, msg); - smart_str_free_ex(msg, 1); + goto done; #endif break; } + + +done: + smart_str_free_ex(msg, 1); } static void msg_send(php_irconn_t *conn, smart_str *msg) @@ -923,7 +970,7 @@ * from the IRC server, and will usually present a nicely formatted * error message to the end-user. * - * We automatically garbage-collect every n-th login, so there is + * We automatically garbage-collect every GC_INTVL seconds, so there is * no need for a separate gc thread. */ @@ -931,9 +978,11 @@ smart_str msg; int msgid; int id; + time_t when; struct errormsg *next; }; +static time_t next_gc; static struct errormsg *errormsgs; static void error_msg_dtor(struct errormsg *m) @@ -942,21 +991,22 @@ free(m); } -static void error_msg_gc(void) +static void error_msg_gc(time_t now) { struct errormsg *m, *prev = NULL, *next; - int lim; + time_t lim; - lim = irconn_id - IRCG_ERROR_MSG_GC_INTERVAL; + lim = now - GC_INTVL; + next_gc = now + GC_INTVL; for (m = errormsgs; m; prev = m, m = m->next) { - if (m->id < lim) { + if (m->when < lim) { struct errormsg *to; /* Check whether we have subsequent outdated records */ for (to = m->next; to; to = next) { next = to->next; - if (m->id >= lim) break; + if (m->when >= lim) break; error_msg_dtor(to); } @@ -987,6 +1037,7 @@ m->id = conn->irconn_id; } + m->when = ircg_now(); m->msg.len = 0; smart_str_append_ex(&m->msg, msg, 1); m->msgid = msgid; @@ -1134,6 +1185,13 @@ if (conn->fd >= 0) send(conn->fd, " ", 2, 0); + else if (conn->file_fd < 0 && (ircg_now() - conn->login) > WINDOW_TIMEOUT) { + char buf[1024]; + + sprintf(buf, "timeout after %d seconds (%d, %d)", ircg_now()-conn->login, + ircg_now(), conn->login); + irc_disconnect(ircc, buf); + } } static void user_kick(irconn_t *ircc, smart_str *channel, smart_str *who, smart_str *kicked_by, smart_str *reason, void *dummy) @@ -1272,6 +1330,9 @@ #ifdef IRCG_WITH_THTTPD zval **p1; php_irconn_t *conn; +#if 0 + socklen_t len = sizeof(struct sockaddr_in); +#endif if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &p1) == FAILURE) WRONG_PARAM_COUNT; @@ -1287,9 +1348,17 @@ zend_hash_index_del(&h_fd2irconn, conn->fd); if (conn->file_fd == -1) irc_write_buf_del(&conn->wb); - shutdown(conn->fd, 2); + if (is_my_conn(conn)) + shutdown(conn->fd, 2); } +#if 0 + /* store peer information for safe shutdown */ + if (getpeername(conn->fd, &conn->sin, &len) == -1) { + php_error(E_WARNING, "getpeername failed: %d (%s)", errno, strerror(errno)); + } +#endif + irc_set_currents++; thttpd_register_on_close(http_closed_connection); thttpd_set_dont_close(); @@ -1800,7 +1869,6 @@ php_fmt_msgs_t *fmt_msgs = NULL; php_irconn_t *conn; int bailout_on_trivial = 1; - struct timeval tv; if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 7 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &p1, &p2, &p3, &p4, &p5, &p6, &p7) == FAILURE) @@ -1874,24 +1942,22 @@ } conn->password = conn->ident = NULL; if (irconn_id == 0) - irconn_id = time(NULL); + irconn_id = 10000.0 * php_combined_lcg(TSRMLS_C); else + irconn_id += 20.0 * (1.0 + php_combined_lcg(TSRMLS_C)); + + + while (zend_hash_index_exists(&h_irconn, irconn_id)) { irconn_id++; - if ((irconn_id % IRCG_ERROR_MSG_GC_INTERVAL) == 0) - error_msg_gc(); + } + conn->irconn_id = irconn_id; zend_hash_index_update(&h_irconn, irconn_id, &conn, sizeof(conn), NULL); conn->buffer.c = NULL; - conn->buffer_count = 0; -#if IRCG_API_VERSION >= 20010601 - if (ircg_now_time_t != (time_t) 0) - conn->login = ircg_now_time_t; - else -#endif - { - gettimeofday(&tv, NULL); - conn->login = tv.tv_sec; - } + conn->login = ircg_now(); + + if (conn->login >= next_gc) + error_msg_gc(conn->login); RETVAL_LONG(irconn_id); }
« previous php.cvs (#12063) next »