?? moncmd.c
字號:
/** \file moncmd.c:
* \brief The guts of the moncmd UDP client.
* \author Ed Sutter esutter@lucent.com
*
* This tool is used to support simple UDP communication between a host and
* a target running MicroMonitor. The target is listening on port
* IPPORT_MONCMD (777) for incoming command strings just as they would be
* seen if typed in at the RS-232 console port. When the monitor receives
* this, it processes the string through the same mechanism as the console.
* The only addition is that all output is copied to the sender of the UDP
* packet (one line at a time). Once the command has been processed, the
* final packet returned to the sender is a packet of size 1 with the data
* being zero. This is what tells moncmd that the command has completed
* on the target.
*
* \attention
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#ifdef BUILD_WITH_VCC
#include <windows.h>
#include <winsock2.h>
#else
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "moncmd.h"
#ifdef BUILD_WITH_VCC
#define sleep(n) Sleep(n*1000)
#define SOCKET_INVALID(s) (s == INVALID_SOCKET)
#else
#define SOCKET_INVALID(s) (s < 0)
#endif
typedef unsigned char uchar;
extern void err(char *);
/** \var char *thisProgname
* \brief String containing the value of argv[0] when the program was
* \brief executed.
*/
char *thisProgname;
/** \var char *msgString
* \brief Pointer to the message that this program is
* \brief to send to the target host.
*/
char *msgString;
/** \var char *targetHost
* \brief Ip address or DNS name of host that this
* \brief program is to communicate with.
*/
char *targetHost;
/** \var int retryFlag
* \brief If set, then the program will retry.
*/
int retryFlag;
/** \var int retryCount
* \brief Running total number of retries.
*/
int retryCount;
/** \var int quietMode
* \brief If set, then don't output status message at
* \brief the end of the program.
*/
int quietMode;
/** \var int interactiveMode
* \brief If set, then moncmd runs similar to netcat, in
* \brief an interactive mode where each line typed is passed
* \brief to the target.
*/
int interactiveMode;
/** \var int multirespMode
* \brief If set, then it is possible that more than one
* \brief target will respond, so don't quit after one
* \brief response is received.
*/
int multirespMode;
/** \var int waitTime
* \brief This is the amount of time that program will
* \brief wait for a response prior to giving up.
*/
int waitTime;
/** \var int socketFd
* \brief File descriptor of the open socket used to
* \brief communicate with the target host.
*/
int socketFd;
/** \var int verbose
* \brief Set for more verbosity.
*/
int verbose;
/** \var int cmdRcvd
* \brief Set if the command has been received by the target, but no
* \brief additional response has been received.
*/
int cmdRcvd;
/** \var int binMode
* \brief If set, then moncmd is sending/receiving binary.
*/
int binMode;
/** \var struct sockaddr_in targetAddr
* \brief This structure is used to hold the socket
* \brief address info related to the target host.
*/
struct sockaddr_in targetAddr;
#ifdef BUILD_WITH_VCC
WSADATA WsaData;
DWORD tid = (DWORD)0;
HANDLE tHandle;
#else
pthread_attr_t attr;
pthread_t tid = (pthread_t)0;
#endif
/** \fn void Giveup(int sig)
* \brief This function is called if the alarm worker determines that
* \brief it is time to call it quits.
*/
void
Giveup(int sig)
{
if (!quietMode) {
if (cmdRcvd) {
fprintf(stderr,
"\n%s timeout: command received but not completed.\n",
thisProgname);
}
else {
fprintf(stderr,"\n%s timeout: command not received.\n",
thisProgname);
}
}
else {
/* If quiteMode is set, then we just exit with */
exit(EXIT_SUCCESS); /* success because the user chooses to ignore */
/* the error. */
}
if (cmdRcvd)
exit(EXIT_CMP_TIMEOUT);
else
exit(EXIT_ACK_TIMEOUT);
}
/** \var int AlarmCount
* \brief If allowed to decrement to zero, the program gives up.
*/
int AlarmCount;
/** \fn DWORD WINAPI AlarmWorker(LPVOID notused)
* \brief This is a thread that is created to provide a timeout if moncmd
* \brief does not receive a response within a specified amount of time.
* \brief For Cygwin, when the alarmworker times out, it sends a SIGUSR1
* \brief signal to the main process so that the recvfrom() call is
* \brief interrupted.
*/
#ifdef BUILD_WITH_VCC
DWORD WINAPI AlarmWorker(LPVOID notused)
#else
void * AlarmWorker(void *notused)
#endif
{
while(1) {
sleep(1);
if (AlarmCount) {
if (AlarmCount == 1) {
if ((retryFlag) && (!cmdRcvd)) {
retryCount++;
if (verbose)
fprintf(stderr,"Retry %d: <%s> to %s...\n",
retryCount, msgString,targetHost);
if (sendto(socketFd,msgString,(int)strlen(msgString)+1,0,
(struct sockaddr *)&targetAddr,sizeof(targetAddr))<0) {
close(socketFd);
err("re-sendto failed");
}
AlarmCount = waitTime+1;
}
else
#ifdef BUILD_WITH_VCC
Giveup(0);
#else
kill(0,SIGUSR1); /* Interrupt the recvfrom below */
pthread_exit(0);
#endif
}
AlarmCount--;
}
}
return(0);
}
#ifndef BUILD_WITH_VCC
/* This handler doesn't have to do anything except "exist". The
* purpose of this SIGUSR1 signal is to interrupt the recvfrom() call.
*/
void
handler(int sig)
{
}
#endif
/** \fn int do_moncmd(char *hostname, char *command_to_monitor, short portnum)
* \param hostname Name or IP of target.
* \param command_to_monitor String to be sent to the target.
* \param portnum UDP port number to use.
* \brief Open a socket and send the command to the specified port of the
* \brief specified host. Wait for a response if necessary.
*/
int
do_moncmd(char *hostname, char *command_to_monitor, short portnum)
{
int i, lasterr;
int msglen;
unsigned long inaddr;
struct hostent *hp, host_info;
char rcvmsg[4096*4], cmdline[128];
#ifdef BUILD_WITH_VCC
if (WSAStartup (0x0101, &WsaData) == SOCKET_ERROR)
err("WSAStartup Failed");
#endif
cmdRcvd = 0;
retryCount = 0;
targetHost = hostname;
/* 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);
socketFd = socket(AF_INET,SOCK_DGRAM,0);
if (SOCKET_INVALID(socketFd))
err("socket failed");
do {
if (interactiveMode) {
do {
gets(cmdline);
command_to_monitor = cmdline;
} while (strlen(command_to_monitor) == 0);
}
if (verbose)
printf("Sending <%s> to %s...\n",command_to_monitor,targetHost);
msgString = command_to_monitor;
if (sendto(socketFd,msgString,(int)strlen(msgString)+1,0,
(struct sockaddr *)&targetAddr,sizeof(targetAddr)) < 0) {
close(socketFd);
err("sendto failed");
}
/* If the -w option says that wait time is zero, then don't bother
* waiting for a response, just return here.
*/
if (waitTime <= 0) {
close(socketFd);
return(EXIT_SUCCESS);
}
AlarmCount = waitTime;
#ifdef BUILD_WITH_VCC
if (tid == (DWORD)0) {
tHandle = CreateThread(NULL,0,AlarmWorker,(LPVOID)0,0,&tid);
#else
if (tid == (pthread_t)0) {
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,0x8000);
pthread_create(&tid,&attr,AlarmWorker,(void *)0);
signal(SIGUSR1,handler);
#endif
}
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);
}
else if (SOCKET_INVALID(i)) {
//perror("socket invalid");
close(socketFd);
Giveup(0);
}
else {
/* Each time something is received, restart the timeout.
*/
AlarmCount = waitTime;
}
/* If ANY response is received from the target, then the command
* was received...
*/
cmdRcvd = 1;
/* If size is 1 and 1st byte is 0 assume that's the target
* saying "I'm done".
*/
if ((i==1) && (rcvmsg[0] == 0)) {
if (multirespMode)
continue;
break;
}
/* Print the received message:
*/
for(j=0;j<i;j++)
putchar(rcvmsg[j]);
fflush(stdout);
}
} while (interactiveMode);
AlarmCount = 0;
close(socketFd);
return(EXIT_SUCCESS);
}
/** \fn void moncmd_init(char *progname)
* \brief Initialize globals at startup
* \param progname Value of argv[0] at startup.
*/
void
moncmd_init(char *progname)
{
thisProgname = progname;
binMode = 0;
waitTime = 10;
verbose = 0;
multirespMode = 0;
interactiveMode = 0;
retryFlag = quietMode = 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -