fixed/improved logging
[rxpd] / src / rxpd_socket.c
1 /*
2     rxpd_socket.c - regex policy daemon
3
4   Copyright (C)
5     2007,               Christian Thaeter <ct@pipapo.org>
6
7   This program is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License as
9   published by the Free Software Foundation; either version 2 of the
10   License, or (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "rxpd.h"
23
24 struct rxpd_socket*
25 rxpd_socket_new_tcp4 (struct rxpd_base* base, const char* addr, unsigned short port)
26 {
27   struct rxpd_socket* self;
28   self = rxpd_malloc (sizeof (struct rxpd_socket));
29
30   self->base = base;
31
32   llist_init (&self->node);
33
34   errno = 0;
35
36   self->fd = socket (PF_INET, SOCK_STREAM, 0);
37   if (self->fd == -1)
38     goto esocket;
39
40   struct sockaddr_in listen_addr;
41   memset (&listen_addr, 0, sizeof (listen_addr));
42
43   listen_addr.sin_family = AF_INET;
44   if (addr)
45     {
46       if (inet_aton (addr, &listen_addr.sin_addr) == 0)
47         goto esocket;
48     }
49   else
50     listen_addr.sin_addr.s_addr = INADDR_ANY;
51
52   listen_addr.sin_port = htons(port);
53
54   static int yes = 1;
55   if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
56     goto esocket;
57
58   if (bind (self->fd, (struct sockaddr*)&listen_addr, sizeof (listen_addr)) == -1)
59     goto esocket;
60
61   if (listen (self->fd, 20) == -1)
62     goto esocket;
63
64   self->rxpd_socket_addr = rxpd_socket_tcp4addr;
65
66   self->accepter = NULL;
67   self->ev = NULL; 
68   llist_init (&self->connections);
69   llist_insert_tail (&base->sockets, &self->node);
70
71   rxpd_log (base, LOG_INFO, "Listening on tcp4:%d\n", port);
72   return self;
73
74  esocket:
75   rxpd_die ("failed creating socket: %s\n", strerror(errno));
76   /* free (self); rxpd_die never returns */
77   return NULL;
78 }
79
80 int
81 rxpd_socket_tcp4addr (struct rxpd_connection* conn, char* dst, const char* pfx, size_t size)
82 {
83   struct sockaddr_in peer;
84   socklen_t len = sizeof (peer);
85   getpeername (conn->fd, (struct sockaddr*)&peer, &len);
86
87   char* addr;
88   addr = inet_ntoa (peer.sin_addr);
89   if (sizeof (":tcp4:") + strlen (pfx) + strlen (addr) > size)
90     return 0;
91
92   strcat (dst, pfx);
93   strcat (dst, ":tcp4:");
94   strcat (dst, addr);
95   return 1;
96 }
97
98 void
99 rxpd_socket_delete (struct rxpd_socket* self)
100 {
101   if (self)
102     {
103       if (self->fd != -1)
104         close (self->fd);
105       llist_unlink (&self->node);
106       free (self);
107     }
108 }
109
110 static void
111 rxpd_socket_cleanup (void* ptr)
112 {
113   struct rxpd_socket* self = ptr;
114   rxpd_log (self->base, LOG_DEBUG, "socket thread canceled\n");
115   pth_event_free (self->ev, PTH_FREE_ALL);
116   close (self->fd);
117   self->fd = -1;
118   LLIST_WHILE_HEAD (&self->connections, m)
119     {
120       struct rxpd_connection* conn = (struct rxpd_connection*)m;
121       rxpd_connection_cancel (conn);
122     }
123 }
124
125 struct rxpd_socket*
126 rxpd_socket_join (struct rxpd_socket* self)
127 {
128   pth_join (self->accepter, NULL);
129   self->accepter = NULL;
130   return self;
131 }
132
133 struct rxpd_socket*
134 rxpd_socket_spawn (struct rxpd_socket* self)
135 {
136   if (self)
137     {
138       if (self->accepter)
139         rxpd_die ("socket thread already spawned\n");
140
141       self->accepter = pth_spawn (PTH_ATTR_DEFAULT, rxpd_socket_accept, self);
142
143       if (!self->accepter)
144         rxpd_die ("failed spawning thread\n");
145     }
146   return self;
147 }
148
149 struct rxpd_socket*
150 rxpd_socket_cancel (struct rxpd_socket* self)
151 {
152   pth_cancel (self->accepter);
153   return self;
154 }
155
156 void *
157 rxpd_socket_accept (void* ptr)
158 {
159   struct rxpd_socket* self = ptr;
160
161   self->ev = pth_event (PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, self->fd);
162
163   pth_cleanup_push (rxpd_socket_cleanup, ptr);
164
165   while (pth_wait (self->ev))
166     {
167
168       int fd = pth_accept (self->fd, NULL, 0);
169       if (fd == -1)
170         rxpd_die ("error accepting connection\n");
171
172       struct rxpd_connection* conn = rxpd_connection_new (self, fd);
173
174       char buf[512];
175       *buf = '\0';
176
177       if (self->rxpd_socket_addr (conn, buf, "", 511))
178         {
179           rxpd_log (self->base, LOG_INFO, "incoming connection '%s'\n", buf);
180           rxpd_connection_spawn (conn);
181         }
182       else
183         rxpd_log (self->base, LOG_ERR, "illegal hostname\n", buf);
184     }
185
186   /* not yet reached code */
187   rxpd_log (self->base, LOG_NOTICE, "closed\n");
188   pth_cleanup_pop (TRUE);
189   return NULL;
190 }
191