Tuesday, December 15, 2009

PC-Based UDP Transactions: moncmd










































PC-Based UDP Transactions: moncmd


MicroMonitor, when built on a target with
Ethernet capability, includes a small server that processes incoming
packets received on UDP port 777. The server simply takes the incoming
UDP packet and assumes the content of the packet is a command destined
for the monitor’s CLI. The server passes the whole string to the
function docommand() and sets a flag within the monitor. This flag tells putchar
to build UDP packets (one line per packet) to be sent back to the
client that issued the command. When the flag is set, the command
results are sent to the target console (if any) and to the remote UDP
port that issued the command. When the final line of output is
complete, the monitor clears the flag and issues one last packet
containing only one NULL byte to signal the remote client that the response to the command is complete.


The moncmd tool (monitor
command) is a specialized UDP client that runs on a PC. It is a simple
program that allows a user to talk remotely to a target system running
MicroMonitor. Listing A.4 demonstrates the basic functionality needed to send and receive on a UDP socket using a Win32-based host. Note that Listing A.4 is a very basic implementation meant only to illustrate the use of socket(), sendto(), and recvfrom(). (A complete implementation is on the CD.)




Listing A.4: do_moncmd().






/* do_moncmd():
* Open a socket and send the command to the specified port of the
* specified host. Wait for a response if necessary.
*
* hostname:
* Character string IP address
* command_to_monitor:
* Character string command destined for target monitor.
* portnum:
* Port number that the UDP packet is to be sent to.
*/
int
do_moncmd(char *hostname, char *command_to_monitor, short portnum)
{
int i, lasterr;
int msglen;
ulong inaddr;
struct hostent *hp, host_info;
char rcvmsg[1024];
WSADATA WsaData;
DWORD tid;
HANDLE tHandle;

if (WSAStartup (0x0101, &WsaData) == SOCKET_ERROR)
err("WSAStartup Failed");

targetHost = hostname;

/* Build the UDP destination address:
* Accept target name as string or internet dotted-decimal address.
*/
memset((char *)&targetAddr,0,sizeof(struct sockaddr));
if ((inaddr = inet_addr(targetHost)) != INADDR_NONE) {
memcpy((char *)&targetAddr.sin_addr,(char *)&inaddr,sizeof(inaddr));
host_info.h_name = NULL;
}
else {
hp = gethostbyname(targetHost);
if (hp == NULL)
err("gethostbyname failed");
host_info = *hp;
memcpy((char *)&targetAddr.sin_addr,hp->h_addr,hp->h_length);
}
targetAddr.sin_family = AF_INET;
targetAddr.sin_port = htons(portnum);

/* Open the socket:
*/
socketFd = socket(AF_INET,SOCK_DGRAM,0);

if (socketFd == INVALID_SOCKET)
err("socket failed");

/* Send the command string to the target:
*/
msgString = command_to_monitor;
if (sendto(socketFd,msgString,(int)strlen(msgString)+1,0,
(struct sockaddr *)&targetAddr,sizeof(targetAddr)) < 0) {
close(socketFd);
err("sendto failed");
}

/* Now wait for the response:
*/
while(1) {
int j;

/* Wait for incoming message: */
msglen = sizeof(struct sockaddr);
i = recvfrom(socketFd,rcvmsg,sizeof(rcvmsg),0,
(struct sockaddr *)&targetAddr,&msglen);

if (i == 0) {
fprintf(stderr,"Connection closed\n");
close(socketFd);
exit(EXIT_ERROR);
}

/* If size is 1 and 1st byte is 0 assume that's the target */
/* saying "I'm done". */
if ((i==1) && (rcvmsg[0] == 0))
break;

/* Print the received message: */
for(j=0;j<i;j++)
putchar(rcvmsg[j]);
fflush(stdout);
}

close(socketFd);
return(EXIT_SUCCESS);
}















Okay, I’m gonna be honest here, I don’t know what WSAStartup() actually does! And yes, I’m OK with that! Like the sneaker commercial says, "just do it!"



The do_moncmd() function processes the IP address or the hostname provided on the command line. The function then opens a socket with SOCK_DGRAM, indicating that the socket is for UDP. After the socket is opened, the code can use the functions sendto() and recvfrom() to send and receive UDP packets. The call to sendto() transfers the string on the command line to the server task on the remote target running MicroMonitor. Finally, the while()
loop processes the response. Each line received is printed to the
console. To support the ability to receive a multiple-line response but
still know when the final line has been received, the server in the
monitor terminates the message with a single 1-byte packet containing a
NULL. The remote moncmd tests for this packet and exits when appropriate.




































No comments: