JackNetUnixSocket.cpp 12.6 KB
Newer Older
sletz's avatar
sletz committed
1
/*
sletz's avatar
sletz committed
2
Copyright (C) 2008-2011 Romain Moret at Grame
sletz's avatar
sletz committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackNetUnixSocket.h"
sletz's avatar
sletz committed
21
22
#include <unistd.h>
#include <fcntl.h>
sletz's avatar
sletz committed
23
24

namespace Jack
25
26
{
    //utility *********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
27
    int GetHostName(char * name, int size)
28
    {
Stephane Letz's avatar
Stephane Letz committed
29
30
31
        if (gethostname(name, size) == SOCKET_ERROR) {
            jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
            strcpy(name, "default");
moret's avatar
moret committed
32
            return SOCKET_ERROR;
33
34
35
36
37
38
39
40
        }
        return 0;
    }

    //construct/destruct***********************************************************************************************
    JackNetUnixSocket::JackNetUnixSocket()
    {
        fSockfd = 0;
moret's avatar
moret committed
41
        fPort = 0;
sletz's avatar
sletz committed
42
        fTimeOut = 0;
43
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
44
45
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
46
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
47
48
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
49
50
    }

Stephane Letz's avatar
Stephane Letz committed
51
    JackNetUnixSocket::JackNetUnixSocket(const char* ip, int port)
52
53
54
    {
        fSockfd = 0;
        fPort = port;
sletz's avatar
sletz committed
55
        fTimeOut = 0;
56
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
57
58
59
        fSendAddr.sin_port = htons(port);
        inet_aton(ip, &fSendAddr.sin_addr);
        memset(&fSendAddr.sin_zero, 0, 8);
60
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
61
62
63
        fRecvAddr.sin_port = htons(port);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
64
65
    }

Stephane Letz's avatar
Stephane Letz committed
66
    JackNetUnixSocket::JackNetUnixSocket(const JackNetUnixSocket& socket)
67
    {
68
        fSockfd = 0;
sletz's avatar
sletz committed
69
        fTimeOut = 0;
70
71
72
73
74
        fPort = socket.fPort;
        fSendAddr = socket.fSendAddr;
        fRecvAddr = socket.fRecvAddr;
    }

75
76
77
78
79
    JackNetUnixSocket::~JackNetUnixSocket()
    {
        Close();
    }

Stephane Letz's avatar
Stephane Letz committed
80
    JackNetUnixSocket& JackNetUnixSocket::operator=(const JackNetUnixSocket& socket)
81
    {
Stephane Letz's avatar
Stephane Letz committed
82
        if (this != &socket) {
83
84
85
86
87
            fSockfd = 0;
            fPort = socket.fPort;
            fSendAddr = socket.fSendAddr;
            fRecvAddr = socket.fRecvAddr;
        }
88
        return *this;
89
90
    }

91
92
93
    //socket***********************************************************************************************************
    int JackNetUnixSocket::NewSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
94
        if (fSockfd) {
95
96
97
            Close();
            Reset();
        }
Stephane Letz's avatar
Stephane Letz committed
98
        fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
sletz's avatar
sletz committed
99

sletz's avatar
sletz committed
100
101
        /* Enable address reuse */
        int res, on = 1;
