~nobuto/ubuntu/natty/synergy/merge-from-experimental

« back to all changes in this revision

Viewing changes to lib/arch/CArchNetworkBSD.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Lutz
  • Date: 2003-10-31 19:36:30 UTC
  • Revision ID: james.westby@ubuntu.com-20031031193630-knbv79x5az7qh49y
Tags: upstream-1.0.14
ImportĀ upstreamĀ versionĀ 1.0.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * synergy -- mouse and keyboard sharing utility
 
3
 * Copyright (C) 2002 Chris Schoeneman
 
4
 * 
 
5
 * This package is free software you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * found in the file COPYING that should have accompanied this file.
 
8
 * 
 
9
 * This package 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
 
 
15
#include "CArchNetworkBSD.h"
 
16
#include "CArch.h"
 
17
#include "XArchUnix.h"
 
18
#if HAVE_SYS_TYPES_H
 
19
#       include <sys/types.h>
 
20
#endif
 
21
#if HAVE_UNISTD_H
 
22
#       include <unistd.h>
 
23
#endif
 
24
#include <netinet/in.h>
 
25
#include <netdb.h>
 
26
#if !defined(TCP_NODELAY)
 
27
#       include <netinet/tcp.h>
 
28
#endif
 
29
#include <arpa/inet.h>
 
30
#include <fcntl.h>
 
31
#include <errno.h>
 
32
 
 
33
#if HAVE_POLL
 
34
#       include <sys/poll.h>
 
35
#else
 
36
#       if HAVE_SYS_SELECT_H
 
37
#               include <sys/select.h>
 
38
#       endif
 
39
#       if HAVE_SYS_TIME_H
 
40
#               include <sys/time.h>
 
41
#       endif
 
42
#endif
 
43
 
 
44
static const int s_family[] = {
 
45
        PF_UNSPEC,
 
46
        PF_INET
 
47
};
 
48
static const int s_type[] = {
 
49
        SOCK_DGRAM,
 
50
        SOCK_STREAM
 
51
};
 
52
 
 
53
//
 
54
// CArchNetworkBSD
 
55
//
 
56
 
 
57
CArchNetworkBSD::CArchNetworkBSD()
 
58
{
 
59
        // create mutex to make some calls thread safe
 
60
        m_mutex = ARCH->newMutex();
 
61
}
 
62
 
 
63
CArchNetworkBSD::~CArchNetworkBSD()
 
64
{
 
65
        ARCH->closeMutex(m_mutex);
 
66
}
 
67
 
 
68
CArchSocket
 
69
CArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
 
70
{
 
71
        // allocate socket object
 
72
        CArchSocketImpl* newSocket = new CArchSocketImpl;
 
73
 
 
74
        // create socket
 
75
        int fd = socket(s_family[family], s_type[type], 0);
 
76
        if (fd == -1) {
 
77
                throwError(errno);
 
78
        }
 
79
 
 
80
        newSocket->m_fd        = fd;
 
81
        newSocket->m_connected = false;
 
82
        newSocket->m_refCount  = 1;
 
83
        return newSocket;
 
84
}
 
85
 
 
86
CArchSocket
 
87
CArchNetworkBSD::copySocket(CArchSocket s)
 
88
{
 
89
        assert(s != NULL);
 
90
 
 
91
        // ref the socket and return it
 
92
        ARCH->lockMutex(m_mutex);
 
93
        ++s->m_refCount;
 
94
        ARCH->unlockMutex(m_mutex);
 
95
        return s;
 
96
}
 
97
 
 
98
void
 
99
CArchNetworkBSD::closeSocket(CArchSocket s)
 
100
{
 
101
        assert(s != NULL);
 
102
 
 
103
        // unref the socket and note if it should be released
 
104
        ARCH->lockMutex(m_mutex);
 
105
        const bool doClose = (--s->m_refCount == 0);
 
106
        ARCH->unlockMutex(m_mutex);
 
107
 
 
108
        // close the socket if necessary
 
109
        if (doClose) {
 
110
                do {
 
111
                        if (close(s->m_fd) == -1) {
 
112
                                // close failed
 
113
                                int err = errno;
 
114
                                if (err == EINTR) {
 
115
                                        // interrupted system call
 
116
                                        ARCH->testCancelThread();
 
117
                                        continue;
 
118
                                }
 
119
 
 
120
                                // restore the last ref and throw
 
121
                                ARCH->lockMutex(m_mutex);
 
122
                                ++s->m_refCount;
 
123
                                ARCH->unlockMutex(m_mutex);
 
124
                                throwError(err);
 
125
                        }
 
126
                } while (false);
 
127
                delete s;
 
128
        }
 
129
}
 
