stun client java实现_stun 协议客户端实现

stun client java实现_stun 协议客户端实现/**Spider–AnopensourceClanguagetoolkit.**Copyright(C)2011,Inc.**lidp**Thisprogramisfreesoftware,distributedunderthetermsof*theGNUGeneralPublicLicenseVersion2.Seethe…

大家好,又见面了,我是你们的朋友全栈君。

/*

* Spider — An open source C language toolkit.

*

* Copyright (C) 2011 , Inc.

*

* lidp

*

* This program is free software, distributed under the terms of

* the GNU General Public License Version 2. See the LICENSE file

* at the top of the source tree.

*/

/*

* \brief stun client implimentation

*/

#include “stun.h”

#include “logger.h”

/*!

* \brief STUN support code

*

* http://www.ietf.org/rfc/rfc3489.txt

*

* This code provides some support for doing STUN transactions.

* STUN is described in RFC3489 and it is based on the exchange

* of UDP packets between a client and one or more servers to

* determine the externally visible address (and port) of the client

* once it has gone through the NAT boxes that connect it to the

* outside.

* The simplest request packet is just the header defined in

* struct stun_header, and from the response we may just look at

* one attribute, STUN_MAPPED_ADDRESS, that we find in the response.

* By doing more transactions with different server addresses we

* may determine more about the behaviour of the NAT boxes, of

* course – the details are in the RFC.

*

* All STUN packets start with a simple header made of a type,

* length (excluding the header) and a 16-byte random transaction id.

* Following the header we may have zero or more attributes, each

* structured as a type, length and a value (whose format depends

* on the type, but often contains addresses).

* Of course all fields are in network format.

*/

/*! \brief STUN message types

* ‘BIND’ refers to transactions used to determine the externally

* visible addresses. ‘SEC’ refers to transactions used to establish

* a session key for subsequent requests.

* ‘SEC’ functionality is not supported here.

*/

#define STUN_BINDREQ    0x0001

#define STUN_BINDRESP   0x0101

#define STUN_BINDERROR  0x0111

#define STUN_SECREQ     0x0002

#define STUN_SECRESP    0x0102

#define STUN_SECERROR   0x0112

/*! \brief Basic attribute types in stun messages.

* Messages can also contain custom attributes (codes above 0x7fff)

*/

#define STUN_MSG_MAPPED_ADDR   0x0001

#define STUN_MSG_RESPONCE_ADDR 0x0002

#define STUN_MSG_RESPONSE_ADDRESS0x0002

#define STUN_MSG_CHANGE_REQUEST0x0003

#define STUN_MSG_SOURCE_ADDRESS0x0004

#define STUN_MSG_CHANGED_ADDRESS0x0005

#define STUN_MSG_USERNAME0x0006

#define STUN_MSG_PASSWORD0x0007

#define STUN_MSG_INTEGRITY0x0008

#define STUN_MSG_ERROR_CODE0x0009

#define STUN_MSG_UNKNOWN_ATTRIBUTES0x000a

#define STUN_MSG_REFLECTED_FROM0x000b

#define stun_debug 0;

typedef struct { unsigned int id[4]; } __attribute__((packed)) stun_transac_id;

/*

0                   1                   2                   3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|0 0|     STUN Message Type     |         Message Length        |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|                         Magic Cookie                          |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|                                                               |

|                     Transaction ID (96 bits)                  |

|                                                               |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

*/

struct stun_header {

unsigned short msgtype;

unsigned short msglen;

stun_transac_id id;

unsigned char attr[0];

};

struct stun_attr {

unsigned short attr;

unsigned short len;

unsigned char value[0];

} __attribute__((packed));

struct stun_addr {

unsigned char unused;

unsigned char family;

unsigned short port;

unsigned int addr;

} __attribute__((packed));

struct stun_state {

const char *username;

const char *password;

};

static const char* stun_msg2str(int msg)

{

switch(msg) {

case STUN_BINDREQ:

return “Binding Request”;

case STUN_BINDRESP:

return “Binding Responce”;

case STUN_BINDERROR:

return “Binding Error”;

case STUN_SECREQ:

return “SecRequest”;

case STUN_SECRESP:

return “SecResponce”

case STUN_SECERROR:

return “SecError”;

default:

return “Not RFC 3489 MSG”;

}

}

static const char *stun_attr2str(int msg)

{

switch (msg) {

case STUN_MSG_MAPPED_ADDR:

return “Mapped Address”;

case STUN_MSG_RESPONCE_ADDR:

return “Responce Address”;

case STUN_MSG_CHANGE_REQUEST:

return “Change Request”;

case STUN_MSG_SOURCE_ADDRESS:

return “Source Address”;

case STUN_MSG_CHANGED_ADDRESS:

return “Changed Address”;

case STUN_MSG_USERNAME:

return

“Username”;

case STUN_MSG_PASSWORD:

return “Password”;

case STUN_MSG_INTEGRITY:

return “Message Integrity”;

case STUN_MSG_UNKNOWN_ATTRIBUTES:

return “

Unknown Attributes”;

case STUN_MSG_REFLECTED_FROM:

return “Reflected From”;

case STUN_MSG_ERROR_CODE:

return “Error Code”;

}

return “Non-RFC3489 Attribute”;

}

static void stun_transaction_id(struct stun_header *req)

{

if(req) {

int x;

for(x = 0; x < 4; x++)

req->id.id[x] = spd_random(void);

}

}

static void apppend_stunattr(struct stun_attr **attr, int attrvalue, const char *s, int *len, int *left)

{

int size = sizeof(**attr) + strlen(s);

if(*left > size) {

(*attr)->attr = htons(attrvalue);

(*attr)->len = htons(strlen(s));

memcpy((*attr)->value, s, strlen(s));

(*attr) = (struct stun_attr *) ((*attr)->value + strlen(s));

*len += size;

*left -=size;

}

}

static int stun_transaction_match(stun_transac_id *left, stun_transac_id *right)

{

return memcmp(left, right, sizeof(*left));

}

static int stun_send(int s, struct sockaddr_in *dst, struct stun_header *resp)

{

return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,

(struct sockaddr *)dst, sizeof(*dst));

}

static void append_attr_address(struct stun_attr **attr, int attrval, struct sockaddr_in *sin, int *len, int *left)

{

int size = sizeof(**attr) + 8;

struct stun_addr *addr;

if(*left > size) {

(*attr)->attr = htons(attrval);

(*attr)->len = htons(8);

addr = (struct stun_addr *)((*attr)->value);

addr->unused = 0;

addr->family = 0x01;

addr->port = sin->sin_port;

addr->addr = sin->sin_addr.s_addr;

(*attr) = (struct stun_attr *) ((*attr)->value + 8);

*len += size;

}

}

static stun_process_attr(struct stun_state *state, struct stun_attr *attr)

{

if(stun_debug)

spd_log(LOG_DEBUG, “Found stun Attribute %s (%04x), length %d\n”,

stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));

switch(ntohs(attr->attr)) {

case STUN_MSG_USERNAME:

state->username = (const char *)(attr->value);

break;

case STUN_MSG_PASSWORD:

state->password = (const char*) (attr->value);

break;

default:

if (stun_debug)

spd_log(LOG_DEBUG, “Ignoring STUN attribute %s (%04x), length %d\n”,

stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));

}

return 0;

}

int spd_stun_response_handle(int fd, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)

{

struct stun_header *hdr = (struct stun_header *)data;

struct stun_attr *attr;

struct stun_state st;

int ret = SPD_STUN_IGNORE;

int x;

if(len < sizeof(struct stun_header)) {

spd_log(LOG_DEBUG, “runt stun packet (only %d, wanting at least %d)\n”, (int)len, (int)sizeof(struct stun_header));

return -1;

}

len -= sizeof(struct stun_header);

data += sizeof(struct stun_header);

x = ntohs(hdr->msglen);

if(stun_debug) {

spd_log(LOG_DEBUG, “stun packet, msg %s (%04x), length: %d\n”, stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), x);

}

