record_stream.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /* libs/cutils/record_stream.c
  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. #include <cutils/record_stream.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <stdint.h>
  24. #if defined(_WIN32)
  25. #include <winsock2.h> /* for ntohl */
  26. #else
  27. #include <netinet/in.h>
  28. #endif
  29. #define HEADER_SIZE 4
  30. struct RecordStream {
  31. int fd;
  32. size_t maxRecordLen;
  33. unsigned char *buffer;
  34. unsigned char *unconsumed;
  35. unsigned char *read_end;
  36. unsigned char *buffer_end;
  37. };
  38. extern RecordStream *record_stream_new(int fd, size_t maxRecordLen)
  39. {
  40. RecordStream *ret;
  41. assert (maxRecordLen <= 0xffff);
  42. ret = (RecordStream *)calloc(1, sizeof(RecordStream));
  43. ret->fd = fd;
  44. ret->maxRecordLen = maxRecordLen;
  45. ret->buffer = (unsigned char *)malloc (maxRecordLen + HEADER_SIZE);
  46. ret->unconsumed = ret->buffer;
  47. ret->read_end = ret->buffer;
  48. ret->buffer_end = ret->buffer + maxRecordLen + HEADER_SIZE;
  49. return ret;
  50. }
  51. extern void record_stream_free(RecordStream *rs)
  52. {
  53. free(rs->buffer);
  54. free(rs);
  55. }
  56. /* returns NULL; if there isn't a full record in the buffer */
  57. static unsigned char * getEndOfRecord (unsigned char *p_begin,
  58. unsigned char *p_end)
  59. {
  60. size_t len;
  61. unsigned char * p_ret;
  62. if (p_end < p_begin + HEADER_SIZE) {
  63. return NULL;
  64. }
  65. //First four bytes are length
  66. len = ntohl(*((uint32_t *)p_begin));
  67. p_ret = p_begin + HEADER_SIZE + len;
  68. if (p_end < p_ret) {
  69. return NULL;
  70. }
  71. return p_ret;
  72. }
  73. static void *getNextRecord (RecordStream *p_rs, size_t *p_outRecordLen)
  74. {
  75. unsigned char *record_start, *record_end;
  76. record_end = getEndOfRecord (p_rs->unconsumed, p_rs->read_end);
  77. if (record_end != NULL) {
  78. /* one full line in the buffer */
  79. record_start = p_rs->unconsumed + HEADER_SIZE;
  80. p_rs->unconsumed = record_end;
  81. *p_outRecordLen = record_end - record_start;
  82. return record_start;
  83. }
  84. return NULL;
  85. }
  86. /**
  87. * Reads the next record from stream fd
  88. * Records are prefixed by a 16-bit big endian length value
  89. * Records may not be larger than maxRecordLen
  90. *
  91. * Doesn't guard against EINTR
  92. *
  93. * p_outRecord and p_outRecordLen may not be NULL
  94. *
  95. * Return 0 on success, -1 on fail
  96. * Returns 0 with *p_outRecord set to NULL on end of stream
  97. * Returns -1 / errno = EAGAIN if it needs to read again
  98. */
  99. int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord,
  100. size_t *p_outRecordLen)
  101. {
  102. void *ret;
  103. ssize_t countRead;
  104. /* is there one record already in the buffer? */
  105. ret = getNextRecord (p_rs, p_outRecordLen);
  106. if (ret != NULL) {
  107. *p_outRecord = ret;
  108. return 0;
  109. }
  110. // if the buffer is full and we don't have a full record
  111. if (p_rs->unconsumed == p_rs->buffer
  112. && p_rs->read_end == p_rs->buffer_end
  113. ) {
  114. // this should never happen
  115. //ALOGE("max record length exceeded\n");
  116. assert (0);
  117. errno = EFBIG;
  118. return -1;
  119. }
  120. if (p_rs->unconsumed != p_rs->buffer) {
  121. // move remainder to the beginning of the buffer
  122. size_t toMove;
  123. toMove = p_rs->read_end - p_rs->unconsumed;
  124. if (toMove) {
  125. memmove(p_rs->buffer, p_rs->unconsumed, toMove);
  126. }
  127. p_rs->read_end = p_rs->buffer + toMove;
  128. p_rs->unconsumed = p_rs->buffer;
  129. }
  130. countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end);
  131. if (countRead <= 0) {
  132. /* note: end-of-stream drops through here too */
  133. *p_outRecord = NULL;
  134. return countRead;
  135. }
  136. p_rs->read_end += countRead;
  137. ret = getNextRecord (p_rs, p_outRecordLen);
  138. if (ret == NULL) {
  139. /* not enough of a buffer to for a whole command */
  140. errno = EAGAIN;
  141. return -1;
  142. }
  143. *p_outRecord = ret;
  144. return 0;
  145. }