ws.h (6283B)
1 #ifndef WS_H 2 #define WS_H 3 4 #include <openssl/evp.h> 5 #include <openssl/sha.h> 6 7 #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 8 9 #define WS_KEY_LENGTH ((SHA_DIGEST_LENGTH * 4) / 3) 10 11 static inline int 12 ws_key_digest(unsigned char *buf, size_t len, unsigned char out[static WS_KEY_LENGTH]) 13 { 14 unsigned char concat[128], sha1[SHA_DIGEST_LENGTH]; 15 size_t concat_len = snprintf((char *) concat, sizeof concat, "%.*s%s", 16 (int) len, buf, WS_GUID); 17 SHA1(concat, concat_len, sha1); 18 return EVP_EncodeBlock(out, sha1, sizeof sha1); 19 } 20 21 static inline uint16_t 22 ws_hton16(uint16_t v) 23 { 24 return htons(v); 25 } 26 27 static inline uint32_t 28 ws_hton32(uint32_t v) 29 { 30 return htonl(v); 31 } 32 33 static inline uint64_t 34 ws_hton64(uint64_t v) 35 { 36 if (1 == htons(1)) return v; 37 38 uint32_t lower = (v & 0xffffffff), upper = (v >> 32); 39 uint64_t res = (((uint64_t) htonl(lower)) << 32) | htonl(upper); 40 return res; 41 } 42 43 static inline uint16_t 44 ws_ntoh16(uint16_t v) 45 { 46 return ntohs(v); 47 } 48 49 static inline uint32_t 50 ws_ntoh32(uint32_t v) 51 { 52 return ntohl(v); 53 } 54 55 static inline uint64_t 56 ws_ntoh64(uint64_t v) 57 { 58 if (1 == htons(1)) return v; 59 60 uint32_t lower = (v & 0xffffffff), upper = (v >> 32); 61 uint64_t res = (((uint64_t) ntohl(lower)) << 32) | htonl(upper); 62 return res; 63 } 64 65 enum ws_error { 66 /* 0 - 999 unused */ 67 68 WS_ERROR_OK = 1000, 69 WS_ERROR_GOING_AWAY = 1001, 70 WS_ERROR_PROTOCOL_ERROR = 1002, 71 WS_ERROR_UNSUPPORTED_DATA = 1003, 72 73 /* 1004 reserved */ 74 75 WS_ERROR_NO_CODE_RECIEVED = 1005, 76 WS_ERROR_CLOSED_ABNORMALLY = 1006, 77 78 WS_ERROR_INVALID_PAYLOAD_DATA = 1007, 79 WS_ERROR_POLICY_VIOLATED = 1008, 80 WS_ERROR_MESSAGE_TOO_BIG = 1009, 81 WS_ERROR_UNSUPPORTED_EXTENSION = 1010, 82 WS_ERROR_INTERNAL_SERVER_ERROR = 1011, 83 84 /* 1012 - 1014 reserved */ 85 86 WS_ERROR_TLS_HANDSHAKE_FAILURE = 1015, 87 88 /* 3000 - 3999 reserved */ 89 90 /* 4000 - 4999 reserved for application */ 91 }; 92 93 enum ws_opcode { 94 WS_CONT = 0x0, 95 WS_DATA_UTF8 = 0x1, 96 WS_DATA_BINARY = 0x2, 97 98 /* 0x3 - 0x7 reserved */ 99 100 WS_CLOSE = 0x8, 101 WS_PING = 0x9, 102 WS_PONG = 0xa, 103 104 /* 0xb - 0xf reserved */ 105 }; 106 107 struct ws_frame { 108 enum ws_opcode opcode; 109 uint8_t fin; 110 uint8_t res; 111 uint64_t len; 112 uint32_t mask; 113 }; 114 115 static inline int 116 ws_frame_recv(int sock, struct ws_frame *out) 117 { 118 int res; 119 120 uint8_t hdr[8]; 121 122 if ((res = recv(sock, hdr, 2, 0)) < 0) 123 return -1; 124 125 out->fin = (hdr[0] >> 7) & 0x1; 126 out->res = (hdr[0] >> 4) & 0x7; 127 out->opcode = hdr[0] & 0xf; 128 129 int masked = (hdr[1] >> 7), len = hdr[1] & 0x7f; 130 131 if (len == 127) { 132 if ((res = recv(sock, hdr, 8, 0)) < 0) 133 return -1; 134 135 uint64_t raw = *((uint64_t *) hdr); 136 out->len = ws_ntoh64(raw); 137 } else if (len == 126) { 138 if ((res = recv(sock, hdr, 2, 0)) < 0) 139 return -1; 140 141 uint16_t raw = *((uint16_t *) hdr); 142 out->len = ws_ntoh16(raw); 143 } else /* len < 126 */ { 144 out->len = len; 145 } 146 147 if (masked) { 148 if ((res = recv(sock, hdr, 4, 0)) < 0) 149 return -1; 150 151 uint32_t raw = *((uint32_t *) hdr); 152 out->mask = ws_ntoh32(raw); 153 } else { 154 out->mask = 0; 155 } 156 157 return 0; 158 } 159 160 static inline int 161 ws_frame_send(int sock, struct ws_frame const *frame) 162 { 163 int res; 164 165 /* serialise frame header */ 166 uint8_t len; 167 if (frame->len < 126) { 168 len = frame->len; 169 } else if (frame->len <= UINT16_MAX) { 170 len = 126; 171 } else { 172 len = 127; 173 } 174 175 uint8_t ptr = 0; 176 uint8_t hdr[14]; 177 hdr[ptr++] = ((!!(frame->fin)) << 7) | ((frame->res & 0x7) << 4) | (frame->opcode & 0xf); 178 hdr[ptr++] = ((!!(frame->mask)) << 7) | len; 179 180 if (len == 126) { 181 uint16_t raw = ws_hton16(frame->len); 182 memcpy(hdr + ptr, &raw, 2); 183 ptr += 2; 184 } 185 186 if (len == 127) { 187 uint64_t raw = ws_hton64(frame->len); 188 memcpy(hdr + ptr, &raw, 8); 189 ptr += 8; 190 } 191 192 if (frame->mask) { 193 uint32_t raw = ws_hton32(frame->mask); 194 memcpy(hdr + ptr, &raw, 4); 195 ptr += 4; 196 } 197 198 /* send frame header */ 199 if ((res = send(sock, hdr, ptr, 0)) < 0) 200 return -1; 201 202 return 0; 203 } 204 205 static inline int 206 ws_data_recv(int sock, struct ws_frame const *frame, unsigned char *buf, size_t cap) 207 { 208 assert(frame->len <= cap); 209 210 int res; 211 212 uint64_t remaining = frame->len; 213 214 unsigned char payload[1024]; 215 unsigned char key[4] = { 216 (frame->mask & 0xff000000) >> 24, 217 (frame->mask & 0x00ff0000) >> 16, 218 (frame->mask & 0x0000ff00) >> 8, 219 (frame->mask & 0x000000ff), 220 }; 221 222 do { 223 size_t masked = (sizeof payload < remaining) ? sizeof payload : remaining; 224 225 /* receive masked payload */ 226 size_t masked_recv = 0; 227 do { 228 if ((res = recv(sock, payload + masked_recv, masked - masked_recv, 0)) < 0) 229 return -1; 230 masked_recv += res; 231 } while (masked_recv < masked); 232 233 /* unmask payload */ 234 for (size_t i = 0; i < masked; i++) 235 *buf++ = payload[i] ^ key[i % 4]; 236 237 remaining -= masked; 238 } while (remaining); 239 240 return 0; 241 } 242 243 static inline int 244 ws_data_send(int sock, struct ws_frame const *frame, unsigned char const *buf) 245 { 246 int res; 247 248 /* send frame payload */ 249 uint64_t remaining = frame->len; 250 251 unsigned char payload[1024]; 252 unsigned char key[4] = { 253 (frame->mask & 0xff000000) >> 24, 254 (frame->mask & 0x00ff0000) >> 16, 255 (frame->mask & 0x0000ff00) >> 8, 256 (frame->mask & 0x000000ff), 257 }; 258 259 do { 260 size_t masked = (sizeof payload < remaining) ? sizeof payload : remaining; 261 262 /* mask payload */ 263 for (size_t i = 0; i < masked; i++) 264 payload[i] = *buf++ ^ key[i % 4]; 265 266 /* send masked payload */ 267 size_t masked_send = 0; 268 do { 269 if ((res = send(sock, payload + masked_send, masked - masked_send, 0)) < 0) return -1; 270 masked_send += res; 271 } while (masked_send < masked); 272 273 remaining -= masked; 274 } while (remaining); 275 276 return 0; 277 } 278 279 static inline int 280 ws_msg_send(int sock, enum ws_opcode opcode, unsigned char *buf, size_t len, uint32_t mask, int fragment) 281 { 282 struct ws_frame frame; 283 frame.opcode = opcode; 284 frame.fin = !fragment; 285 frame.res = 0; 286 frame.len = len; 287 frame.mask = mask; 288 289 if (ws_frame_send(sock, &frame) < 0) 290 return -1; 291 292 return ws_data_send(sock, &frame, buf); 293 } 294 295 static inline int 296 ws_close(int sock, enum ws_error err, unsigned char *msg, size_t len, uint32_t mask) 297 { 298 assert(len <= 123); 299 300 struct ws_frame frame; 301 frame.opcode = WS_CLOSE; 302 frame.fin = 1; 303 frame.res = 0; 304 frame.len = len; 305 frame.mask = mask; 306 307 if (ws_frame_send(sock, &frame) < 0) 308 return -1; 309 310 /* send optional error code */ 311 int res; 312 uint16_t raw = ws_hton16(err); 313 if ((res = send(sock, &raw, sizeof raw, 0)) < 0) 314 return -1; 315 316 return ws_data_send(sock, &frame, msg); 317 } 318 319 #endif /* WS_H */