oracle没有修改的原代码链接:http://docs.oracle.com/cd/E19120-01/open.solaris/817-4415/sockets-27/index.html
修改以后执行:
通过命令sudo apt-get install libsctp-dev lksctp-tools下载netinet/sctp.h
gcc 4.5或以上需要用-pthread,查看gcc版本可以man gcc|grep gcc-
compile: make
run:./oracle_sctpserver.out
./oracle_sctpclient.out
Makefile
OB=oracle_sctpclient.out oracle_sctpserver.out
.PHONY:THISALL
THISALL:$(OB)
.o.out:
#gcc -lpthread $(<) -o $@
#in gcc 4.5.2 use -pthrea
gcc -pthread $(<) -o $@
.c.o:
gcc -c $(<)
clean:
rm %.o
oracle_sctpdef.h
#ifndef __oracle_sctpdef_H__
#define __oracle_sctpdef_H__
//#define _XPG4_2
#define MSG_XPG4_2 0
#define LoopbackAddress "127.0.0.1"
//#define __EXTENSIONS__
#define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG)
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include<arpa/inet.h>//Xu__Jiayu add
#include <netinet/sctp.h>
#include <netdb.h>
#define BUFLEN 1024
typedef unsigned char uchar_t;
/*sctp_notificaton by RFC 6458--https://tools.ietf.org/html/rfc6458#section-6.1
union sctp_notification {
struct sctp_tlv {
uint16_t sn_type; // Notification type.
uint16_t sn_flags;
uint32_t sn_length;
} sn_header;
struct sctp_assoc_change sn_assoc_change;
struct sctp_paddr_change sn_paddr_change;
struct sctp_remote_error sn_remote_error;
struct sctp_send_failed sn_send_failed;
struct sctp_shutdown_event sn_shutdown_event;
struct sctp_adaptation_event sn_adaptation_event;
struct sctp_pdapi_event sn_pdapi_event;
struct sctp_authkey_event sn_auth_event;
struct sctp_sender_dry_event sn_sender_dry_event;
struct sctp_send_failed_event sn_send_failed_event;
};
*/
#endif
oracle_sctpserver.c
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* To enable socket features used for SCTP socket. */
#include"oracle_sctpdef.h"
/*
* Given an event notification, print out what it is.
*/
static void
handle_event(void *buf)
{
struct sctp_assoc_change *sac;
struct sctp_send_failed *ssf;
struct sctp_paddr_change *spc;
struct sctp_remote_error *sre;
union sctp_notification *snp;
char addrbuf[INET6_ADDRSTRLEN];
const char *ap;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
snp = buf;
switch (snp->sn_header.sn_type) {
case SCTP_ASSOC_CHANGE:
sac = &snp->sn_assoc_change;
printf("^^^ assoc_change: state=%hu, error=%hu, instr=%hu "
"outstr=%hu\n", sac->sac_state, sac->sac_error,
sac->sac_inbound_streams, sac->sac_outbound_streams);
break;
case SCTP_SEND_FAILED:
ssf = &snp->sn_send_failed;
printf("^^^ sendfailed: len=%hu err=%d\n", ssf->ssf_length,
ssf->ssf_error);
break;
case SCTP_PEER_ADDR_CHANGE:
spc = &snp->sn_paddr_change;
if (spc->spc_aaddr.ss_family == AF_INET) {
sin = (struct sockaddr_in *)&spc->spc_aaddr;
ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf,
INET6_ADDRSTRLEN);
} else {
sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf,
INET6_ADDRSTRLEN);
}
printf("^^^ intf_change: %s state=%d, error=%d\n", ap,
spc->spc_state, spc->spc_error);
break;
case SCTP_REMOTE_ERROR:
sre = &snp->sn_remote_error;
printf("^^^ remote_error: err=%hu len=%hu\n",
ntohs(sre->sre_error), ntohs(sre->sre_length));
break;
case SCTP_SHUTDOWN_EVENT:
printf("^^^ shutdown event\n");
break;
default:
printf("unknown type: %hu\n", snp->sn_header.sn_type);
break;
}
}
/*
* Receive a message from the network.
*/
static void *
getmsg(int fd, struct msghdr *msg, void *buf, size_t *buflen,
ssize_t *nrp, size_t cmsglen)
{
ssize_t nr = 0;
struct iovec iov[1];
*nrp = 0;
iov->iov_base = buf;
msg->msg_iov = iov;
msg->msg_iovlen = 1;
/* Loop until a whole message is received. */
for (;;) {
msg->msg_flags = MSG_XPG4_2;
msg->msg_iov->iov_len = *buflen;
msg->msg_controllen = cmsglen;
nr += recvmsg(fd, msg, 0);
if (nr <= 0) {
/* EOF or error */
*nrp = nr;
return (NULL);
}
/* Whole message is received, return it. */
if (msg->msg_flags & MSG_EOR) {
*nrp = nr;
return (buf);
}
/* Maybe we need a bigger buffer, do realloc(). */
if (*buflen == nr) {
buf = realloc(buf, *buflen * 2);
if (buf == 0) {
fprintf(stderr, "out of memory\n");
exit(1);
}
*buflen *= 2;
}
/* Set the next read offset */
iov->iov_base = (char *)buf + nr;
iov->iov_len = *buflen - nr;
}
}
/*
* The echo server.
*/
static void
echo(int fd)
{
ssize_t nr;
struct sctp_sndrcvinfo *sri;
struct msghdr msg[1];
struct cmsghdr *cmsg;
char cbuf[sizeof (*cmsg) + sizeof (*sri)];
char *buf;
size_t buflen;
struct iovec iov[1];
size_t cmsglen = sizeof (*cmsg) + sizeof (*sri);
/* Allocate the initial data buffer */
buflen = BUFLEN;
if ((buf = malloc(BUFLEN)) == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
/* Set up the msghdr structure for receiving */
memset(msg, 0, sizeof (*msg));
msg->msg_control = cbuf;
msg->msg_controllen = cmsglen;
msg->msg_flags = 0;
cmsg = (struct cmsghdr *)cbuf;
sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
/* Wait for something to echo */
while ((buf = getmsg(fd, msg, buf, &buflen, &nr, cmsglen)) != NULL) {
/* Intercept notifications here */
if (msg->msg_flags & MSG_NOTIFICATION) {
handle_event(buf);
continue;
}
iov->iov_base = buf;
msg->msg_iov = iov;
msg->msg_iovlen = 1;
iov->iov_len = nr;
msg->msg_control = cbuf;
msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
printf("got %u bytes on stream %hu:\n", nr,
sri->sinfo_stream);
write(0, buf, nr);
/* Echo it back */
msg->msg_flags = MSG_XPG4_2;
if (sendmsg(fd, msg, 0) < 0) {
perror("sendmsg");
exit(1);
}
}
if (nr < 0) {
perror("recvmsg");
}
close(fd);
}
int
main(void)
{
int lfd;
int cfd;
int onoff = 1;
struct sockaddr_in sin[1];
struct sctp_event_subscribe events;
struct sctp_initmsg initmsg;
if ((lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
perror("socket");
exit(1);
}
sin->sin_family = AF_INET;
sin->sin_port = htons(5000);
sin->sin_addr.s_addr = INADDR_ANY;
if (bind(lfd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
perror("bind");
exit(1);
}
if (listen(lfd, 1) == -1) {
perror("listen");
exit(1);
}
(void) memset(&initmsg, 0, sizeof(struct sctp_initmsg));
initmsg.sinit_num_ostreams = 64;
initmsg.sinit_max_instreams = 64;
initmsg.sinit_max_attempts = 64;
if (setsockopt(lfd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
sizeof(struct sctp_initmsg)) < 0) {
perror("SCTP_INITMSG");
exit (1);
}
/* Events to be notified for */
(void) memset(&events, 0, sizeof (events));
events.sctp_data_io_event = 1;
events.sctp_association_event = 1;
events.sctp_send_failure_event = 1;
events.sctp_address_event = 1;
events.sctp_peer_error_event = 1;
events.sctp_shutdown_event = 1;
/* Wait for new associations */
for (;;) {
if ((cfd = accept(lfd, NULL, 0)) == -1) {
perror("accept");
exit(1);
}
/* Enable ancillary data */
if (setsockopt(cfd, IPPROTO_SCTP, SCTP_EVENTS, &events,
sizeof (events)) < 0) {
perror("setsockopt SCTP_EVENTS");
exit(1);
}
/* Echo back any and all data */
echo(cfd);
}
}
oracle_sctpclient.c
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* To enable socket features used for SCTP socket. */
#include"oracle_sctpdef.h"
static void
usage(char *a0)
{
fprintf(stderr, "Usage: %s <addr>\n", a0);
}
/*
* Read from the network.
*/
static void
readit(void *vfdp)
{
int fd;
ssize_t n;
char buf[BUFLEN];
struct msghdr msg[1];
struct iovec iov[1];
struct cmsghdr *cmsg;
struct sctp_sndrcvinfo *sri;
char cbuf[sizeof (*cmsg) + sizeof (*sri)];
union sctp_notification *snp;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
fd = *(int *)vfdp;
/* Initialize the message header for receiving */
memset(msg, 0, sizeof (*msg));
msg->msg_control = cbuf;
msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
msg->msg_flags = 0;
cmsg = (struct cmsghdr *)cbuf;
sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
iov->iov_base = buf;
iov->iov_len = BUFLEN;
msg->msg_iov = iov;
msg->msg_iovlen = 1;
while ((n = recvmsg(fd, msg, 0)) > 0) {
/* Intercept notifications here */
if (msg->msg_flags & MSG_NOTIFICATION) {
snp = (union sctp_notification *)buf;
printf("[ Receive notification type %u ]\n",
snp->sn_header.sn_type/*snp->sn_type*/);//update by Xu__Jiayu error:'union sctp_notification'has no member named 'sn_type'
continue;
}
msg->msg_control = cbuf;
msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
printf("[ Receive echo (%u bytes): stream = %hu, ssn = %hu, "
"flags = %hx, ppid = %u ]\n", n,
sri->sinfo_stream, sri->sinfo_ssn, sri->sinfo_flags,
sri->sinfo_ppid);
}
if (n < 0) {
perror("recv");
exit(1);
}
close(fd);
exit(0);
}
#define MAX_STREAM 64
static void
echo(struct sockaddr_in *addr)
{
int fd;
uchar_t buf[BUFLEN];
ssize_t n;
int perr;
pthread_t tid;
struct cmsghdr *cmsg;
struct sctp_sndrcvinfo *sri;
char cbuf[sizeof (*cmsg) + sizeof (*sri)];
struct msghdr msg[1];
struct iovec iov[1];
int ret;
struct sctp_initmsg initmsg;
struct sctp_event_subscribe events;
/* Create a one-one SCTP socket */
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
perror("socket");
exit(1);
}
/*
* We are interested in association change events and we want
* to get sctp_sndrcvinfo in each receive.
*/
events.sctp_association_event = 1;
events.sctp_data_io_event = 1;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &events,
sizeof (events));
if (ret < 0) {
perror("setsockopt SCTP_EVENTS");
exit(1);
}
/*
* Set the SCTP stream parameters to tell the other side when
* setting up the association.
*/
memset(&initmsg, 0, sizeof(struct sctp_initmsg));
initmsg.sinit_num_ostreams = MAX_STREAM;
initmsg.sinit_max_instreams = MAX_STREAM;
initmsg.sinit_max_attempts = MAX_STREAM;
ret = setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
sizeof(struct sctp_initmsg));
if (ret < 0) {
perror("setsockopt SCTP_INITMSG");
exit(1);
}
if (connect(fd, (struct sockaddr *)addr, sizeof (*addr)) == -1) {
perror("connect");
exit(1);
}
/* Initialize the message header structure for sending. */
memset(msg, 0, sizeof (*msg));
iov->iov_base = buf;
msg->msg_iov = iov;
msg->msg_iovlen = 1;
msg->msg_control = cbuf;
msg->msg_controllen = sizeof (*cmsg) + sizeof (*sri);
msg->msg_flags |= MSG_XPG4_2;
memset(cbuf, 0, sizeof (*cmsg) + sizeof (*sri));
cmsg = (struct cmsghdr *)cbuf;
sri = (struct sctp_sndrcvinfo *)(cmsg + 1);
cmsg->cmsg_len = sizeof (*cmsg) + sizeof (*sri);
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_SNDRCV;
sri->sinfo_ppid = 1;
/* Start sending to stream 0. */
sri->sinfo_stream = 0;
/* Create a thread to receive network traffic. */
perr = pthread_create(&tid, NULL, (void *(*)(void *))readit, &fd);
if (perr != 0) {
fprintf(stderr, "pthread_create: %d\n", perr);
exit(1);
}
/* Read from stdin and then send to the echo server. */
while ((n = read(fileno(stdin), buf, BUFLEN)) > 0) {
iov->iov_len = n;
if (sendmsg(fd, msg, 0) < 0) {
perror("sendmsg");
exit(1);
}
/* Send the next message to a different stream. */
sri->sinfo_stream = (sri->sinfo_stream + 1) % MAX_STREAM;
}
pthread_cancel(tid);
close(fd);
}
int
main(int argc, char **argv)
{
struct sockaddr_in addr[1];
struct hostent *hp;
int error;
/* if (argc < 2) {
usage(*argv);
exit(1);
}*/
/* Find the host to connect to. */
//hp = getipnodebyname(argv[1], AF_INET, AI_DEFAULT, &error);
//参数1,ipv4标志,flag,错误码
//Xu__Jiayu
//char ret_hostname[65];
//gethostname(ret_hostname,sizeof(ret_hostname));//#include<unistd.h>
//printf("by gethostname() get hostname:%s\n",ret_hostname);
// struct hostent *ret_hostent;
// hp=ret_hostent=gethostbyname(ret_hostname);
//参数0为./运行程序名 参数1为需要输入的ip 例如:127.0.0.1
if (hp == NULL) {
fprintf(stderr, "host not found\n");
exit(1);
}
addr->sin_family = AF_INET;
addr->sin_addr.s_addr=inet_addr(LoopbackAddress);
//addr->sin_addr.s_addr=inet_addr(hp->h_addr_list[0]);
// addr->sin_addr.s_addr = *(ipaddr_t *)hp->h_addr_list[0];
addr->sin_port = htons(5000);
echo(addr);
return (0);
}
server screen
ubuntu@linuxc_easy:~/linuxc_easy/pcdtest/sctp$ ./oracle_sctpserver.out
^^^ intf_change: 172.17.0.4 state=5, error=2
got 21 bytes on stream 0:
this is a second and
got 6 bytes on stream 1:
ahah
got 24 bytes on stream 2:
just test 127.0.0.1 end
^^^ shutdown event
client screen
ubuntu@linuxc_easy:~/linuxc_easy/pcdtest/sctp$ ./oracle_sctpclient.out
[ Receive notification type 32769 ]
this is a [ Receive notification type 32770 ]
second and
[ Receive notification type 32777 ]
[ Receive echo (21 bytes): stream = 0, ssn = 0, flags = 0, ppid = 0 ]
ahah
[ Receive notification type 32777 ]
[ Receive echo (6 bytes): stream = 0, ssn = 0, flags = 0, ppid = 0 ]
just test 127.0.0.1 end
[ Receive notification type 32777 ]
[ Receive echo (24 bytes): stream = 0, ssn = 0, flags = 0, ppid = 0 ]
^C