if(x > len) {

spd_log(LOG_DEBUG, “Scrambled STUN packet length (got %d, expecting %d)\n”, x, (int)len);

} else

len = x;

memset(&st, 0, sizeof(st));

while(len) {

if(len < sizeof(struct stun_attr)) {

spd_log(LOG_WARNING,

“stun attribute got (%d)  expect (%d) \n”, len, (int)sizeof(struct stun_attr));

break;

}

if(stun_cb)

stun_cb(attr, arg);

if(stun_process_attr(&st, attr)) {

spd_log(LOG_WARNING, “Failed to handle attribute %s (%04x)\n”, stun_attr2str(attr->attr), ntohs(attr->attr));

break;

}

attr->attr = 0;

data += x;

len -= x;

}

*data = ‘\0’;

if(len == 0) {

unsigned char respdata[1024];

struct stun_header *resp = (struct stun_header)respdata;

int resplen = 0;

int respleft = sizeof(respdata) – sizeof(struct stun_header);

resp->id = hdr->id;

resp->msgtype = 0;

resp->msglen = 0;

attr = (struct stun_attr *)resp->attr;

switch(ntohs(hdr->msgtype)) {

case STUN_BINDREQ:

if(stun_debug)

spd_log(LOG_DEBUG, “STUN Bind Request, username: %s\n”,

st.username ? st.username : “”);

if(st.username)

apppend_stunattr(&attr, STUN_MSG_USERNAME, st.username, &resplen, &respleft);

append_attr_address(&attr, STUN_MSG_MAPPED_ADDR, src, &resplen, &respleft);

resp->msglen = htons(resplen);

resp->msgtype = htons(STUN_BINDRESP);

stun_send(fd, src, resp);

ret = SPD_STUN_ACCEPT;

break;

default:

if(stun_debug)

spd_log(LOG_DEBUG, “Dunnon what to do with stun message %04x (%s)\n”,

ntohs(hdr->msgtype), stun_msg2str(ntohs(hdr->msgtype)));

}

}

return ret;

}

/*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.

* This is used as a callback for stun_handle_response

* when called from ast_stun_request.

*/

static int stun_get_mapped(struct stun_attr *attr, void *arg)

{

struct stun_addr *addr = (struct stun_addr *)(attr+ 1);

struct sockaddr_in *sa = (struct sockaddr_in *)arg;

if(ntohs(attr->attr) != STUN_MSG_MAPPED_ADDR || ntohs(attr->len) != 8)

return 1;

sa->sin_port = addr->port;

sa->sin_addr.s_addr = addr->addr;

return 0;

}

int spd_stun_bind(int fd, struct sockaddr_in *dest, const char *username, struct sockaddr_in *resp)

