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