├── .gitignore ├── LICENSE ├── README.md ├── config.h ├── config.m4 ├── example ├── server.php └── www │ ├── form.html │ ├── index.html │ ├── webim │ ├── login.html │ ├── main.html │ └── resource │ │ ├── css │ │ ├── bootstrap.css │ │ ├── bootstrap1.css │ │ ├── chat.css │ │ └── main.css │ │ ├── img │ │ ├── avatar1.jpg │ │ ├── button.gif │ │ ├── button.jpg │ │ ├── button1.jpg │ │ ├── button2.jpg │ │ ├── default.jpg │ │ ├── f1.png │ │ └── face │ │ │ ├── 1.gif │ │ │ ├── 10.gif │ │ │ ├── 11.gif │ │ │ ├── 12.gif │ │ │ ├── 13.gif │ │ │ ├── 14.gif │ │ │ ├── 15.gif │ │ │ ├── 16.gif │ │ │ ├── 17.gif │ │ │ ├── 18.gif │ │ │ ├── 19.gif │ │ │ ├── 2.gif │ │ │ ├── 3.gif │ │ │ ├── 4.gif │ │ │ ├── 5.gif │ │ │ ├── 6.gif │ │ │ ├── 7.gif │ │ │ ├── 8.gif │ │ │ └── 9.gif │ │ └── js │ │ ├── bootstrap.js │ │ ├── chat.js │ │ ├── jquery.js │ │ └── jquery.json.js │ ├── webqq │ ├── css │ │ └── style.css │ ├── images │ │ ├── QQ-ICON.png │ │ ├── body-bg.jpg │ │ ├── bot-menu │ │ │ ├── 01.png │ │ │ ├── 02.png │ │ │ ├── 03.png │ │ │ ├── 04.png │ │ │ ├── 05.png │ │ │ ├── 06.png │ │ │ ├── 07.png │ │ │ ├── 08.png │ │ │ ├── 09.png │ │ │ ├── 10.png │ │ │ ├── 11.png │ │ │ ├── 12.png │ │ │ ├── 13.png │ │ │ ├── 14.png │ │ │ ├── 15.png │ │ │ └── 16.png │ │ ├── box-bg.jpg │ │ ├── chat │ │ │ ├── fa.png │ │ │ ├── icon-00.png │ │ │ ├── icon-01.png │ │ │ ├── icon-02.png │ │ │ ├── icon-03.png │ │ │ ├── icon-04.png │ │ │ ├── icon-05.png │ │ │ ├── icon-06.png │ │ │ ├── icon-07.png │ │ │ ├── menu-01.png │ │ │ ├── menu-02.png │ │ │ ├── menu-03.png │ │ │ ├── menu-04.png │ │ │ ├── menu-05.png │ │ │ ├── menu-06.png │ │ │ ├── menu-07.png │ │ │ ├── menu-08.png │ │ │ ├── menu-09.png │ │ │ ├── menu-10.png │ │ │ ├── win.png │ │ │ └── wins.png │ │ ├── github.png │ │ ├── head │ │ │ ├── 1.jpg │ │ │ ├── 10.jpg │ │ │ ├── 11.jpg │ │ │ ├── 12.jpg │ │ │ ├── 13.jpg │ │ │ ├── 14.jpg │ │ │ ├── 15.jpg │ │ │ ├── 16.jpg │ │ │ ├── 17.jpg │ │ │ ├── 18.jpg │ │ │ ├── 19.jpg │ │ │ ├── 2.jpg │ │ │ ├── 20.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── 7.jpg │ │ │ ├── 8.jpg │ │ │ └── 9.jpg │ │ ├── icon-02-01.png │ │ ├── icon-02-02.png │ │ ├── icon-02-03.png │ │ ├── icon-02-04.png │ │ ├── login │ │ │ ├── head.jpg │ │ │ └── qq-login-bg.jpg │ │ ├── lv.png │ │ ├── qq-bg.jpg │ │ ├── qq-top-01.png │ │ ├── qq-top-02.png │ │ ├── qq-top.png │ │ ├── qq-xuan-jiao.png │ │ ├── serch.png │ │ ├── svip.png │ │ ├── top-menu.png │ │ ├── win-bg.png │ │ ├── win.png │ │ └── zai.png │ ├── index.html │ ├── js │ │ ├── index.js │ │ ├── jquery.cookie.js │ │ ├── jquery.js │ │ ├── jquery.json.js │ │ ├── nicescroll.js │ │ └── superslide.2.1.js │ └── register.html │ └── website │ ├── css │ ├── bootstrap-theme.min.css │ └── bootstrap.min.css │ ├── img │ ├── qq.png │ └── return-back.png │ ├── index.html │ └── js │ ├── .jquery.min.js.swp │ ├── bootstrap.min.js │ └── jquery.min.js ├── include ├── appnet_dict.h ├── appnet_event.h ├── appnet_list.h ├── appnet_request.h ├── appnet_response.h ├── appnet_sds.h ├── appnet_server.h ├── appnet_socket.h ├── appnet_websocket.h ├── base64.h ├── config.h ├── mime_types.h ├── rbtree.h ├── ring_buffer.h ├── sha1.h ├── share_memory.h └── zmalloc.h ├── php_appnet.c ├── php_appnet.h ├── php_appnet_server.c └── src ├── appnet_dict.c ├── appnet_epoll.c ├── appnet_event.c ├── appnet_list.c ├── appnet_request.c ├── appnet_response.c ├── appnet_sds.c ├── appnet_select.c ├── appnet_server.c ├── appnet_socket.c ├── appnet_websocket.c ├── appnet_worker.c ├── base64.c ├── rbtree.c ├── ring_buffer.c ├── sha1.c ├── share_memory.c ├── test.c └── zmalloc.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | core 31 | 32 | /.deps 33 | /.libs/ 34 | /Makefile 35 | /Makefile.fragments 36 | /Makefile.global 37 | /Makefile.objects 38 | /acinclude.m4 39 | /aclocal.m4 40 | /autom4te.cache/ 41 | /build/ 42 | /config.guess 43 | /config.h.in 44 | /config.log 45 | /config.nice 46 | /config.status 47 | /config.sub 48 | /configure 49 | /configure.in 50 | /install-sh 51 | /libtool 52 | /ltmain.sh 53 | /missing 54 | /mkinstalldirs 55 | /run-tests.php 56 | 57 | /.autotools 58 | /.cproject 59 | /.project 60 | /.settings/ 61 | 62 | # Debug files 63 | *.dSYM/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, lchb369 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # appnet介绍
2 | appnet是一个由C语言开发基于linux epoll的多线程+多进程的高性能异步网络库,可以同时支持TCP,HTTP和Websocket混合协议,目标是用php7+appnet快速构建高性能的长连接服务器。使其可广泛用于聊天系统,游戏服务器,消息通知服务器等实时通信场景。

3 |

4 | ##其特点有
5 | 15 | ##安装方法:
16 | 1,源码安装PHP7.0以上版本
2,下载扩展到任意目录appnet
3,执行如下指令:
 >cd appnet
 >/usr/local/php7/bin/phpize
 >./configure --with-php-config=/usr/local/php7/bin/php-config
 >make
 >make install

17 |

启动服务器

18 |

 >php example/server.php 

19 |

TCP测试:

20 |

 >telnet 127.0.0.1 3011

21 |

Http/Websocket测试:

22 |

webqq:http://www.appnet.site/webqq/index.html

23 |

双击QQ图标打开登录框,随便输入帐号进入

24 |

 

25 |

完整示例参见:https://github.com/lchb369/appnet_php7/blob/master/example/server.php

26 |

 更多介绍参见:https://github.com/lchb369/appnet_php7/wiki/appnet%E4%BB%8B%E7%BB%8D

27 |

 QQ交流群:379084776

28 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.in by autoheader. */ 3 | 4 | /* Whether to build appnet as dynamic module */ 5 | #define COMPILE_DL_APPNET 1 6 | 7 | /* Define to 1 if you have the header file. */ 8 | #define HAVE_DLFCN_H 1 9 | 10 | /* Define to 1 if you have the header file. */ 11 | #define HAVE_INTTYPES_H 1 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #define HAVE_MEMORY_H 1 15 | 16 | /* Define to 1 if you have the header file. */ 17 | #define HAVE_STDINT_H 1 18 | 19 | /* Define to 1 if you have the header file. */ 20 | #define HAVE_STDLIB_H 1 21 | 22 | /* Define to 1 if you have the header file. */ 23 | #define HAVE_STRINGS_H 1 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #define HAVE_STRING_H 1 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #define HAVE_SYS_STAT_H 1 30 | 31 | /* Define to 1 if you have the header file. */ 32 | #define HAVE_SYS_TYPES_H 1 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #define HAVE_UNISTD_H 1 36 | 37 | /* Define to 1 if your C compiler doesn't accept -c and -o together. */ 38 | /* #undef NO_MINUS_C_MINUS_O */ 39 | 40 | /* Define to the address where bug reports for this package should be sent. */ 41 | #define PACKAGE_BUGREPORT "" 42 | 43 | /* Define to the full name of this package. */ 44 | #define PACKAGE_NAME "" 45 | 46 | /* Define to the full name and version of this package. */ 47 | #define PACKAGE_STRING "" 48 | 49 | /* Define to the one symbol short name of this package. */ 50 | #define PACKAGE_TARNAME "" 51 | 52 | /* Define to the home page for this package. */ 53 | #define PACKAGE_URL "" 54 | 55 | /* Define to the version of this package. */ 56 | #define PACKAGE_VERSION "" 57 | 58 | /* Define to 1 if you have the ANSI C header files. */ 59 | #define STDC_HEADERS 1 60 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension appnet 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | dnl PHP_ARG_WITH(appnet, for appnet support, 11 | dnl Make sure that the comment is aligned: 12 | dnl [ --with-appnet Include appnet support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | PHP_ARG_ENABLE(appnet, whether to enable appnet support, 17 | dnl Make sure that the comment is aligned: 18 | [ --enable-appnet Enable appnet support]) 19 | 20 | if test -z "$PHP_DEBUG" ; then 21 | AC_ARG_ENABLE(debug, [--enable-debug compile with debugging system], [PHP_DEBUG=$enableval],[PHP_DEBUG=no] ) 22 | fi 23 | 24 | AC_MSG_CHECKING([if compiling with clang]) 25 | AC_COMPILE_IFELSE([ 26 | AC_LANG_PROGRAM([], [[ 27 | #ifndef __clang__ 28 | not clang 29 | #endif 30 | ]])], 31 | [CLANG=yes], [CLANG=no] 32 | ) 33 | AC_MSG_RESULT([$CLANG]) 34 | 35 | if test "$CLANG" = "yes"; then 36 | CFLAGS="$CFLAGS -std=gnu89" 37 | fi 38 | 39 | if test "$PHP_APPNET" != "no"; then 40 | dnl Write more examples of tests here... 41 | PHP_ADD_LIBRARY(pthread) 42 | dnl # --with-appnet -> check with-path 43 | dnl SEARCH_PATH="/usr/local /usr" # you might want to change this 44 | dnl SEARCH_FOR="/include/appnet.h" # you most likely want to change this 45 | dnl if test -r $PHP_APPNET/$SEARCH_FOR; then # path given as parameter 46 | dnl APPNET_DIR=$PHP_APPNET 47 | dnl else # search default path list 48 | dnl AC_MSG_CHECKING([for appnet files in default path]) 49 | dnl for i in $SEARCH_PATH ; do 50 | dnl if test -r $i/$SEARCH_FOR; then 51 | dnl APPNET_DIR=$i 52 | dnl AC_MSG_RESULT(found in $i) 53 | dnl fi 54 | dnl done 55 | dnl fi 56 | dnl 57 | dnl if test -z "$APPNET_DIR"; then 58 | dnl AC_MSG_RESULT([not found]) 59 | dnl AC_MSG_ERROR([Please reinstall the appnet distribution]) 60 | dnl fi 61 | 62 | dnl # --with-appnet -> add include path 63 | PHP_ADD_INCLUDE($APPNET_DIR/include) 64 | 65 | dnl # --with-appnet -> check for lib and symbol presence 66 | dnl LIBNAME=appnet # you may want to change this 67 | dnl LIBSYMBOL=appnet # you most likely want to change this 68 | 69 | dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 70 | dnl [ 71 | dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $APPNET_DIR/$PHP_LIBDIR, APPNET_SHARED_LIBADD) 72 | dnl AC_DEFINE(HAVE_APPNETLIB,1,[ ]) 73 | dnl ],[ 74 | dnl AC_MSG_ERROR([wrong appnet lib version or lib not found]) 75 | dnl ],[ 76 | dnl -L$APPNET_DIR/$PHP_LIBDIR -lm 77 | dnl ]) 78 | dnl 79 | dnl PHP_SUBST(APPNET_SHARED_LIBADD) 80 | 81 | CFLAGS="-Wall -pthread $CFLAGS" 82 | LDFLAGS="$LDFLAGS -lpthread" 83 | 84 | PHP_SUBST(APPNET_SHARED_LIBADD) 85 | PHP_ADD_LIBRARY(pthread, 1, APPNET_SHARED_LIBADD) 86 | app_source="src/appnet_server.c \ 87 | src/appnet_epoll.c \ 88 | src/appnet_socket.c \ 89 | src/appnet_worker.c \ 90 | src/appnet_event.c \ 91 | src/zmalloc.c \ 92 | src/appnet_sds.c \ 93 | src/appnet_dict.c \ 94 | src/appnet_list.c \ 95 | src/appnet_request.c \ 96 | src/sha1.c \ 97 | src/base64.c \ 98 | src/appnet_websocket.c \ 99 | src/share_memory.c \ 100 | src/appnet_response.c" 101 | PHP_NEW_EXTENSION(appnet, $app_source php_appnet.c php_appnet_server.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) 102 | fi 103 | -------------------------------------------------------------------------------- /example/server.php: -------------------------------------------------------------------------------- 1 | close( $fd ); 50 | } 51 | 52 | } 53 | 54 | public static function getOnline( $serv , $fd , $msg ) 55 | { 56 | $resMsg = array( 57 | 'cmd' => 'getOnline', 58 | ); 59 | $list = self::getConnlist(); 60 | foreach ( $list as $clid => $info ) 61 | { 62 | $resMsg['list'][] = array( 63 | 'fd' => $clid, 64 | 'name' => $info['name'], 65 | 'avatar' => $info['avatar'], 66 | ); 67 | } 68 | $serv->send( $fd , json_encode( $resMsg ) ); 69 | } 70 | 71 | 72 | private static function setConnlist( $fd , $conn ) 73 | { 74 | if( WORKER_NUM > 1 ) 75 | { 76 | $list = apcu_fetch( "webchat_conn_list" ); 77 | $list[$fd] = $conn; 78 | apcu_store( "webchat_conn_list" , $list ); 79 | } 80 | else 81 | { 82 | self::$connections[$fd] = $conn; 83 | } 84 | } 85 | 86 | 87 | private static function delConnlist( $fd ) 88 | { 89 | if( WORKER_NUM > 1 ) 90 | { 91 | $list = apcu_fetch( "webchat_conn_list" ); 92 | unset( $list[$fd] ); 93 | apcu_store( "webchat_conn_list" , $list ); 94 | } 95 | else 96 | { 97 | unset( self::$connections[$fd] ); 98 | } 99 | } 100 | 101 | 102 | private static function getConnlist() 103 | { 104 | if( WORKER_NUM > 1 ) 105 | { 106 | $list = apcu_fetch( "webchat_conn_list" ); 107 | return $list; 108 | } 109 | return self::$connections; 110 | } 111 | 112 | public static function onLogin( $serv , $fd , $msg ) 113 | { 114 | $list = self::getConnlist(); 115 | if( $list ) 116 | { 117 | foreach( $list as $connfd => $info ) 118 | { 119 | if( $info['session_id'] == $msg['session_id'] && $fd != $connfd ) 120 | { 121 | echo "login repeat by same brower"; 122 | self::broadcastOffLine( $serv , $connfd ); 123 | } 124 | } 125 | } 126 | 127 | 128 | self::setConnlist( $fd , array( 'name' => $msg['name'] , 'avatar' => $msg['avatar'] , 'session_id' => $msg['session_id'] )); 129 | 130 | $resMsg = array( 131 | 'cmd' => 'login', 132 | 'fd' => $fd, 133 | 'name' => $msg['name'], 134 | 'avatar' => $msg['avatar'], 135 | ); 136 | $len = $serv->send( $fd , json_encode( $resMsg ) ); 137 | self::broadcastNewUser( $serv , $fd , $msg , $resMsg ); 138 | } 139 | 140 | public static function broadcastNewUser( $serv , $fd , $msg , $resMsg ) 141 | { 142 | $resMsg['cmd'] = 'newUser'; 143 | $loginMsg = array( 144 | 'cmd' => 'fromMsg', 145 | 'from' => 0, 146 | 'channal' => 0 , 147 | 'data' => $msg['name']."上线鸟。。", 148 | ); 149 | 150 | $list = self::getConnlist(); 151 | //将上线消息发送给所有人 152 | foreach ( $list as $clid => $info ) 153 | { 154 | if( $fd != $clid ) 155 | { 156 | $serv->send( $clid , json_encode( $resMsg ) ); 157 | $serv->send( $clid , json_encode( $loginMsg ) ); 158 | } 159 | } 160 | } 161 | 162 | public static function broadcastOffLine( $serv , $fd ) 163 | { 164 | $list = self::getConnlist(); 165 | if(empty($list[$fd]))return; 166 | 167 | $resMsg = array( 168 | 'cmd' => 'offline', 169 | 'fd' => $fd, 170 | 'from' => 0, 171 | 'channal' => 0 , 172 | 'data' => $list[$fd]['name'], 173 | ); 174 | 175 | //将下线消息发送给所有人 176 | foreach ( $list as $clid => $info ) 177 | { 178 | if( $fd != $clid ) 179 | { 180 | $serv->send( $clid , json_encode( $resMsg ) ); 181 | } 182 | } 183 | unset( $list[$fd] ); 184 | self::delConnlist( $fd ); 185 | } 186 | 187 | public static function onMessage( $serv , $fd , $msg ) 188 | { 189 | $resMsg = $msg; 190 | $resMsg['cmd'] = 'fromMsg'; 191 | //表示群发 192 | if( $msg['channal'] == 0 ) 193 | { 194 | 195 | $list = self::getConnlist(); 196 | foreach ( $list as $clid => $info ) 197 | { 198 | $serv->send( $clid , json_encode( $resMsg ) ); 199 | } 200 | } 201 | //表示私聊 202 | elseif ( $msg['channal'] == 1 ) 203 | { 204 | $serv->send( $msg['to'] , json_encode( $resMsg ) ); 205 | $serv->send( $msg['from'] , json_encode( $resMsg ) ); 206 | } 207 | //$serv->close( $fd ); 208 | } 209 | } 210 | 211 | 212 | function onTaskCallback( $server , $data , $taskid , $from ) 213 | { 214 | $pid = posix_getpid(); 215 | echo "onTaskCallback data=[{$data}],taskid=[{$taskid}],from=[{$from}],pid={$pid} \n"; 216 | } 217 | 218 | function onConnect( $server , $fd ) 219 | { 220 | $pid = posix_getpid(); 221 | echo "\n\nNew Connect:{$fd} pid={$pid} \n"; 222 | } 223 | 224 | //在worker进程中,表示回调,在task进程中表示请求 225 | function onTask( $server, $data , $taskid, $from ) 226 | { 227 | $pid = posix_getpid(); 228 | echo "onTask data=[{$data}],taskid=[{$taskid}],from=[{$from}],pid={$pid} \n"; 229 | //sleep( 3 ); 230 | $ret = array( 231 | 'status' => 'ok', 232 | 'data' => array( 'a' => "aaaa" ), 233 | ); 234 | $server->taskCallback( json_encode( $ret ) , $taskid , $from ); 235 | } 236 | 237 | function onRecv( $server , $fd , $buffer ) 238 | { 239 | $header = $server->getHeader(); 240 | $pid = posix_getpid(); 241 | echo "RecvClient:[{$header['Protocol']}][{$buffer}][{$fd}],pid={$pid} \n"; 242 | 243 | if( $header['Protocol'] == "WEBSOCKET" ) 244 | { 245 | WebChat::onReceive( $server , $fd, $buffer ); 246 | } 247 | elseif( $header['Protocol'] == "HTTP" ) 248 | { 249 | if( $header['Uri'] == '/' ) 250 | { 251 | /*redirct url,httpRedirect( $url , $status ),$status can be 301 or 302*/ 252 | $server->httpRedirect( "/website/index.html" ); 253 | 254 | /*response a error header code if you need*/ 255 | //$server->httpRespCode( 403 ); 256 | return; 257 | } 258 | 259 | $data = $buffer; 260 | $data .= microtime(); 261 | echo "Response:[".$data."]\n"; 262 | 263 | /*add async task to task worker process*/ 264 | //$server->addAsynTask( $data , 1 ); 265 | $server->setHeader( "Connection" , "keep-alive" ); 266 | //ajax访问时,会有跨域问题 267 | $server->setHeader( "Access-Control-Allow-Origin" , "*" ); 268 | $server->send( $fd , $data ); 269 | } 270 | else 271 | { 272 | $server->send( $fd , $buffer ); 273 | } 274 | }; 275 | 276 | function onClose( $server , $fd ) 277 | { 278 | echo "CloseClient:$fd \n"; 279 | $header = $server->getHeader(); 280 | if( $header['Protocol'] == "WEBSOCKET" ) 281 | { 282 | WebChat::broadcastOffLine( $server , $fd ); 283 | } 284 | }; 285 | 286 | function onStart( $server ) 287 | { 288 | $pid = posix_getpid(); 289 | echo "On Worker Start!! pid={$pid} \n"; 290 | //3000ms means 3second 291 | $server->timerAdd( 3000 , "flag or json data" ); 292 | }; 293 | 294 | //on worker shutdown,you must save data in last time. 295 | function onFinal( $server ) 296 | { 297 | $pid = posix_getpid(); 298 | echo "On Worker Final!! pid={$pid} \n"; 299 | }; 300 | 301 | function onTimer( $server , $timer_id , $flag ) 302 | { 303 | $pid = posix_getpid(); 304 | echo "onTimer:flag={$flag},pid={$pid},timer_id={$timer_id}...\n"; 305 | //if do not remove it, it will be call this function forever 306 | $server->timerRemove( $timer_id ); 307 | } 308 | 309 | 310 | //dl( "appnet.so"); 311 | $server = new AppnetServer( "0.0.0.0" , 3011 ); 312 | $ret = $server->listenHttp( 80 ); 313 | $server->listenWebsocket( 3200 ); 314 | 315 | $server->setOption( APPNET_OPT_DAEMON , 1); 316 | $server->setOption( APPNET_OPT_WORKER_NUM , WORKER_NUM ); 317 | $server->setOption( APPNET_OPT_TASK_WORKER_NUM , 0 ); 318 | $server->setOption( APPNET_OPT_REACTOR_NUM, 1 ); 319 | $server->setOption( APPNET_OPT_MAX_CONNECTION , 10000 ); 320 | $server->setOption( APPNET_HTTP_DOCS_ROOT , $_SERVER['PWD']."/example/www/" ); 321 | $server->setOption( APPNET_HTTP_UPLOAD_DIR, "/home/upload/" ); 322 | $server->setOption( APPNET_HTTP_404_PAGE , "404.html" ); 323 | $server->setOption( APPNET_HTTP_50X_PAGE , "50x.html" ); 324 | $server->setOption( APPNET_HTTP_KEEP_ALIVE , 1 ); 325 | 326 | $server->addEventListener( APPNET_EVENT_CONNECT , "onConnect"); 327 | $server->addEventListener( APPNET_EVENT_RECV , "onRecv"); 328 | $server->addEventListener( APPNET_EVENT_CLOSE , "onClose"); 329 | $server->addEventListener( APPNET_EVENT_START , "onStart"); 330 | $server->addEventListener( APPNET_EVENT_FINAL , "onFinal"); 331 | $server->addEventListener( APPNET_EVENT_TIMER , "onTimer"); 332 | $server->addEventListener( APPNET_EVENT_TASK , "onTask"); 333 | $server->addEventListener( APPNET_EVENT_TASK_CB , "onTaskCallback" ); 334 | $server->run(); 335 | 336 | $info = $server->getInfo(); 337 | 338 | 339 | ?> 340 | -------------------------------------------------------------------------------- /example/www/form.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Name:
4 | Upload: 5 | 6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /example/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | appnet示例 5 | 6 | 7 |

appnet示例

8 | website
9 | http表单上传
10 | websocket聊天室 11 | 12 |

静态页面和资源直接从tcp层返回客户端,所以服务端不会收到静态资源请求

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /example/www/webim/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 37 | 72 | 73 | 89 | 90 | -------------------------------------------------------------------------------- /example/www/webim/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | appnet websocket chatroom 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 45 | 46 |
47 |
48 |
49 | 50 | 51 |
52 | 53 | 58 | 59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 | 67 | 68 |
69 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 | 87 | 88 |
89 |
90 |
91 | 92 | 93 |
94 |
95 |
96 |
97 | 98 | 99 | 100 | 101 | 102 |
103 |
104 | 109 |
    110 |
111 |
112 |
113 |
114 | 115 |
116 |
117 | 118 | 136 | 137 |
138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /example/www/webim/resource/css/chat.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | 4 | 5 | ul.dropdown-menu { 6 | min-width: 100px; 7 | } 8 | 9 | .login-box { 10 | padding: 50px 0; 11 | background-color: white; 12 | } 13 | 14 | div.container { 15 | width: 98%; 16 | } 17 | 18 | .c-sidebar-nav { 19 | padding: 9px 0; 20 | } 21 | 22 | #left-column { 23 | position:fixed; 24 | left: -10px; 25 | } 26 | 27 | #chat-column { 28 | position: fixed; 29 | background-color: whiteSmoke; 30 | left: 220px; 31 | overflow:auto; 32 | height:600px; 33 | } 34 | 35 | #right-column { 36 | position:fixed; 37 | right: 10px; 38 | } 39 | 40 | #input-box { 41 | position:fixed; 42 | bottom: 0px; 43 | left: 220px; 44 | height: 65px; 45 | background-color: #DDD; 46 | } 47 | 48 | .post-form{ 49 | margin: 10px 10px; 50 | } 51 | 52 | .separator { 53 | border-bottom: 1px solid #222; 54 | } 55 | 56 | #chat-column ul{ 57 | list-style-type: none; 58 | margin-left: 0px; 59 | } 60 | 61 | div.message-container{ 62 | clear: both; 63 | position:relative; 64 | line-height: 20px; 65 | padding: 6px 10px; 66 | } 67 | 68 | div#chat-messages { 69 | overflow: auto; 70 | height:450px; 71 | } 72 | 73 | div.msg-time{ 74 | position:absolute; 75 | top:7px; 76 | right:10px; 77 | font-size: 11px; 78 | color: #999; 79 | } 80 | 81 | div.message{ 82 | margin-right:100px; 83 | } 84 | 85 | #chat-column .userpic{ 86 | float:left; 87 | margin-right:5px; 88 | } 89 | 90 | li.user-online { 91 | margin-bottom: 5px; 92 | } 93 | 94 | li.user-online img { 95 | margin-right: 5px; 96 | } 97 | 98 | #group-column { 99 | left: 250px; 100 | position: fixed; 101 | } 102 | 103 | .chat-room{ 104 | margin-bottom: 20px; 105 | } 106 | #left-userlist { 107 | margin-left: 10px; 108 | } 109 | 110 | #left-userlist li { 111 | float: left; 112 | height: 60px; 113 | list-style: none outside none; 114 | margin-top: 10px; 115 | width: 60px; 116 | margin-left: 0px; 117 | } 118 | #left-userlist li img{ 119 | border-radius: 5px; 120 | } 121 | 122 | .chat_face { 123 | text-align:center; 124 | height:28px; 125 | line-height:28px; 126 | color:#333; 127 | cursor:pointer; 128 | overflow:hidden; 129 | display:inline-block; 130 | } 131 | 132 | .chat_face_hover { 133 | color:#f25000; 134 | height:28px; 135 | line-height:28px; 136 | overflow:hidden; 137 | } 138 | 139 | .show_face { 140 | background:#FFFFFF; 141 | border:#ccc 1px solid; 142 | width:600px; 143 | display:none; 144 | z-index:9999; 145 | } 146 | .show_face_hovers { 147 | display:block; 148 | position:absolute; 149 | } 150 | 151 | .face { 152 | width:30px; 153 | margin-right:1px; 154 | height:30px; 155 | line-height:30px; 156 | font-size:13px; 157 | text-align:center; 158 | background:#f6f6f6; 159 | vertical-align:top; 160 | margin-bottom:1px; 161 | display:inline-block; 162 | } 163 | -------------------------------------------------------------------------------- /example/www/webim/resource/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | } 3 | 4 | 5 | ul.dropdown-menu { 6 | min-width: 100px; 7 | } 8 | 9 | .login-box { 10 | padding: 50px 0; 11 | background-color: white; 12 | } 13 | 14 | div.container { 15 | width: 98%; 16 | } 17 | 18 | .c-sidebar-nav { 19 | padding: 9px 0; 20 | } 21 | 22 | #left-column { 23 | position:fixed; 24 | left: -10px; 25 | } 26 | 27 | #chat-column { 28 | position: fixed; 29 | background-color: whiteSmoke; 30 | left: 220px; 31 | overflow:auto; 32 | height:600px; 33 | } 34 | 35 | #right-column { 36 | position:fixed; 37 | right: 10px; 38 | } 39 | 40 | #input-box { 41 | position:fixed; 42 | bottom: 0px; 43 | left: 220px; 44 | height: 65px; 45 | background-color: #DDD; 46 | } 47 | 48 | .post-form{ 49 | margin: 10px 10px; 50 | } 51 | 52 | .separator { 53 | border-bottom: 1px solid #222; 54 | } 55 | 56 | #chat-column ul{ 57 | list-style-type: none; 58 | margin-left: 0px; 59 | } 60 | 61 | div.message-container{ 62 | clear: both; 63 | position:relative; 64 | line-height: 20px; 65 | padding: 6px 10px; 66 | } 67 | 68 | div#chat-messages { 69 | overflow: auto; 70 | height:600px; 71 | } 72 | 73 | div.msg-time{ 74 | position:absolute; 75 | top:7px; 76 | right:10px; 77 | font-size: 11px; 78 | color: #999; 79 | } 80 | 81 | div.message{ 82 | margin-right:100px; 83 | } 84 | 85 | #chat-column .userpic{ 86 | float:left; 87 | margin-right:5px; 88 | } 89 | 90 | li.user-online { 91 | margin-bottom: 5px; 92 | } 93 | 94 | li.user-online img { 95 | margin-right: 5px; 96 | } 97 | 98 | #group-column { 99 | left: 250px; 100 | position: fixed; 101 | } 102 | 103 | .chat-room{ 104 | margin-bottom: 20px; 105 | } 106 | #left-userlist { 107 | margin-left: 10px; 108 | } 109 | 110 | #left-userlist li { 111 | float: left; 112 | height: 60px; 113 | list-style: none outside none; 114 | margin-top: 10px; 115 | width: 60px; 116 | margin-left: 0px; 117 | } 118 | #left-userlist li img{ 119 | border-radius: 5px; 120 | } -------------------------------------------------------------------------------- /example/www/webim/resource/img/avatar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/avatar1.jpg -------------------------------------------------------------------------------- /example/www/webim/resource/img/button.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/button.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/button.jpg -------------------------------------------------------------------------------- /example/www/webim/resource/img/button1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/button1.jpg -------------------------------------------------------------------------------- /example/www/webim/resource/img/button2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/button2.jpg -------------------------------------------------------------------------------- /example/www/webim/resource/img/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/default.jpg -------------------------------------------------------------------------------- /example/www/webim/resource/img/f1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/f1.png -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/1.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/10.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/11.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/12.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/13.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/14.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/15.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/16.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/17.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/18.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/19.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/2.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/3.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/4.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/5.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/6.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/7.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/8.gif -------------------------------------------------------------------------------- /example/www/webim/resource/img/face/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/webim/resource/img/face/9.gif -------------------------------------------------------------------------------- /example/www/webim/resource/js/chat.js: -------------------------------------------------------------------------------- 1 | var ws = {}; 2 | var client_id = 0; 3 | var userlist = {}; 4 | var GET = new Object(); 5 | GET = getRequest(); 6 | 7 | var ip = document.domain; 8 | var port = location.port; 9 | 10 | $(document).ready( 11 | function() { 12 | if ( window.WebSocket || window.MozWebSocket) 13 | { 14 | ws = new WebSocket( "ws://"+ip+":"+port ); 15 | /** 16 | * 连接建立时触发 17 | */ 18 | ws.onopen = function(e) 19 | { 20 | //必须的输入一个名称和一个图像才可以聊天 21 | if (GET['name'] == undefined || GET['avatar'] == undefined) 22 | { 23 | alert('非法请求'); 24 | ws.close(); 25 | return false; 26 | } 27 | 28 | //发送登录信息 29 | 30 | msg = new Object(); 31 | msg.cmd = 'login'; 32 | msg.name = GET['name']; 33 | msg.avatar = GET['avatar']; 34 | ws.send( $.toJSON( msg )); 35 | }; 36 | 37 | //有消息到来时触发 38 | ws.onmessage = function( e ) 39 | { 40 | var cmd = $.evalJSON( e.data ).cmd; 41 | if( cmd == 'login' ) 42 | { 43 | client_id = $.evalJSON( e.data ).fd; 44 | //获取在线列表 45 | msg = new Object(); 46 | msg.cmd = 'getOnline'; 47 | ws.send( $.toJSON( msg ) ); 48 | 49 | //alert( "收到消息了:"+e.data ); 50 | } 51 | else if( cmd == 'getOnline' ) 52 | { 53 | showOnlineList( e.data ); 54 | } 55 | else if( cmd == 'newUser' ) 56 | { 57 | showNewUser( e.data ); 58 | } 59 | else if( cmd == 'fromMsg' ) 60 | { 61 | showNewMsg( e.data ); 62 | } 63 | else if( cmd == 'offline' ) 64 | { 65 | var cid = $.evalJSON( e.data ).fd; 66 | delUser( cid ); 67 | showNewMsg( e.data ); 68 | } 69 | }; 70 | 71 | 72 | /** 73 | * 连接关闭事件 74 | */ 75 | ws.onclose = function(e) 76 | { 77 | if( confirm( "您已退出聊天室" )) 78 | { 79 | //alert('您已退出聊天室'); 80 | location.href = 'login.html'; 81 | } 82 | }; 83 | 84 | /** 85 | * 异常事件 86 | */ 87 | ws.onerror = function(e) 88 | { 89 | alert( "异常:"+e.data ); 90 | console.log("onerror"); 91 | }; 92 | 93 | function selectUser(userid) { 94 | $('#userlist').val(userid); 95 | } 96 | } 97 | else 98 | { 99 | alert("您的浏览器不支持WebSocket,请使用Chrome/FireFox/Safari/IE10浏览器"); 100 | } 101 | }); 102 | 103 | 104 | document.onkeydown = function(e){ 105 | var ev = document.all ? window.event : e; 106 | if(ev.keyCode==13) 107 | { 108 | sendMsg(); 109 | } 110 | } 111 | 112 | /** 113 | * 显示所有在线列表 114 | * @param data 115 | */ 116 | function showOnlineList( data ) 117 | { 118 | var dataObj = $.evalJSON( data ); 119 | var li = ''; 120 | var option = "" ; 121 | 122 | for ( var i = 0; i < dataObj.list.length; i++ ) 123 | { 124 | li = li+"
  • " + 125 | "" + "
  • " 128 | 129 | userlist[dataObj.list[i].fd] = dataObj.list[i].name; 130 | 131 | if( dataObj.list[i].fd != client_id ) 132 | { 133 | option = option + "" 135 | } 136 | } 137 | $('#left-userlist').html( li ); 138 | $('#userlist').html( option ); 139 | } 140 | 141 | /** 142 | * 当有一个新用户连接上来时 143 | * @param userid 144 | */ 145 | function showNewUser( data ) 146 | { 147 | var dataObj = $.evalJSON( data ); 148 | if( !userlist[dataObj.fd] ) 149 | { 150 | userlist[dataObj.fd] = dataObj.name; 151 | if ( dataObj.fd != client_id ) 152 | { 153 | $('#userlist').append( ""); 154 | 155 | } 156 | 157 | $('#left-userlist').append( 158 | "
  • " + 159 | "" + "
  • "); 162 | 163 | } 164 | } 165 | 166 | /** 167 | * 显示新消息 168 | */ 169 | function showNewMsg( data ) 170 | { 171 | var dataObj = $.evalJSON( data ); 172 | var content = xssFilter( dataObj.data ) 173 | var fromId = dataObj.from; 174 | var channal = dataObj.channal; 175 | content = parseXss( content ); 176 | var said = ''; 177 | 178 | $("#msg-template .msg-time").html(GetDateT()); 179 | if (fromId == 0) 180 | { 181 | $("#msg-template .userpic").html(""); 182 | $("#msg-template .content").html( 183 | "【系统】" + content); 184 | } 185 | else 186 | { 187 | var html = ''; 188 | var to = dataObj.to; 189 | //如果说话的是我自己 190 | if( client_id == fromId ) 191 | { 192 | if( channal == 0 ) 193 | { 194 | said = '我对大家说:'; 195 | } 196 | else if( channal == 1 ) 197 | { 198 | said = "我悄悄的对"+userlist[to]+"说:"; 199 | } 200 | 201 | html += ''+said+' '; 202 | 203 | } 204 | else 205 | { 206 | if( channal == 0 ) 207 | { 208 | said = '对大家说:'; 209 | } 210 | else if( channal == 1 ) 211 | { 212 | said = "悄悄的对我说:"; 213 | } 214 | 215 | html += '' + userlist[fromId] + said; 217 | html += ' ' 218 | } 219 | html += content + ''; 220 | $("#msg-template .content").html(html); 221 | } 222 | $("#chat-messages").append($("#msg-template").html()); 223 | $('#chat-messages')[0].scrollTop = 1000000; 224 | 225 | } 226 | 227 | function xssFilter(val) 228 | { 229 | val = val.replace(/&/g, '&').replace(//g, '>').replace(/\x22/g, '"').replace(/\x27/g, '''); 230 | return val; 231 | } 232 | 233 | function parseXss( val ) 234 | { 235 | val = val.replace( /#(\d*)/g, '' ); 236 | val = val.replace( '&' , '&' ); 237 | return val; 238 | } 239 | 240 | 241 | function GetDateT() { 242 | var d; 243 | d = new Date(); 244 | var h,i,s; 245 | 246 | h = d.getHours(); 247 | i = d.getMinutes(); 248 | s = d.getSeconds(); 249 | 250 | h = ( h < 10 ) ? '0'+h : h; 251 | i = ( i < 10 ) ? '0'+i : i; 252 | s = ( s < 10 ) ? '0'+s : s; 253 | return h+":"+i+":"+s; 254 | } 255 | 256 | function getRequest() 257 | { 258 | var url = location.search; // 获取url中"?"符后的字串 259 | var theRequest = new Object(); 260 | if (url.indexOf("?") != -1) { 261 | var str = url.substr(1); 262 | 263 | strs = str.split("&"); 264 | for ( var i = 0; i < strs.length; i++) { 265 | var decodeParam = decodeURIComponent( strs[i] ); 266 | var param = decodeParam.split( "=" ); 267 | theRequest[param[0]] = param[1]; 268 | } 269 | 270 | } 271 | return theRequest; 272 | } 273 | 274 | function selectUser(userid) 275 | { 276 | $('#userlist').val(userid); 277 | } 278 | 279 | function delUser( userid ) 280 | { 281 | $('#user_' + userid).remove(); 282 | $('#inroom_' + userid).remove(); 283 | delete (userlist[userid]); 284 | 285 | } 286 | 287 | function sendMsg() 288 | { 289 | var content = $('#msg_content').val(); 290 | content = content.replace(" ", " "); 291 | if( !content ) 292 | { 293 | return false; 294 | } 295 | 296 | if( $('#userlist').val() == 0 ) 297 | { 298 | var msg = new Object(); 299 | msg.cmd = 'message'; 300 | msg.from = client_id; 301 | msg.channal = 0; 302 | msg.data = content; 303 | ws.send( $.toJSON( msg ) ); 304 | } 305 | else 306 | { 307 | var msg = new Object(); 308 | msg.cmd = 'message'; 309 | msg.from = client_id; 310 | msg.to = $('#userlist').val(); 311 | msg.channal = 1; 312 | msg.data = content; 313 | ws.send( $.toJSON( msg ) ); 314 | } 315 | $('#msg_content').val( "" ); 316 | return false; 317 | 318 | } 319 | 320 | 321 | $(document).ready(function(){ 322 | var a = ''; 323 | for( var i = 1 ; i < 20 ; i++ ) 324 | { 325 | a = a+''; 326 | } 327 | $("#show_face").html( a ); 328 | }); 329 | 330 | 331 | (function($){ 332 | $.fn.extend({ 333 | insertAtCaret:function( myValue ) 334 | { 335 | var $t=$(this)[0]; 336 | if( document.selection ) 337 | { 338 | this.focus(); 339 | sel = document.selection.createRange(); 340 | sel.text = myValue; 341 | this.focus(); 342 | } 343 | else if( $t.selectionStart || $t.selectionStart == '0') 344 | { 345 | 346 | var startPos = $t.selectionStart; 347 | var endPos = $t.selectionEnd; 348 | var scrollTop = $t.scrollTop; 349 | $t.value = $t.value.substring(0, startPos) + myValue + $t.value.substring(endPos, $t.value.length); 350 | this.focus(); 351 | $t.selectionStart = startPos + myValue.length; 352 | $t.selectionEnd = startPos + myValue.length; 353 | $t.scrollTop = scrollTop; 354 | } 355 | else 356 | { 357 | 358 | this.value += myValue; 359 | this.focus(); 360 | } 361 | } 362 | }) 363 | })(jQuery); 364 | 365 | 366 | function selectFace( id ) 367 | { 368 | var img = ''; 369 | $( "#msg_content" ).insertAtCaret( "#"+id ); 370 | closeChatFace(); 371 | } 372 | 373 | 374 | function showChatFace() 375 | { 376 | $("#chat_face").attr( "class" ,"chat_face chat_face_hover"); 377 | $("#show_face" ).attr( "class" ,"show_face show_face_hovers"); 378 | } 379 | 380 | function closeChatFace() 381 | { 382 | $("#chat_face").attr( "class" ,"chat_face" ); 383 | $("#show_face" ).attr( "class" ,"show_face"); 384 | } 385 | 386 | function toggleFace() 387 | { 388 | $("#chat_face").toggleClass("chat_face_hover" ); 389 | $("#show_face").toggleClass("show_face_hovers" ); 390 | } 391 | -------------------------------------------------------------------------------- /example/www/webim/resource/js/jquery.json.js: -------------------------------------------------------------------------------- 1 | /*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */ 2 | (function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';} 3 | var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;} 4 | if(type==='number'||type==='boolean'){return String(o);} 5 | if(type==='string'){return $.quoteString(o);} 6 | if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());} 7 | if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;} 8 | if(day<10){day='0'+day;} 9 | if(hours<10){hours='0'+hours;} 10 | if(minutes<10){minutes='0'+minutes;} 11 | if(seconds<10){seconds='0'+seconds;} 12 | if(milli<100){milli='0'+milli;} 13 | if(milli<10){milli='0'+milli;} 14 | return'"'+year+'-'+month+'-'+day+'T'+ 15 | hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} 16 | pairs=[];if($.isArray(o)){for(k=0;k 2 | 3 | 4 | QQ Powered By Appnet 5 | 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 |
    14 | 15 |
    16 | 17 | 35 | 36 |
    37 |
    38 |
    39 | 40 | 41 | 42 |
    43 |
    44 | 45 |
    46 |
    47 |
    48 |
    49 |
      50 |
    • 51 |
    52 | 53 | 54 |
    55 |
    搜索:联系人、讨论组、群、企业
    56 |
    57 |
    58 |
      59 |
    • 60 |
    • 61 |
    • 62 |
    • 63 |
    64 |
    65 |
    66 | 67 |
      68 |
    69 |
    70 |
    71 |
    72 |
      73 |
    • 74 |
    • 75 |
    • 76 |
    • 77 |
    • 78 |
    • 79 |
    • 80 |
    • 81 |
    • 82 |
    • 83 |
    84 |
    85 |
    86 |
      87 |
    • 88 |
    • 89 |
    • 90 |
    • 91 |
    • 92 |
    • 查找
    • 93 |
    • 应用宝
    • 94 |
    95 |
    96 |
    97 |
    98 | 99 |
    100 |
    101 |
      102 |
    • 103 |
    104 |
    105 |
    106 |
    107 |
    108 |
    109 |
    站在别人的雨季,淋湿自己空弹一出戏.....
    110 |
    111 |
    112 |
      113 |
    • 114 |
    • 115 |
    • 116 |
    • 117 |
    • 118 |
    • 119 |
    • 120 |
    121 |
    122 |
    123 |
    124 |
    125 |
      126 |
    • 127 |
      128 |
      在么?找你有点事
      129 |
    • 130 |
    131 |
    132 |
    133 |
      134 |
    • 135 |
    • 136 |
    • 137 |
    • 138 |
    • 139 |
    • 140 |
    • 141 |
    • 142 |
    • 143 |
    • 消息记录

    • 144 |
    145 | 146 |
    147 | 发送(S) 148 | 关闭(C) 149 |
    150 |
    151 |
    152 |
    153 |
    154 | 155 | 156 | 157 | 158 | 159 | 160 |
    161 | 162 | 163 | -------------------------------------------------------------------------------- /example/www/webqq/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.4.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2006, 2014 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD (Register as an anonymous module) 11 | define(['jquery'], factory); 12 | } else if (typeof exports === 'object') { 13 | // Node/CommonJS 14 | module.exports = factory(require('jquery')); 15 | } else { 16 | // Browser globals 17 | factory(jQuery); 18 | } 19 | }(function ($) { 20 | 21 | var pluses = /\+/g; 22 | 23 | function encode(s) { 24 | return config.raw ? s : encodeURIComponent(s); 25 | } 26 | 27 | function decode(s) { 28 | return config.raw ? s : decodeURIComponent(s); 29 | } 30 | 31 | function stringifyCookieValue(value) { 32 | return encode(config.json ? JSON.stringify(value) : String(value)); 33 | } 34 | 35 | function parseCookieValue(s) { 36 | if (s.indexOf('"') === 0) { 37 | // This is a quoted cookie as according to RFC2068, unescape... 38 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 39 | } 40 | 41 | try { 42 | // Replace server-side written pluses with spaces. 43 | // If we can't decode the cookie, ignore it, it's unusable. 44 | // If we can't parse the cookie, ignore it, it's unusable. 45 | s = decodeURIComponent(s.replace(pluses, ' ')); 46 | return config.json ? JSON.parse(s) : s; 47 | } catch(e) {} 48 | } 49 | 50 | function read(s, converter) { 51 | var value = config.raw ? s : parseCookieValue(s); 52 | return $.isFunction(converter) ? converter(value) : value; 53 | } 54 | 55 | var config = $.cookie = function (key, value, options) { 56 | 57 | // Write 58 | 59 | if (arguments.length > 1 && !$.isFunction(value)) { 60 | options = $.extend({}, config.defaults, options); 61 | 62 | if (typeof options.expires === 'number') { 63 | var days = options.expires, t = options.expires = new Date(); 64 | t.setMilliseconds(t.getMilliseconds() + days * 864e+5); 65 | } 66 | 67 | return (document.cookie = [ 68 | encode(key), '=', stringifyCookieValue(value), 69 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 70 | options.path ? '; path=' + options.path : '', 71 | options.domain ? '; domain=' + options.domain : '', 72 | options.secure ? '; secure' : '' 73 | ].join('')); 74 | } 75 | 76 | // Read 77 | 78 | var result = key ? undefined : {}, 79 | // To prevent the for loop in the first place assign an empty array 80 | // in case there are no cookies at all. Also prevents odd result when 81 | // calling $.cookie(). 82 | cookies = document.cookie ? document.cookie.split('; ') : [], 83 | i = 0, 84 | l = cookies.length; 85 | 86 | for (; i < l; i++) { 87 | var parts = cookies[i].split('='), 88 | name = decode(parts.shift()), 89 | cookie = parts.join('='); 90 | 91 | if (key === name) { 92 | // If second argument (value) is a function it's a converter... 93 | result = read(cookie, value); 94 | break; 95 | } 96 | 97 | // Prevent storing a cookie that we couldn't decode. 98 | if (!key && (cookie = read(cookie)) !== undefined) { 99 | result[name] = cookie; 100 | } 101 | } 102 | 103 | return result; 104 | }; 105 | 106 | config.defaults = {}; 107 | 108 | $.removeCookie = function (key, options) { 109 | // Must not alter options, thus extending a fresh object... 110 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 111 | return !$.cookie(key); 112 | }; 113 | 114 | })); -------------------------------------------------------------------------------- /example/www/webqq/js/jquery.json.js: -------------------------------------------------------------------------------- 1 | /*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */ 2 | (function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';} 3 | var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;} 4 | if(type==='number'||type==='boolean'){return String(o);} 5 | if(type==='string'){return $.quoteString(o);} 6 | if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());} 7 | if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;} 8 | if(day<10){day='0'+day;} 9 | if(hours<10){hours='0'+hours;} 10 | if(minutes<10){minutes='0'+minutes;} 11 | if(seconds<10){seconds='0'+seconds;} 12 | if(milli<100){milli='0'+milli;} 13 | if(milli<10){milli='0'+milli;} 14 | return'"'+year+'-'+month+'-'+day+'T'+ 15 | hours+':'+minutes+':'+seconds+'.'+milli+'Z"';} 16 | pairs=[];if($.isArray(o)){for(k=0;k=u?0!=m%t?m%t:t:0,Q="leftMarquee"==e||"topMarquee"==e?!0:!1,R=function(){a.isFunction(c.startFun)&&c.startFun(p,k,d,a(c.titCell,d),l,o,f,g)},S=function(){a.isFunction(c.endFun)&&c.endFun(p,k,d,a(c.titCell,d),l,o,f,g)},T=function(){j.removeClass(K),A&&j.eq(defaultIndex).addClass(K)};if("menu"==c.type)return A&&j.removeClass(K).eq(p).addClass(K),j.hover(function(){P=a(this).find(c.targetCell);var b=j.index(a(this));I=setTimeout(function(){switch(p=b,j.removeClass(K).eq(p).addClass(K),R(),e){case"fade":P.stop(!0,!0).animate({opacity:"show"},q,G,S);break;case"slideDown":P.stop(!0,!0).animate({height:"show"},q,G,S)}},c.triggerTime)},function(){switch(clearTimeout(I),e){case"fade":P.animate({opacity:"hide"},q,G);break;case"slideDown":P.animate({height:"hide"},q,G)}}),B&&d.hover(function(){clearTimeout(J)},function(){J=setTimeout(T,q)}),void 0;if(0==k&&(k=m),Q&&(k=2),x){if(m>=u)if("leftLoop"==e||"topLoop"==e)k=0!=m%t?(0^m/t)+1:m/t;else{var U=m-u;k=1+parseInt(0!=U%t?U/t+1:U/t),0>=k&&(k=1)}else k=1;j.html("");var V="";if(1==c.autoPage||"true"==c.autoPage)for(var W=0;k>W;W++)V+="
  • "+(W+1)+"
  • ";else for(var W=0;k>W;W++)V+=c.autoPage.replace("$",W+1);j.html(V);var j=j.children()}if(m>=u){l.children().each(function(){a(this).width()>E&&(E=a(this).width(),D=a(this).outerWidth(!0)),a(this).height()>F&&(F=a(this).height(),C=a(this).outerHeight(!0))});var X=l.children(),Y=function(){for(var a=0;u>a;a++)X.eq(a).clone().addClass("clone").appendTo(l);for(var a=0;O>a;a++)X.eq(m-a-1).clone().addClass("clone").prependTo(l)};switch(e){case"fold":l.css({position:"relative",width:D,height:C}).children().css({position:"absolute",width:E,left:0,top:0,display:"none"});break;case"top":l.wrap('
    ').css({top:-(p*t)*C,position:"relative",padding:"0",margin:"0"}).children().css({height:F});break;case"left":l.wrap('
    ').css({width:m*D,left:-(p*t)*D,position:"relative",overflow:"hidden",padding:"0",margin:"0"}).children().css({"float":"left",width:E});break;case"leftLoop":case"leftMarquee":Y(),l.wrap('
    ').css({width:(m+u+O)*D,position:"relative",overflow:"hidden",padding:"0",margin:"0",left:-(O+p*t)*D}).children().css({"float":"left",width:E});break;case"topLoop":case"topMarquee":Y(),l.wrap('
    ').css({height:(m+u+O)*C,position:"relative",padding:"0",margin:"0",top:-(O+p*t)*C}).children().css({height:F})}}var Z=function(a){var b=a*t;return a==k?b=m:-1==a&&0!=m%t&&(b=-m%t),b},$=function(b){var c=function(c){for(var d=c;u+c>d;d++)b.eq(d).find("img["+n+"]").each(function(){var b=a(this);if(b.attr("src",b.attr(n)).removeAttr(n),l.find(".clone")[0])for(var c=l.children(),d=0;c.size()>d;d++)c.eq(d).find("img["+n+"]").each(function(){a(this).attr(n)==b.attr("src")&&a(this).attr("src",a(this).attr(n)).removeAttr(n)})})};switch(e){case"fade":case"fold":case"top":case"left":case"slideDown":c(p*t);break;case"leftLoop":case"topLoop":c(O+Z(N));break;case"leftMarquee":case"topMarquee":var d="leftMarquee"==e?l.css("left").replace("px",""):l.css("top").replace("px",""),f="leftMarquee"==e?D:C,g=O;if(0!=d%f){var h=Math.abs(0^d/f);g=1==p?O+h:O+h-1}c(g)}},_=function(a){if(!A||M!=p||a||Q){if(Q?p>=1?p=1:0>=p&&(p=0):(N=p,p>=k?p=0:0>p&&(p=k-1)),R(),null!=n&&$(l.children()),o[0]&&(P=o.eq(p),null!=n&&$(o),"slideDown"==e?(o.not(P).stop(!0,!0).slideUp(q),P.slideDown(q,G,function(){l[0]||S()})):(o.not(P).stop(!0,!0).hide(),P.animate({opacity:"show"},q,function(){l[0]||S()}))),m>=u)switch(e){case"fade":l.children().stop(!0,!0).eq(p).animate({opacity:"show"},q,G,function(){S()}).siblings().hide();break;case"fold":l.children().stop(!0,!0).eq(p).animate({opacity:"show"},q,G,function(){S()}).siblings().animate({opacity:"hide"},q,G);break;case"top":l.stop(!0,!1).animate({top:-p*t*C},q,G,function(){S()});break;case"left":l.stop(!0,!1).animate({left:-p*t*D},q,G,function(){S()});break;case"leftLoop":var b=N;l.stop(!0,!0).animate({left:-(Z(N)+O)*D},q,G,function(){-1>=b?l.css("left",-(O+(k-1)*t)*D):b>=k&&l.css("left",-O*D),S()});break;case"topLoop":var b=N;l.stop(!0,!0).animate({top:-(Z(N)+O)*C},q,G,function(){-1>=b?l.css("top",-(O+(k-1)*t)*C):b>=k&&l.css("top",-O*C),S()});break;case"leftMarquee":var c=l.css("left").replace("px","");0==p?l.animate({left:++c},0,function(){l.css("left").replace("px","")>=0&&l.css("left",-m*D)}):l.animate({left:--c},0,function(){-(m+O)*D>=l.css("left").replace("px","")&&l.css("left",-O*D)});break;case"topMarquee":var d=l.css("top").replace("px","");0==p?l.animate({top:++d},0,function(){l.css("top").replace("px","")>=0&&l.css("top",-m*C)}):l.animate({top:--d},0,function(){-(m+O)*C>=l.css("top").replace("px","")&&l.css("top",-O*C)})}j.removeClass(K).eq(p).addClass(K),M=p,y||(g.removeClass("nextStop"),f.removeClass("prevStop"),0==p&&f.addClass("prevStop"),p==k-1&&g.addClass("nextStop")),h.html(""+(p+1)+"/"+k)}};A&&_(!0),B&&d.hover(function(){clearTimeout(J)},function(){J=setTimeout(function(){p=defaultIndex,A?_():"slideDown"==e?P.slideUp(q,T):P.animate({opacity:"hide"},q,T),M=p},300)});var ab=function(a){H=setInterval(function(){w?p--:p++,_()},a?a:r)},bb=function(a){H=setInterval(_,a?a:r)},cb=function(){z||(clearInterval(H),ab())},db=function(){(y||p!=k-1)&&(p++,_(),Q||cb())},eb=function(){(y||0!=p)&&(p--,_(),Q||cb())},fb=function(){clearInterval(H),Q?bb():ab(),i.removeClass("pauseState")},gb=function(){clearInterval(H),i.addClass("pauseState")};if(v?Q?(w?p--:p++,bb(),z&&l.hover(gb,fb)):(ab(),z&&d.hover(gb,fb)):(Q&&(w?p--:p++),i.addClass("pauseState")),i.click(function(){i.hasClass("pauseState")?fb():gb()}),"mouseover"==c.trigger?j.hover(function(){var a=j.index(this);I=setTimeout(function(){p=a,_(),cb()},c.triggerTime)},function(){clearTimeout(I)}):j.click(function(){p=j.index(this),_(),cb()}),Q){if(g.mousedown(db),f.mousedown(eb),y){var hb,ib=function(){hb=setTimeout(function(){clearInterval(H),bb(0^r/10)},150)},jb=function(){clearTimeout(hb),clearInterval(H),bb()};g.mousedown(ib),g.mouseup(jb),f.mousedown(ib),f.mouseup(jb)}"mouseover"==c.trigger&&(g.hover(db,function(){}),f.hover(eb,function(){}))}else g.click(db),f.click(eb)})}})(jQuery),jQuery.easing.jswing=jQuery.easing.swing,jQuery.extend(jQuery.easing,{def:"easeOutQuad",swing:function(a,b,c,d,e){return jQuery.easing[jQuery.easing.def](a,b,c,d,e)},easeInQuad:function(a,b,c,d,e){return d*(b/=e)*b+c},easeOutQuad:function(a,b,c,d,e){return-d*(b/=e)*(b-2)+c},easeInOutQuad:function(a,b,c,d,e){return 1>(b/=e/2)?d/2*b*b+c:-d/2*(--b*(b-2)-1)+c},easeInCubic:function(a,b,c,d,e){return d*(b/=e)*b*b+c},easeOutCubic:function(a,b,c,d,e){return d*((b=b/e-1)*b*b+1)+c},easeInOutCubic:function(a,b,c,d,e){return 1>(b/=e/2)?d/2*b*b*b+c:d/2*((b-=2)*b*b+2)+c},easeInQuart:function(a,b,c,d,e){return d*(b/=e)*b*b*b+c},easeOutQuart:function(a,b,c,d,e){return-d*((b=b/e-1)*b*b*b-1)+c},easeInOutQuart:function(a,b,c,d,e){return 1>(b/=e/2)?d/2*b*b*b*b+c:-d/2*((b-=2)*b*b*b-2)+c},easeInQuint:function(a,b,c,d,e){return d*(b/=e)*b*b*b*b+c},easeOutQuint:function(a,b,c,d,e){return d*((b=b/e-1)*b*b*b*b+1)+c},easeInOutQuint:function(a,b,c,d,e){return 1>(b/=e/2)?d/2*b*b*b*b*b+c:d/2*((b-=2)*b*b*b*b+2)+c},easeInSine:function(a,b,c,d,e){return-d*Math.cos(b/e*(Math.PI/2))+d+c},easeOutSine:function(a,b,c,d,e){return d*Math.sin(b/e*(Math.PI/2))+c},easeInOutSine:function(a,b,c,d,e){return-d/2*(Math.cos(Math.PI*b/e)-1)+c},easeInExpo:function(a,b,c,d,e){return 0==b?c:d*Math.pow(2,10*(b/e-1))+c},easeOutExpo:function(a,b,c,d,e){return b==e?c+d:d*(-Math.pow(2,-10*b/e)+1)+c},easeInOutExpo:function(a,b,c,d,e){return 0==b?c:b==e?c+d:1>(b/=e/2)?d/2*Math.pow(2,10*(b-1))+c:d/2*(-Math.pow(2,-10*--b)+2)+c},easeInCirc:function(a,b,c,d,e){return-d*(Math.sqrt(1-(b/=e)*b)-1)+c},easeOutCirc:function(a,b,c,d,e){return d*Math.sqrt(1-(b=b/e-1)*b)+c},easeInOutCirc:function(a,b,c,d,e){return 1>(b/=e/2)?-d/2*(Math.sqrt(1-b*b)-1)+c:d/2*(Math.sqrt(1-(b-=2)*b)+1)+c},easeInElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),Math.abs(d)>h){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g))+c},easeOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(1==(b/=e))return c+d;if(g||(g=.3*e),Math.abs(d)>h){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*b)*Math.sin((b*e-f)*2*Math.PI/g)+d+c},easeInOutElastic:function(a,b,c,d,e){var f=1.70158,g=0,h=d;if(0==b)return c;if(2==(b/=e/2))return c+d;if(g||(g=e*.3*1.5),Math.abs(d)>h){h=d;var f=g/4}else var f=g/(2*Math.PI)*Math.asin(d/h);return 1>b?-.5*h*Math.pow(2,10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)+c:.5*h*Math.pow(2,-10*(b-=1))*Math.sin((b*e-f)*2*Math.PI/g)+d+c},easeInBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*(b/=e)*b*((f+1)*b-f)+c},easeOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),d*((b=b/e-1)*b*((f+1)*b+f)+1)+c},easeInOutBack:function(a,b,c,d,e,f){return void 0==f&&(f=1.70158),1>(b/=e/2)?d/2*b*b*(((f*=1.525)+1)*b-f)+c:d/2*((b-=2)*b*(((f*=1.525)+1)*b+f)+2)+c},easeInBounce:function(a,b,c,d,e){return d-jQuery.easing.easeOutBounce(a,e-b,0,d,e)+c},easeOutBounce:function(a,b,c,d,e){return 1/2.75>(b/=e)?d*7.5625*b*b+c:2/2.75>b?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:2.5/2.75>b?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c},easeInOutBounce:function(a,b,c,d,e){return e/2>b?.5*jQuery.easing.easeInBounce(a,2*b,0,d,e)+c:.5*jQuery.easing.easeOutBounce(a,2*b-e,0,d,e)+.5*d+c}}); -------------------------------------------------------------------------------- /example/www/website/img/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/website/img/qq.png -------------------------------------------------------------------------------- /example/www/website/img/return-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/website/img/return-back.png -------------------------------------------------------------------------------- /example/www/website/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Bootstrap 101 Template 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 84 | 85 | 86 | 87 | 88 |
    89 |
    90 |
    91 |

    Appnet

    92 | 一个支持TCP/HTTP/Websocket协议混合请求的高性能PHP扩展 93 |
    94 | 95 | 96 | 97 |
    98 |
    99 |

    高性能

    100 | C语言开发,基于redis核心网络组件封装,增强其网络IO能力,linux平台采用epoll异步非阻塞事件通知机制,单线程可支撑10万并发连接。 101 |
    102 | 103 |
    104 |

    高并发

    105 | 多线程异步网络IO,Per Thread One Loop并发模型,多个worker进程并行处理业务。 106 |
    107 |
    108 | 109 | 110 |
    111 |
    112 |

    多协议

    113 | 只需一个Server即可支持TCP协议,websocket协议和http协议的混合访问。 114 |
    115 | 116 |
    117 |

    易于使用

    118 | 提供PHP7扩展,简单几步就可以搭建支持TCP/HTTP/WebSocket协议的服务器。 119 |
    120 |
    121 | 122 | 123 |
    124 |
    125 |

    内存优化

    126 | 进程间通信使用共享内存,兼容jemalloc和tcmalloc内存优化技术。 127 |
    128 | 129 |
    130 |

    缓冲区优化

    131 | 采用sds动态缓冲区,使用内存预分配和动态扩容策略有效避免内存浪费和缓冲区溢出。 132 |
    133 |
    134 |
    135 |
    136 | 137 | 138 |
    139 |

    使用案例

    140 |
    141 |
    142 | 143 |
    144 |
    145 |

    WebQQ

    146 |

    使用appnet http+websocket混合协议实现的仿版QQ,支持QQ好友私聊,群聊。

    147 |

    演示地址:http://www.appnet.site/webqq/index.html

    148 |
    149 |
    150 | 151 |
    152 |
    153 | 154 |
    155 |
    156 |

    WebQQ

    157 | 使用appnet http+websocket混合协议实现的仿版QQ,支持QQ好友私聊,群聊。 158 |
    159 |
    160 | 161 | 162 |
    163 | 164 | 165 | 166 |
    167 |
    168 |
    169 |
    170 |

    This Website Powered By Appnet Server

    171 |

    QQ交流群:379084776

    172 |

    Author Email:lchb@qq.com

    173 |
    174 |
    175 | 176 | 177 |
    178 |
    179 | 180 | 181 | 182 | 183 | 184 | 185 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /example/www/website/js/.jquery.min.js.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uther518/appnet/461869b68b2cceb49e6aace8d1632da43cdda483/example/www/website/js/.jquery.min.js.swp -------------------------------------------------------------------------------- /include/appnet_dict.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef __DICT_H 4 | #define __DICT_H 5 | 6 | #define DICT_OK 0 7 | #define DICT_ERR 1 8 | 9 | /* Unused arguments generate annoying warnings... */ 10 | #define DICT_NOTUSED(V) ((void) V) 11 | 12 | typedef struct dictEntry 13 | { 14 | void *key; 15 | union 16 | { 17 | void *val; 18 | uint64_t u64; 19 | int64_t s64; 20 | double d; 21 | } v; 22 | struct dictEntry *next; 23 | } dictEntry; 24 | 25 | typedef struct dictType 26 | { 27 | unsigned int (*hashFunction)( const void *key ); 28 | void *(*keyDup)( void *privdata , const void *key ); 29 | void *(*valDup)( void *privdata , const void *obj ); 30 | int (*keyCompare)( void *privdata , const void *key1 , const void *key2 ); 31 | void (*keyDestructor)( void *privdata , void *key ); 32 | void (*valDestructor)( void *privdata , void *obj ); 33 | } dictType; 34 | 35 | /* This is our hash table structure. Every dictionary has two of this as we 36 | * implement incremental rehashing, for the old to the new table. */ 37 | typedef struct dictht 38 | { 39 | dictEntry **table; 40 | unsigned long size; 41 | unsigned long sizemask; 42 | unsigned long used; 43 | } dictht; 44 | 45 | typedef struct dict 46 | { 47 | dictType *type; 48 | void *privdata; 49 | dictht ht[2]; 50 | long rehashidx; /* rehashing not in progress if rehashidx == -1 */ 51 | int iterators; /* number of iterators currently running */ 52 | } dict; 53 | 54 | /* If safe is set to 1 this is a safe iterator, that means, you can call 55 | * dictAdd, dictFind, and other functions against the dictionary even while 56 | * iterating. Otherwise it is a non safe iterator, and only dictNext() 57 | * should be called while iterating. */ 58 | typedef struct dictIterator 59 | { 60 | dict *d; 61 | long index; 62 | int table,safe; 63 | dictEntry *entry,*nextEntry; 64 | /* unsafe iterator fingerprint for misuse detection. */ 65 | long long fingerprint; 66 | } dictIterator; 67 | 68 | typedef void (dictScanFunction)( void *privdata , const dictEntry *de ); 69 | 70 | /* This is the initial size of every hash table */ 71 | #define DICT_HT_INITIAL_SIZE 4 72 | 73 | /* ------------------------------- Macros ------------------------------------*/ 74 | #define dictFreeVal(d, entry) \ 75 | if ((d)->type->valDestructor) \ 76 | (d)->type->valDestructor((d)->privdata, (entry)->v.val) 77 | 78 | #define dictSetVal(d, entry, _val_) do { \ 79 | if ((d)->type->valDup) \ 80 | entry->v.val = (d)->type->valDup((d)->privdata, _val_); \ 81 | else \ 82 | entry->v.val = (_val_); \ 83 | } while(0) 84 | 85 | #define dictSetSignedIntegerVal(entry, _val_) \ 86 | do { entry->v.s64 = _val_; } while(0) 87 | 88 | #define dictSetUnsignedIntegerVal(entry, _val_) \ 89 | do { entry->v.u64 = _val_; } while(0) 90 | 91 | #define dictSetDoubleVal(entry, _val_) \ 92 | do { entry->v.d = _val_; } while(0) 93 | 94 | #define dictFreeKey(d, entry) \ 95 | if ((d)->type->keyDestructor) \ 96 | (d)->type->keyDestructor((d)->privdata, (entry)->key) 97 | 98 | #define dictSetKey(d, entry, _key_) do { \ 99 | if ((d)->type->keyDup) \ 100 | entry->key = (d)->type->keyDup((d)->privdata, _key_); \ 101 | else \ 102 | entry->key = (_key_); \ 103 | } while(0) 104 | 105 | #define dictCompareKeys(d, key1, key2) \ 106 | (((d)->type->keyCompare) ? \ 107 | (d)->type->keyCompare((d)->privdata, key1, key2) : \ 108 | (key1) == (key2)) 109 | 110 | #define dictHashKey(d, key) (d)->type->hashFunction(key) 111 | #define dictGetKey(he) ((he)->key) 112 | #define dictGetVal(he) ((he)->v.val) 113 | #define dictGetSignedIntegerVal(he) ((he)->v.s64) 114 | #define dictGetUnsignedIntegerVal(he) ((he)->v.u64) 115 | #define dictGetDoubleVal(he) ((he)->v.d) 116 | #define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size) 117 | #define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used) 118 | #define dictIsRehashing(d) ((d)->rehashidx != -1) 119 | 120 | /* API */ 121 | dict *dictCreate( dictType *type , void *privDataPtr ); 122 | int dictExpand( dict *d , unsigned long size ); 123 | int dictAdd( dict *d , void *key , void *val ); 124 | dictEntry *dictAddRaw( dict *d , void *key ); 125 | int dictReplace( dict *d , void *key , void *val ); 126 | dictEntry *dictReplaceRaw( dict *d , void *key ); 127 | int dictDelete( dict *d , const void *key ); 128 | int dictDeleteNoFree( dict *d , const void *key ); 129 | void dictRelease( dict *d ); 130 | dictEntry * dictFind( dict *d , const void *key ); 131 | void *dictFetchValue( dict *d , const void *key ); 132 | int dictResize( dict *d ); 133 | dictIterator *dictGetIterator( dict *d ); 134 | dictIterator *dictGetSafeIterator( dict *d ); 135 | dictEntry *dictNext( dictIterator *iter ); 136 | void dictReleaseIterator( dictIterator *iter ); 137 | dictEntry *dictGetRandomKey( dict *d ); 138 | unsigned int dictGetSomeKeys( dict *d , dictEntry **des , unsigned int count ); 139 | void dictPrintStats( dict *d ); 140 | unsigned int dictGenHashFunction( const void *key , int len ); 141 | unsigned int dictGenCaseHashFunction( const unsigned char *buf , int len ); 142 | void dictEmpty( dict *d , void (callback)( void* ) ); 143 | void dictEnableResize( void ); 144 | void dictDisableResize( void ); 145 | int dictRehash( dict *d , int n ); 146 | int dictRehashMilliseconds( dict *d , int ms ); 147 | void dictSetHashFunctionSeed( unsigned int initval ); 148 | unsigned int dictGetHashFunctionSeed( void ); 149 | unsigned long dictScan( dict *d , unsigned long v , dictScanFunction *fn , void *privdata ); 150 | 151 | /* Hash table types */ 152 | extern dictType dictTypeHeapStringCopyKey; 153 | extern dictType dictTypeHeapStrings; 154 | extern dictType dictTypeHeapStringCopyKeyValue; 155 | 156 | #endif /* __DICT_H */ 157 | -------------------------------------------------------------------------------- /include/appnet_event.h: -------------------------------------------------------------------------------- 1 | #ifndef __AE_H__ 2 | #define __AE_H__ 3 | 4 | #define AE_OK 0 5 | #define AE_ERR -1 6 | 7 | #define AE_NONE 0 8 | #define AE_READABLE 1 9 | #define AE_WRITABLE 2 10 | 11 | #define AE_FILE_EVENTS 1 12 | #define AE_TIME_EVENTS 2 13 | #define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS) 14 | #define AE_DONT_WAIT 4 15 | 16 | #define AE_NOMORE -1 17 | 18 | /* Macros */ 19 | #define AE_NOTUSED(V) ((void) V) 20 | 21 | #include 22 | struct aeEventLoop; 23 | 24 | /* Types and data structures */ 25 | typedef void aeFileProc( struct aeEventLoop *eventLoop, int fd, void *clientData, int mask ); 26 | typedef int aeTimeProc( struct aeEventLoop *eventLoop, long long id, void *clientData ); 27 | typedef void aeEventFinalizerProc( struct aeEventLoop *eventLoop, void *clientData ); 28 | typedef void aeBeforeSleepProc( struct aeEventLoop *eventLoop ); 29 | 30 | /* File event structure */ 31 | typedef struct aeFileEvent 32 | { 33 | int mask; /* one of AE_(READABLE|WRITABLE) */ 34 | aeFileProc *rfileProc; 35 | aeFileProc *wfileProc; 36 | void *clientData; 37 | } aeFileEvent; 38 | 39 | /* Time event structure */ 40 | typedef struct aeTimeEvent 41 | { 42 | long long id; /* time event identifier. */ 43 | long when_sec; /* seconds */ 44 | long when_ms; /* milliseconds */ 45 | aeTimeProc *timeProc; 46 | aeEventFinalizerProc *finalizerProc; 47 | void *clientData; 48 | struct aeTimeEvent *next; 49 | } aeTimeEvent; 50 | 51 | /* A fired event */ 52 | typedef struct aeFiredEvent 53 | { 54 | int fd; 55 | int mask; 56 | } aeFiredEvent; 57 | 58 | /* State of an event based program */ 59 | typedef struct aeEventLoop 60 | { 61 | int maxfd; /* highest file descriptor currently registered */ 62 | int setsize; /* max number of file descriptors tracked */ 63 | long long timeEventNextId; 64 | time_t lastTime; /* Used to detect system clock skew */ 65 | aeFileEvent *events; /* Registered events */ 66 | aeFiredEvent *fired; /* Fired events */ 67 | aeTimeEvent *timeEventHead; 68 | int stop; 69 | void *apidata; /* This is used for polling API specific data */ 70 | aeBeforeSleepProc *beforesleep; 71 | } aeEventLoop; 72 | 73 | /* Prototypes */ 74 | aeEventLoop *aeCreateEventLoop( int setsize ); 75 | void aeDeleteEventLoop( aeEventLoop *eventLoop ); 76 | void aeStop( aeEventLoop *eventLoop ); 77 | int aeCreateFileEvent( aeEventLoop *eventLoop, int fd, int mask, 78 | aeFileProc *proc, void *clientData ); 79 | void aeDeleteFileEvent( aeEventLoop *eventLoop, int fd, int mask ); 80 | int aeGetFileEvents( aeEventLoop *eventLoop, int fd ); 81 | long long aeCreateTimeEvent( aeEventLoop *eventLoop, long long milliseconds, 82 | aeTimeProc *proc, void *clientData, 83 | aeEventFinalizerProc *finalizerProc ); 84 | int aeDeleteTimeEvent( aeEventLoop *eventLoop, long long id ); 85 | int aeProcessEvents( aeEventLoop *eventLoop, int flags ); 86 | int aeWait( int fd, int mask, long long milliseconds ); 87 | void aeMain( aeEventLoop *eventLoop ); 88 | char *aeGetApiName( void ); 89 | void aeSetBeforeSleepProc( aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep ); 90 | int aeGetSetSize( aeEventLoop *eventLoop ); 91 | int aeResizeSetSize( aeEventLoop *eventLoop, int setsize ); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /include/appnet_list.h: -------------------------------------------------------------------------------- 1 | /* adlist.h - A generic doubly linked list implementation 2 | * 3 | * Copyright (c) 2006-2012, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __ADLIST_H__ 32 | #define __ADLIST_H__ 33 | 34 | /* Node, List, and Iterator are the only data structures used currently. */ 35 | 36 | typedef struct listNode 37 | { 38 | struct listNode *prev; 39 | struct listNode *next; 40 | void *value; 41 | } listNode; 42 | 43 | typedef struct listIter 44 | { 45 | listNode *next; 46 | int direction; 47 | } listIter; 48 | 49 | typedef struct list 50 | { 51 | listNode *head; 52 | listNode *tail; 53 | void *(*dup)( void *ptr ); 54 | void (*free)( void *ptr ); 55 | int (*match)( void *ptr , void *key ); 56 | unsigned long len; 57 | } list; 58 | 59 | /* Functions implemented as macros */ 60 | #define listLength(l) ((l)->len) 61 | #define listFirst(l) ((l)->head) 62 | #define listLast(l) ((l)->tail) 63 | #define listPrevNode(n) ((n)->prev) 64 | #define listNextNode(n) ((n)->next) 65 | #define listNodeValue(n) ((n)->value) 66 | 67 | #define listSetDupMethod(l,m) ((l)->dup = (m)) 68 | #define listSetFreeMethod(l,m) ((l)->free = (m)) 69 | #define listSetMatchMethod(l,m) ((l)->match = (m)) 70 | 71 | #define listGetDupMethod(l) ((l)->dup) 72 | #define listGetFree(l) ((l)->free) 73 | #define listGetMatchMethod(l) ((l)->match) 74 | 75 | /* Prototypes */ 76 | list *listCreate( void ); 77 | void listRelease( list *list ); 78 | list *listAddNodeHead( list *list , void *value ); 79 | list *listAddNodeTail( list *list , void *value ); 80 | list *listInsertNode( list *list , listNode *old_node , void *value , int after ); 81 | void listDelNode( list *list , listNode *node ); 82 | listIter *listGetIterator( list *list , int direction ); 83 | listNode *listNext( listIter *iter ); 84 | void listReleaseIterator( listIter *iter ); 85 | list *listDup( list *orig ); 86 | listNode *listSearchKey( list *list , void *key ); 87 | listNode *listIndex( list *list , long index ); 88 | void listRewind( list *list , listIter *li ); 89 | void listRewindTail( list *list , listIter *li ); 90 | void listRotate( list *list ); 91 | 92 | /* Directions for iterators */ 93 | #define AL_START_HEAD 0 94 | #define AL_START_TAIL 1 95 | 96 | #endif /* __ADLIST_H__ */ 97 | -------------------------------------------------------------------------------- /include/appnet_request.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __HTTP_REQUEST_H_ 4 | #define __HTTP_REQUEST_H_ 5 | 6 | #include "appnet_sds.h" 7 | #include "appnet_websocket.h" 8 | #include 9 | #include 10 | #include 11 | 12 | #define TCP 0 13 | #define HTTP 1 14 | #define WEBSOCKET 2 15 | 16 | #define AE_SPACE ' ' 17 | #define AE_EOL_CRLF "\r\n" 18 | #define AE_HEADER_END "\r\n\r\n" 19 | 20 | #define AE_HTTP_HEADER_MAX_SIZE 8192 21 | 22 | typedef struct { 23 | char *pos; 24 | int len; 25 | } headerString; 26 | 27 | typedef struct { 28 | headerString key; 29 | headerString val; 30 | } headerFiled; 31 | 32 | enum { HEADER_METHOD = 1, HEADER_URI, HEADER_VERSION }; 33 | 34 | typedef struct { 35 | char method[16]; 36 | char version[16]; 37 | char uri[AE_HTTP_HEADER_MAX_SIZE]; 38 | } headerParams; 39 | 40 | enum { 41 | MULTIPART_TYPE_FORM_DATA = 1, 42 | MULTIPART_TYPE_BYTERANGES, 43 | MULTIPART_TYPE_ALTERNATIVE, 44 | MULTIPART_TYPE_DIGEST, 45 | MULTIPART_TYPE_MIXED, 46 | MULTIPART_TYPE_PARALLED, 47 | MULTIPART_TYPE_RELATED 48 | }; 49 | 50 | typedef struct { 51 | int connfd; 52 | int header_length; 53 | int content_length; 54 | int complete_length; 55 | int multipart_data; 56 | int nobody; 57 | int keep_alive; 58 | int trunked; 59 | int filed_nums; 60 | int buffer_pos; 61 | char method[8]; 62 | char uri[1024]; 63 | char version[16]; 64 | char mime_type[32]; 65 | char boundary[64]; 66 | int protocol; 67 | int major; 68 | int minor; 69 | 70 | headerFiled fileds[20]; 71 | headerParams params; 72 | 73 | } httpHeader; 74 | 75 | typedef enum { 76 | HRET_OK = 0, 77 | HRET_NOT_HTTP_REQUEST, 78 | HRET_UNCOMPLETE 79 | } HttpRequestErrorType; 80 | 81 | #define CHUNK_SZ 128 82 | 83 | int wesocketRequestRarse(int connfd, sds buffer, int len, httpHeader *header, 84 | handshake *hs); 85 | static char *findEolChar(const char *s, int len); 86 | static int getLeftEolLength(const char *s); 87 | int bufferLineSearchEOL(httpHeader *header, const char *buffer, int len, 88 | char *eol_style); 89 | int bufferReadln(httpHeader *header, const char *buffer, int len, 90 | char *eol_style); 91 | char *findChar(char sp_char, const char *dest, int len); 92 | char *findSpace(const char *s, int len); 93 | 94 | /* 95 | by RFC2616 96 | http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1 97 | The Request-Line begins with a method token, followed by the Request-URI and the 98 | protocol version, and ending with CRLF. 99 | The elements are separated by SP characters. No CR or LF is allowed except in 100 | the final CRLF sequence. 101 | Request-Line = Method SP Request-URI SP HTTP-Version CRLF 102 | */ 103 | static int parseFirstLine(httpHeader *header, const char *buffer, int len); 104 | static int readingHeaderFirstLine(httpHeader *header, const char *buffer, 105 | int len); 106 | static int readingHeaders(httpHeader *header, const char *buffer, int len); 107 | int readingSingleLine(httpHeader *header, const char *org, int len); 108 | char *getHeaderParams(httpHeader *header, char *pkey); 109 | int isHttpProtocol(char *buffer, int len); 110 | void getGetMethodBody(); 111 | void getPostMethodBody(); 112 | int httpRequestParse(int connfd, sds buffer, int len); 113 | int httpHeaderParse(httpHeader *header, sds buffer, int len); 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /include/appnet_sds.h: -------------------------------------------------------------------------------- 1 | #ifndef __SDS_H 2 | #define __SDS_H 3 | 4 | #define SDS_MAX_PREALLOC (1024*1024) 5 | 6 | #include 7 | #include 8 | 9 | typedef char *sds; 10 | 11 | struct sdshdr 12 | { 13 | unsigned int len; 14 | unsigned int free; 15 | char buf[]; 16 | }; 17 | 18 | static inline size_t sdslen( const sds s ) 19 | { 20 | struct sdshdr *sh = (void*) ( s - ( sizeof(struct sdshdr) ) ); 21 | return sh->len; 22 | } 23 | 24 | static inline size_t sdsavail( const sds s ) 25 | { 26 | struct sdshdr *sh = (void*) ( s - ( sizeof(struct sdshdr) ) ); 27 | return sh->free; 28 | } 29 | 30 | sds sdsnewlen( const void *init , size_t initlen ); 31 | sds sdsnew( const char *init ); 32 | sds sdsempty( void ); 33 | size_t sdslen( const sds s ); 34 | sds sdsdup( const sds s ); 35 | void sdsfree( sds s ); 36 | size_t sdsavail( const sds s ); 37 | sds sdsgrowzero( sds s , size_t len ); 38 | sds sdscatlen( sds s , const void *t , size_t len ); 39 | sds sdscat( sds s , const char *t ); 40 | sds sdscatsds( sds s , const sds t ); 41 | sds sdscpylen( sds s , const char *t , size_t len ); 42 | sds sdscpy( sds s , const char *t ); 43 | 44 | sds sdscatvprintf( sds s , const char *fmt , va_list ap ); 45 | #ifdef __GNUC__ 46 | sds sdscatprintf(sds s, const char *fmt, ...) 47 | __attribute__((format(printf, 2, 3))); 48 | #else 49 | sds sdscatprintf( sds s , const char *fmt , ... ); 50 | #endif 51 | 52 | sds sdscatfmt( sds s , char const *fmt , ... ); 53 | sds sdstrim( sds s , const char *cset ); 54 | void sdsrange( sds s , int start , int end ); 55 | void sdsupdatelen( sds s ); 56 | void sdsclear( sds s ); 57 | int sdscmp( const sds s1 , const sds s2 ); 58 | sds *sdssplitlen( const char *s , int len , const char *sep , int seplen , int *count ); 59 | void sdsfreesplitres( sds *tokens , int count ); 60 | void sdstolower( sds s ); 61 | void sdstoupper( sds s ); 62 | sds sdsfromlonglong( long long value ); 63 | sds sdscatrepr( sds s , const char *p , size_t len ); 64 | sds *sdssplitargs( const char *line , int *argc ); 65 | sds sdsmapchars( sds s , const char *from , const char *to , size_t setlen ); 66 | sds sdsjoin( char **argv , int argc , char *sep ); 67 | 68 | /* Low level functions exposed to the user API */ 69 | sds sdsMakeRoomFor( sds s , size_t addlen ); 70 | void sdsIncrLen( sds s , int incr ); 71 | sds sdsRemoveFreeSpace( sds s ); 72 | size_t sdsAllocSize( sds s ); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /include/appnet_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __APPNET_SERVER_H__ 2 | #define __APPNET_SERVER_H__ 3 | 4 | #include "appnet_event.h" 5 | #include "appnet_dict.h" 6 | #include "appnet_request.h" 7 | #include "appnet_response.h" 8 | #include "appnet_sds.h" 9 | #include "share_memory.h" 10 | #include "appnet_websocket.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define AE_TRUE 1 21 | #define AE_FALSE 0 22 | 23 | 24 | #define OPT_WORKER_NUM "opt_worker_num" 25 | #define OPT_TASK_WORKER_NUM "opt_task_worker_num" 26 | #define OPT_REACTOR_NUM "opt_reactor_num" 27 | #define OPT_MAX_CONNECTION "opt_max_connection" 28 | #define OPT_PROTOCOL_TYPE "opt_protocol_type" 29 | #define OPT_DAEMON "opt_daemon" 30 | #define OPT_PORT_HTTP "opt_port_http" 31 | #define OPT_PORT_WEBSOCKET "opt_port_websocket" 32 | 33 | #define APPNET_HTTP_DOCS_ROOT "http_docs_root" 34 | #define APPNET_HTTP_404_PAGE "http_404_page" 35 | #define APPNET_HTTP_50X_PAGE "http_50x_page" 36 | #define APPNET_HTTP_UPLOAD_DIR "http_upload_dir" 37 | #define APPNET_HTTP_KEEP_ALIVE "http_keep_alive" 38 | 39 | #define DEFAULT_HTTP_DOCS_ROOT "/home/www" 40 | #define DEFALUT_HTTP_404_PAGE "/404.html" 41 | #define DEFALUT_HTTP_50X_PAGE "/50x.html" 42 | 43 | #define MAXFD 1024 44 | #define MAX_EVENT 4096 45 | #define WORKER_PROCESS_COUNT 3 46 | #define REACTOR_THREAD_COUNT 2 47 | 48 | #define TMP_BUFFER_LENGTH 65535 49 | #define RECV_BUFFER_LENGTH 65535 50 | #define SEND_BUFFER_LENGTH 65535 51 | 52 | #define SOCKET_SND_BUF_SIZE 1024 * 1024 53 | #define SOCKET_RCV_BUF_SIZE 1024 * 1024 54 | 55 | #define __SLEEP_WAIT__ usleep(10000) 56 | struct aeEventLoop; 57 | 58 | typedef struct 59 | { 60 | char disable; 61 | char proto_type; 62 | uint16_t listen_port; 63 | uint16_t listen_fd; 64 | char *client_ip; 65 | uint16_t client_port; 66 | uint16_t worker_id; 67 | uint8_t reactor_id; 68 | sds send_buffer; 69 | sds recv_buffer; 70 | int connfd; 71 | char wshs; //websocket handleshake 72 | } appnetConnection; 73 | 74 | typedef struct _appnetServer appnetServer; 75 | typedef struct _reactorThreadParam reactorThreadParam; 76 | 77 | typedef struct 78 | { 79 | int epfd; 80 | int id; 81 | int event_num; 82 | int max_event_num; 83 | int running :1; 84 | void *object; 85 | void *ptr; 86 | aeEventLoop *event_loop; 87 | } appnetReactor; 88 | 89 | typedef struct 90 | { 91 | pid_t pid; 92 | int pipefd[2]; 93 | pthread_mutex_t w_mutex; 94 | pthread_mutex_t r_mutex; 95 | sds send_buffer; /* worker send to pipe */ 96 | sds recv_buffer; /* worker recv from pipe */ 97 | } appnetWorkerProcess; 98 | 99 | typedef struct _appnetWorkerPipes 100 | { 101 | int pipefd[2]; 102 | } appnetWorkerPipes; 103 | 104 | typedef struct 105 | { 106 | char proto; /* current request protocol type */ 107 | int pidx; /* process index */ 108 | pid_t pid; 109 | int pipefd; 110 | int running; 111 | int max_event; 112 | int connfd; 113 | int start; 114 | int task_id; 115 | aeEventLoop *el; 116 | sds send_buffer; /* master send to pipe */ 117 | sds recv_buffer; /* master recv from pipe */ 118 | sds response; 119 | dict *resp_header; 120 | httpHeader req_header; 121 | } appnetWorker; 122 | 123 | typedef struct 124 | { 125 | pthread_t thread_id; 126 | appnetReactor reactor; 127 | reactorThreadParam *param; 128 | handshake *hs; 129 | httpHeader *hh; /* http/websocket header */ 130 | } appnetReactorThread; 131 | 132 | typedef enum 133 | { 134 | PIPE_EVENT_CONNECT = 1, 135 | PIPE_EVENT_MESSAGE, 136 | PIPE_EVENT_CLOSE, 137 | PIPE_EVENT_TASK 138 | } PipeEventType; 139 | 140 | typedef enum 141 | { 142 | LISTEN_TYPE_TCP = 0, 143 | LISTEN_TYPE_HTTP, 144 | LISTEN_TYPE_WS, 145 | LISTEN_TYPE_HTTPS, 146 | LISTEN_TYPE_MAX 147 | } ListenType; 148 | 149 | struct _appnetServer 150 | { 151 | char *listen_ip; 152 | uint16_t listenfd; 153 | uint16_t port; 154 | uint16_t listen_fds[4]; 155 | uint16_t ports[4]; 156 | uint8_t running; 157 | uint8_t daemon; 158 | void *ptr2; 159 | uint16_t reactor_num; 160 | uint16_t worker_num; 161 | uint16_t task_worker_num; 162 | uint32_t connect_max; 163 | uint32_t connect_num; 164 | uint8_t exit_code; 165 | uint8_t proto_type; 166 | uint8_t http_keep_alive; 167 | char http_404_page[64]; 168 | char http_50x_page[64]; 169 | char http_docs_root[255]; 170 | char http_upload_dir[255]; 171 | appnetReactor *main_reactor; 172 | appnetConnection *connlist; 173 | appnetReactorThread *reactor_threads; 174 | appnetWorkerProcess *workers; 175 | appnetWorkerPipes *worker_pipes; 176 | appnetWorker *worker; 177 | int sigPipefd[2]; 178 | int (*sendToClient)( int fd, char *data, int len ); 179 | void (*closeClient)( appnetConnection *conn ); 180 | int (*send)( int fd, char *data, int len ); 181 | int (*close)( int fd ); 182 | int (*setOption)( char *key, char *val ); 183 | int (*setHeader)( char *key, char *val ); 184 | void (*onConnect)( appnetServer *serv, int fd ); 185 | void (*onRecv)( appnetServer *serv, appnetConnection *c, char *buff, int len ); 186 | void (*onTask)( char *data, int len, int id, int from ); 187 | void (*onTaskCallback)( char *data, int len, int id, int from ); 188 | void (*onClose)( appnetServer *serv, appnetConnection *c ); 189 | void (*onStart)( appnetServer *serv ); 190 | void (*onFinal)( appnetServer *serv ); 191 | void (*runForever)( appnetServer *serv ); 192 | }; 193 | 194 | struct _reactorThreadParam 195 | { 196 | int thid; 197 | appnetServer *serv; 198 | }; 199 | 200 | /*receive status*/ 201 | #define CONTINUE_RECV 1 202 | #define BREAK_RECV 2 203 | #define CLOSE_CONNECT 3 204 | 205 | #pragma pack(1) 206 | typedef struct 207 | { 208 | char type; 209 | char proto; 210 | int header_len; 211 | int len; 212 | int connfd; 213 | sds data; 214 | } appnetPipeData; 215 | /*define pipe data header length*/ 216 | #define PIPE_DATA_HEADER_LENG 2+3*sizeof(int) 217 | 218 | typedef struct 219 | { 220 | int id; 221 | int to; 222 | int from; 223 | } asyncTask; 224 | 225 | void initOnLoopStart( struct aeEventLoop *el ); 226 | void initThreadOnLoopStart( struct aeEventLoop *el ); 227 | void onSignEvent( aeEventLoop *el, int fd, void *privdata, int mask ); 228 | void freeClient( appnetConnection *c ); 229 | void onCloseByClient( aeEventLoop *el, void *privdata, appnetServer *serv, appnetConnection *conn ); 230 | void onClientWritable( aeEventLoop *el, int fd, void *privdata, int mask ); 231 | void onClientReadable( aeEventLoop *el, int fd, void *privdata, int mask ); 232 | int setPipeWritable( aeEventLoop *el, void *privdata, int worker_id ); 233 | /*accept connection from client*/ 234 | void acceptCommonHandler( appnetServer *serv, int listenfd, int connfd, char *client_ip, int client_port ); 235 | void onAcceptEvent( aeEventLoop *el, int fd, void *privdata, int mask ); 236 | void runMainReactor( appnetServer *serv ); 237 | void masterSignalHandler( int sig ); 238 | void addSignal( int sig, void (*handler)( int ), int restart ); 239 | void installMasterSignal( appnetServer *serv ); 240 | appnetServer *aeServerCreate( char *ip, int port ); 241 | void createReactorThreads( appnetServer *serv ); 242 | appnetReactorThread getReactorThread( appnetServer *serv, int i ); 243 | void readBodyFromPipe( aeEventLoop *el, int fd, appnetPipeData data ); 244 | void onMasterPipeReadable( aeEventLoop *el, int fd, void *privdata, int mask ); 245 | void onMasterPipeWritable( aeEventLoop *el, int pipe_fd, void *privdata, int mask ); 246 | void *reactorThreadRun( void *arg ); 247 | int socketSetBufferSize( int fd, int buffer_size ); 248 | void createWorkerProcess( appnetServer *serv ); 249 | void stopReactorThread( appnetServer *serv ); 250 | void freeWorkerBuffer( appnetServer *serv ); 251 | int freeConnectBuffers( appnetServer *serv ); 252 | void destroyServer( appnetServer *serv ); 253 | int startServer( appnetServer *serv ); 254 | void initWorkerOnLoopStart( aeEventLoop *l ); 255 | int sendMessageToReactor( int connfd, char *buff, int len ); 256 | void readWorkerBodyFromPipe( int pipe_fd, appnetPipeData data ); 257 | void onWorkerPipeWritable( aeEventLoop *el, int fd, void *privdata, int mask ); 258 | void onWorkerPipeReadable( aeEventLoop *el, int fd, void *privdata, int mask ); 259 | int sendCloseEventToReactor( int connfd ); 260 | int socketWrite( int __fd, void *__data, int __len ); 261 | int send2ReactorThread( int connfd, appnetPipeData data ); 262 | int timerCallback( struct aeEventLoop *l, long long id, void *data ); 263 | void finalCallback( struct aeEventLoop *l, void *data ); 264 | void childTermHandler( int sig ); 265 | void childChildHandler( int sig ); 266 | void runWorkerProcess( int pidx ); 267 | void appendWorkerData( int connfd, char *buffer, int len, int event_type, char *from ); 268 | void appendHttpData( int connfd, char *header, int header_len, char *body, int body_len, int event_type, char *from ); 269 | aeEventLoop *getThreadEventLoop( int connfd ); 270 | int setHeader( char *key, char *val ); 271 | int setOption( char *key, char *val ); 272 | void timerAdd( int ms, void *cb, void *params ); 273 | void resetRespHeader( dict *resp_header ); 274 | sds getRespHeaderString( sds header ); 275 | int setRespHeader( char *key, char *val ); 276 | void appendToClientSendBuffer( int connfd, char *buffer, int len ); 277 | int getPipeIndex( int connfd ); 278 | int checkPort( appnetServer *serv , int proto_type , int port ); 279 | 280 | appnetServer *servG; 281 | #endif 282 | -------------------------------------------------------------------------------- /include/appnet_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef ANET_H 2 | #define ANET_H 3 | 4 | #define ANET_OK 0 5 | #define ANET_ERR -1 6 | #define ANET_ERR_LEN 256 7 | 8 | /* Flags used with certain functions. */ 9 | #define ANET_NONE 0 10 | #define ANET_IP_ONLY (1<<0) 11 | 12 | #if defined(__sun) || defined(_AIX) 13 | #define AF_LOCAL AF_UNIX 14 | #endif 15 | 16 | #ifdef _AIX 17 | #undef ip_len 18 | #endif 19 | #include 20 | #include 21 | int anetTcpConnect( char *err , char *addr , int port ); 22 | int anetTcpNonBlockConnect( char *err , char *addr , int port ); 23 | int anetTcpNonBlockBindConnect( char *err , char *addr , int port , char *source_addr ); 24 | int anetTcpNonBlockBestEffortBindConnect( char *err , char *addr , int port , char *source_addr ); 25 | int anetUnixConnect( char *err , char *path ); 26 | int anetUnixNonBlockConnect( char *err , char *path ); 27 | int anetRead( int fd , char *buf , int count ); 28 | int anetRecv( int fd , char *buf , int count ); 29 | int anetResolve( char *err , char *host , char *ipbuf , size_t ipbuf_len ); 30 | int anetResolveIP( char *err , char *host , char *ipbuf , size_t ipbuf_len ); 31 | int anetTcpServer( char *err , int port , char *bindaddr , int backlog ); 32 | int anetTcp6Server( char *err , int port , char *bindaddr , int backlog ); 33 | int anetUnixServer( char *err , char *path , mode_t perm , int backlog ); 34 | int anetTcpAccept( char *err , int serversock , char *ip , size_t ip_len , int *port ); 35 | int anetUnixAccept( char *err , int serversock ); 36 | int anetWrite( int fd , char *buf , int count ); 37 | int anetNonBlock( char *err , int fd ); 38 | int anetBlock( char *err , int fd ); 39 | int anetEnableTcpNoDelay( char *err , int fd ); 40 | int anetDisableTcpNoDelay( char *err , int fd ); 41 | int anetTcpKeepAlive( char *err , int fd ); 42 | int anetSendTimeout( char *err , int fd , long long ms ); 43 | int anetPeerToString( int fd , char *ip , size_t ip_len , int *port ); 44 | int anetKeepAlive( char *err , int fd , int interval ); 45 | int anetSockName( int fd , char *ip , size_t ip_len , int *port ); 46 | int anetHandup( int fd , int timeout_ms , int events ); 47 | int listenToPort( char *bindaddr , int port , int* fds , int *count ); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /include/appnet_websocket.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef WEBSOCKET_H 3 | #define WEBSOCKET_H 4 | 5 | #include 6 | #include /* isdigit */ 7 | #include /*htons*/ 8 | #include /* uint8_t */ 9 | #include /* sscanf */ 10 | #include /* strtoul */ 11 | #include 12 | //#include /* size_t */ 13 | #include "base64.h" 14 | #include "sha1.h" 15 | 16 | #define PROGMEM 17 | #define PSTR 18 | #define strstr_P strstr 19 | #define sscanf_P sscanf 20 | #define sprintf_P sprintf 21 | #define strlen_P strlen 22 | #define memcmp_P memcmp 23 | #define memcpy_P memcpy 24 | 25 | #ifndef TRUE 26 | #define TRUE 1 27 | #endif 28 | #ifndef FALSE 29 | #define FALSE 0 30 | #endif 31 | 32 | static const char connectionField[] = "Connection: "; 33 | static const char upgrade[] = "upgrade"; 34 | static const char upgrade2[] = "Upgrade"; 35 | static const char upgradeField[] = "Upgrade: "; 36 | static const char websocket[] = "websocket"; 37 | static const char hostField[] = "Host: "; 38 | static const char originField[] = "Origin: "; 39 | static const char keyField[] = "Sec-WebSocket-Key: "; 40 | static const char protocolField[] = "Sec-WebSocket-Protocol: "; 41 | static const char versionField[] = "Sec-WebSocket-Version: "; 42 | static const char version[] = "13"; 43 | static const char secret[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 44 | 45 | enum wsFrameType 46 | { // errors starting from 0xF0 47 | WS_EMPTY_FRAME = 0xF0, 48 | WS_ERROR_FRAME = 0xF1, 49 | WS_INCOMPLETE_FRAME = 0xF2, 50 | WS_TEXT_FRAME = 0x01, 51 | WS_BINARY_FRAME = 0x02, 52 | WS_PING_FRAME = 0x09, 53 | WS_PONG_FRAME = 0x0A, 54 | WS_OPENING_FRAME = 0xF3, 55 | WS_CLOSING_FRAME = 0x08 56 | }; 57 | 58 | enum wsState 59 | { 60 | WS_STATE_OPENING, 61 | WS_STATE_NORMAL, 62 | WS_STATE_CLOSING 63 | }; 64 | 65 | typedef struct _handshake 66 | { 67 | char host[32]; 68 | char origin[64]; 69 | char key[32]; 70 | char key_ext[64]; 71 | int ver[3]; 72 | char *resource; 73 | enum wsFrameType frame_type; 74 | enum wsState state; 75 | } handshake; 76 | 77 | /** 78 | * @param inputFrame Pointer to input frame 79 | * @param inputLength Length of input frame 80 | * @param hs Cleared with nullHandshake() handshake structure 81 | * @return Type of parsed frame 82 | */ 83 | enum wsFrameType wsParseHandshake( const uint8_t *inputFrame , size_t inputLength , 84 | handshake *hs ); 85 | 86 | /** 87 | * @param hs Filled handshake structure 88 | * @param outFrame Pointer to frame buffer 89 | * @param outLength Length of frame buffer. Return length of out frame 90 | */ 91 | void wsGetHandshakeAnswer( const handshake *hs , uint8_t *outFrame , 92 | size_t *outLength , char *ver ); 93 | 94 | // void initHandshake( int connfd , httpHeader* header , handshake* hs ); 95 | /** 96 | * @param data Pointer to input data array 97 | * @param dataLength Length of data array 98 | * @param outFrame Pointer to frame buffer 99 | * @param outLength Length of out frame buffer. Return length of out frame 100 | * @param frameType [WS_TEXT_FRAME] frame type to build 101 | */ 102 | void wsMakeFrame( const uint8_t *data , size_t dataLength , uint8_t *outFrame , 103 | size_t *outLength , enum wsFrameType frameType ); 104 | 105 | /** 106 | * 107 | * @param inputFrame Pointer to input frame. Frame will be modified. 108 | * @param inputLen Length of input frame 109 | * @param outDataPtr Return pointer to extracted data in input frame 110 | * @param outLen Return length of extracted data 111 | * @return Type of parsed frame 112 | */ 113 | enum wsFrameType wsParseInputFrame( uint8_t *inputFrame , size_t inputLength , 114 | uint8_t **dataPtr , size_t *dataLength ); 115 | 116 | /** 117 | * @param hs NULL handshake structure 118 | */ 119 | void nullHandshake( handshake *hs ); 120 | 121 | /** 122 | * @param hs free and NULL handshake structure 123 | */ 124 | void freeHandshake( handshake *hs ); 125 | 126 | #endif /* WEBSOCKET_H */ 127 | -------------------------------------------------------------------------------- /include/base64.h: -------------------------------------------------------------------------------- 1 | /** 2 | https://github.com/nori0428/mod_websocket/blob/master/src/mod_websocket_base64.h 3 | */ 4 | 5 | #ifndef _BASE64_H_ 6 | #define _BASE64_H_ 7 | 8 | #include 9 | #include 10 | 11 | size_t base64_encode( char *buf , size_t nbuf , const unsigned char *p , size_t n ); 12 | int base64_decode( unsigned char ** , size_t * , const unsigned char * ); 13 | #endif /* _BASE64_H_ */ 14 | -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __CONFIG_H 3 | #define __CONFIG_H 4 | 5 | #ifdef __APPLE__ 6 | #include 7 | #endif 8 | 9 | #ifdef __linux__ 10 | #include 11 | #include 12 | #endif 13 | 14 | /* Define redis_fstat to fstat or fstat64() */ 15 | #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) 16 | #define redis_fstat fstat64 17 | #define redis_stat stat64 18 | #else 19 | #define redis_fstat fstat 20 | #define redis_stat stat 21 | #endif 22 | 23 | /* Test for proc filesystem */ 24 | #ifdef __linux__ 25 | #define HAVE_PROC_STAT 1 26 | #define HAVE_PROC_MAPS 1 27 | #define HAVE_PROC_SMAPS 1 28 | #define HAVE_PROC_SOMAXCONN 1 29 | #endif 30 | 31 | /* Test for task_info() */ 32 | #if defined(__APPLE__) 33 | #define HAVE_TASKINFO 1 34 | #endif 35 | 36 | /* Test for backtrace() */ 37 | #if defined(__APPLE__) || (defined(__linux__) && defined(__GLIBC__)) 38 | #define HAVE_BACKTRACE 1 39 | #endif 40 | 41 | /* Test for polling API */ 42 | #ifdef __linux__ 43 | #define HAVE_EPOLL 1 44 | #endif 45 | 46 | #if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) 47 | #define HAVE_KQUEUE 1 48 | #endif 49 | 50 | #ifdef __sun 51 | #include 52 | #ifdef _DTRACE_VERSION 53 | #define HAVE_EVPORT 1 54 | #endif 55 | #endif 56 | 57 | /* Define aof_fsync to fdatasync() in Linux and fsync() for all the rest */ 58 | #ifdef __linux__ 59 | #define aof_fsync fdatasync 60 | #else 61 | #define aof_fsync fsync 62 | #endif 63 | 64 | /* Define rdb_fsync_range to sync_file_range() on Linux, otherwise we use 65 | * the plain fsync() call. */ 66 | #ifdef __linux__ 67 | #if defined(__GLIBC__) && defined(__GLIBC_PREREQ) 68 | #if (LINUX_VERSION_CODE >= 0x020611 && __GLIBC_PREREQ(2, 6)) 69 | #define HAVE_SYNC_FILE_RANGE 1 70 | #endif 71 | #else 72 | #if (LINUX_VERSION_CODE >= 0x020611) 73 | #define HAVE_SYNC_FILE_RANGE 1 74 | #endif 75 | #endif 76 | #endif 77 | 78 | #ifdef HAVE_SYNC_FILE_RANGE 79 | #define rdb_fsync_range(fd,off,size) sync_file_range(fd,off,size,SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE) 80 | #else 81 | #define rdb_fsync_range(fd,off,size) fsync(fd) 82 | #endif 83 | 84 | /* Check if we can use setproctitle(). 85 | * BSD systems have support for it, we provide an implementation for 86 | * Linux and osx. */ 87 | #if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__) 88 | #define USE_SETPROCTITLE 89 | #endif 90 | 91 | #if ((defined __linux && defined(__GLIBC__)) || defined __APPLE__) 92 | #define USE_SETPROCTITLE 93 | #define INIT_SETPROCTITLE_REPLACEMENT 94 | void spt_init(int argc, char *argv[]); 95 | void setproctitle(const char *fmt, ...); 96 | #endif 97 | 98 | /* Byte ordering detection */ 99 | #include /* This will likely define BYTE_ORDER */ 100 | 101 | #ifndef BYTE_ORDER 102 | #if (BSD >= 199103) 103 | # include 104 | #else 105 | #if defined(linux) || defined(__linux__) 106 | # include 107 | #else 108 | #define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ 109 | #define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ 110 | #define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ 111 | 112 | #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \ 113 | defined(vax) || defined(ns32000) || defined(sun386) || \ 114 | defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ 115 | defined(__alpha__) || defined(__alpha) 116 | #define BYTE_ORDER LITTLE_ENDIAN 117 | #endif 118 | 119 | #if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ 120 | defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ 121 | defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ 122 | defined(apollo) || defined(__convex__) || defined(_CRAY) || \ 123 | defined(__hppa) || defined(__hp9000) || \ 124 | defined(__hp9000s300) || defined(__hp9000s700) || \ 125 | defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) 126 | #define BYTE_ORDER BIG_ENDIAN 127 | #endif 128 | #endif /* linux */ 129 | #endif /* BSD */ 130 | #endif /* BYTE_ORDER */ 131 | 132 | /* Sometimes after including an OS-specific header that defines the 133 | * endianess we end with __BYTE_ORDER but not with BYTE_ORDER that is what 134 | * the Redis code uses. In this case let's define everything without the 135 | * underscores. */ 136 | #ifndef BYTE_ORDER 137 | #ifdef __BYTE_ORDER 138 | #if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) 139 | #ifndef LITTLE_ENDIAN 140 | #define LITTLE_ENDIAN __LITTLE_ENDIAN 141 | #endif 142 | #ifndef BIG_ENDIAN 143 | #define BIG_ENDIAN __BIG_ENDIAN 144 | #endif 145 | #if (__BYTE_ORDER == __LITTLE_ENDIAN) 146 | #define BYTE_ORDER LITTLE_ENDIAN 147 | #else 148 | #define BYTE_ORDER BIG_ENDIAN 149 | #endif 150 | #endif 151 | #endif 152 | #endif 153 | 154 | #if !defined(BYTE_ORDER) || \ 155 | (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN) 156 | /* you must determine what the correct bit order is for 157 | * your compiler - the next line is an intentional error 158 | * which will force your compiles to bomb until you fix 159 | * the above macros. 160 | */ 161 | #error "Undefined or invalid BYTE_ORDER" 162 | #endif 163 | 164 | #if (__i386 || __amd64 || __powerpc__) && __GNUC__ 165 | #define GNUC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 166 | #if defined(__clang__) 167 | #define HAVE_ATOMIC 168 | #endif 169 | #if (defined(__GLIBC__) && defined(__GLIBC_PREREQ)) 170 | #if (GNUC_VERSION >= 40100 && __GLIBC_PREREQ(2, 6)) 171 | #define HAVE_ATOMIC 172 | #endif 173 | #endif 174 | #endif 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /include/mime_types.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _MIME_TYPES_H_ 3 | #define _MIME_TYPES_H_ 4 | 5 | #define MIME_TYPES_NUM 79 6 | 7 | const char *mime_types[MIME_TYPES_NUM][2] = 8 | { 9 | {"text/html","html htm shtml"}, 10 | {"text/css","css"}, 11 | {"text/xml","xml"}, 12 | {"image/gif","gif"}, 13 | {"image/jpeg","jpeg jpg"}, 14 | {"application/javascript","js"}, 15 | {"application/atom+xml","atom"}, 16 | {"application/rss+xml","rss"}, 17 | {"text/mathml","mml"}, 18 | {"text/plain","txt"}, 19 | {"text/vnd.sun.j2me.app-descriptor","jad"}, 20 | {"text/vnd.wap.wml","wml"}, 21 | {"text/x-component","htc"}, 22 | {"image/png","png"}, 23 | {"image/tiff","tif tiff"}, 24 | {"image/vnd.wap.wbmp","wbmp"}, 25 | {"image/x-icon","ico"}, 26 | {"image/x-jng","jng"}, 27 | {"image/x-ms-bmp","bmp"}, 28 | {"image/svg+xml","svg svgz"}, 29 | {"image/webp","webp"}, 30 | {"application/font-woff","woff"}, 31 | {"application/java-archive","jar war ear"}, 32 | {"application/json","json"}, 33 | {"application/mac-binhex40","hqx"}, 34 | {"application/msword","doc"}, 35 | {"application/pdf","pdf"}, 36 | {"application/postscript","ps eps ai"}, 37 | {"application/rtf","rtf"}, 38 | {"application/vnd.apple.mpegurl","m3u8"}, 39 | {"application/vnd.ms-excel","xls"}, 40 | {"application/vnd.ms-fontobject","eot"}, 41 | {"application/vnd.ms-powerpoint","ppt"}, 42 | {"application/vnd.wap.wmlc","wmlc"}, 43 | {"application/vnd.google-earth.kml+xml","kml"}, 44 | {"application/vnd.google-earth.kmz","kmz"}, 45 | {"application/x-7z-compressed","7z"}, 46 | {"application/x-cocoa","cco"}, 47 | {"application/x-java-archive-diff","jardiff"}, 48 | {"application/x-java-jnlp-file","jnlp"}, 49 | {"application/x-makeself","run"}, 50 | {"application/x-perl","pl pm"}, 51 | {"application/x-pilot","prc pdb"}, 52 | {"application/x-rar-compressed","rar"}, 53 | {"application/x-redhat-package-manager","rpm"}, 54 | {"application/x-sea","sea"}, 55 | {"application/x-shockwave-flash","swf"}, 56 | {"application/x-stuffit","sit"}, 57 | {"application/x-tcl","tcl tk"}, 58 | {"application/x-x509-ca-cert","der pem crt"}, 59 | {"application/x-xpinstall","xpi"}, 60 | {"application/xhtml+xml","xhtml"}, 61 | {"application/xspf+xml","xspf"}, 62 | {"application/zip","zip"}, 63 | {"application/octet-stream","bin exe dll"}, 64 | {"application/octet-stream","deb"}, 65 | {"application/octet-stream","dmg"}, 66 | {"application/octet-stream","iso img"}, 67 | {"application/octet-stream","msi msp msm"}, 68 | {"audio/midi","mid midi kar"}, 69 | {"audio/mpeg","mp3"}, 70 | {"audio/ogg","ogg"}, 71 | {"audio/x-m4a","m4a"}, 72 | {"audio/x-realaudio","ra"}, 73 | {"video/3gpp","3gpp 3gp"}, 74 | {"video/mp2t","ts"}, 75 | {"video/mp4","mp4"}, 76 | {"video/mpeg","mpeg mpg"}, 77 | {"video/quicktime","mov"}, 78 | {"video/webm","webm"}, 79 | {"video/x-flv","flv"}, 80 | {"video/x-m4v","m4v"}, 81 | {"video/x-mng","mng"}, 82 | {"video/x-ms-asf","asx asf"}, 83 | {"video/x-ms-wmv","wmv"}, 84 | {"video/x-msvideo","avi"}, 85 | {"application/vnd.openxmlformats-officedocument.wordprocessingml.document", 86 | "docx"}, 87 | {"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 88 | "xlsx"}, 89 | {"application/" 90 | "vnd.openxmlformats-officedocument.presentationml.presentation", 91 | "pptx"}}; 92 | 93 | static inline int getExtMimeType( char *ext , char *ctype ) 94 | { 95 | if (!ext) 96 | return 0; 97 | 98 | int i; 99 | char *ret; 100 | for (i = 0; i < MIME_TYPES_NUM; i++) 101 | { 102 | if (!mime_types[i]) 103 | { 104 | return 0; 105 | } 106 | 107 | ret = strstr( mime_types[i][1] , ext ); 108 | if (ret) 109 | { 110 | memcpy( ctype , mime_types[i][0] , strlen( mime_types[i][0] ) ); 111 | return 1; 112 | } 113 | } 114 | return 0; 115 | } 116 | 117 | static inline int getMimeType( char *uri , char *ctype ) 118 | { 119 | char *pos; 120 | pos = strstr( uri , "?" ); 121 | 122 | char file_name[1024] = 123 | {0}; 124 | char ext[16] = 125 | {0}; 126 | char *ptr = strrchr( uri , '/' ); 127 | if (ptr == NULL) 128 | return 0; 129 | 130 | int len = uri - ptr + strlen( uri ); 131 | if (pos != NULL) 132 | { 133 | int pos_len = pos - ptr; 134 | len = pos_len - 1; 135 | } 136 | 137 | memcpy( file_name , ptr + 1 , len ); 138 | char *ext_ptr = strrchr( file_name , '.' ); 139 | if (ext_ptr == NULL) 140 | return 0; 141 | sprintf( ext , "%s" , ext_ptr + 1 ); 142 | 143 | int ret = getExtMimeType( ext , ctype ); 144 | return ret; 145 | } 146 | 147 | #endif /* _MIME_TYPES_H_ */ 148 | -------------------------------------------------------------------------------- /include/rbtree.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Igor Sysoev 4 | * Copyright (C) Nginx, Inc. 5 | */ 6 | 7 | #ifndef _RBTREE_H_ 8 | #define _RBTREE_H_ 9 | 10 | typedef unsigned int uint_t; 11 | typedef unsigned int rbtree_key_t; 12 | typedef int rbtree_key_int_t; 13 | typedef unsigned char u_char; 14 | typedef struct rbtree_node_s rbtree_node_t; 15 | 16 | struct rbtree_node_s 17 | { 18 | rbtree_key_t key; 19 | rbtree_node_t *left; 20 | rbtree_node_t *right; 21 | rbtree_node_t *parent; 22 | u_char color; 23 | u_char data; 24 | }; 25 | 26 | typedef struct rbtree_s rbtree_t; 27 | 28 | typedef void (*rbtree_insert_pt)( rbtree_node_t *root , 29 | rbtree_node_t *node , rbtree_node_t *sentinel ); 30 | 31 | struct rbtree_s 32 | { 33 | rbtree_node_t *root; 34 | rbtree_node_t *sentinel; 35 | rbtree_insert_pt insert; 36 | }; 37 | 38 | #define rbtree_init(tree, s, i) \ 39 | rbtree_sentinel_init(s); \ 40 | (tree)->root = s; \ 41 | (tree)->sentinel = s; \ 42 | (tree)->insert = i 43 | 44 | void rbtree_insert( rbtree_t *tree , rbtree_node_t *node ); 45 | void rbtree_delete( rbtree_t *tree , rbtree_node_t *node ); 46 | void rbtree_insert_value( rbtree_node_t *root , rbtree_node_t *node , rbtree_node_t *sentinel ); 47 | void rbtree_insert_timer_value( rbtree_node_t *root , rbtree_node_t *node , rbtree_node_t *sentinel ); 48 | 49 | #define rbt_red(node) ((node)->color = 1) 50 | #define rbt_black(node) ((node)->color = 0) 51 | #define rbt_is_red(node) ((node)->color) 52 | #define rbt_is_black(node) (!rbt_is_red(node)) 53 | #define rbt_copy_color(n1, n2) (n1->color = n2->color) 54 | 55 | /* a sentinel must be black */ 56 | 57 | #define rbtree_sentinel_init(node) rbt_black(node) 58 | 59 | static inline rbtree_node_t * rbtree_min( rbtree_node_t *node , rbtree_node_t *sentinel ) 60 | { 61 | while (node->left != sentinel) 62 | { 63 | node = node->left; 64 | } 65 | return node; 66 | } 67 | 68 | #endif 69 | 70 | -------------------------------------------------------------------------------- /include/ring_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _RINGBUFFER_H_ 2 | #define _RINGBUFFER_H_ 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | int length; 9 | int start; 10 | int end; 11 | int use_shm; 12 | char *buffer; 13 | } ringBuffer; 14 | 15 | ringBuffer *ringBuffer_create( int length , int use_shm ); 16 | 17 | void ringBuffer_destroy( ringBuffer * buffer ); 18 | 19 | int ringBuffer_read( ringBuffer * buffer , char *target , int amount ); 20 | 21 | int ringBuffer_write( ringBuffer * buffer , char *data , int length ); 22 | 23 | int ringBuffer_empty( ringBuffer * buffer ); 24 | 25 | int ringBuffer_full( ringBuffer * buffer ); 26 | 27 | int ringBuffer_available_data( ringBuffer * buffer ); 28 | 29 | int ringBuffer_available_space( ringBuffer * buffer ); 30 | 31 | #define ringBuffer_available_data(B) (\ 32 | (B)->end % (B)->length - (B)->start) 33 | 34 | #define ringBuffer_available_space(B) (\ 35 | (B)->length - (B)->end - 1) 36 | 37 | #define ringBuffer_full(B) (ringBuffer_available_space(B) == 0) 38 | 39 | #define ringBuffer_empty(B) (ringBuffer_available_data((B)) == 0) 40 | 41 | #define ringBuffer_puts(B, D) ringBuffer_write(\ 42 | (B), bdata((D)), blength((D))) 43 | 44 | #define ringBuffer_starts_at(B) (\ 45 | (B)->buffer + (B)->start) 46 | 47 | #define ringBuffer_ends_at(B) (\ 48 | (B)->buffer + (B)->end) 49 | 50 | #define ringBuffer_commit_read(B, A) (\ 51 | (B)->start = ((B)->start + (A)) % (B)->length) 52 | 53 | #define ringBuffer_commit_write(B, A) (\ 54 | (B)->end = ((B)->end + (A)) % (B)->length) 55 | 56 | #define ringBuffer_clear(B) ringBuffer_commit_read((B),\ 57 | ringBuffer_available_data((B))); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha.h 3 | * 4 | * Originally taken from the public domain SHA1 implementation 5 | * written by by Steve Reid 6 | * 7 | * Modified by Aaron D. Gifford 8 | * 9 | * NO COPYRIGHT - THIS IS 100% IN THE PUBLIC DOMAIN 10 | * 11 | * The original unmodified version is available at: 12 | * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | 26 | SHA_CTX sha; 27 | SHA1_Init(&sha); 28 | SHA1_Update(&sha, (sha1_byte *)key->ptr, key->used - 1); 29 | SHA1_Final(sha_digest, &sha); 30 | */ 31 | 32 | #ifndef _SHA1_H__ 33 | #define _SHA1_H__ 34 | 35 | /* Define this if your machine is LITTLE_ENDIAN, otherwise #undef it: */ 36 | #ifdef WORDS_BIGENDIAN 37 | # undef LITTLE_ENDIAN 38 | #else 39 | # ifndef LITTLE_ENDIAN 40 | # define LITTLE_ENDIAN 41 | # endif 42 | #endif 43 | 44 | /* Make sure you define these types for your architecture: */ 45 | typedef unsigned int sha1_quadbyte; /* 4 byte type */ 46 | typedef unsigned char sha1_byte; /* single byte type */ 47 | 48 | /* 49 | * Be sure to get the above definitions right. For instance, on my 50 | * x86 based FreeBSD box, I define LITTLE_ENDIAN and use the type 51 | * "unsigned long" for the quadbyte. On FreeBSD on the Alpha, however, 52 | * while I still use LITTLE_ENDIAN, I must define the quadbyte type 53 | * as "unsigned int" instead. 54 | */ 55 | 56 | #define SHA1_BLOCK_LENGTH 64 57 | #define SHA1_DIGEST_LENGTH 20 58 | 59 | /* The SHA1 structure: */ 60 | typedef struct _SHA_CTX 61 | { 62 | sha1_quadbyte state[5]; 63 | sha1_quadbyte count[2]; 64 | sha1_byte buffer[SHA1_BLOCK_LENGTH]; 65 | } SHA_CTX; 66 | 67 | void sha1Init( SHA_CTX *context ); 68 | void sha1Update( SHA_CTX *context , sha1_byte *data , unsigned int len ); 69 | void sha1Final( sha1_byte digest[SHA1_DIGEST_LENGTH] , SHA_CTX* context ); 70 | 71 | unsigned char *sha1( const unsigned char *msg , size_t size , unsigned char result[SHA1_DIGEST_LENGTH] ); 72 | #endif 73 | -------------------------------------------------------------------------------- /include/share_memory.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | //#define SHM_TYPE_MMAP 8 | 9 | #define SHM_MMAP_FILE_LEN 64 10 | typedef struct _shareMemory_mmap 11 | { 12 | int size; 13 | char mapfile[SHM_MMAP_FILE_LEN]; 14 | int tmpfd; 15 | int key; 16 | int shmid; 17 | void *mem; 18 | } shareMemory; 19 | 20 | void *shareMemory_mmap_create( shareMemory *object , int size , char *mapfile ); 21 | void *shareMemory_sysv_create( shareMemory *object , int size , int key ); 22 | int shareMemory_sysv_free( shareMemory *object , int rm ); 23 | int shareMemory_mmap_free( shareMemory *object ); 24 | 25 | void* shm_malloc( size_t size ); 26 | void shm_free( void *ptr , int rm ); 27 | void* shm_calloc( size_t num , size_t _size ); 28 | void* shm_realloc( void *ptr , size_t new_size ); 29 | 30 | -------------------------------------------------------------------------------- /include/zmalloc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __ZMALLOC_H 3 | #define __ZMALLOC_H 4 | 5 | #include 6 | 7 | /* Double expansion needed for stringification of macro values. */ 8 | #define __xstr(s) __str(s) 9 | #define __str(s) #s 10 | 11 | #if defined(USE_TCMALLOC) 12 | #define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR)) 13 | #include 14 | #if (TC_VERSION_MAJOR == 1 && TC_VERSION_MINOR >= 6) || (TC_VERSION_MAJOR > 1) 15 | #define HAVE_MALLOC_SIZE 1 16 | #define zmalloc_size(p) tc_malloc_size(p) 17 | #else 18 | #error "Newer version of tcmalloc required" 19 | #endif 20 | 21 | #elif defined(USE_JEMALLOC) 22 | #define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX)) 23 | #include 24 | #if (JEMALLOC_VERSION_MAJOR == 2 && JEMALLOC_VERSION_MINOR >= 1) || (JEMALLOC_VERSION_MAJOR > 2) 25 | #define HAVE_MALLOC_SIZE 1 26 | #define zmalloc_size(p) je_malloc_usable_size(p) 27 | #else 28 | #error "Newer version of jemalloc required" 29 | #endif 30 | 31 | #elif defined(__APPLE__) 32 | #include 33 | #define HAVE_MALLOC_SIZE 1 34 | #define zmalloc_size(p) malloc_size(p) 35 | #endif 36 | 37 | #ifndef ZMALLOC_LIB 38 | #define ZMALLOC_LIB "libc" 39 | #endif 40 | 41 | void *zmalloc( size_t size ); 42 | void *zcalloc( size_t size ); 43 | void *zrealloc( void *ptr , size_t size ); 44 | void zfree( void *ptr ); 45 | char *zstrdup( const char *s ); 46 | size_t zmalloc_used_memory( void ); 47 | void zmalloc_enable_thread_safeness( void ); 48 | void zmalloc_set_oom_handler( void (*oom_handler)( size_t ) ); 49 | float zmalloc_get_fragmentation_ratio( size_t rss ); 50 | size_t zmalloc_get_rss( void ); 51 | size_t zmalloc_get_private_dirty( void ); 52 | size_t zmalloc_get_smap_bytes_by_field( char *field ); 53 | void zlibc_free( void *ptr ); 54 | 55 | #ifndef HAVE_MALLOC_SIZE 56 | size_t zmalloc_size( void *ptr ); 57 | #endif 58 | 59 | #endif /* __ZMALLOC_H */ 60 | -------------------------------------------------------------------------------- /php_appnet.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 7 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2015 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: | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifndef PHP_APPNET_H 22 | #define PHP_APPNET_H 23 | 24 | extern zend_module_entry appnet_module_entry; 25 | #define phpext_appnet_ptr &appnet_module_entry 26 | 27 | #define PHP_APPNET_VERSION \ 28 | "0.1.0" /* Replace with version number for your extension */ 29 | 30 | #ifdef PHP_WIN32 31 | #define PHP_APPNET_API __declspec(dllexport) 32 | #elif defined(__GNUC__) && __GNUC__ >= 4 33 | #define PHP_APPNET_API __attribute__((visibility("default"))) 34 | #else 35 | #define PHP_APPNET_API 36 | #endif 37 | 38 | #ifdef ZTS 39 | #include "TSRM.h" 40 | #endif 41 | #include "include/appnet_server.h" 42 | /* 43 | Declare any global variables you may need between the BEGIN 44 | and END macros here: 45 | 46 | ZEND_BEGIN_MODULE_GLOBALS(appnet) 47 | zend_long global_value; 48 | char *global_string; 49 | ZEND_END_MODULE_GLOBALS(appnet) 50 | */ 51 | 52 | /* Always refer to the globals in your function as APPNET_G(variable). 53 | You are encouraged to rename these macros something shorter, see 54 | examples in any other php module directory. 55 | */ 56 | /* 57 | #define APPNET_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(appnet, v) 58 | 59 | #if defined(ZTS) && defined(COMPILE_DL_APPNET) 60 | ZEND_TSRMLS_CACHE_EXTERN(); 61 | #endif 62 | 63 | #endif /* PHP_APPNET_H */ 64 | 65 | /* 66 | * Local variables: 67 | * tab-width: 4 68 | * c-basic-offset: 4 69 | * End: 70 | * vim600: noet sw=4 ts=4 fdm=marker 71 | * vim<600: noet sw=4 ts=4 72 | */ 73 | 74 | #define APPNET_SERVER_CALLBACK_NUM 8 75 | #define APPNET_SERVER_CB_onConnect 0 // accept new connection(worker) 76 | #define APPNET_SERVER_CB_onReceive 1 // receive data(worker) 77 | #define APPNET_SERVER_CB_onClose 2 // close tcp connection(worker) 78 | #define APPNET_SERVER_CB_onStart 3 79 | #define APPNET_SERVER_CB_onFinal 4 80 | #define APPNET_SERVER_CB_onTimer 5 // timer call(master) 81 | #define APPNET_SERVER_CB_onTask 6 82 | #define APPNET_SERVER_CB_onTask_CB 7 83 | 84 | #define APPNET_EVENT_CONNECT "connect" 85 | #define APPNET_EVENT_RECV "receive" 86 | #define APPNET_EVENT_CLOSE "close" 87 | #define APPNET_EVENT_START "start" 88 | #define APPNET_EVENT_FINAL "final" 89 | #define APPNET_EVENT_TIMER "timer" 90 | #define APPNET_EVENT_TASK "task" 91 | #define APPNET_EVENT_TASK_CB "task_cb" 92 | 93 | extern zval *appnet_serv_callback[APPNET_SERVER_CALLBACK_NUM]; 94 | 95 | zend_class_entry *AppnetServer; 96 | 97 | ZEND_METHOD( AppnetServer , __construct ); 98 | ZEND_METHOD( AppnetServer , on ); 99 | ZEND_METHOD( AppnetServer , run ); 100 | ZEND_METHOD( AppnetServer , send ); 101 | ZEND_METHOD( AppnetServer , close ); 102 | ZEND_METHOD( AppnetServer , getHeader ); 103 | ZEND_METHOD( AppnetServer , setHeader ); 104 | ZEND_METHOD( AppnetServer , httpRedirect ); 105 | ZEND_METHOD( AppnetServer , httpRespCode ); 106 | ZEND_METHOD( AppnetServer , timerAdd ); 107 | ZEND_METHOD( AppnetServer , timerRemove ); 108 | ZEND_METHOD( AppnetServer , setOption ); 109 | ZEND_METHOD( AppnetServer , listenWebsocket ); 110 | ZEND_METHOD( AppnetServer , listenHttp ); 111 | ZEND_METHOD( AppnetServer , getInfo ); 112 | ZEND_METHOD( AppnetServer , setEventCallback ); 113 | ZEND_METHOD( AppnetServer , addEventListener ); 114 | ZEND_METHOD( AppnetServer , addAsynTask ); 115 | ZEND_METHOD( AppnetServer , taskCallback ); 116 | 117 | appnetServer *appnetServInit( char *serv_host , int serv_port ); 118 | void appnetServRun(); 119 | 120 | ZEND_BEGIN_MODULE_GLOBALS( appnet ) 121 | appnetServer *appserv; 122 | ZEND_END_MODULE_GLOBALS( appnet ) 123 | 124 | extern ZEND_DECLARE_MODULE_GLOBALS( appnet ); 125 | /* 126 | #ifdef ZTS 127 | #define APPNET_G(v) TSRMG(appnet_globals_id, zend_appnet_globals *, v) 128 | #else 129 | #define APPNET_G(v) (appnet_globals.v) 130 | #endif 131 | */ 132 | 133 | #define APPNET_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(appnet, v) 134 | #if defined(ZTS) && defined(COMPILE_DL_APPNET) 135 | ZEND_TSRMLS_CACHE_EXTERN(); 136 | #endif 137 | 138 | #endif /* PHP_APPNET_H */ 139 | -------------------------------------------------------------------------------- /src/appnet_epoll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "appnet_event.h" 4 | typedef struct aeApiState 5 | { 6 | int epfd; 7 | struct epoll_event *events; 8 | } aeApiState; 9 | static int aeApiCreate( aeEventLoop *eventLoop ) 10 | { 11 | aeApiState *state = zmalloc( sizeof(aeApiState) ); 12 | if (!state) 13 | { 14 | return -1; 15 | } 16 | state->events = zmalloc( sizeof(struct epoll_event) * eventLoop->setsize ); 17 | if (!state->events) 18 | { 19 | zfree( state ); 20 | return -1; 21 | } 22 | state->epfd = epoll_create( 1024 ); /* 1024 is just a hint for the kernel */ 23 | if (state->epfd == -1) 24 | { 25 | zfree( state->events ); 26 | zfree( state ); 27 | return -1; 28 | } 29 | eventLoop->apidata = state; 30 | return 0; 31 | } 32 | static int aeApiResize( aeEventLoop *eventLoop , int setsize ) 33 | { 34 | aeApiState *state = eventLoop->apidata; 35 | state->events = zrealloc( state->events , sizeof(struct epoll_event) * setsize ); 36 | return 0; 37 | } 38 | static void aeApiFree( aeEventLoop *eventLoop ) 39 | { 40 | aeApiState *state = eventLoop->apidata; 41 | close( state->epfd ); 42 | zfree( state->events ); 43 | zfree( state ); 44 | } 45 | static int aeApiAddEvent( aeEventLoop *eventLoop , int fd , int mask ) 46 | { 47 | aeApiState *state = eventLoop->apidata; 48 | struct epoll_event ee; 49 | 50 | int a = eventLoop->events[fd].mask; 51 | /* If the fd was already monitored for some event, we need a MOD 52 | * operation. Otherwise we need an ADD operation. */ 53 | int op = ( eventLoop->events[fd].mask == AE_NONE ) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; 54 | 55 | ee.events = 0; 56 | mask |= eventLoop->events[fd].mask; /* Merge old events */ 57 | 58 | if (mask & AE_READABLE) 59 | { 60 | ee.events |= EPOLLIN; 61 | } 62 | if (mask & AE_WRITABLE) 63 | { 64 | ee.events |= EPOLLOUT; 65 | } 66 | ee.data.u64 = 0; /* avoid valgrind warning */ 67 | ee.data.fd = fd; 68 | if (epoll_ctl( state->epfd , op , fd , &ee ) == -1) 69 | { 70 | printf( "[epoll_ctr1111 error epfd=%d,op=%d,fd=%d,errno=%d,error=%s]\n" , state->epfd , op , fd , errno , strerror( errno ) ); 71 | return -1; 72 | } 73 | return 0; 74 | } 75 | static void aeApiDelEvent( aeEventLoop *eventLoop , int fd , int delmask ) 76 | { 77 | aeApiState *state = eventLoop->apidata; 78 | struct epoll_event ee; 79 | int mask = eventLoop->events[fd].mask & ( ~delmask ); 80 | ee.events = 0; 81 | if (mask & AE_READABLE) 82 | { 83 | ee.events |= EPOLLIN; 84 | } 85 | if (mask & AE_WRITABLE) 86 | { 87 | ee.events |= EPOLLOUT; 88 | } 89 | ee.data.u64 = 0; /* avoid valgrind warning */ 90 | ee.data.fd = fd; 91 | if (mask != AE_NONE) 92 | { 93 | epoll_ctl( state->epfd , EPOLL_CTL_MOD , fd , &ee ); 94 | } 95 | else 96 | { 97 | /* Note, Kernel < 2.6.9 requires a non null event pointer even for 98 | * EPOLL_CTL_DEL. */ 99 | epoll_ctl( state->epfd , EPOLL_CTL_DEL , fd , &ee ); 100 | } 101 | } 102 | static int aeApiPoll( aeEventLoop *eventLoop , struct timeval *tvp ) 103 | { 104 | aeApiState *state = eventLoop->apidata; 105 | int retval,numevents = 0; 106 | retval = epoll_wait( state->epfd , state->events , eventLoop->setsize , 107 | tvp ? ( tvp->tv_sec * 1000 + tvp->tv_usec / 1000 ) : -1 ); 108 | if (retval > 0) 109 | { 110 | int j; 111 | numevents = retval; 112 | for (j = 0; j < numevents; j++) 113 | { 114 | int mask = 0; 115 | struct epoll_event *e = state->events + j; 116 | if (e->events & EPOLLIN) 117 | { 118 | mask |= AE_READABLE; 119 | } 120 | if (e->events & EPOLLOUT) 121 | { 122 | mask |= AE_WRITABLE; 123 | } 124 | if (e->events & EPOLLERR) 125 | { 126 | mask |= AE_WRITABLE; 127 | } 128 | if (e->events & EPOLLHUP) 129 | { 130 | mask |= AE_WRITABLE; 131 | } 132 | //将触发的事件fd和类型,加入到,触发的事件列表中,这样做是为上层提供统一的激活事件列表。如果仅考虑linux平台,可以直接在里面处理�? 133 | eventLoop->fired[j].fd = e->data.fd; 134 | eventLoop->fired[j].mask = mask; 135 | } 136 | } 137 | return numevents; 138 | } 139 | static char *aeApiName( void ) 140 | { 141 | return "epoll"; 142 | } 143 | -------------------------------------------------------------------------------- /src/appnet_response.c: -------------------------------------------------------------------------------- 1 | #include "appnet_response.h" 2 | #include "appnet_event.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void onRespWritable( aeEventLoop *el , int connfd , void *privdata , int mask ) 9 | { 10 | httpHeader *req_header = (httpHeader *) privdata; 11 | httpResponseStaticProc( req_header ); 12 | aeDeleteFileEvent( el , connfd , AE_WRITABLE ); 13 | } 14 | 15 | void httpResponseStatic( httpHeader *req_header ) 16 | { 17 | int thid = req_header->connfd % servG->reactor_num; 18 | aeEventLoop *el = servG->reactor_threads[thid].reactor.event_loop; 19 | 20 | httpHeader *header = malloc( sizeof(httpHeader) ); 21 | memcpy( header , req_header , sizeof(httpHeader) ); 22 | 23 | if (aeCreateFileEvent( el , req_header->connfd , AE_WRITABLE , onRespWritable , 24 | header ) == -1) 25 | { 26 | 27 | printf( "setPipeWritable_error %s:%d \n" , __FILE__ , __LINE__ ); 28 | return; 29 | } 30 | } 31 | 32 | void httpResponseWrite( int connfd , char *buff , int len ) 33 | { 34 | int nwritten = write( connfd , buff , len ); 35 | if (nwritten <= 0) 36 | { 37 | printf( "I/O error writing to client,connfd=%d,len=%d: %s \n" , connfd , len , 38 | strerror( errno ) ); 39 | return; 40 | } 41 | } 42 | 43 | headerStatus getHttpStatus( int status ) 44 | { 45 | headerStatus header_status; 46 | if (status < http_status_200 || status > http_status_max) 47 | { 48 | return header_status; 49 | } 50 | 51 | int code_i = status % 100; 52 | if (status < http_status_300) 53 | { 54 | return http_status_20x[code_i]; 55 | } 56 | 57 | if (status < http_status_400) 58 | { 59 | return http_status_30x[code_i]; 60 | } 61 | 62 | if (status < http_status_500) 63 | { 64 | return http_status_40x[code_i]; 65 | } 66 | 67 | if (status < http_status_max) 68 | { 69 | return http_status_50x[code_i]; 70 | } 71 | return header_status; 72 | } 73 | 74 | int isDir( char *path ) 75 | { 76 | int s; 77 | struct stat info; 78 | s = stat( path , &info ); 79 | return ( s == 0 && ( info.st_mode & S_IFDIR ) ); 80 | } 81 | 82 | int isFile( char *path ) 83 | { 84 | int s; 85 | struct stat info; 86 | s = stat( path , &info ); 87 | return ( s == 0 && ( info.st_mode & S_IFREG ) ); 88 | } 89 | 90 | int appendHeaderBuffer( headerOut *header_out , char *data , int len ) 91 | { 92 | memcpy( header_out->data + header_out->length , data , len ); 93 | header_out->length += len; 94 | header_out->count += 1; 95 | } 96 | 97 | int appendRespHeader( headerOut *header_out , int line_type , ... ) 98 | { 99 | char line[1024] = 100 | {0}; 101 | int len = 0; 102 | char *arg_string; 103 | int arg_int; 104 | va_list ap; 105 | va_start( ap , line_type ); 106 | 107 | switch (line_type) 108 | { 109 | case HEADER_STATUS: 110 | // error_code, 111 | arg_string = va_arg(ap, char *); 112 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_STATUS] , header_out->req->version , arg_string ); 113 | break; 114 | case HEADER_SERVER: 115 | len = snprintf( line , sizeof( line ) , http_server_full_string ); 116 | break; 117 | case HEADER_CONTENT_TYPE: 118 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_CONTENT_TYPE] , header_out->req->mime_type ); 119 | break; 120 | case HEADER_CONTENT_LENGTH: 121 | // content-length 122 | arg_int = va_arg(ap, int); 123 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_CONTENT_LENGTH] , arg_int ); 124 | break; 125 | case HEADER_LOCATION: 126 | // content-length 127 | arg_string = va_arg(ap, char *); 128 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_LOCATION] , arg_string ); 129 | break; 130 | case HEADER_KEEP_ALIVE: 131 | if (header_out->req->keep_alive == 0) 132 | { 133 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_KEEP_ALIVE] , "close" ); 134 | } 135 | else 136 | { 137 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_KEEP_ALIVE] , "keep-alive" ); 138 | } 139 | break; 140 | case HEADER_END_LINE: 141 | len = snprintf( line , sizeof( line ) , header_formats[HEADER_END_LINE] ); 142 | break; 143 | } 144 | appendHeaderBuffer( header_out , line , strlen( line ) ); 145 | return len; 146 | } 147 | 148 | // this function only process status=200 page, not include resp_error_page 149 | void createCommonHeader( headerOut *header_out , int status_code ) 150 | { 151 | headerStatus error_page = getHttpStatus( status_code ); 152 | // header append 153 | appendRespHeader( header_out , HEADER_STATUS , error_page.status ); 154 | appendRespHeader( header_out , HEADER_SERVER ); 155 | appendRespHeader( header_out , HEADER_CONTENT_TYPE ); 156 | appendRespHeader( header_out , HEADER_KEEP_ALIVE ); 157 | } 158 | 159 | void httpRedirect( httpHeader *req_header , char *uri ) 160 | { 161 | headerOut header_out; 162 | memset( &header_out , 0 , sizeof( header_out ) ); 163 | header_out.req = req_header; 164 | headerStatus error_page = getHttpStatus( 301 ); // header append 165 | 166 | createCommonHeader( &header_out , 301 ); 167 | appendRespHeader( &header_out , HEADER_LOCATION , uri ); 168 | appendRespHeader( &header_out , HEADER_CONTENT_LENGTH , 0 ); 169 | appendRespHeader( &header_out , HEADER_END_LINE ); 170 | 171 | httpResponseWrite( req_header->connfd , header_out.data , header_out.length ); 172 | httpClose( req_header , 0 ); 173 | } 174 | 175 | int pageIsDefined( char *page ) 176 | { 177 | char path[128] = 178 | {0}; 179 | getFilePath( page , path ); 180 | if (isFile( path )) 181 | { 182 | return 1; 183 | } 184 | printf( "%s Is Not Defined Page \n" , path ); 185 | return 0; 186 | } 187 | 188 | // 189 | int respDefinedErrorPage( headerOut *header_out , int err_code ) 190 | { 191 | switch (err_code) 192 | { 193 | case 404: 194 | if (pageIsDefined( servG->http_404_page ) == 0) 195 | return 0; 196 | httpRedirect( header_out->req , servG->http_404_page ); 197 | break; 198 | case 500: 199 | case 501: 200 | case 502: 201 | case 503: 202 | case 504: 203 | case 505: 204 | if (pageIsDefined( servG->http_50x_page ) == 0) 205 | return 0; 206 | httpRedirect( header_out->req , servG->http_50x_page ); 207 | break; 208 | default: 209 | return 0; 210 | } 211 | return 1; 212 | } 213 | 214 | void headerAppendLength( headerOut *header_out , int len ) 215 | { 216 | appendRespHeader( header_out , HEADER_CONTENT_LENGTH , len ); 217 | } 218 | 219 | //如果内容是动态生成的数据流,则需要分段返回给客户端 220 | void appendChunkedHeader( headerOut header_out ) 221 | { 222 | // appendRespHeader( header_out , HEADER_CONTENT_TYPE ); 223 | // appendRespHeader( header_out , HEADER_CONTENT_LENGTH , datalen ); 224 | } 225 | 226 | // 404 227 | void respErrorPage( headerOut *header_out , int status_code ) 228 | { 229 | if (status_code >= 400 && status_code <= 507) 230 | { 231 | int ret = respDefinedErrorPage( header_out , status_code ); 232 | if (ret == AE_TRUE) 233 | { 234 | return; 235 | } 236 | } 237 | 238 | // get header info 239 | headerStatus error_page = getHttpStatus( status_code ); 240 | int datalen = strlen( error_page.data ); 241 | 242 | // header append 243 | createCommonHeader( header_out , status_code ); 244 | headerAppendLength( header_out , datalen ); 245 | appendRespHeader( header_out , HEADER_END_LINE ); 246 | 247 | // send 248 | httpResponseWrite( header_out->req->connfd , header_out->data , 249 | header_out->length ); 250 | if (header_out->req->nobody != AE_TRUE) 251 | { 252 | httpResponseWrite( header_out->req->connfd , error_page.data , datalen ); 253 | } 254 | // nobody强制关闭 255 | httpClose( header_out->req , header_out->req->nobody ); 256 | } 257 | 258 | void httpClose( httpHeader *req_header , int force ) 259 | { 260 | 261 | if (req_header->keep_alive == AE_FALSE || 262 | servG->http_keep_alive == AE_FALSE || force == AE_TRUE) 263 | { 264 | appnetConnection conn = servG->connlist[req_header->connfd]; 265 | freeClient( &conn ); 266 | } 267 | free( req_header ); 268 | } 269 | 270 | void httpResponseStaticProc( httpHeader *req_header ) 271 | { 272 | int len,cllen,ctlen; 273 | char path[1024] = {0}; 274 | headerOut header_out; 275 | memset( &header_out , 0 , sizeof( header_out ) ); 276 | header_out.req = req_header; 277 | 278 | getFilePath( req_header->uri , path ); 279 | struct stat stat_file; 280 | int ret = stat( path , &stat_file ); 281 | 282 | if (ret < 0) 283 | { 284 | respErrorPage( &header_out , 404 ); 285 | return; 286 | } 287 | 288 | createCommonHeader( &header_out , 200 ); 289 | headerAppendLength( &header_out , stat_file.st_size ); 290 | appendRespHeader( &header_out , HEADER_END_LINE ); 291 | 292 | int nwritten = write( req_header->connfd , header_out.data , header_out.length ); 293 | if (nwritten <= 0) 294 | { 295 | printf( "I/O error writing to client connfd=%d,len=%d: %s \n" , 296 | req_header->connfd , header_out.length , strerror( errno ) ); 297 | return; 298 | } 299 | 300 | if (req_header->nobody == AE_TRUE) 301 | { 302 | httpClose( req_header , 1 ); 303 | return; 304 | } 305 | 306 | int fd = open( path , O_RDONLY ); 307 | if (fd < 0) 308 | { 309 | printf( "Open file Error:%s,errno=%d \n" , strerror( errno ) , errno ); 310 | return; 311 | } 312 | 313 | // setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); 314 | off_t offset = 0; 315 | int force_close = 0; 316 | while (offset < stat_file.st_size) 317 | { 318 | int sendn = sendfile( req_header->connfd , fd , &offset , stat_file.st_size - offset ); 319 | if (sendn < 0) 320 | { 321 | //如果socket缓冲区不可用,则挂起等待可用 322 | if (errno == EAGAIN || errno == EINTR) 323 | { 324 | if (anetHandup( req_header->connfd , 5000 , AE_WRITABLE ) < 0) 325 | { 326 | //如果超时,退出 327 | printf( "Sendfile anetHandup timeout.......\n" ); 328 | force_close = 1; 329 | break; 330 | } 331 | else 332 | { 333 | //否则继续发送 334 | continue; 335 | } 336 | } 337 | else 338 | { 339 | break; 340 | } 341 | } 342 | } 343 | close( fd ); 344 | httpClose( req_header , force_close ); 345 | } 346 | 347 | void getFilePath( char *uri , char *path ) 348 | { 349 | 350 | char *pos = strstr( uri , "?" ); 351 | memcpy( path , servG->http_docs_root , strlen( servG->http_docs_root ) ); 352 | 353 | if (pos == NULL) 354 | { 355 | memcpy( path + strlen( servG->http_docs_root ) , uri , strlen( uri ) ); 356 | } 357 | else 358 | { 359 | memcpy( path + strlen( servG->http_docs_root ) , uri , pos - uri ); 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /src/appnet_select.c: -------------------------------------------------------------------------------- 1 | /* Select()-based ae.c module. 2 | * 3 | * Copyright (c) 2009-2012, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | 32 | #include 33 | 34 | typedef struct aeApiState { 35 | fd_set rfds, wfds; 36 | /* We need to have a copy of the fd sets as it's not safe to reuse 37 | * FD sets after select(). */ 38 | fd_set _rfds, _wfds; 39 | } aeApiState; 40 | 41 | static int aeApiCreate(aeEventLoop *eventLoop) { 42 | aeApiState *state = zmalloc(sizeof(aeApiState)); 43 | 44 | if (!state) return -1; 45 | FD_ZERO(&state->rfds); 46 | FD_ZERO(&state->wfds); 47 | eventLoop->apidata = state; 48 | return 0; 49 | } 50 | 51 | static int aeApiResize(aeEventLoop *eventLoop, int setsize) { 52 | /* Just ensure we have enough room in the fd_set type. */ 53 | if (setsize >= FD_SETSIZE) return -1; 54 | return 0; 55 | } 56 | 57 | static void aeApiFree(aeEventLoop *eventLoop) { 58 | zfree(eventLoop->apidata); 59 | } 60 | 61 | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { 62 | aeApiState *state = eventLoop->apidata; 63 | 64 | if (mask & AE_READABLE) FD_SET(fd,&state->rfds); 65 | if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds); 66 | return 0; 67 | } 68 | 69 | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { 70 | aeApiState *state = eventLoop->apidata; 71 | 72 | if (mask & AE_READABLE) FD_CLR(fd,&state->rfds); 73 | if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds); 74 | } 75 | 76 | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { 77 | aeApiState *state = eventLoop->apidata; 78 | int retval, j, numevents = 0; 79 | 80 | memcpy(&state->_rfds,&state->rfds,sizeof(fd_set)); 81 | memcpy(&state->_wfds,&state->wfds,sizeof(fd_set)); 82 | 83 | retval = select(eventLoop->maxfd+1, 84 | &state->_rfds,&state->_wfds,NULL,tvp); 85 | if (retval > 0) { 86 | for (j = 0; j <= eventLoop->maxfd; j++) { 87 | int mask = 0; 88 | aeFileEvent *fe = &eventLoop->events[j]; 89 | 90 | if (fe->mask == AE_NONE) continue; 91 | if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds)) 92 | mask |= AE_READABLE; 93 | if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds)) 94 | mask |= AE_WRITABLE; 95 | eventLoop->fired[numevents].fd = j; 96 | eventLoop->fired[numevents].mask = mask; 97 | numevents++; 98 | } 99 | } 100 | return numevents; 101 | } 102 | 103 | static char *aeApiName(void) { 104 | return "select"; 105 | } 106 | -------------------------------------------------------------------------------- /src/appnet_websocket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * https://github.com/m8rge/cwebsocket/blob/master/lib/websocket.c 3 | http://gtsss.marketminer.org/Doxygen/TradingSystem/docs/code/lib_2websocket_8c_source.html 4 | */ 5 | #include "appnet_websocket.h" 6 | #include 7 | static char rn[] = "\r\n"; 8 | 9 | void nullHandshake( handshake *hs ) 10 | { 11 | hs->frame_type = WS_EMPTY_FRAME; 12 | } 13 | 14 | void freeHandshake( handshake *hs ) 15 | { 16 | if (hs->host) 17 | { 18 | free( hs->host ); 19 | } 20 | if (hs->origin) 21 | { 22 | free( hs->origin ); 23 | } 24 | if (hs->resource) 25 | { 26 | free( hs->resource ); 27 | } 28 | if (hs->key) 29 | { 30 | free( hs->key ); 31 | } 32 | nullHandshake( hs ); 33 | } 34 | 35 | static char *getUptoLinefeed( const char *startFrom ) 36 | { 37 | char *writeTo = NULL; 38 | uint8_t newLength = strstr_P( startFrom , rn ) - startFrom; 39 | assert( newLength ); 40 | writeTo = (char *) malloc( newLength + 1 ); //+1 for '\x00' 41 | assert( writeTo ); 42 | memcpy( writeTo , startFrom , newLength ); 43 | writeTo[newLength] = 0; 44 | return writeTo; 45 | } 46 | 47 | enum wsFrameType wsParseHandshake( const uint8_t *inputFrame , 48 | size_t inputLength , handshake *hs ) 49 | { 50 | } 51 | 52 | void wsGetHandshakeAnswer( const handshake *hs , uint8_t *outFrame , 53 | size_t *outLength , char *ver ) 54 | { 55 | assert( outFrame && *outLength ); 56 | assert( hs->frame_type == WS_OPENING_FRAME ); 57 | assert( hs && hs->key ); 58 | 59 | char responseKey[128] = 60 | {0}; 61 | uint8_t length = strlen( hs->key ) + strlen_P( secret ); 62 | memcpy( responseKey , hs->key , strlen( hs->key ) ); 63 | memcpy_P( &( responseKey[strlen( hs->key )] ) , secret , strlen_P( secret ) ); 64 | unsigned char shaHash[SHA1_DIGEST_LENGTH]; 65 | memset( shaHash , 0 , sizeof( shaHash ) ); 66 | sha1( responseKey , length , shaHash ); 67 | 68 | size_t base64Length = 69 | base64_encode( responseKey , length , shaHash , SHA1_DIGEST_LENGTH ); 70 | 71 | responseKey[base64Length] = '\0'; 72 | int written = sprintf_P( 73 | (char *) outFrame , PSTR( "HTTP/1.1 101 Switching Protocols\r\n" 74 | "%s%s\r\n" 75 | "%s%s\r\n" 76 | "Sec-WebSocket-Version: %s\r\n" 77 | "Sec-WebSocket-Accept: %s\r\n\r\n" ) , 78 | upgradeField , websocket , connectionField , upgrade2 , ver , responseKey ); 79 | 80 | // if assert fail, that means, that we corrupt memory 81 | assert( written <= *outLength ); 82 | *outLength = written; 83 | } 84 | 85 | void wsMakeFrame( const uint8_t *data , size_t dataLength , uint8_t *outFrame , 86 | size_t *outLength , enum wsFrameType frame_type ) 87 | { 88 | 89 | assert( outFrame && *outLength ); 90 | assert( frame_type < 0x10 ); 91 | 92 | if (dataLength > 0) 93 | { 94 | assert( data ); 95 | } 96 | 97 | outFrame[0] = 0x80 | frame_type; 98 | 99 | if (dataLength <= 125) 100 | { 101 | outFrame[1] = dataLength; 102 | *outLength = 2; 103 | 104 | } 105 | else if (dataLength <= 0xFFFF) 106 | { 107 | 108 | outFrame[1] = 126; 109 | uint16_t payloadLength16b = htons( dataLength ); 110 | memcpy( &outFrame[2] , &payloadLength16b , 2 ); 111 | *outLength = 4; 112 | } 113 | else 114 | { 115 | printf( "Websocket wsMakeFrame Large Data dataLength = %d \n" , dataLength ); 116 | assert( dataLength <= 0xFFFF ); 117 | // implementation for 64bit systems 118 | outFrame[1] = 127; 119 | dataLength = htonll(dataLength); 120 | memcpy(&outFrame[2], &dataLength, 8); 121 | outLength = 10; 122 | } 123 | 124 | memcpy( &outFrame[*outLength] , data , dataLength ); 125 | *outLength += dataLength; 126 | } 127 | 128 | static size_t getPayloadLength( const uint8_t *inputFrame , size_t inputLength , 129 | uint8_t *payloadFieldExtraBytes , 130 | enum wsFrameType *frame_type ) 131 | { 132 | 133 | size_t payloadLength = inputFrame[1] & 0x7F; // 127 134 | *payloadFieldExtraBytes = 0; 135 | 136 | if (( payloadLength == 0x7E && inputLength < 4 ) || 137 | ( payloadLength == 0x7F && inputLength < 10 )) 138 | { 139 | *frame_type = WS_INCOMPLETE_FRAME; 140 | return 0; 141 | } 142 | 143 | if (payloadLength == 0x7F && ( inputFrame[3] & 0x80 ) != 0x0) 144 | { 145 | *frame_type = WS_ERROR_FRAME; 146 | return 0; 147 | } 148 | 149 | if (payloadLength == 0x7E) // 126 150 | { 151 | uint16_t payloadLength16b = 0; 152 | *payloadFieldExtraBytes = 2; 153 | memcpy( &payloadLength16b , &inputFrame[2] , *payloadFieldExtraBytes ); 154 | payloadLength = ntohs( payloadLength16b ); 155 | } 156 | else if (payloadLength == 0x7F) // 127 157 | { 158 | printf( "Websocket getPayloadLength Large Data payloadLength=%d \n" , payloadLength ); 159 | // implementation for 64bit systems 160 | uint64_t payloadLength64b = 0; 161 | *payloadFieldExtraBytes = 8; 162 | memcpy(&payloadLength64b, &inputFrame[2], *payloadFieldExtraBytes); 163 | if (payloadLength64b > SIZE_MAX) 164 | { 165 | *frame_type = WS_ERROR_FRAME; 166 | return 0; 167 | } 168 | payloadLength = (size_t)ntohll(payloadLength64b); 169 | } 170 | return payloadLength; 171 | } 172 | 173 | enum wsFrameType wsParseInputFrame( uint8_t *inputFrame , size_t inputLength , 174 | uint8_t **dataPtr , size_t *dataLength ) 175 | { 176 | assert( inputFrame && inputLength ); 177 | 178 | if (inputLength < 2) 179 | { 180 | return WS_INCOMPLETE_FRAME; 181 | } 182 | 183 | if (( inputFrame[0] & 0x70 ) != 0x0) // checks extensions off 184 | { 185 | return WS_ERROR_FRAME; 186 | } 187 | 188 | if (( inputFrame[0] & 0x80 ) != 0x80) // we haven't continuation frames support 189 | { 190 | return WS_ERROR_FRAME; // so, fin flag must be set 191 | } 192 | 193 | if (( inputFrame[1] & 0x80 ) != 0x80) // checks masking bit 194 | { 195 | return WS_ERROR_FRAME; 196 | } 197 | 198 | uint8_t opcode = inputFrame[0] & 0x0F; 199 | if (opcode == WS_TEXT_FRAME || opcode == WS_BINARY_FRAME || 200 | opcode == WS_CLOSING_FRAME || opcode == WS_PING_FRAME || 201 | opcode == WS_PONG_FRAME) 202 | { 203 | 204 | enum wsFrameType frame_type = opcode; 205 | uint8_t payloadFieldExtraBytes = 0; 206 | 207 | size_t payloadLength = getPayloadLength( 208 | inputFrame , inputLength , &payloadFieldExtraBytes , &frame_type ); 209 | 210 | if (payloadLength > 0) 211 | { 212 | if (payloadLength + 6 + payloadFieldExtraBytes > 213 | inputLength) // 4-maskingKey, 2-header 214 | { 215 | return WS_INCOMPLETE_FRAME; 216 | } 217 | 218 | uint8_t *maskingKey = &inputFrame[2 + payloadFieldExtraBytes]; 219 | if (payloadLength != inputLength - 6 - payloadFieldExtraBytes) 220 | { 221 | printf( "Error wsParseInputFrame payloadLength " 222 | "error,payloadLength=%d,inputLength=%d \n" , 223 | payloadLength , inputLength - 6 - payloadFieldExtraBytes ); 224 | return WS_ERROR_FRAME; 225 | } 226 | 227 | // assert(payloadLength == inputLength - 6 - payloadFieldExtraBytes); 228 | *dataPtr = &inputFrame[2 + payloadFieldExtraBytes + 4]; 229 | *dataLength = payloadLength; 230 | 231 | size_t i; 232 | for (i = 0; i < *dataLength; i++) 233 | { 234 | ( *dataPtr )[i] = ( *dataPtr )[i] ^ maskingKey[i % 4]; 235 | } 236 | } 237 | return frame_type; 238 | } 239 | return WS_ERROR_FRAME; 240 | } 241 | -------------------------------------------------------------------------------- /src/base64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "base64.h" 4 | static const signed char base64_decode_chars[] = 5 | { 6 | -1,-1,-1,-1,-1,-1,-1,-1, 7 | -1,-1,-1,-1,-1,-1,-1,-1, 8 | -1,-1,-1,-1,-1,-1,-1,-1, 9 | -1,-1,-1,-1,-1,-1,-1,-1, 10 | -1,-1,-1,-1,-1,-1,-1,-1, 11 | -1,-1,-1,62,-1,-1,-1,63, 12 | 52,53,54,55,56,57,58,59, 13 | 60,61,-1,-1,-1,0,-1,-1, 14 | -1,0,1,2,3,4,5,6, 15 | 7,8,9,10,11,12,13,14, 16 | 15,16,17,18,19,20,21,22, 17 | 23,24,25,-1,-1,-1,-1,-1, 18 | -1,26,27,28,29,30,31,32, 19 | 33,34,35,36,37,38,39,40, 20 | 41,42,43,44,45,46,47,48, 21 | 49,50,51,-1,-1,-1,-1,-1, 22 | -1,-1,-1,-1,-1,-1,-1,-1, 23 | -1,-1,-1,-1,-1,-1,-1,-1, 24 | -1,-1,-1,-1,-1,-1,-1,-1, 25 | -1,-1,-1,-1,-1,-1,-1,-1, 26 | -1,-1,-1,-1,-1,-1,-1,-1, 27 | -1,-1,-1,-1,-1,-1,-1,-1, 28 | -1,-1,-1,-1,-1,-1,-1,-1, 29 | -1,-1,-1,-1,-1,-1,-1,-1, 30 | -1,-1,-1,-1,-1,-1,-1,-1, 31 | -1,-1,-1,-1,-1,-1,-1,-1, 32 | -1,-1,-1,-1,-1,-1,-1,-1, 33 | -1,-1,-1,-1,-1,-1,-1,-1, 34 | -1,-1,-1,-1,-1,-1,-1,-1, 35 | -1,-1,-1,-1,-1,-1,-1,-1, 36 | -1,-1,-1,-1,-1,-1,-1,-1, 37 | -1,-1,-1,-1,-1,-1,-1,-1 38 | }; 39 | size_t base64_encode( char *buf , size_t nbuf , const unsigned char *p , size_t n ) 40 | { 41 | const char t[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 42 | size_t i,m; 43 | m = ( n + 2 ) / 3 * 4; 44 | unsigned x; 45 | if (nbuf >= m) 46 | { 47 | for (i = 0; i < n; ++i) 48 | { 49 | x = p[i] << 0x10; 50 | x |= ( ++i < n ? p[i] : 0 ) << 0x08; 51 | x |= ( ++i < n ? p[i] : 0 ) << 0x00; 52 | *buf++ = t[x >> 3 * 6 & 0x3f]; 53 | *buf++ = t[x >> 2 * 6 & 0x3f]; 54 | *buf++ = ( ( ( n - 0 - i ) >> 31 ) & '=' ) | 55 | ( ~( ( n - 0 - i ) >> 31 ) & t[x >> 1 * 6 & 0x3f] ); 56 | *buf++ = ( ( ( n - 1 - i ) >> 31 ) & '=' ) | 57 | ( ~( ( n - 1 - i ) >> 31 ) & t[x >> 0 * 6 & 0x3f] ); 58 | } 59 | } 60 | return m; 61 | } 62 | int base64_decode( unsigned char **dst , size_t *dstsiz , const unsigned char *src ) 63 | { 64 | union 65 | { 66 | unsigned long x; 67 | char c[4]; 68 | } base64; 69 | unsigned char *pdst; 70 | int i,j = 0; 71 | size_t srcsiz = strlen( (const char *) src ); 72 | if (( srcsiz % 4 ) != 0) 73 | { 74 | return -1; 75 | } 76 | base64.x = 0UL; 77 | *dst = (unsigned char *) malloc( srcsiz ); 78 | if (!*dst) 79 | { 80 | return -1; 81 | } 82 | pdst = *dst; 83 | *dstsiz = 0; 84 | for (; srcsiz > 0; src += 4, srcsiz -= 4) 85 | { 86 | for (i = 0; i < 4; i++) 87 | { 88 | if (base64_decode_chars[src[i]] == -1) 89 | { 90 | return -1; 91 | } 92 | base64.x = base64.x << 6 | base64_decode_chars[src[i]]; 93 | j += ( src[i] == '=' ); 94 | } 95 | for (i = 3; i > j; i--, ( *dstsiz )++) 96 | { 97 | *pdst++ = base64.c[i - 1]; 98 | } 99 | } 100 | *pdst = '\0'; 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/rbtree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rbtree.h" 3 | 4 | static inline void rbtree_left_rotate( rbtree_node_t **root , 5 | rbtree_node_t *sentinel , rbtree_node_t *node ); 6 | static inline void rbtree_right_rotate( rbtree_node_t **root , 7 | rbtree_node_t *sentinel , rbtree_node_t *node ); 8 | 9 | void rbtree_insert( rbtree_t *tree , rbtree_node_t *node ) 10 | { 11 | rbtree_node_t **root,*temp,*sentinel; 12 | root = (rbtree_node_t **) &tree->root; 13 | sentinel = tree->sentinel; 14 | 15 | if (*root == sentinel) 16 | { 17 | node->parent = NULL; 18 | node->left = sentinel; 19 | node->right = sentinel; 20 | rbt_black( node ); 21 | *root = node; 22 | return; 23 | } 24 | 25 | tree->insert( *root , node , sentinel ); 26 | while (node != *root && rbt_is_red(node->parent) ) 27 | { 28 | 29 | if (node->parent == node->parent->parent->left) 30 | { 31 | temp = node->parent->parent->right; 32 | 33 | if (rbt_is_red(temp) ) 34 | { 35 | rbt_black( node->parent ); 36 | rbt_black( temp ); 37 | rbt_red( node->parent->parent ); 38 | node = node->parent->parent; 39 | 40 | } 41 | else 42 | { 43 | if (node == node->parent->right) 44 | { 45 | node = node->parent; 46 | rbtree_left_rotate( root , sentinel , node ); 47 | } 48 | 49 | rbt_black( node->parent ); 50 | rbt_red( node->parent->parent ); 51 | rbtree_right_rotate( root , sentinel , node->parent->parent ); 52 | } 53 | 54 | } 55 | else 56 | { 57 | temp = node->parent->parent->left; 58 | 59 | if (rbt_is_red(temp) ) 60 | { 61 | rbt_black( node->parent ); 62 | rbt_black( temp ); 63 | rbt_red( node->parent->parent ); 64 | node = node->parent->parent; 65 | 66 | } 67 | else 68 | { 69 | if (node == node->parent->left) 70 | { 71 | node = node->parent; 72 | rbtree_right_rotate( root , sentinel , node ); 73 | } 74 | 75 | rbt_black( node->parent ); 76 | rbt_red( node->parent->parent ); 77 | rbtree_left_rotate( root , sentinel , node->parent->parent ); 78 | } 79 | } 80 | } 81 | 82 | rbt_black( *root ); 83 | } 84 | 85 | void 86 | rbtree_insert_value( rbtree_node_t *temp , rbtree_node_t *node , 87 | rbtree_node_t *sentinel ) 88 | { 89 | rbtree_node_t **p; 90 | 91 | for (;;) 92 | { 93 | 94 | p = ( node->key < temp->key ) ? &temp->left : &temp->right; 95 | 96 | if (*p == sentinel) 97 | { 98 | break; 99 | } 100 | 101 | temp = *p; 102 | } 103 | 104 | *p = node; 105 | node->parent = temp; 106 | node->left = sentinel; 107 | node->right = sentinel; 108 | rbt_red( node ); 109 | } 110 | 111 | void rbtree_insert_timer_value( rbtree_node_t *temp , rbtree_node_t *node , 112 | rbtree_node_t *sentinel ) 113 | { 114 | rbtree_node_t **p; 115 | 116 | for (;;) 117 | { 118 | 119 | /* 120 | * Timer values 121 | * 1) are spread in small range, usually several minutes, 122 | * 2) and overflow each 49 days, if milliseconds are stored in 32 bits. 123 | * The comparison takes into account that overflow. 124 | */ 125 | 126 | /* node->key < temp->key */ 127 | 128 | p = ( (rbtree_key_int_t) ( node->key - temp->key ) < 0 ) 129 | ? &temp->left : &temp->right; 130 | 131 | if (*p == sentinel) 132 | { 133 | break; 134 | } 135 | 136 | temp = *p; 137 | } 138 | 139 | *p = node; 140 | node->parent = temp; 141 | node->left = sentinel; 142 | node->right = sentinel; 143 | rbt_red( node ); 144 | } 145 | 146 | void 147 | rbtree_delete( rbtree_t *tree , rbtree_node_t *node ) 148 | { 149 | uint_t red; 150 | rbtree_node_t **root,*sentinel,*subst,*temp,*w; 151 | 152 | /* a binary tree delete */ 153 | 154 | root = (rbtree_node_t **) &tree->root; 155 | sentinel = tree->sentinel; 156 | 157 | if (node->left == sentinel) 158 | { 159 | temp = node->right; 160 | subst = node; 161 | 162 | } 163 | else if (node->right == sentinel) 164 | { 165 | temp = node->left; 166 | subst = node; 167 | 168 | } 169 | else 170 | { 171 | subst = rbtree_min( node->right , sentinel ); 172 | 173 | if (subst->left != sentinel) 174 | { 175 | temp = subst->left; 176 | } 177 | else 178 | { 179 | temp = subst->right; 180 | } 181 | } 182 | 183 | if (subst == *root) 184 | { 185 | *root = temp; 186 | rbt_black( temp ); 187 | 188 | /* DEBUG stuff */ 189 | node->left = NULL; 190 | node->right = NULL; 191 | node->parent = NULL; 192 | node->key = 0; 193 | 194 | return; 195 | } 196 | 197 | red = rbt_is_red(subst); 198 | 199 | if (subst == subst->parent->left) 200 | { 201 | subst->parent->left = temp; 202 | 203 | } 204 | else 205 | { 206 | subst->parent->right = temp; 207 | } 208 | 209 | if (subst == node) 210 | { 211 | 212 | temp->parent = subst->parent; 213 | 214 | } 215 | else 216 | { 217 | 218 | if (subst->parent == node) 219 | { 220 | temp->parent = subst; 221 | 222 | } 223 | else 224 | { 225 | temp->parent = subst->parent; 226 | } 227 | 228 | subst->left = node->left; 229 | subst->right = node->right; 230 | subst->parent = node->parent; 231 | rbt_copy_color( subst , node ); 232 | 233 | if (node == *root) 234 | { 235 | *root = subst; 236 | 237 | } 238 | else 239 | { 240 | if (node == node->parent->left) 241 | { 242 | node->parent->left = subst; 243 | } 244 | else 245 | { 246 | node->parent->right = subst; 247 | } 248 | } 249 | 250 | if (subst->left != sentinel) 251 | { 252 | subst->left->parent = subst; 253 | } 254 | 255 | if (subst->right != sentinel) 256 | { 257 | subst->right->parent = subst; 258 | } 259 | } 260 | 261 | /* DEBUG stuff */ 262 | node->left = NULL; 263 | node->right = NULL; 264 | node->parent = NULL; 265 | node->key = 0; 266 | 267 | if (red) 268 | { 269 | return; 270 | } 271 | 272 | /* a delete fixup */ 273 | 274 | while (temp != *root && rbt_is_black(temp) ) 275 | { 276 | 277 | if (temp == temp->parent->left) 278 | { 279 | w = temp->parent->right; 280 | 281 | if (rbt_is_red(w) ) 282 | { 283 | rbt_black( w ); 284 | rbt_red( temp->parent ); 285 | rbtree_left_rotate( root , sentinel , temp->parent ); 286 | w = temp->parent->right; 287 | } 288 | 289 | if (rbt_is_black(w->left) && rbt_is_black(w->right) ) 290 | { 291 | rbt_red( w ); 292 | temp = temp->parent; 293 | 294 | } 295 | else 296 | { 297 | if (rbt_is_black(w->right) ) 298 | { 299 | rbt_black( w->left ); 300 | rbt_red( w ); 301 | rbtree_right_rotate( root , sentinel , w ); 302 | w = temp->parent->right; 303 | } 304 | 305 | rbt_copy_color( w , temp->parent ); 306 | rbt_black( temp->parent ); 307 | rbt_black( w->right ); 308 | rbtree_left_rotate( root , sentinel , temp->parent ); 309 | temp = *root; 310 | } 311 | 312 | } 313 | else 314 | { 315 | w = temp->parent->left; 316 | 317 | if (rbt_is_red(w) ) 318 | { 319 | rbt_black( w ); 320 | rbt_red( temp->parent ); 321 | rbtree_right_rotate( root , sentinel , temp->parent ); 322 | w = temp->parent->left; 323 | } 324 | 325 | if (rbt_is_black(w->left) && rbt_is_black(w->right) ) 326 | { 327 | rbt_red( w ); 328 | temp = temp->parent; 329 | 330 | } 331 | else 332 | { 333 | if (rbt_is_black(w->left) ) 334 | { 335 | rbt_black( w->right ); 336 | rbt_red( w ); 337 | rbtree_left_rotate( root , sentinel , w ); 338 | w = temp->parent->left; 339 | } 340 | 341 | rbt_copy_color( w , temp->parent ); 342 | rbt_black( temp->parent ); 343 | rbt_black( w->left ); 344 | rbtree_right_rotate( root , sentinel , temp->parent ); 345 | temp = *root; 346 | } 347 | } 348 | } 349 | 350 | rbt_black( temp ); 351 | } 352 | 353 | static inline void rbtree_left_rotate( rbtree_node_t **root , rbtree_node_t *sentinel , rbtree_node_t *node ) 354 | { 355 | rbtree_node_t *temp; 356 | 357 | temp = node->right; 358 | node->right = temp->left; 359 | 360 | if (temp->left != sentinel) 361 | { 362 | temp->left->parent = node; 363 | } 364 | 365 | temp->parent = node->parent; 366 | 367 | if (node == *root) 368 | { 369 | *root = temp; 370 | 371 | } 372 | else if (node == node->parent->left) 373 | { 374 | node->parent->left = temp; 375 | 376 | } 377 | else 378 | { 379 | node->parent->right = temp; 380 | } 381 | 382 | temp->left = node; 383 | node->parent = temp; 384 | } 385 | 386 | static inline void rbtree_right_rotate( rbtree_node_t **root , rbtree_node_t *sentinel , rbtree_node_t *node ) 387 | { 388 | rbtree_node_t *temp; 389 | 390 | temp = node->left; 391 | node->left = temp->right; 392 | 393 | if (temp->right != sentinel) 394 | { 395 | temp->right->parent = node; 396 | } 397 | 398 | temp->parent = node->parent; 399 | 400 | if (node == *root) 401 | { 402 | *root = temp; 403 | 404 | } 405 | else if (node == node->parent->right) 406 | { 407 | node->parent->right = temp; 408 | 409 | } 410 | else 411 | { 412 | node->parent->left = temp; 413 | } 414 | 415 | temp->right = node; 416 | node->parent = temp; 417 | } 418 | 419 | -------------------------------------------------------------------------------- /src/ring_buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../include/ring_buffer.h" 6 | #include "../include/share_memory.h" 7 | #include "../include/zmalloc.h" 8 | #define check(A, M, ...) if(!(A)) {\ 9 | printf(M, ##__VA_ARGS__); errno=0; goto error; } 10 | ringBuffer *ringBuffer_create( int length , int use_shm ) 11 | { 12 | ringBuffer *buffer; 13 | if (use_shm) 14 | { 15 | buffer = shm_calloc( 1 , sizeof(ringBuffer) ); 16 | } 17 | else 18 | { 19 | buffer = zcalloc( sizeof(ringBuffer) ); 20 | } 21 | if (buffer == NULL) 22 | { 23 | printf( "ringBuffer_create error \n" ); 24 | return NULL; 25 | } 26 | buffer->length = length + 1; 27 | buffer->start = 0; 28 | buffer->end = 0; 29 | buffer->use_shm = ( use_shm > 0 ) ? 1 : 0; 30 | if (buffer->use_shm == 1) 31 | { 32 | buffer->buffer = shm_calloc( buffer->length , 1 ); 33 | } 34 | else 35 | { 36 | buffer->buffer = zcalloc( buffer->length ); 37 | } 38 | return buffer; 39 | } 40 | void ringBuffer_destroy( ringBuffer * buffer ) 41 | { 42 | if (buffer) 43 | { 44 | if (buffer->use_shm) 45 | { 46 | shm_free( buffer->buffer , 1 ); 47 | shm_free( buffer , 1 ); 48 | } 49 | else 50 | { 51 | zfree( buffer->buffer ); 52 | zfree( buffer ); 53 | } 54 | } 55 | } 56 | int ringBuffer_write( ringBuffer * buffer , char *data , int length ) 57 | { 58 | if (ringBuffer_available_data(buffer) == 0) 59 | { 60 | buffer->start = buffer->end = 0; 61 | } 62 | check( length <= ringBuffer_available_space(buffer) , 63 | "Not enough space: %d request, %d available" , 64 | ringBuffer_available_data(buffer) , length ); 65 | void *result = memcpy( ringBuffer_ends_at(buffer) , data , length ); 66 | check( result != NULL , "Failed to write data into buffer." ); 67 | ringBuffer_commit_write( buffer , length ); 68 | return length; 69 | error: 70 | return -1; 71 | } 72 | int ringBuffer_read( ringBuffer * buffer , char *target , int amount ) 73 | { 74 | check( amount <= ringBuffer_available_data(buffer) , 75 | "Not enough in the buffer: has %d, needs %d" , 76 | ringBuffer_available_data(buffer) , amount ); 77 | void *result = memcpy( target , ringBuffer_starts_at(buffer) , amount ); 78 | check( result != NULL , "Failed to write buffer into data." ); 79 | ringBuffer_commit_read( buffer , amount ); 80 | if (buffer->end == buffer->start) 81 | { 82 | buffer->start = buffer->end = 0; 83 | } 84 | return amount; 85 | error: 86 | return -1; 87 | } 88 | -------------------------------------------------------------------------------- /src/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.c 3 | * 4 | * Originally witten by Steve Reid 5 | * 6 | * Modified by Aaron D. Gifford 7 | * 8 | * NO COPYRIGHT - THIS IS 100% IN THE PUBLIC DOMAIN 9 | * 10 | * The original unmodified version is available at: 11 | * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | #include 26 | #include 27 | #include "sha1.h" 28 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 29 | /* blk0() and blk() perform the initial expand. */ 30 | /* I got the idea of expanding during the round function from SSLeay */ 31 | #ifdef LITTLE_ENDIAN 32 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&(sha1_quadbyte)0xFF00FF00) \ 33 | |(rol(block->l[i],8)&(sha1_quadbyte)0x00FF00FF)) 34 | #else 35 | #define blk0(i) block->l[i] 36 | #endif 37 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 38 | ^block->l[(i+2)&15]^block->l[i&15],1)) 39 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 40 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 41 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 42 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 43 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 44 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 45 | typedef union _BYTE64QUAD16 46 | { 47 | sha1_byte c[64]; 48 | sha1_quadbyte l[16]; 49 | } BYTE64QUAD16; 50 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 51 | void sha1Transform( sha1_quadbyte state[5] , sha1_byte buffer[64] ) 52 | { 53 | sha1_quadbyte a,b,c,d,e; 54 | BYTE64QUAD16 src; 55 | BYTE64QUAD16 *block; 56 | /* slow but cast-align */ 57 | memcpy( src.c , buffer , sizeof(sha1_byte) * 64 ); 58 | block = &src; 59 | /* Copy context->state[] to working vars */ 60 | a = state[0]; 61 | b = state[1]; 62 | c = state[2]; 63 | d = state[3]; 64 | e = state[4]; 65 | /* 4 rounds of 20 operations each. Loop unrolled. */ 66 | R0( a , b , c , d , e , 0 ); 67 | R0( e , a , b , c , d , 1 ); 68 | R0( d , e , a , b , c , 2 ); 69 | R0( c , d , e , a , b , 3 ); 70 | R0( b , c , d , e , a , 4 ); 71 | R0( a , b , c , d , e , 5 ); 72 | R0( e , a , b , c , d , 6 ); 73 | R0( d , e , a , b , c , 7 ); 74 | R0( c , d , e , a , b , 8 ); 75 | R0( b , c , d , e , a , 9 ); 76 | R0( a , b , c , d , e , 10 ); 77 | R0( e , a , b , c , d , 11 ); 78 | R0( d , e , a , b , c , 12 ); 79 | R0( c , d , e , a , b , 13 ); 80 | R0( b , c , d , e , a , 14 ); 81 | R0( a , b , c , d , e , 15 ); 82 | R1( e , a , b , c , d , 16 ); 83 | R1( d , e , a , b , c , 17 ); 84 | R1( c , d , e , a , b , 18 ); 85 | R1( b , c , d , e , a , 19 ); 86 | R2( a , b , c , d , e , 20 ); 87 | R2( e , a , b , c , d , 21 ); 88 | R2( d , e , a , b , c , 22 ); 89 | R2( c , d , e , a , b , 23 ); 90 | R2( b , c , d , e , a , 24 ); 91 | R2( a , b , c , d , e , 25 ); 92 | R2( e , a , b , c , d , 26 ); 93 | R2( d , e , a , b , c , 27 ); 94 | R2( c , d , e , a , b , 28 ); 95 | R2( b , c , d , e , a , 29 ); 96 | R2( a , b , c , d , e , 30 ); 97 | R2( e , a , b , c , d , 31 ); 98 | R2( d , e , a , b , c , 32 ); 99 | R2( c , d , e , a , b , 33 ); 100 | R2( b , c , d , e , a , 34 ); 101 | R2( a , b , c , d , e , 35 ); 102 | R2( e , a , b , c , d , 36 ); 103 | R2( d , e , a , b , c , 37 ); 104 | R2( c , d , e , a , b , 38 ); 105 | R2( b , c , d , e , a , 39 ); 106 | R3( a , b , c , d , e , 40 ); 107 | R3( e , a , b , c , d , 41 ); 108 | R3( d , e , a , b , c , 42 ); 109 | R3( c , d , e , a , b , 43 ); 110 | R3( b , c , d , e , a , 44 ); 111 | R3( a , b , c , d , e , 45 ); 112 | R3( e , a , b , c , d , 46 ); 113 | R3( d , e , a , b , c , 47 ); 114 | R3( c , d , e , a , b , 48 ); 115 | R3( b , c , d , e , a , 49 ); 116 | R3( a , b , c , d , e , 50 ); 117 | R3( e , a , b , c , d , 51 ); 118 | R3( d , e , a , b , c , 52 ); 119 | R3( c , d , e , a , b , 53 ); 120 | R3( b , c , d , e , a , 54 ); 121 | R3( a , b , c , d , e , 55 ); 122 | R3( e , a , b , c , d , 56 ); 123 | R3( d , e , a , b , c , 57 ); 124 | R3( c , d , e , a , b , 58 ); 125 | R3( b , c , d , e , a , 59 ); 126 | R4( a , b , c , d , e , 60 ); 127 | R4( e , a , b , c , d , 61 ); 128 | R4( d , e , a , b , c , 62 ); 129 | R4( c , d , e , a , b , 63 ); 130 | R4( b , c , d , e , a , 64 ); 131 | R4( a , b , c , d , e , 65 ); 132 | R4( e , a , b , c , d , 66 ); 133 | R4( d , e , a , b , c , 67 ); 134 | R4( c , d , e , a , b , 68 ); 135 | R4( b , c , d , e , a , 69 ); 136 | R4( a , b , c , d , e , 70 ); 137 | R4( e , a , b , c , d , 71 ); 138 | R4( d , e , a , b , c , 72 ); 139 | R4( c , d , e , a , b , 73 ); 140 | R4( b , c , d , e , a , 74 ); 141 | R4( a , b , c , d , e , 75 ); 142 | R4( e , a , b , c , d , 76 ); 143 | R4( d , e , a , b , c , 77 ); 144 | R4( c , d , e , a , b , 78 ); 145 | R4( b , c , d , e , a , 79 ); 146 | /* Add the working vars back into context.state[] */ 147 | state[0] += a; 148 | state[1] += b; 149 | state[2] += c; 150 | state[3] += d; 151 | state[4] += e; 152 | /* Wipe variables */ 153 | a = b = c = d = e = 0; 154 | } 155 | /* SHA1_Init - Initialize new context */ 156 | void sha1Init( SHA_CTX* context ) 157 | { 158 | /* SHA1 initialization constants */ 159 | context->state[0] = 0x67452301; 160 | context->state[1] = 0xEFCDAB89; 161 | context->state[2] = 0x98BADCFE; 162 | context->state[3] = 0x10325476; 163 | context->state[4] = 0xC3D2E1F0; 164 | context->count[0] = context->count[1] = 0; 165 | } 166 | /* Run your data through this. */ 167 | void sha1Update( SHA_CTX *context , sha1_byte *data , unsigned int len ) 168 | { 169 | unsigned int i,j; 170 | j = ( context->count[0] >> 3 ) & 63; 171 | if (( context->count[0] += len << 3 ) < ( len << 3 )) 172 | { 173 | context->count[1]++; 174 | } 175 | context->count[1] += ( len >> 29 ); 176 | if (( j + len ) > 63) 177 | { 178 | memcpy( &context->buffer[j] , data , ( i = 64 - j ) ); 179 | sha1Transform( context->state , context->buffer ); 180 | for (; i + 63 < len; i += 64) 181 | { 182 | sha1Transform( context->state , &data[i] ); 183 | } 184 | j = 0; 185 | } 186 | else 187 | { 188 | i = 0; 189 | } 190 | memcpy( &context->buffer[j] , &data[i] , len - i ); 191 | } 192 | /* Add padding and return the message digest. */ 193 | void sha1Final( sha1_byte digest[SHA1_DIGEST_LENGTH] , SHA_CTX *context ) 194 | { 195 | sha1_quadbyte i,j; 196 | sha1_byte finalcount[8]; 197 | for (i = 0; i < 8; i++) 198 | { 199 | finalcount[i] = (sha1_byte) ( ( context->count[( i >= 4 ? 0 : 1 )] 200 | >> ( ( 3 - ( i & 3 ) ) * 8 ) ) & 255 ); /* Endian independent */ 201 | } 202 | sha1Update( context , (sha1_byte *) "\200" , 1 ); 203 | while (( context->count[0] & 504 ) != 448) 204 | { 205 | sha1Update( context , (sha1_byte *) "\0" , 1 ); 206 | } 207 | /* Should cause a SHA1_Transform() */ 208 | sha1Update( context , finalcount , 8 ); 209 | for (i = 0; i < SHA1_DIGEST_LENGTH; i++) 210 | { 211 | digest[i] = (sha1_byte) 212 | ( ( context->state[i >> 2] >> ( ( 3 - ( i & 3 ) ) * 8 ) ) & 255 ); 213 | } 214 | /* Wipe variables */ 215 | i = j = 0; 216 | memset( context->buffer , 0 , SHA1_BLOCK_LENGTH ); 217 | memset( context->state , 0 , SHA1_DIGEST_LENGTH ); 218 | memset( context->count , 0 , 8 ); 219 | memset( &finalcount , 0 , 8 ); 220 | } 221 | unsigned char *sha1( const unsigned char *msg , size_t size , unsigned char result[SHA1_DIGEST_LENGTH] ) 222 | { 223 | assert( result != NULL ); 224 | SHA_CTX ctx; 225 | sha1Init( &ctx ); 226 | sha1Update( &ctx , msg , size ); 227 | sha1Final( result , &ctx ); 228 | return result; 229 | } 230 | -------------------------------------------------------------------------------- /src/share_memory.c: -------------------------------------------------------------------------------- 1 | #include "share_memory.h" 2 | #define SHM_TYPE_MMAP 1 3 | void* shm_malloc( size_t size ) 4 | { 5 | shareMemory object; 6 | void *mem; 7 | //object对象需要保存在头部 8 | size += sizeof(shareMemory); 9 | #ifdef SHM_TYPE_MMAP 10 | mem = shareMemory_mmap_create( &object , size , NULL ); 11 | #else 12 | mem = shareMemory_sysv_create(&object, size, 0 ); 13 | #endif 14 | if (mem == NULL) 15 | { 16 | return NULL; 17 | } 18 | else 19 | { 20 | memcpy( mem , &object , sizeof(shareMemory) ); 21 | return mem + sizeof(shareMemory); 22 | } 23 | } 24 | void* shm_calloc( size_t num , size_t _size ) 25 | { 26 | shareMemory object; 27 | void *mem; 28 | void *ret_mem; 29 | //object对象需要保存在头部 30 | int size = sizeof(shareMemory) + ( num * _size ); 31 | #ifdef SHM_TYPE_MMAP 32 | mem = shareMemory_mmap_create( &object , size , NULL ); 33 | #else 34 | mem = shareMemory_sysv_create(&object, size, 0 ); 35 | #endif 36 | if (mem == NULL) 37 | { 38 | return NULL; 39 | } 40 | else 41 | { 42 | memcpy( mem , &object , sizeof(shareMemory) ); 43 | ret_mem = mem + sizeof(shareMemory); 44 | //calloc需要初始化 45 | bzero( ret_mem , size - sizeof(shareMemory) ); 46 | return ret_mem; 47 | } 48 | } 49 | void shm_free( void *ptr , int rm ) 50 | { 51 | //object对象在头部,如果释放了错误的对象可能会发生段错误 52 | shareMemory *object = ptr - sizeof(shareMemory); 53 | #ifdef DEBUG 54 | char check = *(char *)(ptr + object->size); //尝试访问 55 | printf("check:%c\n", check); 56 | #endif 57 | #ifdef SHM_TYPE_MMAP 58 | shareMemory_mmap_free( object ); 59 | #else 60 | shareMemory_sysv_free( object, rm ); 61 | #endif 62 | } 63 | void* shm_realloc( void *ptr , size_t new_size ) 64 | { 65 | shareMemory *object = ptr - sizeof(shareMemory); 66 | #ifdef DEBUG 67 | char check = *(char *)(ptr + object->size); //尝试访问 68 | printf("check:%c\n", check); 69 | #endif 70 | void *new_ptr; 71 | new_ptr = shm_malloc( new_size ); 72 | if (new_ptr == NULL) 73 | { 74 | return NULL; 75 | } 76 | else 77 | { 78 | memcpy( new_ptr , ptr , object->size ); 79 | shm_free( ptr , 1 ); 80 | return new_ptr; 81 | } 82 | } 83 | void *shareMemory_mmap_create( shareMemory *object , int size , char *mapfile ) 84 | { 85 | void *mem; 86 | int tmpfd = -1; 87 | int flag = MAP_SHARED; 88 | bzero( object , sizeof(shareMemory) ); 89 | #ifdef MAP_ANONYMOUS 90 | flag |= MAP_ANONYMOUS; 91 | #else 92 | if (mapfile == NULL) 93 | { 94 | mapfile = "/dev/zero"; 95 | } 96 | if (( tmpfd = open( mapfile , O_RDWR ) ) < 0) 97 | { 98 | return NULL; 99 | } 100 | strncpy( object->mapfile , mapfile , SHM_MMAP_FILE_LEN ); 101 | object->tmpfd = tmpfd; 102 | #endif 103 | mem = mmap( NULL , size , PROT_READ | PROT_WRITE , flag , tmpfd , 0 ); 104 | #ifdef MAP_FAILED 105 | if (mem == MAP_FAILED) 106 | #else 107 | if (!mem) 108 | #endif 109 | { 110 | printf( "mmap() failed. Error: %s[%d]" , strerror( errno ) , errno ); 111 | return NULL; 112 | } 113 | else 114 | { 115 | object->size = size; 116 | object->mem = mem; 117 | return mem; 118 | } 119 | } 120 | int shareMemory_mmap_free( shareMemory *object ) 121 | { 122 | return munmap( object->mem , object->size ); 123 | } 124 | void *shareMemory_sysv_create( shareMemory *object , int size , int key ) 125 | { 126 | int shmid; 127 | void *mem; 128 | bzero( object , sizeof(shareMemory) ); 129 | if (key == 0) 130 | { 131 | key = IPC_PRIVATE; 132 | } 133 | //SHM_R | SHM_W | 134 | if (( shmid = shmget( key , size , IPC_CREAT ) ) < 0) 135 | { 136 | printf( "shmget() failed. Error: %s[%d]" , strerror( errno ) , errno ); 137 | return NULL; 138 | } 139 | if (( mem = shmat( shmid , NULL , 0 ) ) < 0) 140 | { 141 | printf( "shmat() failed. Error: %s[%d]" , strerror( errno ) , errno ); 142 | return NULL; 143 | } 144 | else 145 | { 146 | object->key = key; 147 | object->shmid = shmid; 148 | object->size = size; 149 | object->mem = mem; 150 | return mem; 151 | } 152 | } 153 | int shareMemory_sysv_free( shareMemory *object , int rm ) 154 | { 155 | int shmid = object->shmid; 156 | int ret = shmdt( object->mem ); 157 | if (rm == 1) 158 | { 159 | shmctl( shmid , IPC_RMID , NULL ); 160 | } 161 | return ret; 162 | } 163 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | //https://github.com/lchb369/Aenet.git 2 | #include 3 | #include "server.h" 4 | //子进�? 5 | void myRecv( aeServer* serv , userClient *c , int len ) 6 | { 7 | printf( "recv len = %d \n" , len ); 8 | printf( "on_read recv data = %s \n" , c->recv_buffer ); 9 | char buff[64] = "i recv your message:\n"; 10 | int sendlen; 11 | sendlen = serv->send( c->fd , buff , sizeof( buff ) ); 12 | sendlen = serv->send( c->fd , c->recv_buffer , strlen( c->recv_buffer ) ); 13 | } 14 | void myClose( aeServer* serv , userClient *c ) 15 | { 16 | printf( "Worker Client closed = %d \n" , c->fd ); 17 | serv->close( c ); 18 | } 19 | void myConnect( aeServer* serv , userClient *c ) 20 | { 21 | printf( "New Client Connected fd =%d \n" , c->fd ); 22 | } 23 | int main( int argc , char *argv[] ) 24 | { 25 | aeServer* serv = aeServerCreate(); 26 | serv->onConnect = &myConnect; 27 | serv->onRecv = &myRecv; 28 | serv->onClose = &myClose; 29 | serv->runForever( "0.0.0.0" , 3002 ); 30 | return 0; 31 | } 32 | --------------------------------------------------------------------------------