Stephane Letz's avatar
Stephane Letz committed
102
        if ((res = setsockopt(fSockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0) {
sletz's avatar
sletz committed
103
104
            StrError(NET_ERROR_CODE);
        }
105
106
107
        return fSockfd;
    }

Stephane Letz's avatar
Stephane Letz committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
    bool JackNetUnixSocket::IsLocal(char* ip)
    {
        if (strcmp(ip, "127.0.0.1") == 0) {
            return true;
        }

        char host_name[32];
        gethostname(host_name, sizeof(host_name));

        struct hostent* host = gethostbyname(host_name);
        if (host) {
            for (int i = 0; host->h_addr_list[i] != 0; ++i) {
                struct in_addr addr;
                memcpy(&addr, host->h_addr_list[i], sizeof(struct in_addr));
                if (strcmp(inet_ntoa(addr), ip) == 0) {
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }

132
133
    int JackNetUnixSocket::Bind()
    {
Stephane Letz's avatar
Stephane Letz committed
134
        return bind(fSockfd, reinterpret_cast<socket_address_t*>(&fRecvAddr), sizeof(socket_address_t));
135
136
    }

Stephane Letz's avatar
Stephane Letz committed
137
    int JackNetUnixSocket::BindWith(const char* ip)
138
    {
Stephane Letz's avatar
Stephane Letz committed
139
140
        int addr_conv = inet_aton(ip, &fRecvAddr.sin_addr);
        if (addr_conv < 0)
141
142
143
144
            return addr_conv;
        return Bind();
    }

Stephane Letz's avatar
Stephane Letz committed
145
    int JackNetUnixSocket::BindWith(int port)
146
    {
Stephane Letz's avatar
Stephane Letz committed
147
        fRecvAddr.sin_port = htons(port);
148
149
150
151
152
        return Bind();
    }

    int JackNetUnixSocket::Connect()
    {
Stephane Letz's avatar
Stephane Letz committed
153
        return connect(fSockfd, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
154
155
    }

Stephane Letz's avatar
Stephane Letz committed
156
    int JackNetUnixSocket::ConnectTo(const char* ip)
157
    {
Stephane Letz's avatar
Stephane Letz committed
158
159
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
        if (addr_conv < 0)
160
161
162
163
164
165
            return addr_conv;
        return Connect();
    }

    void JackNetUnixSocket::Close()
    {
Stephane Letz's avatar
Stephane Letz committed
166
167
        if (fSockfd)
            close(fSockfd);
168
169
170
171
172
173
        fSockfd = 0;
    }

    void JackNetUnixSocket::Reset()
    {
        fSendAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
174
175
176
        fSendAddr.sin_port = htons(fPort);
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
177
        fRecvAddr.sin_family = AF_INET;
Stephane Letz's avatar
Stephane Letz committed
178
179
180
        fRecvAddr.sin_port = htons(fPort);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
181
182
183
184
    }

    bool JackNetUnixSocket::IsSocket()
    {
Stephane Letz's avatar
Stephane Letz committed
185
        return(fSockfd) ? true : false;
186
187
188
    }

    //IP/PORT***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
189
    void JackNetUnixSocket::SetPort(int port)
190
191
    {
        fPort = port;
Stephane Letz's avatar
Stephane Letz committed
192
193
        fSendAddr.sin_port = htons(port);
        fRecvAddr.sin_port = htons(port);
194
195
196
197
198
199
200
201
    }

    int JackNetUnixSocket::GetPort()
    {
        return fPort;
    }

    //address***********************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
202
    int JackNetUnixSocket::SetAddress(const char* ip, int port)
203
    {
Stephane Letz's avatar
Stephane Letz committed
204
205
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
        if (addr_conv < 0)
206
            return addr_conv;
Stephane Letz's avatar
Stephane Letz committed
207
        fSendAddr.sin_port = htons(port);
208
209
210
211
212
        return 0;
    }

    char* JackNetUnixSocket::GetSendIP()
    {
Stephane Letz's avatar
Stephane Letz committed
213
        return inet_ntoa(fSendAddr.sin_addr);
214
215
216
217
    }

    char* JackNetUnixSocket::GetRecvIP()
    {
Stephane Letz's avatar
Stephane Letz committed
218
        return inet_ntoa(fRecvAddr.sin_addr);
219
220
221
    }

    //utility************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
222
    int JackNetUnixSocket::GetName(char* name)
223
    {
Stephane Letz's avatar
Stephane Letz committed
224
        return gethostname(name, 255);
225
226
    }

Stephane Letz's avatar
Stephane Letz committed
227
    int JackNetUnixSocket::JoinMCastGroup(const char* ip)
228
229
    {
        struct ip_mreq multicast_req;
Stephane Letz's avatar
Stephane Letz committed
230
231
232
        inet_aton(ip, &multicast_req.imr_multiaddr);
        multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
        return SetOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicast_req, sizeof(multicast_req));
233
234
235
    }

    //options************************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
236
    int JackNetUnixSocket::SetOption(int level, int optname, const void* optval, socklen_t optlen)
237
    {
Stephane Letz's avatar
Stephane Letz committed
238
        return setsockopt(fSockfd, level, optname, optval, optlen);
239
240
    }

Stephane Letz's avatar
Stephane Letz committed
241
    int JackNetUnixSocket::GetOption(int level, int optname, void* optval, socklen_t* optlen)
242
    {
Stephane Letz's avatar
Stephane Letz committed
243
        return getsockopt(fSockfd, level, optname, optval, optlen);
244
245
    }

moret's avatar
moret committed
246
    //timeout************************************************************************************************************
sletz's avatar
sletz committed
247
248

#if defined(__sun__) || defined(sun)
Stephane Letz's avatar
Stephane Letz committed
249
    int JackNetUnixSocket::SetTimeOut(int us)
sletz's avatar
sletz committed
250
251
252
    {
        int	flags;
        fTimeOut = us;
sletz's avatar
sletz committed
253

sletz's avatar
sletz committed
254
255
256
257
        if ((flags = fcntl(fSockfd, F_GETFL, 0)) < 0) {
		    jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_GETFL");
		    return -1;
	    }
sletz's avatar
sletz committed
258

sletz's avatar
sletz committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
	    flags |= O_NONBLOCK;
	    if (fcntl(fSockfd, F_SETFL, flags) < 0) {
		    jack_error("JackNetUnixSocket::SetTimeOut error in fcntl F_SETFL");
		    return 1;
	    }

        return 0;
    }

    int JackNetUnixSocket::WaitRead()
    {
        if (fTimeOut > 0) {

            struct timeval tv;
	        fd_set fdset;
            ssize_t	res;
sletz's avatar
sletz committed
275

sletz's avatar
sletz committed
276
277
            tv.tv_sec = fTimeOut / 1000000;
	        tv.tv_usec = fTimeOut % 1000000;
sletz's avatar
sletz committed
278

sletz's avatar
sletz committed
279
280
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
281

sletz's avatar
sletz committed
282
283
	        do {
		        res = select(fSockfd + 1, &fdset, NULL, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
284
	        } while(res < 0 && errno == EINTR);
sletz's avatar
sletz committed
285

sletz's avatar
sletz committed
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
	        if (res < 0) {
 		        return res;
            } else if (res == 0) {
                errno = ETIMEDOUT;
		        return -1;
	        }
        }

        return 0;
    }

    int JackNetUnixSocket::WaitWrite()
    {
        if (fTimeOut > 0) {

            struct timeval tv;
	        fd_set fdset;
            ssize_t	res;
sletz's avatar
sletz committed
304

sletz's avatar
sletz committed
305
            tv.tv_sec = fTimeOut / 1000000;
sletz's avatar
sletz committed
306
307
            tv.tv_usec = fTimeOut % 1000000;

sletz's avatar
sletz committed
308
309
	        FD_ZERO(&fdset);
	        FD_SET(fSockfd, &fdset);
sletz's avatar
sletz committed
310

sletz's avatar
sletz committed
311
312
	        do {
		        res = select(fSockfd + 1, NULL, &fdset, NULL, &tv);
Stephane Letz's avatar
Stephane Letz committed
313
	        } while(res < 0 && errno == EINTR);
sletz's avatar
sletz committed
314

sletz's avatar
sletz committed
315
316
317
318
319
320
321
322
323
324
325
326
	        if (res < 0) {
		        return res;
            } else if (res == 0) {
                errno = ETIMEDOUT;
		        return -1;
	        }
        }

        return 0;
    }

#else
Stephane Letz's avatar
Stephane Letz committed
327
    int JackNetUnixSocket::SetTimeOut(int us)
328
    {
Stephane Letz's avatar
Stephane Letz committed
329
        jack_log("JackNetUnixSocket::SetTimeout %d usecs", us);
moret's avatar
moret committed
330

moret's avatar
moret committed
331
        //negative timeout, or exceding 10s, return
Stephane Letz's avatar
Stephane Letz committed
332
        if ((us < 0) ||(us > 10000000))
moret's avatar
moret committed
333
            return SOCKET_ERROR;
334
        struct timeval timeout;
moret's avatar
moret committed
335

336
        //less than 1sec
Stephane Letz's avatar
Stephane Letz committed
337
        if (us < 1000000) {
338
            timeout.tv_sec = 0;
moret's avatar
moret committed
339
            timeout.tv_usec = us;
Stephane Letz's avatar
Stephane Letz committed
340
        } else {
341
        //more than 1sec
Stephane Letz's avatar
Stephane Letz committed
342
343
344
345
            float sec = static_cast<float>(us) / 1000000.f;
            timeout.tv_sec =(int) sec;
            float usec = (sec - static_cast<float>(timeout.tv_sec)) * 1000000;
            timeout.tv_usec =(int) usec;
346
        }
Stephane Letz's avatar
Stephane Letz committed
347
        return SetOption(SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
348
    }
sletz's avatar
sletz committed
349
#endif
350
351
352
353
354

    //local loop**********************************************************************************************************
    int JackNetUnixSocket::SetLocalLoop()
    {
        char disable = 0;
Stephane Letz's avatar
Stephane Letz committed
355
        return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
356
357
358
    }

    //network operations**************************************************************************************************
Stephane Letz's avatar
Stephane Letz committed
359
    int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags)
360
    {
sletz's avatar
sletz committed
361
362
363
364
    #if defined(__sun__) || defined(sun)
        if (WaitWrite() < 0)
            return -1;
    #endif
Stephane Letz's avatar
Stephane Letz committed
365
        return sendto(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), sizeof(socket_address_t));
366
367
    }

Stephane Letz's avatar
Stephane Letz committed
368
    int JackNetUnixSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
369
    {
Stephane Letz's avatar
Stephane Letz committed
370
371
        int addr_conv = inet_aton(ip, &fSendAddr.sin_addr);
        if (addr_conv < 1)
372
            return addr_conv;
sletz's avatar
sletz committed
373
374
375
376
    #if defined(__sun__) || defined(sun)
        if (WaitWrite() < 0)
            return -1;
    #endif
Stephane Letz's avatar
Stephane Letz committed
377
        return SendTo(buffer, nbytes, flags);
378
379
    }

Stephane Letz's avatar
Stephane Letz committed
380
    int JackNetUnixSocket::Send(const void* buffer, size_t nbytes, int flags)
381
    {
sletz's avatar
sletz committed
382
383
384
385
    #if defined(__sun__) || defined(sun)
        if (WaitWrite() < 0)
            return -1;
    #endif
Stephane Letz's avatar
Stephane Letz committed
386
        return send(fSockfd, buffer, nbytes, flags);
387
388
    }

Stephane Letz's avatar
Stephane Letz committed
389
    int JackNetUnixSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
390
    {
Stephane Letz's avatar
Stephane Letz committed
391
        socklen_t addr_len = sizeof(socket_address_t);
sletz's avatar
sletz committed
392
393
394
    #if defined(__sun__) || defined(sun)
        if (WaitRead() < 0)
            return -1;
sletz's avatar
sletz committed
395
    #endif
Stephane Letz's avatar
Stephane Letz committed
396
        return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fRecvAddr), &addr_len);
397
398
    }

Stephane Letz's avatar
Stephane Letz committed
399
    int JackNetUnixSocket::Recv(void* buffer, size_t nbytes, int flags)
400
    {
sletz's avatar
sletz committed
401
402
403
    #if defined(__sun__) || defined(sun)
        if (WaitRead() < 0)
            return -1;
sletz's avatar
sletz committed
404
    #endif
Stephane Letz's avatar
Stephane Letz committed
405
        return recv(fSockfd, buffer, nbytes, flags);
406
407
    }

Stephane Letz's avatar
Stephane Letz committed
408
    int JackNetUnixSocket::CatchHost(void* buffer, size_t nbytes, int flags)
409
    {
Stephane Letz's avatar
Stephane Letz committed
410
        socklen_t addr_len = sizeof(socket_address_t);
sletz's avatar
sletz committed
411
412
413
    #if defined(__sun__) || defined(sun)
        if (WaitRead() < 0)
            return -1;
sletz's avatar
sletz committed
414
    #endif
Stephane Letz's avatar
Stephane Letz committed
415
        return recvfrom(fSockfd, buffer, nbytes, flags, reinterpret_cast<socket_address_t*>(&fSendAddr), &addr_len);
416
417
418
419
    }

    net_error_t JackNetUnixSocket::GetError()
    {
Stephane Letz's avatar
Stephane Letz committed
420
        switch(errno)
421
        {
moret's avatar
moret committed
422
            case EAGAIN:
sletz's avatar
sletz committed
423
            case ETIMEDOUT:
moret's avatar
moret committed
424
                return NET_NO_DATA;
sletz's avatar
sletz committed
425

moret's avatar
moret committed
426
427
428
            case ECONNABORTED:
            case ECONNREFUSED:
            case ECONNRESET:
sletz's avatar
sletz committed
429
            case EINVAL:
moret's avatar
moret committed
430
431
            case EHOSTDOWN:
            case EHOSTUNREACH:
sletz's avatar
sletz committed
432
433
            case ENETDOWN:
            case ENETUNREACH:
moret's avatar
moret committed
434
                return NET_CONN_ERROR;
sletz's avatar
sletz committed
435

moret's avatar
moret committed
436
            default:
sletz's avatar
sletz committed
437
438
                //return NET_OP_ERROR;
                return NET_CONN_ERROR;
439
440
        }
    }
sletz's avatar
sletz committed
441
}