diff options
Diffstat (limited to 'src/net.c')
-rw-r--r-- | src/net.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..efb6225 --- /dev/null +++ b/src/net.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* wydawca - automatic release submission daemon | ||
2 | Copyright (C) 2007, 2009 Sergey Poznyakoff | ||
3 | |||
4 | Wydawca is free software; you can redistribute it and/or modify it | ||
5 | under the terms of the GNU General Public License as published by the | ||
6 | Free Software Foundation; either version 3 of the License, or (at your | ||
7 | option) any later version. | ||
8 | |||
9 | Wydawca 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 along | ||
15 | with wydawca. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "wydawca.h" | ||
18 | |||
19 | static int | ||
20 | open_listener () | ||
21 | { | ||
22 | int fd; | ||
23 | |||
24 | if (listen_sockaddr.sa == NULL) | ||
25 | { | ||
26 | logmsg (LOG_CRIT, _("listener address is not configured")); | ||
27 | exit (1); | ||
28 | } | ||
29 | |||
30 | fd = socket (listen_sockaddr.sa->sa_family, SOCK_STREAM, 0); | ||
31 | if (fd == -1) | ||
32 | { | ||
33 | logmsg (LOG_CRIT, _("cannot create socket: %s"), | ||
34 | strerror(errno)); | ||
35 | exit (1); | ||
36 | } | ||
37 | if (listen_sockaddr.sa->sa_family == AF_UNIX) | ||
38 | { | ||
39 | struct stat st; | ||
40 | struct sockaddr_un *s_un = (struct sockaddr_un *) listen_sockaddr.sa; | ||
41 | if (stat (s_un->sun_path, &st)) | ||
42 | { | ||
43 | if (errno != ENOENT) | ||
44 | { | ||
45 | logmsg (LOG_CRIT, _("%s: cannot stat socket: %s"), | ||
46 | s_un->sun_path, strerror (errno)); | ||
47 | exit (1); | ||
48 | } | ||
49 | } | ||
50 | else | ||
51 | { | ||
52 | /* FIXME: Check permissions? */ | ||
53 | if (!S_ISSOCK (st.st_mode)) | ||
54 | { | ||
55 | logmsg (LOG_CRIT, _("%s: not a socket"), | ||
56 | s_un->sun_path, strerror (errno)); | ||
57 | exit (1); | ||
58 | } | ||
59 | unlink (s_un->sun_path); | ||
60 | } | ||
61 | /* FIXME: Setup umask */ | ||
62 | } | ||
63 | else | ||
64 | { | ||
65 | int yes = 1; | ||
66 | setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *) &yes, sizeof(yes)); | ||
67 | } | ||
68 | |||
69 | if (bind (fd, listen_sockaddr.sa, listen_sockaddr.len) < 0) | ||
70 | { | ||
71 | logmsg (LOG_CRIT, _("cannot bind to local address: %s"), | ||
72 | strerror (errno)); | ||
73 | close (fd); | ||
74 | exit (1); | ||
75 | } | ||
76 | if (listen (fd, 8) == -1) | ||
77 | { | ||
78 | logmsg (LOG_CRIT, "listen: %s", strerror (errno)); | ||
79 | close (fd); | ||
80 | exit (1); | ||
81 | } | ||
82 | |||
83 | return fd; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | trim_crlf (char *s) | ||
88 | { | ||
89 | size_t len = strlen (s); | ||
90 | if (len > 0 && s[len-1] == '\n') | ||
91 | { | ||
92 | s[--len] = 0; | ||
93 | if (len > 0 && s[len-1] == '\r') | ||
94 | s[--len] = 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | void | ||
99 | handle_connection (FILE *fp) | ||
100 | { | ||
101 | char *buf = NULL; | ||
102 | size_t buflen = 0; | ||
103 | const struct spool *spool; | ||
104 | char *p; | ||
105 | struct passwd *pw; | ||
106 | |||
107 | if (getline (&buf, &buflen, fp) <= 0) | ||
108 | return; | ||
109 | trim_crlf (buf); | ||
110 | if (debug_level) | ||
111 | logmsg (LOG_DEBUG, "recv: %s", buf); | ||
112 | spool = wydawca_find_spool (buf); | ||
113 | if (!spool) | ||
114 | { | ||
115 | fprintf (fp, "- Unknown service name\r\n"); | ||
116 | free (buf); | ||
117 | return; | ||
118 | } | ||
119 | else if (spool->url) | ||
120 | fprintf (fp, "+ OK, URL %s\r\n", spool->url); | ||
121 | else | ||
122 | fprintf (fp, "+ OK, spool %s\r\n", spool->tag); | ||
123 | |||
124 | if (getline (&buf, &buflen, fp) <= 0) | ||
125 | { | ||
126 | logmsg (LOG_ERR, "protocol error"); | ||
127 | free (buf); | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | if (debug_level) | ||
132 | logmsg (LOG_DEBUG, "recv: %s", buf); | ||
133 | |||
134 | p = strchr (buf, ' '); | ||
135 | if (p) | ||
136 | { | ||
137 | *p++ = 0; | ||
138 | while (*p && (*p == ' ' || *p == '\t')) | ||
139 | p++; | ||
140 | } | ||
141 | else | ||
142 | p = ""; | ||
143 | |||
144 | pw = getpwnam (buf); | ||
145 | if (pw) | ||
146 | schedule_job (spool, pw->pw_uid); | ||
147 | else | ||
148 | logmsg (LOG_ERR, "no such user: %s", buf); | ||
149 | free (buf); | ||
150 | } | ||
151 | |||
152 | static int reconfigure; | ||
153 | static int terminate; | ||
154 | |||
155 | RETSIGTYPE | ||
156 | sig_hup (int sig) | ||
157 | { | ||
158 | reconfigure = 1; | ||
159 | terminate = 1; | ||
160 | } | ||
161 | |||
162 | RETSIGTYPE | ||
163 | sig_term (int sig) | ||
164 | { | ||
165 | terminate = 1; | ||
166 | } | ||
167 | |||
168 | void | ||
169 | wydawca_listener () | ||
170 | { | ||
171 | int ctlfd = open_listener (); | ||
172 | |||
173 | job_init (); | ||
174 | signal (SIGHUP, sig_hup); | ||
175 | signal (SIGTERM, sig_term); | ||
176 | signal (SIGQUIT, sig_term); | ||
177 | signal (SIGINT, sig_term); | ||
178 | while (!terminate) | ||
179 | { | ||
180 | int fd; | ||
181 | FILE *fp; | ||
182 | int rc; | ||
183 | fd_set rset; | ||
184 | struct timeval to, *pto; | ||
185 | union { | ||
186 | struct sockaddr sa; | ||
187 | struct sockaddr_in s_in; | ||
188 | struct sockaddr_un s_un; | ||
189 | } addr; | ||
190 | socklen_t len; | ||
191 | |||
192 | job_queue_runner (); | ||
193 | FD_ZERO (&rset); | ||
194 | FD_SET (ctlfd, &rset); | ||
195 | |||
196 | if (wakeup_interval) | ||
197 | { | ||
198 | to.tv_sec = wakeup_interval; | ||
199 | to.tv_usec = 0; | ||
200 | *pto = to; | ||
201 | } | ||
202 | else | ||
203 | pto = NULL; | ||
204 | |||
205 | rc = select (ctlfd + 1, &rset, NULL, NULL, pto); | ||
206 | if (rc == 0) | ||
207 | continue; | ||
208 | else if (rc < 0) | ||
209 | { | ||
210 | if (errno == EINTR) | ||
211 | continue; | ||
212 | logmsg (LOG_ERR, "select: %s", strerror (errno)); | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | len = sizeof (addr); | ||
217 | fd = accept (ctlfd, (struct sockaddr*) &addr, &len); | ||
218 | if (fd == -1) | ||
219 | continue; | ||
220 | /* FIXME: Check if the connection is allowed */ | ||
221 | fp = fdopen (fd, "r+"); | ||
222 | handle_connection (fp); | ||
223 | fclose (fp); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | |||