2 * This is free and unencumbered software released into the public domain.
4 * Anyone is free to copy, modify, publish, use, compile, sell, or
5 * distribute this software, either in source code form or as a compiled
6 * binary, for any purpose, commercial or non-commercial, and by any
9 * In jurisdictions that recognize copyright laws, the author or authors
10 * of this software dedicate any and all copyright interest in the
11 * software to the public domain. We make this dedication for the benefit
12 * of the public at large and to the detriment of our heirs and
13 * successors. We intend this dedication to be an overt act of
14 * relinquishment in perpetuity of all present and future rights to this
15 * software under copyright law.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
28 #include <arpa/inet.h>
39 #define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
42 tob64(unsigned char ch)
62 b64encode(unsigned char *in, size_t ilen, char *out, size_t olen)
67 if ((r = tob64((x) & 0x3F)) == -1) \
89 SET(in[0] << 4 | in[1] >> 4);
96 SET(in[0] << 4 | in[1] >> 4);
97 SET(in[1] << 2 | in[2] >> 6);
116 ws_accept_hdr(const char *secret, char *out, size_t olen)
119 uint8_t hash[SHA1_DIGEST_LENGTH];
122 SHA1Update(&ctx, secret, strlen(secret));
123 SHA1Update(&ctx, WS_GUID, strlen(WS_GUID));
124 SHA1Final(hash, &ctx);
126 return (b64encode(hash, sizeof(hash), out, olen));
130 ws_read(struct client *clt, int *type, size_t *len)
132 struct buffer *rbuf = &clt->bio.rbuf;
135 uint8_t first, second, op, plen;
137 *type = WST_UNKNOWN, *len = 0;
144 memcpy(&first, &rbuf->buf[0], sizeof(first));
145 memcpy(&second, &rbuf->buf[1], sizeof(second));
147 /* for the close message this doesn't seem to be the case... */
149 /* the reserved bits must be zero, don't care about FIN */
150 if ((first & 0x0E) != 0) {
156 /* mask must be set for messages sent by the clients */
157 if ((second >> 7) != 1) {
163 plen = second & 0x7F;
165 /* don't support extended payload length for now */
183 if (rbuf->len < sizeof(first) + sizeof(second) + sizeof(mask) + plen) {
188 buf_drain(rbuf, 2); /* header */
189 memcpy(&mask, rbuf->buf, sizeof(mask));
192 /* decode the payload */
193 for (i = 0; i < plen; ++i)
194 rbuf->buf[i] ^= mask >> (8 * (i % 4));
200 ws_compose(struct client *clt, int type, const void *data, size_t len)
202 struct bufio *bio = &clt->bio;
204 uint8_t first, second;
206 first = (type & 0x0F) | 0x80;
214 * for the extended length, the most significant bit
215 * must be zero. We could use the 64 bit field but
225 if (bufio_compose(bio, &first, 1) == -1 ||
226 bufio_compose(bio, &second, 1) == -1)
229 if (extlen != 0 && bufio_compose(bio, &extlen, sizeof(extlen)) == -1)
232 if (bufio_compose(bio, data, len) == -1)