project_files/frontlib/socket.c
changeset 10017 de822cd3df3a
parent 8091 e0a76056a633
equal deleted inserted replaced
10015:4feced261c68 10017:de822cd3df3a
    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 }