23 #include <stdlib.h> |
23 #include <stdlib.h> |
24 #include <SDL_net.h> |
24 #include <SDL_net.h> |
25 #include <time.h> |
25 #include <time.h> |
26 |
26 |
27 struct _flib_tcpsocket { |
27 struct _flib_tcpsocket { |
28 TCPsocket sock; |
28 TCPsocket sock; |
29 SDLNet_SocketSet sockset; |
29 SDLNet_SocketSet sockset; |
30 }; |
30 }; |
31 |
31 |
32 struct _flib_acceptor { |
32 struct _flib_acceptor { |
33 TCPsocket sock; |
33 TCPsocket sock; |
34 uint16_t port; |
34 uint16_t port; |
35 }; |
35 }; |
36 |
36 |
37 static uint32_t getPeerIp(TCPsocket sock) { |
37 static uint32_t getPeerIp(TCPsocket sock) { |
38 IPaddress *addr = SDLNet_TCP_GetPeerAddress(sock); |
38 IPaddress *addr = SDLNet_TCP_GetPeerAddress(sock); |
39 return SDLNet_Read32(&addr->host); |
39 return SDLNet_Read32(&addr->host); |
40 } |
40 } |
41 |
41 |
42 static bool connectionIsLocal(TCPsocket sock) { |
42 static bool connectionIsLocal(TCPsocket sock) { |
43 return getPeerIp(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1 |
43 return getPeerIp(sock) == (uint32_t)((127UL<<24)+1); // 127.0.0.1 |
44 } |
44 } |
45 |
45 |
46 static flib_tcpsocket *createSocket(TCPsocket sdlsock) { |
46 static flib_tcpsocket *createSocket(TCPsocket sdlsock) { |
47 flib_tcpsocket *result = flib_calloc(1, sizeof(flib_tcpsocket)); |
47 flib_tcpsocket *result = flib_calloc(1, sizeof(flib_tcpsocket)); |
48 if(result) { |
48 if(result) { |
49 result->sock = sdlsock; |
49 result->sock = sdlsock; |
50 result->sockset = SDLNet_AllocSocketSet(1); |
50 result->sockset = SDLNet_AllocSocketSet(1); |
51 |
51 |
52 if(!result->sockset) { |
52 if(!result->sockset) { |
53 flib_log_e("Can't allocate socket: Out of memory!"); |
53 flib_log_e("Can't allocate socket: Out of memory!"); |
54 SDLNet_FreeSocketSet(result->sockset); |
54 SDLNet_FreeSocketSet(result->sockset); |
55 free(result); |
55 free(result); |
56 result = NULL; |
56 result = NULL; |
57 } else { |
57 } else { |
58 SDLNet_AddSocket(result->sockset, (SDLNet_GenericSocket)result->sock); |
58 SDLNet_AddSocket(result->sockset, (SDLNet_GenericSocket)result->sock); |
59 } |
59 } |
60 } |
60 } |
61 return result; |
61 return result; |
62 } |
62 } |
63 |
63 |
64 TCPsocket listen(uint16_t port) { |
64 TCPsocket listen(uint16_t port) { |
65 IPaddress addr; |
65 IPaddress addr; |
66 addr.host = INADDR_ANY; |
66 addr.host = INADDR_ANY; |
67 SDLNet_Write16(port, &addr.port); |
67 SDLNet_Write16(port, &addr.port); |
68 TCPsocket sock = SDLNet_TCP_Open(&addr); |
68 TCPsocket sock = SDLNet_TCP_Open(&addr); |
69 if(!sock) { |
69 if(!sock) { |
70 flib_log_w("Unable to listen on port %u: %s", (unsigned)port, SDLNet_GetError()); |
70 flib_log_w("Unable to listen on port %u: %s", (unsigned)port, SDLNet_GetError()); |
71 } |
71 } |
72 return sock; |
72 return sock; |
73 } |
73 } |
74 |
74 |
75 flib_acceptor *flib_acceptor_create(uint16_t port) { |
75 flib_acceptor *flib_acceptor_create(uint16_t port) { |
76 flib_acceptor *result = flib_calloc(1, sizeof(flib_acceptor)); |
76 flib_acceptor *result = flib_calloc(1, sizeof(flib_acceptor)); |
77 if(result) { |
77 if(result) { |
78 if(port > 0) { |
78 if(port > 0) { |
79 result->port = port; |
79 result->port = port; |
80 result->sock = listen(result->port); |
80 result->sock = listen(result->port); |
81 } else { |
81 } else { |
82 /* SDL_net does not seem to have a way to listen on a random unused port |
82 /* SDL_net does not seem to have a way to listen on a random unused port |
83 and find out which port that is, so let's try to find one ourselves. */ |
83 and find out which port that is, so let's try to find one ourselves. */ |
84 srand(time(NULL)); |
84 srand(time(NULL)); |
85 for(int i=0; !result->sock && i<1000; i++) { |
85 for(int i=0; !result->sock && i<1000; i++) { |
86 // IANA suggests using ports in the range 49152-65535 for things like this |
86 // IANA suggests using ports in the range 49152-65535 for things like this |
87 result->port = 49152+(rand()%(65536-49152)); |
87 result->port = 49152+(rand()%(65536-49152)); |
88 result->sock = listen(result->port); |
88 result->sock = listen(result->port); |
89 } |
89 } |
90 } |
90 } |
91 if(!result->sock) { |
91 if(!result->sock) { |
92 flib_log_e("Failed to create acceptor."); |
92 flib_log_e("Failed to create acceptor."); |
93 free(result); |
93 free(result); |
94 result = NULL; |
94 result = NULL; |
95 } |
95 } |
96 } |
96 } |
97 return result; |
97 return result; |
98 } |
98 } |
99 |
99 |
100 uint16_t flib_acceptor_listenport(flib_acceptor *acceptor) { |
100 uint16_t flib_acceptor_listenport(flib_acceptor *acceptor) { |
101 if(!acceptor) { |
101 if(!acceptor) { |
102 flib_log_e("Call to flib_acceptor_listenport with acceptor==null"); |
102 flib_log_e("Call to flib_acceptor_listenport with acceptor==null"); |
103 return 0; |
103 return 0; |
104 } |
104 } |
105 return acceptor->port; |
105 return acceptor->port; |
106 } |
106 } |
107 |
107 |
108 void flib_acceptor_close(flib_acceptor *acceptor) { |
108 void flib_acceptor_close(flib_acceptor *acceptor) { |
109 if(acceptor) { |
109 if(acceptor) { |
110 SDLNet_TCP_Close(acceptor->sock); |
110 SDLNet_TCP_Close(acceptor->sock); |
111 free(acceptor); |
111 free(acceptor); |
112 } |
112 } |
113 } |
113 } |
114 |
114 |
115 flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly) { |
115 flib_tcpsocket *flib_socket_accept(flib_acceptor *acceptor, bool localOnly) { |
116 flib_tcpsocket *result = NULL; |
116 flib_tcpsocket *result = NULL; |
117 if(!acceptor) { |
117 if(!acceptor) { |
118 flib_log_e("Call to flib_socket_accept with acceptor==null"); |
118 flib_log_e("Call to flib_socket_accept with acceptor==null"); |
119 } else { |
119 } else { |
120 TCPsocket sock = NULL; |
120 TCPsocket sock = NULL; |
121 while(!result && (sock = SDLNet_TCP_Accept(acceptor->sock))) { |
121 while(!result && (sock = SDLNet_TCP_Accept(acceptor->sock))) { |
122 if(localOnly && !connectionIsLocal(sock)) { |
122 if(localOnly && !connectionIsLocal(sock)) { |
123 flib_log_i("Rejected nonlocal connection attempt from %s", flib_format_ip(getPeerIp(sock))); |
123 flib_log_i("Rejected nonlocal connection attempt from %s", flib_format_ip(getPeerIp(sock))); |
124 } else { |
124 } else { |
125 result = createSocket(sock); |
125 result = createSocket(sock); |
126 } |
126 } |
127 if(!result) { |
127 if(!result) { |
128 SDLNet_TCP_Close(sock); |
128 SDLNet_TCP_Close(sock); |
129 } |
129 } |
130 } |
130 } |
131 } |
131 } |
132 return result; |
132 return result; |
133 } |
133 } |
134 |
134 |
135 flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port) { |
135 flib_tcpsocket *flib_socket_connect(const char *host, uint16_t port) { |
136 flib_tcpsocket *result = NULL; |
136 flib_tcpsocket *result = NULL; |
137 if(!host || port==0) { |
137 if(!host || port==0) { |
138 flib_log_e("Invalid parameter in flib_socket_connect"); |
138 flib_log_e("Invalid parameter in flib_socket_connect"); |
139 } else { |
139 } else { |
140 IPaddress ip; |
140 IPaddress ip; |
141 if(SDLNet_ResolveHost(&ip,host,port)==-1) { |
141 if(SDLNet_ResolveHost(&ip,host,port)==-1) { |
142 flib_log_e("SDLNet_ResolveHost: %s\n", SDLNet_GetError()); |
142 flib_log_e("SDLNet_ResolveHost: %s\n", SDLNet_GetError()); |
143 } else { |
143 } else { |
144 TCPsocket sock=SDLNet_TCP_Open(&ip); |
144 TCPsocket sock=SDLNet_TCP_Open(&ip); |
145 if(!sock) { |
145 if(!sock) { |
146 flib_log_e("SDLNet_TCP_Open: %s\n", SDLNet_GetError()); |
146 flib_log_e("SDLNet_TCP_Open: %s\n", SDLNet_GetError()); |
147 } else { |
147 } else { |
148 result = createSocket(sock); |
148 result = createSocket(sock); |
149 if(result) { |
149 if(result) { |
150 sock = NULL; |
150 sock = NULL; |
151 } |
151 } |
152 } |
152 } |
153 SDLNet_TCP_Close(sock); |
153 SDLNet_TCP_Close(sock); |
154 } |
154 } |
155 } |
155 } |
156 return result; |
156 return result; |
157 } |
157 } |
158 |
158 |
159 void flib_socket_close(flib_tcpsocket *sock) { |
159 void flib_socket_close(flib_tcpsocket *sock) { |
160 if(sock) { |
160 if(sock) { |
161 SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock); |
161 SDLNet_DelSocket(sock->sockset, (SDLNet_GenericSocket)sock->sock); |
162 SDLNet_TCP_Close(sock->sock); |
162 SDLNet_TCP_Close(sock->sock); |
163 SDLNet_FreeSocketSet(sock->sockset); |
163 SDLNet_FreeSocketSet(sock->sockset); |
164 free(sock); |
164 free(sock); |
165 } |
165 } |
166 } |
166 } |
167 |
167 |
168 int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen) { |
168 int flib_socket_nbrecv(flib_tcpsocket *sock, void *data, int maxlen) { |
169 if(!sock || (maxlen>0 && !data)) { |
169 if(!sock || (maxlen>0 && !data)) { |
170 flib_log_e("Call to flib_socket_nbrecv with sock==null or data==null"); |
170 flib_log_e("Call to flib_socket_nbrecv with sock==null or data==null"); |
171 return -1; |
171 return -1; |
172 } |
172 } |
173 int readySockets = SDLNet_CheckSockets(sock->sockset, 0); |
173 int readySockets = SDLNet_CheckSockets(sock->sockset, 0); |
174 if(readySockets>0) { |
174 if(readySockets>0) { |
175 int size = SDLNet_TCP_Recv(sock->sock, data, maxlen); |
175 int size = SDLNet_TCP_Recv(sock->sock, data, maxlen); |
176 return size>0 ? size : -1; |
176 return size>0 ? size : -1; |
177 } else if(readySockets==0) { |
177 } else if(readySockets==0) { |
178 return 0; |
178 return 0; |
179 } else { |
179 } else { |
180 flib_log_e("Error in select system call: %s", SDLNet_GetError()); |
180 flib_log_e("Error in select system call: %s", SDLNet_GetError()); |
181 return -1; |
181 return -1; |
182 } |
182 } |
183 } |
183 } |
184 |
184 |
185 int flib_socket_send(flib_tcpsocket *sock, const void *data, int len) { |
185 int flib_socket_send(flib_tcpsocket *sock, const void *data, int len) { |
186 if(!sock || (len>0 && !data)) { |
186 if(!sock || (len>0 && !data)) { |
187 flib_log_e("Call to flib_socket_send with sock==null or data==null"); |
187 flib_log_e("Call to flib_socket_send with sock==null or data==null"); |
188 return -1; |
188 return -1; |
189 } |
189 } |
190 return SDLNet_TCP_Send(sock->sock, data, len); |
190 return SDLNet_TCP_Send(sock->sock, data, len); |
191 } |
191 } |