X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fsptps.c;h=e5946ed6fd8cc8cb9211141063f159188e0c6e8f;hp=4a9683f29aed3076de37f9051ab34eb50fbe35d9;hb=d237efd325cd7bdd73f5eb111c769470238dce6e;hpb=de14308840a96060d700c93117789e83ec948c01 diff --git a/src/sptps.c b/src/sptps.c index 4a9683f2..e5946ed6 100644 --- a/src/sptps.c +++ b/src/sptps.c @@ -495,90 +495,92 @@ static bool sptps_receive_data_datagram(sptps_t *s, const char *data, size_t len } // Receive incoming data. Check if it contains a complete record, if so, handle it. -bool sptps_receive_data(sptps_t *s, const void *data, size_t len) { +size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) { + size_t total_read = 0; + if(!s->state) return error(s, EIO, "Invalid session state zero"); if(s->datagram) - return sptps_receive_data_datagram(s, data, len); - - while(len) { - // First read the 2 length bytes. - if(s->buflen < 2) { - size_t toread = 2 - s->buflen; - if(toread > len) - toread = len; + return sptps_receive_data_datagram(s, data, len) ? len : false; - memcpy(s->inbuf + s->buflen, data, toread); + // First read the 2 length bytes. + if(s->buflen < 2) { + size_t toread = 2 - s->buflen; + if(toread > len) + toread = len; - s->buflen += toread; - len -= toread; - data += toread; + memcpy(s->inbuf + s->buflen, data, toread); - // Exit early if we don't have the full length. - if(s->buflen < 2) - return true; + total_read += toread; + s->buflen += toread; + len -= toread; + data += toread; - // Get the length bytes + // Exit early if we don't have the full length. + if(s->buflen < 2) + return total_read; - memcpy(&s->reclen, s->inbuf, 2); - s->reclen = ntohs(s->reclen); + // Get the length bytes - // If we have the length bytes, ensure our buffer can hold the whole request. - s->inbuf = realloc(s->inbuf, s->reclen + 19UL); - if(!s->inbuf) - return error(s, errno, strerror(errno)); + memcpy(&s->reclen, s->inbuf, 2); + s->reclen = ntohs(s->reclen); - // Exit early if we have no more data to process. - if(!len) - return true; - } + // If we have the length bytes, ensure our buffer can hold the whole request. + s->inbuf = realloc(s->inbuf, s->reclen + 19UL); + if(!s->inbuf) + return error(s, errno, strerror(errno)); - // Read up to the end of the record. - size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; - if(toread > len) - toread = len; + // Exit early if we have no more data to process. + if(!len) + return total_read; + } - memcpy(s->inbuf + s->buflen, data, toread); - s->buflen += toread; - len -= toread; - data += toread; + // Read up to the end of the record. + size_t toread = s->reclen + (s->instate ? 19UL : 3UL) - s->buflen; + if(toread > len) + toread = len; - // If we don't have a whole record, exit. - if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) - return true; + memcpy(s->inbuf + s->buflen, data, toread); + total_read += toread; + s->buflen += toread; + len -= toread; + data += toread; - // Update sequence number. + // If we don't have a whole record, exit. + if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL)) + return total_read; - uint32_t seqno = s->inseqno++; + // Update sequence number. - // Check HMAC and decrypt. - if(s->instate) { - if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) - return error(s, EINVAL, "Failed to decrypt and verify record"); - } + uint32_t seqno = s->inseqno++; - // Append a NULL byte for safety. - s->inbuf[s->reclen + 3UL] = 0; + // Check HMAC and decrypt. + if(s->instate) { + if(!chacha_poly1305_decrypt(s->incipher, seqno, s->inbuf + 2UL, s->reclen + 17UL, s->inbuf + 2UL, NULL)) + return error(s, EINVAL, "Failed to decrypt and verify record"); + } - uint8_t type = s->inbuf[2]; + // Append a NULL byte for safety. + s->inbuf[s->reclen + 3UL] = 0; - if(type < SPTPS_HANDSHAKE) { - if(!s->instate) - return error(s, EIO, "Application record received before handshake finished"); - if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) - return false; - } else if(type == SPTPS_HANDSHAKE) { - if(!receive_handshake(s, s->inbuf + 3, s->reclen)) - return false; - } else { - return error(s, EIO, "Invalid record type %d", type); - } + uint8_t type = s->inbuf[2]; - s->buflen = 0; + if(type < SPTPS_HANDSHAKE) { + if(!s->instate) + return error(s, EIO, "Application record received before handshake finished"); + if(!s->receive_record(s->handle, type, s->inbuf + 3, s->reclen)) + return false; + } else if(type == SPTPS_HANDSHAKE) { + if(!receive_handshake(s, s->inbuf + 3, s->reclen)) + return false; + } else { + return error(s, EIO, "Invalid record type %d", type); } - return true; + s->buflen = 0; + + return total_read; } // Start a SPTPS session.