├── .cproject ├── .project ├── Makefile ├── base64.cpp ├── base64.h ├── debug_log.cpp ├── debug_log.h ├── main.cpp ├── network_interface.cpp ├── network_interface.h ├── sha1.cpp ├── sha1.h ├── test.html ├── websocket_handler.cpp ├── websocket_handler.h ├── websocket_request.cpp ├── websocket_request.h ├── websocket_respond.cpp └── websocket_respond.h /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 33 | 34 | 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 | 73 | 74 | 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 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | websocket 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | FLAG = -g 3 | INCLUDE = 4 | LIBDIR = 5 | LIB = 6 | BIN = 7 | TARGET = websocketserver 8 | SRCS = base64.cpp sha1.cpp network_interface.cpp debug_log.cpp websocket_handler.cpp \ 9 | websocket_request.cpp main.cpp 10 | 11 | $(TARGET):$(SRCS:.cpp=.o) 12 | $(CC) $(FLAG) $(LIBDIR) $(LIB) -o $@ $^ 13 | -rm -f *.o *.d 14 | 15 | %.o:%.cpp 16 | $(CC) $(FLAG) $(INCLUDE) -c -o $@ $< 17 | 18 | clean: 19 | -rm -f *.o *.d 20 | -------------------------------------------------------------------------------- /base64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | base64.cpp and base64.h 3 | 4 | Copyright (C) 2004-2008 René Nyffenegger 5 | 6 | This source code is provided 'as-is', without any express or implied 7 | warranty. In no event will the author be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this source code must not be misrepresented; you must not 15 | claim that you wrote the original source code. If you use this source code 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original source code. 21 | 22 | 3. This notice may not be removed or altered from any source distribution. 23 | 24 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 25 | 26 | */ 27 | 28 | #include "base64.h" 29 | #include 30 | 31 | static const std::string base64_chars = 32 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 33 | "abcdefghijklmnopqrstuvwxyz" 34 | "0123456789+/"; 35 | 36 | 37 | static inline bool is_base64(unsigned char c) { 38 | return (isalnum(c) || (c == '+') || (c == '/')); 39 | } 40 | 41 | std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { 42 | std::string ret; 43 | int i = 0; 44 | int j = 0; 45 | unsigned char char_array_3[3]; 46 | unsigned char char_array_4[4]; 47 | 48 | while (in_len--) { 49 | char_array_3[i++] = *(bytes_to_encode++); 50 | if (i == 3) { 51 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 52 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 53 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 54 | char_array_4[3] = char_array_3[2] & 0x3f; 55 | 56 | for(i = 0; (i <4) ; i++) 57 | ret += base64_chars[char_array_4[i]]; 58 | i = 0; 59 | } 60 | } 61 | 62 | if (i) 63 | { 64 | for(j = i; j < 3; j++) 65 | char_array_3[j] = '\0'; 66 | 67 | char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; 68 | char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); 69 | char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); 70 | char_array_4[3] = char_array_3[2] & 0x3f; 71 | 72 | for (j = 0; (j < i + 1); j++) 73 | ret += base64_chars[char_array_4[j]]; 74 | 75 | while((i++ < 3)) 76 | ret += '='; 77 | 78 | } 79 | 80 | return ret; 81 | 82 | } 83 | 84 | std::string base64_decode(std::string const& encoded_string) { 85 | size_t in_len = encoded_string.size(); 86 | int i = 0; 87 | int j = 0; 88 | int in_ = 0; 89 | unsigned char char_array_4[4], char_array_3[3]; 90 | std::string ret; 91 | 92 | while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { 93 | char_array_4[i++] = encoded_string[in_]; in_++; 94 | if (i ==4) { 95 | for (i = 0; i <4; i++) 96 | char_array_4[i] = base64_chars.find(char_array_4[i]); 97 | 98 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 99 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 100 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 101 | 102 | for (i = 0; (i < 3); i++) 103 | ret += char_array_3[i]; 104 | i = 0; 105 | } 106 | } 107 | 108 | if (i) { 109 | for (j = i; j <4; j++) 110 | char_array_4[j] = 0; 111 | 112 | for (j = 0; j <4; j++) 113 | char_array_4[j] = base64_chars.find(char_array_4[j]); 114 | 115 | char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); 116 | char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); 117 | char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; 118 | 119 | for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; 120 | } 121 | 122 | return ret; 123 | } 124 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | std::string base64_encode(unsigned char const* , unsigned int len); 4 | std::string base64_decode(std::string const& s); 5 | -------------------------------------------------------------------------------- /debug_log.cpp: -------------------------------------------------------------------------------- 1 | #include "debug_log.h" 2 | 3 | void DEBUG_LOG(const char *msg, ...) { 4 | char message[256] = {0}; 5 | va_list args; 6 | va_start(args, msg); 7 | vsprintf(message, msg, args); 8 | va_end(args); 9 | Debug_LOG::log()->write_log(message); 10 | } 11 | 12 | Debug_LOG *Debug_LOG::m_log = NULL; 13 | 14 | Debug_LOG::Debug_LOG(): 15 | tim(0), 16 | t(NULL), 17 | fp(NULL), 18 | filepath(), 19 | message(), 20 | last_log_time() 21 | { 22 | #ifdef __WRITE_FILE__ 23 | create_log_file(); 24 | #endif 25 | } 26 | 27 | Debug_LOG::~Debug_LOG(){ 28 | #ifdef __WRITE_FILE__ 29 | fclose(fp); 30 | #endif 31 | } 32 | 33 | void Debug_LOG::create_log_file(){ 34 | if(fp != NULL) 35 | fclose(fp); 36 | 37 | sprintf(filepath, "./log/debuglog_"); 38 | time(&tim); 39 | t = localtime(&tim); 40 | memcpy(&last_log_time, t, sizeof(struct tm)); 41 | sprintf(filepath + 15, "%02d_%02d",t->tm_mon + 1, t->tm_mday); 42 | fp = fopen(filepath, "a+"); 43 | } 44 | 45 | Debug_LOG *Debug_LOG::log(){ 46 | if(m_log == NULL){ 47 | m_log = new Debug_LOG(); 48 | } 49 | return m_log; 50 | } 51 | 52 | void Debug_LOG::write_log(const char *msg){ 53 | time(&tim); 54 | t = localtime(&tim); 55 | sprintf(message, "[%02d:%02d:%02d] %s\n", t->tm_hour, t->tm_min, t->tm_sec, msg); 56 | #ifdef __WRITE_FILE__ 57 | if(t->tm_mday != last_log_time.tm_mday || t->tm_mon != last_log_time.tm_mon 58 | || t->tm_year != last_log_time.tm_year) 59 | create_log_file(); 60 | fwrite(message, strlen(message), 1, fp); 61 | fflush(fp); 62 | #else 63 | printf("\n%s", message); 64 | fflush(stdout); 65 | #endif 66 | } 67 | 68 | -------------------------------------------------------------------------------- /debug_log.h: -------------------------------------------------------------------------------- 1 | #ifndef __debug_log__ 2 | #define __debug_log__ 3 | 4 | //#define __WRITE_FILE__ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void DEBUG_LOG(const char *msg, ...); 12 | 13 | class Debug_LOG { 14 | private: 15 | Debug_LOG(); 16 | ~Debug_LOG(); 17 | void create_log_file(); 18 | public: 19 | static Debug_LOG *log(); 20 | void write_log(const char *msg); 21 | private: 22 | static Debug_LOG *m_log; 23 | time_t tim; 24 | struct tm *t; 25 | FILE *fp; 26 | char filepath[32]; 27 | char message[256]; 28 | struct tm last_log_time; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "network_interface.h" 2 | 3 | int main(int argc, char **argv){ 4 | NETWORK_INTERFACE->run(); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /network_interface.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "debug_log.h" 12 | #include "network_interface.h" 13 | 14 | Network_Interface *Network_Interface::m_network_interface = NULL; 15 | 16 | Network_Interface::Network_Interface(): 17 | epollfd_(0), 18 | listenfd_(0), 19 | websocket_handler_map_() 20 | { 21 | if(0 != init()) 22 | exit(1); 23 | } 24 | 25 | Network_Interface::~Network_Interface(){ 26 | 27 | } 28 | 29 | int Network_Interface::init(){ 30 | listenfd_ = socket(AF_INET, SOCK_STREAM, 0); 31 | if(listenfd_ == -1){ 32 | DEBUG_LOG("创建套接字失败!"); 33 | return -1; 34 | } 35 | struct sockaddr_in server_addr; 36 | memset(&server_addr, 0, sizeof(sockaddr_in)); 37 | server_addr.sin_family = AF_INET; 38 | server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 39 | server_addr.sin_port = htons(PORT); 40 | if(-1 == bind(listenfd_, (struct sockaddr *)(&server_addr), sizeof(server_addr))){ 41 | DEBUG_LOG("绑定套接字失败!"); 42 | return -1; 43 | } 44 | if(-1 == listen(listenfd_, 5)){ 45 | DEBUG_LOG("监听失败!"); 46 | return -1; 47 | } 48 | epollfd_ = epoll_create(MAXEVENTSSIZE); 49 | 50 | ctl_event(listenfd_, true); 51 | DEBUG_LOG("服务器启动成功!"); 52 | return 0; 53 | } 54 | 55 | int Network_Interface::epoll_loop(){ 56 | struct sockaddr_in client_addr; 57 | socklen_t clilen; 58 | int nfds = 0; 59 | int fd = 0; 60 | int bufflen = 0; 61 | struct epoll_event events[MAXEVENTSSIZE]; 62 | while(true){ 63 | nfds = epoll_wait(epollfd_, events, MAXEVENTSSIZE, TIMEWAIT); 64 | for(int i = 0; i < nfds; i++){ 65 | if(events[i].data.fd == listenfd_){ 66 | fd = accept(listenfd_, (struct sockaddr *)&client_addr, &clilen); 67 | ctl_event(fd, true); 68 | } 69 | else if(events[i].events & EPOLLIN){ 70 | if((fd = events[i].data.fd) < 0) 71 | continue; 72 | Websocket_Handler *handler = websocket_handler_map_[fd]; 73 | if(handler == NULL) 74 | continue; 75 | if((bufflen = read(fd, handler->getbuff(), BUFFLEN)) <= 0){ 76 | ctl_event(fd, false); 77 | } 78 | else{ 79 | handler->process(); 80 | } 81 | } 82 | } 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | int Network_Interface::set_noblock(int fd){ 89 | int flags; 90 | if ((flags = fcntl(fd, F_GETFL, 0)) == -1) 91 | flags = 0; 92 | return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 93 | } 94 | 95 | Network_Interface *Network_Interface::get_share_network_interface(){ 96 | if(m_network_interface == NULL) 97 | m_network_interface = new Network_Interface(); 98 | return m_network_interface; 99 | } 100 | 101 | void Network_Interface::ctl_event(int fd, bool flag){ 102 | struct epoll_event ev; 103 | ev.data.fd = fd; 104 | ev.events = flag ? EPOLLIN : 0; 105 | epoll_ctl(epollfd_, flag ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, fd, &ev); 106 | if(flag){ 107 | set_noblock(fd); 108 | websocket_handler_map_[fd] = new Websocket_Handler(fd); 109 | if(fd != listenfd_) 110 | DEBUG_LOG("fd: %d 加入epoll循环", fd); 111 | } 112 | else{ 113 | close(fd); 114 | delete websocket_handler_map_[fd]; 115 | websocket_handler_map_.erase(fd); 116 | DEBUG_LOG("fd: %d 退出epoll循环", fd); 117 | } 118 | } 119 | 120 | void Network_Interface::run(){ 121 | epoll_loop(); 122 | } 123 | -------------------------------------------------------------------------------- /network_interface.h: -------------------------------------------------------------------------------- 1 | #ifndef __NETWORK_INTERFACE__ 2 | #define __NETWORK_INTERFACE__ 3 | 4 | #include "websocket_handler.h" 5 | 6 | #define PORT 9000 7 | #define TIMEWAIT 100 8 | #define BUFFLEN 2048 9 | #define MAXEVENTSSIZE 20 10 | 11 | typedef std::map WEB_SOCKET_HANDLER_MAP; 12 | 13 | class Network_Interface { 14 | private: 15 | Network_Interface(); 16 | ~Network_Interface(); 17 | int init(); 18 | int epoll_loop(); 19 | int set_noblock(int fd); 20 | void ctl_event(int fd, bool flag); 21 | public: 22 | void run(); 23 | static Network_Interface *get_share_network_interface(); 24 | private: 25 | int epollfd_; 26 | int listenfd_; 27 | WEB_SOCKET_HANDLER_MAP websocket_handler_map_; 28 | static Network_Interface *m_network_interface; 29 | }; 30 | 31 | #define NETWORK_INTERFACE Network_Interface::get_share_network_interface() 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /sha1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.cpp 3 | * 4 | * Copyright (C) 1998, 2009 5 | * Paul E. Jones 6 | * All Rights Reserved. 7 | * 8 | ***************************************************************************** 9 | * $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $ 10 | ***************************************************************************** 11 | * 12 | * Description: 13 | * This class implements the Secure Hashing Standard as defined 14 | * in FIPS PUB 180-1 published April 17, 1995. 15 | * 16 | * The Secure Hashing Standard, which uses the Secure Hashing 17 | * Algorithm (SHA), produces a 160-bit message digest for a 18 | * given data stream. In theory, it is highly improbable that 19 | * two messages will produce the same message digest. Therefore, 20 | * this algorithm can serve as a means of providing a "fingerprint" 21 | * for a message. 22 | * 23 | * Portability Issues: 24 | * SHA-1 is defined in terms of 32-bit "words". This code was 25 | * written with the expectation that the processor has at least 26 | * a 32-bit machine word size. If the machine word size is larger, 27 | * the code should still function properly. One caveat to that 28 | * is that the input functions taking characters and character arrays 29 | * assume that only 8 bits of information are stored in each character. 30 | * 31 | * Caveats: 32 | * SHA-1 is designed to work with messages less than 2^64 bits long. 33 | * Although SHA-1 allows a message digest to be generated for 34 | * messages of any number of bits less than 2^64, this implementation 35 | * only works with messages with a length that is a multiple of 8 36 | * bits. 37 | * 38 | */ 39 | 40 | 41 | #include "sha1.h" 42 | 43 | 44 | /* 45 | * SHA1 46 | * 47 | * Description: 48 | * This is the constructor for the sha1 class. 49 | * 50 | * Parameters: 51 | * None. 52 | * 53 | * Returns: 54 | * Nothing. 55 | * 56 | * Comments: 57 | * 58 | */ 59 | SHA1::SHA1() 60 | { 61 | Reset(); 62 | } 63 | 64 | /* 65 | * ~SHA1 66 | * 67 | * Description: 68 | * This is the destructor for the sha1 class 69 | * 70 | * Parameters: 71 | * None. 72 | * 73 | * Returns: 74 | * Nothing. 75 | * 76 | * Comments: 77 | * 78 | */ 79 | SHA1::~SHA1() 80 | { 81 | // The destructor does nothing 82 | } 83 | 84 | /* 85 | * Reset 86 | * 87 | * Description: 88 | * This function will initialize the sha1 class member variables 89 | * in preparation for computing a new message digest. 90 | * 91 | * Parameters: 92 | * None. 93 | * 94 | * Returns: 95 | * Nothing. 96 | * 97 | * Comments: 98 | * 99 | */ 100 | void SHA1::Reset() 101 | { 102 | Length_Low = 0; 103 | Length_High = 0; 104 | Message_Block_Index = 0; 105 | 106 | H[0] = 0x67452301; 107 | H[1] = 0xEFCDAB89; 108 | H[2] = 0x98BADCFE; 109 | H[3] = 0x10325476; 110 | H[4] = 0xC3D2E1F0; 111 | 112 | Computed = false; 113 | Corrupted = false; 114 | } 115 | 116 | /* 117 | * Result 118 | * 119 | * Description: 120 | * This function will return the 160-bit message digest into the 121 | * array provided. 122 | * 123 | * Parameters: 124 | * message_digest_array: [out] 125 | * This is an array of five unsigned integers which will be filled 126 | * with the message digest that has been computed. 127 | * 128 | * Returns: 129 | * True if successful, false if it failed. 130 | * 131 | * Comments: 132 | * 133 | */ 134 | bool SHA1::Result(unsigned *message_digest_array) 135 | { 136 | int i; // Counter 137 | 138 | if (Corrupted) 139 | { 140 | return false; 141 | } 142 | 143 | if (!Computed) 144 | { 145 | PadMessage(); 146 | Computed = true; 147 | } 148 | 149 | for(i = 0; i < 5; i++) 150 | { 151 | message_digest_array[i] = H[i]; 152 | } 153 | 154 | return true; 155 | } 156 | 157 | /* 158 | * Input 159 | * 160 | * Description: 161 | * This function accepts an array of octets as the next portion of 162 | * the message. 163 | * 164 | * Parameters: 165 | * message_array: [in] 166 | * An array of characters representing the next portion of the 167 | * message. 168 | * 169 | * Returns: 170 | * Nothing. 171 | * 172 | * Comments: 173 | * 174 | */ 175 | void SHA1::Input( const unsigned char *message_array, 176 | unsigned length) 177 | { 178 | if (!length) 179 | { 180 | return; 181 | } 182 | 183 | if (Computed || Corrupted) 184 | { 185 | Corrupted = true; 186 | return; 187 | } 188 | 189 | while(length-- && !Corrupted) 190 | { 191 | Message_Block[Message_Block_Index++] = (*message_array & 0xFF); 192 | 193 | Length_Low += 8; 194 | Length_Low &= 0xFFFFFFFF; // Force it to 32 bits 195 | if (Length_Low == 0) 196 | { 197 | Length_High++; 198 | Length_High &= 0xFFFFFFFF; // Force it to 32 bits 199 | if (Length_High == 0) 200 | { 201 | Corrupted = true; // Message is too long 202 | } 203 | } 204 | 205 | if (Message_Block_Index == 64) 206 | { 207 | ProcessMessageBlock(); 208 | } 209 | 210 | message_array++; 211 | } 212 | } 213 | 214 | /* 215 | * Input 216 | * 217 | * Description: 218 | * This function accepts an array of octets as the next portion of 219 | * the message. 220 | * 221 | * Parameters: 222 | * message_array: [in] 223 | * An array of characters representing the next portion of the 224 | * message. 225 | * length: [in] 226 | * The length of the message_array 227 | * 228 | * Returns: 229 | * Nothing. 230 | * 231 | * Comments: 232 | * 233 | */ 234 | void SHA1::Input( const char *message_array, 235 | unsigned length) 236 | { 237 | Input((unsigned char *) message_array, length); 238 | } 239 | 240 | /* 241 | * Input 242 | * 243 | * Description: 244 | * This function accepts a single octets as the next message element. 245 | * 246 | * Parameters: 247 | * message_element: [in] 248 | * The next octet in the message. 249 | * 250 | * Returns: 251 | * Nothing. 252 | * 253 | * Comments: 254 | * 255 | */ 256 | void SHA1::Input(unsigned char message_element) 257 | { 258 | Input(&message_element, 1); 259 | } 260 | 261 | /* 262 | * Input 263 | * 264 | * Description: 265 | * This function accepts a single octet as the next message element. 266 | * 267 | * Parameters: 268 | * message_element: [in] 269 | * The next octet in the message. 270 | * 271 | * Returns: 272 | * Nothing. 273 | * 274 | * Comments: 275 | * 276 | */ 277 | void SHA1::Input(char message_element) 278 | { 279 | Input((unsigned char *) &message_element, 1); 280 | } 281 | 282 | /* 283 | * operator<< 284 | * 285 | * Description: 286 | * This operator makes it convenient to provide character strings to 287 | * the SHA1 object for processing. 288 | * 289 | * Parameters: 290 | * message_array: [in] 291 | * The character array to take as input. 292 | * 293 | * Returns: 294 | * A reference to the SHA1 object. 295 | * 296 | * Comments: 297 | * Each character is assumed to hold 8 bits of information. 298 | * 299 | */ 300 | SHA1& SHA1::operator<<(const char *message_array) 301 | { 302 | const char *p = message_array; 303 | 304 | while(*p) 305 | { 306 | Input(*p); 307 | p++; 308 | } 309 | 310 | return *this; 311 | } 312 | 313 | /* 314 | * operator<< 315 | * 316 | * Description: 317 | * This operator makes it convenient to provide character strings to 318 | * the SHA1 object for processing. 319 | * 320 | * Parameters: 321 | * message_array: [in] 322 | * The character array to take as input. 323 | * 324 | * Returns: 325 | * A reference to the SHA1 object. 326 | * 327 | * Comments: 328 | * Each character is assumed to hold 8 bits of information. 329 | * 330 | */ 331 | SHA1& SHA1::operator<<(const unsigned char *message_array) 332 | { 333 | const unsigned char *p = message_array; 334 | 335 | while(*p) 336 | { 337 | Input(*p); 338 | p++; 339 | } 340 | 341 | return *this; 342 | } 343 | 344 | /* 345 | * operator<< 346 | * 347 | * Description: 348 | * This function provides the next octet in the message. 349 | * 350 | * Parameters: 351 | * message_element: [in] 352 | * The next octet in the message 353 | * 354 | * Returns: 355 | * A reference to the SHA1 object. 356 | * 357 | * Comments: 358 | * The character is assumed to hold 8 bits of information. 359 | * 360 | */ 361 | SHA1& SHA1::operator<<(const char message_element) 362 | { 363 | Input((unsigned char *) &message_element, 1); 364 | 365 | return *this; 366 | } 367 | 368 | /* 369 | * operator<< 370 | * 371 | * Description: 372 | * This function provides the next octet in the message. 373 | * 374 | * Parameters: 375 | * message_element: [in] 376 | * The next octet in the message 377 | * 378 | * Returns: 379 | * A reference to the SHA1 object. 380 | * 381 | * Comments: 382 | * The character is assumed to hold 8 bits of information. 383 | * 384 | */ 385 | SHA1& SHA1::operator<<(const unsigned char message_element) 386 | { 387 | Input(&message_element, 1); 388 | 389 | return *this; 390 | } 391 | 392 | /* 393 | * ProcessMessageBlock 394 | * 395 | * Description: 396 | * This function will process the next 512 bits of the message 397 | * stored in the Message_Block array. 398 | * 399 | * Parameters: 400 | * None. 401 | * 402 | * Returns: 403 | * Nothing. 404 | * 405 | * Comments: 406 | * Many of the variable names in this function, especially the single 407 | * character names, were used because those were the names used 408 | * in the publication. 409 | * 410 | */ 411 | void SHA1::ProcessMessageBlock() 412 | { 413 | const unsigned K[] = { // Constants defined for SHA-1 414 | 0x5A827999, 415 | 0x6ED9EBA1, 416 | 0x8F1BBCDC, 417 | 0xCA62C1D6 418 | }; 419 | int t; // Loop counter 420 | unsigned temp; // Temporary word value 421 | unsigned W[80]; // Word sequence 422 | unsigned A, B, C, D, E; // Word buffers 423 | 424 | /* 425 | * Initialize the first 16 words in the array W 426 | */ 427 | for(t = 0; t < 16; t++) 428 | { 429 | W[t] = ((unsigned) Message_Block[t * 4]) << 24; 430 | W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16; 431 | W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8; 432 | W[t] |= ((unsigned) Message_Block[t * 4 + 3]); 433 | } 434 | 435 | for(t = 16; t < 80; t++) 436 | { 437 | W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 438 | } 439 | 440 | A = H[0]; 441 | B = H[1]; 442 | C = H[2]; 443 | D = H[3]; 444 | E = H[4]; 445 | 446 | for(t = 0; t < 20; t++) 447 | { 448 | temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 449 | temp &= 0xFFFFFFFF; 450 | E = D; 451 | D = C; 452 | C = CircularShift(30,B); 453 | B = A; 454 | A = temp; 455 | } 456 | 457 | for(t = 20; t < 40; t++) 458 | { 459 | temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 460 | temp &= 0xFFFFFFFF; 461 | E = D; 462 | D = C; 463 | C = CircularShift(30,B); 464 | B = A; 465 | A = temp; 466 | } 467 | 468 | for(t = 40; t < 60; t++) 469 | { 470 | temp = CircularShift(5,A) + 471 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 472 | temp &= 0xFFFFFFFF; 473 | E = D; 474 | D = C; 475 | C = CircularShift(30,B); 476 | B = A; 477 | A = temp; 478 | } 479 | 480 | for(t = 60; t < 80; t++) 481 | { 482 | temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 483 | temp &= 0xFFFFFFFF; 484 | E = D; 485 | D = C; 486 | C = CircularShift(30,B); 487 | B = A; 488 | A = temp; 489 | } 490 | 491 | H[0] = (H[0] + A) & 0xFFFFFFFF; 492 | H[1] = (H[1] + B) & 0xFFFFFFFF; 493 | H[2] = (H[2] + C) & 0xFFFFFFFF; 494 | H[3] = (H[3] + D) & 0xFFFFFFFF; 495 | H[4] = (H[4] + E) & 0xFFFFFFFF; 496 | 497 | Message_Block_Index = 0; 498 | } 499 | 500 | /* 501 | * PadMessage 502 | * 503 | * Description: 504 | * According to the standard, the message must be padded to an even 505 | * 512 bits. The first padding bit must be a '1'. The last 64 bits 506 | * represent the length of the original message. All bits in between 507 | * should be 0. This function will pad the message according to those 508 | * rules by filling the message_block array accordingly. It will also 509 | * call ProcessMessageBlock() appropriately. When it returns, it 510 | * can be assumed that the message digest has been computed. 511 | * 512 | * Parameters: 513 | * None. 514 | * 515 | * Returns: 516 | * Nothing. 517 | * 518 | * Comments: 519 | * 520 | */ 521 | void SHA1::PadMessage() 522 | { 523 | /* 524 | * Check to see if the current message block is too small to hold 525 | * the initial padding bits and length. If so, we will pad the 526 | * block, process it, and then continue padding into a second block. 527 | */ 528 | if (Message_Block_Index > 55) 529 | { 530 | Message_Block[Message_Block_Index++] = 0x80; 531 | while(Message_Block_Index < 64) 532 | { 533 | Message_Block[Message_Block_Index++] = 0; 534 | } 535 | 536 | ProcessMessageBlock(); 537 | 538 | while(Message_Block_Index < 56) 539 | { 540 | Message_Block[Message_Block_Index++] = 0; 541 | } 542 | } 543 | else 544 | { 545 | Message_Block[Message_Block_Index++] = 0x80; 546 | while(Message_Block_Index < 56) 547 | { 548 | Message_Block[Message_Block_Index++] = 0; 549 | } 550 | 551 | } 552 | 553 | /* 554 | * Store the message length as the last 8 octets 555 | */ 556 | Message_Block[56] = (Length_High >> 24) & 0xFF; 557 | Message_Block[57] = (Length_High >> 16) & 0xFF; 558 | Message_Block[58] = (Length_High >> 8) & 0xFF; 559 | Message_Block[59] = (Length_High) & 0xFF; 560 | Message_Block[60] = (Length_Low >> 24) & 0xFF; 561 | Message_Block[61] = (Length_Low >> 16) & 0xFF; 562 | Message_Block[62] = (Length_Low >> 8) & 0xFF; 563 | Message_Block[63] = (Length_Low) & 0xFF; 564 | 565 | ProcessMessageBlock(); 566 | } 567 | 568 | 569 | /* 570 | * CircularShift 571 | * 572 | * Description: 573 | * This member function will perform a circular shifting operation. 574 | * 575 | * Parameters: 576 | * bits: [in] 577 | * The number of bits to shift (1-31) 578 | * word: [in] 579 | * The value to shift (assumes a 32-bit integer) 580 | * 581 | * Returns: 582 | * The shifted value. 583 | * 584 | * Comments: 585 | * 586 | */ 587 | unsigned SHA1::CircularShift(int bits, unsigned word) 588 | { 589 | return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits)); 590 | } 591 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Copyright (C) 1998, 2009 5 | * Paul E. Jones 6 | * All Rights Reserved. 7 | * 8 | ***************************************************************************** 9 | * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ 10 | ***************************************************************************** 11 | * 12 | * Description: 13 | * This class implements the Secure Hashing Standard as defined 14 | * in FIPS PUB 180-1 published April 17, 1995. 15 | * 16 | * Many of the variable names in this class, especially the single 17 | * character names, were used because those were the names used 18 | * in the publication. 19 | * 20 | * Please read the file sha1.cpp for more information. 21 | * 22 | */ 23 | 24 | #ifndef _SHA1_H_ 25 | #define _SHA1_H_ 26 | 27 | 28 | class SHA1 29 | { 30 | public: 31 | 32 | SHA1(); 33 | virtual ~SHA1(); 34 | 35 | /* 36 | * Re-initialize the class 37 | */ 38 | void Reset(); 39 | 40 | /* 41 | * Returns the message digest 42 | */ 43 | bool Result(unsigned *message_digest_array); 44 | 45 | /* 46 | * Provide input to SHA1 47 | */ 48 | void Input( const unsigned char *message_array, 49 | unsigned length); 50 | void Input( const char *message_array, 51 | unsigned length); 52 | void Input(unsigned char message_element); 53 | void Input(char message_element); 54 | SHA1& operator<<(const char *message_array); 55 | SHA1& operator<<(const unsigned char *message_array); 56 | SHA1& operator<<(const char message_element); 57 | SHA1& operator<<(const unsigned char message_element); 58 | 59 | private: 60 | 61 | /* 62 | * Process the next 512 bits of the message 63 | */ 64 | void ProcessMessageBlock(); 65 | 66 | /* 67 | * Pads the current message block to 512 bits 68 | */ 69 | void PadMessage(); 70 | 71 | /* 72 | * Performs a circular left shift operation 73 | */ 74 | inline unsigned CircularShift(int bits, unsigned word); 75 | 76 | unsigned H[5]; // Message digest buffers 77 | 78 | unsigned Length_Low; // Message length in bits 79 | unsigned Length_High; // Message length in bits 80 | 81 | unsigned char Message_Block[64]; // 512-bit message blocks 82 | int Message_Block_Index; // Index into message block array 83 | 84 | bool Computed; // Is the digest computed? 85 | bool Corrupted; // Is the message digest corruped? 86 | 87 | }; 88 | 89 | 90 | #endif // _SHA1_H_ 91 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | websocket test 7 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /websocket_handler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "websocket_handler.h" 3 | 4 | Websocket_Handler::Websocket_Handler(int fd): 5 | buff_(), 6 | status_(WEBSOCKET_UNCONNECT), 7 | header_map_(), 8 | fd_(fd), 9 | request_(new Websocket_Request) 10 | { 11 | } 12 | 13 | Websocket_Handler::~Websocket_Handler(){ 14 | } 15 | 16 | int Websocket_Handler::process(){ 17 | if(status_ == WEBSOCKET_UNCONNECT){ 18 | return handshark(); 19 | } 20 | request_->fetch_websocket_info(buff_); 21 | request_->print(); 22 | memset(buff_, 0, sizeof(buff_)); 23 | return 0; 24 | } 25 | 26 | int Websocket_Handler::handshark(){ 27 | char request[1024] = {}; 28 | status_ = WEBSOCKET_HANDSHARKED; 29 | fetch_http_info(); 30 | parse_str(request); 31 | memset(buff_, 0, sizeof(buff_)); 32 | return send_data(request); 33 | } 34 | 35 | void Websocket_Handler::parse_str(char *request){ 36 | strcat(request, "HTTP/1.1 101 Switching Protocols\r\n"); 37 | strcat(request, "Connection: upgrade\r\n"); 38 | strcat(request, "Sec-WebSocket-Accept: "); 39 | std::string server_key = header_map_["Sec-WebSocket-Key"]; 40 | server_key += MAGIC_KEY; 41 | 42 | SHA1 sha; 43 | unsigned int message_digest[5]; 44 | sha.Reset(); 45 | sha << server_key.c_str(); 46 | 47 | sha.Result(message_digest); 48 | for (int i = 0; i < 5; i++) { 49 | message_digest[i] = htonl(message_digest[i]); 50 | } 51 | server_key = base64_encode(reinterpret_cast(message_digest),20); 52 | server_key += "\r\n"; 53 | strcat(request, server_key.c_str()); 54 | strcat(request, "Upgrade: websocket\r\n\r\n"); 55 | } 56 | 57 | int Websocket_Handler::fetch_http_info(){ 58 | std::istringstream s(buff_); 59 | std::string request; 60 | 61 | std::getline(s, request); 62 | if (request[request.size()-1] == '\r') { 63 | request.erase(request.end()-1); 64 | } else { 65 | return -1; 66 | } 67 | 68 | std::string header; 69 | std::string::size_type end; 70 | 71 | while (std::getline(s, header) && header != "\r") { 72 | if (header[header.size()-1] != '\r') { 73 | continue; //end 74 | } else { 75 | header.erase(header.end()-1); //remove last char 76 | } 77 | 78 | end = header.find(": ",0); 79 | if (end != std::string::npos) { 80 | std::string key = header.substr(0,end); 81 | std::string value = header.substr(end+2); 82 | header_map_[key] = value; 83 | } 84 | } 85 | 86 | return 0; 87 | } 88 | 89 | int Websocket_Handler::send_data(char *buff){ 90 | return write(fd_, buff, strlen(buff)); 91 | } 92 | -------------------------------------------------------------------------------- /websocket_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef __WEBSOCKET_HANDLER__ 2 | #define __WEBSOCKET_HANDLER__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "base64.h" 9 | #include "sha1.h" 10 | #include "debug_log.h" 11 | #include "websocket_request.h" 12 | 13 | #define MAGIC_KEY "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 14 | 15 | enum WEBSOCKET_STATUS { 16 | WEBSOCKET_UNCONNECT = 0, 17 | WEBSOCKET_HANDSHARKED = 1, 18 | }; 19 | 20 | typedef std::map HEADER_MAP; 21 | 22 | class Websocket_Handler{ 23 | public: 24 | Websocket_Handler(int fd); 25 | ~Websocket_Handler(); 26 | int process(); 27 | inline char *getbuff(); 28 | private: 29 | int handshark(); 30 | void parse_str(char *request); 31 | int fetch_http_info(); 32 | int send_data(char *buff); 33 | private: 34 | char buff_[2048]; 35 | WEBSOCKET_STATUS status_; 36 | HEADER_MAP header_map_; 37 | int fd_; 38 | Websocket_Request *request_; 39 | }; 40 | 41 | inline char *Websocket_Handler::getbuff(){ 42 | return buff_; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /websocket_request.cpp: -------------------------------------------------------------------------------- 1 | #include "websocket_request.h" 2 | 3 | Websocket_Request::Websocket_Request(): 4 | fin_(), 5 | opcode_(), 6 | mask_(), 7 | masking_key_(), 8 | payload_length_(), 9 | payload_() 10 | { 11 | } 12 | 13 | Websocket_Request::~Websocket_Request(){ 14 | 15 | } 16 | 17 | int Websocket_Request::fetch_websocket_info(char *msg){ 18 | int pos = 0; 19 | fetch_fin(msg, pos); 20 | fetch_opcode(msg, pos); 21 | fetch_mask(msg, pos); 22 | fetch_payload_length(msg, pos); 23 | fetch_masking_key(msg, pos); 24 | return fetch_payload(msg, pos); 25 | } 26 | 27 | void Websocket_Request::print(){ 28 | DEBUG_LOG("WEBSOCKET PROTOCOL\n" 29 | "FIN: %d\n" 30 | "OPCODE: %d\n" 31 | "MASK: %d\n" 32 | "PAYLOADLEN: %d\n" 33 | "PAYLOAD: %s", 34 | fin_, opcode_, mask_, payload_length_, payload_); 35 | 36 | reset(); 37 | } 38 | 39 | void Websocket_Request::reset(){ 40 | fin_ = 0; 41 | opcode_ = 0; 42 | mask_ = 0; 43 | memset(masking_key_, 0, sizeof(masking_key_)); 44 | payload_length_ = 0; 45 | memset(payload_, 0, sizeof(payload_)); 46 | } 47 | 48 | int Websocket_Request::fetch_fin(char *msg, int &pos){ 49 | fin_ = (unsigned char)msg[pos] >> 7; 50 | return 0; 51 | } 52 | 53 | int Websocket_Request::fetch_opcode(char *msg, int &pos){ 54 | opcode_ = msg[pos] & 0x0f; 55 | pos++; 56 | return 0; 57 | } 58 | 59 | int Websocket_Request::fetch_mask(char *msg, int &pos){ 60 | mask_ = (unsigned char)msg[pos] >> 7; 61 | return 0; 62 | } 63 | 64 | int Websocket_Request::fetch_masking_key(char *msg, int &pos){ 65 | if(mask_ != 1) 66 | return 0; 67 | for(int i = 0; i < 4; i++) 68 | masking_key_[i] = msg[pos + i]; 69 | pos += 4; 70 | return 0; 71 | } 72 | 73 | int Websocket_Request::fetch_payload_length(char *msg, int &pos){ 74 | payload_length_ = msg[pos] & 0x7f; 75 | pos++; 76 | if(payload_length_ == 126){ 77 | uint16_t length = 0; 78 | memcpy(&length, msg + pos, 2); 79 | pos += 2; 80 | payload_length_ = ntohs(length); 81 | } 82 | else if(payload_length_ == 127){ 83 | uint32_t length = 0; 84 | memcpy(&length, msg + pos, 4); 85 | pos += 4; 86 | payload_length_ = ntohl(length); 87 | } 88 | return 0; 89 | } 90 | 91 | int Websocket_Request::fetch_payload(char *msg, int &pos){ 92 | memset(payload_, 0, sizeof(payload_)); 93 | if(mask_ != 1){ 94 | memcpy(payload_, msg + pos, payload_length_); 95 | } 96 | else { 97 | for(uint i = 0; i < payload_length_; i++){ 98 | int j = i % 4; 99 | payload_[i] = msg[pos + i] ^ masking_key_[j]; 100 | } 101 | } 102 | pos += payload_length_; 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /websocket_request.h: -------------------------------------------------------------------------------- 1 | #ifndef __WEBSOCKET_REQUEST__ 2 | #define __WEBSOCKET_REQUEST__ 3 | 4 | #include 5 | #include 6 | #include "debug_log.h" 7 | 8 | class Websocket_Request { 9 | public: 10 | Websocket_Request(); 11 | ~Websocket_Request(); 12 | int fetch_websocket_info(char *msg); 13 | void print(); 14 | void reset(); 15 | 16 | private: 17 | int fetch_fin(char *msg, int &pos); 18 | int fetch_opcode(char *msg, int &pos); 19 | int fetch_mask(char *msg, int &pos); 20 | int fetch_masking_key(char *msg, int &pos); 21 | int fetch_payload_length(char *msg, int &pos); 22 | int fetch_payload(char *msg, int &pos); 23 | private: 24 | uint8_t fin_; 25 | uint8_t opcode_; 26 | uint8_t mask_; 27 | uint8_t masking_key_[4]; 28 | uint64_t payload_length_; 29 | char payload_[2048]; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /websocket_respond.cpp: -------------------------------------------------------------------------------- 1 | #include "websocket_respond.h" 2 | 3 | Websocket_Respond::Websocket_Respond() { } 4 | 5 | Websocket_Respond::~Websocket_Respond() { } 6 | -------------------------------------------------------------------------------- /websocket_respond.h: -------------------------------------------------------------------------------- 1 | #ifndef __WEBSOCKET_RESPOND__ 2 | #define __WEBSOCKET_RESPOND__ 3 | 4 | class Websocket_Respond { 5 | public: 6 | Websocket_Respond(); 7 | ~Websocket_Respond(); 8 | }; 9 | 10 | #endif 11 | --------------------------------------------------------------------------------