1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2008-2020 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* NetIO API tests. */
26 
27 #include "tests.h"
28 
29 /* See RFC 854 for the definition of these Telnet values */
30 
31 /* Telnet "Interpret As Command" indicator */
32 #define TELNET_IAC     255
33 #define TELNET_DONT    254
34 #define TELNET_DO      253
35 #define TELNET_WONT    252
36 #define TELNET_WILL    251
37 #define TELNET_IP      244
38 #define TELNET_DM      242
39 
40 static pool *p = NULL;
41 static int xfer_bufsz = -1;
42 
43 static int tmp_fd = -1;
44 static const char *tmp_path = NULL;
45 
test_cleanup(void)46 static void test_cleanup(void) {
47   (void) close(tmp_fd);
48   tmp_fd = -1;
49 
50   if (tmp_path != NULL) {
51     (void) unlink(tmp_path);
52     tmp_path = NULL;
53   }
54 
55   pr_unregister_netio(PR_NETIO_STRM_CTRL|PR_NETIO_STRM_DATA|PR_NETIO_STRM_OTHR);
56 }
57 
open_tmpfile(void)58 static int open_tmpfile(void) {
59   int fd;
60 
61   if (tmp_path != NULL) {
62     test_cleanup();
63   }
64 
65   tmp_path = "/tmp/netio-test.dat";
66   fd = open(tmp_path, O_RDWR|O_CREAT, 0666);
67   fail_unless(fd >= 0, "Failed to open '%s': %s", tmp_path, strerror(errno));
68   tmp_fd = fd;
69 
70   return fd;
71 }
72 
set_up(void)73 static void set_up(void) {
74   if (p == NULL) {
75     p = permanent_pool = make_sub_pool(NULL);
76   }
77 
78   init_netio();
79   xfer_bufsz = pr_config_get_server_xfer_bufsz(PR_NETIO_IO_RD);
80 
81   if (getenv("TEST_VERBOSE") != NULL) {
82     pr_trace_set_levels("netio", 1, 20);
83   }
84 }
85 
tear_down(void)86 static void tear_down(void) {
87   if (getenv("TEST_VERBOSE") != NULL) {
88     pr_trace_set_levels("netio", 0, 0);
89   }
90 
91   test_cleanup();
92 
93   if (p) {
94     destroy_pool(p);
95     p = permanent_pool = NULL;
96   }
97 }
98 
99 /* Tests */
100 
START_TEST(netio_open_test)101 START_TEST (netio_open_test) {
102   pr_netio_stream_t *nstrm;
103   int fd = -1;
104 
105   nstrm = pr_netio_open(NULL, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
106   fail_unless(nstrm == NULL, "Failed to handle null pool argument");
107   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
108     strerror(errno), errno);
109 
110   nstrm = pr_netio_open(p, 7777, fd, PR_NETIO_IO_RD);
111   fail_unless(nstrm == NULL, "Failed to handle unknown stream type argument");
112   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
113     strerror(errno), errno);
114 
115   /* open/close CTRL stream */
116   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
117   fail_unless(nstrm != NULL, "Failed to open ctrl stream on fd %d: %s", fd,
118     strerror(errno));
119   fail_unless(nstrm->strm_netio != NULL,
120     "Failed to assign owning NetIO to stream");
121   pr_netio_close(nstrm);
122 
123   /* open/close DATA stream */
124   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_WR);
125   fail_unless(nstrm != NULL, "Failed to open data stream on fd %d: %s", fd,
126     strerror(errno));
127   fail_unless(nstrm->strm_netio != NULL,
128     "Failed to assign owning NetIO to stream");
129   pr_netio_close(nstrm);
130 
131   /* open/close OTHR stream */
132   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_WR);
133   fail_unless(nstrm != NULL, "Failed to open othr stream on fd %d: %s", fd,
134     strerror(errno));
135   fail_unless(nstrm->strm_netio != NULL,
136     "Failed to assign owning NetIO to stream");
137   pr_netio_close(nstrm);
138 }
139 END_TEST
140 
START_TEST(netio_postopen_test)141 START_TEST (netio_postopen_test) {
142   pr_netio_stream_t *nstrm;
143   int fd = -1, res;
144 
145   res = pr_netio_postopen(NULL);
146   fail_unless(res < 0, "Failed to handle null argument");
147   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
148     strerror(errno), errno);
149 
150   /* open/postopen/close CTRL stream */
151   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
152   fail_unless(nstrm != NULL, "Failed to open stream on fd %d: %s", fd,
153     strerror(errno));
154 
155   res = pr_netio_postopen(nstrm);
156   fail_unless(res == 0, "Failed to post-open ctrl stream: %s", strerror(errno));
157   (void) pr_netio_close(nstrm);
158 
159   /* open/postopen/close DATA stream */
160   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
161   fail_unless(nstrm != NULL, "Failed to open stream on fd %d: %s", fd,
162     strerror(errno));
163 
164   res = pr_netio_postopen(nstrm);
165   fail_unless(res == 0, "Failed to post-open data stream: %s", strerror(errno));
166   (void) pr_netio_close(nstrm);
167 
168   /* open/postopen/close OTHR stream */
169   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
170   fail_unless(nstrm != NULL, "Failed to open stream on fd %d: %s", fd,
171     strerror(errno));
172 
173   res = pr_netio_postopen(nstrm);
174   fail_unless(res == 0, "Failed to post-open othr stream: %s", strerror(errno));
175   (void) pr_netio_close(nstrm);
176 }
177 END_TEST
178 
START_TEST(netio_close_test)179 START_TEST (netio_close_test) {
180   pr_netio_stream_t *nstrm;
181   int res, fd = -1;
182 
183   res = pr_netio_close(NULL);
184   fail_unless(res == -1, "Failed to handle null stream argument");
185   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
186     strerror(errno), errno);
187 
188   /* Open/close CTRL stream */
189   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
190   nstrm->strm_type = 7777;
191 
192   res = pr_netio_close(nstrm);
193   fail_unless(res == -1, "Failed to handle unknown stream type argument");
194   fail_unless(errno == EPERM, "Failed to set errno to EPERM, got %s (%d)",
195     strerror(errno), errno);
196 
197   nstrm->strm_type = PR_NETIO_STRM_CTRL;
198   res = pr_netio_close(nstrm);
199   fail_unless(res == -1, "Failed to handle bad file descriptor");
200   fail_unless(errno == EBADF, "Failed to set errno to EBADF, got %s (%d)",
201     strerror(errno), errno);
202 
203   /* Open/close DATA stream */
204   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
205   res = pr_netio_close(nstrm);
206   fail_unless(res == -1, "Failed to handle bad file descriptor");
207   fail_unless(errno == EBADF, "Failed to set errno to EBADF, got %s (%d)",
208     strerror(errno), errno);
209 
210   /* Open/close OTHR stream */
211   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
212   res = pr_netio_close(nstrm);
213   fail_unless(res == -1, "Failed to handle bad file descriptor");
214   fail_unless(errno == EBADF, "Failed to set errno to EBADF, got %s (%d)",
215     strerror(errno), errno);
216 }
217 END_TEST
218 
START_TEST(netio_lingering_close_test)219 START_TEST (netio_lingering_close_test) {
220   pr_netio_stream_t *nstrm;
221   int res, fd = -1;
222   long linger = 0L;
223 
224   res = pr_netio_lingering_close(NULL, linger);
225   fail_unless(res == -1, "Failed to handle null stream argument");
226   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
227     strerror(errno), errno);
228 
229   /* Open/close CTRL stream */
230   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
231   nstrm->strm_type = 7777;
232 
233   res = pr_netio_lingering_close(nstrm, linger);
234   fail_unless(res < 0, "Failed to handle unknown stream type argument");
235   fail_unless(errno == EPERM, "Failed to set errno to EPERM, got %s (%d)",
236     strerror(errno), errno);
237 
238   nstrm->strm_type = PR_NETIO_STRM_CTRL;
239   res = pr_netio_lingering_close(nstrm, linger);
240   fail_unless(res == 0, "Failed to close stream: %s", strerror(errno));
241 
242   /* Open/close DATA stream */
243   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
244   res = pr_netio_lingering_close(nstrm, linger);
245   fail_unless(res == 0, "Failed to close stream: %s", strerror(errno));
246 
247   /* Open/close OTHR stream */
248   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
249   res = pr_netio_lingering_close(nstrm, linger);
250   fail_unless(res == 0, "Failed to close stream: %s", strerror(errno));
251 }
252 END_TEST
253 
START_TEST(netio_reopen_test)254 START_TEST (netio_reopen_test) {
255   pr_netio_stream_t *nstrm, *nstrm2;
256   int res, fd = -1;
257 
258   nstrm2 = pr_netio_reopen(NULL, fd, PR_NETIO_IO_RD);
259   fail_unless(nstrm2 == NULL, "Failed to handle null stream argument");
260   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
261     strerror(errno), errno);
262 
263   /* Open/reopen/close CTRL stream */
264   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
265   nstrm->strm_type = 7777;
266 
267   nstrm2 = pr_netio_reopen(nstrm, fd, PR_NETIO_IO_RD);
268   fail_unless(nstrm2 == NULL, "Failed to handle unknown stream type argument");
269   fail_unless(errno == EPERM, "Failed to set errno to EPERM, got %s (%d)",
270     strerror(errno), errno);
271 
272   nstrm->strm_type = PR_NETIO_STRM_CTRL;
273   nstrm2 = pr_netio_reopen(nstrm, fd, PR_NETIO_IO_RD);
274   fail_unless(nstrm2 != NULL, "Failed to reopen ctrl stream: %s",
275     strerror(errno));
276 
277   /* Open/reopen/close DATA stream */
278   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
279   nstrm2 = pr_netio_reopen(nstrm, fd, PR_NETIO_IO_RD);
280   fail_unless(nstrm2 != NULL, "Failed to reopen data stream: %s",
281     strerror(errno));
282 
283   res = pr_netio_close(nstrm);
284   fail_unless(res == -1, "Failed to handle bad file descriptor");
285   fail_unless(errno == EBADF, "Failed to set errno to EBADF, got %s (%d)",
286     strerror(errno), errno);
287 
288   /* Open/reopen/close OTHR stream */
289   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
290   nstrm2 = pr_netio_reopen(nstrm, fd, PR_NETIO_IO_RD);
291   fail_unless(nstrm2 != NULL, "Failed to reopen othr stream: %s",
292     strerror(errno));
293 
294   res = pr_netio_close(nstrm);
295   fail_unless(res == -1, "Failed to handle bad file descriptor");
296   fail_unless(errno == EBADF, "Failed to set errno to EBADF, got %s (%d)",
297     strerror(errno), errno);
298 }
299 END_TEST
300 
START_TEST(netio_buffer_alloc_test)301 START_TEST (netio_buffer_alloc_test) {
302   pr_buffer_t *pbuf;
303   pr_netio_stream_t *nstrm;
304 
305   pbuf = pr_netio_buffer_alloc(NULL);
306   fail_unless(pbuf == NULL, "Failed to handle null arguments");
307   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
308     strerror(errno), errno);
309 
310   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
311 
312   pbuf = pr_netio_buffer_alloc(nstrm);
313   fail_unless(pbuf != NULL, "Failed to allocate buffer: %s", strerror(errno));
314 
315   pr_netio_close(nstrm);
316 }
317 END_TEST
318 
START_TEST(netio_telnet_gets_args_test)319 START_TEST (netio_telnet_gets_args_test) {
320   char *buf, *res;
321   pr_netio_stream_t *in, *out;
322 
323   res = pr_netio_telnet_gets(NULL, 0, NULL, NULL);
324   fail_unless(res == NULL, "Failed to handle null arguments");
325   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
326     strerror(errno), errno);
327 
328   buf = "";
329   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
330   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
331 
332   res = pr_netio_telnet_gets(buf, 0, in, out);
333   fail_unless(res == NULL,
334     "Failed to handle zero-length buffer length argument");
335   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
336     strerror(errno), errno);
337 
338   res = pr_netio_telnet_gets(buf, 1, NULL, out);
339   fail_unless(res == NULL, "Failed to handle null input stream argument");
340   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
341     strerror(errno), errno);
342 
343   res = pr_netio_telnet_gets(buf, 1, in, NULL);
344   fail_unless(res == NULL, "Failed to handle null output stream argument");
345   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL, got %s (%d)",
346     strerror(errno), errno);
347 
348   pr_netio_close(in);
349   pr_netio_close(out);
350 }
351 END_TEST
352 
START_TEST(netio_telnet_gets_single_line_test)353 START_TEST (netio_telnet_gets_single_line_test) {
354   char buf[256], *cmd, *res;
355   pr_netio_stream_t *in, *out;
356   pr_buffer_t *pbuf;
357   int len, xerrno;
358 
359   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
360   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
361 
362   cmd = "Hello, World!\n";
363 
364   pr_netio_buffer_alloc(in);
365   pbuf = in->strm_buf;
366   len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", cmd);
367   pbuf->remaining = pbuf->buflen - len;
368   pbuf->current = pbuf->buf;
369 
370   buf[sizeof(buf)-1] = '\0';
371 
372   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
373   xerrno = errno;
374 
375   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
376     xerrno, strerror(xerrno));
377   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
378     buf);
379   fail_unless(pbuf->remaining == (size_t) xfer_bufsz,
380     "Expected %d remaining bytes, got %lu", xfer_bufsz,
381     (unsigned long) pbuf->remaining);
382 
383   pr_netio_close(in);
384   pr_netio_close(out);
385 }
386 END_TEST
387 
START_TEST(netio_telnet_gets_multi_line_test)388 START_TEST (netio_telnet_gets_multi_line_test) {
389   char buf[256], *cmd, *first_cmd, *second_cmd, *res;
390   pr_netio_stream_t *in, *out;
391   pr_buffer_t *pbuf;
392   int len, xerrno;
393 
394   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
395   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
396 
397   /* Note: the line terminator in Telnet is CRLF, not just a bare LF. */
398   cmd = "Hello, World!\r\nHow are you?\r\n";
399   first_cmd = "Hello, World!\n";
400   second_cmd = "How are you?\n";
401 
402   pr_netio_buffer_alloc(in);
403   pbuf = in->strm_buf;
404   len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", cmd);
405   pbuf->remaining = pbuf->buflen - len;
406   pbuf->current = pbuf->buf;
407 
408   buf[sizeof(buf)-1] = '\0';
409 
410   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
411   xerrno = errno;
412 
413   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
414     xerrno, strerror(xerrno));
415   fail_unless(strcmp(buf, first_cmd) == 0, "Expected string '%s', got '%s'",
416     first_cmd, buf);
417 
418   memset(buf, '\0', sizeof(buf));
419   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
420   xerrno = errno;
421 
422   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
423     xerrno, strerror(xerrno));
424   fail_unless(strcmp(buf, second_cmd) == 0, "Expected string '%s', got '%s'",
425     second_cmd, buf);
426 
427   fail_unless(pbuf->remaining == (size_t) xfer_bufsz,
428     "Expected %d remaining bytes, got %lu", xfer_bufsz,
429     (unsigned long) pbuf->remaining);
430 
431   pr_netio_close(in);
432   pr_netio_close(out);
433 }
434 END_TEST
435 
START_TEST(netio_telnet_gets_no_newline_test)436 START_TEST (netio_telnet_gets_no_newline_test) {
437   char buf[8], *cmd, *res;
438   pr_netio_stream_t *in, *out;
439   pr_buffer_t *pbuf;
440   int len, xerrno;
441 
442   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
443   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
444 
445   cmd = "Hello, World!";
446 
447   pr_netio_buffer_alloc(in);
448   pbuf = in->strm_buf;
449   len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", cmd);
450   pbuf->remaining = pbuf->buflen - len;
451   pbuf->current = pbuf->buf;
452 
453   buf[sizeof(buf)-1] = '\0';
454 
455   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
456   xerrno = errno;
457 
458   fail_unless(res == NULL, "Read in string unexpectedly, got '%s'", buf);
459   fail_unless(xerrno == E2BIG, "Failed to set errno to E2BIG, got (%d) %s",
460     xerrno, strerror(xerrno));
461 
462   pr_netio_close(in);
463   pr_netio_close(out);
464 }
465 END_TEST
466 
START_TEST(netio_telnet_gets_telnet_will_test)467 START_TEST (netio_telnet_gets_telnet_will_test) {
468   char buf[256], *cmd, *res, telnet_opt;
469   pr_netio_stream_t *in, *out;
470   pr_buffer_t *pbuf;
471   int len, out_fd, xerrno;
472 
473   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
474 
475   out_fd = open_tmpfile();
476   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, out_fd, PR_NETIO_IO_WR);
477 
478   cmd = "Hello, World!\n";
479 
480   pr_netio_buffer_alloc(in);
481   pbuf = in->strm_buf;
482 
483   telnet_opt = 7;
484   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c%cWorld!\n", TELNET_IAC,
485     TELNET_WILL, telnet_opt);
486   pbuf->remaining = pbuf->buflen - len;
487   pbuf->current = pbuf->buf;
488 
489   buf[sizeof(buf)-1] = '\0';
490 
491   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
492   xerrno = errno;
493 
494   pr_netio_close(in);
495 
496   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
497     xerrno, strerror(xerrno));
498   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
499     buf);
500 
501   /* Rewind the output stream fd. */
502   lseek(out_fd, 0, SEEK_SET);
503   len = read(out_fd, buf, sizeof(buf)-1);
504   pr_netio_close(out);
505 
506   fail_unless(len == 3, "Expected to read 3 bytes from output stream, got %d",
507     len);
508   fail_unless(buf[0] == (char) TELNET_IAC, "Expected IAC at index 0, got %d",
509     buf[0]);
510   fail_unless(buf[1] == (char) TELNET_DONT, "Expected DONT at index 1, got %d",
511     buf[1]);
512   fail_unless(buf[2] == telnet_opt, "Expected opt '%c' at index 2, got %c",
513     telnet_opt, buf[2]);
514 
515   test_cleanup();
516 }
517 END_TEST
518 
START_TEST(netio_telnet_gets_telnet_bare_will_test)519 START_TEST (netio_telnet_gets_telnet_bare_will_test) {
520   char buf[256], *cmd, *res, telnet_opt;
521   pr_netio_stream_t *in, *out;
522   pr_buffer_t *pbuf;
523   int len, xerrno;
524 
525   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
526   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
527 
528   cmd = "Hello, World!\n";
529 
530   pr_netio_buffer_alloc(in);
531   pbuf = in->strm_buf;
532 
533   telnet_opt = 7;
534   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_WILL,
535     telnet_opt);
536   pbuf->remaining = pbuf->buflen - len;
537   pbuf->current = pbuf->buf;
538 
539   buf[sizeof(buf)-1] = '\0';
540 
541   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
542   xerrno = errno;
543 
544   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
545     xerrno, strerror(xerrno));
546   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
547     7, cmd, 7, buf);
548   fail_unless(buf[7] == (char) TELNET_WILL, "Expected WILL at index 7, got %d",
549     buf[7]);
550   fail_unless(buf[8] == telnet_opt, "Expected Telnet opt %c at index 8, got %d",
551     telnet_opt, buf[8]);
552   fail_unless(strcmp(buf + 9, cmd + 7) == 0, "Expected string '%s', got '%s'",
553     cmd + 7, buf + 9);
554 
555   pr_netio_close(in);
556   pr_netio_close(out);
557 }
558 END_TEST
559 
START_TEST(netio_telnet_gets_telnet_will_multi_read_test)560 START_TEST (netio_telnet_gets_telnet_will_multi_read_test) {
561   char buf[256], *cmd, *res, telnet_opt;
562   pr_netio_stream_t *in, *out;
563   pr_buffer_t *pbuf;
564   int len, out_fd, xerrno;
565 
566   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
567 
568   out_fd = open_tmpfile();
569   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, out_fd, PR_NETIO_IO_WR);
570 
571   cmd = "Hello, World!\n";
572 
573   pr_netio_buffer_alloc(in);
574   pbuf = in->strm_buf;
575 
576   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c", TELNET_IAC,
577     TELNET_WILL);
578   pbuf->remaining = pbuf->buflen - len;
579   pbuf->current = pbuf->buf;
580 
581   buf[sizeof(buf)-1] = '\0';
582 
583   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
584   xerrno = errno;
585 
586   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
587     xerrno, strerror(xerrno));
588   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
589     7, cmd, 7, buf);
590 
591   /* Fill up the input stream's buffer with the rest of the Telnet WILL
592    * sequence.
593    */
594   telnet_opt = 7;
595   len = snprintf(pbuf->buf, pbuf->buflen-1, "%cWorld!\n", telnet_opt);
596   pbuf->remaining = pbuf->buflen - len;
597   pbuf->current = pbuf->buf;
598 
599   /* Read again, to see if the state was preserved across multiple calls
600    * to pr_netio_telnet_gets().
601    */
602   res = pr_netio_telnet_gets(buf + 7, sizeof(buf)-8, in, out);
603   xerrno = errno;
604 
605   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
606     xerrno, strerror(xerrno));
607   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'",
608     cmd, buf);
609 
610   pr_netio_close(in);
611 
612   /* Rewind the output stream fd. */
613   lseek(out_fd, 0, SEEK_SET);
614   len = read(out_fd, buf, sizeof(buf)-1);
615   pr_netio_close(out);
616 
617   fail_unless(len == 3, "Expected to read 3 bytes from output stream, got %d",
618     len);
619   fail_unless(buf[0] == (char) TELNET_IAC, "Expected IAC at index 0, got %d",
620     buf[0]);
621   fail_unless(buf[1] == (char) TELNET_DONT, "Expected DONT at index 1, got %d",
622     buf[1]);
623   fail_unless(buf[2] == telnet_opt, "Expected %c at index 2, got %d",
624     telnet_opt, buf[2]);
625 
626   test_cleanup();
627 }
628 END_TEST
629 
START_TEST(netio_telnet_gets_telnet_wont_test)630 START_TEST (netio_telnet_gets_telnet_wont_test) {
631   char buf[256], *cmd, *res, telnet_opt;
632   pr_netio_stream_t *in, *out;
633   pr_buffer_t *pbuf;
634   int len, out_fd, xerrno;
635 
636   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
637 
638   out_fd = open_tmpfile();
639   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, out_fd, PR_NETIO_IO_WR);
640 
641   cmd = "Hello, World!\n";
642 
643   pr_netio_buffer_alloc(in);
644   pbuf = in->strm_buf;
645 
646   telnet_opt = 7;
647   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c%cWorld!\n", TELNET_IAC,
648     TELNET_WONT, telnet_opt);
649   pbuf->remaining = pbuf->buflen - len;
650   pbuf->current = pbuf->buf;
651 
652   buf[sizeof(buf)-1] = '\0';
653 
654   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
655   xerrno = errno;
656 
657   pr_netio_close(in);
658 
659   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
660     xerrno, strerror(xerrno));
661   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
662     buf);
663 
664   /* Rewind the output stream fd. */
665   lseek(out_fd, 0, SEEK_SET);
666   len = read(out_fd, buf, sizeof(buf)-1);
667   pr_netio_close(out);
668 
669   fail_unless(len == 3, "Expected to read 3 bytes from output stream, got %d",
670     len);
671   fail_unless(buf[0] == (char) TELNET_IAC, "Expected IAC at index 0, got %d",
672     buf[0]);
673   fail_unless(buf[1] == (char) TELNET_DONT, "Expected DONT at index 1, got %d",
674     buf[1]);
675   fail_unless(buf[2] == telnet_opt, "Expected opt '%c' at index 2, got %c",
676     telnet_opt, buf[2]);
677 
678   test_cleanup();
679 }
680 END_TEST
681 
START_TEST(netio_telnet_gets_telnet_bare_wont_test)682 START_TEST (netio_telnet_gets_telnet_bare_wont_test) {
683   char buf[256], *cmd, *res, telnet_opt;
684   pr_netio_stream_t *in, *out;
685   pr_buffer_t *pbuf;
686   int len, xerrno;
687 
688   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
689   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
690 
691   cmd = "Hello, World!\n";
692 
693   pr_netio_buffer_alloc(in);
694   pbuf = in->strm_buf;
695 
696   telnet_opt = 7;
697   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_WONT,
698     telnet_opt);
699   pbuf->remaining = pbuf->buflen - len;
700   pbuf->current = pbuf->buf;
701 
702   buf[sizeof(buf)-1] = '\0';
703 
704   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
705   xerrno = errno;
706 
707   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
708     xerrno, strerror(xerrno));
709   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
710     7, cmd, 7, buf);
711   fail_unless(buf[7] == (char) TELNET_WONT, "Expected WONT at index 7, got %d",
712     buf[7]);
713   fail_unless(buf[8] == telnet_opt, "Expected Telnet opt %c at index 8, got %d",
714     telnet_opt, buf[8]);
715   fail_unless(strcmp(buf + 9, cmd + 7) == 0, "Expected string '%s', got '%s'",
716     cmd + 7, buf + 9);
717 
718   pr_netio_close(in);
719   pr_netio_close(out);
720 }
721 END_TEST
722 
START_TEST(netio_telnet_gets_telnet_do_test)723 START_TEST (netio_telnet_gets_telnet_do_test) {
724   char buf[256], *cmd, *res, telnet_opt;
725   pr_netio_stream_t *in, *out;
726   pr_buffer_t *pbuf;
727   int len, out_fd, xerrno;
728 
729   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
730 
731   out_fd = open_tmpfile();
732   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, out_fd, PR_NETIO_IO_WR);
733 
734   cmd = "Hello, World!\n";
735 
736   pr_netio_buffer_alloc(in);
737   pbuf = in->strm_buf;
738 
739   telnet_opt = 7;
740   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c%cWorld!\n", TELNET_IAC,
741     TELNET_DO, telnet_opt);
742   pbuf->remaining = pbuf->buflen - len;
743   pbuf->current = pbuf->buf;
744 
745   buf[sizeof(buf)-1] = '\0';
746 
747   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
748   xerrno = errno;
749 
750   pr_netio_close(in);
751 
752   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
753     xerrno, strerror(xerrno));
754   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
755     buf);
756 
757   /* Rewind the output stream fd. */
758   lseek(out_fd, 0, SEEK_SET);
759   len = read(out_fd, buf, sizeof(buf)-1);
760   pr_netio_close(out);
761 
762   fail_unless(len == 3, "Expected to read 3 bytes from output stream, got %d",
763     len);
764   fail_unless(buf[0] == (char) TELNET_IAC, "Expected IAC at index 0, got %d",
765     buf[0]);
766   fail_unless(buf[1] == (char) TELNET_WONT, "Expected WONT at index 1, got %d",
767     buf[1]);
768   fail_unless(buf[2] == telnet_opt, "Expected opt '%c' at index 2, got %c",
769     telnet_opt, buf[2]);
770 
771   test_cleanup();
772 }
773 END_TEST
774 
START_TEST(netio_telnet_gets_telnet_bare_do_test)775 START_TEST (netio_telnet_gets_telnet_bare_do_test) {
776   char buf[256], *cmd, *res, telnet_opt;
777   pr_netio_stream_t *in, *out;
778   pr_buffer_t *pbuf;
779   int len, xerrno;
780 
781   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
782   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
783 
784   cmd = "Hello, World!\n";
785 
786   pr_netio_buffer_alloc(in);
787   pbuf = in->strm_buf;
788 
789   telnet_opt = 7;
790   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_DO,
791     telnet_opt);
792   pbuf->remaining = pbuf->buflen - len;
793   pbuf->current = pbuf->buf;
794 
795   buf[sizeof(buf)-1] = '\0';
796 
797   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
798   xerrno = errno;
799 
800   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
801     xerrno, strerror(xerrno));
802   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
803     7, cmd, 7, buf);
804   fail_unless(buf[7] == (char) TELNET_DO, "Expected DO at index 7, got %d",
805     buf[7]);
806   fail_unless(buf[8] == telnet_opt, "Expected Telnet opt %c at index 8, got %d",
807     telnet_opt, buf[8]);
808   fail_unless(strcmp(buf + 9, cmd + 7) == 0, "Expected string '%s', got '%s'",
809     cmd + 7, buf + 9);
810 
811   pr_netio_close(in);
812   pr_netio_close(out);
813 }
814 END_TEST
815 
START_TEST(netio_telnet_gets_telnet_dont_test)816 START_TEST (netio_telnet_gets_telnet_dont_test) {
817   char buf[256], *cmd, *res, telnet_opt;
818   pr_netio_stream_t *in, *out;
819   pr_buffer_t *pbuf;
820   int len, out_fd, xerrno;
821 
822   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
823 
824   out_fd = open_tmpfile();
825   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, out_fd, PR_NETIO_IO_WR);
826 
827   cmd = "Hello, World!\n";
828 
829   pr_netio_buffer_alloc(in);
830   pbuf = in->strm_buf;
831 
832   telnet_opt = 7;
833   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c%cWorld!\n", TELNET_IAC,
834     TELNET_DONT, telnet_opt);
835   pbuf->remaining = pbuf->buflen - len;
836   pbuf->current = pbuf->buf;
837 
838   buf[sizeof(buf)-1] = '\0';
839 
840   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
841   xerrno = errno;
842 
843   pr_netio_close(in);
844 
845   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
846     xerrno, strerror(xerrno));
847   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
848     buf);
849 
850   /* Rewind the output stream fd. */
851   lseek(out_fd, 0, SEEK_SET);
852   len = read(out_fd, buf, sizeof(buf)-1);
853   pr_netio_close(out);
854 
855   fail_unless(len == 3, "Expected to read 3 bytes from output stream, got %d",
856     len);
857   fail_unless(buf[0] == (char) TELNET_IAC, "Expected IAC at index 0, got %d",
858     buf[0]);
859   fail_unless(buf[1] == (char) TELNET_WONT, "Expected WONT at index 1, got %d",
860     buf[1]);
861   fail_unless(buf[2] == telnet_opt, "Expected opt '%c' at index 2, got %c",
862     telnet_opt, buf[2]);
863 
864   test_cleanup();
865 }
866 END_TEST
867 
START_TEST(netio_telnet_gets_telnet_bare_dont_test)868 START_TEST (netio_telnet_gets_telnet_bare_dont_test) {
869   char buf[256], *cmd, *res, telnet_opt;
870   pr_netio_stream_t *in, *out;
871   pr_buffer_t *pbuf;
872   int len, xerrno;
873 
874   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
875   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
876 
877   cmd = "Hello, World!\n";
878 
879   pr_netio_buffer_alloc(in);
880   pbuf = in->strm_buf;
881 
882   telnet_opt = 7;
883   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_DONT,
884     telnet_opt);
885   pbuf->remaining = pbuf->buflen - len;
886   pbuf->current = pbuf->buf;
887 
888   buf[sizeof(buf)-1] = '\0';
889 
890   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
891   xerrno = errno;
892 
893   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
894     xerrno, strerror(xerrno));
895   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
896     7, cmd, 7, buf);
897   fail_unless(buf[7] == (char) TELNET_DONT, "Expected DONT at index 7, got %d",
898     buf[7]);
899   fail_unless(buf[8] == telnet_opt, "Expected Telnet opt %c at index 8, got %d",
900     telnet_opt, buf[8]);
901   fail_unless(strcmp(buf + 9, cmd + 7) == 0, "Expected string '%s', got '%s'",
902     cmd + 7, buf + 9);
903 
904   pr_netio_close(in);
905   pr_netio_close(out);
906 }
907 END_TEST
908 
START_TEST(netio_telnet_gets_telnet_ip_test)909 START_TEST (netio_telnet_gets_telnet_ip_test) {
910   char buf[256], *cmd, *res;
911   pr_netio_stream_t *in, *out;
912   pr_buffer_t *pbuf;
913   int len, xerrno;
914 
915   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
916   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
917 
918   cmd = "Hello, World!\n";
919 
920   pr_netio_buffer_alloc(in);
921   pbuf = in->strm_buf;
922 
923   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_IAC,
924     TELNET_IP);
925   pbuf->remaining = pbuf->buflen - len;
926   pbuf->current = pbuf->buf;
927 
928   buf[sizeof(buf)-1] = '\0';
929 
930   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
931   xerrno = errno;
932 
933   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
934     xerrno, strerror(xerrno));
935   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
936     buf);
937 
938   pr_netio_close(in);
939   pr_netio_close(out);
940 }
941 END_TEST
942 
START_TEST(netio_telnet_gets_telnet_bare_ip_test)943 START_TEST (netio_telnet_gets_telnet_bare_ip_test) {
944   char buf[256], *cmd, *res;
945   pr_netio_stream_t *in, *out;
946   pr_buffer_t *pbuf;
947   int len, xerrno;
948 
949   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
950   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
951 
952   cmd = "Hello, World!\n";
953 
954   pr_netio_buffer_alloc(in);
955   pbuf = in->strm_buf;
956 
957   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %cWorld!\n", TELNET_IP);
958   pbuf->remaining = pbuf->buflen - len;
959   pbuf->current = pbuf->buf;
960 
961   buf[sizeof(buf)-1] = '\0';
962 
963   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
964   xerrno = errno;
965 
966   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
967     xerrno, strerror(xerrno));
968   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
969     7, cmd, 7, buf);
970   fail_unless(buf[7] == (char) TELNET_IP, "Expected IP at index 7, got %d",
971     buf[7]);
972   fail_unless(strcmp(buf + 8, cmd + 7) == 0, "Expected string '%s', got '%s'",
973     cmd + 7, buf + 8);
974 
975   pr_netio_close(in);
976   pr_netio_close(out);
977 }
978 END_TEST
979 
START_TEST(netio_telnet_gets_telnet_dm_test)980 START_TEST (netio_telnet_gets_telnet_dm_test) {
981   char buf[256], *cmd, *res;
982   pr_netio_stream_t *in, *out;
983   pr_buffer_t *pbuf;
984   int len, xerrno;
985 
986   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
987   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
988 
989   cmd = "Hello, World!\n";
990 
991   pr_netio_buffer_alloc(in);
992   pbuf = in->strm_buf;
993 
994   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_IAC,
995     TELNET_DM);
996   pbuf->remaining = pbuf->buflen - len;
997   pbuf->current = pbuf->buf;
998 
999   buf[sizeof(buf)-1] = '\0';
1000 
1001   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
1002   xerrno = errno;
1003 
1004   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
1005     xerrno, strerror(xerrno));
1006   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
1007     buf);
1008 
1009   pr_netio_close(in);
1010   pr_netio_close(out);
1011 }
1012 END_TEST
1013 
START_TEST(netio_telnet_gets_telnet_bare_dm_test)1014 START_TEST (netio_telnet_gets_telnet_bare_dm_test) {
1015   char buf[256], *cmd, *res;
1016   pr_netio_stream_t *in, *out;
1017   pr_buffer_t *pbuf;
1018   int len, xerrno;
1019 
1020   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1021   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1022 
1023   cmd = "Hello, World!\n";
1024 
1025   pr_netio_buffer_alloc(in);
1026   pbuf = in->strm_buf;
1027 
1028   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %cWorld!\n", TELNET_DM);
1029   pbuf->remaining = pbuf->buflen - len;
1030   pbuf->current = pbuf->buf;
1031 
1032   buf[sizeof(buf)-1] = '\0';
1033 
1034   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
1035   xerrno = errno;
1036 
1037   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
1038     xerrno, strerror(xerrno));
1039   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
1040     7, cmd, 7, buf);
1041   fail_unless(buf[7] == (char) TELNET_DM, "Expected DM at index 7, got %d",
1042     buf[7]);
1043   fail_unless(strcmp(buf + 8, cmd + 7) == 0, "Expected string '%s', got '%s'",
1044     cmd + 7, buf + 8);
1045 
1046   pr_netio_close(in);
1047   pr_netio_close(out);
1048 }
1049 END_TEST
1050 
START_TEST(netio_telnet_gets_telnet_single_iac_test)1051 START_TEST (netio_telnet_gets_telnet_single_iac_test) {
1052   char buf[256], *cmd, *res;
1053   pr_netio_stream_t *in, *out;
1054   pr_buffer_t *pbuf;
1055   int len, xerrno;
1056 
1057   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1058   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1059 
1060   cmd = "Hello, World!\n";
1061 
1062   pr_netio_buffer_alloc(in);
1063   pbuf = in->strm_buf;
1064 
1065   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %cWorld!\n", TELNET_IAC);
1066   pbuf->remaining = pbuf->buflen - len;
1067   pbuf->current = pbuf->buf;
1068 
1069   buf[sizeof(buf)-1] = '\0';
1070 
1071   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
1072   xerrno = errno;
1073 
1074   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
1075     xerrno, strerror(xerrno));
1076   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
1077     7, cmd, 7, buf);
1078   fail_unless(buf[7] == (char) TELNET_IAC, "Expected IAC at index 7, got %d",
1079     buf[7]);
1080   fail_unless(strcmp(buf + 8, cmd + 7) == 0, "Expected string '%s', got '%s'",
1081     cmd + 7, buf + 8);
1082 
1083   pr_netio_close(in);
1084   pr_netio_close(out);
1085 }
1086 END_TEST
1087 
START_TEST(netio_telnet_gets_bug3521_test)1088 START_TEST (netio_telnet_gets_bug3521_test) {
1089   char buf[10], *res, telnet_opt;
1090   pr_netio_stream_t *in, *out;
1091   pr_buffer_t *pbuf;
1092   int len, xerrno;
1093 
1094   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1095   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1096 
1097   pr_netio_buffer_alloc(in);
1098   pbuf = in->strm_buf;
1099 
1100   telnet_opt = 7;
1101   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%c%c%cWorld!\n",
1102     TELNET_IAC, TELNET_IAC, TELNET_WILL, telnet_opt);
1103   pbuf->remaining = pbuf->buflen - len;
1104   pbuf->current = pbuf->buf;
1105 
1106   buf[sizeof(buf)-1] = '\0';
1107 
1108   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
1109   xerrno = errno;
1110 
1111   fail_unless(res == NULL, "Expected null");
1112   fail_unless(xerrno == E2BIG, "Failed to set errno to E2BIG, got %s (%d)",
1113     strerror(xerrno), xerrno);
1114 
1115   pr_netio_close(in);
1116   pr_netio_close(out);
1117 }
1118 END_TEST
1119 
START_TEST(netio_telnet_gets_bug3697_test)1120 START_TEST (netio_telnet_gets_bug3697_test) {
1121   char buf[256], *cmd, *res;
1122   pr_netio_stream_t *in, *out;
1123   pr_buffer_t *pbuf;
1124   int len, xerrno;
1125 
1126   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1127   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1128 
1129   cmd = "Hello, World!\n";
1130 
1131   pr_netio_buffer_alloc(in);
1132   pbuf = in->strm_buf;
1133 
1134   len = snprintf(pbuf->buf, pbuf->buflen-1, "Hello, %c%cWorld!\n", TELNET_IAC,
1135     TELNET_IAC);
1136   pbuf->remaining = pbuf->buflen - len;
1137   pbuf->current = pbuf->buf;
1138 
1139   buf[sizeof(buf)-1] = '\0';
1140 
1141   res = pr_netio_telnet_gets(buf, sizeof(buf)-1, in, out);
1142   xerrno = errno;
1143 
1144   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
1145     xerrno, strerror(xerrno));
1146   fail_unless(strncmp(buf, cmd, 7) == 0, "Expected string '%*s', got '%*s'",
1147     7, cmd, 7, buf);
1148   fail_unless(buf[7] == (char) TELNET_IAC, "Expected IAC at index 7, got %d",
1149     buf[7]);
1150   fail_unless(strcmp(buf + 8, cmd + 7) == 0, "Expected string '%s', got '%s'",
1151     cmd + 7, buf + 8);
1152 
1153   pr_netio_close(in);
1154   pr_netio_close(out);
1155 }
1156 END_TEST
1157 
START_TEST(netio_telnet_gets_eof_test)1158 START_TEST (netio_telnet_gets_eof_test) {
1159   char buf[256], *cmd, *res;
1160   pr_netio_stream_t *in, *out;
1161   pr_buffer_t *pbuf;
1162   int len, xerrno;
1163 
1164   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1165   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1166 
1167   cmd = "Hello, World!";
1168 
1169   pr_netio_buffer_alloc(in);
1170   pbuf = in->strm_buf;
1171 
1172   len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", cmd);
1173   pbuf->remaining = pbuf->buflen - len;
1174   pbuf->current = pbuf->buf;
1175 
1176   buf[sizeof(buf)-1] = '\0';
1177 
1178   /* In this scenario, we have not supplied an LF, but the resulting buffer
1179    * is terminated with a NUL because of the end-of-stream (or error) checks
1180    * in pr_netio_telnet_gets(), when we read the input stream for more data
1181    * looking for that LF.
1182    */
1183   res = pr_netio_telnet_gets(buf, strlen(cmd) + 2, in, out);
1184   xerrno = errno;
1185 
1186   fail_unless(res != NULL, "Failed to get string from stream: (%d) %s",
1187     xerrno, strerror(xerrno));
1188   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
1189     buf);
1190 
1191   pr_netio_close(in);
1192   pr_netio_close(out);
1193 }
1194 END_TEST
1195 
START_TEST(netio_telnet_gets2_single_line_test)1196 START_TEST (netio_telnet_gets2_single_line_test) {
1197   int res;
1198   char buf[256], *cmd;
1199   size_t cmd_len;
1200   pr_netio_stream_t *in, *out;
1201   pr_buffer_t *pbuf;
1202   int len, xerrno;
1203 
1204   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1205   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1206 
1207   cmd = "Hello, World!\n";
1208   cmd_len = strlen(cmd);
1209 
1210   pr_netio_buffer_alloc(in);
1211   pbuf = in->strm_buf;
1212   len = snprintf(pbuf->buf, pbuf->buflen-1, "%s", cmd);
1213   pbuf->remaining = pbuf->buflen - len;
1214   pbuf->current = pbuf->buf;
1215 
1216   buf[sizeof(buf)-1] = '\0';
1217 
1218   res = pr_netio_telnet_gets2(buf, sizeof(buf)-1, in, out);
1219   xerrno = errno;
1220 
1221   fail_unless(res > 0, "Failed to get string from stream: (%d) %s",
1222     xerrno, strerror(xerrno));
1223   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
1224     buf);
1225 
1226   fail_unless((size_t) res == cmd_len, "Expected length %lu, got %d",
1227     (unsigned long) cmd_len, res);
1228   fail_unless(pbuf->remaining == (size_t) xfer_bufsz,
1229     "Expected %d remaining bytes, got %lu", xfer_bufsz,
1230     (unsigned long) pbuf->remaining);
1231 
1232   pr_netio_close(in);
1233   pr_netio_close(out);
1234 }
1235 END_TEST
1236 
START_TEST(netio_telnet_gets2_single_line_crnul_test)1237 START_TEST (netio_telnet_gets2_single_line_crnul_test) {
1238   int res;
1239   char buf[256], *cmd;
1240   size_t cmd_len;
1241   pr_netio_stream_t *in, *out;
1242   pr_buffer_t *pbuf;
1243   int xerrno;
1244 
1245   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1246   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1247 
1248   /* See Bug#4167.  We cannot use strlen(3) due to the embedded NUL. */
1249   cmd = "Hello, \015\000World!\n";
1250   cmd_len = 14;
1251 
1252   pr_netio_buffer_alloc(in);
1253   pbuf = in->strm_buf;
1254   memcpy(pbuf->buf, cmd, cmd_len);
1255   pbuf->remaining = pbuf->buflen - cmd_len;
1256   pbuf->current = pbuf->buf;
1257 
1258   buf[sizeof(buf)-1] = '\0';
1259 
1260   res = pr_netio_telnet_gets2(buf, sizeof(buf)-1, in, out);
1261   xerrno = errno;
1262 
1263   fail_unless(res > 0, "Failed to get string from stream: (%d) %s",
1264     xerrno, strerror(xerrno));
1265   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
1266     buf);
1267 
1268   fail_unless((size_t) res == cmd_len, "Expected length %lu, got %d",
1269     (unsigned long) cmd_len, res);
1270   fail_unless(pbuf->remaining == (size_t) xfer_bufsz,
1271     "Expected %d remaining bytes, got %lu", xfer_bufsz,
1272     (unsigned long) pbuf->remaining);
1273 
1274   pr_netio_close(in);
1275   pr_netio_close(out);
1276 }
1277 END_TEST
1278 
START_TEST(netio_telnet_gets2_single_line_lf_test)1279 START_TEST (netio_telnet_gets2_single_line_lf_test) {
1280   int res;
1281   char buf[256], *cmd;
1282   size_t cmd_len;
1283   pr_netio_stream_t *in, *out;
1284   pr_buffer_t *pbuf;
1285   int xerrno;
1286 
1287   in = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_RD);
1288   out = pr_netio_open(p, PR_NETIO_STRM_CTRL, -1, PR_NETIO_IO_WR);
1289 
1290   cmd = "Hello, \012World!\n";
1291   cmd_len = strlen(cmd);
1292 
1293   pr_netio_buffer_alloc(in);
1294   pbuf = in->strm_buf;
1295   memcpy(pbuf->buf, cmd, cmd_len);
1296   pbuf->remaining = pbuf->buflen - cmd_len;
1297   pbuf->current = pbuf->buf;
1298 
1299   buf[sizeof(buf)-1] = '\0';
1300 
1301   res = pr_netio_telnet_gets2(buf, sizeof(buf)-1, in, out);
1302   xerrno = errno;
1303 
1304   fail_unless(res > 0, "Failed to get string from stream: (%d) %s",
1305     xerrno, strerror(xerrno));
1306   fail_unless(strcmp(buf, cmd) == 0, "Expected string '%s', got '%s'", cmd,
1307     buf);
1308 
1309   fail_unless((size_t) res == cmd_len, "Expected length %lu, got %d",
1310     (unsigned long) cmd_len, res);
1311   fail_unless(pbuf->remaining == (size_t) xfer_bufsz,
1312     "Expected %d remaining bytes, got %lu", xfer_bufsz,
1313     (unsigned long) pbuf->remaining);
1314 
1315   pr_netio_close(in);
1316   pr_netio_close(out);
1317 }
1318 END_TEST
1319 
netio_poll_cb(pr_netio_stream_t * nstrm)1320 static int netio_poll_cb(pr_netio_stream_t *nstrm) {
1321   /* Always return >0, to indicate that we haven't timed out, AND that there
1322    * is a writable fd available.
1323    */
1324   return 7;
1325 }
1326 
1327 static int netio_read_eof = FALSE;
1328 static int netio_read_epipe = FALSE;
1329 
netio_read_cb(pr_netio_stream_t * nstrm,char * buf,size_t buflen)1330 static int netio_read_cb(pr_netio_stream_t *nstrm, char *buf, size_t buflen) {
1331   const char *text;
1332   int res;
1333 
1334   if (netio_read_eof) {
1335     netio_read_eof = FALSE;
1336     return 0;
1337   }
1338 
1339   if (netio_read_epipe) {
1340     netio_read_epipe = FALSE;
1341     errno = EPIPE;
1342     return -1;
1343   }
1344 
1345   text = "Hello, World!\r\n";
1346   sstrncpy(buf, text, buflen);
1347 
1348   /* Make sure the next read returns EOF. */
1349   netio_read_eof = TRUE;
1350 
1351   res = strlen(text);
1352   return res;
1353 }
1354 
1355 static int netio_write_epipe = FALSE;
1356 
netio_write_cb(pr_netio_stream_t * nstrm,char * buf,size_t buflen)1357 static int netio_write_cb(pr_netio_stream_t *nstrm, char *buf, size_t buflen) {
1358   if (netio_write_epipe) {
1359     netio_write_epipe = FALSE;
1360     errno = EPIPE;
1361     return -1;
1362   }
1363 
1364   return buflen;
1365 }
1366 
netio_read_from_stream(int strm_type)1367 static int netio_read_from_stream(int strm_type) {
1368   int fd = 2, res;
1369   char buf[1024], *expected_text;
1370   size_t expected_sz;
1371   pr_netio_stream_t *nstrm;
1372 
1373   res = pr_netio_read(NULL, NULL, 0, 0);
1374   if (res == 0) {
1375     errno = EINVAL;
1376     return -1;
1377   }
1378 
1379   nstrm = pr_netio_open(p, strm_type, fd, PR_NETIO_IO_RD);
1380   if (nstrm == NULL) {
1381     int xerrno = errno;
1382 
1383     pr_trace_msg("netio", 1, "error opening custom netio stream: %s",
1384       strerror(xerrno));
1385     errno = xerrno;
1386     return -1;
1387   }
1388 
1389   res = pr_netio_read(nstrm, NULL, 0, 0);
1390   if (res == 0) {
1391     pr_netio_close(nstrm);
1392     errno = EINVAL;
1393     return -1;
1394   }
1395 
1396   res = pr_netio_read(nstrm, buf, 0, 0);
1397   if (res == 0) {
1398     pr_netio_close(nstrm);
1399     errno = EINVAL;
1400     return -1;
1401   }
1402 
1403   expected_text = "Hello, World!\r\n";
1404   expected_sz = strlen(expected_text);
1405 
1406   memset(buf, '\0', sizeof(buf));
1407   res = pr_netio_read(nstrm, buf, sizeof(buf)-1, 1);
1408 
1409   if (res != (int) expected_sz) {
1410     pr_trace_msg("netio", 1, "Expected %lu bytes, got %d",
1411       (unsigned long) expected_sz, res);
1412     pr_netio_close(nstrm);
1413 
1414     if (res < 0) {
1415       return -1;
1416     }
1417 
1418     errno = EIO;
1419     return -1;
1420   }
1421 
1422   if (strcmp(buf, expected_text) != 0) {
1423     pr_trace_msg("netio", 1, "Expected '%s', got '%s'", expected_text, buf);
1424     pr_netio_close(nstrm);
1425 
1426     errno = EIO;
1427     return -1;
1428   }
1429 
1430   netio_read_eof = TRUE;
1431   res = pr_netio_read(nstrm, buf, sizeof(buf)-1, 1);
1432   if (res > 0) {
1433     pr_trace_msg("netio", 1, "Expected EOF (0), got %d", res);
1434     pr_netio_close(nstrm);
1435 
1436     errno = EIO;
1437     return -1;
1438   }
1439 
1440   netio_read_epipe = TRUE;
1441   res = pr_netio_read(nstrm, buf, sizeof(buf)-1, sizeof(buf)-1);
1442   if (res >= 0) {
1443     pr_trace_msg("netio", 1, "Expected EPIPE (-1), got %d", res);
1444     pr_netio_close(nstrm);
1445 
1446     errno = EIO;
1447     return -1;
1448   }
1449 
1450   mark_point();
1451   pr_netio_close(nstrm);
1452   return 0;
1453 }
1454 
netio_write_to_stream(int strm_type,int use_async)1455 static int netio_write_to_stream(int strm_type, int use_async) {
1456   int fd = 2, res;
1457   char *buf;
1458   size_t buflen;
1459   pr_netio_stream_t *nstrm;
1460 
1461   res = pr_netio_write(NULL, NULL, 0);
1462   if (res == 0) {
1463     errno = EINVAL;
1464     return -1;
1465   }
1466 
1467   nstrm = pr_netio_open(p, strm_type, fd, PR_NETIO_IO_WR);
1468   if (nstrm == NULL) {
1469     int xerrno = errno;
1470 
1471     pr_trace_msg("netio", 1, "error opening custom netio stream: %s",
1472       strerror(xerrno));
1473     errno = xerrno;
1474     return -1;
1475   }
1476 
1477   res = pr_netio_write(nstrm, NULL, 0);
1478   if (res == 0) {
1479     pr_netio_close(nstrm);
1480     errno = EINVAL;
1481     return -1;
1482   }
1483 
1484   buf = "Hello, World!\n";
1485   buflen = strlen(buf);
1486 
1487   res = pr_netio_write(nstrm, buf, 0);
1488   if (res == 0) {
1489     pr_netio_close(nstrm);
1490     errno = EINVAL;
1491     return -1;
1492   }
1493 
1494   if (use_async) {
1495     res = pr_netio_write_async(nstrm, buf, buflen);
1496 
1497   } else {
1498     res = pr_netio_write(nstrm, buf, buflen);
1499   }
1500 
1501   if ((size_t) res != buflen) {
1502     pr_trace_msg("netio", 1, "wrote buffer (%lu bytes), got %d",
1503       (unsigned long) buflen, res);
1504     pr_netio_close(nstrm);
1505 
1506     if (res < 0) {
1507       return -1;
1508     }
1509 
1510     errno = EIO;
1511     return -1;
1512   }
1513 
1514   netio_write_epipe = TRUE;
1515   res = pr_netio_write(nstrm, buf, buflen);
1516   if (res >= 0) {
1517     pr_trace_msg("netio", 1, "Expected EPIPE (-1), got %d", res);
1518     pr_netio_close(nstrm);
1519     errno = EIO;
1520     return -1;
1521   }
1522 
1523   mark_point();
1524   pr_netio_close(nstrm);
1525   return 0;
1526 }
1527 
START_TEST(netio_read_test)1528 START_TEST (netio_read_test) {
1529   int res;
1530   pr_netio_t *netio, *netio2;
1531 
1532   netio = pr_alloc_netio2(p, NULL, "testsuite");
1533   netio->poll = netio_poll_cb;
1534   netio->read = netio_read_cb;
1535 
1536   /* Write to control stream */
1537   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1538   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1539     strerror(errno));
1540 
1541   netio2 = pr_get_netio(PR_NETIO_STRM_CTRL);
1542   fail_unless(netio2 != NULL, "Failed to get custom ctrl NetIO: %s",
1543     strerror(errno));
1544   fail_unless(netio2 == netio, "Expected custom ctrl NetIO %p, got %p",
1545     netio, netio2);
1546 
1547   res = netio_read_from_stream(PR_NETIO_STRM_CTRL);
1548   fail_unless(res == 0, "Failed to read from custom ctrl NetIO: %s",
1549     strerror(errno));
1550 
1551   mark_point();
1552   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1553 
1554   /* Read from data stream */
1555   res = pr_register_netio(netio, PR_NETIO_STRM_DATA);
1556   fail_unless(res == 0, "Failed to register custom data NetIO: %s",
1557     strerror(errno));
1558 
1559   netio2 = pr_get_netio(PR_NETIO_STRM_DATA);
1560   fail_unless(netio2 != NULL, "Failed to get custom data NetIO: %s",
1561     strerror(errno));
1562   fail_unless(netio2 == netio, "Expected custom data NetIO %p, got %p",
1563     netio, netio2);
1564 
1565   res = netio_read_from_stream(PR_NETIO_STRM_DATA);
1566   fail_unless(res == 0, "Failed to read from custom data NetIO: %s",
1567     strerror(errno));
1568 
1569   mark_point();
1570   pr_unregister_netio(PR_NETIO_STRM_DATA);
1571 
1572   /* Read from other stream */
1573   res = pr_register_netio(netio, PR_NETIO_STRM_OTHR);
1574   fail_unless(res == 0, "Failed to register custom other NetIO: %s",
1575     strerror(errno));
1576 
1577   netio2 = pr_get_netio(PR_NETIO_STRM_OTHR);
1578   fail_unless(netio2 != NULL, "Failed to get custom othr NetIO: %s",
1579     strerror(errno));
1580   fail_unless(netio2 == netio, "Expected custom othr NetIO %p, got %p",
1581     netio, netio2);
1582 
1583   res = netio_read_from_stream(PR_NETIO_STRM_OTHR);
1584   fail_unless(res == 0, "Failed to read from custom other NetIO: %s",
1585     strerror(errno));
1586 
1587   mark_point();
1588   pr_unregister_netio(PR_NETIO_STRM_OTHR);
1589 }
1590 END_TEST
1591 
START_TEST(netio_gets_test)1592 START_TEST (netio_gets_test) {
1593   int fd = 2, res;
1594   char *buf, *expected, *text;
1595   size_t buflen;
1596   pr_netio_t *netio;
1597   pr_netio_stream_t *nstrm;
1598 
1599   text = pr_netio_gets(NULL, 0, NULL);
1600   fail_unless(text == NULL, "Failed to handle null arguments");
1601   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1602     strerror(errno), errno);
1603 
1604   netio = pr_alloc_netio2(p, NULL, "testsuite");
1605   netio->poll = netio_poll_cb;
1606   netio->read = netio_read_cb;
1607 
1608   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1609   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1610     strerror(errno));
1611 
1612   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
1613   fail_unless(nstrm != NULL, "Failed to open stream: %s", strerror(errno));
1614 
1615   text = pr_netio_gets(NULL, 0, nstrm);
1616   fail_unless(text == NULL, "Failed to handle null buffer");
1617   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1618     strerror(errno), errno);
1619 
1620   buflen = 1024;
1621   buf = pcalloc(p, buflen);
1622 
1623   text = pr_netio_gets(buf, 0, nstrm);
1624   fail_unless(text == NULL, "Failed to handle zero buffer length");
1625   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1626     strerror(errno), errno);
1627 
1628   expected = "Hello, World!\r\n";
1629   text = pr_netio_gets(buf, buflen-1, nstrm);
1630   fail_unless(text != NULL, "Failed to get text: %s", strerror(errno));
1631   fail_unless(strcmp(text, expected) == 0, "Expected '%s', got '%s'",
1632     expected, text);
1633 
1634   mark_point();
1635   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1636 }
1637 END_TEST
1638 
START_TEST(netio_write_test)1639 START_TEST (netio_write_test) {
1640   int res;
1641   pr_netio_t *netio, *netio2;
1642 
1643   netio = pr_alloc_netio2(p, NULL, "testsuite");
1644   netio->poll = netio_poll_cb;
1645   netio->write = netio_write_cb;
1646 
1647   /* Write to control stream */
1648   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1649   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1650     strerror(errno));
1651 
1652   netio2 = pr_get_netio(PR_NETIO_STRM_CTRL);
1653   fail_unless(netio2 != NULL, "Failed to get custom ctrl NetIO: %s",
1654     strerror(errno));
1655   fail_unless(netio2 == netio, "Expected custom ctrl NetIO %p, got %p",
1656     netio, netio2);
1657 
1658   res = netio_write_to_stream(PR_NETIO_STRM_CTRL, FALSE);
1659   fail_unless(res == 0, "Failed to write to custom ctrl NetIO: %s",
1660     strerror(errno));
1661 
1662   mark_point();
1663   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1664 
1665   /* Write to data stream */
1666   res = pr_register_netio(netio, PR_NETIO_STRM_DATA);
1667   fail_unless(res == 0, "Failed to register custom data NetIO: %s",
1668     strerror(errno));
1669 
1670   netio2 = pr_get_netio(PR_NETIO_STRM_DATA);
1671   fail_unless(netio2 != NULL, "Failed to get custom data NetIO: %s",
1672     strerror(errno));
1673   fail_unless(netio2 == netio, "Expected custom data NetIO %p, got %p",
1674     netio, netio2);
1675 
1676   res = netio_write_to_stream(PR_NETIO_STRM_DATA, FALSE);
1677   fail_unless(res == 0, "Failed to write to custom data NetIO: %s",
1678     strerror(errno));
1679 
1680   mark_point();
1681   pr_unregister_netio(PR_NETIO_STRM_DATA);
1682 
1683   /* Write to other stream */
1684   res = pr_register_netio(netio, PR_NETIO_STRM_OTHR);
1685   fail_unless(res == 0, "Failed to register custom other NetIO: %s",
1686     strerror(errno));
1687 
1688   netio2 = pr_get_netio(PR_NETIO_STRM_OTHR);
1689   fail_unless(netio2 != NULL, "Failed to get custom othr NetIO: %s",
1690     strerror(errno));
1691   fail_unless(netio2 == netio, "Expected custom othr NetIO %p, got %p",
1692     netio, netio2);
1693 
1694   res = netio_write_to_stream(PR_NETIO_STRM_OTHR, FALSE);
1695   fail_unless(res == 0, "Failed to write to custom other NetIO: %s",
1696     strerror(errno));
1697 
1698   mark_point();
1699   pr_unregister_netio(PR_NETIO_STRM_OTHR);
1700 }
1701 END_TEST
1702 
START_TEST(netio_write_async_test)1703 START_TEST (netio_write_async_test) {
1704   int res;
1705   pr_netio_t *netio;
1706 
1707   netio = pr_alloc_netio2(p, NULL, "testsuite");
1708   netio->poll = netio_poll_cb;
1709   netio->write = netio_write_cb;
1710 
1711   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1712   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1713     strerror(errno));
1714 
1715   res = netio_write_to_stream(PR_NETIO_STRM_CTRL, TRUE);
1716   fail_unless(res == 0, "Failed to write to custom ctrl NetIO: %s",
1717     strerror(errno));
1718 
1719   mark_point();
1720   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1721 }
1722 END_TEST
1723 
netio_print_to_stream(int strm_type,int use_async)1724 static int netio_print_to_stream(int strm_type, int use_async) {
1725   int fd = 2, res;
1726   char *buf;
1727   size_t buflen;
1728   pr_netio_stream_t *nstrm;
1729 
1730   nstrm = pr_netio_open(p, strm_type, fd, PR_NETIO_IO_WR);
1731   if (nstrm == NULL) {
1732     int xerrno = errno;
1733 
1734     pr_trace_msg("netio", 1, "error opening custom netio stream: %s",
1735       strerror(xerrno));
1736     errno = xerrno;
1737     return -1;
1738   }
1739 
1740   buf = "Hello, World!\n";
1741   buflen = strlen(buf);
1742 
1743   if (use_async) {
1744     res = pr_netio_printf_async(nstrm, "%s", buf);
1745 
1746   } else {
1747     res = pr_netio_printf(nstrm, "%s", buf);
1748   }
1749 
1750   if ((size_t) res != buflen) {
1751     pr_trace_msg("netio", 1, "printed buffer (%lu bytes), got %d",
1752       (unsigned long) buflen, res);
1753     pr_netio_close(nstrm);
1754 
1755     if (res < 0) {
1756       return -1;
1757     }
1758 
1759     errno = EIO;
1760     return -1;
1761   }
1762 
1763   mark_point();
1764   pr_netio_close(nstrm);
1765   return 0;
1766 }
1767 
START_TEST(netio_printf_test)1768 START_TEST (netio_printf_test) {
1769   int res;
1770   pr_netio_t *netio;
1771 
1772   netio = pr_alloc_netio2(p, NULL, "testsuite");
1773   netio->poll = netio_poll_cb;
1774   netio->write = netio_write_cb;
1775 
1776   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1777   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1778     strerror(errno));
1779 
1780   res = netio_print_to_stream(PR_NETIO_STRM_CTRL, FALSE);
1781   fail_unless(res == 0, "Failed to print to custom ctrl NetIO: %s",
1782     strerror(errno));
1783 
1784   mark_point();
1785   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1786 }
1787 END_TEST
1788 
START_TEST(netio_printf_async_test)1789 START_TEST (netio_printf_async_test) {
1790   int res;
1791   pr_netio_t *netio;
1792 
1793   netio = pr_alloc_netio2(p, NULL, "testsuite");
1794   netio->poll = netio_poll_cb;
1795   netio->write = netio_write_cb;
1796 
1797   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1798   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1799     strerror(errno));
1800 
1801   res = netio_print_to_stream(PR_NETIO_STRM_CTRL, TRUE);
1802   fail_unless(res == 0, "Failed to print to custom ctrl NetIO: %s",
1803     strerror(errno));
1804 
1805   mark_point();
1806   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1807 }
1808 END_TEST
1809 
START_TEST(netio_abort_test)1810 START_TEST (netio_abort_test) {
1811   pr_netio_stream_t *nstrm;
1812   int fd = -1;
1813 
1814   mark_point();
1815   pr_netio_abort(NULL);
1816 
1817   /* open/abort/close CTRL stream */
1818   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
1819   fail_unless(nstrm != NULL, "Failed to open ctrl stream on fd %d: %s", fd,
1820     strerror(errno));
1821 
1822   pr_netio_abort(nstrm);
1823   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1824     "Failed to set PR_NETIO_SESS_ABORT flags on ctrl stream");
1825 
1826   pr_netio_close(nstrm);
1827 
1828   /* open/abort/close DATA stream */
1829   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_WR);
1830   fail_unless(nstrm != NULL, "Failed to open data stream on fd %d: %s", fd,
1831     strerror(errno));
1832 
1833   pr_netio_abort(nstrm);
1834   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1835     "Failed to set PR_NETIO_SESS_ABORT flags on data stream");
1836 
1837   pr_netio_close(nstrm);
1838 
1839   /* open/abort/close OTHR stream */
1840   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_WR);
1841   fail_unless(nstrm != NULL, "Failed to open othr stream on fd %d: %s", fd,
1842     strerror(errno));
1843 
1844   pr_netio_abort(nstrm);
1845   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1846     "Failed to set PR_NETIO_SESS_ABORT flags on othr stream");
1847 
1848   pr_netio_close(nstrm);
1849 }
1850 END_TEST
1851 
netio_close_cb(pr_netio_stream_t * nstrm)1852 static int netio_close_cb(pr_netio_stream_t *nstrm) {
1853   return 0;
1854 }
1855 
START_TEST(netio_lingering_abort_test)1856 START_TEST (netio_lingering_abort_test) {
1857   pr_netio_t *netio;
1858   pr_netio_stream_t *nstrm;
1859   int fd = 0, res;
1860   long linger = 0L;
1861 
1862   mark_point();
1863   res = pr_netio_lingering_abort(NULL, linger);
1864   fail_unless(res < 0, "Failed to handle null arguments");
1865   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1866     strerror(errno), errno);
1867 
1868   netio = pr_alloc_netio2(p, NULL, "testsuite");
1869   netio->close = netio_close_cb;
1870 
1871   /* open/abort/close CTRL stream */
1872   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1873   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1874     strerror(errno));
1875 
1876   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
1877   fail_unless(nstrm != NULL, "Failed to open ctrl stream on fd %d: %s", fd,
1878     strerror(errno));
1879 
1880   res = pr_netio_lingering_abort(nstrm, linger);
1881   fail_unless(res == 0, "Failed to set lingering abort on ctrl stream: %s",
1882     strerror(errno));
1883 
1884   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1885     "Failed to set PR_NETIO_SESS_ABORT flags on ctrl stream");
1886 
1887   pr_netio_close(nstrm);
1888   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1889 
1890   /* open/abort/close DATA stream */
1891   res = pr_register_netio(netio, PR_NETIO_STRM_DATA);
1892   fail_unless(res == 0, "Failed to register custom data NetIO: %s",
1893     strerror(errno));
1894 
1895   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
1896   fail_unless(nstrm != NULL, "Failed to open data stream on fd %d: %s", fd,
1897     strerror(errno));
1898 
1899   res = pr_netio_lingering_abort(nstrm, linger);
1900   fail_unless(res == 0, "Failed to set lingering abort on data stream: %s",
1901     strerror(errno));
1902 
1903   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1904     "Failed to set PR_NETIO_SESS_ABORT flags on data stream");
1905 
1906   pr_netio_close(nstrm);
1907   pr_unregister_netio(PR_NETIO_STRM_DATA);
1908 
1909   /* open/abort/close OTHR stream */
1910   res = pr_register_netio(netio, PR_NETIO_STRM_OTHR);
1911   fail_unless(res == 0, "Failed to register custom othr NetIO: %s",
1912     strerror(errno));
1913 
1914   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
1915   fail_unless(nstrm != NULL, "Failed to open othr stream on fd %d: %s", fd,
1916     strerror(errno));
1917 
1918   res = pr_netio_lingering_abort(nstrm, linger);
1919   fail_unless(res == 0, "Failed to set lingering abort on othr stream: %s",
1920     strerror(errno));
1921 
1922   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_ABORT,
1923     "Failed to set PR_NETIO_SESS_ABORT flags on othr stream");
1924 
1925   pr_netio_close(nstrm);
1926   pr_unregister_netio(PR_NETIO_STRM_OTHR);
1927 }
1928 END_TEST
1929 
START_TEST(netio_poll_interval_test)1930 START_TEST (netio_poll_interval_test) {
1931   pr_netio_stream_t *nstrm;
1932   int fd = -1;
1933   unsigned int interval = 3;
1934 
1935   mark_point();
1936   pr_netio_set_poll_interval(NULL, 0);
1937 
1938   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
1939   fail_unless(nstrm != NULL, "Failed to open ctrl stream on fd %d: %s", fd,
1940     strerror(errno));
1941 
1942   pr_netio_set_poll_interval(nstrm, interval);
1943   fail_unless(nstrm->strm_interval == interval,
1944     "Expected stream interval %u, got %u", interval, nstrm->strm_interval);
1945   fail_unless(nstrm->strm_flags & PR_NETIO_SESS_INTR,
1946     "Failed to set PR_NETIO_SESS_INTR stream flag");
1947 
1948   mark_point();
1949   pr_netio_reset_poll_interval(NULL);
1950 
1951   pr_netio_reset_poll_interval(nstrm);
1952   fail_if(nstrm->strm_flags & PR_NETIO_SESS_INTR,
1953     "Failed to clear PR_NETIO_SESS_INTR stream flag");
1954 
1955   (void) pr_netio_close(nstrm);
1956 }
1957 END_TEST
1958 
netio_shutdown_cb(pr_netio_stream_t * nstrm,int how)1959 static int netio_shutdown_cb(pr_netio_stream_t *nstrm, int how) {
1960   return 0;
1961 }
1962 
START_TEST(netio_shutdown_test)1963 START_TEST (netio_shutdown_test) {
1964   pr_netio_t *netio;
1965   pr_netio_stream_t *nstrm;
1966   int fd = 0, how = SHUT_RD, res;
1967 
1968   mark_point();
1969   res = pr_netio_shutdown(NULL, how);
1970   fail_unless(res < 0, "Failed to handle null arguments");
1971   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1972     strerror(errno), errno);
1973 
1974   netio = pr_alloc_netio2(p, NULL, "testsuite");
1975   netio->close = netio_close_cb;
1976   netio->shutdown = netio_shutdown_cb;
1977 
1978   /* open/shutdown/close CTRL stream */
1979   res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
1980   fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
1981     strerror(errno));
1982 
1983   nstrm = pr_netio_open(p, PR_NETIO_STRM_CTRL, fd, PR_NETIO_IO_RD);
1984   fail_unless(nstrm != NULL, "Failed to open ctrl stream on fd %d: %s", fd,
1985     strerror(errno));
1986 
1987   res = pr_netio_shutdown(nstrm, how);
1988   fail_unless(res == 0, "Failed to shutdown ctrl stream: %s", strerror(errno));
1989 
1990   pr_netio_close(nstrm);
1991   pr_unregister_netio(PR_NETIO_STRM_CTRL);
1992 
1993   /* open/shutdown/close DATA stream */
1994   res = pr_register_netio(netio, PR_NETIO_STRM_DATA);
1995   fail_unless(res == 0, "Failed to register custom data NetIO: %s",
1996     strerror(errno));
1997 
1998   nstrm = pr_netio_open(p, PR_NETIO_STRM_DATA, fd, PR_NETIO_IO_RD);
1999   fail_unless(nstrm != NULL, "Failed to open data stream on fd %d: %s", fd,
2000     strerror(errno));
2001 
2002   res = pr_netio_shutdown(nstrm, how);
2003   fail_unless(res == 0, "Failed to shutdown ctrl stream: %s", strerror(errno));
2004 
2005   pr_netio_close(nstrm);
2006   pr_unregister_netio(PR_NETIO_STRM_DATA);
2007 
2008   /* open/shutdown/close OTHR stream */
2009   res = pr_register_netio(netio, PR_NETIO_STRM_OTHR);
2010   fail_unless(res == 0, "Failed to register custom othr NetIO: %s",
2011     strerror(errno));
2012 
2013   nstrm = pr_netio_open(p, PR_NETIO_STRM_OTHR, fd, PR_NETIO_IO_RD);
2014   fail_unless(nstrm != NULL, "Failed to open othr stream on fd %d: %s", fd,
2015     strerror(errno));
2016 
2017   res = pr_netio_shutdown(nstrm, how);
2018   fail_unless(res == 0, "Failed to shutdown ctrl stream: %s", strerror(errno));
2019 
2020   pr_netio_close(nstrm);
2021   pr_unregister_netio(PR_NETIO_STRM_OTHR);
2022 }
2023 END_TEST
2024 
tests_get_netio_suite(void)2025 Suite *tests_get_netio_suite(void) {
2026   Suite *suite;
2027   TCase *testcase;
2028 
2029   suite = suite_create("netio");
2030 
2031   testcase = tcase_create("base");
2032   tcase_add_checked_fixture(testcase, set_up, tear_down);
2033 
2034   tcase_add_test(testcase, netio_open_test);
2035   tcase_add_test(testcase, netio_postopen_test);
2036   tcase_add_test(testcase, netio_close_test);
2037   tcase_add_test(testcase, netio_lingering_close_test);
2038   tcase_add_test(testcase, netio_reopen_test);
2039   tcase_add_test(testcase, netio_buffer_alloc_test);
2040 
2041   tcase_add_test(testcase, netio_telnet_gets_args_test);
2042   tcase_add_test(testcase, netio_telnet_gets_single_line_test);
2043   tcase_add_test(testcase, netio_telnet_gets_multi_line_test);
2044   tcase_add_test(testcase, netio_telnet_gets_no_newline_test);
2045   tcase_add_test(testcase, netio_telnet_gets_telnet_will_test);
2046   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_will_test);
2047   tcase_add_test(testcase, netio_telnet_gets_telnet_will_multi_read_test);
2048   tcase_add_test(testcase, netio_telnet_gets_telnet_wont_test);
2049   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_wont_test);
2050   tcase_add_test(testcase, netio_telnet_gets_telnet_do_test);
2051   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_do_test);
2052   tcase_add_test(testcase, netio_telnet_gets_telnet_dont_test);
2053   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_dont_test);
2054   tcase_add_test(testcase, netio_telnet_gets_telnet_ip_test);
2055   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_ip_test);
2056   tcase_add_test(testcase, netio_telnet_gets_telnet_dm_test);
2057   tcase_add_test(testcase, netio_telnet_gets_telnet_bare_dm_test);
2058   tcase_add_test(testcase, netio_telnet_gets_telnet_single_iac_test);
2059   tcase_add_test(testcase, netio_telnet_gets_bug3521_test);
2060   tcase_add_test(testcase, netio_telnet_gets_bug3697_test);
2061   tcase_add_test(testcase, netio_telnet_gets_eof_test);
2062 
2063   tcase_add_test(testcase, netio_telnet_gets2_single_line_test);
2064   tcase_add_test(testcase, netio_telnet_gets2_single_line_crnul_test);
2065   tcase_add_test(testcase, netio_telnet_gets2_single_line_lf_test);
2066 
2067   tcase_add_test(testcase, netio_read_test);
2068   tcase_add_test(testcase, netio_gets_test);
2069   tcase_add_test(testcase, netio_write_test);
2070   tcase_add_test(testcase, netio_write_async_test);
2071   tcase_add_test(testcase, netio_printf_test);
2072   tcase_add_test(testcase, netio_printf_async_test);
2073   tcase_add_test(testcase, netio_abort_test);
2074   tcase_add_test(testcase, netio_lingering_abort_test);
2075   tcase_add_test(testcase, netio_poll_interval_test);
2076   tcase_add_test(testcase, netio_shutdown_test);
2077 
2078   suite_add_tcase(suite, testcase);
2079   return suite;
2080 }
2081