📄 c-extend3.html
字号:
</dl></dl><dd><div class="Item"><a name="84555"> </a>close brace (<b>}</b>)</div><dl class="margin"><dl class="margin"><dd><div class="Indent2"><a name="84556"> </a>ends the subroutine. (Note that for all Gopher constructions using matching delimiters (<b class="symbol_lc">{ }</b>, <b class="symbol_lc">< ></b>, and so on) the "outer" value of the pointer is saved during the execution of the inner material, and restored when the closing delimiter is executed.)</div><br></dl></dl></dl><dl class="margin"><dd><p class="Body"><a name="84557"> </a>Now that you have a Gopher script to move the pointer from the first element of the first structure to the first element of each successive structure in the linked list, you need to write a Tcl routine that uses the Gopher script to traverse the linked list, printing out the address of each node. The <b class="tclProc">wtxGopherEval</b> procedure allows you to send a Gopher script to the target for interpretation and execution. The procedure <b class="tclProc">netIfList </b>returns a list of network interface descriptors (pointers to <b class="symbol_lc">ifnet</b> structures):</p><dl class="margin"><dd><pre class="Code2"><b><a name="84558">proc netIfList {} { set block [wtxMemRead [lindex [wtxSymFind -name ifnet] 1] 4] set ifnet [memBlockGet -l $block] return [wtxGopherEval "$ifnet {! +4 *}"] }</a></b></pre></dl><dd><p class="Body"><a name="84563"> </a>Try this routine from the shell by using the <b class="symbol_lc">?</b> character to toggle to the shell Tcl prompt:</p><dl class="margin"><dd><pre class="Code2"><b><a name="84564"></b><tt class="output">-> </tt><b>? </b><tt class="output">tcl> </tt><b>source <i class="textVariable">homeDir</i>/.wind/netIfList.tcl </b><tt class="output">tcl> </tt><b>netIfList </b><tt class="output">0x94e8c 0x9531c</tt><b></a></b></pre></dl><dd><p class="Body"><a name="84568"> </a>Restart the shell before switching to the Tcl prompt or source the file.</p></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H3"><i><a name="84569">5.3.4 Listing the Contents of Each Structure</a></i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="84570"> </a>The next step is to write a routine that extracts the relevant fields from one network interface descriptor in the form of a list. The list serves as an intermediate representation which is the basis for the shell's and browser's presentations of the data.</p><dd><p class="Body"><a name="84571"> </a>Use the Gopher language interpreter to extract the data. (For a detailed discussion of the Gopher operators, see <a href="c-wtx3.html#84997"><i class="title">4.3.11 Gopher Support</i></a>.) The first field of interest in the <b class="symbol_lc">ifnet</b> structure is the <b class="symbol_lc">if_name</b> field. You used <b class="tclProc">netIfList</b> to find the address of the first byte of the structure, which is also the address of the string. Use the following Gopher string to dereference this pointer and write the string to the tape:</p></dl><dl class="margin"><dd><pre class="Code"><b><a name="84575"> <*$></a></b></pre></dl><dl class="margin"><dd><p class="Body"><a name="84576"> </a>Remember that the angle brackets delineate a subcontext in which the outer pointer value is saved. When the <b class="symbol_lc">*</b> is executed, the pointer is dereferenced, but outside the angle brackets, the old value of the pointer is preserved. The operator <b class="symbol_lc">$</b> copies the string to the tape. After leaving the subcontext, the pointer still points to the top of the structure. </p><dd><p class="Body"><a name="84577"> </a>Now, fetch the next two interesting fields, <b class="symbol_lc">if_unit</b> and <b class="symbol_lc">if_flags</b>. The pointer is still pointing to <b class="symbol_lc">if_name</b>, therefore use a signed constant to advance it over the twenty two bytes of the pointer (<b class="symbol_lc">+22</b>). The <b class="symbol_lc">@</b> operator with the <b class="symbol_lc">w</b> suffix (16-bit word) writes the value at the pointer to the tape. A side effect of the <b class="symbol_lc">@</b> operator is that the pointer value is advanced past the data written; in effect, <b class="symbol_lc">@w</b> copies the 16-bit value at the pointer to the tape and increases the value of the pointer by 2. Next, fetch <b class="symbol_lc">if_mtu</b> and <b class="symbol_lc">if_metric</b>, which are stored in the <b class="symbol_lc">if_data</b> structure. Use a signed constant (<b class="symbol_lc">+2</b>) to skip over the field <b class="symbol_lc">if_timer</b>, and (<b class="symbol_lc">+4</b>) to skip the first bytes (including one byte for padding) of the <b class="symbol_lc">if_data</b> structure to get the <b class="symbol_lc">if_mtu</b> and <b class="symbol_lc">if_metric</b> fields. To read the four fields starting with the pointer at the <b class="symbol_lc">if_unit</b> field, the fragment is:</p></dl><dl class="margin"><dd><pre class="Code"><b><a name="84578"> +22 @w +2 @w +4 @@</a></b></pre></dl><dl class="margin"><dd><p class="Body"><a name="84579"> </a>For the five packet-statistics fields (<b class="symbol_lc">ifi_ipackets</b> through <b class="symbol_lc">ifi_collisions</b>), advance the pointer to the first field and use the <b class="symbol_lc">@</b> operator five times.</p></dl><dl class="margin"><dd><pre class="Code"><b><a name="84580"> +4 @@@@@</a></b></pre></dl><dl class="margin"><dd><p class="Body"><a name="84581"> </a>The routine <b class="tclProc">netIfInfo</b> combines these fragments to return the values of interest, given the address of a single network interface. </p><dl class="margin"><dd><pre class="Code2"><b><a name="84582">proc netIfInfo {netIf} {</a></b><dd> <b><a name="84583"> return [wtxGopherEval "$netIf <*$> +22 @w +2 @w +4 @@ +4 @@@@@"]</a></b><dd> <b><a name="84584">}</a></b></pre></dl><dd><p class="Body"><a name="84585"> </a>Test the two routines with the following expression:</p><dl class="margin"><dd><pre class="Code2"><b><a name="84586"></b><tt class="output">tcl</tt><b>> foreach netIf [netIfList] {puts stdout [netIfInfo $netIf]}</b><tt class="output"> ei 0 0x8063 0x5dc 0 0x19b 0 0x1 0 0 lo 0 0x8069 0x8000 0 0 0 0 0 0</tt><b></a></b></pre></dl><dd><p class="Body"><a name="84589"> </a>You now have most of the information needed to duplicate the output produced by the target shell routine <b class="routine"><i class="routine">ifShow</i></b><b>( )</b>. You still need the Internet addresses of the interfaces, which are stored in a linked list attached to each node of the <b class="symbol_lc">ifNet</b> list by way of the <b class="symbol_lc">if_addrlist </b>pointer. The following example shows the definition of the <b class="symbol_lc">if_addr</b> structure:</p></dl><dl class="margin"><dd><pre class="Code"><b><a name="84613">struct ifaddr { struct sockaddr * ifa_addr; /* address of interface */ struct sockaddr * ifa_dstaddr; /* other end of p-to-p link */ #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ struct sockaddr * ifa_netmask; /* used to determine subnet */ struct ifnet * ifa_ifp; /* back-pointer to interface */ struct ifaddr * ifa_next; /* next address for interface */ void (*ifa_rtrequest)(); /* check or clean routes */ /* (+ or -)'d */ u_short ifa_flags; /* mostly rt_flags for cloning */ short ifa_refcnt; /* count of references */ int ifa_metric; /* cost of going out this */ /* interface */ }; struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; struct in_addr { u_long s_addr; };</a></b></pre></dl><dl class="margin"><dd><p class="Body"><a name="85522"> </a>The second set of four bytes in the <b class="symbol_lc">sockaddr</b> structures contains the Internet addresses. Note that they are stored in Internet byte order (big-endian). If you were to use an <b class="symbol_lc">@l</b> operator to extract them, the result would come out swapped if the target architecture is little-endian. To avoid this, read the addresses as four one-byte values. Given a pointer to the first node in a list of these structures and the various offsets, the Gopher script to extract the two addresses in each node (<b class="symbol_lc">ifa_addr</b> and <b class="symbol_lc">ifa_dstaddr</b>) is:</p><dl class="margin"><dd><pre class="Code2"><b><a name="84614"><*{+4 @b@b@b@b 0}> +4 <*{+4 @b@b@b@b 0}> </a></b></pre></dl><dd><p class="Body"><a name="84615"> </a>The <b class="tclProc">netIfAddrList</b> routine takes a network interface descriptor, advances to the <b class="symbol_lc">if_addrlist</b> field and dereferences it, and then repeatedly executes this fragment to copy the Internet addresses (we skip the first address, which represents an internal linkage).</p><dl class="margin"><dd><pre class="Code2"><b><a name="84616">proc netIfAddrList {netIf} { return [wtxGopherEval "$netIf +8 * {+16 * {<*{+4 @b@b@b@b 0}> +4 <*{+4 @b@b@b@b 0}>+12 *}0}"]</a></b><dd> <b><a name="84619">}</a></b></pre></dl><dd><p class="Body"><a name="84620"> </a>Testing from the shell yields:</p><dl class="margin"><dd><pre class="Code2"><b><a name="84621"></b><tt class="output">tcl></tt><b> foreach netIf [netIfList] {puts stdout [netIfAddrList $netIf]} </b><tt class="output">0x93 0xb 0x50 0xca 0x93 0xb 0x50 0xff 0x7f 0 0 0x1 0x7f 0 0 0x1</tt><b></a></b></pre></dl><dd><p class="Body"><a name="84624"> </a>Each interface has two addresses so each result has eight octets. The program that calls this routine must partition the results into four-octet sets. </p><dd><p class="Body"><a name="84625"> </a>By designing these routines to return results in Tcl list form, you have created information gathering routines that can be used in multiple contexts. They can be used by the shell, the browser, or other any Tcl application. Storing them in the <b class="file">resource/tcl</b> directory makes them available to all Tcl applications (see <a href="c-extend2.html#84416">Figure 5-1</a>).</p></dl></dl><dl class="margin"><dd><p class="table" callout><table border="0" cellpadding="0" cellspacing="0"><tr valign="top"><td valign="top" width="40"><br><img border="0" alt="*" src="icons/note.gif"></td><td><hr><div class="CalloutCell"><a name="85749"><b class="symbol_UC"><font face="Helvetica, sans-serif" size="-1" class="sans">NOTE: </font></b></a>Wind River Systems has developed a "Gopher generator" tool which generates gopher scripts from a C structure. This tool is not supported, but is available free of charge. It can be downloaded from the Wind River System WEB server (www.wrs.com). </div></td></tr><tr valign="top"><td></td><td><hr></td></tr><tr valign="middle"><td colspan="20"></td></tr></table></p callout></dl><a name="foot"><hr></a><p class="navbar" align="right"><a href="index.html"><img border="0" alt="[Contents]" src="icons/contents.gif"></a><a href="c-extend.html"><img border="0" alt="[Index]" src="icons/index.gif"></a><a href="c-extend.html"><img border="0" alt="[Top]" src="icons/top.gif"></a><a href="c-extend2.html"><img border="0" alt="[Prev]" src="icons/prev.gif"></a><a href="c-extend4.html"><img border="0" alt="[Next]" src="icons/next.gif"></a></p></body></html><!---by WRS Documentation (), Wind River Systems, Inc. conversion tool: Quadralay WebWorks Publisher 4.0.11 template: CSS Template, Jan 1998 - Jefro --->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -