mirror of git://git.psyc.eu/libpsyc
289 lines
7.6 KiB
C
289 lines
7.6 KiB
C
/*
|
|
This file is part of libpsyc.
|
|
Copyright (C) 2011,2012 Carlo v. Loesch, Gabor X Toth, Mathias L. Baumann,
|
|
and other contributing authors.
|
|
|
|
libpsyc is free software: you can redistribute it and/or modify it under the
|
|
terms of the GNU Affero General Public License as published by the Free
|
|
Software Foundation, either version 3 of the License, or (at your option) any
|
|
later version. As a special exception, libpsyc is distributed with additional
|
|
permissions to link libpsyc libraries with non-AGPL works.
|
|
|
|
libpsyc is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License and
|
|
the linking exception along with libpsyc in a COPYING file.
|
|
*/
|
|
|
|
#include "lib.h"
|
|
#include <psyc/packet.h>
|
|
|
|
extern inline size_t
|
|
psyc_num_length (size_t n);
|
|
|
|
extern inline PsycModifierFlag
|
|
psyc_modifier_length_check (PsycModifier *m);
|
|
|
|
extern inline void
|
|
psyc_modifier_init (PsycModifier *m, PsycOperator oper,
|
|
char *name, size_t namelen,
|
|
char *value, size_t valuelen, PsycModifierFlag flag);
|
|
|
|
inline PsycElemFlag
|
|
psyc_elem_length_check (PsycString *value, const char end)
|
|
{
|
|
if (value->length > PSYC_ELEM_SIZE_THRESHOLD
|
|
|| memchr(value->data, (int)end, value->length))
|
|
return PSYC_ELEM_NEED_LENGTH;
|
|
|
|
return PSYC_ELEM_NO_LENGTH;;
|
|
}
|
|
|
|
inline size_t
|
|
psyc_elem_length (PsycElem *elem)
|
|
{
|
|
return
|
|
(elem->type.length ? 1 + elem->type.length : 0)
|
|
+ (elem->value.length && elem->flag != PSYC_ELEM_NO_LENGTH
|
|
? (elem->type.length ? 1 : 0) + psyc_num_length(elem->value.length) : 0)
|
|
+ (elem->value.length ? 1 + elem->value.length : 0);
|
|
}
|
|
|
|
inline size_t
|
|
psyc_dict_key_length (PsycDictKey *elem)
|
|
{
|
|
return
|
|
(elem->flag != PSYC_ELEM_NO_LENGTH
|
|
? psyc_num_length(elem->value.length) : 0)
|
|
+ (elem->value.length ? 1 + elem->value.length : 0);
|
|
}
|
|
|
|
inline size_t
|
|
psyc_list_length_set (PsycList *list)
|
|
{
|
|
size_t i;
|
|
PsycElem *elem;
|
|
|
|
list->length = list->type.length;
|
|
|
|
for (i = 0; i < list->num_elems; i++) {
|
|
elem = &list->elems[i];
|
|
if (elem->flag == PSYC_ELEM_CHECK_LENGTH)
|
|
elem->flag = psyc_elem_length_check(&elem->value, '|');
|
|
elem->length = psyc_elem_length(elem);
|
|
list->length += 1 + elem->length;
|
|
}
|
|
|
|
return list->length;
|
|
}
|
|
|
|
inline size_t
|
|
psyc_dict_length_set (PsycDict *dict)
|
|
{
|
|
size_t i;
|
|
PsycDictKey *key;
|
|
PsycElem *value;
|
|
|
|
dict->length = dict->type.length;
|
|
|
|
for (i = 0; i < dict->num_elems; i++) {
|
|
key = &dict->elems[i].key;
|
|
value = &dict->elems[i].value;
|
|
|
|
if (key->flag == PSYC_ELEM_CHECK_LENGTH)
|
|
key->flag = psyc_elem_length_check(&key->value, '}');
|
|
if (value->flag == PSYC_ELEM_CHECK_LENGTH)
|
|
value->flag = psyc_elem_length_check(&value->value, '{');
|
|
|
|
key->length = psyc_dict_key_length(key);
|
|
value->length = psyc_elem_length(value);
|
|
|
|
dict->length += 1 + key->length + 1 + value->length;
|
|
}
|
|
|
|
return dict->length;
|
|
}
|
|
|
|
void
|
|
psyc_list_init (PsycList *list, PsycElem *elems, size_t num_elems)
|
|
{
|
|
*list = (PsycList) {
|
|
.num_elems = num_elems,
|
|
.elems = elems,
|
|
};
|
|
psyc_list_length_set(list);
|
|
}
|
|
|
|
void
|
|
psyc_dict_init (PsycDict *dict, PsycDictElem *elems, size_t num_elems)
|
|
{
|
|
*dict = (PsycDict) {
|
|
.num_elems = num_elems,
|
|
.elems = elems,
|
|
};
|
|
psyc_dict_length_set(dict);
|
|
}
|
|
|
|
inline size_t
|
|
psyc_modifier_length (PsycModifier *m)
|
|
{
|
|
size_t length = 2; // oper\n
|
|
if (m->name.length > 0)
|
|
length += m->name.length + 1 + m->value.length; // name\tvalue
|
|
|
|
// add length of length if needed
|
|
if (m->value.length
|
|
&& (m->flag & PSYC_MODIFIER_NEED_LENGTH
|
|
|| m->flag == PSYC_MODIFIER_CHECK_LENGTH))
|
|
length += psyc_num_length(m->value.length) + 1; // SP length
|
|
|
|
return length;
|
|
}
|
|
|
|
inline PsycPacketFlag
|
|
psyc_packet_length_check (PsycPacket *p)
|
|
{
|
|
if (p->data.length == 1 && p->data.data[0] == PSYC_PACKET_DELIMITER_CHAR)
|
|
return PSYC_PACKET_NEED_LENGTH;
|
|
|
|
if (p->data.length > PSYC_CONTENT_SIZE_THRESHOLD)
|
|
return PSYC_PACKET_NEED_LENGTH;
|
|
|
|
int i;
|
|
// If any entity modifiers need length, it is possible they contain
|
|
// a packet terminator, thus the content should have a length as well.
|
|
for (i = 0; i < p->entity.lines; i++)
|
|
if (p->entity.modifiers[i].flag & PSYC_MODIFIER_NEED_LENGTH
|
|
|| p->entity.modifiers[i].flag == PSYC_MODIFIER_CHECK_LENGTH)
|
|
return PSYC_PACKET_NEED_LENGTH;
|
|
|
|
if (memmem(p->data.data, p->data.length, PSYC_C2ARG(PSYC_PACKET_DELIMITER)))
|
|
return PSYC_PACKET_NEED_LENGTH;
|
|
|
|
return PSYC_PACKET_NO_LENGTH;
|
|
}
|
|
|
|
inline size_t
|
|
psyc_packet_length_set (PsycPacket *p)
|
|
{
|
|
size_t i;
|
|
p->routinglen = 0;
|
|
p->contentlen = 0;
|
|
|
|
// add routing header length
|
|
for (i = 0; i < p->routing.lines; i++)
|
|
p->routinglen += psyc_modifier_length(&(p->routing.modifiers[i]));
|
|
|
|
if (p->content.length)
|
|
p->contentlen = p->content.length;
|
|
else {
|
|
// add state operation
|
|
if (p->stateop != PSYC_STATE_NOOP)
|
|
p->contentlen += 2; // op\n
|
|
|
|
// add entity header length
|
|
for (i = 0; i < p->entity.lines; i++)
|
|
p->contentlen += psyc_modifier_length(&(p->entity.modifiers[i]));
|
|
|
|
// add length of method, data & delimiter
|
|
if (p->method.length)
|
|
p->contentlen += p->method.length + 1; // method\n
|
|
if (p->data.length)
|
|
p->contentlen += p->data.length + 1; // data\n
|
|
}
|
|
|
|
// set total length: routing-header content |\n
|
|
p->length = p->routinglen + p->contentlen + 2;
|
|
|
|
if (p->contentlen)
|
|
p->length++; // add \n at the start of the content part
|
|
|
|
// add length of length if needed
|
|
if (p->contentlen && !(p->flag & PSYC_PACKET_NO_LENGTH))
|
|
p->length += psyc_num_length(p->contentlen);
|
|
|
|
return p->length;
|
|
}
|
|
|
|
inline void
|
|
psyc_packet_init (PsycPacket *p,
|
|
PsycModifier *routing, size_t routinglen,
|
|
PsycModifier *entity, size_t entitylen,
|
|
char *method, size_t methodlen,
|
|
char *data, size_t datalen,
|
|
char stateop, PsycPacketFlag flag)
|
|
{
|
|
*p = (PsycPacket) {
|
|
.routing = {routinglen, routing},
|
|
.entity = {entitylen, entity},
|
|
.method = {methodlen, method},
|
|
.data = {datalen, data},
|
|
.content = {0, 0},
|
|
.routinglen = 0,
|
|
.contentlen = 0,
|
|
.length = 0,
|
|
.stateop = stateop,
|
|
.flag = flag,
|
|
};
|
|
|
|
if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length
|
|
p->flag = psyc_packet_length_check(p);
|
|
|
|
psyc_packet_length_set(p);
|
|
}
|
|
|
|
inline void
|
|
psyc_packet_init_raw (PsycPacket *p,
|
|
PsycModifier *routing, size_t routinglen,
|
|
char *content, size_t contentlen,
|
|
PsycPacketFlag flag)
|
|
{
|
|
*p = (PsycPacket) {
|
|
.routing = {routinglen, routing},
|
|
.entity = {0, 0},
|
|
.method = {0, 0},
|
|
.data = {0, 0},
|
|
.content = {contentlen, content},
|
|
.routinglen = 0,
|
|
.contentlen = 0,
|
|
.length = 0,
|
|
.stateop = 0,
|
|
.flag = flag,
|
|
};
|
|
|
|
if (flag == PSYC_PACKET_CHECK_LENGTH) // find out if it needs length
|
|
p->flag = psyc_packet_length_check(p);
|
|
|
|
psyc_packet_length_set(p);
|
|
}
|
|
|
|
void
|
|
psyc_packet_id (PsycList *list, PsycElem *elems,
|
|
char *context, size_t contextlen,
|
|
char *source, size_t sourcelen,
|
|
char *target, size_t targetlen,
|
|
char *counter, size_t counterlen,
|
|
char *fragment, size_t fragmentlen)
|
|
{
|
|
if (contextlen)
|
|
elems[PSYC_PACKET_ID_CONTEXT] =
|
|
PSYC_ELEM_VF(context, contextlen, PSYC_ELEM_NO_LENGTH);
|
|
if (sourcelen)
|
|
elems[PSYC_PACKET_ID_SOURCE] =
|
|
PSYC_ELEM_VF(source, sourcelen, PSYC_ELEM_NO_LENGTH);
|
|
if (targetlen)
|
|
elems[PSYC_PACKET_ID_TARGET] =
|
|
PSYC_ELEM_VF(target, targetlen, PSYC_ELEM_NO_LENGTH);
|
|
if (counterlen)
|
|
elems[PSYC_PACKET_ID_COUNTER] =
|
|
PSYC_ELEM_VF(counter, counterlen, PSYC_ELEM_NO_LENGTH);
|
|
if (fragmentlen)
|
|
elems[PSYC_PACKET_ID_FRAGMENT] =
|
|
PSYC_ELEM_VF(fragment, fragmentlen, PSYC_ELEM_NO_LENGTH);
|
|
|
|
psyc_list_init(list, elems, PSYC_PACKET_ID_ELEMS);
|
|
}
|