The steps described here are all executed from the main()
function in the ipprobe.c
file.
Initially, the application calls the FreeBSD function evCreate()
to create an event context.
Next, the application reads the configuration values to determine what the user asked for.
config_read()
function, in the file ipprobe_config.c
. (For introductory information about DAX, see Using DAX to Read Configurations.) For example, the following code reads the probe name and its parameters:
status = -1; while (dax_visit_container(top, &dop)) { if (!dax_get_stringr_by_aid(dop, PROBE_NAME, probe_params.name, sizeof(probe_params.name))) { PRINT_ERROR("Read probe name!\n"); goto exit; } if (strcmp(probe_params.name, probe_name) == 0) { /* Protocol is mandatory. */ if (!dax_get_ubyte_by_aid(dop, PROBE_PROTOCOL, &probe_params.protocol)) { PRINT_ERROR("Read probe protocol!\n"); goto exit; } /* The following parameters are optional. */ dax_get_ubyte_by_aid(dop, PROBE_TOS, &probe_params.tos); dax_get_ushort_by_aid(dop, PROBE_SRC_PORT, &probe_params.src_port); dax_get_ushort_by_aid(dop, PROBE_DST_PORT, &probe_params.dst_port); dax_get_ushort_by_aid(dop, PACKET_SIZE, &probe_params.packet_size); dax_get_ushort_by_aid(dop, PACKET_COUNT, &probe_params.packet_count); dax_get_ushort_by_aid(dop, PACKET_INTERVAL, &probe_params.packet_interval); status = 0; break; } }
connect_manager()
function in the file ipprobe.c
opens a socket, creates a signal handler, sets timeout values, connects to the manager running on the target, and creates a pipe for the session. The following snippets show the socket creation, connection, and pipe creation:
/* Create socket to connect to the manager on the target. */ manager_socket = socket(AF_INET, SOCK_STREAM, 0); ... manager_addr.sin_port = htons(manager_port); if (connect(manager_socket, (struct sockaddr *)&manager_addr, sizeof(manager_addr)) < 0) { if (errno == EINTR) { PRINT_ERROR("Connect to the manager TIMEOUT!\n"); } else { PRINT_ERRORNO("Connect to the manager\n"); } goto error; } ... /* Create pipe for the session. */ manager_pipe = ipc_pipe_create(PROBE_MANAGER_PIPE_SIZE); if (manager_pipe == NULL) { PRINT_ERROR("Create manager pipe!\n"); goto error; } if (ipc_pipe_attach_socket(manager_pipe, manager_socket)) { PRINT_ERROR("Attach session pipe!"); goto error; }
Once it has connected to the manager, the application retrieves the socket name by calling the FreeBSD function getsockname()
. It then calls the enable_responder()
function, which sends a message to the manager on the target router to set up the probe responder.
The request message to start the probe is defined as follows:
typedef struct { u_char protocol; /** The IP protocol */ u_short port; /** The protocol port */ } msg_start_t; ... msg_start_t msg_data;
The code calls functions in libjipc to add the message to the pipe and then send it:
req.type = PROBE_MANAGER_MSG_TYPE; req.subtype = PROBE_MANAGER_MSG_START; req.length = sizeof(msg_data); msg_data.protocol = probe_params.protocol; msg_data.port = probe_params.dst_port; if (ipc_msg_write(manager_pipe, &req, &msg_data)) { PRINT_ERRORNO("Write message!"); goto exit; } else if(ipc_pipe_write(manager_pipe, NULL)) { PRINT_ERRORNO("Write pipe!"); goto exit; }
It then calls ipc_msg_read()
to read the acknowledgment message from the manager:
do { status = ipc_pipe_read(manager_pipe); } while ((status < 0) && (errno == EAGAIN)); ... status = -1; msg = ipc_msg_read(manager_pipe); if ((msg->type != PROBE_MANAGER_MSG_TYPE) || (msg->subtype != PROBE_MANAGER_MSG_ACK)) { PRINT_ERROR("Read ACK message! type: %d", msg->subtype); goto exit; } status = 0;
receive_probe_packets()
event handler is to be invoked at the timer intervals. (See Receiving Reply Packets and Calculating Statistics for more information about this handler).