AREXPORT bool ArServerClient::tcpCallback(void) { if (myState == STATE_REJECTED) { myTcpSender.sendData(); ArUtil::sleep(10); return false; } if (myState == STATE_DISCONNECTED && (myHaveSlowPackets || myHaveIdlePackets)) return true; if (myState == STATE_DISCONNECTED) return false; if (myState == STATE_SENT_INTRO && myStateStart.secSince() >= 60) { ArLog::log(myVerboseLogLevel, "%sTook too long for %s to connect", myLogPrefix.c_str(), getIPString()); return false; } if (myTcpOnly && !mySentTcpOnly) { mySentTcpOnly = true; ArNetPacket sending; sending.setCommand(ArServerCommands::TCP_ONLY); sendPacketTcp(&sending); } if (!myTcpReceiver.readData()) { ArLog::log(myVerboseLogLevel, "%sTrouble receiving tcp data from %s", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return tcpCallback(); //return false; } if (!myTcpSender.sendData()) { ArLog::log(myVerboseLogLevel, "%sTrouble sending tcp data to %s", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return tcpCallback(); //return false; } return true; }
AREXPORT void ArServerClient::forceDisconnect(bool quiet) { if (!quiet) ArLog::log(ArLog::Normal, "Client from %s has been forcibly disconnected.", getIPString()); internalSwitchState(STATE_DISCONNECTED); }
/* This cannot write more than 512 number of bytes @param str the string to write to the socket @return number of bytes written **/ AREXPORT int ArSocket::writeString(const char *str, ...) { char buf[1200]; int len; int ret; myWriteStringMutex.lock(); va_list ptr; va_start(ptr, str); vsnprintf(buf, sizeof(buf), str, ptr); va_end(ptr); len = strlen(buf); if (myStringWrongEndChars) { buf[len] = '\n'; len++; buf[len] = '\r'; len++; } else { buf[len] = '\r'; len++; buf[len] = '\n'; len++; } ret = write(buf, len); buf[len] = '\0'; len++; if (ret <= 0) { if (ret < 0) ArLog::log(ArLog::Normal, "Problem sending (ret %d errno %d) to %s: %s", ret, errno, getIPString(), buf); else ArLog::log(ArLog::Normal, "Problem sending (backed up) to %s: %s", getIPString(), buf); } else if (myLogWriteStrings) ArLog::log(ArLog::Normal, "Sent to %s: %s", getIPString(), buf); myWriteStringMutex.unlock(); return ret; }
AREXPORT void ArServerClient::setIdentifier( ArServerClientIdentifier identifier) { std::string oldIPString = myIPString; myIdentifier = identifier; myIPString = myTcpSocket.getRawIPString(); if (myIdentifier.getIDString() != 0 && myIdentifier.getIDString()[0] != '\0') { myIPString += " "; myIPString += myIdentifier.getIDString(); } if (!oldIPString.empty() && oldIPString != myIPString) ArLog::log(ArLog::Normal, "%s%s changed to %s", myLogPrefix.c_str(), oldIPString.c_str(), getIPString()); myTcpSocket.setIPString(getIPString()); }
/* This cannot write more than 512 number of bytes @param str the string to write to the socket @return number of bytes written **/ AREXPORT int ArSocket::writeString(const char *str, ...) { char buf[1200]; int len; int ret; myWriteStringMutex.lock(); va_list ptr; va_start(ptr, str); vsnprintf(buf, sizeof(buf), str, ptr); va_end(ptr); if (myLogWriteStrings) ArLog::log(ArLog::Normal, "Sent to %s: %s", getIPString(), buf); len = strlen(buf); buf[len] = '\n'; len++; buf[len] = '\r'; len++; ret = write(buf, len); myWriteStringMutex.unlock(); return ret; }
AREXPORT char *ArSocket::readString(unsigned int msWait) { size_t i; int n; myReadStringMutex.lock(); myStringBufEmpty[0] = '\0'; // read one byte at a time for (i = myStringPos; i < sizeof(myStringBuf); i++) { n = read(&myStringBuf[i], 1, msWait); if (n > 0) { if (i == 0 && myStringBuf[i] < 0) { myStringGotEscapeChars = true; } if (myStringIgnoreReturn && myStringBuf[i] == '\r') { i--; continue; } if (myStringBuf[i] == '\n' || myStringBuf[i] == '\r') { if (i != 0) myStringGotComplete = true; myStringBuf[i] = '\0'; myStringPos = 0; myStringPosLast = 0; // if we have leading escape characters get rid of them if (myStringBuf[0] < 0) { int ei; myStringGotEscapeChars = true; // increment out the escape chars for (ei = 0; myStringBuf[ei] < 0 || (ei > 0 && myStringBuf[ei - 1] < 0); ei++); // okay now return the good stuff doStringEcho(); myLastStringReadTime.setToNow(); myReadStringMutex.unlock(); return &myStringBuf[ei]; } // if we don't return what we got doStringEcho(); myLastStringReadTime.setToNow(); myReadStringMutex.unlock(); return myStringBuf; } // if its not an ending character but was good keep going else continue; } // failed else if (n == 0) { myStringPos = i; myStringBuf[myStringPos] = '\0'; myReadStringMutex.unlock(); return NULL; } else // which means (n < 0) { #ifdef WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) { myStringPos = i; doStringEcho(); myReadStringMutex.unlock(); return myStringBufEmpty; } #endif #ifndef WIN32 if (errno == EAGAIN) { myStringPos = i; doStringEcho(); myReadStringMutex.unlock(); return myStringBufEmpty; } #endif perror("Error in reading from network"); myReadStringMutex.unlock(); return NULL; } } // if they want a 0 length string ArLog::log(ArLog::Normal, "Some trouble in ArSocket::readString to %s (cannot fit string into buffer?)", getIPString()); writeString("String too long"); myReadStringMutex.unlock(); return NULL; }
AREXPORT void ArServerClient::processPacket(ArNetPacket *packet, bool tcp) { std::string str; struct sockaddr_in sin; unsigned int clientUdpPort; ArNetPacket retPacket; //printf("Command number %d\n", packet->getCommand()); // if we're in intro mode and received back the intro if (myState == STATE_SENT_INTRO && packet->getCommand() == ArClientCommands::INTRODUCTION) { char user[512]; unsigned char password[16]; clientUdpPort = packet->bufToUByte2(); packet->bufToStr(user, sizeof(user)); packet->bufToData((char *)password, 16); if (myRejecting != 0) { retPacket.empty(); retPacket.setCommand(ArServerCommands::REJECTED); retPacket.byte2ToBuf(myRejecting); retPacket.strToBuf(myRejectingString.c_str()); sendPacketTcp(&retPacket); if (myRejecting == 2) ArLog::log(ArLog::Normal, "%sRejected connection from %s since we're using a central server at %s", myLogPrefix.c_str(), getIPString(), myRejectingString.c_str()); internalSwitchState(STATE_REJECTED); return; } // if user info is NULL we're not checking passwords if (myUserInfo != NULL && !myUserInfo->matchUserPassword(user, password, myPasswordKey.c_str(), myServerKey.c_str(), myLogPasswordFailureVerbosely)) { retPacket.empty(); retPacket.setCommand(ArServerCommands::REJECTED); retPacket.byte2ToBuf(1); retPacket.strToBuf(""); sendPacketTcp(&retPacket); ArLog::log(ArLog::Normal, "%sRejected user '%s' or password from %s", myLogPrefix.c_str(), user, getIPString()); internalSwitchState(STATE_REJECTED); return; } if (myUserInfo != NULL) myGroups = myUserInfo->getUsersGroups(user); else myGroups.clear(); sin.sin_family = AF_INET; sin.sin_addr = *myTcpSocket.inAddr(); sin.sin_port = ArSocket::hostToNetOrder(clientUdpPort); if (myUserInfo != NULL) ArLog::log(ArLog::Normal, "%sClient connected from %s with user %s", myLogPrefix.c_str(), getIPString(), user); else ArLog::log(ArLog::Normal, "%sClient connected from %s", myLogPrefix.c_str(), getIPString()); setUdpAddress(&sin); // send that we've connected retPacket.empty(); retPacket.setCommand(ArServerCommands::CONNECTED); sendPacketTcp(&retPacket); // note that we're connected internalSwitchState(STATE_CONNECTED); // send them the list sendListPacket(); // send the udp introduction if we're using udp if (!myTcpOnly) { retPacket.empty(); retPacket.setCommand(ArServerCommands::UDP_INTRODUCTION); retPacket.byte4ToBuf(myIntroKey); sendPacketUdp(&retPacket); } } // if we aren't in intro mode and got an intro somethings wrong else if (packet->getCommand() == ArClientCommands::INTRODUCTION) { ArLog::log(ArLog::Terse, "%sReceived introduction when not in intro mode", myLogPrefix.c_str()); return; } // if we got this over tcp then they only want tcp else if (packet->getCommand() == ArClientCommands::UDP_INTRODUCTION) { if (!myTcpOnly) { ArLog::log(ArLog::Normal, "%sGot UDP introduction over tcp, assuming client only wants tcp data.", myLogPrefix.c_str()); myTcpOnly = true; } return; } // if we're connected and got a udp confirmation else if ((myState == STATE_CONNECTED || myState == STATE_SENT_INTRO) && packet->getCommand() == ArClientCommands::UDP_CONFIRMATION) { myUdpConfirmedTo = true; ArLog::log(myVerboseLogLevel, "%s: udp connection to client confirmed.", myLogPrefix.c_str()); return; } // if we're not connected (or close) and got a confirmation else if (packet->getCommand() == ArClientCommands::UDP_CONFIRMATION) { ArLog::log(ArLog::Normal, "%sReceived udp confirmation when not connected.", myLogPrefix.c_str()); return; } else if (packet->getCommand() == ArClientCommands::TCP_ONLY) { ArLog::log(myVerboseLogLevel, "%sClient only wants tcp data.", myLogPrefix.c_str()); myTcpOnly = true; return; } else if (packet->getCommand() == ArClientCommands::SHUTDOWN) { ArLog::log(ArLog::Normal, "%sClient from %s has disconnected.", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return; } // if we're connected its a request, then set all that up else if (myState == STATE_CONNECTED && packet->getCommand() == ArClientCommands::REQUEST) { std::list<ArServerClientData *>::iterator it; ArServerClientData *data; ArServerData *serverData; unsigned int command; long mSec; // see which one they requested command = packet->bufToUByte2(); mSec = packet->bufToByte4(); // first we see if we already have this one for (it = myRequested.begin(); it != myRequested.end(); ++it) { data = (*it); serverData = data->getServerData(); if (serverData->getCommand() == command) { trackPacketReceived(packet, command); data->setMSec(mSec); data->setPacket(packet); data->getPacket()->setCommand(command); serverData->callRequestChangedFunctor(); ArLog::log(myVerboseLogLevel, "%sRevised request for command %s to %d mSec with new argument", myLogPrefix.c_str(), findCommandName(serverData->getCommand()), mSec); return; } } // we didn't have it, so make a new one std::map<unsigned int, ArServerData *>::iterator sdit; if ((sdit = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sGot request for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } serverData = (*sdit).second; if (serverData == NULL) { ArLog::log(ArLog::Terse, "%sprocessPackets request handler has NULL serverData", myLogPrefix.c_str()); } if (myUserInfo != NULL && serverData->getCommandGroup() != NULL && serverData->getCommandGroup()[0] != '\0' && myGroups.count(serverData->getCommandGroup()) == 0 && myGroups.count("all") == 0) { ArLog::log(ArLog::Normal, "%s%s tried to request command '%s' but it doesn't have access to that command", myLogPrefix.c_str(), getIPString(), serverData->getName()); return; } trackPacketReceived(packet, command); data = new ArServerClientData(serverData, mSec, packet); data->getPacket()->setCommand(command); ArLog::log(myVerboseLogLevel, "%sadded request for command %s every %d mSec", myLogPrefix.c_str(), serverData->getName(), mSec); if (mSec == 0) ArLog::log(ArLog::Normal, "%sClient from %s requested command %s every at 0 msec", myLogPrefix.c_str(), getIPString(), serverData->getName()); myRequested.push_front(data); serverData->callRequestChangedFunctor(); pushCommand(command); pushForceTcpFlag(false); if (serverData->getFunctor() != NULL) serverData->getFunctor()->invoke(this, data->getPacket()); popCommand(); popForceTcpFlag(); return; } // if we got a request when we're not connected else if (packet->getCommand() == ArClientCommands::REQUEST) { ArLog::log(ArLog::Normal, "Got a request while not connected.", myLogPrefix.c_str()); return; } // if we're connected its a requestStop, then set all that up else if (myState == STATE_CONNECTED && packet->getCommand() == ArClientCommands::REQUESTSTOP) { std::list<ArServerClientData *>::iterator it; ArServerClientData *data; ArServerData *serverData; unsigned int command; // see which one they requested command = packet->bufToUByte2(); // first we see if we have this one for (it = myRequested.begin(); it != myRequested.end(); ++it) { data = (*it); serverData = data->getServerData(); // we have a match, so set the new params then return if (data->getServerData()->getCommand() == command) { trackPacketReceived(packet, command); myRequested.erase(it); ArLog::log(myVerboseLogLevel, "%sStopped request for command %s", myLogPrefix.c_str(), findCommandName(serverData->getCommand())); delete data; serverData->callRequestChangedFunctor(); return; } } // if we don't have it... that means that it wasn't here // find out what to call it std::map<unsigned int, ArServerData *>::iterator sdit; if ((sdit = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sGot a requeststop for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } trackPacketReceived(packet, command); serverData = (*sdit).second; if (serverData == NULL) ArLog::log(ArLog::Terse, "%srequeststop handler has NULL serverData on back command %d", myLogPrefix.c_str(), command); else ArLog::log(ArLog::Normal, "%s: Got a stop request for command %s that isn't requested", myLogPrefix.c_str(), serverData->getName()); return; } // if we got a requestStop when we're not connected else if (packet->getCommand() == ArClientCommands::REQUESTSTOP) { ArLog::log(ArLog::Normal, "%sGot a requeststop while not connected.", myLogPrefix.c_str()); return; } // if we're connected and its a command to execute just once else if (myState == STATE_CONNECTED) { unsigned int command; std::map<unsigned int, ArServerData *>::iterator it; ArServerData *serverData; command = packet->getCommand(); if ((it = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sArServerClient got request for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } serverData = (*it).second; if (myUserInfo != NULL && serverData->getCommandGroup() != NULL && serverData->getCommandGroup()[0] != '\0' && myGroups.count(serverData->getCommandGroup()) == 0 && myGroups.count("all") == 0) { ArLog::log(ArLog::Normal, "%s%s tried to request command '%s' once but it doesn't have access to that command", myLogPrefix.c_str(), getIPString(), serverData->getName()); return; } trackPacketReceived(packet, command); // copy it out and return if its an idle packet if (myAllowIdlePackets && serverData->isIdlePacket()) { myHaveIdlePackets = true; if (command <= 255) ArLog::log(myVerboseLogLevel, "%sStoring idle command %d", myLogPrefix.c_str(), command); else ArLog::log(myVerboseLogLevel, "%sStoring idle command %s", myLogPrefix.c_str(), serverData->getName()); myIdlePacketsMutex.lock(); ArNetPacket *idlePacket = new ArNetPacket(packet->getLength() + 5); idlePacket->duplicatePacket(packet); myIdlePackets.push_back(idlePacket); myIdlePacketsMutex.unlock(); return; } // If its a slow or an idle packet (and we're not allowing the // idle behavior) and we allow slow packets then copy it else if (myAllowSlowPackets && (serverData->isSlowPacket() || serverData->isIdlePacket())) { myHaveSlowPackets = true; if (command <= 255) ArLog::log(myVerboseLogLevel, "%sStoring slow command %d", myLogPrefix.c_str(), command); else ArLog::log(myVerboseLogLevel, "%sStoring slow command %s", myLogPrefix.c_str(), serverData->getName()); mySlowPacketsMutex.lock(); ArNetPacket *slowPacket = new ArNetPacket(packet->getLength() + 5); slowPacket->duplicatePacket(packet); mySlowPackets.push_back(slowPacket); mySlowPacketsMutex.unlock(); return; } if (command <= 255) ArLog::log(myVerboseLogLevel, "%sGot command %s", myLogPrefix.c_str(), serverData->getName()); else ArLog::log(ArLog::Verbose, "%sGot command %s", myLogPrefix.c_str(), serverData->getName()); pushCommand(command); pushForceTcpFlag(tcp); if (serverData->getFunctor() != NULL) serverData->getFunctor()->invoke(this, packet); if (serverData->getRequestOnceFunctor() != NULL) serverData->getRequestOnceFunctor()->invoke(this, packet); popCommand(); popForceTcpFlag(); return; } else { ArLog::log(ArLog::Terse, "%sRogue packet command %s in state %d", myLogPrefix.c_str(), findCommandName(packet->getCommand()), myState); } }
AREXPORT void ArServerClient::logTracking(bool terse) { std::map<ArTypes::UByte2, Tracker *>::iterator it; ArTypes::UByte2 command; Tracker *tracker = NULL; long seconds; seconds = myTrackingStarted.secSince(); if (seconds == 0) seconds = 1; char name[512]; long packetsReceivedTcp = 0; long bytesReceivedTcp = 0; long packetsReceivedUdp = 0; long bytesReceivedUdp = 0; ArLog::log(ArLog::Terse, ""); ArLog::log(ArLog::Terse, "Received tracking for %s (active %d seconds):", getIPString(), seconds); for (it = myTrackingReceivedMap.begin(); it != myTrackingReceivedMap.end(); it++) { command = (*it).first; tracker = (*it).second; packetsReceivedTcp += tracker->myPacketsTcp; bytesReceivedTcp += tracker->myBytesTcp; packetsReceivedUdp += tracker->myPacketsUdp; bytesReceivedUdp += tracker->myBytesUdp; std::map<unsigned int, ArServerData *>::iterator nameIt; if ((nameIt = myDataMap->find(command)) != myDataMap->end()) snprintf(name, sizeof(name), "%s", (*nameIt).second->getName()); // if we're command 255 or less and there's no name its probably // one of the server commands we don't really need to track else if (command <= 255) continue; // we should know what the name of everything other then the // server command is, but print if we don't, just in case else snprintf(name, sizeof(name), "#%d", command); if (terse) { ArLog::log(ArLog::Terse, "%35s %7ld pkts %10ld B %7ld B/sec", name, tracker->myPacketsTcp + tracker->myPacketsUdp, tracker->myBytesTcp + tracker->myBytesUdp, ((tracker->myBytesTcp + tracker->myBytesUdp)/ seconds)); } else { ArLog::log(ArLog::Terse, "%35s %7ld tcp pkts %10ld tcp B %7ld tcp B/S %7ld udp pkts %10ld udp B %7ld udp B/s ", name, tracker->myPacketsTcp, tracker->myBytesTcp, tracker->myBytesTcp/seconds, tracker->myPacketsUdp, tracker->myBytesUdp, tracker->myBytesUdp/seconds); } } ArLog::log(ArLog::Terse, ""); if (terse) { ArLog::log(ArLog::Terse, "%-35s %7ld pkts %10ld B %7ld B/sec", "Total Received", packetsReceivedTcp + packetsReceivedUdp, bytesReceivedTcp + bytesReceivedUdp, (bytesReceivedTcp + bytesReceivedUdp) / seconds); } else { ArLog::log(ArLog::Terse, "%-35s %7ld tcp pkts %10ld tcp B %7ld tcp B/S %7ld udp pkts %10ld udp B %7ld udp B/sec", "Total Received", packetsReceivedTcp, bytesReceivedTcp, bytesReceivedTcp/seconds, packetsReceivedUdp, bytesReceivedUdp, bytesReceivedUdp/seconds); ArLog::log(ArLog::Terse, "%-35s %7ld tcp rcvs %10ld tcp B %7ld tcp B/S", "Low level TCP Received", myTcpSocket.getRecvs(), myTcpSocket.getBytesRecvd(), myTcpSocket.getBytesRecvd()/seconds); } long packetsSentTcp = 0; long bytesSentTcp = 0; long packetsSentUdp = 0; long bytesSentUdp = 0; ArLog::log(ArLog::Terse, ""); ArLog::log(ArLog::Terse, "Sent tracking for %s (active %d seconds):", getIPString(), seconds); for (it = myTrackingSentMap.begin(); it != myTrackingSentMap.end(); it++) { command = (*it).first; tracker = (*it).second; packetsSentTcp += tracker->myPacketsTcp; bytesSentTcp += tracker->myBytesTcp; packetsSentUdp += tracker->myPacketsUdp; bytesSentUdp += tracker->myBytesUdp; std::map<unsigned int, ArServerData *>::iterator nameIt; if ((nameIt = myDataMap->find(command)) != myDataMap->end()) snprintf(name, sizeof(name), "%s", (*nameIt).second->getName()); // if we're command 255 or less and there's no name its probably // one of the server commands we don't really need to track else if (command <= 255) continue; // we should know what the name of everything other then the // server command is, but print if we don't, just in case else snprintf(name, sizeof(name), "#%d", command); if (terse) { ArLog::log(ArLog::Terse, "%35s %7ld pkts %10ld B %7ld B/sec", name, tracker->myPacketsTcp + tracker->myPacketsUdp, tracker->myBytesTcp + tracker->myBytesUdp, ((tracker->myBytesTcp + tracker->myBytesUdp)/ seconds)); } else { ArLog::log(ArLog::Terse, "%35s %7ld tcp pkts %10ld tcp B %7ld tcp B/S %7ld udp pkts %10ld udp B %7ld udp B/s ", name, tracker->myPacketsTcp, tracker->myBytesTcp, tracker->myBytesTcp/seconds, tracker->myPacketsUdp, tracker->myBytesUdp, tracker->myBytesUdp/seconds); } } ArLog::log(ArLog::Terse, ""); if (terse) { ArLog::log(ArLog::Terse, "%-35s %7ld pkts %10ld B %7ld B/sec", "Total Sent", packetsSentTcp + packetsSentUdp, bytesSentTcp + bytesSentUdp, (bytesSentTcp + bytesSentUdp) / seconds); ArLog::log(ArLog::Terse, ""); ArLog::log(ArLog::Terse, "%-35s %7ld pkts %10ld B %7ld B/sec", "Total Sent and Received", (packetsSentTcp + packetsSentUdp + packetsReceivedTcp + packetsReceivedUdp), (bytesSentTcp + bytesSentUdp + bytesReceivedTcp + bytesReceivedUdp), (bytesSentTcp + bytesSentUdp + bytesReceivedTcp + bytesReceivedUdp) / seconds); } else { ArLog::log(ArLog::Terse, "%-35s %7ld tcp pkts %10ld tcp B %7ld tcp B/S %7ld udp pkts %10ld udp B %7ld udp B/sec", "Total Sent", packetsSentTcp, bytesSentTcp, bytesSentTcp / seconds, packetsSentUdp, bytesSentUdp, bytesSentUdp / seconds); ArLog::log(ArLog::Terse, "%-35s %7ld tcp snds %10ld tcp B %7ld tcp B/S", "Low level TCP Sent", myTcpSocket.getSends(), myTcpSocket.getBytesSent(), myTcpSocket.getBytesSent() / seconds); ArLog::log(ArLog::Terse, ""); ArLog::log(ArLog::Terse, "%-35s %7ld tcp pkts %10ld tcp B %7ld tcp B/S %7ld udp pkts %10ld udp B %7ld udp B/sec", "Total Sent and Received", packetsSentTcp = packetsReceivedTcp, bytesSentTcp + bytesReceivedTcp, (bytesSentTcp + bytesReceivedTcp) / seconds, packetsSentUdp + packetsReceivedUdp, bytesSentUdp + bytesReceivedUdp, (bytesSentUdp + bytesReceivedUdp) / seconds); } ArLog::log(ArLog::Terse, ""); }
/* * Case of a server with two sockets: * function trying to create and set up all (ipv4 and ipv6) available server sockets of * the host. When one socket is IPv6, the IPV6_V6ONLY socket option is set. * The list of sockets is passed as a parameter to be completed. */ void createAndSetUpAllTCPServerSockets(int *nb_sockets, int *tb_sockets, int port, int max_connections) { int server_socket; struct addrinfo hints, *address_list, *paddress; int on = 1; char ip[IP_MAX_CHARS]; char port_string[PORT_MAX_DIGITS]; *nb_sockets = 0; /* getaddrinfo parameters */ memset(&hints, 0, sizeof(hints)); /* init */ hints.ai_flags |= AI_PASSIVE; /* server behaviour: accept connection on any network address */ hints.ai_family = AF_UNSPEC; /* find both ipv4 and ipv6 addresses */ hints.ai_socktype = SOCK_STREAM; /* type of socket */ sprintf (port_string, "%d", port); getaddrinfo(NULL, port_string, &hints, &address_list); paddress = address_list; while (paddress) { /* create the socket */ server_socket = socket(paddress->ai_family, paddress->ai_socktype, paddress->ai_protocol); if (server_socket == -1) { /* try next address */ paddress = paddress->ai_next; continue; } /* set SO_REUSEADDR option */ setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); /* we must set IPV6_V6ONLY in order to allow an IPv4 socket on the same port number. */ if (paddress->ai_family == AF_INET6) { setsockopt(server_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); } /* bind and listen */ if ( (bind(server_socket, paddress->ai_addr, paddress->ai_addrlen) == -1) || (listen(server_socket, max_connections) == -1)) { close(server_socket); /* try next address */ paddress = paddress->ai_next; continue; } /* get the ip string, display it with the port number */ getIPString(paddress->ai_addr, ip, IP_MAX_CHARS); printf("Server socket now listening on %s port %d\n", ip, port); tb_sockets[*nb_sockets] = server_socket; *nb_sockets += 1; paddress = paddress->ai_next; } /* free the list */ freeaddrinfo(address_list); }
/* * Case of a server with one socket: * function trying to create a server socket using all available addresses of the host * until one is successfully created. If the socket is IPv6, the IPV6_V6ONLY * socket option is unset. * Then the socket is returned, or -1 in case of failure. */ int createAndSetUpATCPServerSocket(int port, int max_connections) { int server_socket; struct addrinfo hints, *address_list, *paddress; int on = 1, off = 0; char ip[IP_MAX_CHARS]; char port_string[PORT_MAX_DIGITS]; server_socket = -1; scar_log(1, "Try address...\n"); /* getaddrinfo parameters */ memset(&hints, 0, sizeof(hints)); /* init */ hints.ai_flags |= AI_PASSIVE; /* server behaviour: accept connection on any network address */ hints.ai_family = AF_UNSPEC; /* find both ipv4 and ipv6 addresses */ hints.ai_socktype = SOCK_STREAM; /* type of socket */ sprintf (port_string, "%d", port); getaddrinfo(NULL, port_string, &hints, &address_list); paddress = address_list; while (paddress) { /* create the socket */ server_socket = socket(paddress->ai_family, paddress->ai_socktype, paddress->ai_protocol); if (server_socket == -1) { /* try next address */ paddress = paddress->ai_next; continue; } /* set SO_REUSEADDR option */ setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); /* we must unset IPV6_V6ONLY in order to allow IPv4 client to connect to the IPv6 socket */ if (paddress->ai_family == AF_INET6) { setsockopt(server_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); } /* Make the master socket non-blocking */ if (fcntl (server_socket, F_SETFL, fcntl(server_socket, F_GETFL)|O_NONBLOCK) == -1) { net_printErrNo (errno, __func__); return -1; } /* bind and listen */ if ((bind (server_socket, paddress->ai_addr, paddress->ai_addrlen) == -1) || (listen (server_socket, max_connections) == -1)) { close(server_socket); server_socket = -1; /* try next address */ paddress = paddress->ai_next; continue; } /* get the ip string, display it with the port number */ getIPString(paddress->ai_addr, ip, IP_MAX_CHARS); scar_log (1, "Server socket now listening on %s port %d (socket fd %d)\n", ip, port, server_socket); /* break if no error */ break; } /* free the list */ freeaddrinfo(address_list); /* return the server socket */ return server_socket; }
int main(int argc, char * argv[]) { struct sockaddr_in sockname, client; struct sigaction sa; char *ep, *inbuff, *tmp; char outbuff[256]; int clientlen, sd; u_short port; u_long p; pid_t pid; /* daemonize */ #ifndef DEBUG /* don't daemonize if we compile with -DDEBUG */ if (daemon(1,1) == -1) err(1, "daemon() failed"); #endif /* check params */ if (argc != 4) usage(); errno = 0; p = strtoul(argv[1], &ep, 10); if (&argv[1] == '\0' || *ep != '\0'){ /* parameter wasn't a number, or was empty */ fprintf(stderr, "%s - not a number\n", argv[1]); usage(); } if ((errno == ERANGE && p == ULONG_MAX) || (p > USHRT_MAX)) { /* It's a number, but it either can't fit in an unsigned * long, or it is too big for an unsigned short */ fprintf(stderr, "%s - value out of range\n", argv[1]); usage(); } /* Ensure argv[2] is a valid directory */ if (chdir(argv[2]) == -1) err(1, "chdir failed"); /* TODO : Ensure argv[3] is a valid file */ LOG_FILE = argv[3]; /* now safe to do this */ port = p; memset(&sockname, 0, sizeof(sockname)); sockname.sin_family = AF_INET; sockname.sin_port = htons(port); sockname.sin_addr.s_addr = htonl(INADDR_ANY); sd = socket(AF_INET, SOCK_STREAM, 0); if (sd == -1) err(1, "socket failed"); if (bind(sd, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) err(1, "bind failed"); if (listen(sd, 3) == -1) err(1, "listen failed"); /* We are now bound and listening for connections on "sd" */ /* Catch SIGCHLD to stop zombie children wandering around */ sa.sa_handler = kidhandler; sigemptyset(&sa.sa_mask); /* allow system calls (accept) to restart if interrupted by SIGCHLD */ sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) err(1, "sigaction failed"); /* main loop. Accept connections and do stuff */ for(;;) { int clientsd; ssize_t written, w; clientlen = sizeof(&client); clientsd = accept(sd, (struct sockaddr *)&client, &clientlen); if (clientsd == -1) err(1, "accept failed"); /* fork child to deal with each connection */ pid = fork(); if (pid == -1) internalError((struct sockaddr *)&client, "fork failed", NULL); if (pid == 0) { char * getLine, *fName; int valid, written; long lSize; FILE * fp; /* Parse GET */ inbuff = malloc(12800*sizeof(char)); fName = malloc(256*sizeof(char)); if (inbuff == NULL || fName == NULL) internalError(&client, "malloc failed", NULL); readSocket(clientsd, inbuff, 12800); getLine = malloc(256*sizeof(char)); if (getLine == NULL) internalError(&client, "malloc failed", NULL); valid = checkGET(inbuff, fName, getLine); fName++; if (valid == 0) { /* BAD REQUEST */ sendBadRequestError(clientsd); logBadRequest(getIPString(&client), getLine); } else { /* GET is good. Try reading file & sending */ fp = fopen(fName, "r"); if (fp == NULL) { if (errno == ENOENT) { sendNotFoundError(clientsd); logNotFound( getIPString(&client), getLine); } else if (errno == EACCES) { sendForbiddenError(clientsd); logForbidden( getIPString(&client), getLine); } else internalError(&client, "fopen failed", getLine); } else { /* get file size */ fseek(fp, sizeof(char), SEEK_END); lSize = ftell(fp); rewind(fp); /* send OK and file */ sendOK(clientsd, lSize); written = sendFile(fp, clientsd); logOK(getIPString(&client), getLine, written, lSize-1); } fclose(fp); } /* Clean up */ fName--; free(getLine); free(inbuff); free(fName); fName = NULL; getLine = NULL; inbuff = NULL; exit(0); } close(clientsd); } }
///////////////////////////////////////////////////////////////////////////// // handle leaving ///////////////////////////////////////////////////////////////////////////// void CNetworkConnectorSetupDialog::OnOK() { CString str; UpdateData(); //update the max players allowed m_MaxStatic.GetWindowText(str); GAME->m_nMaxPlayers = atoi(str); //update quit cutoff percent m_CutoffStatic.GetWindowText(str); GAME->m_nQuitCutoff = atoi(str); //set the ladder value GAME->m_bLadder = m_LadderCheck.GetCheck(); //set the team value GAME->m_bTeam = m_TeamCheck.GetCheck(); //set some variants automatically if playing in team if(TRUE == GAME->m_bTeam) { VARIANTS->m_iVariants |= (VARIANT_TRADE_ZERO | VARIANT_TRADE_AFTER_BUILD); } //remove any |'s from the game name m_strName.Remove('|'); if(TRUE == CONNECTOR->isPortForwarding()) { //see if we need to get the IP if(FALSE == m_IPAddress.IsBlank()) { //get the IP address str = getIPString(); //now set it in the connector CONNECTOR->setIP(str); } //write it WritePrivateProfileString(INI_NETWORK, INI_PORTFOR_IP, str, INI_FILE); str.Empty(); //see if we need to set the port if(FALSE == m_strPort.IsEmpty()) { //set the value str = m_strPort; CONNECTOR->setPort(atoi(str)); } else { str.Format("%d", PORT); } //write it WritePrivateProfileString(INI_NETWORK, INI_PORTFOR_PORT, str, INI_FILE); } CHelpDialog::OnOK(); }