├── LICENSE ├── Makefile ├── README.md ├── dtls_client.cpp ├── dtls_server.cpp ├── my_cbio.cpp └── my_cbio.h /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2019 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | OPENSSL_DIR=/usr/local/openssl 3 | OPENSSL_INC=-I$(OPENSSL_DIR)/include 4 | OPENSSL_LIB=-L$(OPENSSL_DIR)/lib -Wl,-rpath=$(OPENSSL_DIR)/lib -lssl -lcrypto 5 | OPENSSL=$(OPENSSL_DIR)/bin/openssl 6 | 7 | CPPFLAGS=-g -O3 $(OPENSSL_INC) 8 | LDFLAGS=$(OPENSSL_LIB) 9 | 10 | .PHONY: all clean certs distclean 11 | 12 | all: dtls_server dtls_client certs 13 | 14 | dtls_server: dtls_server.cpp my_cbio.cpp 15 | g++ -g $(CPPFLAGS) -o $@ $^ $(LDFLAGS) 16 | 17 | dtls_client: dtls_client.cpp my_cbio.cpp 18 | g++ -g $(CPPFLAGS) -o $@ $^ $(LDFLAGS) -lreadline 19 | 20 | 21 | certs: root-key.pem root-ca.pem server-key.pem server-csr.pem server-cert.pem client-key.pem client-csr.pem client-cert.pem 22 | 23 | clean: 24 | rm -f dtls_server dtls_client 25 | 26 | distclean: clean 27 | rm -f *.pem *.srl 28 | 29 | %-key.pem: 30 | $(OPENSSL) ecparam -name secp384r1 -genkey -noout -out $@ 31 | 32 | %-cert.pem: %-csr.pem root-ca.pem root-key.pem 33 | $(OPENSSL) x509 -req -in $< -out $@ -CA root-ca.pem -CAkey root-key.pem -days 7 34 | 35 | %-csr.pem: %-key.pem 36 | $(OPENSSL) req -new -key $< -out $@ -subj /CN=test_$*/ 37 | 38 | root-ca.pem: root-key.pem 39 | $(OPENSSL) req -new -x509 -nodes -days 7 -key $< -out $@ -subj /CN=test_rootCA/ 40 | test -f root-ca.srl || echo 00 > root-ca.srl 41 | 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dtls_epoll_example 2 | 3 | * A DTLS server/client example with openssl-1.1.0 or above 4 | * Server support multi-client 5 | * A custom BIO with STL unordered_map and deque 6 | * Tested on CentOS 7.6 7 | 8 | # Install 9 | * yum install -y readline-devel 10 | * Modify Makefile if needed 11 | * make all 12 | 13 | # Usage: 14 | * ./dtls_server 127.0.0.1:9000 15 | * ./dtls_client 127.0.0.1:9000 16 | -------------------------------------------------------------------------------- /dtls_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "my_cbio.h" 18 | 19 | 20 | #define EPOLL_TIMEOUT 8000 // ms 21 | 22 | #define MAX(x, y) ((x) >= (y) ? (x) : (y)) 23 | #define MIN(x, y) ((x) <= (y) ? (x) : (y)) 24 | 25 | void signal_handler(int sig) 26 | { 27 | if (sig==SIGINT) 28 | fprintf(stderr, "signal SIGINT\n"); 29 | else 30 | fprintf(stderr, "get signal[%d]\n", sig); 31 | 32 | fflush(stderr); 33 | } 34 | 35 | SSL *ssl; 36 | 37 | int run = 1; 38 | int connected = 0; 39 | 40 | void readline_handler(char *line) 41 | { 42 | if (line) 43 | { 44 | if (connected){ 45 | SSL_write(ssl, line, strlen(line)); 46 | } 47 | else 48 | fputs("NOT connected\n", stderr); 49 | 50 | free(line); 51 | } 52 | else 53 | { 54 | fprintf(stderr, "^D\n"); 55 | run = 0; 56 | if (connected) 57 | SSL_shutdown(ssl); 58 | } 59 | } 60 | 61 | void show_usage(const char* name) 62 | { 63 | printf("usage: %s ip:port\n", name); 64 | } 65 | 66 | int main(int argc, char **argv) 67 | { 68 | int ret; 69 | char* p; 70 | int port; 71 | int epfd; 72 | CustomBioData bio_data; 73 | 74 | if(argc < 2){ 75 | show_usage(argv[0]); 76 | exit(1); 77 | } 78 | 79 | p = strchr(argv[1], ':'); 80 | if(p == NULL){ 81 | show_usage(argv[0]); 82 | exit(1); 83 | } 84 | port = atoi(p+1); 85 | if(port <= 0 || port > 65535){ 86 | printf("invalid port:%d\n", port); 87 | exit(1); 88 | } 89 | char ip[32]; 90 | memset(ip, 0, sizeof(ip)); 91 | strncpy(ip, argv[1], MIN(sizeof(ip) - 1, p - argv[1])); 92 | 93 | struct sockaddr_in* ipv4_addr = (struct sockaddr_in*)&bio_data.m_stClientAddr; 94 | bio_data.m_stAddrBuf.m_iLen = sizeof(struct sockaddr_in); 95 | 96 | memset(ipv4_addr, 0, sizeof(struct sockaddr_in)); 97 | ipv4_addr->sin_family = AF_INET; 98 | ipv4_addr->sin_port = htons(port); 99 | 100 | ret = inet_pton(AF_INET, ip, &ipv4_addr->sin_addr); 101 | if(ret == 0){ 102 | printf("server address invalid:%s\n", ip); 103 | exit(1); 104 | } 105 | 106 | 107 | int sockfd = socket(ipv4_addr->sin_family, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); 108 | 109 | if (connect(sockfd, (struct sockaddr *)&bio_data.m_stClientAddr, bio_data.m_stAddrBuf.m_iLen)){ 110 | fputs("failed to connect\n", stderr); 111 | 112 | exit(1); 113 | } 114 | bio_data.m_iFd = sockfd; 115 | bio_data.m_iPeekMode = 0; 116 | 117 | epfd = epoll_create1(EPOLL_CLOEXEC); 118 | struct epoll_event epe = {0}; 119 | 120 | epe.data.fd = fileno(stdin); 121 | epe.events = EPOLLIN; 122 | 123 | epoll_ctl(epfd, EPOLL_CTL_ADD, epe.data.fd, &epe); 124 | 125 | fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL) | O_NONBLOCK); 126 | 127 | SSL_load_error_strings(); 128 | SSL_library_init(); 129 | 130 | SSL_CTX *ctx = SSL_CTX_new(DTLS_client_method()); 131 | SSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION); 132 | 133 | SSL_CTX_use_certificate_chain_file(ctx, "client-cert.pem"); 134 | SSL_CTX_use_PrivateKey_file(ctx, "client-key.pem", SSL_FILETYPE_PEM); 135 | ret = SSL_CTX_load_verify_locations(ctx, "root-ca.pem", NULL); 136 | printf("SSL_CTX_load_verify_locations(): %d\n", ret); 137 | 138 | ret = SSL_CTX_set_default_verify_file(ctx); 139 | printf("SSL_CTX_set_default_verify_file(): %d\n", ret); 140 | 141 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); 142 | 143 | ssl = SSL_new(ctx); 144 | 145 | BIO *custom_bio = BIO_new(BIO_s_custom()); 146 | BIO_set_data(custom_bio, (void *)&bio_data); 147 | BIO_set_init(custom_bio, 1); 148 | SSL_set_bio(ssl, custom_bio, custom_bio); 149 | 150 | epe.data.fd = sockfd; 151 | epe.events = EPOLLIN|EPOLLET; 152 | 153 | epoll_ctl(epfd, EPOLL_CTL_ADD, epe.data.fd, &epe); 154 | 155 | signal(SIGINT, signal_handler); 156 | 157 | CustomBuffer *packet; 158 | packet = CustomBuffer::NewBuf(2000); 159 | 160 | ret = SSL_connect(ssl); 161 | if (ret==1) 162 | { 163 | connected = 1; 164 | fputs("connected\n", stderr); 165 | } 166 | else if (SSL_get_error(ssl, ret)==SSL_ERROR_SSL) 167 | { 168 | dump_addr((struct sockaddr *)&bio_data.m_stClientAddr, "ssl error: "); 169 | ERR_print_errors_fp(stderr); 170 | } 171 | 172 | rl_callback_handler_install(">> ", readline_handler); 173 | 174 | while(run) 175 | { 176 | ret = epoll_wait(epfd, &epe, 1, EPOLL_TIMEOUT); 177 | if (ret<0) 178 | { 179 | if (connected) 180 | SSL_shutdown(ssl); 181 | 182 | break; 183 | } 184 | else if (ret==0) // time out 185 | continue; 186 | 187 | if (epe.data.fd==fileno(stdin)) 188 | rl_callback_read_char(); 189 | if (epe.data.fd==sockfd) 190 | { 191 | while ((packet->m_iLen=recv(sockfd, packet->BufBegin(), packet->m_iCap, 0))>=0) 192 | { 193 | fprintf(stderr, "\033[2K\r<< %d bytes\n", packet->m_iLen); 194 | 195 | bio_data.m_stQueue.push_back(packet); 196 | 197 | 198 | packet = CustomBuffer::NewBuf(2000); 199 | 200 | if (connected) 201 | { 202 | packet->m_iLen = SSL_read(ssl, packet->BufBegin(), packet->m_iCap); 203 | 204 | if (packet->m_iLen>0) 205 | { 206 | packet->BufBegin()[packet->m_iLen] = 0; 207 | printf("recv: %s\n", (const char*)packet->BufBegin()); 208 | } 209 | else if (packet->m_iLen==0) 210 | { 211 | SSL_shutdown(ssl); 212 | run = 0; 213 | } 214 | } 215 | else 216 | { 217 | ret = SSL_connect(ssl); 218 | 219 | if (ret==1) 220 | { 221 | connected = 1; 222 | fputs("connected\n", stderr); 223 | } 224 | else if (SSL_get_error(ssl, ret)==SSL_ERROR_SSL) 225 | { 226 | dump_addr((struct sockaddr *)&bio_data.m_stClientAddr, "ssl error: "); 227 | ERR_print_errors_fp(stderr); 228 | 229 | run = 0; 230 | break; 231 | } 232 | } 233 | rl_forced_update_display(); 234 | } 235 | } 236 | } 237 | 238 | free(packet); 239 | 240 | SSL_free(ssl); 241 | SSL_CTX_free(ctx); 242 | 243 | BIO_s_custom_meth_free(); 244 | 245 | rl_cleanup_after_signal(); 246 | fputc('\n', stderr); 247 | 248 | close(sockfd); 249 | 250 | rl_callback_handler_remove(); 251 | 252 | return 0; 253 | } 254 | 255 | -------------------------------------------------------------------------------- /dtls_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "my_cbio.h" 19 | 20 | #define COOKIE_SECRET_LENGTH 16 21 | #define EPOLL_TIMEOUT 1000 // miliseconds 22 | #define SOCKET_IDLE_TIMEOUT 600 // seconds 23 | #define SHUTDOWN_TIMEOUT 5 // seconds 24 | 25 | #define MAX(x, y) ((x) >= (y) ? (x) : (y)) 26 | #define MIN(x, y) ((x) <= (y) ? (x) : (y)) 27 | 28 | 29 | struct UdpConnectInfo; 30 | typedef int (*EventHandler)(UdpConnectInfo* pstConnInfo); 31 | 32 | 33 | #if (__cplusplus >= 201103L) // c++11 34 | #include 35 | typedef std::unordered_map ConnectMap; 36 | typedef std::unordered_map::iterator ConnectMapIterator; 37 | 38 | #else // c++98 39 | 40 | #include 41 | typedef std::tr1::unordered_map ConnectMap; 42 | typedef std::tr1::unordered_map::iterator ConnectMapIterator; 43 | 44 | #endif 45 | 46 | typedef enum{ 47 | DTLS_STATUS_INIT=0, // wait connect 48 | DTLS_STATUS_CONNECTED=1, // connected 49 | DTLS_STATUS_SHUTDOWN=2, // shutdown & wait close 50 | }ConnStatusType; 51 | 52 | struct UdpConnectInfo{ 53 | CustomBioData m_stBioData; 54 | SSL* m_pstSSL; 55 | int m_iStatus; 56 | time_t m_tLastAccess; 57 | ConnectMap* m_pstConnMap; 58 | EventHandler m_fEvHandle; 59 | 60 | UdpConnectInfo() 61 | { 62 | m_pstSSL = NULL; 63 | m_iStatus = DTLS_STATUS_INIT; 64 | m_tLastAccess = 0; 65 | m_pstConnMap = NULL; 66 | m_fEvHandle = NULL; 67 | } 68 | 69 | ~UdpConnectInfo() 70 | { 71 | if(m_pstConnMap != NULL) 72 | m_pstConnMap->erase(&(m_stBioData.m_stAddrBuf)); 73 | 74 | if(m_pstSSL != NULL) 75 | SSL_free(m_pstSSL); 76 | m_pstSSL = NULL; 77 | m_iStatus = DTLS_STATUS_INIT; 78 | m_tLastAccess = 0; 79 | m_pstConnMap = NULL; 80 | m_fEvHandle = NULL; 81 | } 82 | }; 83 | 84 | unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; 85 | int listen_fd; 86 | SSL_CTX *ctx; 87 | ConnectMap stConnMap; 88 | UdpConnectInfo* pstListenConnInfo = NULL; 89 | 90 | 91 | UdpConnectInfo* new_udpconnect_info(); 92 | 93 | 94 | void signal_handler(int sig) 95 | { 96 | if (sig==SIGINT) 97 | fprintf(stderr, "signal SIGINT\n"); 98 | else 99 | fprintf(stderr, "get signal[%d]\n", sig); 100 | } 101 | 102 | int init_cookie_secret() 103 | { 104 | if(!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH)){ 105 | printf("error setting random cookie secret\n"); 106 | return -1; 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | 113 | int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len) 114 | { 115 | unsigned char *buffer, result[EVP_MAX_MD_SIZE]; 116 | unsigned int length = 0, resultlength; 117 | 118 | BIO_ADDR* pstPeerAddr = BIO_ADDR_new(); 119 | struct sockaddr_storage stAddr; 120 | struct sockaddr_in* ipv4_addr = (struct sockaddr_in*)&stAddr; 121 | struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&stAddr; 122 | 123 | /* Read peer information */ 124 | (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), pstPeerAddr); 125 | 126 | stAddr.ss_family = BIO_ADDR_family(pstPeerAddr); 127 | 128 | /* Create buffer with peer's address and port */ 129 | length = 0; 130 | switch (stAddr.ss_family) { 131 | case AF_INET: 132 | length += sizeof(struct in_addr); 133 | ipv4_addr->sin_port = BIO_ADDR_rawport(pstPeerAddr); 134 | BIO_ADDR_rawaddress(pstPeerAddr, &ipv4_addr->sin_addr, NULL); 135 | break; 136 | 137 | case AF_INET6: 138 | length += sizeof(struct in6_addr); 139 | ipv6_addr->sin6_port = BIO_ADDR_rawport(pstPeerAddr); 140 | BIO_ADDR_rawaddress(pstPeerAddr, &ipv6_addr->sin6_addr, NULL); 141 | break; 142 | 143 | default: 144 | printf("unknow family:%d. AF_UNSPEC=%d\n", BIO_ADDR_family(pstPeerAddr), AF_UNSPEC); 145 | BIO_ADDR_free(pstPeerAddr); 146 | OPENSSL_assert(0); 147 | break; 148 | } 149 | length += sizeof(in_port_t); 150 | 151 | BIO_ADDR_free(pstPeerAddr); 152 | 153 | buffer = (unsigned char*) OPENSSL_malloc(length); 154 | if(buffer == NULL){ 155 | printf("out of memory\n"); 156 | 157 | return 0; 158 | } 159 | 160 | switch (stAddr.ss_family) { 161 | case AF_INET: 162 | memcpy(buffer, &ipv4_addr->sin_port, sizeof(in_port_t)); 163 | memcpy(buffer + sizeof(ipv4_addr->sin_port), &ipv4_addr->sin_addr, sizeof(struct in_addr)); 164 | break; 165 | 166 | case AF_INET6: 167 | memcpy(buffer, &ipv6_addr->sin6_port, sizeof(in_port_t)); 168 | memcpy(buffer + sizeof(in_port_t), &ipv6_addr->sin6_addr, sizeof(struct in6_addr)); 169 | break; 170 | 171 | default: 172 | OPENSSL_assert(0); 173 | break; 174 | } 175 | 176 | /* Calculate HMAC of buffer using the secret */ 177 | HMAC(EVP_sha1(), (const void*) cookie_secret, COOKIE_SECRET_LENGTH, (const unsigned char*) buffer, length, result, &resultlength); 178 | OPENSSL_free(buffer); 179 | 180 | memcpy(cookie, result, resultlength); 181 | *cookie_len = resultlength; 182 | 183 | return 1; 184 | } 185 | 186 | int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len) 187 | { 188 | int ret; 189 | unsigned char result[EVP_MAX_MD_SIZE]; 190 | unsigned int result_len; 191 | 192 | ret = generate_cookie(ssl, result, &result_len); 193 | if(ret != 1) 194 | return ret; 195 | 196 | if(cookie_len == result_len && memcmp(result, cookie, result_len) == 0) 197 | return 1; 198 | 199 | return 0; 200 | } 201 | 202 | 203 | int dtls_verify_callback (int ok, X509_STORE_CTX *ctx) 204 | { 205 | /* This function should ask the user 206 | * if he trusts the received certificate. 207 | * Here we always trust. 208 | */ 209 | return 1; 210 | } 211 | 212 | 213 | 214 | int on_message(UdpConnectInfo* pstInfo) 215 | { 216 | int len; 217 | char buf[200]; 218 | 219 | printf("socket[%d] %s ...\n", pstInfo->m_stBioData.m_iFd, __FUNCTION__); 220 | 221 | len = SSL_read(pstInfo->m_pstSSL, buf, sizeof(buf) - 1); 222 | if(len == 0){ 223 | SSL_shutdown(pstInfo->m_pstSSL); 224 | 225 | dump_addr((struct sockaddr *)&pstInfo->m_stBioData.m_stClientAddr, "client close: "); 226 | return(1); 227 | } 228 | else if(len <= 0){ 229 | switch (SSL_get_error(pstInfo->m_pstSSL, len)) { 230 | case SSL_ERROR_NONE: 231 | case SSL_ERROR_WANT_READ: 232 | case SSL_ERROR_ZERO_RETURN: 233 | return(0); 234 | 235 | case SSL_ERROR_SYSCALL: 236 | printf("ssl error syscall\n"); 237 | return(-1); 238 | 239 | case SSL_ERROR_SSL: 240 | printf("ssl error ssl\n"); 241 | return(-1); 242 | 243 | default: 244 | printf("unknow error when ssl accept\n"); 245 | return(-1); 246 | } 247 | } 248 | buf[len] = 0; 249 | 250 | printf("recv: %d bytes:%s\n", len, buf); 251 | 252 | len = SSL_write(pstInfo->m_pstSSL, buf, len); 253 | if(len <= 0){ 254 | switch (SSL_get_error(pstInfo->m_pstSSL, len)) { 255 | case SSL_ERROR_NONE: 256 | case SSL_ERROR_WANT_WRITE: 257 | case SSL_ERROR_ZERO_RETURN: 258 | return(0); 259 | 260 | case SSL_ERROR_SYSCALL: 261 | printf("ssl error syscall\n"); 262 | return(-1); 263 | 264 | case SSL_ERROR_SSL: 265 | printf("ssl error ssl\n"); 266 | return(-1); 267 | 268 | default: 269 | printf("unknow error when ssl accept\n"); 270 | return(-1); 271 | } 272 | } 273 | printf("send %d bytes\n", len); 274 | 275 | return(0); 276 | } 277 | 278 | int on_connect(UdpConnectInfo* pstInfo) 279 | { 280 | int iRet; 281 | int tmp; 282 | 283 | iRet = SSL_accept(pstInfo->m_pstSSL); 284 | printf("SSL_accept():%d\n", iRet); 285 | 286 | if(iRet == 1){ 287 | dump_addr((struct sockaddr *)&pstInfo->m_stBioData.m_stClientAddr, "new connection: "); 288 | 289 | pstInfo->m_fEvHandle = on_message; 290 | pstInfo->m_iStatus = DTLS_STATUS_CONNECTED; 291 | } 292 | 293 | else{ 294 | tmp = SSL_get_error(pstInfo->m_pstSSL, iRet); 295 | switch (tmp) { 296 | case SSL_ERROR_NONE: 297 | case SSL_ERROR_WANT_READ: 298 | case SSL_ERROR_WANT_WRITE: 299 | printf("SSL_accept delay\n"); 300 | return(0); 301 | 302 | case SSL_ERROR_SYSCALL: 303 | printf("SSL_accept error syscall\n"); 304 | return(0); 305 | 306 | case SSL_ERROR_SSL: 307 | printf("SSL_accept error ssl\n"); 308 | return(-1); 309 | 310 | default: 311 | printf("unknow error when ssl accept:%d\n", tmp); 312 | return(-1); 313 | } 314 | } 315 | 316 | return(0); 317 | } 318 | 319 | int do_new_connection(UdpConnectInfo*& pstInfo) 320 | { 321 | int iRet; 322 | 323 | BIO_ADDR* pstPeerAddr = BIO_ADDR_new(); 324 | iRet = DTLSv1_listen(pstInfo->m_pstSSL, pstPeerAddr); 325 | printf("DTLSv1_listen():%d\n", iRet); 326 | 327 | BIO_ADDR_free(pstPeerAddr); 328 | 329 | if(iRet != 1) 330 | return(0); 331 | 332 | (*pstInfo->m_pstConnMap)[&pstInfo->m_stBioData.m_stAddrBuf] = pstInfo; 333 | pstInfo->m_fEvHandle(pstInfo); 334 | 335 | pstInfo = new_udpconnect_info(); 336 | 337 | return(0); 338 | } 339 | 340 | UdpConnectInfo* new_udpconnect_info() 341 | { 342 | UdpConnectInfo* pstInfo; 343 | 344 | pstInfo = new UdpConnectInfo; 345 | if(pstInfo == NULL){ 346 | printf("new UdpConnectInfo fail: %m\n"); 347 | return(NULL); 348 | } 349 | 350 | pstInfo->m_pstSSL = SSL_new(ctx); 351 | if(pstInfo->m_pstSSL == NULL){ 352 | printf("SSL_new fail:%m\n"); 353 | delete pstInfo; 354 | return(NULL); 355 | } 356 | 357 | pstInfo->m_stBioData.m_stAddrBuf.m_iCap = sizeof(struct sockaddr_storage); 358 | pstInfo->m_stBioData.m_stAddrBuf.m_iLen = sizeof(struct sockaddr_storage); 359 | memset(&pstInfo->m_stBioData.m_stClientAddr, 0, sizeof(struct sockaddr_storage)); 360 | pstInfo->m_stBioData.m_iPeekMode = 0; 361 | pstInfo->m_pstConnMap = &stConnMap; // connect map 362 | pstInfo->m_fEvHandle = on_connect; 363 | 364 | BIO *bio = BIO_new(BIO_s_custom()); 365 | BIO_set_data(bio, (void *)&pstInfo->m_stBioData); 366 | BIO_set_init(bio, 1); 367 | SSL_set_bio(pstInfo->m_pstSSL, bio, bio); 368 | 369 | return pstInfo; 370 | } 371 | 372 | 373 | void check_idle_socket(time_t time_now) 374 | { 375 | for(ConnectMapIterator it=stConnMap.begin(); it != stConnMap.end(); ){ 376 | UdpConnectInfo* pstInfo = it->second; 377 | if(time_now - pstInfo->m_tLastAccess < SOCKET_IDLE_TIMEOUT){ 378 | ++it; 379 | continue; 380 | } 381 | 382 | if(pstInfo->m_iStatus == DTLS_STATUS_SHUTDOWN){ 383 | if(time_now - pstInfo->m_tLastAccess < SOCKET_IDLE_TIMEOUT + SHUTDOWN_TIMEOUT){ 384 | ++it; 385 | continue; 386 | } 387 | 388 | printf("client socket[%d] shutdown timeout, release it now\n", pstInfo->m_stBioData.m_iFd); 389 | 390 | stConnMap.erase(it++); 391 | 392 | delete pstInfo; 393 | } 394 | else{ 395 | printf("client socket[%d] idle timeout, shutdown it now\n", pstInfo->m_stBioData.m_iFd); 396 | 397 | SSL_shutdown(pstInfo->m_pstSSL); 398 | ++it; 399 | } 400 | 401 | } 402 | 403 | return; 404 | } 405 | 406 | 407 | void show_usage(const char* name) 408 | { 409 | printf("usage: %s ip:port\n", name); 410 | } 411 | 412 | int main(int argc, char* argv[]) 413 | { 414 | int ret; 415 | char* p; 416 | int port; 417 | int listen_fd; 418 | sockaddr_in listen_addr; 419 | unsigned int listen_addr_len = sizeof(struct sockaddr_in); 420 | int on = 1, off = 0; 421 | int epfd; 422 | 423 | if(argc < 2){ 424 | show_usage(argv[0]); 425 | exit(1); 426 | } 427 | 428 | p = strchr(argv[1], ':'); 429 | if(p == NULL){ 430 | show_usage(argv[0]); 431 | exit(1); 432 | } 433 | port = atoi(p+1); 434 | if(port <= 0 || port > 65535){ 435 | printf("invalid port:%d\n", port); 436 | exit(1); 437 | } 438 | char ip[32]; 439 | memset(ip, 0, sizeof(ip)); 440 | strncpy(ip, argv[1], MIN(sizeof(ip) - 1, p - argv[1])); 441 | 442 | memset(&listen_addr, 0, sizeof(listen_addr)); 443 | listen_addr.sin_family = AF_INET; 444 | listen_addr.sin_port = htons(port); 445 | 446 | ret = inet_pton(AF_INET, ip, &listen_addr.sin_addr); 447 | if(ret == 0){ 448 | printf("listen address invalid:%s\n", ip); 449 | exit(1); 450 | } 451 | 452 | 453 | init_cookie_secret(); 454 | 455 | // ssl init 456 | SSL_load_error_strings(); 457 | SSL_library_init(); 458 | 459 | const SSL_METHOD *mtd = DTLS_server_method(); 460 | ctx = SSL_CTX_new(mtd); 461 | SSL_CTX_set_min_proto_version(ctx, DTLS1_2_VERSION); 462 | if(SSL_CTX_use_certificate_chain_file(ctx, "server-cert.pem") != 1){ 463 | printf("load cert chain file fail\n"); 464 | exit(1); 465 | } 466 | if(SSL_CTX_use_PrivateKey_file(ctx, "server-key.pem", SSL_FILETYPE_PEM) != 1){ 467 | printf("load private key file fail\n"); 468 | exit(1); 469 | } 470 | if(SSL_CTX_check_private_key (ctx) != 1){ 471 | printf("invalid private key!\n"); 472 | exit(1); 473 | } 474 | 475 | /* Client has to authenticate */ 476 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback); 477 | 478 | ret = SSL_CTX_load_verify_locations(ctx, "root-ca.pem", NULL); 479 | printf("SSL_CTX_load_verify_location(): %d\n", ret); 480 | 481 | ret = SSL_CTX_set_default_verify_file(ctx); 482 | printf("SSL_CTX_set_default_verify_file(): %d\n", ret); 483 | 484 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); 485 | 486 | 487 | SSL_CTX_set_read_ahead(ctx, 1); 488 | SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); 489 | SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); 490 | 491 | 492 | epfd = epoll_create1(EPOLL_CLOEXEC); 493 | struct epoll_event epe = {0}; 494 | 495 | listen_fd = socket(listen_addr.sin_family, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); 496 | if(listen_fd < 0){ 497 | printf("listen socket fail:%m\n"); 498 | exit(3); 499 | } 500 | else{ 501 | printf("listen fd:%d\n", listen_fd); 502 | } 503 | 504 | UdpConnectInfo* pstListenConnInfo = new_udpconnect_info(); 505 | if(pstListenConnInfo == NULL){ 506 | printf("new udpconnect info error:%m\n"); 507 | exit(4); 508 | } 509 | pstListenConnInfo->m_fEvHandle = on_connect; 510 | 511 | 512 | setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &on, (socklen_t) sizeof(on)); 513 | #ifdef SO_REUSEPORT 514 | setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &on, (socklen_t) sizeof(on)); 515 | #endif 516 | 517 | ret = bind(listen_fd, (struct sockaddr *)&listen_addr, (socklen_t)listen_addr_len); 518 | if(ret != 0){ 519 | printf("bind addr[%s] error:%m\n", argv[0]); 520 | exit(2); 521 | } 522 | 523 | 524 | epe.events = EPOLLIN|EPOLLET; 525 | epe.data.fd = listen_fd; 526 | epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &epe); 527 | 528 | 529 | signal(SIGINT, signal_handler); 530 | 531 | int ev_num; 532 | struct epoll_event evs[10]; 533 | time_t last_time=0, time_now=0; 534 | CustomBuffer* pstPkg = CustomBuffer::NewBuf(2000); // buffer must large than MTU 535 | 536 | while(1){ 537 | ev_num = epoll_wait(epfd, evs, sizeof(evs)/sizeof(evs[0]), EPOLL_TIMEOUT); 538 | if(ev_num == -1){ 539 | printf("epoll_wait error: %m\n"); 540 | break; 541 | } 542 | 543 | time_now = time(NULL); 544 | 545 | for(int i=0; i < ev_num; i++){ 546 | if(evs[i].data.fd < 0){ 547 | printf("invalid epoll event. fd:%d\n", evs[i].data.fd); 548 | continue; 549 | } 550 | 551 | while((pstPkg->m_iLen = recvfrom(evs[i].data.fd, pstPkg->BufBegin(), pstPkg->m_iCap, 0, (struct sockaddr *)&pstListenConnInfo->m_stBioData.m_stClientAddr, (socklen_t*)&pstListenConnInfo->m_stBioData.m_stAddrBuf.m_iLen)) > 0){ 552 | dump_addr((struct sockaddr *)&pstListenConnInfo->m_stBioData.m_stClientAddr, "<< "); 553 | 554 | ConnectMapIterator it = stConnMap.find(&(pstListenConnInfo->m_stBioData.m_stAddrBuf)); 555 | if(it != stConnMap.end()){ 556 | dump_addr((struct sockaddr *)&pstListenConnInfo->m_stBioData.m_stClientAddr, "recv data from client: "); 557 | 558 | UdpConnectInfo* pstConn = it->second; 559 | 560 | pstConn->m_tLastAccess = time_now; 561 | pstConn->m_stBioData.m_stQueue.push_back((void*)pstPkg); 562 | ret = pstConn->m_fEvHandle(pstConn); 563 | if(ret != 0){ 564 | if(ret > 0) 565 | dump_addr((struct sockaddr *)&pstConn->m_stBioData.m_stClientAddr, "client shutdown socket: "); 566 | else 567 | dump_addr((struct sockaddr *)&pstConn->m_stBioData.m_stClientAddr, "event process fail! "); 568 | 569 | stConnMap.erase(it); 570 | delete pstConn; 571 | } 572 | } 573 | else{ 574 | dump_addr((struct sockaddr *)&pstListenConnInfo->m_stBioData.m_stClientAddr, "new connection: "); 575 | 576 | pstListenConnInfo->m_stBioData.m_iFd = evs[i].data.fd; 577 | pstListenConnInfo->m_stBioData.m_stQueue.push_back((void*)pstPkg); 578 | 579 | ret = do_new_connection(pstListenConnInfo); 580 | } 581 | 582 | pstPkg = CustomBuffer::NewBuf(2000); 583 | } 584 | } 585 | 586 | 587 | if(time_now - last_time >= (SOCKET_IDLE_TIMEOUT / 2)){ 588 | check_idle_socket(time_now); 589 | last_time = time_now; 590 | } 591 | } 592 | 593 | for(ConnectMapIterator it=stConnMap.begin(); it != stConnMap.end(); ){ 594 | UdpConnectInfo* pstConn = it->second; 595 | 596 | stConnMap.erase(it++); 597 | 598 | delete pstConn; 599 | } 600 | 601 | free(pstPkg); 602 | pstPkg = NULL; 603 | 604 | delete pstListenConnInfo; 605 | pstListenConnInfo = NULL; 606 | 607 | close(listen_fd); 608 | SSL_CTX_free(ctx); 609 | 610 | BIO_s_custom_meth_free(); 611 | 612 | return(0); 613 | } 614 | -------------------------------------------------------------------------------- /my_cbio.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "my_cbio.h" 15 | 16 | 17 | void dump_hex(const unsigned char *buf, size_t len, const char *indent) 18 | { 19 | size_t i; 20 | 21 | for(i=0; isa_family) 49 | { 50 | case AF_INET: 51 | memmove(buf, "INET: ", 6); 52 | inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, buf+6, sizeof(buf)-6); 53 | sprintf(buf+strlen(buf), ":%d", ntohs(((struct sockaddr_in *)sa)->sin_port)); 54 | break; 55 | 56 | case AF_INET6: 57 | memmove(buf, "INET6: [", 8); 58 | inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, buf+8, sizeof(buf)-8); 59 | sprintf(buf+strlen(buf), "]:%d", ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); 60 | break; 61 | 62 | default: 63 | memmove(buf, "unknown", 8); 64 | break; 65 | } 66 | 67 | return buf; 68 | } 69 | 70 | void dump_addr(struct sockaddr *sa, const char *indent) 71 | { 72 | fprintf(stderr, "%s%s\n", indent, sdump_addr(sa)); 73 | } 74 | 75 | 76 | // #define fprintf(...) 77 | 78 | int BIO_s_custom_write_ex(BIO *b, const char *data, size_t dlen, size_t *written) 79 | { 80 | fprintf(stderr, "%s: BIO[0x%016lX], data[0x%016lX], dlen[%ld], *written[%ld]\n", __FUNCTION__, b, data, dlen, *written); 81 | fflush(stderr); 82 | 83 | return -1; 84 | } 85 | 86 | int BIO_s_custom_write(BIO *b, const char *data, int dlen) 87 | { 88 | int ret; 89 | CustomBioData *cdp; 90 | 91 | ret = -1; 92 | fprintf(stderr, "%s: BIO[0x%016lX], buf[0x%016lX], dlen[%ld]\n", __FUNCTION__, b, data, dlen); 93 | 94 | cdp = (CustomBioData *)BIO_get_data(b); 95 | 96 | dump_addr((struct sockaddr *)&cdp->m_stClientAddr, ">> "); 97 | // dump_hex((unsigned const char *)data, dlen, " "); 98 | ret = sendto(cdp->m_iFd, data, dlen, 0, (struct sockaddr *)&cdp->m_stClientAddr, cdp->m_stAddrBuf.m_iLen); 99 | if (ret >= 0) 100 | fprintf(stderr, " %d bytes sent\n", ret); 101 | else 102 | fprintf(stderr, " ret: %d errno: [%d] %s\n", ret, errno, strerror(errno)); 103 | 104 | return ret; 105 | } 106 | 107 | int BIO_s_custom_read_ex(BIO *b, char *data, size_t dlen, size_t *readbytes) 108 | { 109 | fprintf(stderr, "%s: BIO[0x%016lX], data[0x%016lX], dlen[%ld], *readbytes[%ld]\n", __FUNCTION__, b, data, dlen, *readbytes); 110 | 111 | return -1; 112 | } 113 | 114 | int BIO_s_custom_read(BIO *b, char *data, int dlen) 115 | { 116 | int ret; 117 | CustomBioData *cdp; 118 | std::deque *dp; 119 | CustomBuffer *bp; 120 | 121 | ret = -1; 122 | cdp = (CustomBioData *)BIO_get_data(b); 123 | 124 | fprintf(stderr, "%s: BIO[0x%016lX], data[0x%016lX], dlen[%ld], peekmode:%d\n", __FUNCTION__, b, data, dlen, cdp->m_iPeekMode); 125 | 126 | 127 | dp = &cdp->m_stQueue; 128 | fprintf(stderr, " data[0x%016lX] queue_size: %d\n", dp, dp->size()); 129 | if (!dp->empty()){ 130 | bp = (CustomBuffer*)dp->front(); 131 | 132 | ret = (bp->m_iLen <= dlen) ? bp->m_iLen : dlen; 133 | memmove(data, bp->BufBegin(), ret); 134 | 135 | fprintf(stderr, " buf[0x%016lX] read len:%d\n", bp, ret); 136 | 137 | if (cdp->m_iPeekMode == 0){ 138 | dp->pop_front(); 139 | free(bp); 140 | } 141 | } 142 | 143 | return ret; 144 | } 145 | 146 | int BIO_s_custom_gets(BIO *b, char *data, int size); 147 | 148 | int BIO_s_custom_puts(BIO *b, const char *data); 149 | 150 | 151 | static int copy_addr(struct sockaddr_storage* peer, const struct sockaddr *sa) 152 | { 153 | if (sa->sa_family == AF_INET) { 154 | *(struct sockaddr_in *)peer = *(const struct sockaddr_in *)sa; 155 | return 1; 156 | } 157 | 158 | if (sa->sa_family == AF_INET6) { 159 | *(struct sockaddr_in6 *)peer = *(const struct sockaddr_in6 *)sa; 160 | return 1; 161 | } 162 | 163 | if (sa->sa_family == AF_UNIX) { 164 | *(struct sockaddr_un *)peer = *(const struct sockaddr_un *)sa; 165 | return 1; 166 | } 167 | 168 | 169 | return 0; 170 | } 171 | 172 | long BIO_s_custom_ctrl(BIO *b, int cmd, long num, void *ptr) 173 | { 174 | long ret = 0; 175 | 176 | // fprintf(stderr, "%s: BIO[0x%016lX], cmd[%d], num[%ld], ptr[0x%016lX]\n", __FUNCTION__, b, cmd, num, ptr); 177 | // fflush(stderr); 178 | 179 | CustomBioData* pstData = (CustomBioData *)BIO_get_data(b); 180 | 181 | switch(cmd) 182 | { 183 | case BIO_CTRL_FLUSH: 184 | ret = 1; 185 | break; 186 | 187 | case BIO_CTRL_DGRAM_CONNECT: 188 | copy_addr(&pstData->m_stClientAddr, (struct sockaddr *)ptr); 189 | break; 190 | 191 | case BIO_CTRL_DGRAM_SET_CONNECTED: 192 | if(ptr != NULL) { 193 | pstData->m_iConnected = 1; 194 | copy_addr(&pstData->m_stClientAddr, (struct sockaddr *)ptr); 195 | } else { 196 | pstData->m_iConnected = 0; 197 | memset(&pstData->m_stClientAddr, 0, sizeof(pstData->m_stClientAddr)); 198 | } 199 | break; 200 | 201 | case BIO_CTRL_DGRAM_SET_PEER: 202 | if(ptr == NULL) 203 | break; 204 | 205 | copy_addr(&pstData->m_stClientAddr, (struct sockaddr *)ptr); 206 | break; 207 | 208 | case BIO_CTRL_DGRAM_GET_PEER: 209 | if(ptr == NULL) 210 | break; 211 | 212 | switch(pstData->m_stClientAddr.ss_family){ 213 | case AF_INET: 214 | ret = sizeof(struct sockaddr_in); 215 | break; 216 | 217 | case AF_INET6: 218 | ret = sizeof(struct sockaddr_in6); 219 | break; 220 | 221 | case AF_UNIX: 222 | default: 223 | ret = sizeof(pstData->m_stClientAddr); 224 | break; 225 | } 226 | /* FIXME: if num < ret, we will only return part of an address. 227 | That should bee an error, no? */ 228 | if (num == 0 || num > ret) 229 | num = ret; 230 | memcpy(ptr, &pstData->m_stClientAddr, (ret = num)); 231 | break; 232 | 233 | 234 | case BIO_CTRL_WPENDING: 235 | ret = 0; 236 | break; 237 | case BIO_CTRL_DGRAM_QUERY_MTU: 238 | case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: 239 | ret = 1500; 240 | break; 241 | case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 242 | ret = 96; // random guess 243 | break; 244 | case BIO_CTRL_DGRAM_SET_PEEK_MODE: 245 | ((CustomBioData *)BIO_get_data(b))->m_iPeekMode = !!num; 246 | ret = 1; 247 | break; 248 | case BIO_CTRL_PUSH: 249 | case BIO_CTRL_POP: 250 | case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 251 | ret = 0; 252 | break; 253 | default: 254 | fprintf(stderr, "%s unknow cmd. BIO[0x%016lX], cmd[%d], num[%ld], ptr[0x%016lX]\n", __FUNCTION__, b, cmd, num, ptr); 255 | ret = 0; 256 | raise(SIGTRAP); 257 | break; 258 | } 259 | 260 | return ret; 261 | } 262 | 263 | int BIO_s_custom_create(BIO *b) 264 | { 265 | fprintf(stderr, "%s: BIO[0x%016lX]\n", __FUNCTION__, b); 266 | fflush(stderr); 267 | 268 | return 1; 269 | } 270 | 271 | int BIO_s_custom_destroy(BIO *b) 272 | { 273 | fprintf(stderr, "%s: BIO[0x%016lX]\n", __FUNCTION__, b); 274 | fflush(stderr); 275 | 276 | return 1; 277 | } 278 | 279 | // long BIO_s_custom_callback_ctrl(BIO *, int, BIO_info_cb *); 280 | 281 | BIO_METHOD *_BIO_s_custom = NULL; // FixMe: multi-thread race condition 282 | BIO_METHOD *BIO_s_custom(void) 283 | { 284 | if (_BIO_s_custom) 285 | return _BIO_s_custom; 286 | 287 | _BIO_s_custom = BIO_meth_new(BIO_get_new_index()|BIO_TYPE_SOURCE_SINK, "BIO_s_custom"); 288 | 289 | // BIO_meth_set_write_ex(_BIO_s_custom, BIO_s_custom_write_ex); 290 | BIO_meth_set_write(_BIO_s_custom, BIO_s_custom_write); 291 | // BIO_meth_set_read_ex(_BIO_s_custom, BIO_s_custom_read_ex); 292 | BIO_meth_set_read(_BIO_s_custom, BIO_s_custom_read); 293 | BIO_meth_set_ctrl(_BIO_s_custom, BIO_s_custom_ctrl); 294 | BIO_meth_set_create(_BIO_s_custom, BIO_s_custom_create); 295 | BIO_meth_set_destroy(_BIO_s_custom, BIO_s_custom_destroy); 296 | // BIO_meth_set_callback_ctrl(_BIO_s_custom, BIO_s_custom_callback_ctrl); 297 | 298 | return _BIO_s_custom; 299 | } 300 | 301 | void BIO_s_custom_meth_free(void) 302 | { 303 | if (_BIO_s_custom) 304 | BIO_meth_free(_BIO_s_custom); 305 | 306 | _BIO_s_custom = NULL; 307 | } 308 | 309 | -------------------------------------------------------------------------------- /my_cbio.h: -------------------------------------------------------------------------------- 1 | #ifndef MY_CBIO_H 2 | #define MY_CBIO_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "openssl/ssl.h" 10 | #include "openssl/err.h" 11 | #include "openssl/bio.h" 12 | 13 | struct CustomBuffer{ 14 | int m_iCap; 15 | int m_iLen; 16 | // unsigned char m_auchBuf[]; 17 | 18 | CustomBuffer() 19 | { 20 | m_iCap = 0; 21 | m_iLen = 0; 22 | } 23 | 24 | ~CustomBuffer() 25 | { 26 | m_iCap = 0; 27 | m_iLen = 0; 28 | } 29 | 30 | unsigned char* BufBegin() const 31 | { 32 | return (unsigned char*)&m_iLen + sizeof(int); 33 | } 34 | 35 | static CustomBuffer* NewBuf(unsigned int uiBufSize) 36 | { 37 | CustomBuffer* p = (CustomBuffer*)calloc(1, sizeof(CustomBuffer) + uiBufSize); 38 | if(p == NULL) 39 | return(NULL); 40 | 41 | p->m_iCap = uiBufSize; 42 | p->m_iLen = 0; 43 | 44 | return(p); 45 | } 46 | }; 47 | 48 | struct CustomBioData{ 49 | CustomBuffer m_stAddrBuf; 50 | struct sockaddr_storage m_stClientAddr; 51 | int m_iFd; 52 | // BIO_ADDR m_stPeer; // set by bio 53 | int m_iConnected; // set by bio 54 | int m_iPeekMode; 55 | std::deque m_stQueue; 56 | 57 | CustomBioData() 58 | { 59 | m_iFd = -1; 60 | // memset(&m_stPeer, 0, sizeof(m_stPeer)); 61 | m_iConnected = 0; 62 | m_iPeekMode = 0; 63 | } 64 | 65 | ~CustomBioData() 66 | { 67 | m_iFd = -1; 68 | m_iPeekMode = 0; 69 | 70 | if(!m_stQueue.empty()){ 71 | for(std::deque::iterator it=m_stQueue.begin(); it != m_stQueue.end(); ){ 72 | CustomBuffer* p = (CustomBuffer*)*it; 73 | m_stQueue.erase(it++); 74 | delete p; 75 | } 76 | } 77 | } 78 | }; 79 | 80 | struct HashCustomBuffer 81 | { 82 | inline size_t hash_unsigned_string(const char* pchKey, unsigned int uiKeySize) const 83 | { 84 | unsigned int h = 0, g = 0; 85 | const char *pchEnd = pchKey + uiKeySize; 86 | 87 | //key hash 88 | while (pchKey < pchEnd){ 89 | h = (h << 4) + *pchKey++; 90 | if ((g = (h & 0xF0000000))){ 91 | h = h ^ (g >> 24); 92 | h = h ^ g; 93 | } 94 | } 95 | 96 | return size_t(h); 97 | } 98 | 99 | size_t operator()(const CustomBuffer* o) const 100 | { 101 | 102 | return hash_unsigned_string((const char*)o->BufBegin(), (unsigned int)o->m_iLen); 103 | } 104 | }; 105 | 106 | struct CompareCustomBuffer{ 107 | bool operator()(const CustomBuffer* a, const CustomBuffer* b) const 108 | { 109 | if(a->m_iLen != b->m_iLen) 110 | return(0); 111 | 112 | const int len = a->m_iLen; 113 | for(int i=0; i < len; i++){ 114 | if(a->BufBegin()[i] != b->BufBegin()[i]) 115 | return(0); 116 | } 117 | 118 | return(1); 119 | } 120 | }; 121 | 122 | 123 | void dump_hex(const unsigned char *buf, size_t len, const char *indent); 124 | void dump_addr(struct sockaddr *sa, const char *indent); 125 | 126 | 127 | int BIO_s_custom_write_ex(BIO *b, const char *data, size_t dlen, size_t *written); 128 | int BIO_s_custom_write(BIO *b, const char *data, int dlen); 129 | int BIO_s_custom_read_ex(BIO *b, char *data, size_t dlen, size_t *readbytes); 130 | int BIO_s_custom_read(BIO *b, char *data, int dlen); 131 | int BIO_s_custom_gets(BIO *b, char *data, int size); 132 | int BIO_s_custom_puts(BIO *b, const char *data); 133 | long BIO_s_custom_ctrl(BIO *b, int cmd, long num, void *ptr); 134 | int BIO_s_custom_create(BIO *b); 135 | int BIO_s_custom_destroy(BIO *b); 136 | // long BIO_s_custom_callback_ctrl(BIO *, int, BIO_info_cb *); 137 | 138 | BIO_METHOD *BIO_s_custom(void); 139 | void BIO_s_custom_meth_free(void); 140 | 141 | #endif 142 | --------------------------------------------------------------------------------