source: sources/src/ioNetworkServer.cc @ 1464:3f6711617be1

Revision 1464:3f6711617be1, 12.5 KB checked in by niam, 22 months ago (diff)

{issue #58[resolved]} support for non-c++ exceptions

Line 
1/***************************************************************************
2 *            ioNetworkServer.cc
3 *
4 *  Thu Sep 20 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <arpa/inet.h>
33#include <netinet/in.h>
34#include <sys/un.h>
35#include <sys/stat.h>
36#include <sys/socket.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <unistd.h>
40
41#include <libdodo/ioNetworkServer.h>
42#include <libdodo/ioNetworkServerEx.h>
43#include <libdodo/types.h>
44#include <libdodo/ioNetworkConnection.h>
45#include <libdodo/ioNetworkExchange.h>
46#include <libdodo/xexec.h>
47#include <libdodo/ioEventDescriptor.h>
48
49using namespace dodo::io::network;
50
51#ifndef IO_WO_XEXEC
52server::__collected_data__::__collected_data__(xexec *a_executor,
53                                               short execObject) : xexec::__collected_data__(a_executor, execObject)
54{
55}
56#endif
57
58//-------------------------------------------------------------------
59
60#ifndef IO_WO_XEXEC
61server::server(server &s) : xexec(s),
62                            collectedData(this, xexec::OBJECT_IONETWORKSERVER)
63#else
64server::server(server &)
65#endif
66{
67}
68
69//-------------------------------------------------------------------
70
71server::server(short a_family,
72               short a_type) : blockInherited(false),
73                               family(a_family),
74                               type(a_type)
75#ifndef IO_WO_XEXEC
76                               ,
77                               collectedData(this, xexec::OBJECT_IONETWORKSERVER)
78#endif
79{
80}
81
82//-------------------------------------------------------------------
83
84server::~server()
85{
86    if (socket != -1) {
87        ::shutdown(socket, SHUT_RDWR);
88
89        ::close(socket);
90    }
91
92    if (unixSock.size() != 0)
93        ::unlink(unixSock.data());
94}
95
96//-------------------------------------------------------------------
97
98void
99server::restoreOptions()
100{
101    setInBufferSize(inSocketBufferSize);
102    setOutBufferSize(outSocketBufferSize);
103
104    setInTimeout(inSocketTimeout);
105    setOutTimeout(outSocketTimeout);
106
107    setLingerOption(lingerOpts, lingerSeconds);
108
109    block(blocked);
110}
111
112//-------------------------------------------------------------------
113
114void
115server::makeSocket()
116{
117    if (socket != -1) {
118        ::shutdown(socket, SHUT_RDWR);
119
120        if (::close(socket) == -1)
121            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_MAKESOCKET, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
122
123        socket = -1;
124    }
125
126    int real_domain(PF_INET), real_type(SOCK_STREAM);
127
128    switch (family) {
129        case PROTOCOL_FAMILY_IPV4:
130
131            real_domain = PF_INET;
132
133            break;
134
135        case PROTOCOL_FAMILY_IPV6:
136
137            real_domain = PF_INET6;
138
139            break;
140
141        case PROTOCOL_FAMILY_UNIX_SOCKET:
142
143            real_domain = PF_UNIX;
144
145            break;
146
147        default:
148
149            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_MAKESOCKET, exception::ERRNO_LIBDODO, SERVEREX_WRONGPARAMETER, IONETWORKSERVEREX_WRONGPARAMETER_STR, __LINE__, __FILE__);
150    }
151
152    switch (type) {
153        case TRANSFER_STREAM:
154
155            real_type = SOCK_STREAM;
156
157            break;
158
159        case TRANSFER_DATAGRAM:
160
161            real_type = SOCK_DGRAM;
162
163            break;
164
165        default:
166
167            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_MAKESOCKET, exception::ERRNO_LIBDODO, SERVEREX_WRONGPARAMETER, IONETWORKSERVEREX_WRONGPARAMETER_STR, __LINE__, __FILE__);
168    }
169
170    socket = ::socket(real_domain, real_type, 0);
171    if (socket == -1)
172        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_MAKESOCKET, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
173
174    restoreOptions();
175}
176
177//-------------------------------------------------------------------
178
179void
180server::serve(const dodo::string &host,
181              int              port,
182              int              numberOfConnections)
183{
184#ifndef IO_WO_XEXEC
185    performPreExec(OPERATION_BINDNLISTEN);
186#endif
187
188    makeSocket();
189
190    int sockFlag(1);
191    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &sockFlag, sizeof(int)) == 1)
192        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
193
194    addFlag(socketOpts, 1 << OPTION_REUSE_ADDRESS);
195
196    setLingerOption(IONETWORKCONNECTION_SOCKET_LINGER_OPTION, IONETWORKCONNECTION_SOCKET_LINGER_PERIOD);
197
198    if (family == PROTOCOL_FAMILY_IPV6) {
199        struct sockaddr_in6 sa;
200        sa.sin6_family = AF_INET6;
201        sa.sin6_port = htons(port);
202        sa.sin6_flowinfo = 0;
203        sa.sin6_scope_id = 0;
204        if (host == "*")
205            sa.sin6_addr = in6addr_any;
206        else
207            inet_pton(AF_INET6, host.data(), &sa.sin6_addr);
208
209        if (::bind(socket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
210            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
211    } else {
212        struct sockaddr_in sa;
213
214        sa.sin_family = AF_INET;
215        sa.sin_port = htons(port);
216        if (host == "*")
217            sa.sin_addr.s_addr = htonl(INADDR_ANY);
218        else
219            inet_pton(AF_INET, host.data(), &sa.sin_addr);
220
221        if (::bind(socket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
222            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
223    }
224
225    if (type == TRANSFER_STREAM)
226        if (::listen(socket, numberOfConnections) == -1)
227            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
228
229#ifndef IO_WO_XEXEC
230    performPostExec(OPERATION_BINDNLISTEN);
231#endif
232}
233
234//-------------------------------------------------------------------
235
236void
237server::serve(const dodo::string &path,
238              int              numberOfConnections,
239              bool             force)
240{
241#ifndef IO_WO_XEXEC
242    performPreExec(OPERATION_SERVE);
243#endif
244
245    makeSocket();
246
247    if (force) {
248        struct stat st;
249        if (::lstat(path.data(), &st) != -1) {
250            if (S_ISSOCK(st.st_mode))
251                ::unlink(path.data());
252            else
253                dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_LIBDODO, SERVEREX_WRONGFILENAME, IONETWORKSERVEREX_WRONGFILENAME_STR, __LINE__, __FILE__);
254        }
255    }
256
257    int sockFlag(1);
258    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &sockFlag, sizeof(int)) == -1)
259        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
260
261    addFlag(socketOpts, 1 << OPTION_REUSE_ADDRESS);
262
263    setLingerOption(IONETWORKCONNECTION_SOCKET_LINGER_OPTION, IONETWORKCONNECTION_SOCKET_LINGER_PERIOD);
264
265    struct sockaddr_un sa;
266
267    unsigned long size = path.size();
268
269    if (size >= 108)
270        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_LIBDODO, SERVEREX_LONGPATH, IONETWORKSERVEREX_LONGPATH_STR, __LINE__, __FILE__);
271
272    strncpy(sa.sun_path, path.data(), size);
273    sa.sun_family = AF_UNIX;
274
275    if (::bind(socket, (struct sockaddr *)&sa, path.size() + sizeof(sa.sun_family)) == -1)
276        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
277
278    if (::listen(socket, numberOfConnections) == -1)
279        dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_BINDNLISTEN, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
280
281    unixSock = path;
282
283#ifndef IO_WO_XEXEC
284    performPostExec(OPERATION_SERVE);
285#endif
286}
287
288//-------------------------------------------------------------------
289
290bool
291server::accept(exchange::__init__ &init,
292               __peer__           &info)
293{
294#ifndef IO_WO_XEXEC
295    performPreExec(OPERATION_ACCEPT);
296#endif
297
298    if (type != TRANSFER_STREAM) {
299        init.socket = socket;
300        init.blocked = blocked;
301        init.blockInherited = blockInherited;
302
303        return true;
304    }
305
306    int sock(-1);
307    info.host.clear();
308
309    switch (family) {
310        case PROTOCOL_FAMILY_IPV4:
311        {
312            struct sockaddr_in sa;
313            socklen_t len = sizeof(sockaddr_in);
314            sock = ::accept(socket, (sockaddr *)&sa, &len);
315
316            if (sock == -1) {
317                if (errno == EAGAIN)
318                    return false;
319                else
320                    dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
321            }
322
323            char temp[INET_ADDRSTRLEN];
324            if (inet_ntop(AF_INET, &(sa.sin_addr), temp, INET_ADDRSTRLEN) != NULL)
325                info.host = temp;
326            info.port = ntohs(sa.sin_port);
327
328            break;
329        }
330
331        case PROTOCOL_FAMILY_IPV6:
332        {
333            struct sockaddr_in6 sa;
334            socklen_t len = sizeof(sockaddr_in6);
335
336            sock = ::accept(socket, (sockaddr *)&sa, &len);
337
338            if (sock == -1) {
339                if (errno == EAGAIN)
340                    return false;
341                else
342                    dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
343            }
344
345            char temp[INET6_ADDRSTRLEN];
346            if (inet_ntop(AF_INET6, &(sa.sin6_addr), temp, INET6_ADDRSTRLEN) != NULL)
347                info.host = temp;
348            info.port = ntohs(sa.sin6_port);
349
350            break;
351        }
352
353        case PROTOCOL_FAMILY_UNIX_SOCKET:
354
355            sock = ::accept(socket, NULL, NULL);
356            if (sock == -1) {
357                if (errno == EAGAIN)
358                    return false;
359                else
360                    dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
361            }
362
363            break;
364
365        default:
366
367            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_ACCEPT, exception::ERRNO_LIBDODO, SERVEREX_WRONGPARAMETER, IONETWORKSERVEREX_WRONGPARAMETER_STR, __LINE__, __FILE__);
368    }
369
370    init.socket = sock;
371    init.blocked = blocked;
372    init.blockInherited = blockInherited;
373
374#ifndef IO_WO_XEXEC
375    performPostExec(OPERATION_ACCEPT);
376#endif
377
378    return true;
379}
380
381//-------------------------------------------------------------------
382
383bool
384server::accept(exchange::__init__ &init)
385{
386#ifndef IO_WO_XEXEC
387    performPreExec(OPERATION_ACCEPT);
388#endif
389
390    if (type != TRANSFER_STREAM) {
391        init.socket = socket;
392        init.blocked = blocked;
393        init.blockInherited = blockInherited;
394
395        return true;
396    }
397
398    int sock = ::accept(socket, NULL, NULL);
399    if (sock == -1) {
400        if (errno == EAGAIN)
401            return false;
402        else
403            dodo_throw exception::basic(exception::MODULE_IONETWORKSERVER, SERVEREX_ACCEPT, exception::ERRNO_ERRNO, errno, strerror(errno), __LINE__, __FILE__);
404    }
405
406    init.socket = sock;
407    init.blocked = blocked;
408    init.blockInherited = blockInherited;
409
410#ifndef IO_WO_XEXEC
411    performPostExec(OPERATION_ACCEPT);
412#endif
413
414    return true;
415}
416
417//-------------------------------------------------------------------
418
419int
420server::inDescriptor() const
421{
422    return socket;
423}
424
425//-------------------------------------------------------------------
426
427int
428server::outDescriptor() const
429{
430    return socket;
431}
432
433//-------------------------------------------------------------------
434
Note: See TracBrowser for help on using the repository browser.