OSDN Git Service

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