@@ -921,118 +921,6 @@ static int32_t parse_ipv4_socket_table_line(const char *const line_start,
921921 return SCAP_SUCCESS ;
922922}
923923
924- static int32_t parse_procfs_proc_pid_net_ipv4_file_impl (const int fd ,
925- const char * const filename ,
926- scap_fdinfo * * sockets ,
927- const int l4proto ,
928- char * const error ) {
929- // note: 32 kB is a good choice for the majority of the use cases. Each file line is
930- // approximately 150 bytes. The following table estimate how many read() system call are issued
931- // in the optimistic case (e.g.: no signals):
932- // - 100 sockets -> ~15 kB -> 1 read()
933- // - 1000 sockets -> ~150 kB -> ~5 read()
934- // - 10000 sockets -> ~1.5 MB -> ~50 read()
935- // Even in the worst scenario, the cost of issuing 50 system call should be overcome by the
936- // cache-friendly accesses using the stack-allocated buffer.
937- char buff [32 * 1024 ];
938- // `bytes_in_buff` accounts for the total amount of data currently present in `buff`.
939- size_t bytes_in_buff = 0 ;
940- while (1 ) {
941- const ssize_t read_bytes = read (fd , buff + bytes_in_buff , sizeof (buff ) - bytes_in_buff );
942- if (read_bytes < 0 ) {
943- if (errno == EINTR ) { // Re-attempt upon signal.
944- continue ;
945- }
946- return scap_errprintf (error , errno , "can't read socket table file %s" , filename );
947- }
948- if (read_bytes == 0 ) {
949- return SCAP_SUCCESS ;
950- }
951- bytes_in_buff += read_bytes ;
952-
953- // Calculate the buffer valid data range, consisting of all read data up to the last '\n'
954- // (i.e. excluding the trailing truncated new line, if present).
955- // note: if we cannot find any '\n', we set `buff_valid_len` to 0 and see later if we can
956- // recover a complete line with a shift logic and a subsequent read.
957- // optimization: search for '\n' only in the new read data, because we are sure any old data
958- // doesn't contain it.
959- const char * const new_data_start = buff + bytes_in_buff - read_bytes ;
960- const char * const last_newline = memrchr (new_data_start , '\n' , read_bytes );
961- const size_t buff_valid_len = last_newline ? last_newline - buff + 1 : 0 ;
962-
963- const char * line_start = buff ;
964- const char * buff_valid_end = buff + buff_valid_len ;
965- // note: if `buff_valid_len` is 0, this loop doesn't run.
966- while (line_start < buff_valid_end ) {
967- char * const line_end = memchr (line_start , '\n' , buff_valid_end - line_start );
968- if (!line_end ) {
969- // bug: if we enter the loop, the range [line_start, buff_valid_end] contains '\n',
970- // so it's impossible to end up here.
971- ASSERT (false);
972- return scap_errprintf (error ,
973- 0 ,
974- "bug found while parsing socket table file %s: unexpected "
975- "line with no newline" ,
976- filename );
977- }
978- // Replace '\n' with '\0' to make string-related API work.
979- // note: the original '\n' is restored at the end of the iteration.
980- * line_end = '\0' ;
981-
982- const int32_t res =
983- parse_ipv4_socket_table_line (line_start , line_end , sockets , l4proto , error );
984- if (res != SCAP_SUCCESS ) {
985- return res ;
986- }
987-
988- * line_end = '\n' ;
989- line_start = line_end + 1 ;
990- }
991-
992- // Apply shifting logic to move the truncated trailing line (if any) at the beginning of the
993- // buffer.
994- // note: this remove from the buffer any processed data, that is data in the range
995- // [buff, buff+buff_valid_len]).
996- // note: the shift is not applied if we haven't processed any data in this iteration.
997- const size_t buff_unprocessed_data_len = bytes_in_buff - buff_valid_len ;
998- if (buff_unprocessed_data_len > 0 && buff_valid_len > 0 ) {
999- memmove (buff , buff + buff_valid_len , buff_unprocessed_data_len );
1000- }
1001- // Now the buffer contains only unprocessed data.
1002- bytes_in_buff = buff_unprocessed_data_len ;
1003- if (bytes_in_buff == sizeof (buff )) {
1004- // It is almost impossible we filled the entire buffer with something not containing any
1005- // '\n' character. We don't have much to do here: just returning.
1006- ASSERT (false);
1007- return SCAP_SUCCESS ;
1008- }
1009- }
1010-
1011- // This is unreachable!
1012- ASSERT (false);
1013- return scap_errprintf (error ,
1014- 0 ,
1015- "bug found while parsing socket table file %s: control should never "
1016- "reach any statement after the outer while loop in "
1017- "parse_procfs_proc_pid_net_ipv4_file_impl()!" ,
1018- filename );
1019- }
1020-
1021- static int32_t parse_procfs_proc_pid_net_ipv4_file (const char * filename ,
1022- const int l4proto ,
1023- scap_fdinfo * * sockets ,
1024- char * const error ) {
1025- const int fd = open (filename , O_RDONLY , 0 );
1026- if (fd == -1 ) {
1027- return scap_errprintf (error , errno , "can't open socket table file %s" , filename );
1028- }
1029-
1030- const int32_t res =
1031- parse_procfs_proc_pid_net_ipv4_file_impl (fd , filename , sockets , l4proto , error );
1032- close (fd );
1033- return res ;
1034- }
1035-
1036924// Convert a single hex char to 0-15. `c` must be a valid hex char (i.e.: '0'-'9','a'-'f','A'-'F').
1037925static uint32_t hex_char_to_u32 (const char c ) {
1038926 return (c & 0xF ) + 9 * (c >> 6 );
@@ -1163,11 +1051,12 @@ static int32_t parse_ipv6_socket_table_line(const char *const line_start,
11631051 return SCAP_SUCCESS ;
11641052}
11651053
1166- static int32_t parse_procfs_proc_pid_net_ipv6_file_impl (const int fd ,
1167- const char * const filename ,
1168- scap_fdinfo * * sockets ,
1169- const int l4proto ,
1170- char * const error ) {
1054+ static int32_t parse_procfs_proc_pid_socket_table_file_impl (const int fd ,
1055+ const char * const filename ,
1056+ const int socket_domain ,
1057+ scap_fdinfo * * sockets ,
1058+ const int l4proto ,
1059+ char * const error ) {
11711060 // note: 32 kB is a good choice for the majority of the use cases. Each file line is
11721061 // approximately 150 bytes. The following table estimate how many read() system call are issued
11731062 // in the optimistic case (e.g.: no signals):
@@ -1221,8 +1110,26 @@ static int32_t parse_procfs_proc_pid_net_ipv6_file_impl(const int fd,
12211110 // note: the original '\n' is restored at the end of the iteration.
12221111 * line_end = '\0' ;
12231112
1224- const int32_t res =
1225- parse_ipv6_socket_table_line (line_start , line_end , sockets , l4proto , error );
1113+ int32_t res = SCAP_FAILURE ;
1114+ switch (socket_domain ) {
1115+ case AF_INET : {
1116+ res = parse_ipv4_socket_table_line (line_start , line_end , sockets , l4proto , error );
1117+ break ;
1118+ }
1119+ case AF_INET6 : {
1120+ res = parse_ipv6_socket_table_line (line_start , line_end , sockets , l4proto , error );
1121+ break ;
1122+ }
1123+ default : {
1124+ ASSERT (false);
1125+ return scap_errprintf (
1126+ error ,
1127+ 0 ,
1128+ "bug found while parsing socket table file %s: unknown socket domain %d" ,
1129+ filename ,
1130+ socket_domain );
1131+ }
1132+ }
12261133 if (res != SCAP_SUCCESS ) {
12271134 return res ;
12281135 }
@@ -1256,21 +1163,26 @@ static int32_t parse_procfs_proc_pid_net_ipv6_file_impl(const int fd,
12561163 0 ,
12571164 "bug found while parsing socket table file %s: control should never "
12581165 "reach any statement after the outer while loop in "
1259- "parse_procfs_proc_pid_net_ipv6_file_impl ()!" ,
1166+ "parse_procfs_proc_pid_socket_table_file_impl ()!" ,
12601167 filename );
12611168}
12621169
1263- static int32_t parse_procfs_proc_pid_net_ipv6_file (const char * filename ,
1264- const int l4proto ,
1265- scap_fdinfo * * sockets ,
1266- char * const error ) {
1170+ static int32_t parse_procfs_proc_pid_socket_table_file (const char * filename ,
1171+ const int socket_domain ,
1172+ const int l4proto ,
1173+ scap_fdinfo * * sockets ,
1174+ char * const error ) {
12671175 const int fd = open (filename , O_RDONLY , 0 );
12681176 if (fd == -1 ) {
12691177 return scap_errprintf (error , errno , "can't open socket table file %s" , filename );
12701178 }
12711179
1272- const int32_t res =
1273- parse_procfs_proc_pid_net_ipv6_file_impl (fd , filename , sockets , l4proto , error );
1180+ const int32_t res = parse_procfs_proc_pid_socket_table_file_impl (fd ,
1181+ filename ,
1182+ socket_domain ,
1183+ sockets ,
1184+ l4proto ,
1185+ error );
12741186 close (fd );
12751187 return res ;
12761188}
@@ -1293,22 +1205,31 @@ int32_t scap_fd_read_sockets(char *procdir, struct scap_ns_socket_list *sockets,
12931205 }
12941206
12951207 snprintf (filename , sizeof (filename ), "%stcp" , netroot );
1296- if (parse_procfs_proc_pid_net_ipv4_file (filename , SCAP_L4_TCP , & sockets -> sockets , err_buf ) ==
1297- SCAP_FAILURE ) {
1208+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1209+ AF_INET ,
1210+ SCAP_L4_TCP ,
1211+ & sockets -> sockets ,
1212+ err_buf ) == SCAP_FAILURE ) {
12981213 scap_fd_free_table (& sockets -> sockets );
12991214 return scap_errprintf (error , 0 , "Could not read ipv4 tcp sockets (%s)" , err_buf );
13001215 }
13011216
13021217 snprintf (filename , sizeof (filename ), "%sudp" , netroot );
1303- if (parse_procfs_proc_pid_net_ipv4_file (filename , SCAP_L4_UDP , & sockets -> sockets , err_buf ) ==
1304- SCAP_FAILURE ) {
1218+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1219+ AF_INET ,
1220+ SCAP_L4_UDP ,
1221+ & sockets -> sockets ,
1222+ err_buf ) == SCAP_FAILURE ) {
13051223 scap_fd_free_table (& sockets -> sockets );
13061224 return scap_errprintf (error , 0 , "Could not read ipv4 udp sockets (%s)" , err_buf );
13071225 }
13081226
13091227 snprintf (filename , sizeof (filename ), "%sraw" , netroot );
1310- if (parse_procfs_proc_pid_net_ipv4_file (filename , SCAP_L4_RAW , & sockets -> sockets , err_buf ) ==
1311- SCAP_FAILURE ) {
1228+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1229+ AF_INET ,
1230+ SCAP_L4_RAW ,
1231+ & sockets -> sockets ,
1232+ err_buf ) == SCAP_FAILURE ) {
13121233 scap_fd_free_table (& sockets -> sockets );
13131234 return scap_errprintf (error , 0 , "Could not read ipv4 raw sockets (%s)" , err_buf );
13141235 }
@@ -1328,27 +1249,38 @@ int32_t scap_fd_read_sockets(char *procdir, struct scap_ns_socket_list *sockets,
13281249 }
13291250
13301251 snprintf (filename , sizeof (filename ), "%stcp6" , netroot );
1331- /* We assume if there is /proc/net/tcp6 that ipv6 is available */
1332- if (access (filename , R_OK ) == 0 ) {
1333- if (parse_procfs_proc_pid_net_ipv6_file (filename , SCAP_L4_TCP , & sockets -> sockets , err_buf ) ==
1334- SCAP_FAILURE ) {
1335- scap_fd_free_table (& sockets -> sockets );
1336- return scap_errprintf (error , 0 , "Could not read ipv6 tcp sockets (%s)" , err_buf );
1337- }
1252+ // We assume IPv6 isn't available if /proc/net/tcp6 is not available.
1253+ if (access (filename , R_OK ) != 0 ) {
1254+ return SCAP_SUCCESS ;
1255+ }
13381256
1339- snprintf (filename , sizeof (filename ), "%sudp6" , netroot );
1340- if (parse_procfs_proc_pid_net_ipv6_file (filename , SCAP_L4_UDP , & sockets -> sockets , err_buf ) ==
1341- SCAP_FAILURE ) {
1342- scap_fd_free_table (& sockets -> sockets );
1343- return scap_errprintf (error , 0 , "Could not read ipv6 udp sockets (%s)" , err_buf );
1344- }
1257+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1258+ AF_INET6 ,
1259+ SCAP_L4_TCP ,
1260+ & sockets -> sockets ,
1261+ err_buf ) == SCAP_FAILURE ) {
1262+ scap_fd_free_table (& sockets -> sockets );
1263+ return scap_errprintf (error , 0 , "Could not read ipv6 tcp sockets (%s)" , err_buf );
1264+ }
13451265
1346- snprintf (filename , sizeof (filename ), "%sraw6" , netroot );
1347- if (parse_procfs_proc_pid_net_ipv6_file (filename , SCAP_L4_RAW , & sockets -> sockets , err_buf ) ==
1348- SCAP_FAILURE ) {
1349- scap_fd_free_table (& sockets -> sockets );
1350- return scap_errprintf (error , 0 , "Could not read ipv6 raw sockets (%s)" , err_buf );
1351- }
1266+ snprintf (filename , sizeof (filename ), "%sudp6" , netroot );
1267+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1268+ AF_INET6 ,
1269+ SCAP_L4_UDP ,
1270+ & sockets -> sockets ,
1271+ err_buf ) == SCAP_FAILURE ) {
1272+ scap_fd_free_table (& sockets -> sockets );
1273+ return scap_errprintf (error , 0 , "Could not read ipv6 udp sockets (%s)" , err_buf );
1274+ }
1275+
1276+ snprintf (filename , sizeof (filename ), "%sraw6" , netroot );
1277+ if (parse_procfs_proc_pid_socket_table_file (filename ,
1278+ AF_INET6 ,
1279+ SCAP_L4_RAW ,
1280+ & sockets -> sockets ,
1281+ err_buf ) == SCAP_FAILURE ) {
1282+ scap_fd_free_table (& sockets -> sockets );
1283+ return scap_errprintf (error , 0 , "Could not read ipv6 raw sockets (%s)" , err_buf );
13521284 }
13531285
13541286 return SCAP_SUCCESS ;
0 commit comments