Tuesday, November 10, 2009

Finger: A Simple Directory Service










Perl for System AdministrationSearch this book









6.2. Finger: A Simple Directory Service








Finger and
WHOIS are good examples of simple directory services. Finger exists
primarily to provide read-only information about the users of a
machine (although we'll see some more creative uses shortly).
Later versions of Finger, like the GNU Finger server and its
derivatives, expanded upon this basic functionality by allowing you
to query one machine and receive information back from all of the
machines on your network.







Finger was one of the first widely deployed directory services. Once
upon a time, if you wanted to locate a user's email address at
another site, or even within your own, the finger
command was the best option. finger
harry@hogwarts.edu
would tell you whether Harry's
email address was harry,
hpotter, or something more obscure (along with
listing all of the other Harrys at that school). Though it is still
in use today, Finger's popularity has waned over time as web
home pages became prevalent and the practice of freely giving out
user information became problematic.








Using the Finger protocol from Perl
provides another good example of TMTOWTDI. When I first looked on
CPAN for something to perform Finger operations, there were no
modules available for this task. If you look now, you'll find
Dennis Taylor's Net::Finger module, which he
published six months or so after my initial search. We'll see
how to use it in a moment, but in the meantime, let's pretend
it doesn't exist and take advantage of this opportunity to
learn how to use a more generic module to talk a specific protocol
when the "perfect" module doesn't exist.







The Finger protocol itself is a very simple TCP/IP-based text
protocol. Defined in RFC1288, it calls for a standard TCP connect to
port 79. The client passes a simple CRLF-terminated[1] string over the connection. This string either requests
specific user information or, if empty, asks for information about
all users of that machine. The server responds with the requested
data and closes the connection at the end of the data stream. You can
see this in action by telnet ing to the Finger
port directly on a remote machine:








[1]Carriage return + linefeed, i.e., ASCII 13 + ASCII 10.













$ telnet kantine.diku.dk 79
Trying 192.38.109.142 ...
Connected to kantine.diku.dk.
Escape character is '^]'.
cola<CR><LF>
Login: cola Name: RHS Linux User
Directory: /home/cola Shell: /bin/noshell
Never logged in.
No mail.
Plan:

Current state of the coke machine at DIKU
This file is updated every 5 seconds
At the moment, it's necessary to use correct change.
This has been the case the last 19 hours and 17 minutes

Column 1 is currently *empty*.
It's been 14 hours and 59 minutes since it became empty.
31 items were sold from this column before it became empty.
Column 2 contains some cokes.
It's been 2 days, 17 hours, and 43 minutes since it was filled.
Meanwhile, 30 items have been sold from this column.
Column 3 contains some cokes.
It's been 2 days, 17 hours, and 41 minutes since it was filled.
Meanwhile, 11 items have been sold from this column.
Column 4 contains some cokes.
It's been 5 days, 15 hours, and 28 minutes since it was filled.
Meanwhile, 26 items have been sold from this column.
Column 5 contains some cokes.
It's been 5 days, 15 hours, and 29 minutes since it was filled.
Meanwhile, 18 items have been sold from this column.
Column 6 contains some coke-lights.
It's been 5 days, 15 hours, and 30 minutes since it was filled.
Meanwhile, 16 items have been sold from this column.

Connection closed by foreign host.
$







In this example we've connected directly to kantine.diku.dk's Finger port. We
typed the user name "cola," and the server returned
information about that user.







I chose this particular host and user just to show you some of the
whimsy that accompanied the early days of the Internet. Finger
servers got pressed into service for all sorts of tasks. In this
case, anyone anywhere on the planet can see whether the soda machine
at the Department of Computer Science at the University of Copenhagen
is currently stocked. For more examples of strange devices hooked to
Finger servers, you may wish to check out Bennet Yee's
"Internet Accessible Coke Machines" and "Internet
Accessible Machines" pages; they are available online at
http://www.cs.ucsd.edu/~bsy/fun.html.







Let's take the network communication we just performed using a
telnet binary back to the world of Perl. With
Perl, we can also open up a network socket and communicate over it.
Instead of using lower-level socket commands, we'll use Jay
Roger's Net::Telnet module to introduce a
family of modules that handle generic network discussions. Other
modules in this family (some of which we use in other chapters)
include Eric Arnold's Comm.pl, Austin
Schutz's Expect.pm, and the venerable but
outdated and nonportable chat2.pl by Randal L.
Schwartz.








Net::Telnet will handle all of the connection
setup work for us and provides a clean interface for sending and
receiving data over this connection. Though we won't use them
in this example, Net::Telnet also provides some
handy pattern-scanning mechanisms that allow your program to watch
for specific responses from the other
server.







Here's a Net::Telnet version of a simple
Finger client. This code takes an argument of the form
user@finger_server. If the user name is omitted, a
list of all users considered active by the server will be returned.
If the hostname is omitted, we query the local host:








use Net::Telnet;

($username,$host) = split(/\@/,$ARGV[0]);
$host = $host ? $host : 'localhost';

# create a new connection
$cn = new Net::Telnet(Host => $host,
Port => 'finger');

# send the username down this connection
unless ($cn->print("$username")){ # could be "/W $username"
$cn->close;
die "Unable to send finger string: ".$cn->errmg."\n";
}

# grab all of the data we receive, stopping when the
# connection is dropped
while (defined $ret = $cn->get) {
$data .= $ret;
}

# close the connection
$cn->close;

# display the data we collected
print $data;







RFC1288 specifies that a /W switch can be
prepended to the username sent to the server to request it to provide
"a higher level of verbosity in the user information
output," hence the /W comment above.







If you need to connect to another TCP-based text protocol besides
Finger, you'd use very similar code. For example, to connect to
a Daytime server (which shows the local time on a machine) the code
looks very similar:








use Net::Telnet;

$host = $ARGV[0] ? $ARGV[0] : 'localhost';

$cn = new Net::Telnet(Host => $host,
Port => 'daytime');

while (defined $ret = $cn->get) {
$data .= $ret;
}
$cn->close;

print $data;







Now you have a sense of how easy it is to create generic TCP-based
network clients. If someone has taken the time to write a module
specifically designed to handle a protocol, it can be even easier. In
the case of Finger, you can use Taylor's
Net::Finger to turn the whole task into a single
function call:








use Net::Finger;

# finger( ) takes a user@host string and returns the data received
print finger($ARGV[0]);







Just to present all of the options, there's also the fallback
position of calling another executable (if it exists on the machine)
like so:








($username,$host) = split('@',$ARGV[0]);
$host = $host ? $host : 'localhost';

# location of finger executable, MacOS users can't use this method
$fingerex = ($^O eq "MSWin32") ?
$ENV{'SYSTEMROOT'}."\\System32\\finger" :
"/usr/ucb/finger"; # (could also be /usr/bin/finger)

print `$fingerex ${username}\@${host}`







Now you've seen three different methods for performing Finger
requests. The third method is probably the least ideal because it
requires spawning another process.
Net::Finger will handle simple
Finger requests; for everything else, Net::Telnet
or any of its kin should work well for you.















Copyright © 2001 O'Reilly & Associates. All rights reserved.







Semaphores, Events, Messages, and Timers










































Semaphores, Events, Messages, and Timers


At this point, you have a basic understanding of
the core parts of the RTOS. I have mentioned system calls several times
but never really elaborated on what a system call is. Like threads and
tasks, the definition of a system call depends on the company you keep.
In general, a system call refers to an operating system facility that,
when invoked, causes a context switch into the kernel because the
resource with which the system call interfaces is only accessible in
kernel mode. With embedded systems, the term system call
usually just refers to one of the RTOS’s API functions, and that
definition is the one I’ve used in this book. If the RTOS has all of
the nice stuff I’ve talked about so far, it still can’t do much.
Compare it to a farm tractor that has a heavy-duty motor and a lot of
power but doesn’t have any attachments. The attachments included with
the RTOS are the system calls that allow us to communicate between
tasks, to communicate between interrupt handlers and tasks, to
guarantee that only one task executes a certain function at a time, to
set up timers, and so forth. Every RTOS comes with some set of system
calls, but, in general, all RTOSs share a few basic functions.



Semaphores can be used to
synchronize access to a shared resource. A common form of
synchronization is mutual exclusion, meaning that tasks coordinate
their access to a resource so that only one task at a time is
manipulating the resource. For example, if a semaphore-protected
function has begun executing and a context switch transfers control to
another section of code that also tries to call the protected function,
the second call is blocked. Mutually exclusive access is needed
whenever more than one task (i.e., code in separate threads or
processes) is allowed to access the same resource.


For example, assume a system has some memory-mapped
register that contains eight bits, each of which control an LED (1 =
on), and assume that I use the function in Listing B.1 to modify those bits.



Listing B.1: LedOn().







unsigned char
LedOn(unsigned char onbits)
{
unsigned char current_bits;

current_bits = *(unsigned char *)LED_PORT;
current_bits |= onbits;
*(unsigned char *)LED_PORT = current_bits;
return(current_bits);
}













What would happen if (referring to Listing B.1), just after the variable current_bits is loaded from the LED_PORT
address, an asynchronous context switch occurred and some other task
called this function, passing it a different value? Quick answer: the
setting established by the second task would be lost. Let’s assume that
on the first call to LedOn(), the value of onbits is 0x01, and the current value in LED_PORT is 0x80. If no context switch occurred, the result would be that LED_PORT would be 0x81, meaning that two LEDs would be lit.


If, however, a context switch happens in just the right place, the result is different. On the first call to LedOn() after the line


current_bits = *(unsigned char *)LED_PORT; 

the value stored in current_bits is 0x80. Now assume that a context switch occurs after this line and that another task calls this function with 0x02 as the onbits value. The second invocation runs to completion leaving, for the momemt, the LED_PORT value at 0x82. At some point in the future, context is restored to the original task. This instance of the function resumes at the line


current_bits |= onbits 

with current_bits (in the original context) set to 0x80. When this value of current_bits is logically ORed with onbits (0x01), the result 0x81 is written to the LED port. The result is that the value established by the preempting task (0x82) is lost.


The solution to this problem is mutual exclusion. If these LED operations were properly wrapped with semaphore operations (Get at the top and Release
at the bottom), then when the context switch occurred, the preempting
task would not have been allowed to manipulate the LEDs until the task
that owned the semaphore was done.



Events are OS-provided
flags that, when set by one task or interrupt handler, cause some other
task to wake up (i.e., to enter the ready-to-run state). Typically,
signaling with events involves two system calls: one to post an event
and one to block waiting for an event. Events are typically not queued.
If the same event is posted several times prior to the acknowledgment
of the event by the task that is blocked while waiting for it, those
additional postings are lost. Because events are a simple flag, after
the flag is set, setting it again has no significance. Usually events
have lower overhead than other types of interprocess communication and
thus are commonly used for communication between an interrupt handler
and a task.



Messages provide a
mechanism that allows a task (or interrupt handler) to send some data
to another task. Unlike events, messages are queued. When multiple
messages are sent to some task that is blocked while waiting for the
message, each message is queued by the OS for later consumption by the
receiver of the message.


Most RTOSs support the ability to send a message to be
posted to the end of the queue and also to be posted to the head of the
queue. In some situations, it can be very handy to be able to expedite
a message by posting it to the head of the queue, but this feature must
not be abused. When a message is placed in a queue, it is usually on a
first-in first-out (FIFO) basis. If the message is put at the top of
the queue, then it becomes a last-in first-out (LIFO) basis, which is
ok, but you’d bet ter be aware of the difference.


Messages can be passed from task-to-task or from interrupt-to-task, but a message usually imposes more overhead than an event.



Timers are probably the
most heavily used facility within an RTOS. Not only is there typically
some set of system calls specifically for timers, but many of the other
system calls usually provide some time-out mechanism as well. The most
common timer function is the ability to put a task to sleep for some
period of time or to wake a task at some time of day in the future. The
simplest example would be a task that blinks an LED (see Listing B.2).



Listing B.2: task_BLINKER().






void
task_BLINKER(void)
{
while(1)
{
Turn_On_Led();
GoToSleep(1000);
Turn_Off_Led();
GoToSleep(1000);
}
}













The GoToSleep() system call is the timer function that allows the task to wake up periodically. Aside from GoToSleep(),
other system calls intrinsically use timers to support the ability to
time-out. For example, a task might want to wait for an incoming event,
but, if the event does not occur for 30 seconds, some other action must
occur. In this case, the system call is an event mechanism, but, under
the hood, the event mechanism is using timers.




































10.5 Default Auditing












for Ru-Brd & DownSky

size=+0>

10.5 Default Auditing


As we
mentioned earlier in this chapter, some actions will be stored to
operating system files whether auditing is enabled or not. These actions
are:




  • Database startup



  • Database shutdown



  • Connection to the database from a privileged account



  • Structural changes made to the database, like adding a tablespace
    datafile, etc.


When the database is started up, a record is written automatically to
an operating system file. If the database was started with either
sys or internal, the user information will not be recorded.
The information recorded is the operating system username of the process
starting the database, the terminal identifier, the timestamp (date and
time) when the database was started, and whether or not auditing was
enabled. The purpose of writing this information is to create a record of
anyone attempting to start the database and disable auditing in order to
hide their actions. At the time of database startup, the database audit
trail is not yet available, so the startup information is always written
to an operating system audit file.


In all of the auditing situations listed above, the information is
recorded to an operating system log. If the operating system does not
enable Oracle to access its audit facility, Oracle will record the
information in a log in the same directory in which the background
processes record their activities.


10.5.1 Auditing During Database Startup


The first type of default
auditing occurs during database startup. An example of operating system
audit entries stored automatically for a Windows NT
system running Oracle version 8.0.4 is shown here:

Audit trail: ACTION : 'startup' OS_AUTHENT_PREFIX : OPS$. (3:55:41 a.m.)
Audit trail: ACTION : `startup' AUDIT_TRAIL : none. (3:55:40 a.m.)
Audit trail: ACTION : `connect INTERNAL' OSPRIV : OPER CLIENT USER: SYSTEM CLIENT TERMINAL: MLT-PC. (3:55:31 a.m.)

These three entries were found in the Event Viewer, at the Start Programs
Administrative Tools Event Viewer
menu option on a Window NT system. There are three event logs — System,
Security, and Application — into which anyone can insert an event. Oracle
will log events in both the System and the Application event logs. The
time notations in parentheses were added by us to show you more clearly
the sequence of events.


The first entry in the sequence above is actually the one listed last.
This entry shows the initial connection made to the database in order to
start it. Of special interest in the third entry is the notation of the
client terminal from which the database was started — MLT-PC — and the
system privilege used — OSPRIV. The three audit notations were present in
the Windows NT Administrative Tools Event Viewer, in the Application log,
after the database was started. As each of the individual detached
processes (PMON, SMON, DBWR, LGWR, CKPT, RECO) was started, an individual
entry was inserted in the event log. There was also an entry for the time
at which the SGA was initialized.


10.5.2 Auditing During Database Shutdown


The second form of default auditing that may occur
is at the time of database shutdown. Each time the database is shut down,
a record may be written to the audit trail indicating the operating system
username, the user's terminal identifier, and the date and timestamp when
the action occurred. The use of the words "may be" in the last sentence is
intentional. Depending on the operating system involved, if a privileged
user, like SYSDBA or SYSOPER, shuts the database down, the
event might not be registered in the System event log. On a Windows NT
version 4.0 system running Oracle8 version 8.0.4, if the database is shut
down using the command:

net stop OracleStart<db_name>

no record of the database shutdown is made either to the Windows NT
Application event log or to the database alert log.


If your operating system/database automatically
records the shutdown attempts performed by non-privileged users, you will
find this information very valuable if you are investigating why your
database unexpectedly shut down. The absence of an event entry for the
shutdown could help you eliminate the fear that your database had been
intentionally shut down by an outsider.


10.5.3 Auditing During Database Connection with Privileges


The third default action
recorded to the operating system audit trail occurs when a user connects
to the database with administrative privileges. The operating system user
information is recorded. This information is very valuable in helping you
detect whether someone has managed to acquire privileges they should not
have.


10.5.4 Auditing During Database Structure Modification


When a command is issued from
the database to modify the structure of the database, the command and its
outcome are captured to the alert log for that database. This is the
fourth default action. Some examples of commands that will be captured in
the alert log follow:

CREATE TABLESPACE <tablespace_name>
ALTER TABLESPACE <tablespace_name> ADD DATAFILE
ALTER TABLESPACE OFFLINE DROP TABLESPACE <tablespace_name>
INCLUDING CONTENTS
CREATE ROLLBACK SEGMENT <rollback_segment_name>

In all of these commands, the successful completion of the command will
in some way alter the structure of the database.











for Ru-Brd & DownSky




Section 34.2.&nbsp; Routing Table Initialization










34.2. Routing Table Initialization


Routing tables are initialized with fib_hash_init, defined in net/ipv4/fib_hash.c. It is called by ip_fib_init, which initializes the IP routing subsystem, to create the ip_fib_main_table and ip_fib_local_table tables (see the section "Routing Subsystem Initialization" in Chapter 32).


The first time fib_hash_init is called, it creates the memory pool fn_hash_kmem that will be used to allocate fib_node data structures.


fib_hash_init first allocates a fib_table data structure and then initializes its virtual functions to the routines shown in Table 34-1. The function also clears the content of the bottom part of the structure (fn_hash), which, as shown in Figure 34-1, is used to distribute the routing entries on different hash tables based on their netmask lengths.


Table 34-1. Initialization of the fib_table's virtual functions

Method

Routine used

tb_lookup

fn_hash_lookup

tb_insert

fn_hash_insert

tb_delete

fn_hash_delete

tb_flush

fn_hash_flush

tb_select_default

fn_hash_select_default

tb_dump

fn_hash_dump













5.9 Combined Observer-Controller











 < Day Day Up > 











5.9 Combined Observer-Controller


The next design step is to combine the observer and controller to form the compensator of Figure 5.1. Equation 5.5 shows the complete computation of the state estimate and the plant actuator commands u using the reference input r and sensor measurements y as inputs to the algorithm.








(5.5) 


Note that in the configuration of Figure 5.1, the plant and the observer both receive the actuator commands directly. As a result, assuming the linear plant model ideally represents the real plant, the observer tracks the plant response to changes in the reference input r with zero error.


During controller startup, the state estimate vector should be initialized as accurately as possible. This will minimize transient estimator errors during the initial period of system operation.



Equation 5.5 requires the plant input vector u and the measured plant outputs y as inputs. In MATLAB state-space models, only the outputs (y vector elements) of a state-space component are available as inputs to a subsequent component. The input vector elements are not available to use as outputs, which creates a small problem.



The solution is to form an augmented plant output vector ỹ by appending the plant inputs to the output vector. This requires modification of the C and D matrices of the plant model. Equation 5.6 shows the format of the modified matrices.








(5.6) 


With the result of Eq. 5.6, the closed-loop system equations consisting of the plant model and the observer-controller are written as follows.








(5.7) 






Note 

In Eqs. 5.6 and 5.7, 0 represents a zero matrix and I is an identity matrix. For a system with r inputs and n states, the 0 matrix in these equations has r rows and n columns and the I matrix has r rows and r columns.




Equation 5.7 is the mathematical formulation of the closed-loop system shown in Figure 5.1. The top two lines of Eq. 5.7 represent the behavior of the plant. The third line implements the observer, and the fourth line computes the actuator commands. These last two lines form the observer-controller.


The companion CD-ROM contains the MATLAB function ss_design(), which develops an observer-controller and feedforward gain for a SISO plant that using the pole placement method. The inputs to this command are the plant model and constraints for the locations of the closed-loop system and the observer poles. The form of ss_design() is shown here.




>> [n, ssobsctrl, sscl] = ss_design(ssplant, t_settle, ...
damp_ratio, obs_pole_mult)


The input arguments are ssplant, the state-space plant model; t_settle, the closed-loop settling time requirement in seconds; damp_ratio, the damping ratio requirement; and obs_pole_mult, the multiplier used to determine the observer pole locations given the closed-loop pole locations. The select_poles() function is used internally to determine the closed-loop pole locations from the given specifications.


The outputs of ss_design() are the scalar feedforward gain n, the state-space observer-controller ssobsctrl, and a state-space model of the closed-loop system sscl. The ssobsctrl system requires the augmented plant output vector ỹ as its input and produces the term - as its output. The actuator command must be computed as shown in the last line of Eq. 5.7.



You can use plot_poles() (included on the CD-ROM) to display the pole locations of the closed-loop system sscl and verify that they satisfy the specifications.




>> plot_poles(sscl, t_settle, damp_ratio)



















 < Day Day Up > 



Summary










 < Free Open Study > 





Summary



The main question that organization executives and project managers ask is, "But, does it really work?" Documented case studies of software process improvement indicate that significant improvements in both quality and productivity are a result of the improvement effort.[7] When the organizational investment is made, the return on investment is typically between 5:1 and 8:1 for successful process improvement efforts.[8] Continuous process improvement begins with an awareness of the process maturity within the project development organization. Although continuous improvement could be done by a single project, the benefit is not realized until the next project. Continuous improvement is an organization-wide initiative. It must be supported by the entire organization and must extend over all projects. For an organization like AEC, in which the average billable rate is $165 per hour, a 5:1 improvement would be a net $825 for each process improvement hour invested.



Success as a software project manager is judged by delivering quality products on time and with the resources budgeted. Quality is determined by the customer and comes from improving the product development process. Continuous process improvement is the mechanism that an organization uses to ensure that products that are less costly, more capable of meeting customer requirements, and more reliable. This mechanism also reduces cost and eliminates waste within the existing development processes, thus allowing project execution on time and within resources.



This chapter looked at continuous process improvement as a process in and of itself. It is not a collection of statistical tools. It is a process of analysis and picking the highest payback improvement targets to add quality and eliminate waste.












     < Free Open Study > 



    20.4 'dg_cli' Function Using Broadcasting



    [ Team LiB ]






    20.4 dg_cli Function Using Broadcasting


    We modify our dg_cli function one more time, this time allowing it to broadcast to the standard UDP daytime server (Figure 2.18) and printing all replies. The only change we make to the main function (Figure 8.7) is to change the destination port number to 13.





    servaddr.sin_port = htons(13);


    We first compile this modified main function with the unmodified dg_cli function from Figure 8.8 and run it on the host freebsd.





    freebsd % udpcli01 192.168.42.255
    hi
    sendto error: Permission denied


    The command-line argument is the subnet-directed broadcast address for the secondary Ethernet. We type a line of input, the program calls sendto, and the error EACCES is returned. The reason we receive the error is that we are not allowed to send a datagram to a broadcast destination address unless we explicitly tell the kernel that we will be broadcasting. We do this by setting the SO_BROADCAST socket option (Section 7.5).


    Berkeley-derived implementations implement this sanity check. Solaris 2.5, on the other hand, accepts the datagram destined for the broadcast address even if we do not specify the socket option. The POSIX specification requires the SO_BROADCAST socket option to be set to send a broadcast packet.

    Broadcasting was a privileged operation with 4.2BSD and the SO_BROADCAST socket option did not exist. This option was added to 4.3BSD and any process was allowed to set the option.


    We now modify our dg_cli function as shown in Figure 20.5. This version sets the SO_BROADCAST socket option and prints all the replies received within five seconds.



    Allocate room for server's address, set socket option


    11�13 malloc allocates room for the server's address to be returned by recvfrom. The SO_BROADCAST socket option is set and a signal handler is installed for SIGALRM.




    Read line, send to socket, read all replies


    14�24 The next two steps, fgets and sendto, are similar to previous versions of this function. But since we are sending a broadcast datagram, we can receive multiple replies. We call recvfrom in a loop and print all the replies received within five seconds. After five seconds, SIGALRM is generated, our signal handler is called, and recvfrom returns the error EINTR.




    Print each received reply


    25�29 For each reply received, we call sock_ntop_host, which in the case of IPv4 returns a string containing the dotted-decimal IP address of the server. This is printed along with the server's reply.


    If we run the program specifying the subnet-directed broadcast address of 192.168.42.255, we see the following:





    freebsd % udpcli01 192.168.42.255
    hi
    from 192.168.42.2: Sat Aug 2 16:42:45 2003
    from 192.168.42.1: Sat Aug 2 14:42:45 2003
    from 192.168.42.3: Sat Aug 2 14:42:45 2003
    hello
    from 192.168.42.3: Sat Aug 2 14:42:57 2003
    from 192.168.42.2: Sat Aug 2 16:42:57 2003
    from 192.168.42.1: Sat Aug 2 14:42:57 2003


    Each time we must type a line of input to generate the output UDP datagram. Each time we receive three replies, and this includes the sending host. As we said earlier, the destination of a broadcast datagram is all the hosts on the attached network, including the sender. Each reply is unicast because the source address of the request, which is used by each server as the destination address of the reply, is a unicast address.


    All the systems report the same time because all run NTP.



    Figure 20.5 dg_cli function that broadcasts.

    bcast/dgclibcast1.c




    1 #include "unp.h"

    2 static void recvfrom_alarm(int);

    3 void
    4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
    5 {
    6 int n;
    7 const int on = 1;
    8 char sendline[MAXLINE], recvline[MAXLINE + 1];
    9 socklen_t len;
    10 struct sockaddr *preply_addr;

    11 preply_addr = Malloc(servlen);

    12 Setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

    13 Signal(SIGALRM, recvfrom_alarm);

    14 while (Fgets(sendline, MAXLINE, fp) != NULL) {

    15 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

    16 alarm(5);
    17 for ( ; ; ) {
    18 len = servlen;
    19 n = recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
    20 if (n < 0) {
    21 if (errno == EINTR)
    22 break; /* waited long enough for replies */
    23 else
    24 err_sys("recvfrom error");
    25 } else {
    26 recvline[n] = 0; /* null terminate */
    27 printf("from %s: %s",
    28 Sock_ntop_host(preply_addr, len), recvline);
    29 }
    30 }
    31 }
    32 free(preply_addr);
    33 }

    34 static void
    35 recvfrom_alarm(int signo)
    36 {
    37 return; /* just interrupt the recvfrom() */
    38 }




    IP Fragmentation and Broadcasts


    Berkeley-derived kernels do not allow a broadcast datagram to be fragmented. If the size of an IP datagram that is being sent to a broadcast address exceeds the outgoing interface MTU, EMSGSIZE is returned (pp. 233�234 of TCPv2). This is a policy decision that has existed since 4.2BSD. There is nothing that prevents a kernel from fragmenting a broadcast datagram, but the feeling is that broadcasting puts enough load on the network as it is, so there is no need to multiply this load by the number of fragments.


    We can see this scenario with our program in Figure 20.5. We redirect standard input from a file containing a 2,000-byte line, which will require fragmentation on an Ethernet.





    freebsd % udpcli01 192.168.42.255 < 2000line
    sendto error: Message too long


    AIX, FreeBSD, and MacOS implement this limitation. Linux, Solaris, and HP-UX fragment datagrams sent to a broadcast address. For portability, however, an application that needs to broadcast should determine the MTU of the outgoing interface using the SIOCGIFMTU ioctl, and then subtract the IP and transport header lengths to determine the maximum payload size. Alternately, it can pick a common MTU, like Ethernet's 1500, and use it as a constant.







      [ Team LiB ]



      Newer Posts Older Posts Home