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