@@ -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