JackNetWinSocket.cpp 13.3 KB
Newer Older
1
/*
2
 Copyright (C) 2004-2008 Grame
3

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

9
10
11
12
 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 Lesser General Public License for more details.
13

14
15
16
 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17

18
 */
19

sletz's avatar
sletz committed
20
#include "JackError.h"
21
22
23
24
25
#include "JackNetWinSocket.h"

namespace Jack
{
    //utility *********************************************************************************************************
26
    SERVER_EXPORT int GetHostName(char * name, int size)
27
    {
28
29
30
        if (gethostname(name, size) == SOCKET_ERROR) {
            jack_error("Can't get 'hostname' : %s", strerror(NET_ERROR_CODE));
            strcpy(name, "default");
31
32
33
34
35
            return -1;
        }
        return 0;
    }

36
    win_net_error_t NetErrorList[] =
37
    {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
        E(0,                  "No error"),
        E(WSAEINTR,           "Interrupted system call"),
        E(WSAEBADF,           "Bad file number"),
        E(WSAEACCES,          "Permission denied"),
        E(WSAEFAULT,          "Bad address"),
        E(WSAEINVAL,          "Invalid argument"),
        E(WSAEMFILE,          "Too many open sockets"),
        E(WSAEWOULDBLOCK,     "Operation would block"),
        E(WSAEINPROGRESS,     "Operation now in progress"),
        E(WSAEALREADY,        "Operation already in progress"),
        E(WSAENOTSOCK,        "Socket operation on non-socket"),
        E(WSAEDESTADDRREQ,    "Destination address required"),
        E(WSAEMSGSIZE,        "Message too long"),
        E(WSAEPROTOTYPE,      "Protocol wrong type for socket"),
        E(WSAENOPROTOOPT,     "Bad protocol option"),
        E(WSAEPROTONOSUPPORT, "Protocol not supported"),
        E(WSAESOCKTNOSUPPORT, "Socket type not supported"),
        E(WSAEOPNOTSUPP,      "Operation not supported on socket"),
        E(WSAEPFNOSUPPORT,    "Protocol family not supported"),
        E(WSAEAFNOSUPPORT,    "Address family not supported"),
        E(WSAEADDRINUSE,      "Address already in use"),
        E(WSAEADDRNOTAVAIL,   "Can't assign requested address"),
        E(WSAENETDOWN,        "Network is down"),
        E(WSAENETUNREACH,     "Network is unreachable"),
        E(WSAENETRESET,       "Net connection reset"),
        E(WSAECONNABORTED,    "Software caused connection abort"),
        E(WSAECONNRESET,      "Connection reset by peer"),
        E(WSAENOBUFS,         "No buffer space available"),
        E(WSAEISCONN,         "Socket is already connected"),
        E(WSAENOTCONN,        "Socket is not connected"),
        E(WSAESHUTDOWN,       "Can't send after socket shutdown"),
        E(WSAETOOMANYREFS,    "Too many references, can't splice"),
        E(WSAETIMEDOUT,       "Connection timed out"),
        E(WSAECONNREFUSED,    "Connection refused"),
        E(WSAELOOP,           "Too many levels of symbolic links"),
        E(WSAENAMETOOLONG,    "File name too long"),
        E(WSAEHOSTDOWN,       "Host is down"),
        E(WSAEHOSTUNREACH,    "No route to host"),
        E(WSAENOTEMPTY,       "Directory not empty"),
        E(WSAEPROCLIM,        "Too many processes"),
        E(WSAEUSERS,          "Too many users"),
        E(WSAEDQUOT,          "Disc quota exceeded"),
        E(WSAESTALE,          "Stale NFS file handle"),
        E(WSAEREMOTE,         "Too many levels of remote in path"),
        E(WSASYSNOTREADY,     "Network system is unavailable"),
        E(WSAVERNOTSUPPORTED, "Winsock version out of range"),
        E(WSANOTINITIALISED,  "WSAStartup not yet called"),
        E(WSAEDISCON,         "Graceful shutdown in progress"),
        E(WSAHOST_NOT_FOUND,  "Host not found"),
        E(WSANO_DATA,         "No host data of that type was found"),
88
89
90
        { -1, NULL },
    };

91
    SERVER_EXPORT const char* PrintError(int error)
92
93
    {
        int i;
94
95
        for (i = 0; NetErrorList[i].code >= 0; ++i) {
            if (error == NetErrorList[i].code)
96
                return NetErrorList[i].msg;
97
        }
98
        return strerror(error);
99
100
101
102
103
104
105
    }

