@@ -305,6 +305,61 @@ static int init_udp(char *in_host, int in_port, struct sockaddr_in *addr)
305305    return  fd ;
306306}
307307
308+ /* Copy src into dst, stripping a single trailing '\n' if present; return len */ 
309+ static  size_t  rstrip_nl_copy (char  * dst , size_t  dstsz , const  char  * src )
310+ {
311+     size_t  n  =  strlen (src );
312+     if  (n  >  0  &&  src [n  -  1 ] ==  '\n' ) {
313+         n  -=  1 ;
314+     }
315+     if  (n  +  1  >  dstsz ) {
316+         n  =  dstsz  -  1 ;
317+     }
318+     memcpy (dst , src , n );
319+     dst [n ] =  '\0' ;
320+     return  n ;
321+ }
322+ 
323+ /* Build one octet-counted frame into 'out' as: "<len> " + msg [+ '\n' if add_lf] */ 
324+ /* Returns total bytes written (excluding terminal '\0' in 'out') */ 
325+ static  size_t  build_octet_frame (char  * out , size_t  outsz ,
326+                                 const  char  * msg , int  add_lf )
327+ {
328+     char  tmp [2048 ];
329+     size_t  mlen  =  rstrip_nl_copy (tmp , sizeof (tmp ), msg );
330+     char  hdr [64 ];
331+     int   hlen  =  snprintf (hdr , sizeof (hdr ), "%zu " , mlen );
332+     size_t  need  =  (size_t )hlen  +  mlen  +  (add_lf  ? 1  : 0 );
333+ 
334+     if  (need  +  1  >  outsz ) {
335+         /* truncate conservatively if buffer too small (shouldn't happen in tests) */ 
336+         need  =  outsz  -  1 ;
337+         add_lf  =  0 ;
338+         if  ((size_t )hlen  >  need ) {
339+             hlen  =  (int )need ;
340+         }
341+     }
342+ 
343+     memcpy (out , hdr , (size_t )hlen );
344+     memcpy (out  +  hlen , tmp , mlen );
345+     if  (add_lf ) {
346+         out [hlen  +  mlen ] =  '\n' ;
347+     }
348+     out [need ] =  '\0' ;
349+     return  need ;
350+ }
351+ 
352+ /* Build two consecutive octet-counted frames into one buffer */ 
353+ static  size_t  build_two_frames (char  * out , size_t  outsz ,
354+                                const  char  * msg1 , const  char  * msg2 ,
355+                                int  add_lf_for_each )
356+ {
357+     size_t  off  =  0 ;
358+     off  +=  build_octet_frame (out  +  off , outsz  -  off , msg1 , add_lf_for_each );
359+     off  +=  build_octet_frame (out  +  off , outsz  -  off , msg2 , add_lf_for_each );
360+     return  off ;
361+ }
362+ 
308363void  flb_test_syslog_tcp ()
309364{
310365    struct  flb_lib_out_cb  cb_data ;
@@ -1002,6 +1057,269 @@ void flb_test_syslog_rfc3164()
10021057    test_ctx_destroy (ctx );
10031058}
10041059
1060+ void  flb_test_syslog_tcp_octet_counting ()
1061+ {
1062+     struct  flb_lib_out_cb  cb_data ;
1063+     struct  test_ctx  * ctx ;
1064+     flb_sockfd_t  fd ;
1065+     int  ret ;
1066+     int  num ;
1067+     ssize_t  w_size ;
1068+ 
1069+     struct  str_list  expected  =  {
1070+         .size   =  sizeof (RFC5424_EXPECTED_STRS_1 )/sizeof (char * ),
1071+         .lists  =  & RFC5424_EXPECTED_STRS_1 [0 ],
1072+     };
1073+ 
1074+     char  frame [4096 ];
1075+     size_t  fsize  =  build_octet_frame (frame , sizeof (frame ), RFC5424_EXAMPLE_1 , /*add_lf=*/ 0 );
1076+ 
1077+     clear_output_num ();
1078+     cb_data .cb    =  cb_check_json_str_list ;
1079+     cb_data .data  =  & expected ;
1080+ 
1081+     ctx  =  test_ctx_create (& cb_data );
1082+     if  (!TEST_CHECK (ctx  !=  NULL )) {
1083+         TEST_MSG ("test_ctx_create failed" );
1084+         exit (EXIT_FAILURE );
1085+     }
1086+ 
1087+     ret  =  flb_input_set (ctx -> flb , ctx -> i_ffd ,
1088+                         "mode" , "tcp" ,
1089+                         "frame" , "octet_counting" ,
1090+                         "parser" , PARSER_NAME_RFC5424 ,
1091+                         NULL );
1092+     TEST_CHECK (ret  ==  0 );
1093+ 
1094+     ret  =  flb_start (ctx -> flb );
1095+     TEST_CHECK (ret  ==  0 );
1096+ 
1097+     fd  =  connect_tcp (NULL , -1 );
1098+     if  (!TEST_CHECK (fd  >= 0 )) {
1099+         test_ctx_destroy (ctx );
1100+         exit (EXIT_FAILURE );
1101+     }
1102+ 
1103+     w_size  =  send (fd , frame , fsize , 0 );
1104+     if  (!TEST_CHECK (w_size  ==  (ssize_t )fsize )) {
1105+         TEST_MSG ("failed to send, errno=%d" , errno );
1106+         flb_socket_close (fd );
1107+         test_ctx_destroy (ctx );
1108+         exit (EXIT_FAILURE );
1109+     }
1110+ 
1111+     flb_time_msleep (500 );
1112+     num  =  get_output_num ();
1113+     if  (!TEST_CHECK (num  >  0 )) {
1114+         TEST_MSG ("no outputs (octet_counting single)" );
1115+     }
1116+ 
1117+     flb_socket_close (fd );
1118+     test_ctx_destroy (ctx );
1119+ }
1120+ 
1121+ /* -------- TCP + RFC6587 octet-counting: frame with trailing LF -------- */ 
1122+ void  flb_test_syslog_tcp_octet_counting_lf ()
1123+ {
1124+     struct  flb_lib_out_cb  cb_data ;
1125+     struct  test_ctx  * ctx ;
1126+     flb_sockfd_t  fd ;
1127+     int  ret ;
1128+     int  num ;
1129+     ssize_t  w_size ;
1130+ 
1131+     struct  str_list  expected  =  {
1132+         .size   =  sizeof (RFC5424_EXPECTED_STRS_1 )/sizeof (char * ),
1133+         .lists  =  & RFC5424_EXPECTED_STRS_1 [0 ],
1134+     };
1135+ 
1136+     char  frame [4096 ];
1137+     size_t  fsize  =  build_octet_frame (frame , sizeof (frame ), RFC5424_EXAMPLE_1 , /*add_lf=*/ 1 );
1138+ 
1139+     clear_output_num ();
1140+     cb_data .cb    =  cb_check_json_str_list ;
1141+     cb_data .data  =  & expected ;
1142+ 
1143+     ctx  =  test_ctx_create (& cb_data );
1144+     if  (!TEST_CHECK (ctx  !=  NULL )) {
1145+         TEST_MSG ("test_ctx_create failed" );
1146+         exit (EXIT_FAILURE );
1147+     }
1148+ 
1149+     ret  =  flb_input_set (ctx -> flb , ctx -> i_ffd ,
1150+                         "mode" , "tcp" ,
1151+                         "frame" , "octet_counting" ,
1152+                         "parser" , PARSER_NAME_RFC5424 ,
1153+                         NULL );
1154+     TEST_CHECK (ret  ==  0 );
1155+ 
1156+     ret  =  flb_start (ctx -> flb );
1157+     TEST_CHECK (ret  ==  0 );
1158+ 
1159+     fd  =  connect_tcp (NULL , -1 );
1160+     if  (!TEST_CHECK (fd  >= 0 )) {
1161+         test_ctx_destroy (ctx );
1162+         exit (EXIT_FAILURE );
1163+     }
1164+ 
1165+     w_size  =  send (fd , frame , fsize , 0 );
1166+     if  (!TEST_CHECK (w_size  ==  (ssize_t )fsize )) {
1167+         TEST_MSG ("failed to send, errno=%d" , errno );
1168+         flb_socket_close (fd );
1169+         test_ctx_destroy (ctx );
1170+         exit (EXIT_FAILURE );
1171+     }
1172+ 
1173+     flb_time_msleep (500 );
1174+     num  =  get_output_num ();
1175+     if  (!TEST_CHECK (num  >  0 )) {
1176+         TEST_MSG ("no outputs (octet_counting + LF)" );
1177+     }
1178+ 
1179+     flb_socket_close (fd );
1180+     test_ctx_destroy (ctx );
1181+ }
1182+ 
1183+ /* -------- TCP + RFC6587 octet-counting: fragmented send (header then body) -------- */ 
1184+ void  flb_test_syslog_tcp_octet_counting_fragmented ()
1185+ {
1186+     struct  flb_lib_out_cb  cb_data ;
1187+     struct  test_ctx  * ctx ;
1188+     flb_sockfd_t  fd ;
1189+     int  ret ;
1190+     int  num ;
1191+     ssize_t  w_size ;
1192+ 
1193+     struct  str_list  expected  =  {
1194+         .size   =  sizeof (RFC5424_EXPECTED_STRS_1 )/sizeof (char * ),
1195+         .lists  =  & RFC5424_EXPECTED_STRS_1 [0 ],
1196+     };
1197+ 
1198+     char  msg [2048 ];
1199+     size_t  mlen  =  rstrip_nl_copy (msg , sizeof (msg ), RFC5424_EXAMPLE_1 );
1200+     char  hdr [64 ];
1201+     int    hlen  =  snprintf (hdr , sizeof (hdr ), "%zu " , mlen );
1202+ 
1203+     clear_output_num ();
1204+     cb_data .cb    =  cb_check_json_str_list ;
1205+     cb_data .data  =  & expected ;
1206+ 
1207+     ctx  =  test_ctx_create (& cb_data );
1208+     if  (!TEST_CHECK (ctx  !=  NULL )) {
1209+         TEST_MSG ("test_ctx_create failed" );
1210+         exit (EXIT_FAILURE );
1211+     }
1212+ 
1213+     ret  =  flb_input_set (ctx -> flb , ctx -> i_ffd ,
1214+                         "mode" , "tcp" ,
1215+                         "frame" , "octet_counting" ,
1216+                         "parser" , PARSER_NAME_RFC5424 ,
1217+                         NULL );
1218+     TEST_CHECK (ret  ==  0 );
1219+ 
1220+     ret  =  flb_start (ctx -> flb );
1221+     TEST_CHECK (ret  ==  0 );
1222+ 
1223+     fd  =  connect_tcp (NULL , -1 );
1224+     if  (!TEST_CHECK (fd  >= 0 )) {
1225+         test_ctx_destroy (ctx );
1226+         exit (EXIT_FAILURE );
1227+     }
1228+ 
1229+     /* Send header only first */ 
1230+     w_size  =  send (fd , hdr , (size_t )hlen , 0 );
1231+     if  (!TEST_CHECK (w_size  ==  hlen )) {
1232+         TEST_MSG ("failed to send header, errno=%d" , errno );
1233+         flb_socket_close (fd );
1234+         test_ctx_destroy (ctx );
1235+         exit (EXIT_FAILURE );
1236+     }
1237+     /* Give the input a moment to hit 'need more bytes' path */ 
1238+     flb_time_msleep (50 );
1239+ 
1240+     /* Now send body */ 
1241+     w_size  =  send (fd , msg , mlen , 0 );
1242+     if  (!TEST_CHECK (w_size  ==  (ssize_t )mlen )) {
1243+         TEST_MSG ("failed to send body, errno=%d" , errno );
1244+         flb_socket_close (fd );
1245+         test_ctx_destroy (ctx );
1246+         exit (EXIT_FAILURE );
1247+     }
1248+ 
1249+     flb_time_msleep (500 );
1250+     num  =  get_output_num ();
1251+     if  (!TEST_CHECK (num  >  0 )) {
1252+         TEST_MSG ("no outputs (octet_counting fragmented)" );
1253+     }
1254+ 
1255+     flb_socket_close (fd );
1256+     test_ctx_destroy (ctx );
1257+ }
1258+ 
1259+ /* -------- TCP + RFC6587 octet-counting: two frames back-to-back -------- */ 
1260+ void  flb_test_syslog_tcp_octet_counting_multi ()
1261+ {
1262+     struct  flb_lib_out_cb  cb_data ;
1263+     struct  test_ctx  * ctx ;
1264+     flb_sockfd_t  fd ;
1265+     int  ret ;
1266+     int  num ;
1267+     ssize_t  w_size ;
1268+ 
1269+     struct  str_list  expected  =  {
1270+         .size   =  sizeof (RFC5424_EXPECTED_STRS_1 )/sizeof (char * ),
1271+         .lists  =  & RFC5424_EXPECTED_STRS_1 [0 ],
1272+     };
1273+ 
1274+     char  frames [8192 ];
1275+     size_t  fsize  =  build_two_frames (frames , sizeof (frames ),
1276+                                     RFC5424_EXAMPLE_1 , RFC5424_EXAMPLE_1 ,
1277+                                     /*add_lf_for_each=*/ 0 );
1278+ 
1279+     clear_output_num ();
1280+     cb_data .cb    =  cb_check_json_str_list ;
1281+     cb_data .data  =  & expected ;
1282+ 
1283+     ctx  =  test_ctx_create (& cb_data );
1284+     if  (!TEST_CHECK (ctx  !=  NULL )) {
1285+         TEST_MSG ("test_ctx_create failed" );
1286+         exit (EXIT_FAILURE );
1287+     }
1288+ 
1289+     ret  =  flb_input_set (ctx -> flb , ctx -> i_ffd ,
1290+                         "mode" , "tcp" ,
1291+                         "frame" , "octet_counting" ,
1292+                         "parser" , PARSER_NAME_RFC5424 ,
1293+                         NULL );
1294+     TEST_CHECK (ret  ==  0 );
1295+ 
1296+     ret  =  flb_start (ctx -> flb );
1297+     TEST_CHECK (ret  ==  0 );
1298+ 
1299+     fd  =  connect_tcp (NULL , -1 );
1300+     if  (!TEST_CHECK (fd  >= 0 )) {
1301+         test_ctx_destroy (ctx );
1302+         exit (EXIT_FAILURE );
1303+     }
1304+ 
1305+     w_size  =  send (fd , frames , fsize , 0 );
1306+     if  (!TEST_CHECK (w_size  ==  (ssize_t )fsize )) {
1307+         TEST_MSG ("failed to send frames, errno=%d" , errno );
1308+         flb_socket_close (fd );
1309+         test_ctx_destroy (ctx );
1310+         exit (EXIT_FAILURE );
1311+     }
1312+ 
1313+     flb_time_msleep (500 );
1314+     num  =  get_output_num ();
1315+     if  (!TEST_CHECK (num  >= 2 )) {
1316+         TEST_MSG ("expected at least 2 outputs (octet_counting multi), got %d" , num );
1317+     }
1318+ 
1319+     flb_socket_close (fd );
1320+     test_ctx_destroy (ctx );
1321+ }
1322+ 
10051323TEST_LIST  =  {
10061324    {"syslog_tcp" , flb_test_syslog_tcp },
10071325    {"syslog_udp" , flb_test_syslog_udp },
@@ -1020,6 +1338,9 @@ TEST_LIST = {
10201338    {"syslog_udp_unix" , flb_test_syslog_udp_unix },
10211339#endif 
10221340#endif 
1341+     {"syslog_tcp_octet_counting" , flb_test_syslog_tcp_octet_counting },
1342+     {"syslog_tcp_octet_counting_lf" , flb_test_syslog_tcp_octet_counting_lf },
1343+     {"syslog_tcp_octet_counting_fragmented" , flb_test_syslog_tcp_octet_counting_fragmented },
1344+     {"syslog_tcp_octet_counting_multi" , flb_test_syslog_tcp_octet_counting_multi },
10231345    {NULL , NULL }
10241346};
1025- 
0 commit comments