Use of Select() cpp with tracking client data needs - c++

First off I am still very new to c++. I am trying to write a GNSS internet radio caster program. Basically when a client logs in and is accepted my program stores what data stream source the client requests in a Client class. I was going to match an array of Client objects and an array of clientSockets using the index number of both arrays however trying to use Select() to check nonblocking sockets has made that complicated. I have found some examples of implementing Select() but I'm not certain how to track the original clientSocket from my array that I use to accept the connection from the listenSocket with.
class Client{
public:
std::string source;
std::string user; //stored in txt file as name:password
boolean connected;
int IndexNumber;
};
typedef struct _MYSOCKET_INFORMATION{
char Buffer[BUFFERSIZE];
WSABUF DataBuf;
SOCKET Socket;
DWORD SendBytes;
DWORD RecvBytes;
}SOCKET_INFORMATION, *LPSOCKET_INFORMATION;
// creates number of objects of this structure
LPSOCKET_INFORMATION SocketList[NUMBER_CLIENTS];
FD_SET Writer;
FD_SET Reader;
DWORD TotalSockets = 0;
DWORD Flags;
u_long NonBlock = 1;
timeval tv;
long tv_sec = 1;
long tv_usec = 0;
//intiate objects
Caster caster;
DataStream datastream[NUMBER_BASES]; //100 base stations max
Client client[NUMBER_CLIENTS];
SOCKET listenSocket;
SOCKET clientSocket[NUMBER_CLIENTS];
SOCKET serverSocket;
char recvArray[BUFFERSIZE];
using namespace std;
int main()
{
//initialize the Read and Write socket sets
FD_ZERO(&Reader);
FD_ZERO(&Writer);
//check for connection attempt
FD_SET(listenSocket, &Reader);
FD_SET(serverSocket, &Reader);
//set read and write state based on state of buffer
for( unsigned int i=0; i<TotalSockets; i++){
if( SocketList[i]->RecvBytes < SocketList[i]->SendBytes){
FD_SET(SocketList[i]->Socket,&Writer);
}
else{
FD_SET(SocketList[i]->Socket,&Reader);
}
}
//Select returns number of sockets ready to be read/writen
Total = select(0, &Reader, &Writer, NULL, &tv);
if(Total == SOCKET_ERROR){
printf("Error select function %d\n", WSAGetLastError());
return 1;
}
if( FD_ISSET(listenSocket, &Reader)){
Total--;
//set current client no
while(client[current].connected == true){
current++;
if(current >= NUMBER_CLIENTS){
current = 0;
count++;
if(count >= 2){//has cylcled twice all must be set to true, can add no more.
count =0;
printf("client limit reached.\n");
break;
}
}
}
clientSocket[current] = accept(listenSocket, NULL, NULL); //setup client connection for further use
if( clientSocket[current] != INVALID_SOCKET){
//set new client to non blocking
check = ioctlsocket(clientSocket[current], FIONBIO, &NonBlock);
if( check == SOCKET_ERROR){
printf("Error setting client to nonblocking mode. %d.\n", WSAGetLastError());
closesocket(clientSocket[current]);
continue;
}
else{
printf("Accepted client connection request \n");
//recieve data
check = recv(clientSocket[current], recvArray, BUFFERSIZE, 0);
if( check == SOCKET_ERROR){ //close connection if error
printf("error recieving login data. %d \n", WSAGetLastError());
closesocket(clientSocket[current]);
continue;
}
if( check == 0){//no data is recieved then client disconnected
printf("ERROR no data, client dsiconnected.\n");
closesocket(clientSocket[current]);
continue;
}
else{
for(int n=0; n<check +1 ; n++){ //must be request message for data per NTRIP 1.0
clientRequest << recvArray[n]; //place read char bytes into stringstream object for parsing.
}
//if request is good returns a client requested source, username, and true false for data send.
checkClientRequest(clientSocket[current], client[current].source, client[current].connected, client[current].user);
}
}
}
}//end of check client listen socket
for(unsigned int i=0; Total>0 && i<TotalSockets; i++){
LPSOCKET_INFORMATION SocketInfo = SocketList[i];
//check if client sends GGA string
if(FD_ISSET(SocketInfo->Socket, &Reader)){
Total--;
SocketInfo->DataBuf.buf = SocketInfo->Buffer;
SocketInfo->DataBuf.len = BUFFERSIZE;
Flags = 0;
SocketInfo->RecvBytes = sizeof(SocketInfo->DataBuf);
check = WSARecv(SocketInfo->Socket, &(SocketInfo->DataBuf), 1, &(SocketInfo->RecvBytes), &Flags, NULL, NULL);
if( check == SOCKET_ERROR){
FreeSocketInformation(i); //shuts down client socket if socket error
continue;
}
else{
memcpy(recvArray, SocketInfo->DataBuf.buf, SocketInfo->RecvBytes +1);
//print data on screen change to sort lines
printf("%s \n", SocketInfo->DataBuf.buf);
}
}
There's more to it than just this but how do I track the structure SocketInfo with my clientSocket[]'s?

Related

Closing master socket from server side

So I'm writing a very basic TCP server which just echoes back the messages sent from the client back to the client. I have a setup where the server is running in a while loop and waiting for either a new client to connect or for a message from one of the existing clients using the select() method.
My question is:
How do i, from the server side, close the master socket and basically shutting down the server. Im not asking for exact code but more for standard practice.
For some context:
In the long run I am imagining multiple clients connected to my server and I need to shutdown the server gracefully from the server side.
Even more context: The server code.
#define TRUE 1
#define FALSE 0
#define PORT 55555
int main(int argc, char* argv[])
{
int opt = TRUE;
int masterSocket, addrlen, newSocket, maxClients = 10, clientSockets[maxClients],
activity, valread, sd, maxSd;
struct sockaddr_in address;
char buffer[1025];
fd_set readfds;
const char *message = "ECHO DAMON v1.0 \r\n";
/* Initialize array with 0 so it's not read */
for(int i = 0; i < maxClients ; i++)
{
clientSockets[i] = 0;
}
/* Create master socket */
if((masterSocket = socket(AF_INET, SOCK_STREAM,0)) == 0)
{
perror("Error when trying to create master socket.\n");
exit(EXIT_FAILURE);
}
/* Set master socket to allow multiple connections */
if( setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)
{
perror("Could not set sockopt");
exit(EXIT_FAILURE);
}
/* Socket type */
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if( bind(masterSocket, (struct sockaddr*)&address, sizeof(address)) < 0)
{
perror("Error, could not bind master socket. \n");
exit(EXIT_FAILURE);
}
printf("Listening on %d. \n", PORT);
if( listen(masterSocket, 3) < 0)
{
perror("Error, could not listen.\n");
exit(EXIT_FAILURE);
}
addrlen = sizeof(address);
puts("Waiting for connections...\n"); //just a printf variant
/* END INIT */
while(TRUE)
{
/* Clear socket set */
FD_ZERO(&readfds);
/* Add master socket to set */
FD_SET(masterSocket, &readfds);
/* Add child sockets to set, will be 0 first iteration */
for(int i = 0; i < maxClients ; i++)
{
sd = clientSockets[i]; // sd = socket descriptor
/* If valid socket descriptor */
if(sd > 0)
{
FD_SET(sd, &readfds);
}
/* Get highest fd number, needed for the select function (later) */
if(sd > maxSd)
{
maxSd = sd;
}
}//end for-loop
/* Wait for activity on any socket */
activity = select(maxSd +1, &readfds, NULL, NULL, NULL);
if((activity < 0) && (errno != EINTR))
{
printf("Error on select.\n"); //no need for exit.
}
/* If the bit for the file descriptor fd is set in the
file descriptor set pointed to by fdset */
/* If something happend in the master socket, its a new connection */
if(FD_ISSET(masterSocket, &readfds))
{
if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
{
perror("Could not accept new socket.\n");
exit(EXIT_FAILURE);
}
/* Print info about connector */
printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
if( send(newSocket, message, strlen(message), 0) != strlen(message))
{
perror("Could not sent welcome message to new socket.\n");
}
puts("Welcome message sen successfully.\n");
/* Add new socket to array of clients */
for(int i = 0; i < maxClients; i++)
{
if(clientSockets[i] == 0)
{
clientSockets[i] = newSocket;
printf("Adding socket to list of client at index %d\n", i);
break;
}
}
}//end masterSocket if
/* Else something happend at client side */
for(int i = 0; i < maxClients; i++)
{
sd = clientSockets[i];
if(FD_ISSET(sd, &readfds))
{ /* Read socket, if it was closing, else read value */
if((valread = read( sd, buffer, 1024)) == 0)
{
getpeername( sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
close(sd);
clientSockets[i] = 0;
}
}
else
{
buffer[valread] = '\0';
send(sd, buffer, strlen(buffer), 0);
}
}
}
return 0;
}
If you are planning to exit your application gracefully by adding a breakstatement in your app by something similar to this:
if (exit_condition)
{
break;
}
You can place this loop at the end of your main function:
/* close connections gracefully */
closesocket(masterSocket);
masterSocket = 0; /* optional, see comment below */
for(int i = 0; i < maxClients; i++)
{
if (clientSockets[i] != 0)
{
shutdown(clientSockets[i]);
closesocket(clientSockets[i]);
clientSockets[i] = 0; /* optional, except if you also have a SIGINT handler */
}
}
If you want to do the same to handle an exit with Ctrl-C, you will find details on how to setup a SIGINT handler to handle Ctr-C here:
Catch Ctrl-C in C. Place the above loop in your handler, then. Your sockets-related variables will have to be declared at global scope, since your sockets are only visible from main() in your current code.

Buffer overflow on socket connection

i was working on a socket server on a friend's computer and everythng was working fine but then i executed the code on my computer and it throws a buffer overflow like this
*** buffer overflow detected ***: /home/erick/CLionProjects/AirWar++/cmake-build-debug/AirWar__ terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f906c5047e5]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7f906c5a556c]
/lib/x86_64-linux-gnu/libc.so.6(+0x116570)[0x7f906c5a3570]
/lib/x86_64-linux-gnu/libc.so.6(+0x1169da)[0x7f906c5a39da]
We are using rapidjson library to send the data, i dont know why this happens if the exact same code runs perfectly on his computer, the only difference is that i am running Ubuntu on a VM and he was running Ubuntu as the main OS.
I would really appreciate your help, the code fails on this if:
if ((valread = read( sd , buffer, 1024)) == 0)
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[3] ,
max_clients = 3 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
void server::init() {
using namespace rapidjson;
char buffer[400];
//set of socket descriptors
fd_set readfds;
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.100.19");//Write your IP
address.sin_port = htons( PORT );
//bind the socket to localhost port 8080
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Escuchando en el puerto %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Esperando conexiones ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number
printf("Nueva conexion , socket fd %d , ip : %s , puerto : %d\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs
(address.sin_port));
//send new connection message
//if( send(new_socket, "Conectado", strlen("Conectado"), 0) != strlen("Conectado") )
//{
// perror("send");
//}
//puts("Mensaje enviado con exito");//succesfully send
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("AƱadido a la lista de sockets como %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and read the message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , \
(socklen_t*)&addrlen);
printf("Cliente desconectado , ip %s , port %d \n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
run=FALSE;
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//se eliminan dos caracteres nulos del buffer;
std::string m=buffer;
std::string s(m.substr(0,valread));
const char * json= s.c_str();
std::cout<<json;
Document d;
d.Parse(json);
Value& type=d["type"];
if(strcmp(type.GetString(),"shoot")==0){
stat= 5;//Dispara
}else if(strcmp(type.GetString(),"izq")==0){
//Mov. izquierda
stat= 4;
}else if(strcmp(type.GetString(),"der")==0){
//Mov. derecha
stat=6;
}else if(strcmp(type.GetString(),"arr")==0){
//Mov. arriba
stat=8;
}else if(strcmp(type.GetString(),"aba")==0){
//Mov. abajo
stat= 2;
}else{
stat=0;//Quieta
}
}
}
}
}
}
long server:: Send(const char * msg){
send(client_socket[0],msg,strlen(msg),0);
}
Btw we both use CLion.
Will be waiting for your help, thanks!
char buffer[400];
// ^^^
...
if ((valread = read( sd , buffer, 1024)) == 0)
// ^^^^
I hate to sound like a jerk, but didn't the error message prompt you to check the size of buffers that you were reading data into?
Also note that with TCP reads you might not get the entire message in a read() call so buffer might not be null terminated which can cause problems here:
std::string m=buffer;
And this line makes me think that the null terminator might not even be part of the message (we'd have to see the client code to be sure):
send(client_socket[0],msg,strlen(msg),0);
Buffer overflow is exactly what it is.
if ((valread = read( sd , buffer, 1024)) == 0)
Here you are lying to the operating system about the size of buffer, which is 400, not 1024. This line of code should be
if ((valread = read( sd , buffer, sizeof buffer)) == 0)
and you also need to check it for -1.

C++ multithread socket cannot receive client data

I would like to create a multithreaded socket server. I have the server working fine, but when i try to move my code into a worker function the server stops working when reading the client data.
original code:
main.cpp
int sock;
main(){
SocketServer *ss = new SocketServer(8888);
pthread_t thread;
if(ss != NULL){
while(true){
sock = ss->Accept();
char* out;
ss->GetRequest(sock, out);
}
}
}
SocketServer.cpp
void SocketServer::GetRequest(int msgsock, char* out){
char buf[1024];
int rval;
std::cout<<"before read\n";
if ((rval = read(msgsock, buf, 1024)) < 0){
perror("reading socket");
}else{
strcpy(out,buf);
}
std::cout<<"after read\n";
}
After adding threads:
main.cpp
int sock;
main(){
SocketServer *ss = new SocketServer(8888);
pthread_t thread;
if(ss != NULL){
while(true){
sock = ss->Accept();
pthread_create(&thread, NULL, SocketThread, &(*ss));
pthread_detach(thread);
}
}
}
static void* SocketThread(void* lp){
SocketServer *ss = (SocketServer*) lp;
char* out;
ss->GetRequest(sock, out);
}
Original outputs:
before read
after read
New outputs:
before read
This is broken:
if ((rval = read(msgsock, buf, 1024)) < 0){
perror("reading socket");
}else{
strcpy(out,buf);
You are ignoring rval unless it signals an error. It should be:
if ((rval = read(msgsock, buf, 1024)) < 0){
perror("reading socket");
else if (rval == 0) {
// peer closed the connection
close(msgsock); // or closesocket(), depending on your platform
break;
}else{
strncpy(out,buf,rval);
and this is also broken:
sock = ss->Accept();
pthread_create(&thread, NULL, SocketThread, &(*ss));
The thread started to handle the client has no interest in the listening socket. What it needs is the accepted socket sock, and it needs to get it in such a way that it won't be overridden on the next call. Typically sock is a local variable in the accept loop and is passed via pthread_create().

c++ winsock - server communicates only with single client while it should communicate with every client

I am writing a single chat program with GUI. I wanted to write a server that would accept many clients. Every client can connect successfuly. But there is a strange problem with sending and receiving data. I use select() and a thread to handle many sockets at the same time. If a client sends some data to server, it will receive it and send it back to that client (the client is especially written without "prediction"). But the server won't send it further to another clients (like every client had its own private conversation with the server). Here's my code:
// this is rewritten from the Beej's tutorial with a little and insignificant changes
/* in the thread */
fd_set mainfd;
fd_set readfd;
// sin-size, newfd, maxfd - int
while(TRUE)
{
readfd = mainfd;
if(select(maxfd+1, &readfd, NULL, NULL, NULL) == -1)
{
MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
itoa(GetLastError(), buf, 10);
MessageBoxA(NULL, buf, buf, 0);
break;
}
for(int i = 0; i <= maxfd; i++)
{
char* psr;
char srMsg[256];
if(FD_ISSET(i, &readfd))
{
if(i == mainSocket)
{
sin_size = sizeof(their_addr);
newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
if(newfd == SOCKET_ERROR)
{
AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
}
else
{
FD_SET(newfd, &mainfd);
if(newfd > maxfd)
{
maxfd = newfd;
}
}
}
else
{
len = recv(i, srMsg, 256, 0);
if(len == 0 || len == SOCKET_ERROR)
{
AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
close(i);
FD_CLR(i, &mainfd);
}
else
{
AddTextToEdit(hStaticChat, srMsg, TRUE);
for(int j = 0; j <= maxfd; j++)
{
if(FD_ISSET(j, &readfd))
{
send(j, srMsg, len, 0);
}
}
}
}
}
}
}
You are only sending data to the clients whos fd is in readfd, that is, only to that one which just communicated to you. Try to test FD_ISSET(j, mainfd) instead.
This code is not valid under WinSock. Windows does not deal with sockets using integer file descriptors like other platforms do. Sockets are represented using actual kernel objects instead, so you can't use loop counters as socket handles and such. There is also API differences (closesocket() instead of close(), maxfd is ignored by select(), FD_XXX() expect SOCKET handles instead of int, etc).
On Windows, you need to use something more like this instead:
fd_set mainfd;
SOCKET newfd;
int sin_size;
...
while(TRUE)
{
fd_set readfd = mainfd;
if (select(0, &readfd, NULL, NULL, NULL) == SOCKET_ERROR)
{
itoa(WSAGetLastError(), buf, 10);
MessageBoxA(NULL, "Error while trying to accept incoming connections (select)", "Error", 16);
MessageBoxA(NULL, buf, buf, 0);
break;
}
for(int i = 0; i < readfd.fd_count; i++)
{
if (readfd.fd_array[i] == mainSocket)
{
sin_size = sizeof(their_addr);
newfd = accept(mainSocket, (struct sockaddr*)&their_addr, &sin_size);
if (newfd == INVALID_SOCKET)
{
AddTextToEdit(hStaticChat, "* Error: couldn't accept incoming connection.", TRUE);
}
else
{
// Note that fd_set can only hold FD_SETSIZE (64) sockets as a time!
FD_SET(newfd, &mainfd);
}
}
else
{
char srMsg[257];
len = recv(readfd.fd_array[i], srMsg, 256, 0);
if (len < 1)
{
if (len == 0)
AddTextToEdit(hStaticChat, "* Client has disconnected", TRUE);
else
AddTextToEdit(hStaticChat, "* Error: couldn't read from a client connection.", TRUE);
closesocket(readfd.fd_array[i]);
FD_CLR(readfd.fd_array[i], &mainfd);
}
else
{
srMsg[len] = 0;
AddTextToEdit(hStaticChat, srMsg, TRUE);
for (int j = 0; j < mainfd.fd_count; j++)
{
if (mainfd.fd_array[i] != mainSocket)
send(mainfd.fd_array[j], srMsg, len, 0);
}
}
}
}
}

Packet sniffer only detects sent packets

I have been working on a packet sniffer just for fun/education and it's been going quite well. The problem that I'm having is that the only packets appearing in recvfrom() are SENT packets i.e. packets with my IP as their source IP and not my WAN IP but my LAN IP (if that makes sense).
I tried fixing it and spent hours reading everything I could find but to me there seems no solution.
I am 100% positive that the code I've written does not detect all packets because wireshark detects way more (ingoing and outgoing) and it's obvious that there is not only outgoing traffic from my PC.
packetsize = recvfrom(sniffer , Buffer , 65536 , 0 , (SOCKADDR *)&SenderAddr , &SenderAddrSize);
for (int x = 12; x < 16; x++)
{
printf("%c ",Buffer[x]);
}
std::cout << "\n";
iphdr = (IPV4_HDR *)Buffer;
memset(&source, 0, sizeof(source));
source.sin_addr.s_addr = iphdr->ip_srcaddr;
std::cout << inet_ntoa(source.sin_addr) << "\n\n";
That's the point where it all goes down (there is way more code but not important), the structures are all properly defined so there is no errors there (else I couldn't be getting the same IP adress over and over in every single packet).
Also there is another, non-existent IP from my network showing up as source IP and very occasionally the source IP is 0.0.0.0 which I both find very weird.
Buffer is declared as
char *Buffer = (char *)malloc(65536);
so it's signed char and I have no idea how I could manually "extract" the separate parts of the header from these values.
I hope anyone can explain to me that recvfrom is actually not losing packets and that I'm doing something wrong.
Also I'd like to know how to interpret the output from recvfrom, i.e. converting signed to unsigned or maybe some other way?
I hope I made my problem clear, thanks in advance.
EDIT. Bigger chunk of my code
int main()
{
SOCKET sniffer;
struct in_addr addr;
int in;
char hostname[100];
struct hostent *local;
WSADATA wsa;
// Initialise Winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0)
{
printf("WSAStartup() failed.\n");
getchar();
return 1;
}
printf("Initialised");
// Create a RAW Socket
printf("\nCreating RAW Socket....");
sniffer = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
if (sniffer == INVALID_SOCKET)
{
printf("Failed to create raw socket.\n");
printf("WSA throws error code %d\n",WSAGetLastError());
printf("Run as admin to fix\n");
getchar();
return 1;
}
printf("Created.");
// Retrieve the local hostname
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR)
{
printf("WSA throws error code %d\n",WSAGetLastError());
getchar();
return 1;
}
printf("\nHost name : %s \n",hostname);
bool retry = true;
signed int maxnumber = -1;
do
{
// Retrieve the available IPs of the local host
local = gethostbyname(hostname);
printf("\nAvailable Network Interfaces \n");
if (local == NULL)
{
printf("WSA throws error code %d.\n",WSAGetLastError());
getchar();
return 1;
}
// Available interfaces
for (i = 0; local->h_addr_list[i] != 0; i++) // h_addr_list is null terminated
{
// local is hostent struct in which information about the host is stored
// in_addr represents an IPv4 internet address. inet_ntoa: in_addr to string (ip adress)
memmove(&addr, local->h_addr_list[i], sizeof(struct in_addr));
//memmove(destination, source, number of bytes to copy)
printf("Interface Number : %d Address : %s\n", i, inet_ntoa(addr));
maxnumber = i;
printf("\n");
}
// Choose interface
if (maxnumber > 0)
{
printf("Enter the interface number you would like to sniff : ");
scanf("%d",&in);
printf(" in: %d | maxnumber: %d \n", in, maxnumber);
if (in <= maxnumber)
{
retry = false;
} else {
printf("Interface number %d with adress %d does not exist \n\n", in, local->h_addr_list[in]);
}
}
else
{
printf("Only one interface available");
in = 0;
retry = false;
}
} while (retry);
self = addr;
CreateFolder(self);
memset(&dest, 0, sizeof(dest));
memcpy(&dest.sin_addr.s_addr,local->h_addr_list[in],sizeof(dest.sin_addr.s_addr));
dest.sin_family = AF_INET;
dest.sin_port = htons(source.sin_port);//=0;
printf("\nBinding socket to local system and port 0 ...");
if (bind(sniffer,(struct sockaddr *)&dest,sizeof(dest)) == SOCKET_ERROR)
{
printf("bind(%s) failed.\n", inet_ntoa(addr));
getchar();
return 1;
}
printf("Binding successful");
j=1;
unsigned long nbytesret;
printf("\nSetting socket to sniff...");
if (WSAIoctl(sniffer, SIO_RCVALL, &j, sizeof(j), 0, 0, &nbytesret , 0 , 0) == SOCKET_ERROR)
{
printf("WSAIoctl() failed.\n");
getchar();
return 1;
}
printf("Socket set\n");
printf("Press enter to start\n");
getchar();
printf("Packet Capture Statistics...\n");
StartSniffing(sniffer);
printf("Ending sniffer, press enter to exit \n");
getchar();
closesocket(sniffer);
WSACleanup();
return 0;
}
void StartSniffing(SOCKET sniffer)
{
char *Buffer = (char *)malloc(65536);
int packetsize;
if (Buffer == NULL)
{
printf("malloc() failed.\n");
getchar();
return;
}
do
{
packetsize = recvfrom(sniffer , Buffer , 65536 , 0 , (SOCKADDR *)&SenderAddr , &SenderAddrSize);
if(packetsize > 0)
{
ProcessPacket(Buffer, packetsize);
}
else
{
printf( "recvfrom() failed.\n");
getchar();
}
}
while (packetsize > 0);
free(Buffer);
}
To read from the buffer as unsigned, use reinterpret_cast like so to get an unsigned pointer:
unsigned char *uBuffer = reinterpret_cast<unsigned char *>(Buffer);