move accept to socket_accept itself
[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   // TODO all abort() shall become rxpd_die
35   self->fd = socket (PF_INET, SOCK_STREAM, 0);
36   if (self->fd == -1)
37     abort ();
38
39   struct sockaddr_in listen_addr;
40   memset (&listen_addr, 0, sizeof (listen_addr));
41
42   listen_addr.sin_family = AF_INET;
43   if (addr)
44     {
45       if (inet_aton (addr, &listen_addr.sin_addr) == 0)
46         abort();
47     }
48   else
49     listen_addr.sin_addr.s_addr = INADDR_ANY;
50
51   listen_addr.sin_port = htons(port);
52
53   if (bind (self->fd, (struct sockaddr*)&listen_addr, sizeof (listen_addr)) == -1)
54     abort();
55
56   static int yes = 1;
57   if (setsockopt (self->fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
58     abort ();
59
60   if (listen (self->fd, 20) == -1)
61     abort ();
62
63   self->rxpd_socket_addr = rxpd_socket_tcp4addr;
64
65   self->accepter = NULL;
66   llist_insert_tail (&base->sockets, &self->node);
67
68   rxpd_log (base, LOG_INFO, "Listening on tcp4:%d\n", port);
69   return self;
70 }
71
72 int
73 rxpd_socket_tcp4addr (struct rxpd_connection* conn, char* dst, const char* pfx, size_t size)
74 {
75   struct sockaddr_in peer;
76   socklen_t len = sizeof (peer);
77   getpeername (conn->fd, (struct sockaddr*)&peer, &len);
78
79   char* addr;
80   addr = inet_ntoa (peer.sin_addr);
81   if (sizeof (":tcp4:") + strlen (pfx) + strlen (addr) > size)
82     return 0;
83
84   strcat (dst, pfx);
85   strcat (dst, ":tcp4:");
86   strcat (dst, addr);
87   return 1;
88 }
89
90 void
91 rxpd_socket_delete (struct rxpd_socket* self)
92 {
93   if (self)
94     {
95       llist_unlink (&self->node);
96       close (self->fd);
97     }
98   free (self);
99 }
100
101 struct rxpd_socket*
102 rxpd_socket_join (struct rxpd_socket* self)
103 {
104   pth_join (self->accepter, NULL);
105   self->accepter = NULL;
106   return self;
107 }
108
109 struct rxpd_socket*
110 rxpd_socket_spawn (struct rxpd_socket* self)
111 {
112   if (self)
113     {
114       if (self->accepter)
115         rxpd_die ("socket thread already spawned\n");
116
117       self->accepter = pth_spawn (PTH_ATTR_DEFAULT, rxpd_socket_accept, self);
118
119       if (!self->accepter)
120         rxpd_die ("failed spawning thread\n");
121     }
122   return self;
123 }
124
125 void *
126 rxpd_socket_accept (void* ptr)
127 {
128   struct rxpd_socket* self = ptr;
129
130   pth_event_t ev = pth_event (PTH_EVENT_FD|PTH_UNTIL_FD_READABLE, self->fd);
131
132   // TODO cancel thread to leave the loop?
133   while (pth_wait (ev))
134     {
135       int fd = pth_accept (self->fd, NULL, 0);
136       if (fd == -1)
137         rxpd_die ("error accepting connection\n");
138
139       struct rxpd_connection* conn = rxpd_connection_new (self, fd);
140       rxpd_connection_spawn (conn);
141     }
142
143   rxpd_log (NULL, LOG_NOTICE, "closed\n");
144
145   return NULL;
146 }
147