130
 
 
131
void
 
132
CArchNetworkBSD::closeSocketForRead(CArchSocket s)
 
133
{
 
134
        assert(s != NULL);
 
135
 
 
136
        if (shutdown(s->m_fd, 0) == -1) {
 
137
                if (errno != ENOTCONN) {
 
138
                        throwError(errno);
 
139
                }
 
140
        }
 
141
}
 
142
 
 
143
void
 
144
CArchNetworkBSD::closeSocketForWrite(CArchSocket s)
 
145
{
 
146
        assert(s != NULL);
 
147
 
 
148
        if (shutdown(s->m_fd, 1) == -1) {
 
149
                if (errno != ENOTCONN) {
 
150
                        throwError(errno);
 
151
                }
 
152
        }
 
153
}
 
154
 
 
155
void
 
156
CArchNetworkBSD::bindSocket(CArchSocket s, CArchNetAddress addr)
 
157
{
 
158
        assert(s    != NULL);
 
159
        assert(addr != NULL);
 
160
 
 
161
        if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
 
162
                throwError(errno);
 
163
        }
 
164
}
 
165
 
 
166
void
 
167
CArchNetworkBSD::listenOnSocket(CArchSocket s)
 
168
{
 
169
        assert(s != NULL);
 
170
 
 
171
        // hardcoding backlog
 
172
        if (listen(s->m_fd, 3) == -1) {
 
173
                throwError(errno);
 
174
        }
 
175
}
 
176
 
 
177
CArchSocket
 
178
CArchNetworkBSD::acceptSocket(CArchSocket s, CArchNetAddress* addr)
 
179
{
 
180
        assert(s != NULL);
 
181
 
 
182
        // if user passed NULL in addr then use scratch space
 
183
        CArchNetAddress dummy;
 
184
        if (addr == NULL) {
 
185
                addr = &dummy;
 
186
        }
 
187
 
 
188
        // create new socket and address
 
189
        CArchSocketImpl* newSocket = new CArchSocketImpl;
 
190
        *addr                      = new CArchNetAddressImpl;
 
191
 
 
192
        // accept on socket
 
193
        int fd;
 
194
        do {
 
195
                fd = accept(s->m_fd, &(*addr)->m_addr, &(*addr)->m_len);
 
196
                if (fd == -1) {
 
197
                        int err = errno;
 
198
                        if (err == EINTR) {
 
199
                                // interrupted system call
 
200
                                ARCH->testCancelThread();
 
201
                                continue;
 
202
                        }
 
203
                        if (err == ECONNABORTED) {
 
204
                                // connection was aborted;  try again
 
205
                                ARCH->testCancelThread();
 
206
                                continue;
 
207
                        }
 
208
                        delete newSocket;
 
209
                        delete *addr;
 
210
                        *addr = NULL;
 
211
                        throwError(err);
 
212
                }
 
213
        } while (false);
 
214
 
 
215
        // initialize socket
 
216
        newSocket->m_fd        = fd;
 
217
        newSocket->m_connected = true;
 
218
        newSocket->m_refCount  = 1;
 
219
 
 
220
        // discard address if not requested
 
221
        if (addr == &dummy) {
 
222
                ARCH->closeAddr(dummy);
 
223
        }
 
224
 
 
225
        return newSocket;
 
226
}
 
227
 
 
228
void
 
229
CArchNetworkBSD::connectSocket(CArchSocket s, CArchNetAddress addr)
 
230
{
 
231
        assert(s    != NULL);
 
232
        assert(addr != NULL);
 
233
 
 
234
        do {
 
235
                if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) {
 
236
                        if (errno == EINTR) {
 
237
                                // interrupted system call
 
238
                                ARCH->testCancelThread();
 
239
                                continue;
 
240
                        }
 
241
 
 
242
                        if (errno == EISCONN) {
 
243
                                // already connected
 
244
                                break;
 
245
                        }
 
246
 
 
247
                        if (errno == EAGAIN) {
 
248
                                // connecting
 
249
                                throw XArchNetworkConnecting(new XArchEvalUnix(errno));
 
250
                        }
 
251
 
 
252
                        throwError(errno);
 
253
                }
 
254
        } while (false);
 
