SCTP:成功调用 connect() 后,SCTP 套接字的 sctp_status.sstate 值应该是多少?
SCTP: What should be the sctp_status.sstate value of an SCTP socket after succesful connect() call?
我正在尝试通过 SCTP 连接到远程对等点(除了通过套接字和 ping 连接到它之外,我没有目录访问权限)。假设我已成功连接,如果我尝试调用 getsocktopt(),我的 sctp_status.sstate 的值应该是多少?根据 sctp.h,我的是 SCTP_COOKIE_ECHOED(3)。这是正确的吗?不应该是SCTP_ESTABLISHED吗?
因为我尝试使用此代码向远程对等方发送消息:
ret = sctp_sendmsg (connSock, (void *) data, (size_t) strlen (data), (struct sockaddr *) &servaddr, sizeof (servaddr), 46, 0, 0, 0, 0);
它返回了我尝试发送的字节数。然后当我尝试捕捉是否有任何响应时:
ret = sctp_recvmsg (connSock, (void *) reply, sizeof (reply), NULL,
NULL, NULL, &flags);
它 returns -1 错误号为 ECONNRESET(104)。我的代码或流程中可能存在哪些错误?我错过了什么吗?
提前感谢您的回答。会很高兴的。 :)
更新:下面是我连接到远程对等点的客户端代码。它实际上是一个供我使用的节点插件,因为节点不完全支持 SCTP。使用 lksctp-tools 包来包含 headers.
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAX_BUFFER 1024
int connSock = 0;
int connect(char host[], int port, char remote_host[], int remote_port, int timeout) {
int ret, flags;
fd_set rset, wset;
struct sockaddr_in servaddr;
struct sockaddr_in locaddr;
struct sctp_initmsg initmsg;
struct timeval tval;
struct sctp_status status;
socklen_t opt_len;
errno = 0;
connSock = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);
flags = fcntl(connSock, F_GETFL, 0);
fcntl(connSock, F_SETFL, flags | O_NONBLOCK);
if (connSock == -1)
{
return (-1);
}
memset(&locaddr, 0, sizeof(locaddr));
locaddr.sin_family = AF_INET;
locaddr.sin_port = htons(port);
locaddr.sin_addr.s_addr = inet_addr(host);
ret = bind(connSock, (struct sockaddr *)&locaddr, sizeof(locaddr));
if (ret == -1)
{
return (-1);
}
memset (&initmsg, 0, sizeof (initmsg));
initmsg.sinit_num_ostreams = 5;
initmsg.sinit_max_instreams = 5;
initmsg.sinit_max_attempts = 10;
ret = setsockopt(connSock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
if (ret == -1)
{
return (-1);
}
memset (&servaddr, 0, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (remote_port);
servaddr.sin_addr.s_addr = inet_addr (remote_host);
if((ret = connect (connSock, (struct sockaddr *) &servaddr, sizeof (servaddr))) < 0)
if (errno != EINPROGRESS)
return (-1);
if (ret == 0) {
fcntl(connSock, F_SETFL, flags);
return 0;
}
FD_ZERO(&rset);
FD_SET(connSock, &rset);
wset = rset;
tval.tv_sec = timeout;
tval.tv_usec = 0;
ret = select(connSock+1, &rset, &wset, NULL, timeout ? &tval : NULL);
if (ret == 0) {
close(connSock);
errno = ETIMEDOUT;
return(-1);
}
else if (ret < 0) {
return(-1);
}
fcntl(connSock, F_SETFL, flags);
opt_len = (socklen_t) sizeof(struct sctp_status);
getsockopt(connSock, IPPROTO_SCTP, SCTP_STATUS, &status, &opt_len);
printf ("assoc id = %d\n", status.sstat_assoc_id);
printf ("state = %d\n", status.sstat_state);
printf ("instrms = %d\n", status.sstat_instrms);
printf ("outstrms = %d\n", status.sstat_outstrms);
return 0;
}
int sendMessage(char remote_host[], int remote_port, char data[]) {
int ret, flags;
struct sockaddr_in servaddr;
char reply[1024];
errno = 0;
memset (&servaddr, 0, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (remote_port);
servaddr.sin_addr.s_addr = inet_addr (remote_host);
printf("\nSending %s (%li bytes)", data, strlen(data));
ret = sctp_sendmsg (connSock, (void *) data, (size_t) strlen (data),
(struct sockaddr *) &servaddr, sizeof (servaddr), 46, 0, 0, 0, 0);
if (ret == -1)
{
printf("\nError sending errno(%d)", errno);
return -1;
}
else {
ret = sctp_recvmsg (connSock, (void *) reply, sizeof (reply), NULL,
NULL, NULL, &flags);
if (ret == -1)
{
printf("\nError receiving errno(%d)", errno);
return -1;
}
else {
printf("\nServer replied with %s", reply);
return 0;
}
}
}
int getSocket() {
return connSock;
}
我不知道在连接之前我是否需要先设置任何我错过的重要内容。我从不同的来源得到了片段,所以它很乱。
另一个更新,这是执行该代码时的 tshark 日志:
3336.919408 local -> remote SCTP 82 INIT
3337.006690 remote -> local SCTP 810 INIT_ACK
3337.006727 local -> remote SCTP 774 COOKIE_ECHO
3337.085390 remote -> local SCTP 50 COOKIE_ACK
3337.086650 local -> remote SCTP 94 DATA
3337.087277 remote -> local SCTP 58 ABORT
3337.165266 remote -> local SCTP 50 ABORT
此 here.
的详细 tshark 日志
看起来远程发送了它的 COOKIE_ACK 块,但我的客户端未能将其状态设置为 ESTABLISHED(我仔细检查了 3 here 的 sstate 值)。
如果关联设置过程已完成,则状态应为 SCTP_ESTABLISHED。 SCTP_COOKIE_ECHOED表示关联还没有完全建立。这意味着发起端(在这种情况下是您的本地主机)已经发送(一次或多次)COOKIE_ECHO 块,但 COOKIE_ACK 尚未从远程端确认。
您可以在此状态下发送消息(SCTP 将简单地缓冲它直到它到达 COOKIE_ACK 并稍后重新发送)。
根据您提供的信息,很难说出了什么问题。在这个阶段,可能值得深入研究 wireshark 跟踪,以查看远程端正在回复您的 COOKIE_ECHO。
此外,如果您可以分享您的 client/server 辅助代码,这可能有助于确定根本原因。
更新 #1:
还应注意,应用程序可以自行中止与它们的关联(例如,如果未在该服务器上配置此关联)。如果您尝试连接到随机服务器(而不是您的特定服务器),那很有可能并且在您的情况下实际上是有意义的。在这种情况下,你这边的关联状态是 COOKIE_ECHOED 因为 COOKIE_ACK 还没有到达(只是一个竞争条件)。正如我之前所说,SCTP 很高兴地接受您处于这种状态的数据,并且只是缓冲它直到它接收到 COOKIE_ACK。远程端的 SCTP 立即发送 COOKIE_ACK,甚至在应用程序在 accept() 中接收到执行控制之前。如果应用程序决定以不正常的方式终止关联,它将发送 ABORT(这是您在 wireshark 跟踪中的第一个 ABORT)。你方还没有收到这个 ABORT 并发送数据块。由于远程端认为此关联已终止,因此无法处理数据块,因此它将其视为突然发生(请参阅 RFC 4960 第 8.4 章)并发送另一个将 t 位设置为 1 的 ABORT。
我想这就是你的情况。您只需查看 wireshark trace 即可轻松确认。
我正在尝试通过 SCTP 连接到远程对等点(除了通过套接字和 ping 连接到它之外,我没有目录访问权限)。假设我已成功连接,如果我尝试调用 getsocktopt(),我的 sctp_status.sstate 的值应该是多少?根据 sctp.h,我的是 SCTP_COOKIE_ECHOED(3)。这是正确的吗?不应该是SCTP_ESTABLISHED吗?
因为我尝试使用此代码向远程对等方发送消息:
ret = sctp_sendmsg (connSock, (void *) data, (size_t) strlen (data), (struct sockaddr *) &servaddr, sizeof (servaddr), 46, 0, 0, 0, 0);
它返回了我尝试发送的字节数。然后当我尝试捕捉是否有任何响应时:
ret = sctp_recvmsg (connSock, (void *) reply, sizeof (reply), NULL,
NULL, NULL, &flags);
它 returns -1 错误号为 ECONNRESET(104)。我的代码或流程中可能存在哪些错误?我错过了什么吗?
提前感谢您的回答。会很高兴的。 :)
更新:下面是我连接到远程对等点的客户端代码。它实际上是一个供我使用的节点插件,因为节点不完全支持 SCTP。使用 lksctp-tools 包来包含 headers.
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAX_BUFFER 1024
int connSock = 0;
int connect(char host[], int port, char remote_host[], int remote_port, int timeout) {
int ret, flags;
fd_set rset, wset;
struct sockaddr_in servaddr;
struct sockaddr_in locaddr;
struct sctp_initmsg initmsg;
struct timeval tval;
struct sctp_status status;
socklen_t opt_len;
errno = 0;
connSock = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);
flags = fcntl(connSock, F_GETFL, 0);
fcntl(connSock, F_SETFL, flags | O_NONBLOCK);
if (connSock == -1)
{
return (-1);
}
memset(&locaddr, 0, sizeof(locaddr));
locaddr.sin_family = AF_INET;
locaddr.sin_port = htons(port);
locaddr.sin_addr.s_addr = inet_addr(host);
ret = bind(connSock, (struct sockaddr *)&locaddr, sizeof(locaddr));
if (ret == -1)
{
return (-1);
}
memset (&initmsg, 0, sizeof (initmsg));
initmsg.sinit_num_ostreams = 5;
initmsg.sinit_max_instreams = 5;
initmsg.sinit_max_attempts = 10;
ret = setsockopt(connSock, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
if (ret == -1)
{
return (-1);
}
memset (&servaddr, 0, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (remote_port);
servaddr.sin_addr.s_addr = inet_addr (remote_host);
if((ret = connect (connSock, (struct sockaddr *) &servaddr, sizeof (servaddr))) < 0)
if (errno != EINPROGRESS)
return (-1);
if (ret == 0) {
fcntl(connSock, F_SETFL, flags);
return 0;
}
FD_ZERO(&rset);
FD_SET(connSock, &rset);
wset = rset;
tval.tv_sec = timeout;
tval.tv_usec = 0;
ret = select(connSock+1, &rset, &wset, NULL, timeout ? &tval : NULL);
if (ret == 0) {
close(connSock);
errno = ETIMEDOUT;
return(-1);
}
else if (ret < 0) {
return(-1);
}
fcntl(connSock, F_SETFL, flags);
opt_len = (socklen_t) sizeof(struct sctp_status);
getsockopt(connSock, IPPROTO_SCTP, SCTP_STATUS, &status, &opt_len);
printf ("assoc id = %d\n", status.sstat_assoc_id);
printf ("state = %d\n", status.sstat_state);
printf ("instrms = %d\n", status.sstat_instrms);
printf ("outstrms = %d\n", status.sstat_outstrms);
return 0;
}
int sendMessage(char remote_host[], int remote_port, char data[]) {
int ret, flags;
struct sockaddr_in servaddr;
char reply[1024];
errno = 0;
memset (&servaddr, 0, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (remote_port);
servaddr.sin_addr.s_addr = inet_addr (remote_host);
printf("\nSending %s (%li bytes)", data, strlen(data));
ret = sctp_sendmsg (connSock, (void *) data, (size_t) strlen (data),
(struct sockaddr *) &servaddr, sizeof (servaddr), 46, 0, 0, 0, 0);
if (ret == -1)
{
printf("\nError sending errno(%d)", errno);
return -1;
}
else {
ret = sctp_recvmsg (connSock, (void *) reply, sizeof (reply), NULL,
NULL, NULL, &flags);
if (ret == -1)
{
printf("\nError receiving errno(%d)", errno);
return -1;
}
else {
printf("\nServer replied with %s", reply);
return 0;
}
}
}
int getSocket() {
return connSock;
}
我不知道在连接之前我是否需要先设置任何我错过的重要内容。我从不同的来源得到了片段,所以它很乱。
另一个更新,这是执行该代码时的 tshark 日志:
3336.919408 local -> remote SCTP 82 INIT
3337.006690 remote -> local SCTP 810 INIT_ACK
3337.006727 local -> remote SCTP 774 COOKIE_ECHO
3337.085390 remote -> local SCTP 50 COOKIE_ACK
3337.086650 local -> remote SCTP 94 DATA
3337.087277 remote -> local SCTP 58 ABORT
3337.165266 remote -> local SCTP 50 ABORT
此 here.
的详细 tshark 日志看起来远程发送了它的 COOKIE_ACK 块,但我的客户端未能将其状态设置为 ESTABLISHED(我仔细检查了 3 here 的 sstate 值)。
如果关联设置过程已完成,则状态应为 SCTP_ESTABLISHED。 SCTP_COOKIE_ECHOED表示关联还没有完全建立。这意味着发起端(在这种情况下是您的本地主机)已经发送(一次或多次)COOKIE_ECHO 块,但 COOKIE_ACK 尚未从远程端确认。
您可以在此状态下发送消息(SCTP 将简单地缓冲它直到它到达 COOKIE_ACK 并稍后重新发送)。
根据您提供的信息,很难说出了什么问题。在这个阶段,可能值得深入研究 wireshark 跟踪,以查看远程端正在回复您的 COOKIE_ECHO。
此外,如果您可以分享您的 client/server 辅助代码,这可能有助于确定根本原因。
更新 #1: 还应注意,应用程序可以自行中止与它们的关联(例如,如果未在该服务器上配置此关联)。如果您尝试连接到随机服务器(而不是您的特定服务器),那很有可能并且在您的情况下实际上是有意义的。在这种情况下,你这边的关联状态是 COOKIE_ECHOED 因为 COOKIE_ACK 还没有到达(只是一个竞争条件)。正如我之前所说,SCTP 很高兴地接受您处于这种状态的数据,并且只是缓冲它直到它接收到 COOKIE_ACK。远程端的 SCTP 立即发送 COOKIE_ACK,甚至在应用程序在 accept() 中接收到执行控制之前。如果应用程序决定以不正常的方式终止关联,它将发送 ABORT(这是您在 wireshark 跟踪中的第一个 ABORT)。你方还没有收到这个 ABORT 并发送数据块。由于远程端认为此关联已终止,因此无法处理数据块,因此它将其视为突然发生(请参阅 RFC 4960 第 8.4 章)并发送另一个将 t 位设置为 1 的 ABORT。 我想这就是你的情况。您只需查看 wireshark trace 即可轻松确认。