antd-fcgi-plugin/proto.c
2023-01-26 17:22:59 +01:00

279 lines
8.8 KiB
C

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "proto.h"
#define PARAMS_LENGTH_11 ((0<<0) | (0<<1))
#define PARAMS_LENGTH_14 ((0<<0) | (1<<1))
#define PARAMS_LENGTH_41 ((1<<0) | (0<<1))
#define PARAMS_LENGTH_44 ((1<<0) | (1<<1))
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
char value[0];
} FCGI_NameValuePair11;
typedef struct {
unsigned char nameLengthB0; /* nameLengthB0 >> 7 == 0 */
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
char value[0];
} FCGI_NameValuePair14;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB0; /* valueLengthB0 >> 7 == 0 */
char value[0];
} FCGI_NameValuePair41;
typedef struct {
unsigned char nameLengthB3; /* nameLengthB3 >> 7 == 1 */
unsigned char nameLengthB2;
unsigned char nameLengthB1;
unsigned char nameLengthB0;
unsigned char valueLengthB3; /* valueLengthB3 >> 7 == 1 */
unsigned char valueLengthB2;
unsigned char valueLengthB1;
unsigned char valueLengthB0;
char value[0];
} FCGI_NameValuePair44;
typedef union {
FCGI_NameValuePair11 d11;
FCGI_NameValuePair14 d14;
FCGI_NameValuePair41 d41;
FCGI_NameValuePair44 d44;
} FCGI_Params_Body;
static int fcgi_send_record(antd_client_t* cl, FCGI_Header* header, uint8_t* buff, size_t len)
{
if(!header)
{
ERROR("Record header should not empty");
return -1;
}
// send the header
int ret = antd_send(cl, (uint8_t*)header, sizeof(FCGI_Header));
if(ret != sizeof(FCGI_Header))
{
ERROR("fcgi_send_record: Unable to send record header, only %d of %d bytes sent: %s", ret, sizeof(FCGI_Header), strerror(errno));
return -1;
}
if(!buff)
{
return 0;
}
// send the data
ret = antd_send(cl, (uint8_t*)buff, len);
if(ret != (int)len)
{
ERROR("fcgi_send_record: Unable to send record data, only %d of %d bytes sent", ret, len);
return -1;
}
return 0;
}
int fcgi_begin_request(antd_client_t* cl, uint16_t id, uint16_t role, uint8_t flags)
{
FCGI_BeginRequestRecord record;
record.header.version = FCGI_VERSION_1;
record.header.type = FCGI_BEGIN_REQUEST;
record.header.requestIdB1 = id >> 8;
record.header.requestIdB0 = id & 0xFF;
record.header.contentLengthB1 = 0;
record.header.contentLengthB0 = 8;
record.header.paddingLength = 0;
record.body.roleB1 = role >> 8;
record.body.roleB0 = role & 0xFF;
record.body.flags = flags;
int ret = antd_send(cl, (uint8_t*)&record, sizeof(record));
if(ret != sizeof(record))
{
ERROR("fcgi_begin_request: Unable to send record data, only %d of %d bytes sent", ret, sizeof(record));
return -1;
}
return 0;
}
int fcgi_abort_request(antd_client_t* cl, uint16_t id)
{
FCGI_Header header;
header.version = FCGI_VERSION_1;
header.type = FCGI_BEGIN_REQUEST;
header.requestIdB1 = id >> 8;
header.requestIdB0 = id & 0xFF;
header.contentLengthB1 = 0;
header.contentLengthB0 = 0;
header.paddingLength = 0;
int ret = antd_send(cl, (uint8_t*)&header, sizeof(header));
if(ret != sizeof(header))
{
ERROR("fcgi_abort_request: Unable to send record data, only %d of %d bytes sent", ret, sizeof(header));
return -1;
}
return 0;
}
int fcgi_send_param(antd_client_t* cl, int id, const char* key, const char* value)
{
size_t k_length = strlen(key);
size_t v_length = strlen(value);
//LOG("sending [%s] -> [%s]", key, value);
FCGI_Params_Body* body = NULL;
uint8_t* buff = NULL;
size_t clen = k_length + v_length;
if(clen > 0)
{
size_t max_buff_len = sizeof(FCGI_Params_Body) + k_length + v_length + 8;
buff = (uint8_t*)malloc(max_buff_len);
if(!buff)
{
ERROR("Unable to allocate PARAMS record buffer memory: %s", strerror(errno));
return -1;
}
}
body = (FCGI_Params_Body*) buff;
FCGI_Header header;
header.version = FCGI_VERSION_1;
header.type = FCGI_PARAMS;
header.requestIdB1 = id >> 8;
header.requestIdB0 = id & 0xFF;
if(clen > 0)
{
uint8_t encoding_type = ((k_length>127?1:0) << 0) | ((v_length>127?1:0) << 1);
switch(encoding_type)
{
case PARAMS_LENGTH_11:
body->d11.nameLengthB0 = k_length;
body->d11.valueLengthB0 = v_length;
memcpy(body->d11.value, key, k_length);
memcpy(body->d11.value+k_length, value, v_length);
clen += 2;
break;
case PARAMS_LENGTH_14:
body->d14.nameLengthB0 = k_length;
body->d14.valueLengthB3 = (v_length >> 24) | 0x80;
body->d14.valueLengthB2 = (v_length >> 16) & 0xFF;
body->d14.valueLengthB1 = (v_length >> 8) & 0xFF;
body->d14.valueLengthB0 = v_length & 0xFF;
memcpy(body->d14.value, key, k_length);
memcpy(body->d14.value+k_length, value, v_length);
clen += 5;
break;
case PARAMS_LENGTH_41:
body->d41.valueLengthB0 = v_length;
body->d41.nameLengthB3 = (k_length >> 24) | 0x80;
body->d41.nameLengthB2 = (k_length >> 16) & 0xFF;
body->d41.nameLengthB1 = (k_length >> 8) & 0xFF;
body->d41.nameLengthB0 = k_length & 0xFF;
memcpy(body->d41.value, key, k_length);
memcpy(body->d41.value+k_length, value, v_length);
clen += 5;
break;
case PARAMS_LENGTH_44:
body->d44.nameLengthB3 = (k_length >> 24) | 0x80;
body->d44.nameLengthB2 = (k_length >> 16) & 0xFF;
body->d44.nameLengthB1 = (k_length >> 8) & 0xFF;
body->d44.nameLengthB0 = k_length & 0xFF;
body->d44.valueLengthB3 = (v_length >> 24) | 0x80;
body->d44.valueLengthB2 = (v_length >> 16) & 0xFF;
body->d44.valueLengthB1 = (v_length >> 8) & 0xFF;
body->d44.valueLengthB0 = v_length & 0xFF;
memcpy(body->d44.value, key, k_length);
memcpy(body->d44.value+k_length, value, v_length);
clen += 8;
break;
default:
// this should never happends
free(buff);
return -1;
}
}
header.contentLengthB1 = clen >> 8;
header.contentLengthB0 = clen & 0xFF;
header.paddingLength = (clen % 8 == 0)? 0 : 8 - (clen % 8);
// send the record
int ret = fcgi_send_record(cl, &header, buff, clen + header.paddingLength);
if(buff)
free(buff);
return ret;
}
int fcgi_send_stdin(antd_client_t* cl, int id, uint8_t* padded_data, size_t len, uint8_t paddlen)
{
FCGI_Header header;
header.version = FCGI_VERSION_1;
header.type = FCGI_STDIN;
header.requestIdB1 = id >> 8;
header.requestIdB0 = id & 0xFF;
header.contentLengthB1 = len >> 8;
header.contentLengthB0 = len & 0xFF;
header.paddingLength = paddlen;
// send the record
return fcgi_send_record(cl, &header, padded_data, len + paddlen);
}
int fcgi_read_header(antd_client_t* cl, FCGI_Header* header)
{
uint8_t* buff = (uint8_t*) header;
int ret = antd_recv(cl, buff, sizeof(FCGI_Header));
if(ret != sizeof(FCGI_Header))
{
ERROR("Unable to read header: received %d bytes out of %d bytes", ret, sizeof(FCGI_Header));
return -1;
}
return 0;
}
int fcgi_read_data(antd_client_t* cl, FCGI_Header* header, uint8_t* buffer)
{
int len = ((header->contentLengthB1 << 8) | header->contentLengthB0) + header->paddingLength;
int ret = antd_recv(cl, buffer, len);
if(ret != len)
{
ERROR("Unable to read record body: received %d bytes out of %d bytes", ret, len);
return -1;
}
return 0;
}
uint8_t* fcgi_read_payload(antd_client_t* cl, FCGI_Header* header, int* size)
{
int len = ((header->contentLengthB1 << 8) | header->contentLengthB0) + header->paddingLength;
uint8_t* buff = (uint8_t*) malloc(len + 1);
if(!buff)
{
ERROR("Unable to allocate buffer of size %d", len);
return NULL;
}
int ret = antd_recv(cl, buff, len);
if(ret != len)
{
ERROR("Unable to read record body: received %d bytes out of %d bytes", ret, len);
free(buff);
return NULL;
}
*size = len - header->paddingLength;
buff[*size] = '\0';
return buff;
}