diff --git a/client_test.c b/client_test.c index dac3f6e..3cd921d 100644 --- a/client_test.c +++ b/client_test.c @@ -104,11 +104,11 @@ main(int argc, char **argv) printf("received payload of " SSIZE_T_PARAM " bytes:\n---\n%s\n---\n", len, out); - assert(0 == dumb_close(&ws)); + assert(DWS_OK == dumb_close(&ws)); printf("sent a CLOSE frame!\n"); // Our socket should be closed now - assert(-1 == dumb_recv(&ws, buf, sizeof(buf))); + assert(DWS_ERR_READ == dumb_recv(&ws, buf, sizeof(buf))); printf("socket looks closed!\n"); return 0; diff --git a/dws.c b/dws.c index a0a2bfd..ac256cf 100644 --- a/dws.c +++ b/dws.c @@ -133,7 +133,7 @@ choose(unsigned int upper_bound) * * Since RFC6455 says we don't care about the random 16-byte value used * for the key (the server never decodes it), why bother actually writing - * propery base64 encoding when we can just pick 22 valid base64 characters + * a proper base64 encoding when we can just pick 22 valid base64 characters * to make our key? */ static void @@ -202,8 +202,8 @@ ws_read(struct websocket *ws, void *buf, size_t buflen) break; } else if (sz == -1) { - // TODO: check some common errno's and return something better. - printf("%s: err %s\n", __func__, strerror(errno)); + // TODO: check some common errno's and return + // something better. return -1; } } @@ -315,8 +315,6 @@ ws_read_txt(struct websocket *ws, void *buf, size_t buflen) * * Will write the entirety of the given buffer. Does not currently use any * poll like functionality, so will busy poll the socket! - * - * XXX: for now failures to write are fatal :X */ static ssize_t ws_write(struct websocket *ws, const void *buf, size_t buflen) @@ -325,7 +323,7 @@ ws_write(struct websocket *ws, const void *buf, size_t buflen) char *_buf; if (buflen > INT_MAX) - crap(1, "%s: buflen too large", __func__); + return -1; if (buflen == 0) return 0; @@ -460,7 +458,7 @@ dumb_frame(uint8_t *frame, const uint8_t *data, size_t len) // Just a quick safety check: we don't do large payloads if (len > (1 << 24)) - return -1; + return DWS_ERR_TOO_LARGE; // Pretend we're in Eyes Wide Shut dumb_mask(mask); @@ -490,8 +488,8 @@ dumb_frame(uint8_t *frame, const uint8_t *data, size_t len) * * Returns: * 0 on success, - * -1 if it failed to generate the handshake buffer, - * -2 if it received an invalid handshake response, + * DWS_ERR_HANDSHAKE_BUF if it failed to generate the handshake buffer, + * DWS_ERR_HANDSHAKE_ERR if it received an invalid handshake response, * fatal error otherwise. */ int @@ -507,7 +505,7 @@ dumb_handshake(struct websocket *ws, const char *path, const char *proto) len = snprintf(buf, sizeof(buf), HANDSHAKE_TEMPLATE, path, ws->host, ws->port, key, proto); if (len < 1) - return -1; + return DWS_ERR_HANDSHAKE_BUF; // Send our upgrade request. sz = ws_write(ws, buf, len); @@ -517,14 +515,13 @@ dumb_handshake(struct websocket *ws, const char *path, const char *proto) memset(buf, 0, sizeof(buf)); len = ws_read_txt(ws, buf, sizeof(buf)); if (len == -1) - return -1; + return DWS_ERR_HANDSHAKE_BUF; /* XXX: If we gave a crap, we'd validate the returned key per the * requirements of RFC6455 sec. 4.1, but we don't. */ if (memcmp(server_handshake, buf, sizeof(server_handshake) - 1)) { - printf("%s: bad handshake:\n%s\n", __func__, buf); - ret = -2; + ret = DWS_ERR_HANDSHAKE_RES; } return ret; @@ -543,9 +540,9 @@ dumb_handshake(struct websocket *ws, const char *path, const char *proto) * * Returns: * 0 on success, - * -1 if it failed to create a socket, - * -2 if it failed to resolve host (check h_errno), - * -3 if it failed to connect(2). + * DWS_ERR_CONN_CREATE if it failed to create a socket, + * DWS_ERR_CONN_RESOLVE if it failed to resolve host (check h_errno), + * DWS_ERR_CONN_CONNECT if it failed to connect(2). */ int dumb_connect(struct websocket *ws, const char *host, uint16_t port) @@ -564,7 +561,7 @@ dumb_connect(struct websocket *ws, const char *host, uint16_t port) s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) - return -1; + return DWS_ERR_CONN_CREATE; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; @@ -575,15 +572,15 @@ dumb_connect(struct websocket *ws, const char *host, uint16_t port) memset(port_buf, 0, sizeof(port_buf)); snprintf(port_buf, sizeof(port_buf), "%d", port); if (getaddrinfo(host, port_buf, &hints, &res)) - return -2; + return DWS_ERR_CONN_RESOLVE; // XXX: for now we're lazy and only try the first addrinfo if (connect(s, res->ai_addr, res->ai_addrlen)) - return -3; + return DWS_ERR_CONN_CONNECT; // Set to non blocking if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) - return -3; + return DWS_ERR_CONN_CONNECT; // Store some state ws->port = port; @@ -651,8 +648,8 @@ dumb_connect_tls(struct websocket *ws, const char *host, uint16_t port, * * Returns: * the amount of bytes sent, - * -1 on failure to calloc(3) a buffer for the dumb websocket frame, - * or whatever ws_write might return on error (zero or a negative value) + * DWS_ERR_MALLOC on failure to calloc(3) a buffer for the dumb websocket + * frame, or whatever ws_write might return on error (zero or a negative value) */ ssize_t dumb_send(struct websocket *ws, const void *payload, size_t len) @@ -663,7 +660,7 @@ dumb_send(struct websocket *ws, const void *payload, size_t len) // We need payload size + 14 bytes minimum, but pad a little extra frame = calloc(1, len + 16); if (frame == NULL) - return -1; + return DWS_ERR_MALLOC; frame_len = dumb_frame(frame, payload, len); if (frame_len < 0) @@ -691,7 +688,7 @@ dumb_send(struct websocket *ws, const void *payload, size_t len) * * Returns: * the number of bytes received in the payload (not including frame headers), - * -1 on failure to read(2) data, DWS_WANT_POLL or DWS_SHUTDOWN. + * DWS_ERR_READ on failure to read(2) data, DWS_WANT_POLL or DWS_SHUTDOWN. */ ssize_t dumb_recv(struct websocket *ws, void *buf, size_t buflen) @@ -702,12 +699,15 @@ dumb_recv(struct websocket *ws, void *buf, size_t buflen) // Read first 2 bytes to figure out the framing details. n = ws_read(ws, frame, 2); - if (n < 0) + if (n < 0) { + if (n == -1) + return DWS_ERR_READ; return n; + } // Now to validate the frame... if (!(frame[0] & 0x80)) { - // XXX: We don't currently fragmentation + // XXX: We don't currently support fragmentation crap(1, "%s: fragmentation unsupported", __func__); } @@ -737,20 +737,20 @@ dumb_recv(struct websocket *ws, void *buf, size_t buflen) // arrives in network byte order. n = ws_read_all(ws, frame + 2, 2); if (n < 2) - return -1; + return DWS_ERR_READ; payload_len = frame[2] << 8; payload_len += frame[3]; } else if (payload_len > 126) crap(1, "%s: unsupported payload size", __func__); // We can now read the the payload, if there is one. - payload_len = MIN(payload_len, buflen); + payload_len = MIN((size_t)payload_len, buflen); if (payload_len == 0) return 0; - n = ws_read_all(ws, buf, (size_t) payload_len); + n = ws_read_all(ws, buf, (size_t)payload_len); if (n < payload_len) - return -1; + return DWS_ERR_READ; return payload_len; } @@ -766,9 +766,9 @@ dumb_recv(struct websocket *ws, void *buf, size_t buflen) * * Returns: * 0 on success, - * -1 on failure during write(2), - * -2 on failure to receive(2) the response, - * -3 on the response being invalid (i.e. not a PONG) + * DWS_ERR_WRITE on failure during write(2), + * DWS_ERR_READ on failure to receive(2) the response, + * DWS_ERR_INVALID on the response being invalid (i.e. not a PONG) */ int dumb_ping(struct websocket *ws) @@ -784,18 +784,18 @@ dumb_ping(struct websocket *ws) len = ws_write(ws, frame, (size_t) len); if (len < 1) - return -1; + return DWS_ERR_WRITE; memset(frame, 0, sizeof(frame)); // Read first 2 bytes. len = ws_read_all(ws, frame, 2); if (len < 0) - return -2; + return DWS_ERR_READ; // We should have a PONG reply. if (frame[0] != (0x80 + PONG)) - return -3; + return DWS_ERR_INVALID; payload_len = frame[1] & 0x7F; if (payload_len >= 126) @@ -803,9 +803,10 @@ dumb_ping(struct websocket *ws) // Dump the rest of the data on the floor. if (payload_len > 0) { - len = ws_read_all(ws, frame + 2, MIN(payload_len, sizeof(frame) - 2)); + len = ws_read_all(ws, frame + 2, + MIN((size_t)payload_len, sizeof(frame) - 2)); if (len < 1) - return -3; + return DWS_ERR_INVALID; } return 0; @@ -851,9 +852,9 @@ ws_shutdown(struct websocket *ws) * * Returns: * 0 on success, - * -1 on failure to send(2) the close frame, - * -2 on failure to read(2) a response, - * -3 on a response being invalid (i.e. not a CLOSE), + * DWS_ERR_WRITE on failure to send(2) the close frame, + * DWS_ERR_READ on failure to read(2) a response, + * DWS_ERR_INVALID on a response being invalid (i.e. not a CLOSE), */ int dumb_close(struct websocket *ws) @@ -869,20 +870,20 @@ dumb_close(struct websocket *ws) len = ws_write(ws, frame, (size_t) len); if (len < 1) - return -1; + return DWS_ERR_WRITE; memset(frame, 0, sizeof(frame)); // A valid RFC6455 websocket server MUST send a Close frame in response // Read first 2 bytes. - len = ws_read_all(ws, frame, 2); + len = ws_read_all(ws, frame, 2); if (len != 2) - return -2; + return DWS_ERR_READ; // If we don't have a CLOSE frame...someone screwed up before calling // dumb_close and there's still unread data! if (frame[0] != (0x80 + CLOSE)) - return -3; + return DWS_ERR_INVALID; payload_len = frame[1] & 0x7F; if (payload_len > 126) @@ -890,9 +891,10 @@ dumb_close(struct websocket *ws) // Dump the rest of the data on the floor. if (payload_len > 0) { - len = ws_read_all(ws, frame + 2, MIN(payload_len, sizeof(frame) - 2)); + len = ws_read_all(ws, frame + 2, + MIN((size_t)payload_len, sizeof(frame) - 2)); if (len < 1) - return -4; + return DWS_ERR_READ; } ws_shutdown(ws); diff --git a/dws.h b/dws.h index c831bcb..672f59b 100644 --- a/dws.h +++ b/dws.h @@ -58,10 +58,29 @@ struct websocket { // TODO: add basic auth details? }; +/* + * Possible non-error responses from dumb_recv() based on the state of the + * socket or the next websocket control message (e.g. PING). + */ #define DWS_WANT_POLL -2 #define DWS_WANT_PONG -3 #define DWS_SHUTDOWN -4 +/* + * Simplistic error code approach using define's. + */ +#define DWS_OK 0 +#define DWS_ERR_CONN_CREATE -1 +#define DWS_ERR_CONN_RESOLVE -2 +#define DWS_ERR_CONN_CONNECT -3 +#define DWS_ERR_MALLOC -4 +#define DWS_ERR_READ -5 +#define DWS_ERR_WRITE -6 +#define DWS_ERR_INVALID -7 +#define DWS_ERR_HANDSHAKE_BUF -8 +#define DWS_ERR_HANDSHAKE_RES -9 +#define DWS_ERR_TOO_LARGE -10 + int dumb_connect(struct websocket *ws, const char*, uint16_t); int dumb_connect_tls(struct websocket *ws, const char*, uint16_t, int); int dumb_handshake(struct websocket *s, const char*, const char*);