1 /* $OpenBSD: client-tcp.c,v 1.2 2020/01/17 20:45:50 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Alexander Bluhm <bluhm@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 22 #include <err.h> 23 #include <errno.h> 24 #include <netdb.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "util.h" 31 32 void __dead usage(void); 33 int connect_socket(const char *, const char *); 34 35 void __dead 36 usage(void) 37 { 38 fprintf(stderr, "client [-r rcvmsg] [-s sndmsg] host port\n" 39 " -E wait for EOF\n" 40 " -N shutdown write\n" 41 " -r rcvmsg receive from server and check message\n" 42 " -s sndmsg send message to server\n"); 43 exit(2); 44 } 45 46 int 47 main(int argc, char *argv[]) 48 { 49 const char *host, *port; 50 struct task todo[100]; 51 size_t tlen = 0; 52 int ch, s; 53 54 while ((ch = getopt(argc, argv, "ENr:s:")) != -1) { 55 switch (ch) { 56 case 'E': 57 case 'N': 58 case 'r': 59 case 's': 60 if (tlen >= sizeof(todo) / sizeof(todo[0])) 61 errx(1, "too many tasks"); 62 task_enqueue(&todo[tlen], ch, optarg); 63 tlen++; 64 break; 65 default: 66 usage(); 67 } 68 } 69 argc -= optind; 70 argv += optind; 71 72 if (argc == 2) { 73 host = argv[0]; 74 port = argv[1]; 75 } else { 76 usage(); 77 } 78 79 alarm_timeout(); 80 s = connect_socket(host, port); 81 print_sockname(s); 82 print_peername(s); 83 task_run(s, todo, tlen); 84 if (close(s) == -1) 85 err(1, "close"); 86 87 return 0; 88 } 89 90 int 91 connect_socket(const char *host, const char *port) 92 { 93 struct addrinfo hints, *res, *res0; 94 int error; 95 int save_errno; 96 int s; 97 const char *cause = NULL; 98 99 memset(&hints, 0, sizeof(hints)); 100 hints.ai_family = AF_UNSPEC; 101 hints.ai_socktype = SOCK_STREAM; 102 error = getaddrinfo(host, port, &hints, &res0); 103 if (error) 104 errx(1, "%s", gai_strerror(error)); 105 s = -1; 106 for (res = res0; res; res = res->ai_next) { 107 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 108 if (s == -1) { 109 cause = "socket"; 110 continue; 111 } 112 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { 113 cause = "connect"; 114 save_errno = errno; 115 close(s); 116 errno = save_errno; 117 s = -1; 118 continue; 119 } 120 break; /* okay we got one */ 121 } 122 if (s == -1) 123 err(1, "%s", cause); 124 freeaddrinfo(res0); 125 126 return s; 127 } 128