I am making a Winsock application, and something fails in the server when it tries to make the shutdown funtion. The project builds and runs, but when the first connection of the client arrives it takes it and fails showing in the comand line: "shutdown failed with error: 10038". I have been reading about the error and it is said that it is usually because the funcion shutdown is applied to something that is not a SOCKET, or like that. But when debugging I saw that apparently it is a Socket, so I don't know what to do.
#undef UNICODE
#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
// Need to link with Ws2_32.lib
#pragma comment (lib, "Ws2_32.lib")
// #pragma comment (lib, "Mswsock.lib")
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "27015"
//Function declaration
const std::string currentDateTime();
int __cdecl NewClient(SOCKET ListenSocket, SOCKET ClientSocket, char *recvbuf, int recvbuflen, int iSendResult, int iResult);
std::string CommandGet(char *recvbuf);
void Login(char *recvbuf);
void print_data(char *recvbuf);
string GetUsername(char *recvbuf);
string GetThirdToken(char *recvbuf);
//Map & Struct creation
struct message{
static unsigned int last_id;
unsigned int id;
std::string baa;
std::string timestamp;
message(){};
message(const std::string& recvbuf_baa,const std::string& a_timestamp) :
baa(recvbuf_baa), timestamp(a_timestamp), id(++last_id)
{
}
};
map<std::string,std::vector<message *> > data;
map<std::string,std::vector<string> > followers;
//Global variables
unsigned int message::last_id = 0;
map<std::string,bool> loggedin;
int __cdecl main(void)
{
WSADATA wsaData;
int iResult;
SOCKET ListenSocket = INVALID_SOCKET;
SOCKET ClientSocket = INVALID_SOCKET;
struct addrinfo *result = NULL;
struct addrinfo hints;
int iSendResult=0;
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
while(true){
// Resolve the server address and port
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Create a SOCKET for connecting to server
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Setup the TCP listening socket
iResult = ::bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
// No longer need server socket
closesocket(ListenSocket);
return NewClient(ListenSocket, ClientSocket, recvbuf, recvbuflen, iSendResult, iResult);
}
}
int __cdecl NewClient(SOCKET ListenSocket, SOCKET ClientSocket, char *recvbuf, int recvbuflen, int iSendResult, int iResult){
// Receive until the peer shuts down the connection
do {
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("Bytes received: %d\n", iResult);
std::string cmd=CommandGet(recvbuf);
if (cmd=="log"){
std::string usrn=GetUsername(recvbuf);
std::string recvbuf_str="";
for(auto it=loggedin.begin();it!=loggedin.end();it++){
if ((*it).first==usrn){
recvbuf_str="loggedin";
if ((*it).second){
recvbuf_str="cantlogin";
break;
}
else{
loggedin[usrn]=1;
break;
}
break;
}
}
if (recvbuf_str==""){
recvbuf_str="newlogin";
Login(recvbuf);
}
iSendResult = send( ClientSocket, recvbuf_str.c_str(), iResult, 0 );
if (iSendResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
}
}
else if (iResult == 0){
printf("Connection closing...\n");
closesocket(ClientSocket);}
else {
printf("recv failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// shutdown the connection since we're done
iResult = shutdown(ClientSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
printf("shutdown failed with error: %d\n", WSAGetLastError());
closesocket(ClientSocket);
WSACleanup();
return 1;
}
// cleanup
closesocket(ClientSocket);
WSACleanup();
return 0;
}
const std::string currentDateTime() {
time_t now = time(0);
struct tm tstruct;
char buf[80];
localtime_s(&tstruct, &now);
strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct);
return buf;
}
void Login(char *recvbuf){
std::string usrn= GetUsername(recvbuf);
std::vector<message *> messages;
data[usrn]=messages;
std::vector<string> follow;
followers[usrn]=follow;
loggedin[usrn]=1;
}
void print_data(char *recvbuf){
std::string usrn= GetUsername(recvbuf);
for(auto mapIt = data.cbegin(); mapIt != data.cend(); ++mapIt)
{
std::cout << "printing data for " << mapIt->first << ":" << std::endl;
for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter)
{
std::cout << (*vectIter)->baa << ", " << (*vectIter)->timestamp << ", "
<< (*vectIter)->id << std::endl;
}
}
}
void print_followers(char *recvbuf){
std::string usrn= GetUsername(recvbuf);
for(auto mapIt = followers.cbegin(); mapIt != followers.cend(); ++mapIt)
{
std::cout << "printing followers for " << mapIt->first << ":" << std::endl;
for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter)
{
std::cout << (*vectIter) << endl;
}
}
}
std::string CommandGet(char *recvbuf){
int start0=0;
std::string recvbuf_cmd;
std::string recvstr(recvbuf);
start0=recvstr.find(';');
recvbuf_cmd=recvstr.substr(0,start0);
return recvbuf_cmd;
}
string GetUsername(char *recvbuf){
int start0=0, start1=0;
std::string recvbuf_usrn;
std::string recvstr(recvbuf);
start0=recvstr.find(';');
start1=recvstr.find(';',start0+1);
recvbuf_usrn=recvstr.substr(start0+1,start1-start0-1);
return recvbuf_usrn;
}
string GetThirdToken(char *recvbuf){
int start0=0, start1=0, start2=0;
std::string recvbuf_thirdtoken;
std::string recvstr(recvbuf);
start0=recvstr.find(';');
start1=recvstr.find(';',start0+1);
start2=recvstr.find(';',start1+1);
recvbuf_thirdtoken=recvstr.substr(start1+1,start2-start1-1);
return recvbuf_thirdtoken;
}
I upload the whole project in case you want to check it deeper( https://mega.nz/#!dtcx1DCL!dKWV2ryDDfiXv5H3Mi2p4PrBpie2CGrGJOTAwvQAV8M), but the problem is located in the server(which i simplified the code), the client is just so you can start the conection entering the username(but dont care about it).
Thank you in advance, any help will be appreciated.
Lets consider the following lines, take from your shown source:
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
...
else if (iResult == 0){
printf("Connection closing...\n");
closesocket(ClientSocket);}
...
iResult = shutdown(ClientSocket, SD_SEND);
When recv
returns zero that means the connection has been closed (nicely) by the other end. When that happens you call closesocket
to close the socket. But then you proceed to unconditionally call shutdown
on the closed socket, leading to the error you got.
Simple solution? Just close the socket using closesocket
once, no need for shutdown
here that I can see (there seldom are).