summaryrefslogtreecommitdiff
path: root/ecp/src/ecp/ext/frag.c
blob: 879547008c9c3fa964b0f970aa1d5cce3c173d43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <stdlib.h>
#include <string.h>

#include <ecp/core.h>

#include "frag.h"

int ecp_frag_iter_init(ECPConnection *conn, ECPFragIter *iter, unsigned char *buffer, size_t buf_size) {
    memset(iter, 0, sizeof(ECPFragIter));
    iter->buffer = buffer;
    iter->buf_size = buf_size;

    conn->iter = iter;
    return ECP_OK;
}

void ecp_frag_iter_reset(ECPFragIter *iter) {
    iter->seq = 0;
    iter->frag_cnt = 0;
    iter->pld_size = 0;
}

ssize_t ecp_pld_defrag(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *payload, size_t pld_size) {
    ECPFragIter *iter = conn->iter;
    unsigned char *msg;
    unsigned char frag_cnt, frag_tot;
    uint16_t frag_size;
    size_t hdr_size, msg_size;
    size_t buf_offset;
    int rv;

    rv = ecp_pld_get_frag(payload, pld_size, &frag_cnt, &frag_tot, &frag_size);
    if (rv) return ECP_ERR;

    msg = ecp_pld_get_msg(payload, pld_size);
    if (msg == NULL) return ECP_ERR;
    hdr_size = msg - payload;

    msg_size = pld_size - hdr_size;
    if (msg_size == 0) return ECP_ERR;

    if (iter->pld_size && (iter->seq + frag_cnt != seq)) ecp_frag_iter_reset(iter);

    if (iter->pld_size == 0) {
        iter->seq = seq - frag_cnt;
        iter->frag_cnt = 0;
    }

    mtype &= ~ECP_MTYPE_FLAG_FRAG;
    buf_offset = ECP_SIZE_MTYPE + ECP_SIZE_MT_FLAG(mtype) + frag_size * frag_cnt;
    if (buf_offset + msg_size > iter->buf_size) return ECP_ERR_SIZE;
    memcpy(iter->buffer + buf_offset, msg, msg_size);

    if (frag_cnt == 0) {
        if (ECP_SIZE_MTYPE + ECP_SIZE_MT_FLAG(mtype) > iter->buf_size) return ECP_ERR_SIZE;

        iter->buffer[0] = mtype;
        if (ECP_SIZE_MT_FLAG(mtype)) {
            memcpy(iter->buffer + ECP_SIZE_MTYPE, payload + ECP_SIZE_MTYPE, ECP_SIZE_MT_FLAG(mtype));
        }
        msg_size += ECP_SIZE_MTYPE + ECP_SIZE_MT_FLAG(mtype);
    }

    iter->frag_cnt++;
    iter->pld_size += msg_size;
    if (iter->frag_cnt == frag_tot) {
        ecp_pld_handle_one(conn, iter->seq, iter->buffer, iter->pld_size, NULL);
        ecp_frag_iter_reset(iter);
    }

    return pld_size;
}

ssize_t ecp_msg_send_wfrag(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, ECPBuffer *packet, ECPBuffer *payload) {
    unsigned char *msg_buf;
    unsigned char *pld_buf;
    size_t pld_size;
    size_t frag_size, frag_size_final;
    ecp_nonce_t nonce, nonce_start;
    int pkt_cnt = 0;
    int i;

    mtype |= ECP_MTYPE_FLAG_FRAG;
    frag_size = ECP_MAX_PKT - ECP_SIZE_PKT_BUF(0, mtype, conn);
    pkt_cnt = msg_size / frag_size;
    frag_size_final = msg_size - frag_size * pkt_cnt;
    if (frag_size_final) pkt_cnt++;

#ifdef ECP_WITH_PTHREAD
    pthread_mutex_lock(&conn->mutex);
#endif

    nonce_start = conn->nonce_out;
    conn->nonce_out += pkt_cnt;

#ifdef ECP_WITH_PTHREAD
    pthread_mutex_unlock(&conn->mutex);
#endif

    pld_buf = payload->buffer;
    pld_size = payload->size;
    for (i=0; i<pkt_cnt; i++) {
        ssize_t rv;

        ecp_pld_set_type(pld_buf, pld_size, mtype);
        ecp_pld_set_frag(pld_buf, pld_size, i, pkt_cnt, frag_size);
        msg_buf = ecp_pld_get_msg(pld_buf, pld_size);

        if ((i == pkt_cnt - 1) && frag_size_final) frag_size = frag_size_final;
        memcpy(msg_buf, msg, frag_size);
        msg += frag_size;
        nonce = nonce_start + i;

        rv = ecp_pld_send_wnonce(conn, packet, payload, ECP_SIZE_PLD(frag_size, mtype), 0, &nonce);
        if (rv < 0) return rv;
    }

    return msg_size;
}

ssize_t ecp_ext_pld_handle_one(ECPConnection *conn, ecp_seq_t seq, unsigned char *payload, size_t pld_size, ECP2Buffer *bufs) {
    if (conn->iter) {
        unsigned char mtype;
        int rv;

        rv = ecp_pld_get_type(payload, pld_size, &mtype);
        if (rv) return rv;

        if (mtype & ECP_MTYPE_FLAG_FRAG) {
            return ecp_pld_defrag(conn, seq, mtype, payload, pld_size);
        }
    }

    return 0;
}

ssize_t ecp_ext_msg_send(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, ECPBuffer *packet, ECPBuffer *payload) {
    if (ECP_SIZE_PKT_BUF(msg_size, mtype, conn) > ECP_MAX_PKT) {
        return ecp_msg_send_wfrag(conn, mtype, msg, msg_size, packet, payload);
    } else {
        return 0;
    }
}