diff --git a/src/lib/fastcgi.c b/src/lib/fastcgi.c index 15be5a1..9a73003 100644 --- a/src/lib/fastcgi.c +++ b/src/lib/fastcgi.c @@ -15,7 +15,6 @@ #include #include #include -#include // TODO use pipes for stdin, stdout, stderr in FastCGI @@ -28,20 +27,14 @@ char *fastcgi_add_param(char *buf, const char *key, const char *value) { ptr[0] = (char) (key_len & 0x7F); ptr++; } else { - ptr[0] = (char) (0x80 | (key_len >> 24)); - ptr[1] = (char) ((key_len >> 16) & 0xFF); - ptr[2] = (char) ((key_len >> 8) & 0xFF); - ptr[3] = (char) (key_len & 0xFF); + *((int *) ptr) = htonl(0x80000000 | key_len); ptr += 4; } if (val_len <= 127) { ptr[0] = (char) (val_len & 0x7F); ptr++; } else { - ptr[0] = (char) (0x80 | (val_len >> 24)); - ptr[1] = (char) ((val_len >> 16) & 0xFF); - ptr[2] = (char) ((val_len >> 8) & 0xFF); - ptr[3] = (char) (val_len & 0xFF); + *((int *) ptr) = htonl(0x80000000 | val_len); ptr += 4; } @@ -53,6 +46,33 @@ char *fastcgi_add_param(char *buf, const char *key, const char *value) { return ptr; } +int fastcgi_send_data(fastcgi_cnx_t *cnx, unsigned char type, unsigned short len, void *data) { + // build header + FCGI_Header header = { + .version = FCGI_VERSION_1, + .type = type, + .requestId = htons(cnx->req_id), + .contentLength = htons(len), + .paddingLength = 0, + .reserved = 0, + }; + + // send FastCGI header with MSG_MORE flag + if (sock_send_x(&cnx->socket, &header, sizeof(header), (len != 0) ? MSG_MORE : 0) == -1) { + error("Unable to send to FastCGI socket"); + return -1; + } + + // send data (if available) + if (sock_send_x(&cnx->socket, data, len, 0) == -1) { + error("Unable to send to FastCGI socket"); + return -1; + } + + // return bytes sent totally + return len + (int) sizeof(header); +} + int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock *client, const http_req *req, const http_uri *uri) { conn->mode = mode; conn->req_id = (req_num + 1) & 0xFFFF; @@ -60,45 +80,32 @@ int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock conn->out_off = 0; conn->webroot = uri->webroot; - int fcgi_sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (fcgi_sock < 0) { + conn->socket.enc = 0; + if ((conn->socket.socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { error("Unable to create unix socket"); return -1; } - conn->socket = fcgi_sock; - struct sockaddr_un sock_addr = {AF_UNIX}; + struct sockaddr_un sock_addr = { AF_UNIX }; if (conn->mode == FASTCGI_BACKEND_PHP) { - snprintf(sock_addr.sun_path, sizeof(sock_addr.sun_path) - 1, "%s", PHP_FPM_SOCKET); + strcpy(sock_addr.sun_path, PHP_FPM_SOCKET); } - if (connect(conn->socket, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0) { + if (connect(conn->socket.socket, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) != 0) { error("Unable to connect to unix socket of FastCGI socket"); return -1; } - FCGI_Header header = { - .version = FCGI_VERSION_1, - .requestId = htons(conn->req_id), - .paddingLength = 0, - .reserved = 0 + FCGI_BeginRequestBody begin = { + .role = htons(FCGI_RESPONDER), + .flags = 0, + .reserved = {0}, }; - header.type = FCGI_BEGIN_REQUEST; - header.contentLength = htons(sizeof(FCGI_BeginRequestBody)); - FCGI_BeginRequestRecord begin = { - header, - {.roleB1 = (FCGI_RESPONDER >> 8) & 0xFF, .roleB0 = FCGI_RESPONDER & 0xFF, .flags = 0} - }; - if (send(conn->socket, &begin, sizeof(begin), 0) != sizeof(begin)) { - error("Unable to send to FastCGI socket"); - return -2; - } - - char param_buf[4096]; - char buf0[256]; - char *param_ptr = param_buf + sizeof(header); + if (fastcgi_send_data(conn, FCGI_BEGIN_REQUEST, sizeof(begin), &begin) == -1) + return -1; + char param_buf[4096], buf0[256], *param_ptr = param_buf; param_ptr = fastcgi_add_param(param_ptr, "REDIRECT_STATUS", "CGI"); param_ptr = fastcgi_add_param(param_ptr, "DOCUMENT_ROOT", uri->webroot); param_ptr = fastcgi_add_param(param_ptr, "GATEWAY_INTERFACE", "CGI/1.1"); @@ -170,39 +177,18 @@ int fastcgi_init(fastcgi_cnx_t *conn, int mode, unsigned int req_num, const sock param_ptr = fastcgi_add_param(param_ptr, buf0, http_field_get_value(f)); } - unsigned short param_len = param_ptr - param_buf - sizeof(header); - header.type = FCGI_PARAMS; - header.contentLength = htons(param_len); - memcpy(param_buf, &header, sizeof(header)); - if (send(conn->socket, param_buf, param_len + sizeof(header), 0) != param_len + sizeof(header)) { - error("Unable to send to FastCGI socket"); - return -2; - } + if (fastcgi_send_data(conn, FCGI_PARAMS, param_ptr - param_buf, param_buf) == -1) + return -1; - header.type = FCGI_PARAMS; - header.contentLength = htons(0); - if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) { - error("Unable to send to FastCGI socket"); - return -2; - } + if (fastcgi_send_data(conn, FCGI_PARAMS, 0, NULL) == -1) + return -1; return 0; } int fastcgi_close_stdin(fastcgi_cnx_t *conn) { - FCGI_Header header = { - .version = FCGI_VERSION_1, - .type = FCGI_STDIN, - .requestId = htons(conn->req_id), - .contentLength = htons(0), - .paddingLength = 0, - .reserved = 0 - }; - - if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) { - error("Unable to send to FastCGI socket"); - return -2; - } + if (fastcgi_send_data(conn, FCGI_STDIN, 0, NULL) == -1) + return -1; return 0; } @@ -282,8 +268,7 @@ int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) { int err = 0; while (1) { - ret = recv(conn->socket, &header, sizeof(header), 0); - if (ret != sizeof(header)) { + if (sock_recv_x(&conn->socket, &header, sizeof(header), 0) == -1) { res->status = http_get_status(500); sprintf(err_msg, "Unable to communicate with FastCGI socket."); error("Unable to receive from FastCGI socket"); @@ -292,8 +277,7 @@ int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) { req_id = ntohs(header.requestId); content_len = ntohs(header.contentLength); content = malloc(content_len + header.paddingLength); - ret = recv(conn->socket, content, content_len + header.paddingLength, 0); - if (ret != (content_len + header.paddingLength)) { + if (sock_recv_x(&conn->socket, content, content_len + header.paddingLength, 0) == -1) { res->status = http_get_status(500); sprintf(err_msg, "Unable to communicate with FastCGI socket."); error("Unable to receive from FastCGI socket"); @@ -307,16 +291,14 @@ int fastcgi_header(fastcgi_cnx_t *conn, http_res *res, char *err_msg) { if (header.type == FCGI_END_REQUEST) { FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; - int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | - body->appStatusB0; + int app_status = ntohl(body->appStatus); if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { error("FastCGI protocol error: %i", body->protocolStatus); } if (app_status != 0) { error("FastCGI app terminated with exit code %i", app_status); } - close(conn->socket); - conn->socket = 0; + sock_close(&conn->socket); free(content); return 1; } else if (header.type == FCGI_STDERR) { @@ -379,7 +361,7 @@ int fastcgi_send(fastcgi_cnx_t *conn, sock *client, int flags) { long ret; char buf0[256], *content, *ptr; int len; - unsigned short req_id, content_len; + unsigned short content_len; if (conn->out_buf != NULL && conn->out_len > conn->out_off) { content = conn->out_buf; @@ -389,23 +371,18 @@ int fastcgi_send(fastcgi_cnx_t *conn, sock *client, int flags) { } while (1) { - ret = recv(conn->socket, &header, sizeof(header), 0); - if (ret < 0) { + if ((sock_recv_x(&conn->socket, &header, sizeof(header), 0)) == -1) { error("Unable to receive from FastCGI socket"); return -1; - } else if (ret != sizeof(header)) { - error("Unable to receive from FastCGI socket: received len (%li) != header len (%li)", ret, sizeof(header)); - return -1; } - req_id = ntohs(header.requestId); content_len = ntohs(header.contentLength); content = malloc(content_len + header.paddingLength); ptr = content; long rcv_len = 0; while (rcv_len < content_len + header.paddingLength) { - ret = recv(conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0); + ret = sock_recv(&conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0); if (ret < 0) { error("Unable to receive from FastCGI socket"); free(content); @@ -416,16 +393,14 @@ int fastcgi_send(fastcgi_cnx_t *conn, sock *client, int flags) { if (header.type == FCGI_END_REQUEST) { FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; - int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | - body->appStatusB0; + int app_status = ntohl(body->appStatus); if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { error("FastCGI protocol error: %i", body->protocolStatus); } if (app_status != 0) { error("FastCGI app terminated with exit code %i", app_status); } - close(conn->socket); - conn->socket = 0; + sock_close(&conn->socket); free(content); if (flags & FASTCGI_CHUNKED) { @@ -457,29 +432,24 @@ int fastcgi_dump(fastcgi_cnx_t *conn, char *buf, long len) { long ret; char buf0[256]; char *content, *ptr = buf; - unsigned short req_id, content_len; + unsigned short content_len; if (conn->out_buf != NULL && conn->out_len > conn->out_off) { ptr += snprintf(ptr, len, "%.*s", conn->out_len - conn->out_off, conn->out_buf + conn->out_off); } while (1) { - ret = recv(conn->socket, &header, sizeof(header), 0); - if (ret < 0) { + if (sock_recv_x(&conn->socket, &header, sizeof(header), 0) == -1) { error("Unable to receive from FastCGI socket"); return -1; - } else if (ret != sizeof(header)) { - error("Unable to receive from FastCGI socket: received len (%li) != header len (%li)", ret, sizeof(header)); - return -1; } - req_id = ntohs(header.requestId); content_len = ntohs(header.contentLength); content = malloc(content_len + header.paddingLength); long rcv_len = 0; while (rcv_len < content_len + header.paddingLength) { - ret = recv(conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0); + ret = sock_recv(&conn->socket, content + rcv_len, content_len + header.paddingLength - rcv_len, 0); if (ret < 0) { error("Unable to receive from FastCGI socket"); free(content); @@ -490,16 +460,14 @@ int fastcgi_dump(fastcgi_cnx_t *conn, char *buf, long len) { if (header.type == FCGI_END_REQUEST) { FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; - int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | - body->appStatusB0; + int app_status = ntohl(body->appStatus); if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { error("FastCGI protocol error: %i", body->protocolStatus); } if (app_status != 0) { error("FastCGI app terminated with exit code %i", app_status); } - close(conn->socket); - conn->socket = 0; + sock_close(&conn->socket); free(content); return 0; @@ -517,50 +485,31 @@ int fastcgi_dump(fastcgi_cnx_t *conn, char *buf, long len) { } int fastcgi_receive(fastcgi_cnx_t *conn, sock *client, unsigned long len) { - unsigned long rcv_len = 0; char *buf[16384]; - long ret; - FCGI_Header header = { - .version = FCGI_VERSION_1, - .type = FCGI_STDIN, - .requestId = htons(conn->req_id), - .contentLength = htons(0), - .paddingLength = 0, - .reserved = 0 - }; - while (rcv_len < len) { - ret = sock_recv(client, buf, sizeof(buf), 0); - if (ret <= 0) { + for (long to_send = (long) len, ret; to_send > 0; to_send -= ret) { + if ((ret = sock_recv(client, buf, (to_send > sizeof(buf)) ? sizeof(buf) : to_send, 0)) <= 0) { error("Unable to receive"); return -1; } - rcv_len += ret; - header.contentLength = htons(ret); - if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) goto err; - if (send(conn->socket, buf, ret, 0) != ret) { - err: - error("Unable to send to FastCGI socket"); - return -2; - } + if (fastcgi_send_data(conn, FCGI_STDIN, ret, buf) == -1) + return -1; } + return 0; } int fastcgi_receive_chunked(fastcgi_cnx_t *conn, sock *client) { - long ret; - unsigned long next_len; + for (long ret;;) { + if ((ret = sock_get_chunk_header(client)) < 0) { + return (int) ret; + } else if (ret == 0) { + break; + } - while (1) { - ret = sock_get_chunk_header(client); - if (ret < 0) return (int) ret; - - next_len = ret; - if (next_len <= 0) break; - - ret = fastcgi_receive(conn, client, next_len); - if (ret < 0) return (int) ret; + if ((ret = fastcgi_receive(conn, client, ret)) < 0) + return (int) ret; } return 0; diff --git a/src/lib/fastcgi.h b/src/lib/fastcgi.h index a41ac04..a22418c 100644 --- a/src/lib/fastcgi.h +++ b/src/lib/fastcgi.h @@ -23,7 +23,8 @@ typedef struct { int mode; - int socket; + sock socket; + int in, out, err; unsigned short req_id; const char *webroot; char *out_buf; diff --git a/src/lib/http.c b/src/lib/http.c index 1c866d4..deef451 100644 --- a/src/lib/http.c +++ b/src/lib/http.c @@ -251,8 +251,7 @@ int http_receive_request(sock *client, http_req *req) { if (header_len < 0) return (int) -header_len; - rcv_len = sock_recv(client, buf, header_len, 0); - if (rcv_len != header_len) + if (sock_recv_x(client, buf, header_len, 0) == -1) return -1; return 0; diff --git a/src/lib/include/fastcgi.h b/src/lib/include/fastcgi.h index fdb5948..6138a91 100644 --- a/src/lib/include/fastcgi.h +++ b/src/lib/include/fastcgi.h @@ -54,8 +54,7 @@ typedef struct { #define FCGI_NULL_REQUEST_ID 0 typedef struct { - unsigned char roleB1; - unsigned char roleB0; + unsigned short role; unsigned char flags; unsigned char reserved[5]; } FCGI_BeginRequestBody; @@ -78,10 +77,7 @@ typedef struct { #define FCGI_FILTER 3 typedef struct { - unsigned char appStatusB3; - unsigned char appStatusB2; - unsigned char appStatusB1; - unsigned char appStatusB0; + unsigned int appStatus; unsigned char protocolStatus; unsigned char reserved[3]; } FCGI_EndRequestBody; diff --git a/src/lib/proxy.c b/src/lib/proxy.c index 4717521..8e894b9 100644 --- a/src/lib/proxy.c +++ b/src/lib/proxy.c @@ -549,7 +549,7 @@ int proxy_init(proxy_ctx_t **proxy_ptr, http_req *req, http_res *res, http_statu } ptr = pos0 + 2; } - sock_recv(&proxy->proxy, buffer, header_len, 0); + sock_recv_x(&proxy->proxy, buffer, header_len, 0); ret = proxy_response_header(req, res, conf); if (ret != 0) { @@ -654,7 +654,7 @@ int proxy_send(proxy_ctx_t *proxy, sock *client, unsigned long len_to_send, int if (finish_comp) goto finish; } if (ret <= 0) break; - if (flags & PROXY_CHUNKED) sock_recv(&proxy->proxy, buffer, 2, 0); + if (flags & PROXY_CHUNKED) sock_recv_x(&proxy->proxy, buffer, 2, 0); } while ((flags & PROXY_CHUNKED) && len_to_send > 0); if (ret <= 0) return -1; diff --git a/src/lib/sock.c b/src/lib/sock.c index 893b4e7..adde43f 100644 --- a/src/lib/sock.c +++ b/src/lib/sock.c @@ -107,13 +107,17 @@ long sock_send(sock *s, void *buf, unsigned long len, int flags) { } long sock_send_x(sock *s, void *buf, unsigned long len, int flags) { - long sent = 0; - for (long ret; sent < len; sent += ret) { - ret = sock_send(s, (unsigned char *) buf + sent, len - sent, flags); - if (ret <= 0) - return ret; + for (long ret, sent = 0; sent < len; sent += ret) { + if ((ret = sock_send(s, (unsigned char *) buf + sent, len - sent, flags)) <= 0) { + if (errno == EINTR) { + errno = 0, ret = 0; + continue; + } else { + return -1; + } + } } - return sent; + return (long) len; } long sock_recv(sock *s, void *buf, unsigned long len, int flags) { @@ -134,6 +138,20 @@ long sock_recv(sock *s, void *buf, unsigned long len, int flags) { } } +long sock_recv_x(sock *s, void *buf, unsigned long len, int flags) { + for (long ret, rcv = 0; rcv < len; rcv += ret) { + if ((ret = sock_recv(s, (unsigned char *) buf + rcv, len - rcv, flags)) <= 0) { + if (errno == EINTR) { + errno = 0, ret = 0; + continue; + } else { + return -1; + } + } + } + return (long) len; +} + long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len) { long ret; unsigned long send_len = 0; @@ -213,16 +231,24 @@ long sock_get_chunk_header(sock *s) { char buf[16]; do { - ret = sock_recv(s, buf, sizeof(buf), MSG_PEEK); - if (ret <= 0) return -2; - else if (ret < 2) continue; + if ((ret = sock_recv(s, buf, sizeof(buf) - 1, MSG_PEEK)) <= 0) { + if (errno == EINTR) { + errno = 0; + continue; + } else { + return -1; + } + } else if (ret < 2) { + continue; + } + buf[ret] = 0; - ret = sock_parse_chunk_header(buf, ret, &len); - if (ret == -2) return -1; + if ((ret = sock_parse_chunk_header(buf, ret, &len)) == -2) + return -1; } while (ret < 0); - if (sock_recv(s, buf, len, 0) != len) - return -2; + if (sock_recv_x(s, buf, len, 0) == -1) + return -1; return ret; } diff --git a/src/lib/sock.h b/src/lib/sock.h index b554868..886c6a2 100644 --- a/src/lib/sock.h +++ b/src/lib/sock.h @@ -44,6 +44,8 @@ long sock_send_x(sock *s, void *buf, unsigned long len, int flags); long sock_recv(sock *s, void *buf, unsigned long len, int flags); +long sock_recv_x(sock *s, void *buf, unsigned long len, int flags); + long sock_splice(sock *dst, sock *src, void *buf, unsigned long buf_len, unsigned long len); long sock_splice_chunked(sock *dst, sock *src, void *buf, unsigned long buf_len); diff --git a/src/lib/websocket.c b/src/lib/websocket.c index 6e63147..0a0f6e6 100644 --- a/src/lib/websocket.c +++ b/src/lib/websocket.c @@ -36,13 +36,9 @@ int ws_calc_accept_key(const char *key, char *accept_key) { int ws_recv_frame_header(sock *s, ws_frame *frame) { unsigned char buf[12]; - long ret = sock_recv(s, buf, 2, 0); - if (ret < 0) { + if (sock_recv_x(s, buf, 2, 0) == -1) { error("Unable to receive from socket"); return -1; - } else if (ret != 2) { - error("Unable to receive 2 bytes from socket"); - return -2; } unsigned short bits = (buf[0] << 8) | buf[1]; @@ -61,13 +57,9 @@ int ws_recv_frame_header(sock *s, ws_frame *frame) { remaining += 8; } - ret = sock_recv(s, buf, remaining, 0); - if (ret < 0) { + if (sock_recv_x(s, buf, remaining, 0) == -1) { error("Unable to receive from socket"); return -1; - } else if (ret != remaining) { - error("Unable to receive correct number of bytes from socket"); - return -2; } if (len == 126) { diff --git a/src/worker/fastcgi_handler.c b/src/worker/fastcgi_handler.c index 16a4975..e83c6a7 100644 --- a/src/worker/fastcgi_handler.c +++ b/src/worker/fastcgi_handler.c @@ -38,7 +38,8 @@ static int fastcgi_handler_1(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) { sock *client = &ctx->socket; char *err_msg = ctx->err_msg; - fcgi_cnx->socket = 0; + fcgi_cnx->socket.socket = 0; + fcgi_cnx->socket.enc = 0; fcgi_cnx->req_id = 0; fcgi_cnx->r_addr = ctx->socket.addr; fcgi_cnx->r_host = (ctx->host[0] != 0) ? ctx->host : NULL; @@ -144,9 +145,8 @@ static int fastcgi_handler_2(client_ctx_t *ctx, fastcgi_cnx_t *fcgi_cnx) { errno = 0; } - if (fcgi_cnx->socket != 0) { - close(fcgi_cnx->socket); - fcgi_cnx->socket = 0; + if (fcgi_cnx->socket.socket != 0) { + sock_close(&fcgi_cnx->socket); } return ret;