Blob


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