Windows ping源码
需要测试外网的联通性,想到了用ping。网上下载了ping的源代码,调试下整理如下:
/******************************************************************************\
* ping.c - Simple ping utility using SOCK_RAW
*
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996-1997 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/ #pragma pack(4) #define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib") #define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0 #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header) /* The IP header */
typedef struct iphdr
{
unsigned int h_len:; // length of the header
unsigned int version:; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl;
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP;
unsigned int destIP;
}IpHeader; //
// ICMP header
//
typedef struct _ihdr {
BYTE i_type; //消息类型
BYTE i_code; //代码 /* type sub code */
USHORT i_cksum; //校验和
USHORT i_id; //ID号
USHORT i_seq; //序列号
ULONG timestamp; //时间戳 /* This is not the std header, but we reserve space for time */
}IcmpHeader; //ICMP报文 包括报头和数据 #define STATUS_FAILED 0xFFFF
#define DEF_PACKET_SIZE 32
#define MAX_PACKET 1024 #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
#define xfree(p) HeapFree (GetProcessHeap(),0,(p)) void fill_icmp_data(char *, int);
USHORT checksum(USHORT *, int);
void decode_resp(char *,int ,struct sockaddr_in *); int main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET sockRaw;
struct sockaddr_in dest;
struct hostent * hp;
int bread,datasize;
int timeout = ;
char *dest_ip;
char *icmp_data;
char *recvbuf;
unsigned int addr=;
USHORT seq_no = ;
struct sockaddr_in from;
int fromlen = sizeof(from); if (WSAStartup(MAKEWORD(,),&wsaData) != )
{
fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
ExitProcess(STATUS_FAILED);
} /*
为了使用发送接收超时设置(即设置SO_RCVTIMEO, SO_SNDTIMEO),
// 必须将标志位设为WSA_FLAG_OVERLAPPED !
*/
sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, ,WSA_FLAG_OVERLAPPED); //建立一个原始套接字
//sockRaw = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,0); if (sockRaw == INVALID_SOCKET)
{
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} timeout = ; //设置接收超时时间
bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout)); //RECVTIMEO是接收超时时间
if(bread == SOCKET_ERROR)
{
fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} timeout = ; //设置发送超时时间
bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout)); //SNDTIMEO是发送超时时间
if(bread == SOCKET_ERROR)
{
fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
}
memset(&dest,,sizeof(dest)); //目标地址清零 hp = gethostbyname("www.baidu.com"); //通过域名或者主机名获取IP地址
if (!hp) //失败返回NULL
{
ExitProcess(STATUS_FAILED);
}
else
{
addr = inet_addr("14.215.177.37"); //www.baidu.com的ip地址
} if ((!hp) && (addr == INADDR_NONE)) //既不是域名也不是点分十进制的IP地址
{
ExitProcess(STATUS_FAILED);
} if (hp != NULL) //获取的是域名
memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); //从hostent得到的对方ip地址
else
dest.sin_addr.s_addr = addr; if (hp)
dest.sin_family = hp->h_addrtype; //sin_family不是一定只能填AF_INET吗?
else
dest.sin_family = AF_INET; dest_ip = inet_ntoa(dest.sin_addr); //目标IP地址 datasize = DEF_PACKET_SIZE; //ICMP包数据大小设定为32 datasize += sizeof(IcmpHeader); //另外加上ICMP包的包头 其实包头占12个字节 icmp_data = (char *)xmalloc(MAX_PACKET);//发送icmp_data数据包内存
recvbuf = (char *)xmalloc(MAX_PACKET); //存放接收到的数据 if (!icmp_data) //分配内存
{
ExitProcess(STATUS_FAILED);
} memset(icmp_data,,MAX_PACKET);
fill_icmp_data(icmp_data,datasize); //只填充了ICMP包 fprintf(stdout,"\nPinging %s ....\n\n",dest_ip); while()
{
int bwrote; ((IcmpHeader*)icmp_data)->i_cksum = ;
((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); //时间戳 ((IcmpHeader*)icmp_data)->i_seq = seq_no++; //ICMP的序列号
((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize); //icmp校验位 //下面这个函数的问题是 发送数据只是ICMP数据包,而接收到的数据时包含ip头的 也就是发送和接收不对等
//问题是sockRaw 设定了协议为 IPPROTO_ICMP
bwrote = sendto(sockRaw,icmp_data,datasize,,(struct sockaddr*)&dest, sizeof(dest));
if (bwrote == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT) //发送时间超时
{
printf("timed out\n");
continue;
} fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
} if (bwrote < datasize )
{
fprintf(stdout,"Wrote %d bytes\n",bwrote);
} bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,,(struct sockaddr*)&from, &fromlen);
if (bread == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("timed out\n");
continue;
}
fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
}
decode_resp(recvbuf,bread,&from); Sleep();
} WSACleanup();
system("pause"); return ;
} /*
The response is an IP packet. We must decode the IP header to locate
the ICMP data
*/
void decode_resp(char *buf, int bytes,struct sockaddr_in *from)
{
IpHeader *iphdr;
IcmpHeader *icmphdr;
unsigned short iphdrlen; iphdr = (IpHeader *)buf; //接收到的数据就是原始的IP数据报 iphdrlen = iphdr->h_len * ; // number of 32-bit words *4 = bytes if (bytes < iphdrlen + ICMP_MIN)
{
printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
} icmphdr = (IcmpHeader*)(buf + iphdrlen); if(icmphdr->i_type == )
{
printf("network unreachable -- Response from %s.\n",inet_ntoa(from->sin_addr));
return ;
} if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
{
fprintf(stderr,"someone else's packet!\n");
return ;
}
printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
printf(" icmp_seq = %d ",icmphdr->i_seq);
printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
printf(" ttl: %d",iphdr->ttl);
printf("\n");
} //完成ICMP的校验
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=; while(size >)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
} if(size )
{
cksum += *(UCHAR*)buffer;
} cksum = (cksum >> ) + (cksum & 0xffff);
cksum += (cksum >>);
return (USHORT)(~cksum);
} /*
Helper function to fill in various stuff in our ICMP request.
*/
void fill_icmp_data(char * icmp_data, int datasize){ IcmpHeader *icmp_hdr;
char *datapart; icmp_hdr = (IcmpHeader*)icmp_data; icmp_hdr->i_type = ICMP_ECHO; //ICMP_ECHO要求收到包的主机回复此ICMP包
icmp_hdr->i_code = ;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); //id填当前进程的id
icmp_hdr->i_cksum = ;
icmp_hdr->i_seq = ; datapart = icmp_data + sizeof(IcmpHeader);
//
// Place some junk in the buffer.
//
memset(datapart,'E', datasize - sizeof(IcmpHeader)); //填充了一些废物
}
我下到代码的时候,第91行创建原始套接字的地方原本是被屏蔽的第92行,区别在与创建套接字时赋予的标志位不一样。
WSASocket函数的定义如下:
SOCKET WSASocket (
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags
);
af:[in]一个地址族规范。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。
type:新套接口的类型描述。
protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。
lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。
g:保留给未来使用的套接口组。套接口组的标识符。
iFlags:套接口属性描述。
具体详细介绍看微软官方介绍文档:https://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx
Windows ping源码的更多相关文章
- E-Form++ for Windows CE源码库2020,嵌入式开放源码!
E-Form++ for Windows CE源码库2020! 现在就把这个下载到您的Windows CE中,体验极致HMI触摸. Windows CE评估版下载! 1. E-Form++ for ...
- yate: windows下源码下载,配置,编译
源码下载:使用svn下载checkout:http://voip.null.ro/svn/yate/trunk 配置:(本人使用的是vs2008,故下载的qt工具都是对应2008) 1. 下载并安装q ...
- windows下源码安装调试postgresql
环境:windows 10 postgresql版本:postgresql-9.6.5 使用工具:vs2017社区版 辅助工具:perl.diff.flex.bison 相关工具下载地址: perl下 ...
- windows平台源码编译最新版openssl
本文有问题,待改中................. 1.从openssl官网下载最新版openssl https://www.openssl.org/source/ The latest ...
- 32位win7+vs2008编译mysql 5.6.22源码并安装
以下这部分安装说明是来自http://www.2cto.com/database/201407/316681.html的win7+vs2010源码编译mysql,文章最后会说明用vs2008编译遇见的 ...
- thingsboard源码编译启动
开发环境 不同的版本对应的开发环境不同(这里以3.3.3版本说明) jdk11+:参考jdk11+安装(win) Maven3.6+:Maven安装配置 Git:参考Git安装 IDEA: 参考IDE ...
- [安卓]windows下如何安装Android源码
本文改写于:http://www.cnblogs.com/skyme/archive/2011/05/14/2046040.html 1.下载并安装git: 在git-scm.com上下载并安装git ...
- 【完全开源】知乎日报UWP版(下篇):商店APP、github源码、功能说明。Windows APP 良心出品。
目录 说明 功能 截图+视频 关于源码和声明 说明 陆陆续续大概花了一个月的时间,APP算是基本完成了.12月份一直在外出差,在出差期间进行了两次功能完善,然后断断续续修补了一些bug,到目前为止,我 ...
- Windows编译Nginx源码
Windows下的Nginx战役,人不作就不会死!就像是拿着麦当劳的优惠券去买肯德基一样,别扭啊 Nginx是一款轻量级的Web 服务器.反向代理服务器.邮件服务器等等集一大串荣誉于一身的大牌人物!他 ...
随机推荐
- [BZOJ1419] Red is good(期望DP)
传送门 逆推 只不过顺序还是顺着的,思想是逆着的 f[i][j]表示还剩下i张红牌,j张黑牌的期望值 那么边界是 f[i][0]=i,因为只剩i张红牌 f[0][j]=0,只剩黑牌,显然直接停止最优 ...
- sublime text3安装angularjs插件
sublime能够支持AngularJS开发那绝对是一件很爽的事情.下面我一步步讲解如何为sublime安装AngularJS插件. 首先提供一个破解版的sublime text 3的下载地址:htt ...
- mock数据。根据表中一天的数据模拟其他日期的数据
package test; import java.sql.*; import java.text.SimpleDateFormat; import java.util.*; import java. ...
- LA 4973异面线段
题目大意:给两条线段求他们间的最小距离的平方(以分数形式输出). 贴个模版吧!太抽象了. #include<cstdio> #include<cmath> #include&l ...
- 蒲公英(bzoj 2724)
Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input ...
- STL学习笔记(三) 关联容器
条款19:理解相等(equality)和等价(equivalence)的区别 相等的概念是基于 operator== 的,如果 operator== 的实现不正确,会导致并不实际相等等价关系是以&qu ...
- Codeforces Round #291 (Div. 2) C. Watto and Mechanism [字典树]
传送门 C. Watto and Mechanism time limit per test 3 seconds memory limit per test 256 megabytes input s ...
- commons.apache
1.ToStringBuilder //对象及其属性一行显示 System.out.println(ToStringBuilder.reflectionToString(u)); System.out ...
- Ubuntu官方Wiki教程资源
前言:通常学习一样新知识时,最快的方式是通过搜索引擎然后以最快的方式拿枪上战场,如果接下来还一直依赖搜索引擎去打,那么你会发现自己永远都在打游击:那么如果要解决这个问题,必须要学会系统的学习,只有连贯 ...
- Linux下使用vi新建文件保存文件时遇到错误:E212: Can't open file for writing
出现E212: Can't open file for writing的问题是由于权限问题导致的,解决方法有以下思路: 1.使用root进行登录,然后再操作. 2.在使用命令时,前面加sudo. 3. ...