}
// 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.