    //construct/destruct***********************************************************************************************
    JackNetWinSocket::JackNetWinSocket()
    {
        fSockfd = 0;
        fSendAddr.sin_family = AF_INET;
106
107
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
108
        fRecvAddr.sin_family = AF_INET;
109
110
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
111
112
    }

113
    JackNetWinSocket::JackNetWinSocket(const char* ip, int port)
114
115
116
117
    {
        fSockfd = 0;
        fPort = port;
        fSendAddr.sin_family = AF_INET;
118
119
120
        fSendAddr.sin_port = htons(port);
        fSendAddr.sin_addr.s_addr = inet_addr(ip);
        memset(&fSendAddr.sin_zero, 0, 8);
121
        fRecvAddr.sin_family = AF_INET;
122
123
124
        fRecvAddr.sin_port = htons(port);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
125
126
    }

127
    JackNetWinSocket::JackNetWinSocket(const JackNetWinSocket& socket)
128
129
130
131
132
133
134
    {
        fSockfd = 0;
        fPort = socket.fPort;
        fSendAddr = socket.fSendAddr;
        fRecvAddr = socket.fRecvAddr;
    }

135
136
137
138
139
    JackNetWinSocket::~JackNetWinSocket()
    {
        Close();
    }

140
    JackNetWinSocket& JackNetWinSocket::operator=(const JackNetWinSocket& socket)
141
    {
142
        if (this != &socket) {
143
144
145
146
147
            fSockfd = 0;
            fPort = socket.fPort;
            fSendAddr = socket.fSendAddr;
            fRecvAddr = socket.fRecvAddr;
        }
148
        return *this;
149
150
    }

151
152
153
    //socket***********************************************************************************************************
    int JackNetWinSocket::NewSocket()
    {
154
        if (fSockfd) {
155
156
157
            Close();
            Reset();
        }
158
        fSockfd = socket(AF_INET, SOCK_DGRAM, 0);
159
160
161
        return fSockfd;
    }

sletz's avatar
sletz committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
    bool JackNetWinSocket::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;
        }
    }

186
187
    int JackNetWinSocket::Bind()
    {
188
        return bind(fSockfd, reinterpret_cast<SOCKADDR*>(&fRecvAddr), sizeof(SOCKADDR));
189
190
    }

191
    int JackNetWinSocket::BindWith(const char* ip)
192
    {
193
        fRecvAddr.sin_addr.s_addr = inet_addr(ip);
194
195
196
        return Bind();
    }

197
    int JackNetWinSocket::BindWith(int port)
198
    {
199
        fRecvAddr.sin_port = htons(port);
200
201
202
203
204
        return Bind();
    }

    int JackNetWinSocket::Connect()
    {
205
        return connect(fSockfd, reinterpret_cast<SOCKADDR*>(&fSendAddr), sizeof(SOCKADDR));
206
207
    }

208
    int JackNetWinSocket::ConnectTo(const char* ip)
209
    {
210
        fSendAddr.sin_addr.s_addr = inet_addr(ip);
211
212
213
214
215
        return Connect();
    }

    void JackNetWinSocket::Close()
    {
216
217
        if (fSockfd)
            closesocket(fSockfd);
218
219
220
221
222
223
        fSockfd = 0;
    }

    void JackNetWinSocket::Reset()
    {
        fSendAddr.sin_family = AF_INET;
224
225
226
        fSendAddr.sin_port = htons(fPort);
        fSendAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fSendAddr.sin_zero, 0, 8);
227
        fRecvAddr.sin_family = AF_INET;
228
229
230
        fRecvAddr.sin_port = htons(fPort);
        fRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        memset(&fRecvAddr.sin_zero, 0, 8);
231
232
233
234
    }

    bool JackNetWinSocket::IsSocket()
    {
235
        return(fSockfd) ? true : false;
236
237
238
    }

    //IP/PORT***********************************************************************************************************
239
    void JackNetWinSocket::SetPort(int port)
240
241
    {
        fPort = port;
242
243
        fSendAddr.sin_port = htons(port);
        fRecvAddr.sin_port = htons(port);
244
245
246
247
248
249
250
251
    }

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

    //address***********************************************************************************************************
252
    int JackNetWinSocket::SetAddress(const char* ip, int port)
253
    {
254
255
        fSendAddr.sin_addr.s_addr = inet_addr(ip);
        fSendAddr.sin_port = htons(port);
256
257
258
259
260
        return 0;
    }

    char* JackNetWinSocket::GetSendIP()
    {
261
        return inet_ntoa(fSendAddr.sin_addr);
262
263
264
265
    }

    char* JackNetWinSocket::GetRecvIP()
    {
266
        return inet_ntoa(fRecvAddr.sin_addr);
267
268
269
    }

    //utility************************************************************************************************************
270
    int JackNetWinSocket::GetName(char* name)
271
    {
272
        return gethostname(name, 255);
273
274
    }

