How to get number of connections on PORT per IP in Windows? - c++

I have been searching around Google for some time and I can`t seem to find an answer...
I am using GetExtendedTcpTable() to view my current connections, but I am unable to get the number of connections that each IP does on a specific PORT.
Is there any example/function for this ? Or do I have to create something ?
Any guidance or example is much appreciated.
Have a nice day!

So using this code from MSDN as the basis we end up with this example which enumerates a list of connections, populating the pointer to int ports with the number of connections from remote systems to the local ports.
To determine the number of connections to a particular local port, you can simply print out the value of ports[port].
The code as supplied is very much more C, than C++, I just used a new[] and delete[] for the ports.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#define MALLOC(x) calloc(1, (x))
#define FREE(x) free((x))
int main()
{
// Declare and initialize variables
PMIB_TCPTABLE_OWNER_PID pTcpTable;
int *ports; // an array of all the possible ports
DWORD dwSize = 0;
DWORD dwRetVal = 0;
char szRemoteAddr[128];
struct in_addr IpAddr;
int i;
ports = new int[1 << (sizeof(u_short) * 8)]();
pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(sizeof(MIB_TCPTABLE_OWNER_PID));
if (pTcpTable == NULL) {
printf("Error allocating memory\n");
return 1;
}
dwSize = sizeof(MIB_TCPTABLE);
// Make an initial call to GetTcpTable to
// get the necessary size into the dwSize variable
if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_BASIC_CONNECTIONS, 0)) ==
ERROR_INSUFFICIENT_BUFFER) {
FREE(pTcpTable);
pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(dwSize);
if (pTcpTable == NULL) {
printf("Error allocating memory\n");
return 1;
}
}
// Make a second call to GetTcpTable to get
// the actual data we require
if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_BASIC_CONNECTIONS, 0)) == NO_ERROR) {
printf("\tNumber of entries: %d\n", (int)pTcpTable->dwNumEntries);
for (i = 0; i < (int)pTcpTable->dwNumEntries; i++) {
printf("\n\tTCP[%d] State: %ld - ", i,
pTcpTable->table[i].dwState);
if (pTcpTable->table[i].dwState != MIB_TCP_STATE_ESTAB)
continue;
// get the port in host order
u_short port = ntohs((u_short)pTcpTable->table[i].dwLocalPort);
ports[port] += 1; // increment this port
IpAddr.S_un.S_addr = (u_long)pTcpTable->table[i].dwRemoteAddr;
inet_ntop(AF_INET, &IpAddr, szRemoteAddr, sizeof(szRemoteAddr));
printf("\tTCP[%d] Remote Addr: %s:%d\n", i, szRemoteAddr, ntohs((u_short)pTcpTable->table[i].dwRemotePort));
}
}
else {
printf("\tGetExtendedTcpTable failed with %d\n", dwRetVal);
FREE(pTcpTable);
delete[] ports;
return 1;
}
if (pTcpTable != NULL) {
FREE(pTcpTable);
pTcpTable = NULL;
}
delete[] ports;
return 0;
}
Now if you wanted a list of the remote addresses coming to a port, then you could make a std::vector<std::string> remote_addresses and perform a remote_addresses.push_back(szRemoteAddr) when you determined that the port was correct.
There is a potential race condition where between the initial call to GetExtendedTcpTable and the subsequent call to GetExtendedTcpTable another connection comes in, which increases the value of dwSize. Generally asking for more memory helps in this case to just prevent this from being an issue - i.e. after the initial call, try asking for 8K more than you need - it's not likely to be a big issue, though.

Related

How to get IP Address from url without gethostbyname in Winsock API

I want to get IP Address from URL. I find the answer in google, it only has gethostbyname() function solution, but MSDN said that this function is not used anymore.
I try to use getaddressinfo() or getnameinfo() (the example in MSDN), it only returns 255.255.255.255.
How can I do? Thank all!
gethostbyname() is indeed deprecated, and getaddrinfo() is the correct function to use now.
You need to parse the URL to extract its hostname, and optionally its port number (see InternetCrackUrl(), or other similar parser), then pass that hostname/port to getaddrinfo(). It will give you back a linked list of addrinfo structs containing each IP address assigned to the host, in sockaddr_in (IPv4) or sockaddr_in6 (IPv6) format.
If you need those IPs as strings, you can use inet_ntop(), RtlIpv4AddressToString()/RtlIpv6AddressToString(), getnameinfo() with the NI_NUMERICHOST flag, etc.
Addresses are obtained by domain name, not by URL.
Here are two functions to get an IPv6 and IPv4 address from a domain name.
Functions parameter is domain_name - domain name (eg dns.google).
The result is local_internet_name - a list of IPv6 or IPv4 addresses depending on the function used (e.g. {[8.8.8.8], [8.8.4.4]} for IPv4 addresses of the dns.google domain)
The return value is the attribute "Addresses found or not found" (true and false).
domain_name_to_internet_6_name
domain_name_to_internet_4_name
The functions use the MFC string classes, the C++ standard library, Windows DNS functions, and network functions.
An example of the output from a test console program:
2001:4860:4860::8888
2001:4860:4860::8844
8.8.8.8
8.8.4.4
D:\Projects\DNS_Test\Debug\DNS_Test.exe (process 14740) exited with code 0.
Press any key to close this window . . .
To create an executable for Windows, in Microsoft Visual Studio, you need to create a project from the "Console Application for Windows" template, and set the project properties to "Use MFC library" (as a shared library or as a static library)
Here's the code for a console program:
#include <afxwin.h>
#include <iostream>
#include <string>
#include <list>
#include <ws2tcpip.h>
#pragma comment(lib, "normaliz.lib")
#pragma comment(lib, "dnsapi.lib")
bool domain_name_to_internet_6_name(CStringW domain_name, std::list<CStringA>& local_internet_name)
{
const size_t CONST_MESSAGE_LENGTH = 500;
wchar_t local_domain_name_unicode[CONST_MESSAGE_LENGTH];
ZeroMemory(local_domain_name_unicode, sizeof(wchar_t) * CONST_MESSAGE_LENGTH);
if (IdnToAscii(0, domain_name, domain_name.GetLength(), local_domain_name_unicode, CONST_MESSAGE_LENGTH) == 0)
{
const int local_error_message_size = 500;
wchar_t local_error_message[local_error_message_size];
const int local_system_error_message_size = local_error_message_size - 250;
wchar_t local_system_error_message[local_system_error_message_size];
wcscpy_s(local_system_error_message, local_system_error_message_size, L"IdnToAscii finished with error");
CString local_time_string = CTime::GetCurrentTime().FormatGmt("%d/%m/%y %H:%M:%S GMT");
wsprintf((wchar_t*)local_error_message, L"Networking error -- %s -- %s\r\n", local_system_error_message, local_time_string.GetBuffer());
// В local_error_message находится текст с кодом сетевой ошибки при выполнении функции IdnToAscii
return false;
}
PDNS_RECORD ppQueryResults;
ZeroMemory(&ppQueryResults, sizeof(ppQueryResults));
if (DnsQuery_W(local_domain_name_unicode, DNS_TYPE_AAAA, 0, NULL, &ppQueryResults, NULL) == ERROR_SUCCESS)
{
for (PDNS_RECORD ptr = ppQueryResults; ptr != NULL; ptr = ptr->pNext)
{
if (ptr->wType == DNS_TYPE_AAAA)
{
if (ptr->wDataLength != 0)
{
char local_address_buffer[100];
inet_ntop(AF_INET6, &ptr->Data.AAAA.Ip6Address.IP6Byte, local_address_buffer, 100);
local_internet_name.push_back(local_address_buffer);
}
}
}
DnsFree(ppQueryResults, DnsFreeRecordList);
if (local_internet_name.size() != 0)
{
return true; // Адреса найдены
}
else
{
return false; // Адреса не найдены
}
return true;
}
return false;
}
bool domain_name_to_internet_4_name(CStringW domain_name, std::list<CStringA>& local_internet_name)
{
const size_t CONST_MESSAGE_LENGTH = 500;
wchar_t local_domain_name_unicode[CONST_MESSAGE_LENGTH];
ZeroMemory(local_domain_name_unicode, sizeof(wchar_t) * CONST_MESSAGE_LENGTH);
if (IdnToAscii(0, domain_name, domain_name.GetLength(), local_domain_name_unicode, CONST_MESSAGE_LENGTH) == 0)
{
const int local_error_message_size = 500;
wchar_t local_error_message[local_error_message_size];
const int local_system_error_message_size = local_error_message_size - 250;
wchar_t local_system_error_message[local_system_error_message_size];
wcscpy_s(local_system_error_message, local_system_error_message_size, L"IdnToAscii finished with error");
CString local_time_string = CTime::GetCurrentTime().FormatGmt("%d/%m/%y %H:%M:%S GMT");
wsprintf((wchar_t*)local_error_message, L"Networking error -- %s -- %s\r\n", local_system_error_message, local_time_string.GetBuffer());
// В local_error_message находится текст с кодом сетевой ошибки при выполнении функции IdnToAscii
return false;
}
PDNS_RECORD ppQueryResults;
ZeroMemory(&ppQueryResults, sizeof(ppQueryResults));
if (DnsQuery_W(local_domain_name_unicode, DNS_TYPE_A, 0, NULL, &ppQueryResults, NULL) == ERROR_SUCCESS)
{
for (PDNS_RECORD ptr = ppQueryResults; ptr != NULL; ptr = ptr->pNext)
{
if (ptr->wType == DNS_TYPE_A)
{
if (ptr->wDataLength != 0)
{
char local_address_buffer[100];
inet_ntop(AF_INET, &ptr->Data.A.IpAddress, local_address_buffer, 100);
local_internet_name.push_back(local_address_buffer);
}
}
}
DnsFree(ppQueryResults, DnsFreeRecordList);
if (local_internet_name.size() != 0)
{
return true; // Адреса найдены
}
else
{
return false; // Адреса не найдены
}
return true;
}
return false;
}
int main()
{
std::list<CStringA> local_internet_name_6;
if (domain_name_to_internet_6_name(CStringW(L"dns.google"), local_internet_name_6))
{
for (auto i = local_internet_name_6.begin(); i != local_internet_name_6.end(); i++)
{
std::cout << *i << std::endl;
}
}
std::list<CStringA> local_internet_name_4;
if (domain_name_to_internet_4_name(CStringW(L"dns.google"), local_internet_name_4))
{
for (auto i = local_internet_name_4.begin(); i != local_internet_name_4.end(); i++)
{
std::cout << *i << std::endl;
}
}
}

poll() method not working in Linux but working in Mac

I am using C++ code snippet for port forwarding. The requirement is to do the hand shake between two ports. It should be two way communication. That is to forward what ever iscoming on the source port to destination port. And then to forward the response of the destination port to the source port.
This piece of code is working as expected on my mac system. But when I am running this code on Linux system I am facing one issue.
Issue:
The C++ code that I am using is having 3 parts:
establish_connection_to_source();
open_connection_to_destination();
processconnetion();
On Linux: establish_connection_to_source(); and open_connection_to_destination(); is working perfectly fine. But processconnetion(); is havng one issue.
Following is the process connection method:
void processconnetion()
{
buffer *todest = new buffer(socket_list[e_source].fd,socket_list[e_dest].fd);
buffer *tosrc = new buffer(socket_list[e_dest].fd,socket_list[e_source].fd);
if (todest == NULL || tosrc == NULL){
fprintf(stderr,"out of mememory\n");
exit(-1);
}
unsigned int loopcnt;
profilecommuncation srcprofile(COMM_BUFSIZE);
profilecommuncation destprofile(COMM_BUFSIZE);
while (true) {
int withevent = poll(socket_list, 2, -1);
loopcnt++;
fprintf(stderr,"loopcnt %d socketswith events = %d source:0x%x dest:0x%x\n", loopcnt, withevent, socket_list[e_source].revents, socket_list[e_dest].revents);
if ((socket_list[e_source].revents | socket_list[e_dest].revents) & (POLLHUP | POLLERR)) {
// one of the connections has a problem or has Hungup
fprintf(stderr,"socket_list[e_source].revents= 0x%X\n", socket_list[e_source].revents);
fprintf(stderr,"socket_list[e_dest].revents= 0x%X\n", socket_list[e_dest].revents);
fprintf(stderr,"POLLHUP= 0x%X\n", POLLHUP);
fprintf(stderr,"POLLERR= 0x%X\n", POLLERR);
int result;
socklen_t result_len = sizeof(result);
getsockopt(socket_list[e_dest].fd, SOL_SOCKET, SO_ERROR, &result, &result_len);
fprintf(stderr, "result = %d\n", result);
fprintf(stderr,"exiting as one connection had an issue\n");
break;
}
if (socket_list[e_source].revents & POLLIN) {
srcprofile.increment_size(todest->copydata());
}
if (socket_list[e_dest].revents & POLLIN) {
destprofile.increment_size(tosrc->copydata());
}
}
delete todest;
delete tosrc;
close(socket_list[e_source].fd);
close(socket_list[e_dest].fd);
srcprofile.dumpseensizes("source");
destprofile.dumpseensizes("destination");
}
Here it is giving error - exiting as one connection had an issue that means that if ((socket_list[e_source].revents | socket_list[e_dest].revents) & (POLLHUP | POLLERR)) is returning true. The issue is with the destination port and not in case of source.
Note:
Variales used in the processconnetion(); method:
socket_list is a structure of type pollfd. Following is the description:
struct pollfd {
int fd;
short events;
short revents;
};
pollfd socket_list[3];
#define e_source 0
#define e_dest 1
#define e_listen 2
Following is the output at the time for exit:
connecting to destination: destination IP / 32001.
connected...
loopcnt 1 socketswith events = 1 source:0x0 dest:0x10
socket_list[e_source].revents= 0x0
socket_list[e_dest].revents= 0x10
POLLHUP= 0x10
POLLERR= 0x8
result = 0
exiting as one connection had an issue
int withevent = poll(socket_list, 2, -1); here the withevent value returned is 1
Socket List Initialisation:
guard( (socket_list[e_listen].fd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )), "Failed to create socket listen, error: %s\n", "created listen socket");
void guard(int n, char *msg, char *success)
{
if (n < 0) {
fprintf(stderr, msg, strerror(errno) );
exit(-1);
}
fprintf(stderr,"n = %d %s\n",n, success);
}
I am not able to figure out the issue as it is working fine in mac. Any leads why this behaviour in Linux is highly appreciated. Thanks in advance.

Generate machine-specific key for Mac

On Windows, we generate a PC-specific unique key used to tie a license to a PC. It's a C++ app using wxWidgets, which is theoretically cross-platform compatible but not been maintained on the Mac side. We use some Win32-specific code for generating a key... how might I do something comparable on the Mac?
Looking more into whitelionV and blahdiblah's asnwers, I found this useful page:
Accessing the system serial number programmatically
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// Returns the serial number as a CFString.
// It is the caller's responsibility to release the returned CFString when done with it.
void CopySerialNumber(CFStringRef *serialNumber)
{
if (serialNumber != NULL) {
*serialNumber = NULL;
io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpert) {
CFTypeRef serialNumberAsCFString =
IORegistryEntryCreateCFProperty(platformExpert,
CFSTR(kIOPlatformSerialNumberKey),
kCFAllocatorDefault, 0);
if (serialNumberAsCFString) {
*serialNumber = serialNumberAsCFString;
}
IOObjectRelease(platformExpert);
}
}
}
Accessing the built-in MAC address programmatically
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices);
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize);
static kern_return_t FindEthernetInterfaces(io_iterator_t *matchingServices)
{
kern_return_t kernResult;
CFMutableDictionaryRef matchingDict;
CFMutableDictionaryRef propertyMatchDict;
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
if (NULL == matchingDict) {
printf("IOServiceMatching returned a NULL dictionary.\n");
}
else {
propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (NULL == propertyMatchDict) {
printf("CFDictionaryCreateMutable returned a NULL dictionary.\n");
}
else {
CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
CFRelease(propertyMatchDict);
}
}
kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, matchingServices);
if (KERN_SUCCESS != kernResult) {
printf("IOServiceGetMatchingServices returned 0x%08x\n", kernResult);
}
return kernResult;
}
static kern_return_t GetMACAddress(io_iterator_t intfIterator, UInt8 *MACAddress, UInt8 bufferSize)
{
io_object_t intfService;
io_object_t controllerService;
kern_return_t kernResult = KERN_FAILURE;
if (bufferSize < kIOEthernetAddressSize) {
return kernResult;
}
bzero(MACAddress, bufferSize);
while ((intfService = IOIteratorNext(intfIterator)))
{
CFTypeRef MACAddressAsCFData;
kernResult = IORegistryEntryGetParentEntry(intfService,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kernResult) {
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kernResult);
}
else {
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData) {
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
CFRelease(MACAddressAsCFData);
}
(void) IOObjectRelease(controllerService);
}
(void) IOObjectRelease(intfService);
}
return kernResult;
}
int main(int argc, char *argv[])
{
kern_return_t kernResult = KERN_SUCCESS;
io_iterator_t intfIterator;
UInt8 MACAddress[kIOEthernetAddressSize];
kernResult = FindEthernetInterfaces(&intfIterator);
if (KERN_SUCCESS != kernResult) {
printf("FindEthernetInterfaces returned 0x%08x\n", kernResult);
}
else {
kernResult = GetMACAddress(intfIterator, MACAddress, sizeof(MACAddress));
if (KERN_SUCCESS != kernResult) {
printf("GetMACAddress returned 0x%08x\n", kernResult);
}
else {
printf("This system's built-in MAC address is %02x:%02x:%02x:%02x:%02x:%02x.\n",
MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]);
}
}
(void) IOObjectRelease(intfIterator); // Release the iterator.
return kernResult;
}
While MAC is on the face of it probably preferable as being more predictable, they warn that:
Netbooting introduces a wrinkle with systems with multiple built-in
Ethernet ports. The primary Ethernet port on these systems is the one
that is connected to the NetBoot server. This means that a search for
the primary port may return either of the built-in MAC addresses
depending on which port was used for netbooting. Note that "built-in"
does not include Ethernet ports that reside on an expansion card.
It concerns me this might mean you don't always get the same value back?
You could just call system_profiler and look for "Serial Number"
/usr/sbin/system_profiler | grep "Serial Number (system)"
There might well be a programmatic way to get the same information, but I don't know it offhand.
To uniquely identify any machine you could try to use the MAC address. The process, although not trivial, its quite simple. There are a lot of cross platform open source libraries.
In fact you could try this Apple dev example

C++ code to find BSSID OF associated network [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Want to know the ESSID of wireless network via C++ in UBUNTU
Hello I have written the following code which is a part of a project. It is used to find the ESSID of the current associated network. But it has a flaw that it also the displays the ESSID of the network with which I am not associated i.e. if I try to associate myself with a wireless n/w and if it is unsuccessfull i.e. NO DHCP OFFERS ARE RECEIVED, then also it will display the that ESSID with which I have made my attempt.
Is it possible to find the BSSID of current associated wireless network as it is the only way with which I can mark b/w associated and non associated, e.g. with an ioctl call?
int main (void)
{
int errno;
struct iwreq wreq;
CStdString result = "None";
int sockfd;
char * id;
char ESSID[20];
memset(&wreq, 0, sizeof(struct iwreq));
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Cannot open socket \n");
fprintf(stderr, "errno = %d \n", errno);
fprintf(stderr, "Error description is : %s\n",strerror(errno));
return result ;
}
CLog::Log(LOGINFO,"Socket opened successfully");
FILE* fp = fopen("/proc/net/dev", "r");
if (!fp)
{
// TBD: Error
return result;
}
char* line = NULL;
size_t linel = 0;
int n;
char* p;
int linenum = 0;
while (getdelim(&line, &linel, '\n', fp) > 0)
{
// skip first two lines
if (linenum++ < 2)
continue;
p = line;
while (isspace(*p))
++p;
n = strcspn(p, ": \t");
p[n] = 0;
strcpy(wreq.ifr_name, p);
id = new char[IW_ESSID_MAX_SIZE+100];
wreq.u.essid.pointer = id;
wreq.u.essid.length = 100;
if ( ioctl(sockfd,SIOCGIWESSID, &wreq) == -1 ) {
continue;
}
else
{
strcpy(ESSID,id);
return ESSID;
}
free(id);
}
free(line);
fclose(fp);
return result;
}
Note: Since this question seems to be duplicated in two places, I'm repeating my answer here as well.
You didn't mention whether you were using an independent basic service set or not (i.e., an ad-hoc network with no controlling access point), so if you're not trying to create an ad-hoc network, then the BSSID should be the MAC address of the local access point. The ioctl() constant you can use to access that information is SIOCGIWAP. The ioctl payload information will be stored inside of your iwreq structure at u.ap_addr.sa_data.

Socket class Error

ListenSocket.h
// class does not contain WSASTARTUP () and WSACLEANUP ()
#ifndef LISTENTHREAD_H
#define LISTENTHREAD_H
#include "includes.h"
#include "LOGMSGs.h"
// 1, CListenSocket: class is used to create the listener thread local variable.
// This class can be reused. When you call Close () is closed, re-calling Open () the new listening port. But the system did not use the feature.
class CListenSocket
{
public:
// main method:
// BIND each object only to a port.
CListenSocket(u_short nPort, int nSndSize = 0);
// to release SOCKET
~CListenSocket(){};
// Create server listening SOCKET, specific options see the code. Fails to return false.
bool Open(); // call can be repeated
// error return INVALID_SOCKET
SOCKET Accept(u_long & nClientIP);
// repeated calls. Usually not, can be used to take the initiative to close the SOCKET.
// close the re-call after Open () re-use the object.
void Close(); // call can be repeated
bool IsOpen() { return m_bState; }
bool Rebuild();
public:
SOCKET Socket() { return m_sockListen; }
protected:
// main member variables:
const u_short m_nPort;
const int m_nSndBuf;
SOCKET m_sockListen;
// network status is normal sign.
// When the value is false that the object is not available. May not have Open (), may also be a network error.
bool m_bState;
time_t m_tCloseTime; // SOCKET last closed the time delay for the automatic re-SOCKET
};
#endif // LISTENTHREAD_H
ListenSocket.cpp
#include "ListenSocket.h"
long s_nSocketCount = 0;
int REBUILDLISTENDELAYSEC;
CListenSocket::CListenSocket(u_short nPort, int nSndBuf /*= 0*/) // 0: Default
: m_nPort(nPort), m_nSndBuf(nSndBuf)
{
m_sockListen = INVALID_SOCKET;
m_bState = false;
// m_nPort = nPort;
m_tCloseTime = 0;
}
// Error returned INVALID_SOCKET
SOCKET CListenSocket::Accept(u_long & nClientIP)
{
/*
// Reconstruction SOCKET
if(!m_bState)
{
if(clock() < m_tCloseTime + REBUILDLISTENDELAYSEC*CLOCKS_PER_SEC)
return INVALID_SOCKET;
else
{
LOGMSG("Anti-crash system start listening SOCKET [%d] re under construction...", m_nPort);
if(Open())
{
LOGMSG("... listen SOCKET reconstruction success.");
PrintText("Listen SOCKET [%d] failed to rebuild SOCKET success. Server continues to run in the ...", m_nPort);
}
else
{
Error("... listen SOCKET reconstruction has failed. Server will not accept new connections");
PrintText("Listen SOCKET [%d] error, [%d] seconds after the re-SOCKET. Server continues to run in the ...", m_nPort, REBUILDLISTENDELAYSEC); // nDelaySec);
}
m_tCloseTime = clock();
}
}
//*/
if(!m_bState)
{
Error("ACCEPT inner exception a1");
return INVALID_SOCKET;
}
// ACCEPT
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
int len = sizeof(addr);
SOCKET newsock = accept(m_sockListen, (sockaddr*)&addr, (int*)&len); // receive to the other side of the map, you can use
#ifdef PROFILE_X
// Analysis Accept speed (cycle speed)
const int nTimes2 = ACCEPTPROFILESEC; // Statistics once every 30 seconds the speed ACCEPT
static clock_t tNextTime2 = clock() + nTimes2 * CLOCKS_PER_SEC; //? Only one monitor thread, no sharing violation
static long nCount2 = 0; //? Only one monitor thread, no sharing violation
if(clock() >= tNextTime2)
{
PrintText("Each [%d] seconds to execute a [%d] times Accept ()", nTimes2, InterlockedExchange(&nCount2, 0));
tNextTime2 = clock() + nTimes2 * CLOCKS_PER_SEC;
}
else
{
InterlockedIncrement(&nCount2);
}
#endif // PROFILE
if(newsock == INVALID_SOCKET)
{
// Network Error
int err = WSAGetLastError();
if(err != WSAEWOULDBLOCK)
{
PrintText("Listen SOCKET %d failed, %s seconds after the re-SOCKET.", m_nPort, REBUILDLISTENDELAYSEC);
Error("Listen SOCKET [%d] failed [%d], [%s] seconds after the re-SOCKET.", m_nPort, err, REBUILDLISTENDELAYSEC);
Close();
}
else
Error("ACCEPT inner exception a2");
return INVALID_SOCKET;
}
else
{
nClientIP = addr.sin_addr.S_un.S_addr;
InterlockedIncrement(&s_nSocketCount);
}
// Check whether the SOCKET closed
fd_set readmask;
FD_ZERO(&readmask);
FD_SET(newsock, &readmask);
struct timeval timeout = {0, 0};
/*
char nTemp;
if(select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &timeout)
&& recv(newsock, &nTemp, 1, MSG_PEEK) == 0)
{
#ifdef ALPHA_X
LOGMSG("ACCEPT a new SOCKET is invalid .");
#endif
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
//else*/
//*
fd_set exceptmask;
FD_ZERO(&exceptmask);
FD_SET(newsock, &exceptmask);
int ret = select(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) &exceptmask, &timeout);
if(ret < 0)
{
Error("ACCEPT a new SOCKET is invalid . can't read"); // Not trigger
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
else if(ret > 0)
{
if(FD_ISSET(newsock, &exceptmask))
{
LOGMSG("ACCEPT a new SOCKET is invalid.except"); // Not trigger
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
else if(FD_ISSET(newsock, &readmask))
{
char nTemp;
if(recv(newsock, &nTemp, 1, MSG_PEEK) == 0)
{
#ifdef ALPHA_X
LOGMSG("ACCEPT a new SOCKET is invalid. recv==0"); // Not trigger
#endif
closesocket(newsock);
InterlockedDecrement(&s_nSocketCount);
return INVALID_SOCKET;
}
}
}
//*/
#ifdef PROFILE_X
// analysis Accept speed (received valid SOCKET)
const int nTimes = ACCEPTPROFILESEC; // Statistics once every 10 seconds the speed ACCEPT
static clock_t tNextTime = clock() + nTimes * CLOCKS_PER_SEC; //? Only one monitor thread, no sharing violation
static long nCount = 0; //? Only one monitor thread, no sharing violation
if(clock() >= tNextTime)
{
LOGPROFILE("Port [%d] for every [%d] seconds, the successful implementation of the [%d] times Accept()",
m_nPort, nTimes, InterlockedExchange(&nCount, 0));
tNextTime = clock() + nTimes * CLOCKS_PER_SEC;
}
else
{
InterlockedIncrement(&nCount);
}
#endif // PROFILE
return newsock;
}
Main.cpp
#include "includes.h"
#include "IniFile.h"
#include "LOGMSGs.h"
#include "ListenSocket.h"
CListenSocket Sock(9985);
int main()
{
Sock.Open();
if(!Sock.Open())
{
Sock.Rebuild();
}
if(Sock.IsOpen())
PrintText("okey");
Sock.Socket();
u_long ip;
Sock.Accept(ip);
}
but i always got this error : ACCEPT inner exception a2 while it should work anyclue why?
CListenSocket Sock(9985);
int main()
{
Sock.Open();
if(!Sock.Open())
/* I think you meant 'IsOpen()' */
{
Sock.Rebuild();
}
if(Sock.IsOpen())
PrintText("okey");
Sock.Socket();
u_long ip;
Sock.Accept(ip);
}
Incidentally, this code sure reads funny. It feels like a generic toolkit programmed without a specific goal in mind. Maybe I'm missing it, but I have to think you'd have better results if you just wrote the network code that actually needed, and then abstract out the common bits into some helper routines later. There's no point in trying too hard to make the be-all and end-all network helper library, but there is a huge point in making tools that collapse common cases.
Feel free to ignore that last paragraph if you know what you're doing :) but if you're just starting out, I'd like to suggest writing a few smaller clients and servers, and then try writing your abstraction layer.