int main(int argc, char **argv) { int opt; int flag_description = 0; const char *address; opt = getopt(argc, argv, "d"); if (opt == 'd') { argc--; argv++; flag_description = 1; } else if (opt != -1) { printf("\nUNKNOWN OPTION: -%c.\n\n", opt); print_syntax(); return 1; } address = (argc == 1) ? NULL : argv[1]; print_addr_info(address, flag_description); printf("\n"); return 0; }
static int deal(int fd, fd_set *socket_fd_set) { int client_socket_fd; struct sockaddr_in client_address; int client_addr_len; if (socket_fd_set == NULL) return 0; if (fd == socket_fd) { client_addr_len = sizeof(client_address); client_socket_fd = accept(socket_fd, (struct sockaddr*)&client_address, (socklen_t*)&client_addr_len); if (client_socket_fd != -1) { FD_SET(client_socket_fd, socket_fd_set); #ifdef DEBUG printf("A client connect.\n"); print_addr_info(client_address); #endif } } else { if (!echo(fd)) { close(fd); FD_CLR(fd, socket_fd_set); #ifdef DEBUG printf("A client disconnect.\n"); #endif } } return 1; }
int main(int argc, char **argv) { int opt, sock, newsock, result, flags, if_index = 0, on = 1; socklen_t sinlen, opt_len; struct sockaddr_storage sin; struct addrinfo hints, *res; struct sctp_sndrcvinfo sinfo; struct pollfd poll_fd; char getsockopt_peerlabel[1024]; char byte, *peerlabel, msglabel[1024], if_name[30]; bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; char *context, *host_addr = NULL, *bindx_addr = NULL; struct sockaddr_in ipv4_addr; unsigned short port; while ((opt = getopt(argc, argv, "4b:h:inv")) != -1) { switch (opt) { case '4': ipv4 = true; break; case 'b': bindx_addr = optarg; break; case 'h': host_addr = optarg; break; case 'i': snd_opt = true; break; case 'n': nopeer = true; break; case 'v': verbose = true; break; default: usage(argv[0]); } } if ((argc - optind) != 2) usage(argv[0]); port = atoi(argv[optind + 1]); if (!port) usage(argv[0]); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_protocol = IPPROTO_SCTP; if (ipv4) hints.ai_family = AF_INET; else hints.ai_family = AF_INET6; if (!strcmp(argv[optind], "stream")) hints.ai_socktype = SOCK_STREAM; else if (!strcmp(argv[optind], "seq")) hints.ai_socktype = SOCK_SEQPACKET; else usage(argv[0]); if (verbose) { if (getcon(&context) < 0) context = strdup("unavailable"); printf("Server process context: %s\n", context); free(context); } if (host_addr) { char *ptr; ptr = strpbrk(host_addr, "%"); if (ptr) strcpy(if_name, ptr + 1); if_index = if_nametoindex(if_name); if (!if_index) { perror("Server if_nametoindex"); exit(1); } result = getaddrinfo(host_addr, argv[optind + 1], &hints, &res); } else { result = getaddrinfo(NULL, argv[optind + 1], &hints, &res); } if (result < 0) { fprintf(stderr, "Server getaddrinfo: %s\n", gai_strerror(result)); exit(1); } sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) { perror("Server socket"); exit(1); } result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (result < 0) { perror("Server setsockopt: SO_REUSEADDR"); close(sock); exit(1); } /* Enables sctp_data_io_events for sctp_recvmsg(3) for assoc_id. */ result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on, sizeof(on)); if (result < 0) { perror("Server setsockopt: SCTP_EVENTS"); close(sock); exit(1); } if (bindx_addr) { memset(&ipv4_addr, 0, sizeof(struct sockaddr_in)); ipv4_addr.sin_family = AF_INET; ipv4_addr.sin_port = htons(port); ipv4_addr.sin_addr.s_addr = inet_addr(bindx_addr); result = sctp_bindx(sock, (struct sockaddr *)&ipv4_addr, 1, SCTP_BINDX_ADD_ADDR); if (result < 0) { perror("Server sctp_bindx ADD - ipv4"); close(sock); exit(1); } } else { result = bind(sock, res->ai_addr, res->ai_addrlen); if (result < 0) { perror("Server bind"); close(sock); exit(1); } } if (verbose) { print_context(sock, "Server LISTEN"); print_ip_option(sock, ipv4, "Server LISTEN"); } if (listen(sock, SOMAXCONN)) { perror("Server listen"); close(sock); exit(1); } if (hints.ai_socktype == SOCK_STREAM) { if (verbose) print_context(sock, "Server STREAM"); do { socklen_t labellen = sizeof(getsockopt_peerlabel); sinlen = sizeof(sin); newsock = accept(sock, (struct sockaddr *)&sin, &sinlen); if (newsock < 0) { perror("Server accept"); close(sock); exit(1); } if (verbose) { print_context(newsock, "Server STREAM accept on newsock"); print_addr_info((struct sockaddr *)&sin, "Server connected to Client"); print_ip_option(newsock, ipv4, "Server STREAM accept on newsock"); } if (nopeer) { peerlabel = strdup("nopeer"); } else if (snd_opt) { peerlabel = get_ip_option(newsock, ipv4, &opt_len); if (!peerlabel) peerlabel = strdup("no_ip_options"); } else { result = getpeercon(newsock, &peerlabel); if (result < 0) { perror("Server getpeercon"); close(sock); close(newsock); exit(1); } /* Also test the getsockopt version */ result = getsockopt(newsock, SOL_SOCKET, SO_PEERSEC, getsockopt_peerlabel, &labellen); if (result < 0) { perror("Server getsockopt: SO_PEERSEC"); close(sock); close(newsock); exit(1); } if (verbose) printf("Server STREAM SO_PEERSEC peer label: %s\n", getsockopt_peerlabel); } printf("Server STREAM %s: %s\n", snd_opt ? "sock_opt" : "peer label", peerlabel); result = read(newsock, &byte, 1); if (result < 0) { perror("Server read"); close(sock); close(newsock); exit(1); } result = write(newsock, peerlabel, strlen(peerlabel)); if (result < 0) { perror("Server write"); close(sock); close(newsock); exit(1); } if (verbose) printf("Server STREAM sent: %s\n", peerlabel); free(peerlabel); /* Let the client close the connection first as this * will stop OOTB chunks if newsock closed early. */ poll_fd.fd = newsock; poll_fd.events = POLLRDHUP; poll_fd.revents = 1; result = poll(&poll_fd, 1, 1000); if (verbose && result == 1) printf("Server STREAM: Client closed connection\n"); else if (verbose && result == 0) printf("Server: poll(2) timed out - OKAY\n"); else if (result < 0) perror("Server - poll"); close(newsock); } while (1); } else { /* hints.ai_socktype == SOCK_SEQPACKET */ if (verbose) print_context(sock, "Server SEQPACKET sock"); do { sinlen = sizeof(sin); result = sctp_recvmsg(sock, msglabel, sizeof(msglabel), (struct sockaddr *)&sin, &sinlen, &sinfo, &flags); if (result < 0) { perror("Server sctp_recvmsg"); close(sock); exit(1); } if (verbose) { print_context(sock, "Server SEQPACKET recvmsg"); print_addr_info((struct sockaddr *)&sin, "Server SEQPACKET recvmsg"); print_ip_option(sock, ipv4, "Server SEQPACKET recvmsg"); } if (nopeer) { peerlabel = strdup("nopeer"); } else if (snd_opt) { peerlabel = get_ip_option(sock, ipv4, &opt_len); if (!peerlabel) peerlabel = strdup("no_ip_options"); } else { result = getpeercon(sock, &peerlabel); if (result < 0) { perror("Server getpeercon"); close(sock); exit(1); } } printf("Server SEQPACKET %s: %s\n", snd_opt ? "sock_opt" : "peer label", peerlabel); if (sin.ss_family == AF_INET6 && host_addr) ((struct sockaddr_in6 *)&sin)->sin6_scope_id = if_index; result = sctp_sendmsg(sock, peerlabel, strlen(peerlabel), (struct sockaddr *)&sin, sinlen, 0, 0, 0, 0, 0); if (result < 0) { perror("Server sctp_sendmsg"); close(sock); exit(1); } if (verbose) printf("Server SEQPACKET sent: %s\n", peerlabel); free(peerlabel); } while (1); } close(sock); exit(0); }