#pragma module TCPIP$SCTP_CLIENTX "V5.7-00" /* ** PURPOSE: ** ** Simple SCTP client using the sctp_connectx() API. ** ** BUILD ENVIRONMENT: ** ** If the current version of DECC does not suport SCTP, then you must ** manually configure the environment as follows: ** ** $ define netinet tcpip$examples ** ** BUILD INSTRUCTIONS: ** ** $ cc tcpip$sctp_clientx ** $ link tcpip$sctp_clientx,tcpip$sctp.opt/opt ** ** SYNTAX: ** ** tcpip$sctp_clientx [port] ** ** EXAMPLE: ** ** Define a foreign symbol to point at the application. ** ** $ sctp_clientx :== $TCPIP$EXAMPLES:tcpip$sctp_clientx ** $ sctp_clientx myserver */ #define _SOCKADDR_LEN #include #include #include #ifndef __VMS #include #else #include #endif typedef unsigned int socklen_t; /* normally found in socket.h */ #include #include #include #include #include /* SCTP */ #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 /* SCTP */ #endif #define SA(x) ((struct sockaddr *)(x)) #define SIN(x) ((struct sockaddr_in *)(x)) #define DECODE_AF(af) ((af) == AF_INET ? "AF_INET" : \ (af) == AF_INET6 ? "AF_INET6" : \ "Unknown"), af #define DECODE_ST(st) ((st) == SOCK_STREAM ? "SOCK_STREAM" : \ (st) == SOCK_DGRAM ? "SOCK_DGRAM" : \ (st) == SOCK_RAW ? "SOCK_RAW" : \ (st) == SOCK_SEQPACKET ? "SOCK_SEQPACKET" : \ "Unknown"), st #define DECODE_PR(pr) ((pr) == IPPROTO_TCP ? "IPPROTO_TCP" : \ (pr) == IPPROTO_UDP ? "IPPROTO_UDP" : \ (pr) == IPPROTO_SCTP ? "IPPROTO_SCTP" : \ "Unknown"), pr #define DEF_PORTNAME "55555" void display_sockaddr(struct sockaddr *sa) { struct sockaddr_in *sin; struct sockaddr_in6 *sin6; char name[256]; int err; /* retrieve the nodename */ err = getnameinfo(sa, sa->sa_len, name, sizeof(name), NULL, 0, 0); if(err) { if(err == EAI_SYSTEM) perror("getnameinfo"); else printf("getnameinfo: %s\n", gai_strerror(err)); return; } printf("sockaddr:\n"); printf(" len : %d\n", sa->sa_len); printf(" family: %s (%d)\n", DECODE_AF(sa->sa_family)); switch(sa->sa_family) { case AF_INET: printf(" IPV4 Address Details:\n"); sin = (struct sockaddr_in *)sa; printf(" sin_port : %d\n", ntohs(sin->sin_port)); printf(" sin_addr : %#x (%s)\n", sin->sin_addr.s_addr, name); break; case AF_INET6: printf(" IPV6 Address Details:\n"); sin6 = (struct sockaddr_in6 *)sa; printf(" sin6_port : %d\n", ntohs(sin6->sin6_port)); printf(" sin6_flowinfo: %d\n", sin6->sin6_flowinfo); printf(" sin6_addr : %#x%#x%#x%#x (%s)\n", sin6->sin6_addr.s6_laddr[3], sin6->sin6_addr.s6_laddr[2], sin6->sin6_addr.s6_laddr[1], sin6->sin6_addr.s6_laddr[0], name); break; default: printf("Unknown address family: %d\n", sa->sa_family); } } void display_addrinfo(struct addrinfo *ai) { int i = 0; for(; ai; ai = ai->ai_next) { printf("--- %d ----------------------------\n", ++i); printf("ai_family : %s (%d)\n", DECODE_AF(ai->ai_family)); printf("ai_socktype : %s (%d)\n", DECODE_ST(ai->ai_socktype)); printf("ai_protocol : %s (%d)\n", DECODE_PR(ai->ai_protocol)); printf("ai_addrlen : %d\n", ai->ai_addrlen); printf("ai_canonname: %s\n", ai->ai_canonname); display_sockaddr(ai->ai_addr); } } void display_packed_sockaddrs(struct sockaddr_storage *ss, int count) { int i, len; len = 0; for(i = 0; i < count; i++) { printf("+++ %d of %d +++++++++++++++++++++++++++++\n", i+1, count); display_sockaddr(SA((char *)ss + len)); len += ss->ss_len; } } struct addrinfo *parse_addrinfo(char *server, char *service, int protocol, int socktype) { struct addrinfo *res, hints; int err; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_protocol = protocol; hints.ai_socktype = socktype; hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; err = getaddrinfo(server, /* name, alias, or numeric address IPV4/IPV6 */ service,/* service name or port number */ &hints, /* hints limit search to sock type, AF or proto */ &res); /* linked list of addrinfo structures */ if(err) { if(err == EAI_SYSTEM) perror("getaddrinfo"); else printf("%s", gai_strerror(err)); return NULL; } return res; } int main(int argc, char *argv[]) { int sd; int count, cc; char *server, *portname; struct addrinfo *ai; char line[128]; in_addr_t in_addr; struct hostent *hent; struct sockaddr_storage *connectx_addrs = NULL; /* packed addresses */ struct sockaddr_storage *paddrs, *laddrs; /* packed addresses */ if(argc == 1) {printf("Usage: connectx [port]\n"); return 1;} server = argv[1]; if(argc == 3) portname = argv[2]; else portname = DEF_PORTNAME; ai = parse_addrinfo(server, portname, IPPROTO_SCTP, SOCK_STREAM); if(ai == NULL) {printf("Error retrieving address information\n"); return 1;} printf("Addresses matching %s\n", server); display_addrinfo(ai); /* pack socket addresses into the connectx buffer */ count = 0; cc = 0; for(; ai; ai = ai->ai_next) { connectx_addrs = realloc(connectx_addrs, cc + ai->ai_addrlen); /* add an element */ if(connectx_addrs == NULL) {perror("realloc"); return 1;} memcpy((char *)connectx_addrs + cc, ai->ai_addr, ai->ai_addrlen); count++; /* one more address packed in */ cc += ai->ai_addrlen; } freeaddrinfo(ai); /* finished with address info */ printf("\nAddresses (packed) to connect to (%d):\n", count); display_packed_sockaddrs(connectx_addrs, count); /* create socket */ sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); if(sd == -1) {perror("socket"); return 1;} if(sctp_connectx(sd, SA(connectx_addrs), count, 0) == -1) {perror("sctp_connectx"); return 1;} /* call getpaddrs to get list of peer addresses in association */ count = sctp_getpaddrs(sd, 0, (struct sockaddr **)&paddrs); if(count == -1) {perror("sctp_getpaddrs"); return 1;} printf("\nPeer Addresses in association 0:\n"); display_packed_sockaddrs(paddrs, count); /* call getladdrs to get list of local addresses in association */ count = sctp_getladdrs(sd, 0, (struct sockaddr **)&laddrs); if(count == -1) {perror("sctp_getladdrs"); return 1;} printf("\nLocal Addresses in association 0:\n"); display_packed_sockaddrs(laddrs, count); /* write loop */ count = 0; do { printf("Enter a line to send:"); if(scanf("%[^\n]%*c", line) == -1) {perror("scanf"); return 1;} cc = write(sd, line, strlen(line)); if(cc == -1) {perror("send"); return 1;} if(cc == 0) {printf("Peer disconnected\n"); break;} } while(cc != -1 && line[0] != 'Q'); if(close(sd) == -1) {perror("close"); return 1;} }