@@ -57,8 +57,6 @@ const char *nc_msgtype2str[] = {
5757 "notification message" ,
5858};
5959
60- #define BUFFERSIZE 512
61-
6260static ssize_t
6361nc_read (struct nc_session * session , char * buf , uint32_t count , uint32_t inact_timeout , struct timespec * ts_act_timeout )
6462{
@@ -174,68 +172,55 @@ nc_read(struct nc_session *session, char *buf, uint32_t count, uint32_t inact_ti
174172 return (ssize_t )readd ;
175173}
176174
177- static ssize_t
178- nc_read_chunk (struct nc_session * session , size_t len , uint32_t inact_timeout , struct timespec * ts_act_timeout , char * * chunk )
179- {
180- ssize_t r ;
181-
182- assert (session );
183- assert (chunk );
184-
185- if (!len ) {
186- return 0 ;
187- }
188-
189- * chunk = malloc ((len + 1 ) * sizeof * * chunk );
190- NC_CHECK_ERRMEM_RET (!* chunk , -1 );
191-
192- r = nc_read (session , * chunk , len , inact_timeout , ts_act_timeout );
193- if (r <= 0 ) {
194- free (* chunk );
195- return -1 ;
196- }
197-
198- /* terminating null byte */
199- (* chunk )[r ] = 0 ;
200-
201- return r ;
202- }
203-
175+ /**
176+ * @brief Read data until a specific characters sequence is found.
177+ *
178+ * @param[in] session Session to read from.
179+ * @param[in] endtag End tag to match, no characters read after that.
180+ * @param[in] inact_timeout Inactive timeout to use.
181+ * @param[in] ts_act_timeout Active timeout to use.
182+ * @param[in,out] buf Buffer for read data, may be NULL.
183+ * @param[in,out] buf_size Current size of @p buf - 1 (actual size is one byte larger).
184+ * @return Number of characters read;
185+ * @return -1 on error.
186+ */
204187static ssize_t
205188nc_read_until (struct nc_session * session , const char * endtag , uint32_t inact_timeout , struct timespec * ts_act_timeout ,
206- char * * result )
189+ char * * buf , uint32_t * buf_size )
207190{
208- char * chunk = NULL ;
209- size_t size , count = 0 , r , len , i , matched = 0 ;
191+ char * local_buf = NULL ;
192+ uint32_t local_size = 0 ;
193+ size_t r , len , i , matched = 0 ;
194+ ssize_t count = 0 ;
210195
211196 assert (session );
212197 assert (endtag );
213198
214- size = BUFFERSIZE ;
215- chunk = malloc ((size + 1 ) * sizeof * chunk );
216- NC_CHECK_ERRMEM_RET (!chunk , -1 );
199+ if (!buf ) {
200+ buf = & local_buf ;
201+ buf_size = & local_size ;
202+ }
217203
218204 len = strlen (endtag );
219- while ( 1 ) {
205+ do {
220206 /* resize buffer if needed */
221- if ((count + (len - matched )) >= size ) {
222- /* get more memory */
223- size = size + BUFFERSIZE ;
224- chunk = nc_realloc (chunk , (size + 1 ) * sizeof * chunk );
225- NC_CHECK_ERRMEM_RET (!chunk , -1 );
207+ if ((count + (len - matched )) > * buf_size ) {
208+ * buf_size += NC_READ_BUF_SIZE_STEP ;
209+ * buf = nc_realloc (* buf , (* buf_size + 1 ) * sizeof * * buf );
210+ NC_CHECK_ERRMEM_GOTO (!* buf , count = -1 , cleanup );
226211 }
227212
228213 /* get another character */
229- r = nc_read (session , & ( chunk [ count ]) , len - matched , inact_timeout , ts_act_timeout );
214+ r = nc_read (session , * buf + count , len - matched , inact_timeout , ts_act_timeout );
230215 if (r != len - matched ) {
231- free ( chunk ) ;
232- return -1 ;
216+ count = -1 ;
217+ goto cleanup ;
233218 }
234219
235220 count += len - matched ;
236221
237222 for (i = len - matched ; i > 0 ; i -- ) {
238- if (!strncmp (& endtag [ matched ], & ( chunk [ count - i ] ), i )) {
223+ if (!strncmp (endtag + matched , * buf + ( count - i ), i )) {
239224 /*part of endtag found */
240225 matched += i ;
241226 break ;
@@ -245,35 +230,30 @@ nc_read_until(struct nc_session *session, const char *endtag, uint32_t inact_tim
245230 }
246231
247232 /* whole endtag found */
248- if (matched == len ) {
249- break ;
250- }
251- }
233+ } while (matched < len );
252234
253235 /* terminating null byte */
254- chunk [count ] = 0 ;
236+ ( * buf ) [count ] = 0 ;
255237
256- if (result ) {
257- * result = chunk ;
258- } else {
259- free (chunk );
260- }
238+ cleanup :
239+ free (local_buf );
261240 return count ;
262241}
263242
264243int
265244nc_read_msg_io (struct nc_session * session , int io_timeout , struct ly_in * * msg , int passing_io_lock )
266245{
267246 int ret = 1 , r , io_locked = passing_io_lock ;
268- char * data = NULL , * chunk ;
269- uint64_t chunk_len , len = 0 ;
270- /* use timeout in milliseconds instead seconds */
271- uint32_t inact_timeout = NC_READ_INACT_TIMEOUT * 1000 ;
247+ char * data = NULL , * frame_size_buf = NULL ;
248+ uint32_t chunk_len , frame_buf_len , data_len = 0 , inact_timeout ;
272249 struct timespec ts_act_timeout ;
273250
274251 assert (session && msg );
275252 * msg = NULL ;
276253
254+ /* use timeout in milliseconds instead seconds */
255+ inact_timeout = NC_READ_INACT_TIMEOUT * 1000 ;
256+
277257 if ((session -> status != NC_STATUS_RUNNING ) && (session -> status != NC_STATUS_STARTING )) {
278258 ERR (session , "Invalid session to read from." );
279259 ret = -1 ;
@@ -294,7 +274,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
294274 /* read the message */
295275 switch (session -> version ) {
296276 case NC_VERSION_10 :
297- r = nc_read_until (session , NC_VERSION_10_ENDTAG , inact_timeout , & ts_act_timeout , & data );
277+ r = nc_read_until (session , NC_VERSION_10_ENDTAG , inact_timeout , & ts_act_timeout , & data , & data_len );
298278 if (r == -1 ) {
299279 ret = r ;
300280 goto cleanup ;
@@ -304,21 +284,25 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
304284 data [r - NC_VERSION_10_ENDTAG_LEN ] = '\0' ;
305285 break ;
306286 case NC_VERSION_11 :
287+ /* prepare the buffer large enough for reading the framing chunk size */
288+ frame_buf_len = 11 ;
289+ frame_size_buf = malloc (frame_buf_len + 1 );
290+ NC_CHECK_ERRMEM_GOTO (!frame_size_buf , ret = -1 , cleanup );
291+
307292 while (1 ) {
308- r = nc_read_until (session , "\n#" , inact_timeout , & ts_act_timeout , NULL );
293+ r = nc_read_until (session , "\n#" , inact_timeout , & ts_act_timeout , NULL , NULL );
309294 if (r == -1 ) {
310295 ret = r ;
311296 goto cleanup ;
312297 }
313- r = nc_read_until (session , "\n" , inact_timeout , & ts_act_timeout , & chunk );
298+ r = nc_read_until (session , "\n" , inact_timeout , & ts_act_timeout , & frame_size_buf , & frame_buf_len );
314299 if (r == -1 ) {
315300 ret = r ;
316301 goto cleanup ;
317302 }
318303
319- if (!strcmp (chunk , "#\n" )) {
304+ if (!strcmp (frame_size_buf , "#\n" )) {
320305 /* end of chunked framing message */
321- free (chunk );
322306 if (!data ) {
323307 ERR (session , "Invalid frame chunk delimiters." );
324308 ret = -2 ;
@@ -328,28 +312,27 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
328312 }
329313
330314 /* convert string to the size of the following chunk */
331- chunk_len = strtoul (chunk , (char * * )NULL , 10 );
332- free (chunk );
315+ chunk_len = strtoul (frame_size_buf , NULL , 10 );
333316 if (!chunk_len ) {
334317 ERR (session , "Invalid frame chunk size detected, fatal error." );
335318 ret = -2 ;
336319 goto cleanup ;
337320 }
338321
339- /* now we have size of next chunk, so read the chunk */
340- r = nc_read_chunk (session , chunk_len , inact_timeout , & ts_act_timeout , & chunk );
322+ /* now we have size of next chunk, prepare a buffer large enough */
323+ data = nc_realloc (data , data_len + chunk_len + 1 );
324+ NC_CHECK_ERRMEM_GOTO (!data , ret = -1 , cleanup );
325+
326+ /* read the next chunk */
327+ r = nc_read (session , data + data_len , chunk_len , inact_timeout , & ts_act_timeout );
341328 if (r == -1 ) {
342329 ret = r ;
343330 goto cleanup ;
344331 }
345332
346- /* realloc message buffer, remember to count terminating null byte */
347- data = nc_realloc (data , len + chunk_len + 1 );
348- NC_CHECK_ERRMEM_GOTO (!data , ret = -1 , cleanup );
349- memcpy (data + len , chunk , chunk_len );
350- len += chunk_len ;
351- data [len ] = '\0' ;
352- free (chunk );
333+ /* update data length and terminate the data */
334+ data_len += chunk_len ;
335+ data [data_len ] = '\0' ;
353336 }
354337
355338 break ;
@@ -374,6 +357,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
374357 /* SESSION IO UNLOCK */
375358 nc_session_io_unlock (session , __func__ );
376359 }
360+ free (frame_size_buf );
377361 free (data );
378362 return ret ;
379363}
@@ -551,10 +535,9 @@ nc_session_is_connected(const struct nc_session *session)
551535 return 1 ;
552536}
553537
554- #define WRITE_BUFSIZE (2 * BUFFERSIZE)
555538struct nc_wclb_arg {
556539 struct nc_session * session ;
557- char buf [WRITE_BUFSIZE ];
540+ char buf [NC_WRITE_CHUNK_SIZE_MAX ];
558541 uint32_t len ;
559542};
560543
@@ -757,7 +740,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
757740 return ret ;
758741 }
759742
760- if (warg -> len && (warg -> len + count > WRITE_BUFSIZE )) {
743+ if (warg -> len && (warg -> len + count > NC_WRITE_CHUNK_SIZE_MAX )) {
761744 /* dump current buffer */
762745 c = nc_write_clb_flush (warg );
763746 if (c == -1 ) {
@@ -766,7 +749,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
766749 ret += c ;
767750 }
768751
769- if (!xmlcontent && (count > WRITE_BUFSIZE )) {
752+ if (!xmlcontent && (count > NC_WRITE_CHUNK_SIZE_MAX )) {
770753 /* write directly */
771754 c = nc_write_starttag_and_msg (warg -> session , buf , count );
772755 if (c == -1 ) {
@@ -777,7 +760,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
777760 /* keep in buffer and write later */
778761 if (xmlcontent ) {
779762 for (l = 0 ; l < count ; l ++ ) {
780- if (warg -> len + 5 >= WRITE_BUFSIZE ) {
763+ if (warg -> len + 5 >= NC_WRITE_CHUNK_SIZE_MAX ) {
781764 /* buffer is full */
782765 c = nc_write_clb_flush (warg );
783766 if (c == -1 ) {
@@ -810,7 +793,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
810793 }
811794 } else {
812795 memcpy (& warg -> buf [warg -> len ], buf , count );
813- warg -> len += count ; /* is <= WRITE_BUFSIZE */
796+ warg -> len += count ; /* is <= NC_WRITE_CHUNK_SIZE_MAX */
814797 ret += count ;
815798 }
816799 }
0 commit comments