📄 sctp_darn.c
字号:
poll_snd_size = POLL_SND_SIZE; } while (!done) { if (use_poll) { for (i = 0; i < poll_skn; i++) { poll_fds[i].events = POLLIN; } if (remote_host) { /* Poll output on the first socket. */ poll_fds[0].events |= POLLOUT; } if ((ret = poll(poll_fds, poll_skn, -1))) { if (ret == -1) { break; } } } else { for (i = 0; i < poll_skn; i++) { FD_SET(poll_sks[i], ibitsp); FD_SET(poll_sks[i], xbitsp); } if (remote_host) { /* Only select output on the first socket. */ FD_SET(poll_sks[0], obitsp); } if ((ret = select(max_fd + 1, ibitsp, obitsp, xbitsp, (struct timeval *)0)) < 0) { if (ret == -1) { break; } } } if (remote_host) { if (use_poll) { temp_set = poll_fds[0].revents & POLLOUT; temp_fd = poll_fds[0].fd; } else { temp_set = FD_ISSET(poll_sks[0], obitsp); temp_fd = poll_sks[0]; } if (temp_set) { inter_outbuf = gen_message(poll_snd_size); if (!inter_outbuf) { fprintf(stderr, "Cannot allocate out message.\n"); exit(1); } iov.iov_base = inter_outbuf; msglen = poll_snd_size; iov.iov_len = msglen; error = sendmsg(temp_fd, &outmsg, 0); fprintf(stderr, "sent a message, msglen = %d\n", msglen); if (error != msglen) { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); if ((!nonblocking) || (EAGAIN != errno)) { exit(1); } } /* Clean up. */ free(inter_outbuf); inter_outbuf = NULL; } } /* while(!done) */ for (i = 0; !done && (i < poll_skn); i++) { if (use_poll) { temp_set = poll_fds[i].revents & POLLIN; temp_fd = poll_fds[i].fd; } else { temp_set = FD_ISSET(poll_sks[i], ibitsp); temp_fd = poll_sks[i]; } if (temp_set) { error = recvmsg(temp_fd, &inmessage, MSG_WAITALL); if (error < 0) { if ((EAGAIN == errno)) { error = 0; continue; } else { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); exit(1); } } test_print_message(temp_fd, &inmessage, error); inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); iov.iov_len = REALLY_BIG; } /* Update the associd when a notification is received * on a UDP-style socket. */ if (inmessage.msg_flags & MSG_NOTIFICATION) associd = test_verify_assoc_change(&inmessage); /* Verify there is no association. */ if (0 != test_sk_for_assoc(poll_sks[i], associd)) { printf("No association is present in sk " "No.%d now!!\n",i); } } } if (!use_poll) { free(ibitsp); free(obitsp); free(xbitsp); } return error;} /* command_poll() *//******************************************************************** * 3rd Level Abstractions ********************************************************************/#define FPS(arg) fprintf(stderr, arg)voidusage(char *argv0){ /* * The bindx options, --bindx-add and --bindx-rem, are added to * * 1. provide first testcases for the new bindx system call * * 2. continue to grow sctp_darn with more functions and * features so it will be equivalent to the "sock" tool for * TCP as for SCTP. * * FIXME - * * It is not very effective to use these two options in the * current command line mode of sctp_darn. For example, the * --bindx-rem option can only be used in conjunction with the * --bindx-add simply to test the function in the kernel * path. Ideally, bindx needs to be tested by a tool which * provides an interactive mode for users to change parameters * and configuration dynamically with existing endpoints and * associations. */ fprintf(stderr, "Usage: %s -H <localhost> -P <localport> " "[-h <remotehost>] [-p <remoteport>] -l|s\n" " -H, --local\t\tspecify one of the local addresses,\n" " -P, --local-port\tspecify the port number for local addresses,\n" " -h, --remote\t\tspecify the peer address,\n" " -p, --remote-port\tspecify the port number for the peer address,\n" " -l, --listen\t\tprint messages received from the peer,\n" " -s, --send\t\tsend messages to the peer,\n" " -B, --bindx-add" "\tadd the specified address(es) as additional bind\n" "\t\t\taddresses to the local socket. Multiple addresses can\n" "\t\t\tbe specified by using this argument multiple times.\n" "\t\t\tFor example, '-B 10.0.0.1 -B 20.0.0.2'.\n" " -b, --bindx-rem" "\tremove the specified address(es) from the bind\n" "\t\t\taddresses of the local socket. Multiple addresses can\n" "\t\t\tbe specified by using this argument multiple times.\n" "\t\t\tFor example, '-b 10.0.0.1 -b 20.0.0.2'.\n" " -c, --connectx" "\t\tuse the specified address(es) for connection to the\n" "\t\t\tpeer socket. Multiple addresses can be specified by\n" "\t\t\tusing this argument multiple times.\n" "\t\t\tFor example, '-c 10.0.0.1 -c 20.0.0.2'.\n" "\t\t\tThis option is incompatible with the -h option.\n" " -I\t\t\tuse the interactive mode.\n" " -i\t\t\tsetup the specified number of endpoints by using the\n" "\t\t\tspecified local host (-H) and local port (-P). The port\n" "\t\t\tnumber will be incremented by one for each additional\n" "\t\t\tendpoint. All of these endpoints will be listening.\n" "\t\t\tIf a remote host (-h) and a remote port are also\n" "\t\t\tspecified, the first endpoint will start sending fixed\n" "\t\t\tsized messages to the remote host.\n" " -m\t\t\tspecify the sockopt sndbuf/rcvbuf size.\n" " -n\t\t\tset the socket(s) to be in the non-blocking mode.\n" "\t\t\tcollect messages from stdin and deliver them to the\n" "\t\t\tpeer,\n" "--use-poll\t\tuse system call poll() for polling among the\n" "\t\t\tnumber of endpoints specified by the -i option. Without\n" "\t\t\tthis option, select() would be used as default.\n" " -t\t\t\tuse SOCK_STREAM tcp-style sockets.\n" " -z\t\t\tspecify the message size to be sent. The default\n" "\t\t\tmessage size generated would be 16K.\n" " --interface=\"ifname\"\tselect interface for sin6_scope_id.\n", argv0);}/* This function checks messages to see if they are of type 'event' * and if they are well-formed. */intuser_test_check_message(struct msghdr *msg, int controllen, sctp_cmsg_t event){ if (msg->msg_controllen != controllen) { fprintf(stderr, "Got control structure of length %d, not %d\n", msg->msg_controllen, controllen); exit(1); } if (controllen > 0 && event != CMSG_FIRSTHDR(msg)->cmsg_type) { fprintf(stderr, "Wrong kind of event: %d, not %d\n", CMSG_FIRSTHDR(msg)->cmsg_type, event); exit(1); } return 1;} /* user_test_check_message() *//* Add another address represented as the string 'parm' to the list * addrs. The argument count is the number of addrs on input and is * adjusted for output. */struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs, int *ret_count){ struct sockaddr *new_addrs = NULL; void *aptr; struct sockaddr *sa_addr; struct sockaddr_in *b4ap; struct sockaddr_in6 *b6ap; struct hostent *hst4 = NULL; struct hostent *hst6 = NULL; int i4 = 0; int i6 = 0; int j; int orig_count = *ret_count; int count = orig_count; /* Get the entries for this host. */ hst4 = gethostbyname(parm); hst6 = gethostbyname2(parm, AF_INET6); if ((NULL == hst4 || hst4->h_length < 1) && (NULL == hst6 || hst6->h_length < 1)) { fprintf(stderr, "bad hostname: %s\n", parm); goto finally; } /* Figure out the number of addresses. */ if (NULL != hst4) { for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) { count++; } } if (NULL != hst6) { for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) { count++; } } /* Expand memory for the new addresses. Assume all the addresses * are v6 addresses. */ new_addrs = (struct sockaddr *) realloc(addrs, sizeof(struct sockaddr_in6) * count); if (NULL == new_addrs) { count = *ret_count; goto finally; } /* Skip the existing addresses. */ aptr = new_addrs; for (j = 0; j < orig_count; j++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: aptr += sizeof(struct sockaddr_in); break; case AF_INET6: aptr += sizeof(struct sockaddr_in6); break; default: count = orig_count; goto finally; } } /* Put the new addresses away. */ if (NULL != hst4) { for (j = 0; j < i4; ++j) { b4ap = (struct sockaddr_in *)aptr; bzero(b4ap, sizeof(*b4ap)); b4ap->sin_family = AF_INET; b4ap->sin_port = htons(local_port); bcopy(hst4->h_addr_list[j], &b4ap->sin_addr, hst4->h_length); aptr += sizeof(struct sockaddr_in); } /* for (loop through the new v4 addresses) */ } if (NULL != hst6) { for (j = 0; j < i6; ++j) { b6ap = (struct sockaddr_in6 *)aptr; bzero(b6ap, sizeof(*b6ap)); b6ap->sin6_family = AF_INET6; b6ap->sin6_port = htons(local_port); b6ap->sin6_scope_id = if_index; bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr, hst6->h_length); aptr += sizeof(struct sockaddr_in6); } /* for (loop through the new v6 addresses) */ } finally: *ret_count = count; return new_addrs;} /* append_addr() */static intparse_inter_commands(char *argv0, char *input, int snd_only){ int i; char *p; int len; int set = 0; int val; struct sockaddr *tmp_addrs = NULL; p = input; if (*p == '?' || *p == '\n') { printf("Interactive commands:\n"); printf("snd=<int> - Do a sendmsg with the specified"); printf(" length.\n"); printf("rcv=<int> - Do a recvmsg."); printf("The length is ignored for now.\n"); printf("bindx-add=<addr> - Add a local address"); printf(" with bindx. \n"); printf("bindx-rem=<addr> - Remove a local address"); printf(" with bindx. \n"); printf("rcvbuf=<int> - Get/Set receive buffer size\n"); printf("sndbuf=<int> - Get/Set send buffer size.\n"); printf("primary=<addr> - Get/Set association's primary\n"); printf("peer_primary=addr- Set association's peer_primary\n"); printf("maxseg=<int> - Get/Set Maximum fragment size.\n"); printf("nodelay=<0|1> - Get/Set NODELAY option.\n"); printf("shutdown - Shutdown the association.\n"); printf("abort - Abort the association.\n"); printf("? - Help. Display this message.\n"); return -1; } for (i = 0; i < REALLY_BIG; i++) { if (('=' == *p) || ('?' == *p) || ('\n' == *p)) { if ('=' == *p) { set = 1; } *p++ = '\0'; break; } p++; } if (i >= REALLY_BIG) { printf("Invalid input.\n"); return -1; } i = 0; while (NULL != inter_commands[i].cmd) { if (!strcmp(input, inter_commands[i].cmd)) { switch (i) { case INTER_SND: if (snd_only) { if (*p < '0' || *p > '9') { goto err_input; } snd_func(p); } else { goto err_input; } break; case INTER_RCV: if (snd_only) { goto err_input; } break; case INTER_SNDBUF: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } len = (set) ? atoi(p) : 0; sndbuf_func(argv0, inter_sk, len, set); break; case INTER_RCVBUF: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } len = (set) ? atoi(p) : 0; rcvbuf_func(argv0, inter_sk, len, set); break; case INTER_BINDX_ADD: tmp_addrs = get_bindx_addr(p, &len); bindx_func(argv0, inter_sk, tmp_addrs, len, SCTP_BINDX_ADD_ADDR, local_port); free(tmp_addrs); break; case INTER_BINDX_REM: tmp_addrs = get_bindx_addr(p, &len); bindx_func(argv0, inter_sk, tmp_addrs, len, SCTP_BINDX_REM_ADDR, local_port); free(tmp_addrs); break; case INTER_SET_PRIM: primary_func(argv0, inter_sk, p, set); break; case INTER_SET_PEER_PRIM: peer_primary_func(argv0, inter_sk, p, set); break; case INTER_SHUTDOWN: shutdown_func(argv0, &inter_sk, SHUTDOWN_SHUTDOWN); break; case INTER_ABORT: shutdown_func(argv0, &inter_sk, SHUTDOWN_ABORT); break; case INTER_NODELAY: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } val = (set) ? atoi(p) : 0; nodelay_func(argv0, inter_sk, val, set); break; case INTER_MAXSEG: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } val = (set) ? atoi(p) : 0; maxseg_func(argv0, inter_sk, val, set); break; default: goto err_input; break; } return i; } i++; }err_input: printf("Invalid input.\n"); return -1;} /* parse_inter_commands() */static char *gen_message(int len){ char *buf; char *p; int i; buf = malloc(len); if (NULL != buf) { for (i = 0, p = buf; i < len; i++, p++) { if (gen_data > GEN_DATA_LAST) { gen_data = GEN_DATA_FIRST; } *p = gen_data++; } } return(buf);} /* gen_message() */static voidsnd_func(char *input){ int len; len = atoi(input); if (!(inter_outbuf = gen_message(len))) { fprintf(stderr, "Cannot allocate out message.\n"); exit(1); } inter_outlen = len;} /* snd_func() */static voidsndbuf_func(char *argv0, int sk, int len, int set){ int error; socklen_t optlen; if (set) { error = setsockopt(sk, SOL_SOCKET, SO_SNDBUF, (char *)&len, sizeof(len)); } else { optlen = sizeof(len); error = getsockopt(sk, SOL_SOCKET, SO_SNDBUF, (char *)&len, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting sndbuf: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("sndbuf is %d.\n", len); }} /* sndbuf_func() */static voidrcvbuf_func(char *argv0, int sk, int len, int set){ int error; socklen_t optlen; if (set) { error = setsockopt(sk, SOL_SOCKET, SO_RCVBUF, (char *)&len, sizeof(len)); } else { optlen = sizeof(len); error = getsockopt(sk, SOL_SOCKET, SO_RCVBUF, (char *)&len, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting rcvbuf: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("rcvbuf is %d.\n", len);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -