原文地址:http://miniupnp.free.fr/libnatpmp.html
通过对libupnp,及mimiupnp两个项目的了解,感觉libupnp太繁杂,太沉重了,miniupnp包括对upnp客户端及服务器的实现。 最为重要的是libnatpmp项目,其提供了十分简单的借口形式对路由器端口映射进行的封装,只要路由器支持upnp可以实现客户端自动绑定路由器外部 端口,十分的有用。
而且今天在学习upnp的过程无意发现了俩个异步事件机制的软件库,可以用来取代网络服务器所使用的循环检查架构,可以省去对网络的处理。
I hadn't noticed when I started to code libnatpmp, but another library was allready existing using the same name : Allen Porter made his C++ library in october/november 2007. If you want to have a look at it, it is available here. So what's next ? maybe I should change the name of my library ? what do you think of libnatpmpc ? (c like client or like the C language ?)
The NAT Port Mapping Protocol (NAT-PMP)
NAT-PMP
is the direct concurrent to the UPnP IGD specification. It is providing a way to do
NAT traversal
. It is part of the
Bonjour protocol specifications
. You can get the description of this simple protocol
here
or by reading the
draft
. At the moment it is mainly supported by
Apple
software and hardware. If you are looking for a way to add NAT-PMP capabilities to your *BSD, Linux or (Open)Solaris Router, you should have a look at
MiniUPnPd
which is supporting NAT-PMP in addition to UPnP since December 2007 !
libnatpmp description
libnatpmp is an attempt to make a portable and fully compliant implementation of the protocol for the client side. It is based on non blocking sockets and all calls of the API are asynchronous. It is therefore very easy to integrate the NAT-PMP code to any event driven code.
Download and build libnatpmp
To download the source code, go to the
MiniUPnP Download page
.
Use
gmake
or
make
to build the library and samples.
Use libnatpmp in your programs
It should be very easy to use libnatpmp in any C/C++ program. All the API is described in the natpmp.h file.
- First of all, a variable of type natpmp_t must be allocated and initnatpmp() must be called.
- sendpublicaddressrequest() or sendnewportmappingrequest() can be called.
- For each request sent, readnatpmpresponseorretry() should be called as long as it returns NATPMP_TRYAGAIN.
- If you are waiting for the socket (field s in the natpmp_t object) to be ready for reading using system calls such as select() or poll(), you can use getnatpmprequesttimeout() in order to know how long to wait before calling readnatpmpresponseorretry() anyway.
- To free all used resources, closenatpmp() can be called.
Sample code
Error checking has been deliberately omitted. Please check all return codes in natpmp.h file.
simple sample
This very simple sample just ask for a redirection and return when the job is done.
void redirect(uint16_t privateport, uint16_t publicport)
{
int r;
natpmp_t natpmp;
natpmpresp_t response;
initnatpmp(&natpmp);
sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, privateport, publicport, 3600);
do {
fd_set fds;
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(natpmp.s, &fds);
getnatpmprequesttimeout(&natpmp, &timeout);
select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
r = readnatpmpresponseorretry(&natpmp, &response);
} while(r==NATPMP_TRYAGAIN);
printf("mapped public port %hu to localport %hu liftime %u\n",
response.newportmapping.mappedpublicport,
response.newportmapping.privateport,
response.newportmapping.lifetime);
closenatpmp(&natpmp);
}
more complex sample
We could imagine the init phase of a P2P software. During this phase, the software tries to get the public IP address and add a port mapping. At the end of the process, natpmpstate will be either
Sdone
or
Serror
.
{
natpmp_t natpmp;
natpmpresp_t response;
enum { Sinit=0, Ssendpub, Srecvpub, Ssendmap, Srecvmap, Sdone, Serror=1000 } natpmpstate = Sinit;
int r;
[...]
if(initnatpmp(&natpmp)<0)
natpmpstate = Serror;
else
natpmpstate = Ssendpub;
[...]
while(!finished_all_init_stuff) {
[...]
other init stuff :)
[...]
switch(natpmpstate) {
case Ssendpub:
if(sendpublicaddressrequest(&natpmp)<0);
natpmpstate = Serror;
else
natpmpstate = Srecvpub;
break;
case Srecvpub:
r = readnatpmpresponseorretry(&natpmp, &response);
if(r<0 && r!=NATPMP_TRYAGAIN)
natpmpstate = Serror;
else if(r!=NATPMP_TRYAGAIN) {
copy(publicaddress, response.publicaddress.addr);
natpmpstate = Ssendmap;
}
break;
case Ssendmap:
if(sendnewportmappingrequest(&natpmp, protocol, privateport, publicport, lifetime)<0);
natpmpstate = Serror;
else
natpmpstate = Srecvmap;
break;
case Srecvmap:
r = readnatpmpresponseorretry(&natpmp, &response);
if(r<0 && r!=NATPMP_TRYAGAIN)
natpmpstate = Serror;
else if(r!=NATPMP_TRYAGAIN) {
copy(publicport, response.newportmapping.mappedpublicport);
copy(privateport, response.newportmapping.privateport);
copy(mappinglifetime, response.newportmapping.lifetime);
natpmpclose(&natpmp);
natpmpstate = Sdone;
}
break;
}
[...]
}
[...]
}
Thomas Bernard
To contact me, use the MiniUPnP forum or use email : miniupnp _AT_ free _DOT_ fr
(Allen Porter) |