Blob


1 /* $Id: icbirc.c,v 1.3 2016/04/25 08:17:01 dhartmei Exp $ */
3 /*
4 * Copyright (c) 2023 Omar Polo <op@openbsd.org>
5 * Copyright (c) 2003-2004 Daniel Hartmeier
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * - Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <netdb.h>
46 #include <poll.h>
47 #include <signal.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <time.h>
53 #include <unistd.h>
55 #include "icb.h"
56 #include "irc.h"
58 void icbirc_quit(void);
59 int sync_write(int, const char *, int);
60 static void usage(void);
62 time_t t;
63 unsigned long bytes_in, bytes_out;
65 static void
66 usage(void)
67 {
68 extern char *__progname;
70 fprintf(stderr, "usage: %s host[:port][/room]\n",
71 getprogname());
72 exit(1);
73 }
75 int
76 main(int argc, char *argv[])
77 {
78 struct pollfd pfds[2], *pirc, *picb;
79 struct addrinfo hints, *res, *res0;
80 const char *host, *cause = NULL;
81 char *port, *room;
82 int ch, error, save_errno;
83 int listen_fd = -1, server_fd = -1;
85 #ifdef __OpenBSD__
86 if (pledge("stdio inet dns", NULL) == -1)
87 err(1, "pledge");
88 #endif /* __OpenBSD__ */
90 while ((ch = getopt(argc, argv, "")) != -1) {
91 switch (ch) {
92 default:
93 usage();
94 }
95 }
96 argc -= optind;
97 argv += optind;
99 if (argc != 1)
100 usage();
102 signal(SIGPIPE, SIG_IGN);
103 if (fcntl(0, F_SETFL, fcntl(listen_fd, F_GETFL) | O_NONBLOCK))
104 err(1, "fcntl");
106 if ((port = strchr(argv[0], ':')) != NULL) {
107 *port++ = '\0';
108 if ((room = strchr(port, '/')) != NULL) {
109 *room++ = '\0';
110 strlcpy(irc_pass, room, sizeof(irc_pass));
112 } else if ((room = strchr(argv[0], '/')) != NULL) {
113 *room++ = '\0';
114 strlcpy(irc_pass, room, sizeof(irc_pass));
116 host = argv[0];
117 if (port == NULL)
118 port = "7326";
120 t = time(NULL);
122 irc_send_notice(1, "*** Connecting to server %s:%s", host, port);
124 memset(&hints, 0, sizeof(hints));
125 hints.ai_family = AF_UNSPEC;
126 hints.ai_socktype = SOCK_STREAM;
127 error = getaddrinfo(host, port, &hints, &res0);
128 if (error)
129 errx(1, "can't resolve %s: %s", host, gai_strerror(error));
131 for (res = res0; res; res = res->ai_next) {
132 server_fd = socket(res->ai_family, res->ai_socktype,
133 res->ai_protocol);
134 if (server_fd == -1) {
135 cause = "socket";
136 continue;
139 if (connect(server_fd, res->ai_addr, res->ai_addrlen) == -1) {
140 cause = "connect";
141 save_errno = errno;
142 close(server_fd);
143 errno = save_errno;
144 server_fd = -1;
145 continue;
148 break;
150 freeaddrinfo(res0);
151 if (server_fd == -1)
152 err(1, "%s", cause);
154 if (fcntl(server_fd, F_SETFL, fcntl(server_fd, F_GETFL) | O_NONBLOCK))
155 err(1, "fcntl");
157 #ifdef __OpenBSD__
158 /* drop inet dns */
159 if (pledge("stdio", NULL) == -1)
160 err(1, "pledge");
161 #endif /* __OpenBSD__ */
163 irc_send_notice(1, "*** Connected");
164 icb_init();
166 memset(&pfds, 0, sizeof(pfds));
167 pirc = &pfds[0];
168 picb = &pfds[1];
170 pirc->fd = 0;
171 pirc->events = POLLIN;
173 picb->fd = server_fd;
174 picb->events = POLLIN;
176 for (;;) {
177 char buf[65535];
178 int len;
180 if (poll(pfds, 2, 10000) == -1) {
181 if (errno == EINTR)
182 continue;
183 err(1, "poll");
186 if (picb->revents & (POLLIN|POLLNVAL|POLLHUP)) {
187 len = read(server_fd, buf, sizeof(buf));
188 if (len < 0) {
189 if (errno == EINTR)
190 continue;
191 warnx("read");
192 len = 0;
194 if (len == 0) {
195 warnx("connection closed by server");
196 irc_send_notice(1, "*** Connection "
197 "closed by server");
198 break;
200 icb_recv(buf, len, 1, server_fd);
201 bytes_in += len;
204 if (pirc->revents & (POLLIN|POLLNVAL|POLLHUP)) {
205 len = read(0, buf, sizeof(buf));
206 if (len < 0) {
207 if (errno == EINTR)
208 continue;
209 warnx("read");
210 len = 0;
212 if (len == 0) {
213 warnx("connection closed by client");
214 break;
216 irc_recv(buf, len, 1, server_fd);
217 bytes_out += len;
221 icbirc_quit();
224 void
225 icbirc_quit(void)
227 irc_send_notice(1, "*** Closing connection "
228 "(%u seconds, %lu:%lu bytes)",
229 time(NULL) - t, bytes_out, bytes_in);
230 exit(0);
233 int
234 sync_write(int fd, const char *buf, int len)
236 int off = 0;
238 while (len > off) {
239 fd_set writefds;
240 struct timeval tv;
241 int r;
243 FD_ZERO(&writefds);
244 FD_SET(fd, &writefds);
245 memset(&tv, 0, sizeof(tv));
246 tv.tv_sec = 10;
247 r = select(fd + 1, NULL, &writefds, NULL, &tv);
248 if (r < 0) {
249 if (errno != EINTR) {
250 perror("select");
251 return (1);
253 continue;
255 if (r > 0 && FD_ISSET(fd, &writefds)) {
256 r = write(fd, buf + off, len - off);
257 if (r < 0) {
258 perror("write");
259 return (1);
261 off += r;
264 return (0);