275
    int JackNetWinSocket::JoinMCastGroup(const char* ip)
276
277
    {
        struct ip_mreq multicast_req;
278
279
        multicast_req.imr_multiaddr.s_addr = inet_addr(ip);
        multicast_req.imr_interface.s_addr = htonl(INADDR_ANY);
280
        //12 is IP_ADD_MEMBERSHIP in winsock2 (differs from winsock1...)
281
        return SetOption(IPPROTO_IP, 12, &multicast_req, sizeof(multicast_req));
282
283
284
    }

    //options************************************************************************************************************
285
    int JackNetWinSocket::SetOption(int level, int optname, const void* optval, SOCKLEN optlen)
286
    {
287
        return setsockopt(fSockfd, level, optname, static_cast<const char*>(optval), optlen);
288
289
    }

290
    int JackNetWinSocket::GetOption(int level, int optname, void* optval, SOCKLEN* optlen)
291
    {
292
        return getsockopt(fSockfd, level, optname, static_cast<char*>(optval), optlen);
293
294
295
    }

    //tiemout************************************************************************************************************
296
    int JackNetWinSocket::SetTimeOut(int usec)
297
    {
298
        jack_log("JackNetWinSocket::SetTimeout %d usec", usec);
moret's avatar
moret committed
299

300
        //negative timeout, or exceeding 10s, return
301
        if (( usec < 0) || (usec > 10000000))
302
            return SOCKET_ERROR;
303
        int time = usec / 1000;
304
        return SetOption(SOL_SOCKET, SO_RCVTIMEO, &time, sizeof(time));
305
306
307
308
309
    }

    //local loop*********************************************************************************************************
    int JackNetWinSocket::SetLocalLoop()
    {
310
311
312
313
314
315
        //char disable = 0;
        /*
        see http://msdn.microsoft.com/en-us/library/aa916098.aspx
        Default value is TRUE. When TRUE, data that is sent from the local interface to the multicast group to
        which the socket is joined, including data sent from the same socket, will be echoed to its receive buffer.
        */
316
        char disable = 1;
317
        return SetOption(IPPROTO_IP, IP_MULTICAST_LOOP, &disable, sizeof(disable));
318
319
320
    }

    //network operations*************************************************************************************************
321
    int JackNetWinSocket::SendTo(const void* buffer, size_t nbytes, int flags)
322
    {
323
        return sendto(fSockfd, reinterpret_cast<const char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&fSendAddr), sizeof(SOCKADDR));
324
325
    }

326
    int JackNetWinSocket::SendTo(const void* buffer, size_t nbytes, int flags, const char* ip)
327
    {
328
329
        fSendAddr.sin_addr.s_addr = inet_addr(ip);
        return SendTo(buffer, nbytes, flags);
330
331
    }

332
    int JackNetWinSocket::Send(const void* buffer, size_t nbytes, int flags)
333
    {
334
        return send(fSockfd, reinterpret_cast<const char*>(buffer), nbytes, flags);
335
336
    }

337
    int JackNetWinSocket::RecvFrom(void* buffer, size_t nbytes, int flags)
338
    {
339
340
        SOCKLEN addr_len = sizeof(SOCKADDR);
        return recvfrom(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&fRecvAddr), &addr_len);
341
342
    }

343
    int JackNetWinSocket::Recv(void* buffer, size_t nbytes, int flags)
344
    {
345
        return recv(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags);
346
347
    }

348
    int JackNetWinSocket::CatchHost(void* buffer, size_t nbytes, int flags)
349
    {
350
351
        SOCKLEN addr_len = sizeof(SOCKADDR);
        return recvfrom(fSockfd, reinterpret_cast<char*>(buffer), nbytes, flags, reinterpret_cast<SOCKADDR*>(&fSendAddr), &addr_len);
352
353
354
355
    }

    net_error_t JackNetWinSocket::GetError()
    {
356
        switch (NET_ERROR_CODE)
357
        {
moret's avatar
moret committed
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
            case WSABASEERR:
                return NET_NO_ERROR;
            case WSAETIMEDOUT:
                return NET_NO_DATA;
            case WSAEWOULDBLOCK:
                return NET_NO_DATA;
            case WSAECONNREFUSED:
                return NET_CONN_ERROR;
            case WSAECONNRESET:
                return NET_CONN_ERROR;
            case WSAEACCES:
                return NET_CONN_ERROR;
            case WSAECONNABORTED:
                return NET_CONN_ERROR;
            case WSAEHOSTDOWN:
                return NET_CONN_ERROR;
            case WSAEHOSTUNREACH:
                return NET_CONN_ERROR;
            default:
                return NET_OP_ERROR;
378
379
380
381
        }
    }
}