255
 
 
256
        ARCH->lockMutex(m_mutex);
 
257
        s->m_connected = true;
 
258
        ARCH->unlockMutex(m_mutex);
 
259
}
 
260
 
 
261
#if HAVE_POLL
 
262
 
 
263
int
 
264
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
 
265
{
 
266
        assert(pe != NULL || num == 0);
 
267
 
 
268
        // return if nothing to do
 
269
        if (num == 0) {
 
270
                if (timeout > 0.0) {
 
271
                        ARCH->sleep(timeout);
 
272
                }
 
273
                return 0;
 
274
        }
 
275
 
 
276
        // allocate space for translated query
 
277
        struct pollfd* pfd = new struct pollfd[num];
 
278
 
 
279
        // translate query
 
280
        for (int i = 0; i < num; ++i) {
 
281
                pfd[i].fd     = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd;
 
282
                pfd[i].events = 0;
 
283
                if ((pe[i].m_events & kPOLLIN) != 0) {
 
284
                        pfd[i].events |= POLLIN;
 
285
                }
 
286
                if ((pe[i].m_events & kPOLLOUT) != 0) {
 
287
                        pfd[i].events |= POLLOUT;
 
288
                }
 
289
        }
 
290
 
 
291
        // do the poll
 
292
        int n;
 
293
        do {
 
294
                n = poll(pfd, num, static_cast<int>(1000.0 * timeout));
 
295
                if (n == -1) {
 
296
                        if (errno == EINTR) {
 
297
                                // interrupted system call
 
298
                                ARCH->testCancelThread();
 
299
                                continue;
 
300
                        }
 
301
                        delete[] pfd;
 
302
                        throwError(errno);
 
303
                }
 
304
        } while (false);
 
305
 
 
306
        // translate back
 
307
        for (int i = 0; i < num; ++i) {
 
308
                pe[i].m_revents = 0;
 
309
                if ((pfd[i].revents & POLLIN) != 0) {
 
310
                        pe[i].m_revents |= kPOLLIN;
 
311
                }
 
312
                if ((pfd[i].revents & POLLOUT) != 0) {
 
313
                        pe[i].m_revents |= kPOLLOUT;
 
314
                }
 
315
                if ((pfd[i].revents & POLLERR) != 0) {
 
316
                        pe[i].m_revents |= kPOLLERR;
 
317
                }
 
318
                if ((pfd[i].revents & POLLNVAL) != 0) {
 
319
                        pe[i].m_revents |= kPOLLNVAL;
 
320
                }
 
321
        }
 
322
 
 
323
        // done with translated query
 
324
        delete[] pfd;
 
325
 
 
326
        return n;
 
327
}
 
328
 
 
329
#else
 
330
 
 
331
int
 
332
CArchNetworkBSD::pollSocket(CPollEntry pe[], int num, double timeout)
 
333
{
 
334
        int i, n;
 
335
 
 
336
        do {
 
337
                // prepare sets for select
 
338
                n = 0;
 
339
                fd_set readSet, writeSet, errSet;
 
340
                fd_set* readSetP  = NULL;
 
341
                fd_set* writeSetP = NULL;
 
342
                fd_set* errSetP   = NULL;
 
343
                FD_ZERO(&readSet);
 
344
                FD_ZERO(&writeSet);
 
345
                FD_ZERO(&errSet);
 
346
                for (i = 0; i < num; ++i) {
 
347
                        // reset return flags
 
348
                        pe[i].m_revents = 0;
 
349
 
 
350
                        // set invalid flag if socket is bogus then go to next socket
 
351
                        if (pe[i].m_socket == NULL) {
 
352
                                pe[i].m_revents |= kPOLLNVAL;
 
353
                                continue;
 
354
                        }
 
355
 
 
356
                        int fdi = pe[i].m_socket->m_fd;
 
357
                        if (pe[i].m_events & kPOLLIN) {
 
358
                                FD_SET(pe[i].m_socket->m_fd, &readSet);
 
359
                                readSetP = &readSet;
 
360
                                if (fdi > n) {
 
361
                                        n = fdi;
 
362
                                }
 
363
                        }
 
364
                        if (pe[i].m_events & kPOLLOUT) {
 
365
                                FD_SET(pe[i].m_socket->m_fd, &writeSet);
 
366
                                writeSetP = &writeSet;
 
367
                                if (fdi > n) {
 
368
                                        n = fdi;
 
369
                                }
 
370
                        }
 
371
                        if (true) {
 
372
                                FD_SET(pe[i].m_socket->m_fd, &errSet);
 
373
                                errSetP = &errSet;
 
374
                                if (fdi > n) {
 
375
                                        n = fdi;
 
376
                                }
 
377
                        }
 
378
                }
 
379
 
 
380
                // if there are no sockets then don't block forever
 
381
                if (n == 0 && timeout < 0.0) {
 
382
                        timeout = 0.0;
 
383
                }
 
384
 
 
385
                // prepare timeout for select
 
386
                struct timeval timeout2;
 
387
                struct timeval* timeout2P;
 
388
                if (timeout < 0) {
 
389
                        timeout2P = NULL;
 
390
                }
 
391
                else {
 
392
                        timeout2P = &timeout2;
 
393
                        timeout2.tv_sec  = static_cast<int>(timeout);
 
394
                        timeout2.tv_usec = static_cast<int>(1.0e+6 *
 
395
                                                                                        (timeout - timeout2.tv_sec));
 
396
                }
 
397
 
 
398
                // do the select
 
399
                n = select((SELECT_TYPE_ARG1)  n + 1,
 
400
                                        SELECT_TYPE_ARG234 readSetP,
 
401
                                        SELECT_TYPE_ARG234 writeSetP,
 
402
                                        SELECT_TYPE_ARG234 errSetP,
 
403
                                        SELECT_TYPE_ARG5   timeout2P);
 
404
 
 
405
                // handle results
 
406
                if (n == -1) {
 
407
                        if (errno == EINTR) {
 
408
                                // interrupted system call
 
409
                                ARCH->testCancelThread();
 
410
                                continue;
 
411
                        }
 
412
                        throwError(errno);
 
413
                }
 
414
                n = 0;
 
415
                for (i = 0; i < num; ++i) {
 
416
                        if (pe[i].m_socket != NULL) {
 
417
                                if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) {
 
418
                                        pe[i].m_revents |= kPOLLIN;
 
419
                                }
 
420
                                if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) {
 
421
                                        pe[i].m_revents |= kPOLLOUT;
 
422
                                }
 
423
                                if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) {
 
424
                                        pe[i].m_revents |= kPOLLERR;
 
425
                                }
 
426
                        }
 
427
                        if (pe[i].m_revents != 0) {
 
428
                                ++n;
 
429
                        }
 
430
                }
 
431
        } while (false);
 
432
 
 
433
        return n;
 
434
}
 
435
 
 
436
#endif
 
437
 
 
438
size_t
 
439
CArchNetworkBSD::readSocket(CArchSocket s, void* buf, size_t len)
 
440
{
 
441
        assert(s != NULL);
 
442
 
 
443
        ssize_t n;
 
444
        do {
 
445
                n = read(s->m_fd, buf, len);
 
446
                if (n == -1) {
 
447
                        if (errno == EINTR) {
 
448
                                // interrupted system call
 
449
                                ARCH->testCancelThread();
 
450
                                continue;
 
451
                        }
 
452
                        throwError(errno);
 
453
                }
 
454
        } while (false);
 
455
        ARCH->testCancelThread();
 
456
        return n;
 
457
}
 
458
 
 
459
size_t
 
460
CArchNetworkBSD::writeSocket(CArchSocket s, const void* buf, size_t len)
 
461
{
 
462
        assert(s != NULL);
 
463
 
 
464
        ssize_t n;
 
465
        do {
 
466
                n = write(s->m_fd, buf, len);
 
467
                if (n == -1) {
 
468
                        if (errno == EINTR) {
 
469
                                // interrupted system call
 
470
                                ARCH->testCancelThread();
 
471
                                continue;
 
472
                        }
 
473
                        throwError(errno);
 
474
                }
 
475
        } while (false);
 
476
        ARCH->testCancelThread();
 
477
        return n;
 
478
}
 
479
 
 
480
void
 
481
CArchNetworkBSD::throwErrorOnSocket(CArchSocket s)
 
482
{
 
483
        assert(s != NULL);
 
484
 
 
485
        // get the error from the socket layer
 
486
        int err        = 0;
 
487
        socklen_t size = sizeof(err);
 
488
        if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, &err, &size) == -1) {
 
489
                err = errno;
 
490
        }
 
491
 
 
492
        // throw if there's an error
 
493
        if (err != 0) {
 
494
                throwError(err);
 
495
        }
 
496
}
 
497
 
 
498
bool
 
499
CArchNetworkBSD::setBlockingOnSocket(CArchSocket s, bool blocking)
 
500
{
 
501
        assert(s != NULL);
 
502
 
 
503
        int mode = fcntl(s->m_fd, F_GETFL, 0);
 
504
        if (mode == -1) {
 
505
                throwError(errno);
 
506
        }
 
507
        bool old = ((mode & O_NDELAY) == 0);
 
508
        if (blocking) {
 
509
                mode &= ~O_NDELAY;
 
510
        }
 
511
        else {
 
512
                mode |= O_NDELAY;
 
513
        }
 
514
        if (fcntl(s->m_fd, F_SETFL, mode) == -1) {
 
515
                throwError(errno);
 
516
        }
 
517
        return old;
 
518
}
 
519
 
 
520
bool
 
521
CArchNetworkBSD::setNoDelayOnSocket(CArchSocket s, bool noDelay)
 
522
{
 
523
        assert(s != NULL);
 
524
 
 
525
        // get old state
 
526
        int oflag;
 
527
        socklen_t size = sizeof(oflag);
 
528
        if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &oflag, &size) == -1) {
 
529
                throwError(errno);
 
530
        }
 
531
 
 
532
        int flag = noDelay ? 1 : 0;
 
533
        size     = sizeof(flag);
 
534
        if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, &flag, size) == -1) {
 
535
                throwError(errno);
 
536
        }
 
537
 
 
538
        return (oflag != 0);
 
539
}
 
540
 
 
541
std::string
 
542
CArchNetworkBSD::getHostName()
 
543
{
 
544
        char name[256];
 
545
        if (gethostname(name, sizeof(name)) == -1) {
 
546
                name[0] = '\0';
 
547
        }
 
548
        else {
 
549
                name[sizeof(name) - 1] = '\0';
 
550
        }
 
551
        return name;
 
552
}
 
553
 
 
554
CArchNetAddress
 
555
CArchNetworkBSD::newAnyAddr(EAddressFamily family)
 
556
{
 
557
        // allocate address
 
558
        CArchNetAddressImpl* addr = new CArchNetAddressImpl;
 
559
 
 
560
        // fill it in
 
561
        switch (family) {
 
562
        case kINET: {
 
563
                struct sockaddr_in* ipAddr =
 
564
                        reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
 
565
                ipAddr->sin_family         = AF_INET;
 
566
                ipAddr->sin_port           = 0;
 
567
                ipAddr->sin_addr.s_addr    = INADDR_ANY;
 
568
                addr->m_len                = sizeof(struct sockaddr_in);
 
569
                break;
 
570
        }
 
571
 
 
572
        default:
 
573
                delete addr;
 
574
                assert(0 && "invalid family");
 
575
        }
 
576
 
 
577
        return addr;
 
578
}
 
579
 
 
580
CArchNetAddress
 
581
CArchNetworkBSD::copyAddr(CArchNetAddress addr)
 
582
{
 
583
        assert(addr != NULL);
 
584
 
 
585
        // allocate and copy address
 
586
        return new CArchNetAddressImpl(*addr);
 
587
}
 
588
 
 
589
CArchNetAddress
 
590
CArchNetworkBSD::nameToAddr(const std::string& name)
 
591
{
 
592
        // allocate address
 
593
        CArchNetAddressImpl* addr = new CArchNetAddressImpl;
 
594
 
 
595
        // try to convert assuming an IPv4 dot notation address
 
596
        struct sockaddr_in inaddr;
 
597
        memset(&inaddr, 0, sizeof(inaddr));
 
598
        if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) {
 
599
                // it's a dot notation address
 
600
                addr->m_len       = sizeof(struct sockaddr_in);
 
601
                inaddr.sin_family = AF_INET;
 
602
                inaddr.sin_port   = 0;
 
603
                memcpy(&addr->m_addr, &inaddr, addr->m_len);
 
604
        }
 
