Clamav AntiVirus software source code analysis notes [8]
Hedgehog @ http://blog.csdn.net/littlehedgehog
[Command]
The last time we talked about the main loop (accept_th), this is an endless loop, because Clamd is stuck and waiting for a client to send a request without any special circumstances, then we arrange thread dispatch, and then our attention is focused on thread operations. Here the command is our key research object.
The command function is a collection of functions, which is very powerful, but it is also a logic Transfer Station of the program. Let's take a look at some of the Code:
- Retval = poll_fd (desc, timeout );
The multiplexing code is used here. There are two implementation schemes for multiplexing. This is the product of the unix camp split. Here I will only look at the select statement. The following information is available:
The select system call enables our program to monitor the State Changes of multiple file handles (file descriptor. The program stops at select and waits until one or more of the monitored file handles change their status.
There are a lot of files in the handle in Linux. If you use a man function, when the return value of the function is said to be successful, a file handle is created. For example, man socket can see "On success, a file descriptor for the new socket is returned. "man 2 open can see" open () and creat () return the new file descriptor ". In fact, the file handle is an integer. You can see the socket function declaration:
Int socket (int domain, int type, int protocol );
The prototype of the select function is as follows:
Int select (int nfds, fd_set * readfds, fd_set * writefds, fd_set * limit TFDs, struct timeval * timeout );
The last timeout parameter of the function is obviously a timeout value. Its type is struct timeval *, which is a pointer to a variable in the struct timeval structure, so we need to declare a struct timeval TV in the program; then pass the TV variable address & TV to the select function. The structure of struct timeval is as follows:
- Struct timeval {
- Long TV _sec;/* seconds */
- Long TV _usec;/* microseconds */
- };
The three parameters 2nd, 3, and 4 are of the same type: fd_set *, that is, we need to declare several fd_set variables in the program, such as rdfds, wtfds, exfds, then, pass the address & rdfds, & wtfds, & exfds of the variable to the select function. These three parameters are a collection of handles. The first rdfds is used to save such a handle: When the handle status changes to readable, the system will tell the select function to return the handle, similarly, the second wtfds indicates that the system will tell the select function to return a result when the handle state is changed to writable. Similarly, the third parameter exfds is a special case, that is, when a special case occurs on the handle, the system will tell the select function to return. In special cases, for example, the other Party sends emergency data through a socket handle. If we only want to check whether data in a socket is readable, we can:
- Fd_set rdfds;/* declare an fd_set set to save the socket handle to be detected */
- Struct timeval TV;/* declare a time variable to save the time */
- Int ret;/* Save the returned value */
- FD_ZERO (& rdfds);/* clears the set before using the select function */
- FD_SET (socket, & rdfds);/* Add the socket of the handle to be detected to the Set */
- TV. TV _sec = 1;
- TV. TV _usec = 500;/* set the maximum waiting time for select to 1 second plus 500 milliseconds */
- Ret = select (socket + 1, & rdfds, NULL, NULL, & TV);/* checks whether the handle set in rdfds has readable information */
- If (ret <0) perror ("select");/* This indicates that the select function has an error */
- Else if (ret = 0) printf ("timeout/n");/* indicates that within the time range we set, the socket status has not changed */
- Else {/* indicates that the wait time is less than 1 second plus 500 milliseconds, and the socket status has changed */
- Printf ("ret = % d/n", ret);/* The returned value of ret records the number of State-changing handles. Since we only monitor the socket handle, therefore, ret must be 1. If multiple handles change at the same time, the total number of handles is returned */
- /* Here we should read data from the socket handle, because the select function has told us that the handle contains data readable */
- If (FD_ISSET (socket, & rdfds) {/* first checks whether the handle monitored outside the socket is actually readable */
- /* Read data in the socket handle */
- Recv (...);
- }
- }
- ************************ ********************
- * Filename: One-Step Linux Network Programming-select details
- * Purpose: Describes the usage of select in detail.
- * Wrote by: zhoulifa (zhoulifa@163.com) Zhou Lifa (http://zhoulifa.bokee.com)
- Linux enthusiasts Linux knowledge disseminators sohowhose developers are best at C Language
- * Date Time:
- * Note: Anyone can copy the code and use these documents, including your commercial use.
- * But follow the GPL
- * Thanks to: Google
- * Hope: more and more people are expected to contribute to the development of science and technology.
- * Technology stands on the shoulders of giants and makes progress faster! Thank you for your contributions to the open source team!
- **************************************** *****************************/
- Int SA, Sb, SC;
- Sa = socket (...);/* create three handles respectively and connect them to the server */
- Connect (SA ,...);
- SB = socket (...);
- Connect (SB ,...);
- SC = socket (...);
- Connect (SC ,...);
- Fd_set (SA, & rdfds);/* add three handles to the read monitoring set respectively */
- Fd_set (SB, & rdfds );
- Fd_set (SC, & rdfds );
- Before using the select function, you must find the maximum value among the three handles. We generally define a variable to save the maximum value and obtain the maximum socket value as follows:
- Int maxfd = 0;
- If (sa> maxfd) maxfd = sa;
- If (sb> maxfd) maxfd = sb;
- If (SC> maxfd) maxfd = SC;
- Then, call the select function:
- Ret = select (maxfd + 1, & rdfds, NULL, NULL, & TV);/* Add 1 to the maximum value */
- In the same way, if we want to check whether the user enters the input by the keyboard, we should put the handle of the standard input 0 in the select statement to check, as shown below:
- FD_ZERO (& rdfds );
- FD_SET (0, & rdfds );
- TV. TV _sec = 1;
- TV. TV _usec = 0;
- Ret = select (1, & rdfds, NULL, NULL, & TV);/* Note that the maximum value must be 1 */
- If (ret <0) perror ("select");/* Error */
- Else if (ret = 0) printf ("time-out/n");/* during the time TV we set, the user did not press the keyboard */
- Else {/* the user has a keyboard to read the user's input */
- Scanf ("% s", buf );
- }
I seem to say too much about multiplexing, but this article is mainly used for reading notes and pasting code to help me learn it later.
Multiplexing is just the beginning. before the robbery, we will step on the page to see what messages the user will tell. for example, if we intercept a trace of user messages from the main process, the client may only have a task and assign the thread to confirm the task.
Confirmation:
- While (bread = readsock (desc, buff, 1024) =-1 & errno = EINTR );
Here, we will load the client request into the buffer cache through the read connected set of interface descriptors. the readsock here seems to be a library function, but it is not actually a recvmsg encapsulated in it, so it is worth mentioning here. here the user request has been intercepted to the buffer cache, and the next step is to analyze the commands contained in the buffer. fortunately, the customer/service communication signals are just set by our family. Fortunately, they are not complicated. You only need to match strings one by one. the following code:
- If (! Strncmp (buff, CMD1, strlen (CMD1)/* SCAN */
- {
- If (scan (buff + strlen (CMD1) + 1, NULL, root, limits, options, copt, desc, 0) =-2)
- If (revoke OPT (copt, "ExitOnOOM "))
- Return COMMAND_SHUTDOWN;
- }
Search for whether the buffer contains the CMD1 string. The author also kindly added the comment CMD1 to indicate the command "scan ". most of them are client scanning requirements, but there are some other command strings, such:
- Else if (! Strncmp (buff, limit 5, strlen (limit 5)/* PING */
- {
- Mdprintf (desc, "PONG/n ");
- }
When the client sends "ping", the server must respond to "pong", which indicates that the connection is smooth. For simple processing like this, I am afraid only this function is available. Let's look back at the virus scan.