{

struct stun_header *req;

struct stun_header *rsp;

unsigned char req_buf[1024];

unsigned char rsp_buf[1024];

int reqlen, reqleft;

struct stun_attr *attr;

int res = -1;

int retry;

if(resp) {

memset(resp, 0, sizeof(struct sockaddr_in));

}

req = (struct stun_header *) req_buf;

/* construct stun header */

stun_transaction_id(req);

reqlen = 0;

reqleft = sizeof(req_buf) – sizeof(struct stun_header);

req->msgtype = 0;

req->msglen = 0;

/* stun body */

attr = (struct stun_attr *) req->attr;

if(username) {

apppend_stunattr(&attr, STUN_MSG_USERNAME, username, &reqlen, &reqleft);

}

req->msglen = htons(reqlen);

req->msgtype = htons(STUN_BINDREQ);

for(retry = 0; retry< 3; retry++;) {

struct sockaddr_in src;

socklen_t srclen;

res = stun_send(fd, dest, req);

if(res < 0) {

spd_log(LOG_DEBUG, ” stun_send try %d failed: %s\n”, retry, strerror(errno));

break;

}

if(!resp) {

res = 0;

break;

}

try_again:

{

struct pollfd pfds = { .fd = fd, .events = POLLIN };

res = spd_poll(&pfds, 1, 3000);

if(res < 0) {

/* Error */

continue;

}

if(!res) {

/* timeout */

res = 1;

continue;

}

}

/* read stun response  */

memset(&src, 0, sizeof(src));

srclen = sizeof(src);

res = recvfrom(fd, rsp_buf, sizeof(rsp_buf) -1,

0, (struct sockaddr *)&src, &srclen);

if(res < 0) {

spd_log(LOG_DEBUG, “recvfrom try %d failed: %s\n”, retry, strerror(errno));

break;

}

rsp = (struct stun_header *) rsp_buf;

if(spd_stun_response_handle(fd, &src, rsp_buf, res, stun_get_mapped, resp)

|| (rsp->msgtype != htons(STUN_BINDRESP))

|| stun_transaction_match(&req->id, &rsp->id)) {

memset(resp, 0, sizeof(struct sockaddr_in));

goto try_again;

}

res = 0;

break;

}

return res;

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160553.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Executors和ThreadPoolExecutor学习整理

    任务的执行与线程池(上) https://mp.weixin.qq.com/s/p3JZERyZXnF8jR_3KKIGJA 任务的执行与线程池(下) https://mp.weixin.qq.com/s/iUAaVXIB8rCzP_GeDhIlqAjava并发编程–Executor 框架 https://www.cnblogs.com/MOBIN/p/5436482.html线程…

  • 学校老师要求微信群里的家长下载钉钉建群,解散微信群,钉钉是不正当商业竞争吗?「建议收藏」

    学校老师要求微信群里的家长下载钉钉建群,解散微信群,钉钉是不正当商业竞争吗?「建议收藏」仅仅只是一个学校里面在推广使用钉钉软件建群,不再使用微信群。就可以涉及不正当的商业竞争,我想这也未免太夸大其词了。学校使用什么样的软件来帮助老师管理学生管理学校,同时软件又是免费的,何来不正当竞争之说?反过来说如果学校还在使用微信群,那么是不是微信又涉及到不正当的商业竞争呢?所以不论是钉钉还是微信,都只是方便家校沟通的一种软件,只要不牵扯到经济利益,就不存在任何的不正当竞争。微信群为什么越来越不适合作为家校沟通的渠道在当今的移动互联网时代,学校的班级管理同样需要借助于互联网的先进技术,但是就我们

  • opc服务器消息通知代码,OPC 服务器 操作示例源码

    opc服务器消息通知代码,OPC 服务器 操作示例源码【实例简介】TestOPC【实例截图】【核心代码】usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingHaiGrang.Package.OpcNetApiChs.DaNet;usingHaiGrang.Package.OpcNetApiChs.Opc;usingHaiGr…

  • java.sql.SQLException: not support oracle driver 8.0

    java.sql.SQLException: not support oracle driver 8.0

  • php7.2调用curl_init()报错解决方案「建议收藏」

    php7.2调用curl_init()报错解决方案「建议收藏」使用PHP7.2运行代码的时候出现提示curl_init()调用失败:未定义的问题,即Calltoundefinedfunctioncurl_init()解决方法:1.在linux终端键入apt-cachesearchcurl|grepphpubuntu@VM-16-9-ubuntu:/etc/php/7.2/apache2$apt-cachesearc…

  • 拉氏变换应用_拉氏反变换公式表

    拉氏变换应用_拉氏反变换公式表由系统函数零、极点分别决定时域特性(一)零、极点分布与波形特征的对应的零、极点:典型情况极点分布与原函数波形对应关系极点位于s平面坐标原点,冲激响应为阶跃函数 极点位于s平面实轴上,冲激响应具有指数形式,正为指数增长,负为指数衰减 虚轴上共轭极点给出等幅振荡 极点落在s平面左平面内共轭极点对应衰减震荡(左平面衰减,共轭极点振荡)多重极点典型情况(一般几重极点就乘上t的几次方)位于s平面坐标原点的二阶或三阶极点分别给出时间函数为t或他(1/2)t^2 实轴上二阶极点给出t与指数函数的

    2022年10月28日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号