605
 
 
606
        else {
 
607
                // mutexed address lookup (ugh)
 
608
                ARCH->lockMutex(m_mutex);
 
609
                struct hostent* info = gethostbyname(name.c_str());
 
610
                if (info == NULL) {
 
611
                        ARCH->unlockMutex(m_mutex);
 
612
                        delete addr;
 
613
                        throwNameError(h_errno);
 
614
                }
 
615
 
 
616
                // copy over address (only IPv4 currently supported)
 
617
                addr->m_len       = sizeof(struct sockaddr_in);
 
618
                inaddr.sin_family = info->h_addrtype;
 
619
                inaddr.sin_port   = 0;
 
620
                memcpy(&inaddr.sin_addr, info->h_addr_list[0], info->h_length);
 
621
                memcpy(&addr->m_addr, &inaddr, addr->m_len);
 
622
 
 
623
                // done with static buffer
 
624
                ARCH->unlockMutex(m_mutex);
 
625
        }
 
626
 
 
627
        return addr;
 
628
}
 
629
 
 
630
void
 
631
CArchNetworkBSD::closeAddr(CArchNetAddress addr)
 
632
{
 
633
        assert(addr != NULL);
 
634
 
 
635
        delete addr;
 
636
}
 
637
 
 
638
std::string
 
639
CArchNetworkBSD::addrToName(CArchNetAddress addr)
 
640
{
 
641
        assert(addr != NULL);
 
642
 
 
643
        // mutexed name lookup (ugh)
 
644
        ARCH->lockMutex(m_mutex);
 
645
        struct hostent* info = gethostbyaddr(
 
646
                                                        reinterpret_cast<const char*>(&addr->m_addr),
 
647
                                                        addr->m_len, addr->m_addr.sa_family);
 
648
        if (info == NULL) {
 
649
                ARCH->unlockMutex(m_mutex);
 
650
                throwNameError(h_errno);
 
651
        }
 
652
 
 
653
        // save (primary) name
 
654
        std::string name = info->h_name;
 
655
 
 
656
        // done with static buffer
 
657
        ARCH->unlockMutex(m_mutex);
 
658
 
 
659
        return name;
 
660
}
 
661
 
 
662
std::string
 
663
CArchNetworkBSD::addrToString(CArchNetAddress addr)
 
664
{
 
665
        assert(addr != NULL);
 
666
 
 
667
        switch (getAddrFamily(addr)) {
 
668
        case kINET: {
 
669
                struct sockaddr_in* ipAddr =
 
670
                        reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
 
671
                ARCH->lockMutex(m_mutex);
 
672
                std::string s = inet_ntoa(ipAddr->sin_addr);
 
673
                ARCH->unlockMutex(m_mutex);
 
674
                return s;
 
675
        }
 
676
 
 
677
        default:
 
678
                assert(0 && "unknown address family");
 
679
                return "";
 
680
        }
 
681
}
 
682
 
 
683
IArchNetwork::EAddressFamily
 
684
CArchNetworkBSD::getAddrFamily(CArchNetAddress addr)
 
685
{
 
686
        assert(addr != NULL);
 
687
 
 
688
        switch (addr->m_addr.sa_family) {
 
689
        case AF_INET:
 
690
                return kINET;
 
691
 
 
692
        default:
 
693
                return kUNKNOWN;
 
694
        }
 
695
}
 
696
 
 
697
void
 
698
CArchNetworkBSD::setAddrPort(CArchNetAddress addr, int port)
 
699
{
 
700
        assert(addr != NULL);
 
701
 
 
702
        switch (getAddrFamily(addr)) {
 
703
        case kINET: {
 
704
                struct sockaddr_in* ipAddr =
 
705
                        reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
 
706
                ipAddr->sin_port = htons(port);
 
707
                break;
 
708
        }
 
709
 
 
710
        default:
 
711
                assert(0 && "unknown address family");
 
712
                break;
 
713
        }
 
714
}
 
715
 
 
716
int
 
717
CArchNetworkBSD::getAddrPort(CArchNetAddress addr)
 
718
{
 
719
        assert(addr != NULL);
 
720
 
 
721
        switch (getAddrFamily(addr)) {
 
722
        case kINET: {
 
723
                struct sockaddr_in* ipAddr =
 
724
                        reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
 
725
                return ntohs(ipAddr->sin_port);
 
726
        }
 
727
 
 
728
        default:
 
729
                assert(0 && "unknown address family");
 
730
                return 0;
 
731
        }
 
732
}
 
733
 
 
734
bool
 
735
CArchNetworkBSD::isAnyAddr(CArchNetAddress addr)
 
