/* * Netris -- A free networked version of T*tris * Copyright (C) 1994,1995,1996 Mark H. Weaver * * 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. * * $Id: inet.c,v 1.18 1996/02/09 08:22:13 mhw Exp $ */ #include "netris.h" #include #include #include #include #include #include #include #include #define HEADER_SIZE sizeof(netint2[2]) #ifdef INET6 # define MAX_LISTEN_SOCKS 16 #endif static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event); #ifdef INET6 static int Default_Ai_Family = PF_UNSPEC; static char str_buff[64 + NI_MAXHOST]; #endif static int sock = -1; static EventGenRec netGen = { NULL, 0, FT_read, -1, NetGenFunc, EM_net }; static char netBuf[64]; static int netBufSize, netBufGoal = HEADER_SIZE; static int isServer, lostConn, gotEndConn; ExtFunc void InitNet(int default_ai_family) { #ifdef INET6 Default_Ai_Family = default_ai_family; #endif AtExit(CloseNet); } ExtFunc int WaitForConnection(char *portStr) { #ifdef INET6 struct sockaddr_storage addr; struct addrinfo hints,*res0,*res; int gai; char serv_buf[NI_MAXSERV]; #ifdef FD_ZERO fd_set fdvar; #endif int socklistListen[MAX_LISTEN_SOCKS]; int countSock, maxSock; int i, sel; #else struct sockaddr_in addr; struct hostent *host; #endif int sockListen; int addrLen; #ifndef INET6 short port; #endif int val1; struct linger val2; #ifdef INET6 if (portStr) strncpy(serv_buf, portStr, sizeof(serv_buf)); else snprintf(serv_buf, sizeof(serv_buf), "%d", DEFAULT_PORT); #else if (portStr) port = atoi(portStr); /* XXX Error checking */ else port = DEFAULT_PORT; #endif #ifdef INET6 memset(&hints, 0, sizeof(hints)); hints.ai_family = Default_Ai_Family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; gai = getaddrinfo(NULL, serv_buf, &hints, &res0); if (gai){ snprintf(str_buff, sizeof(str_buff)-1, "getaddrinfo(): %s", gai_strerror(gai)); str_buff[sizeof(str_buff)-1] = '\0'; fatal(str_buff); } countSock = 0; maxSock = -1; #ifdef FD_ZERO FD_ZERO(&fdvar); #endif for (res=res0; res && (countSock < MAX_LISTEN_SOCKS); res=res->ai_next){ sockListen = socket(res->ai_family, res->ai_socktype, 0); if(sockListen < 0) continue; val1 = 1; setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, (void *)&val1, sizeof(val1)); if (bind(sockListen, res->ai_addr, res->ai_addrlen) < 0){ close(sockListen); continue; } if (listen(sockListen, 1) < 0){ close(sockListen); continue; } #ifdef FD_ZERO FD_SET(sockListen, &fdvar); #endif socklistListen[countSock++] = sockListen; if (maxSock < sockListen) maxSock = sockListen; #ifndef FD_ZERO #warn You do not have FD_ZERO macro, so netris listens only one socket. This should be ok, but you might want to specify the protocol with -6 or -4 option. if (countSock){ break; #endif } if (!countSock){ die("socket(),bind(),listen()"); } freeaddrinfo(res0); #ifdef FD_ZERO sockListen = -1; while(sockListen < 0){ sel = select(maxSock + 1, &fdvar, NULL, NULL, NULL); if (sel < 0){ for (i=0; ih_name) { strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1); } } #endif opponentHost[sizeof(opponentHost)-1] = 0; AddEventGen(&netGen); isServer = 1; return 0; } ExtFunc int InitiateConnection(char *hostStr, char *portStr) { #ifdef INET6 struct sockaddr_storage; struct addrinfo hints, *res0, *res; char serv_buf[NI_MAXSERV]; int gai; #else struct sockaddr_in addr; struct hostent *host; short port; #endif int mySock = -1; #ifdef INET6 if (portStr) strncpy(serv_buf, portStr, sizeof(serv_buf)); else snprintf(serv_buf, sizeof(serv_buf), "%d", DEFAULT_PORT); #else if (portStr) port = atoi(portStr); /* XXX Error checking */ else port = DEFAULT_PORT; #endif #ifdef INET6 while (mySock < 0){ memset(&hints, 0, sizeof(hints)); hints.ai_family = Default_Ai_Family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; gai = getaddrinfo(hostStr, serv_buf, &hints, &res0); if (gai){ snprintf(str_buff, sizeof(str_buff)-1, "getaddrinfo(): %s", gai_strerror(gai)); str_buff[sizeof(str_buff)-1] = '\0'; fatal(str_buff); } for (res=res0; res; res=res->ai_next){ mySock = socket(res->ai_family, res->ai_socktype, 0); if (mySock < 0) continue; if (connect(mySock, res->ai_addr, res->ai_addrlen) < 0){ close(mySock); mySock = -1; if(errno != ECONNREFUSED){ freeaddrinfo(res0); die("connect"); } else{ continue; } } if (res->ai_canonname) strncpy(opponentHost, res->ai_canonname, sizeof(opponentHost)-1); else strncpy(opponentHost, hostStr, sizeof(opponentHost)-1); opponentHost[sizeof(opponentHost)-1] = 0; break; } if (mySock < 0){ freeaddrinfo(res0); sleep(1); continue; } } #else host = gethostbyname(hostStr); if (!host) die("gethostbyname"); assert(host->h_addrtype == AF_INET); strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1); opponentHost[sizeof(opponentHost)-1] = 0; while (1){ memset(&addr, 0, sizeof(addr)); addr.sin_family = host->h_addrtype; memcpy(&addr.sin_addr, host->h_addr, host->h_length); addr.sin_port = htons(port); mySock = socket(AF_INET, SOCK_STREAM, 0); if (mySock < 0) die("socket"); if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { if (errno != ECONNREFUSED) die("connect"); close(mySock); sleep(1); continue; } break; } #endif netGen.fd = sock = mySock; AddEventGen(&netGen); return 0; } static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event) { int result; short type, size; netint2 data[2]; result = MyRead(sock, netBuf + netBufSize, netBufGoal - netBufSize); if (result < 0) { lostConn = 1; return E_lostConn; } netBufSize += result; if (netBufSize < netBufGoal) return E_none; memcpy(data, netBuf, sizeof(data)); type = ntoh2(data[0]); size = ntoh2(data[1]); if (size >= sizeof(netBuf)) fatal("Received an invalid packet (too large), possibly an attempt\n" " to exploit a vulnerability in versions before 0.52 !"); netBufGoal = size; if (netBufSize < netBufGoal) return E_none; netBufSize = 0; netBufGoal = HEADER_SIZE; event->u.net.type = type; event->u.net.size = size - HEADER_SIZE; event->u.net.data = netBuf + HEADER_SIZE; if (type == NP_endConn) { gotEndConn = 1; return E_lostConn; } else if (type == NP_byeBye) { lostConn = 1; return E_lostConn; } return E_net; } ExtFunc void CheckNetConn(void) { } ExtFunc void SendPacket(NetPacketType type, int size, void *data) { netint2 header[2]; header[0] = hton2(type); header[1] = hton2(size + HEADER_SIZE); if (MyWrite(sock, header, HEADER_SIZE) != HEADER_SIZE) die("write"); if (size > 0 && data && MyWrite(sock, data, size) != size) die("write"); } ExtFunc void CloseNet(void) { MyEvent event; if (sock >= 0) { if (!lostConn) { SendPacket(NP_endConn, 0, NULL); if (isServer) { while (!lostConn) WaitMyEvent(&event, EM_net); } else { while (!gotEndConn) WaitMyEvent(&event, EM_net); SendPacket(NP_byeBye, 0, NULL); } } close(sock); sock = -1; } if (netGen.next) RemoveEventGen(&netGen); } /* * vi: ts=4 ai * vim: noai si */