Drop -Werror
[pmc.git] / mudio.c
blob67fed21902b68643bb6df0ba99c75b3006e25aa3
1 #include <string.h>
2 #include <sys/types.h>
3 #include <malloc.h>
4 #include <errno.h>
5 #include <arpa/inet.h>
6 #include <fcntl.h>
7 #include <poll.h>
8 #include <unistd.h>
9 #include <netdb.h>
10 #include <sys/time.h>
12 #include <mudio.h>
13 #include <cbuf.h>
16 mud_conn_t *
17 mud_connect(const char *name,
18 const char *host,
19 int port,
20 size_t in_bufsz, size_t out_bufsz, int fd)
22 mud_conn_t *mud;
23 struct sockaddr_in sin;
24 struct addrinfo *ai;
25 struct addrinfo ai_hint;
26 int ret, esv;
28 memset(&ai_hint, 0, sizeof(ai_hint));
30 errno = ENOMEM;
31 mud = malloc (sizeof(*mud));
32 if (!mud)
33 return NULL;
34 memset(mud, 0, sizeof(*mud));
35 mud->input_buffer = malloc(in_bufsz);
36 mud->output_buffer = malloc(out_bufsz);
37 if (!mud->input_buffer || !mud->output_buffer) {
38 goto out_free;
41 mud->input_buffer = cb_init(mud->input_buffer, in_bufsz, NULL);
42 mud->output_buffer = cb_init(mud->output_buffer, out_bufsz, NULL);
43 mud->name = strdup(name);
44 mud->host = strdup(host);
45 mud->port = port;
46 mud->flags = FL_ECHO;
48 mud->sockfd = fd;
50 if (fd < 0) {
51 mud->sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
52 if (mud->sockfd < 0) {
53 fprintf(stderr, "socket: %s\n", strerror(errno));
54 goto out_free;
57 memset(&ai_hint,0, sizeof(ai_hint));
58 ai_hint.ai_family = PF_INET;
59 ret = getaddrinfo(host, NULL, &ai_hint, &ai);
60 if (ret != 0) {
61 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
62 goto out_free;
65 memcpy(&sin, ai->ai_addr, sizeof(sin));
66 sin.sin_family = PF_INET;
67 sin.sin_port = htons(port);
69 freeaddrinfo(ai);
71 if (connect(mud->sockfd, (struct sockaddr *)&sin,
72 (socklen_t)(sizeof(sin))) < 0) {
73 fprintf(stderr, "connect: %s\n", strerror(errno));
74 goto out_free;
78 return mud;
80 out_free:
81 esv = errno;
82 if (mud->sockfd >= 0)
83 close(mud->sockfd);
84 free(mud->name);
85 free(mud->host);
86 cb_free(mud->input_buffer);
87 cb_free(mud->output_buffer);
88 free(mud);
89 errno = esv;
90 return NULL;
94 mud_conn_t *
95 mud_create(const char *name,
96 const char *host,
97 int port,
98 size_t in_bufsz, size_t out_bufsz)
100 return mud_connect(name, host, port, in_bufsz, out_bufsz, -1);
104 #if 0
105 void
106 do_telnet_req(mud_conn_t *mud, buf[x]);
108 case ''
113 telnet_scan_buf(mud_conn_t *mud, char *buf, size_t len, size_t curr)
115 int x;
116 int needed = 0;
117 int in_code = 0;
118 int req = 0;
120 retry:
121 for (x = 0; x < curr; x++) {
122 if (needed)
123 needed--;
125 if (req && in_code == 2) {
126 do_req(mud, req, buf[x]);
129 switch(buf[x]) {
130 case TN_ESCAPE:
131 if (in_code) {
132 in_code = 0;
133 /* output 0xff */
134 } else {
135 in_code = 1;
136 needed = 1;
138 break;
139 case TN_DO:
140 case TN_DONT:
141 case TN_WILL:
142 case TN_WONT:
143 if (in_code) {
144 req = buf[x];
145 in_code = 2;
146 needed = 1;
148 break;
154 #endif
156 static int
157 delta_est(struct timeval *old, struct timeval *now)
159 struct timeval tv;
161 if (now->tv_usec > old->tv_usec) {
162 old->tv_usec += 1000000;
163 old->tv_sec--;
165 tv.tv_sec = now->tv_sec - old->tv_sec;
166 tv.tv_usec = now->tv_usec - old->tv_usec;
168 return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
172 static void
173 est_rtt(mud_conn_t *mud, struct timeval *prev, struct timeval *now)
175 int x, total = 0;
176 mud->rtt_hist[mud->rtt_idx] = delta_est(prev, now);
177 mud->rtt_idx++;
178 if (mud->rtt_idx >= RTT_HIST_LEN)
179 mud->rtt_idx = 0;
181 for (x = 0; x < RTT_HIST_LEN; x++) {
182 if (mud->rtt_hist[x] == 0)
183 break;
184 total += mud->rtt_hist[x];
187 mud->rtt = (total / x);
192 mud_io(mud_conn_t *mud)
194 char buf[4096]; // XXX _sysconf(_SC_PAGESIZE)
195 struct pollfd fd;
196 int ret, total = 0, timeout = 0, written = 0;
197 struct timeval tv;
199 if (mud->sockfd < 0)
200 goto out_conn;
202 memset(&fd, 0, sizeof(fd));
203 fd.fd = mud->sockfd;
204 fd.events = POLLIN | POLLERR | POLLHUP;
206 if (cb_length(mud->output_buffer))
207 fd.events |= POLLOUT;
209 switch (poll(&fd, 1, timeout)) {
210 case -1:
211 return -1;
212 case 0:
213 return 0;
214 default:
215 break;
218 if (fd.revents & (POLLERR|POLLHUP)) {
219 goto out_conn;
222 if ((fd.revents & POLLOUT) && cb_length(mud->output_buffer)) {
223 written = write(mud->sockfd,
224 mud->output_buffer,
225 cb_length(mud->output_buffer));
226 if (written > 0) {
227 gettimeofday(&mud->last_send, NULL);
228 cb_discard(mud->output_buffer, (size_t)written);
232 if (!(fd.revents & POLLIN))
233 return 0;
235 do {
236 ret = read(mud->sockfd,
237 buf, sizeof(buf));
238 if (ret < 0) {
239 if (errno == EINTR)
240 return 0;
241 else {
242 goto out_conn;
246 //telnet_scan_buf(mud, buf, sizeof(buf), ret);
248 if (ret > 0) {
249 if (!written && mud->last_send.tv_sec) {
250 gettimeofday(&tv, NULL);
251 est_rtt(mud, &mud->last_send, &tv);
252 mud->last_send.tv_sec = 0;
254 cb_append(mud->input_buffer, buf, ret);
257 total += ret;
258 if (total == 0 && ret == 0)
259 /* went high but no data? lost conn (only on some systems) */
260 goto out_conn;
261 } while (ret == sizeof(buf));
263 return total;
265 out_conn:
266 if (mud->sockfd >= 0)
267 close(mud->sockfd);
268 errno = ECONNRESET;
269 cb_strcat(mud->input_buffer, "\n\nNO CARRIER\n");
270 mud->sockfd = -1;
271 return -1;