736
{
 
737
        assert(addr != NULL);
 
738
 
 
739
        switch (getAddrFamily(addr)) {
 
740
        case kINET: {
 
741
                struct sockaddr_in* ipAddr =
 
742
                        reinterpret_cast<struct sockaddr_in*>(&addr->m_addr);
 
743
                return (ipAddr->sin_addr.s_addr == INADDR_ANY &&
 
744
                                addr->m_len == sizeof(struct sockaddr_in));
 
745
        }
 
746
 
 
747
        default:
 
748
                assert(0 && "unknown address family");
 
749
                return true;
 
750
        }
 
751
}
 
752
 
 
753
void
 
754
CArchNetworkBSD::throwError(int err)
 
755
{
 
756
        switch (err) {
 
757
        case EAGAIN:
 
758
                throw XArchNetworkWouldBlock(new XArchEvalUnix(err));
 
759
 
 
760
        case EACCES:
 
761
        case EPERM:
 
762
                throw XArchNetworkAccess(new XArchEvalUnix(err));
 
763
 
 
764
        case ENFILE:
 
765
        case EMFILE:
 
766
        case ENODEV:
 
767
        case ENOBUFS:
 
768
        case ENOMEM:
 
769
        case ENETDOWN:
 
770
#if defined(ENOSR)
 
771
        case ENOSR:
 
772
#endif
 
773
                throw XArchNetworkResource(new XArchEvalUnix(err));
 
774
 
 
775
        case EPROTOTYPE:
 
776
        case EPROTONOSUPPORT:
 
777
        case EAFNOSUPPORT:
 
778
        case EPFNOSUPPORT:
 
779
        case ESOCKTNOSUPPORT:
 
780
        case EINVAL:
 
781
        case ENOPROTOOPT:
 
782
        case EOPNOTSUPP:
 
783
        case ESHUTDOWN:
 
784
#if defined(ENOPKG)
 
785
        case ENOPKG:
 
786
#endif
 
787
                throw XArchNetworkSupport(new XArchEvalUnix(err));
 
788
 
 
789
        case EIO:
 
790
                throw XArchNetworkIO(new XArchEvalUnix(err));
 
791
 
 
792
        case EADDRNOTAVAIL:
 
793
                throw XArchNetworkNoAddress(new XArchEvalUnix(err));
 
794
 
 
795
        case EADDRINUSE:
 
796
                throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
 
797
 
 
798
        case EHOSTUNREACH:
 
799
        case ENETUNREACH:
 
800
                throw XArchNetworkNoRoute(new XArchEvalUnix(err));
 
801
 
 
802
        case ENOTCONN:
 
803
                throw XArchNetworkNotConnected(new XArchEvalUnix(err));
 
804
 
 
805
        case EPIPE:
 
806
        case ECONNABORTED:
 
807
        case ECONNRESET:
 
808
                throw XArchNetworkDisconnected(new XArchEvalUnix(err));
 
809
 
 
810
        case ECONNREFUSED:
 
811
                throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
 
812
 
 
813
        case EINPROGRESS:
 
814
        case EALREADY:
 
815
                throw XArchNetworkConnecting(new XArchEvalUnix(err));
 
816
 
 
817
        case EHOSTDOWN:
 
818
        case ETIMEDOUT:
 
819
                throw XArchNetworkTimedOut(new XArchEvalUnix(err));
 
820
 
 
821
        default:
 
822
                throw XArchNetwork(new XArchEvalUnix(err));
 
823
        }
 
824
}
 
825
 
 
826
void
 
827
CArchNetworkBSD::throwNameError(int err)
 
828
{
 
829
        static const char* s_msg[] = {
 
830
                "The specified host is unknown",
 
831
                "The requested name is valid but does not have an IP address",
 
832
                "A non-recoverable name server error occurred",
 
833
                "A temporary error occurred on an authoritative name server",
 
834
                "An unknown name server error occurred"
 
835
        };
 
836
 
 
837
        switch (err) {
 
838
        case HOST_NOT_FOUND:
 
839
                throw XArchNetworkNameUnknown(s_msg[0]);
 
840
 
 
841
        case NO_DATA:
 
842
                throw XArchNetworkNameNoAddress(s_msg[1]);
 
843
 
 
844
        case NO_RECOVERY:
 
845
                throw XArchNetworkNameFailure(s_msg[2]);
 
846
 
 
847
        case TRY_AGAIN:
 
848
                throw XArchNetworkNameUnavailable(s_msg[3]);
 
849
 
 
850
        default:
 
851
                throw XArchNetworkName(s_msg[4]);
 
852
        }
 
853
}