1abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin/* libs/cutils/record_stream.c 2abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** 3abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** Copyright 2006, The Android Open Source Project 4abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** 5abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** Licensed under the Apache License, Version 2.0 (the "License"); 6abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** you may not use this file except in compliance with the License. 7abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** You may obtain a copy of the License at 8abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** 9abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** http://www.apache.org/licenses/LICENSE-2.0 10abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** 11abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** Unless required by applicable law or agreed to in writing, software 12abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** distributed under the License is distributed on an "AS IS" BASIS, 13abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** See the License for the specific language governing permissions and 15abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin** limitations under the License. 16abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin*/ 17abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 18abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <stdlib.h> 19abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <unistd.h> 20abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <assert.h> 21abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <errno.h> 22abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <cutils/record_stream.h> 23abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <string.h> 24abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <stdint.h> 25abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#ifdef HAVE_WINSOCK 26abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <winsock2.h> /* for ntohl */ 27abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#else 28abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#include <netinet/in.h> 29abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#endif 30abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 31abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin#define HEADER_SIZE 4 32abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 33abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinstruct RecordStream { 34abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin int fd; 35abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin size_t maxRecordLen; 36abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 37abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *buffer; 38abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 39abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *unconsumed; 40abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *read_end; 41abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *buffer_end; 42abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin}; 43abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 44abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 45abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinextern RecordStream *record_stream_new(int fd, size_t maxRecordLen) 46abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin{ 47abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin RecordStream *ret; 48abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 49abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin assert (maxRecordLen <= 0xffff); 50abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 51abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret = (RecordStream *)calloc(1, sizeof(RecordStream)); 52abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 53abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->fd = fd; 54abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->maxRecordLen = maxRecordLen; 55abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->buffer = (unsigned char *)malloc (maxRecordLen + HEADER_SIZE); 56abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 57abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->unconsumed = ret->buffer; 58abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->read_end = ret->buffer; 59abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret->buffer_end = ret->buffer + maxRecordLen + HEADER_SIZE; 60abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 61abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return ret; 62abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin} 63abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 64abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 65abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinextern void record_stream_free(RecordStream *rs) 66abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin{ 67abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin free(rs->buffer); 68abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin free(rs); 69abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin} 70abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 71abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 72abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin/* returns NULL; if there isn't a full record in the buffer */ 73abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinstatic unsigned char * getEndOfRecord (unsigned char *p_begin, 74abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *p_end) 75abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin{ 76abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin size_t len; 77abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char * p_ret; 78abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 79abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (p_end < p_begin + HEADER_SIZE) { 80abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return NULL; 81abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 82abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 83abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin //First four bytes are length 84abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin len = ntohl(*((uint32_t *)p_begin)); 85abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 86abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin p_ret = p_begin + HEADER_SIZE + len; 87abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 88abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (p_end < p_ret) { 89abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return NULL; 90abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 91abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 92abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return p_ret; 93abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin} 94abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 95abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinstatic void *getNextRecord (RecordStream *p_rs, size_t *p_outRecordLen) 96abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin{ 97abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin unsigned char *record_start, *record_end; 98abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 99abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin record_end = getEndOfRecord (p_rs->unconsumed, p_rs->read_end); 100abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 101abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (record_end != NULL) { 102abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin /* one full line in the buffer */ 103abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin record_start = p_rs->unconsumed + HEADER_SIZE; 104abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin p_rs->unconsumed = record_end; 105abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 106abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin *p_outRecordLen = record_end - record_start; 107abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 108abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return record_start; 109abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 110abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 111abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return NULL; 112abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin} 113abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 114abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin/** 115abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Reads the next record from stream fd 116abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Records are prefixed by a 16-bit big endian length value 117abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Records may not be larger than maxRecordLen 118abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * 119abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Doesn't guard against EINTR 120abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * 121abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * p_outRecord and p_outRecordLen may not be NULL 122abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * 123abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Return 0 on success, -1 on fail 124abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Returns 0 with *p_outRecord set to NULL on end of stream 125abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin * Returns -1 / errno = EAGAIN if it needs to read again 126abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin */ 127abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavinint record_stream_get_next (RecordStream *p_rs, void ** p_outRecord, 128abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin size_t *p_outRecordLen) 129abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin{ 130abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin void *ret; 131abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 132abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ssize_t countRead; 133abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 134abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin /* is there one record already in the buffer? */ 135abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret = getNextRecord (p_rs, p_outRecordLen); 136abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 137abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (ret != NULL) { 138abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin *p_outRecord = ret; 139abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return 0; 140abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 141abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 142abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin // if the buffer is full and we don't have a full record 143abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (p_rs->unconsumed == p_rs->buffer 144abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin && p_rs->read_end == p_rs->buffer_end 145abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ) { 146abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin // this should never happen 147abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin //ALOGE("max record length exceeded\n"); 148abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin assert (0); 149abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin errno = EFBIG; 150abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return -1; 151abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 152abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 153abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (p_rs->unconsumed != p_rs->buffer) { 154abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin // move remainder to the beginning of the buffer 155abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin size_t toMove; 156abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 157abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin toMove = p_rs->read_end - p_rs->unconsumed; 158abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (toMove) { 159abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin memmove(p_rs->buffer, p_rs->unconsumed, toMove); 160abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 161abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 162abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin p_rs->read_end = p_rs->buffer + toMove; 163abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin p_rs->unconsumed = p_rs->buffer; 164abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 165abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 166abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end); 167abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 168abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (countRead <= 0) { 169abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin /* note: end-of-stream drops through here too */ 170abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin *p_outRecord = NULL; 171abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return countRead; 172abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 173abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 174abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin p_rs->read_end += countRead; 175abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 176abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin ret = getNextRecord (p_rs, p_outRecordLen); 177abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 178abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin if (ret == NULL) { 179abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin /* not enough of a buffer to for a whole command */ 180abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin errno = EAGAIN; 181abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return -1; 182abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin } 183abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin 184abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin *p_outRecord = ret; 185abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin return 0; 186abb7d58010da1fcd466e6e032c5f7bf8810ed4ddDima Zavin} 187