aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/libpies.h3
-rw-r--r--lib/urlconn.c157
-rw-r--r--src/piesctl.c122
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am9
-rwxr-xr-xtests/aux/in.test22
-rw-r--r--tests/inet.at38
-rw-r--r--tests/iobuf.h141
-rw-r--r--tests/nt.c339
-rw-r--r--tests/testsuite.at1
-rw-r--r--tests/to.c50
12 files changed, 761 insertions, 123 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7b4eb42..4eb6041 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -33,6 +33,7 @@ libpies_a_SOURCES=\
33 split3.c\ 33 split3.c\
34 strtotok.c\ 34 strtotok.c\
35 url.c\ 35 url.c\
36 urlconn.c\
36 wildmatch.c 37 wildmatch.c
37 38
38libpies_a_LIBADD=\ 39libpies_a_LIBADD=\
diff --git a/lib/libpies.h b/lib/libpies.h
index 76b70fe..40364a6 100644
--- a/lib/libpies.h
+++ b/lib/libpies.h
@@ -102,5 +102,8 @@ void sockaddr_to_str (const struct sockaddr *sa, int salen,
102 size_t *plen); 102 size_t *plen);
103char *sockaddr_to_astr (const struct sockaddr *sa, int salen); 103char *sockaddr_to_astr (const struct sockaddr *sa, int salen);
104 104
105/* urlconn.c */
106int url_connect (struct pies_url *url, struct grecs_sockaddr *source_addr);
107
105 108
106 109
diff --git a/lib/urlconn.c b/lib/urlconn.c
new file mode 100644
index 0000000..5994626
--- /dev/null
+++ b/lib/urlconn.c
@@ -0,0 +1,157 @@
1/* This file is part of GNU Pies.
2 Copyright (C) 2019 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/un.h>
21#include <sys/stat.h>
22#include <netinet/in.h>
23#include <netdb.h>
24#include <errno.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <libpies.h>
28#include <grecs.h>
29
30int
31url_connect (struct pies_url *url, struct grecs_sockaddr *source_addr)
32{
33 int fd;
34 union pies_sockaddr_storage addr;
35 socklen_t socklen;
36 int flags;
37
38 if (strcmp (url->scheme, "unix") == 0
39 || strcmp (url->scheme, "file") == 0
40 || strcmp (url->scheme, "socket") == 0)
41 {
42 struct stat st;
43
44 if (url->port)
45 {
46 grecs_error (NULL, 0, _("%s: invalid connection type: "
47 "port is meaningless for UNIX sockets"),
48 url->string);
49 errno = EINVAL;
50 return -1;
51 }
52
53 if (strlen (url->path) > sizeof addr.s_un.sun_path)
54 {
55 grecs_error (NULL, 0,
56 _("%s: UNIX socket name too long"),
57 url->path);
58 errno = EINVAL;
59 return -1;
60 }
61
62 addr.s.sa_family = PF_UNIX;
63 socklen = sizeof (addr.s_un);
64 strcpy (addr.s_un.sun_path, url->path);
65
66 if (stat (url->path, &st))
67 {
68 if (errno != ENOENT)
69 {
70 grecs_error (NULL, errno, _("%s: %s failed"), url->path, "stat");
71 return -1;
72 }
73 }
74 else
75 {
76 if (!S_ISSOCK (st.st_mode))
77 {
78 grecs_error (NULL, 0, _("%s: not a socket"), url->path);
79 errno = EINVAL;
80 return -1;
81 }
82 }
83 }
84 else if (strcmp (url->scheme, "inet") == 0)
85 {
86 struct addrinfo hints;
87 struct addrinfo *res;
88 int rc;
89
90 memset (&hints, 0, sizeof (hints));
91 hints.ai_socktype = SOCK_STREAM;
92 hints.ai_flags = 0;
93 hints.ai_family = AF_INET;
94
95 rc = getaddrinfo (url->host, url->port_s, &hints, &res);
96 switch (rc)
97 {
98 case 0:
99 break;
100
101 case EAI_SYSTEM:
102 grecs_error (NULL, errno, "%s", _("cannot parse address"));
103 return -1;
104
105 case EAI_BADFLAGS:
106 case EAI_SOCKTYPE:
107 grecs_error (NULL, 0, _("%s:%d: internal error converting address"),
108 __FILE__,__LINE__);
109 return -1;
110
111 case EAI_MEMORY:
112 grecs_alloc_die ();
113
114 default:
115 grecs_error (NULL, 0, "getaddrinfo: %s", gai_strerror(rc));
116 return -1;
117 }
118
119 socklen = sizeof (addr.s_in);
120 memcpy (&addr.s_in, res->ai_addr, socklen);
121 freeaddrinfo (res);
122 }
123
124 fd = socket (addr.s.sa_family, SOCK_STREAM, 0);
125 if (fd == -1)
126 {
127 grecs_error (NULL, errno, _("%s: %s failed"), url->string, "socket");
128 return -1;
129 }
130
131 if ((flags = fcntl (fd, F_GETFD, 0)) == -1
132 || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
133 grecs_error (NULL, 0, _("%s: cannot set close-on-exec: %s"),
134 url->string, strerror (errno));
135
136 if (source_addr)
137 {
138 if (source_addr->sa->sa_family != addr.s.sa_family)
139 grecs_error (NULL, 0,
140 _("source and destination address family differ"));
141 else if (bind (fd, source_addr->sa, source_addr->len) < 0)
142 {
143 grecs_error (NULL, errno, _("%s: %s failed"), url->string, "bind");
144 close (fd);
145 return -1;
146 }
147 }
148
149 if (connect (fd, &addr.s, socklen))
150 {
151 grecs_error (NULL, errno, _("%s: %s failed"), url->string, "connect");
152 close (fd);
153 return -1;
154 }
155
156 return fd;
157}
diff --git a/src/piesctl.c b/src/piesctl.c
index 2e35aea..aa983ee 100644
--- a/src/piesctl.c
+++ b/src/piesctl.c
@@ -415,123 +415,22 @@ static struct shttp_connection *
415shttp_connect (struct pies_url *url, struct grecs_sockaddr *source_addr) 415shttp_connect (struct pies_url *url, struct grecs_sockaddr *source_addr)
416{ 416{
417 int fd; 417 int fd;
418 union pies_sockaddr_storage addr; 418 struct pies_url *conn_url;
419 socklen_t socklen;
420 int flags;
421 struct shttp_connection *conn; 419 struct shttp_connection *conn;
422 FILE *fp; 420 FILE *fp;
423
424 if (strcmp (url->scheme, "unix") == 0
425 || strcmp (url->scheme, "file") == 0
426 || strcmp (url->scheme, "socket") == 0)
427 {
428 struct stat st;
429
430 if (url->port)
431 {
432 grecs_error (NULL, 0, _("%s: invalid connection type: "
433 "port is meaningless for UNIX sockets"),
434 url->string);
435 return NULL;
436 }
437
438 if (strlen (url->path) > sizeof addr.s_un.sun_path)
439 {
440 errno = EINVAL;
441 grecs_error (NULL, 0,
442 _("%s: UNIX socket name too long"),
443 url->path);
444 return NULL;
445 }
446
447 addr.s.sa_family = PF_UNIX;
448 socklen = sizeof (addr.s_un);
449 strcpy (addr.s_un.sun_path, url->path);
450
451 if (stat (url->path, &st))
452 {
453 if (errno != ENOENT)
454 {
455 grecs_error (NULL, errno, _("%s: %s failed"), url->path, "stat");
456 return NULL;
457 }
458 }
459 else
460 {
461 if (!S_ISSOCK (st.st_mode))
462 {
463 grecs_error (NULL, 0, _("%s: not a socket"), url->path);