I'm doing an implementation of FTP, now I'm implementing the RETR command, I take the errno code 88 when I try to do "get FILENAME".
I think that the error can be the conversion of unsigned to uint32_t and uint16_t in the port command.
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <cerrno>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include "common.h"
#include "ClientConnection.h"
ClientConnection::ClientConnection(int s) {
int sock = (int)(s);
char buffer[MAX_BUFF];
control_socket = s;
// Consultar la documentación para conocer el funcionamiento de fdopen.
fd = fdopen(s, "a+");
if (fd == NULL){
std::cout << "Connection closed" << std::endl;
fclose(fd);
close(control_socket);
ok = false;
return ;
}
ok = true;
data_socket = -1;
};
ClientConnection::~ClientConnection() {
fclose(fd);
close(control_socket);
}
int connect_TCP(uint32_t address, uint16_t port) {
struct sockaddr_in sin;
struct hostent
*hent;
int s;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = address;
//if(hent = gethostbyname(address))
//memcpy(&sin.sin_addr,hent->h_addr,hent->h_length);
//else if ((sin.sin_addr.s_addr = inet_addr((char*)address)) == INADDR_NONE)
//errexit("No puedo resolver el nombre \"%s\"\n", address);
s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0){
printf("No se puede crear el socket\n");
return 0;
}
if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0){
printf("No se puede conectar con %u\n", address);
return 0;
}
return s;
}
void ClientConnection::stop() {
close(data_socket);
close(control_socket);
parar = true;
}
#define COMMAND(cmd) strcmp(command, cmd)==0
void ClientConnection::WaitForRequests() {
if (!ok) {
return;
}
fprintf(fd, "220 Service ready\n");
while(!parar) {
fscanf(fd, "%s", command);
if (COMMAND("USER")) {
fscanf(fd, "%s", arg);
fprintf(fd, "331 User name ok, need password\n");
}
else if (COMMAND("PWD")) {
}
else if (COMMAND("PASS")) {
char pass[30];
fscanf(fd,"%s",pass);
fprintf(fd,"230 User logged in\n");
}
else if (COMMAND("PORT")) {
unsigned ip[4];
unsigned port[2];
fscanf(fd,"%u,%u,%u,%u,%u,%u",&ip[0],&ip[1],&ip[2],&ip[3],&port[0],&port[1]);
uint32_t aux1;
uint16_t aux2;
aux1 = ip[3] << 24 | ip[2] << 16 | ip[1] << 8 | ip[0];
aux2 = port[1]*256 + port[0];
data_socket = connect_TCP(aux1,aux2);
fprintf(fd,"200 OK\n");
}
else if (COMMAND("PASV")) {
}
else if (COMMAND("CWD")) {
}
else if (COMMAND("STOR") ) { //put
FILE* fp = fopen("filename","w+");
int size_buffer = 512;
char buffer[size_buffer];
int recived_datas;
while(recived_datas == size_buffer){
datos_recibidos = recv(data_socket,buffer,size_buffer,0);
fwrite(buffer,1,recived_datas,fp);
}
close(data_socket);
fclose(fp);
}
else if (COMMAND("SYST")) {
fprintf(fd,"SYSTEM DETAILS\n");
}
else if (COMMAND("TYPE")) {
fprintf(fd,"type 1");
}
else if (COMMAND("RETR")) {
fscanf(fd,"%s",arg);
std::cout << "Argument: " << arg << std::endl;
FILE* fp = fopen(arg,"r+");
int sent_datas;
int size_buffer = 512;
char buffer[size_buffer];
std::cout << "Buffer size = " << size_buffer << std::endl;
do{
sent_datas = fread(buffer,size_buffer,1,fp);
printf("Code %d | %s\n",errno,strerror(errno));
send(data_socket,buffer,sent_datas,0);
printf("Code %d | %s\n",errno,strerror(errno));
}while(sent_datas == size_buffer);
close(data_socket);
fclose(fp);
fprintf(fd,"Transferencia completada");
}
else if (COMMAND("QUIT")) {
}
else if (COMMAND("LIST")) {
}
else {
fprintf(fd, "502 Command not implemented.\n"); fflush(fd);
printf("Comando : %s %s\n", command, arg);
printf("Error interno del servidor\n");
}
}
fclose(fd);
return;
};
Error code 88 is ENOTSOCK meaning that your tried to do a socket operation on "not a socket".
The offending line, I believe is:
send(data_socket,buffer,sent_datas,0);
It looks like in your RETR section you never set data_socket to a valid socket with your connect_TCP function, as you did in PORT. Are you certain that data_socket is a valid fd when you call your RETR function?
Related
I've recently into c/c++ socket programming so I just made simple program that server and client respond each other. My server is in VMware( linux fedora) and client is windows(in visual studio 2017).
And it worked(pls notice that server and client are in one laptop)..
I also tried same client code with another computer(my deskTop) and got a WSAETIMEDOUT(10060)
error. The error was captured in connect() function in client code.
I have no idea how to solve :(
Could anybody help me?
Here's a client code
#include <iostream>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
using namespace std;
#define DEFAULT_BUFLEN 512
int main(int argc, char *argv[]) {
WSADATA wsaData;
SOCKET connectSocket;
SOCKADDR_IN servAddr;
char sendBuf[DEFAULT_BUFLEN];
char recvBuf[DEFAULT_BUFLEN];
char nickName[DEFAULT_BUFLEN];
int recvLen = 0;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "start up error";
exit(1);
}
connectSocket = socket(PF_INET, SOCK_STREAM, 0);
if (connectSocket == INVALID_SOCKET) {
cout << "socket creation error";
exit(1);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(argv[1]);
servAddr.sin_port = htons(atoi(argv[2]));
if (connect(connectSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
cout << "connect error: " << WSAGetLastError();
exit(1);
}
while (1) {
recvLen = recv(connectSocket, recvBuf, sizeof(recvBuf), 0);
if (recvLen > 0) {
if (strcmp(recvBuf, "Exit") == 0)
break;
cout << recvBuf;
//cin >> nickName;
cin.getline(nickName, DEFAULT_BUFLEN);
send(connectSocket, nickName, sizeof(nickName),0);
}
else if (recvLen == 0)
cout << "Connection closed";
else if (recvLen == -1)
cout << "Connection failed";
}
closesocket(connectSocket);
WSACleanup();
return 0;
}
Blockquote
and server code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <iostream>
#include <string>
#define DEFAULT_LEN 512
#define DEFAULT_CLIENT_NUM 30
using namespace std;
char nickNameCommand[]="Please set your nickName:";
void error_handling(char * message);
class Client {
private:
char nickName[DEFAULT_LEN];
int clientSock;
public:
struct sockaddr_in clnt_addr;
int& getClientSock(){
return clientSock;
}
};
class Server {
private:
int serv_sock;
char informClientNickName[DEFAULT_LEN] = "Your NickName is ";
public:
Server(){
}
char message[DEFAULT_LEN]= "";
char clientNickName[DEFAULT_CLIENT_NUM][DEFAULT_LEN];
struct sockaddr_in serv_addr;
void setServSock(int value){
serv_sock = value;
}
int getServSock(){
return serv_sock;
}
void setInformClientNickName(int clientNum){
strcat(informClientNickName,clientNickName[clientNum]);
strcat(message , informClientNickName);
}
char* getInformClientNickName(){
return informClientNickName;
}
};
int main(int argc,char * argv[])
{
Client clientSocket[DEFAULT_CLIENT_NUM];
Server server;
int clientNum=0;
int recvLen=0;
socklen_t clnt_addr_size;
char message[DEFAULT_LEN];
if(argc!=2)
{
printf("Usage: %s <port>\n",argv[0]);
exit(1);
}
server.setServSock(socket(PF_INET,SOCK_STREAM,0));
if(server.getServSock() == -1)
error_handling("socket() error");
memset(&(server.serv_addr),0,sizeof(server.serv_addr));
server.serv_addr.sin_family=AF_INET;
server.serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server.serv_addr.sin_port=htons(atoi(argv[1]));
if(bind(server.getServSock(),(struct sockaddr*)&
(server.serv_addr),sizeof(server.serv_addr)) ==-1)
error_handling("bind() error");
if(listen(server.getServSock(),5)==-1)
error_handling("listen() error");
clnt_addr_size=sizeof(clientSocket[0].clnt_addr);
while(1) {
clientSocket[clientNum].getClientSock() = accept(server.getServSock(),
(struct sockaddr*)&(clientSocket[clientNum].clnt_addr),&clnt_addr_size);
if(clientSocket[clientNum].getClientSock()==-1)
error_handling("accept() error");
else{
write(clientSocket[clientNum].getClientSock(),nickNameCommand,sizeof(nickNameCommand));
read(clientSocket[clientNum].getClientSock(),(void*)(server.clientNickName[clientNum]),DEFAULT_LEN);
}
cout << "Received name is : " << server.clientNickName[clientNum]<<endl;
clientNum++;
cout << "ClientNum: " << clientNum <<endl;
recvLen=0;
for(int i=0;i<clientNum;i++){
server.setInformClientNickName(i);
write(clientSocket[clientNum].getClientSock(),server.message,sizeof(server.message));
}
}
for(int i=0;i<clientNum;i++)
close(clientSocket[i].getClientSock());
close(server.getServSock());
return 0;
}
void error_handling(char * message)
{
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
I want to code this kind of program so that I can merge it with my ip handler program that adds ip addresses onto a database. My question now is how can I get the external ip address of the computer and not the router nor the ISP provider or something else. It is worth noting that I'm on Visual Studio 2017. Please note I'm using this for learning purposes and not for malicious purposes. Here's my revised version of the code:
IpHandler.cpp
#include "stdafx.h"
#include "IpHandler.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPCRECATED
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
#pragma comment(lib,"ws2_32.lib")
using std::cout; using std::locale; using std::istringstream;
string IpHandler::website_HTML = "";
char IpHandler::buffer[10000];
IpHandler::IpHandler(){ }
void IpHandler::get_Website(string url) {
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
struct hostent *host;
string get_http = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
return;
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
host = gethostbyname(url.c_str());
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
cout << "Could not connect";
system("pause");
return;
}
send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
website_HTML += buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
}
string IpHandler::GetExternalIp() {
locale local;
char lineBuffer[200][80] = { ' ' };
char ip_address[16];
int lineIndex = 0;
get_Website("api.ipify.org");
for (int i = 0; i < website_HTML.length(); ++i) { website_HTML[i] = tolower(website_HTML[i], local); }
istringstream ss(website_HTML);
string stoken;
while (getline(ss, stoken, '\n')) {
strcpy_s(lineBuffer[lineIndex], stoken.c_str());
int dot = 0;
for (int ii = 0; ii< strlen(lineBuffer[lineIndex]); ii++) {
if (lineBuffer[lineIndex][ii] == '.') dot++;
if (dot >= 3) {
dot = 0;
strcpy_s(ip_address, lineBuffer[lineIndex]);
}
}
lineIndex++;
}
return ip_address;
}
IpHandler::~IpHandler()
{
}
IpHandler.h
#pragma once
#include <string>
using std::string;
class IpHandler
{
static string website_HTML;
static void get_Website(string url);
static char buffer[10000];
public:
IpHandler();
static string GetExternalIp();
~IpHandler();
};
I have a client who wants to send a message to the server over UDP.
I have a message struct:
struct Msg1
{
uint8_t tag = 1;
uint32_t nonce = 0;
uint16_t length = 0;
char *name;
};
I convert it to an uint32_t array, send it over UDP and reconvert it. But the output is:
1 Byte: TAG:
4 Byte: NONCE: 1111111
2 Byte: LENGTH: 5
8 Byte: NAME:
Now I am confused, because two variables are right and two are not. Maybe someone has an idea?
// EDIT example files
/* Client.cpp */
#include "Client.h"
#include <gmp.h>
Client::Client(){}
void Client::start()
{
this->prepareMsg1();
this->sendMsg1();
}
void Client::prepareMsg1()
{
// generate random Na and copy
MyRandom *r = new MyRandom();
myMsg1->nonce = r->getNewRandom();
this->na = myMsg1->nonce;
// copy name and length
myMsg1->name = new char[nameMsg1.size()];
strcpy(myMsg1->name, nameMsg1.c_str());
myMsg1->length = nameMsg1.size();
}
void Client::sendMsg1()
{
// set the size of data
udp->data = new uint8_t[sizeof(myMsg1) - 1 + myMsg1->length];
int pos = 0;
memcpy(udp->data, &myMsg1->tag, sizeof(myMsg1->tag));
memcpy(udp->data + (pos += sizeof(myMsg1->tag)), &myMsg1->nonce, sizeof(myMsg1->nonce));
memcpy(udp->data + (pos += sizeof(myMsg1->nonce)), &myMsg1->length, sizeof(myMsg1->length));
memcpy(udp->data + (pos += sizeof(myMsg1->length)), myMsg1->name, myMsg1->length);
udp->write(client);
}
/* Client.h */
#ifndef CLIENT_H_
#define CLIENT_H_
#include <cstdint> // int32_t
#include <gmp.h>
#include <iostream> // cout, endl
#include <string> // string
#include <stdlib.h>
#include "Random.h"
#include "messages.h"
#include "UDP.h"
using std::cout;
using std::endl;
using std::string;
class Client
{
public:
Client();
void start();
void prepareMsg1();
void sendMsg1();
string nameMsg1 = "Alice";
Msg1 *myMsg1 = new Msg1();
UDP *udp = new UDP();
};
#endif /* CLIENT_H_ */
/* UDP.cpp */
#include "UDP.h"
void die(char *s)
{
perror(s);
exit(1);
}
UDP::UDP(){}
void UDP::listen()
{
data = new uint8_t[BUFLEN];
struct sockaddr_in si_me, si_other;
int s = sizeof(si_other), recv_len;
socklen_t slen = sizeof(si_other);
// create UDP socket
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
// bind socket to port
if (bind(s, (struct sockaddr*) &si_me, sizeof(si_me)) == -1)
die("bind");
fflush(stdout);
if ((recv_len = recvfrom(s, data, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1)
die("recvfrom()");
close(s);
}
void UDP::write(Device d)
{
struct sockaddr_in si_other;
int s = sizeof(si_other);
socklen_t slen = sizeof(si_other);
memset((char *) &si_other, 0, sizeof(si_other));
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
die("socket");
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if(d == client)
{
if (inet_aton(SERVER, &si_other.sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
}
else if(d == server)
{
if (inet_aton(CLIENT, &si_other.sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
}
if (sendto(s, data, sizeof(data), 0, (struct sockaddr *) &si_other, slen) == -1)
die("sendto()");
close(s);
}
/* UDP.h */
#ifndef UDP_H_
#define UDP_H_
#include <iostream> // cout, endl
#include <stdio.h> // printf
#include <string.h> // memset
#include <stdlib.h> // exit(0);
#include <unistd.h> // close
#include <arpa/inet.h>
#include <sys/socket.h>
#include "messages.h"
#define BUFLEN 512
#define PORT 8888
#define CLIENT "192.168.2.106"
#define SERVER "192.168.2.104"
using std::cout;
using std::endl;
class UDP
{
public:
UDP();
void listen();
void write(Device);
bool output = true;
uint8_t *data = new uint8_t[BUFLEN];
};
#endif /* UDP_H_ */
/* Server.cpp */
#include "Server.h"
Server::Server(){}
Server::~Server(){}
void Server::start()
{
udp->listen();
this->printMsg1();
}
void Server::printMsg1()
{
int pos = 0;
memcpy(&myMsg1->tag, udp->data, sizeof(myMsg1->tag));
memcpy(&myMsg1->nonce, udp->data + (pos += sizeof(myMsg1->tag)), sizeof(myMsg1->nonce));
memcpy(&myMsg1->length, udp->data + (pos += sizeof(myMsg1->nonce)), sizeof(myMsg1->length));
myMsg1->name = new char[myMsg1->length];
memcpy(myMsg1->name, udp->data + (pos += myMsg1->length), myMsg1->length);
if(output)
{
cout << sizeof(myMsg1->tag) << " Byte: TAG : " << (int8_t) myMsg1->tag
<< endl;
cout << sizeof(myMsg1->nonce) << " Byte: NONCE : " << myMsg1->nonce
<< endl;
cout << sizeof(myMsg1->length) << " Byte: LENGTH : " << myMsg1->length
<< endl;
cout << sizeof(myMsg1->name) << " Byte: NAME : ";
for(int i = 0; i<myMsg1->length; i++)
cout << myMsg1->name[i];
}
}
/* Server.h */
#ifndef SERVER_H_
#define SERVER_H_
#include <cstdint> // int32_t
#include <gmp.h>
#include <iostream> // cout, endl
#include <string> // string
#include <stdlib.h>
#include "Random.h"
#include "messages.h"
#include "UDP.h"
using std::cout;
using std::endl;
using std::string;
class Server
{
public:
Server();
virtual ~Server();
void start();
void printMsg1();
Msg1 *myMsg1 = new Msg1();
UDP *udp = new UDP();
};
#endif /* SERVER_H_ */
i wrote an script, who can create an connection to an HTTP Server and shows the content of the website in the console.
Very easy.
But i want to connect to an https server and do the same procedures.
I searched at google and didn't found what i searched.
Please help me and give me an tutorial who can i use the openssl library.
I tried myself on the openssl library, but the library is very complicated and difficult to understand.
Here is my code of the http client:
#include <iostream>
#include <ctype.h>
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <string>
#include <arpa/inet.h>
#include <openssl/ssl.h>
using namespace std;
int sock;
struct sockaddr_in client;
int PORT = 80;
int main(int argc, char const *argv[])
{
bzero(&client, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons( PORT );
client.sin_addr.s_addr = inet_addr("172.16.0.6");
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
cout << "Error creating socket." << endl;
exit(1);
}
if ( connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0 ) {
close(sock);
cout << "Could not connect" << endl;
exit(1);
}
stringstream ss;
ss << "GET /" << "\r\n"
<< "Host: 172.16.1.4\r\n"
<< "Accept: application/json\r\n"
<< "Connection: close"
<< "\r\n\r\n";
string request = ss.str();
if (send(sock, request.c_str(), request.length(), 0) != (int)request.length()) {
cout << "Error sending request." << endl;
exit(1);
}
char cur;
while ( read(sock, &cur, 1) > 0 ) {
cout << cur;
}
return 0;
}
Here is a sample SSL client that connects to https://about.google/intl/en/ and prints downloaded a page : SSLClient.cpp
//============================================================================
// Name : SSLClient.cpp
// Compiling : g++ -c -o SSLClient.o SSLClient.cpp
// g++ -o SSLClient SSLClient.o -lssl -lcrypto
//============================================================================
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>
using namespace std;
SSL *ssl;
int sock;
int RecvPacket()
{
int len=100;
char buf[1000000];
do {
len=SSL_read(ssl, buf, 100);
buf[len]=0;
printf("%s\n",buf);
// fprintf(fp, "%s",buf);
} while (len > 0);
if (len < 0) {
int err = SSL_get_error(ssl, len);
if (err == SSL_ERROR_WANT_READ)
return 0;
if (err == SSL_ERROR_WANT_WRITE)
return 0;
if (err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL || err == SSL_ERROR_SSL)
return -1;
}
}
int SendPacket(const char *buf)
{
int len = SSL_write(ssl, buf, strlen(buf));
if (len < 0) {
int err = SSL_get_error(ssl, len);
switch (err) {
case SSL_ERROR_WANT_WRITE:
return 0;
case SSL_ERROR_WANT_READ:
return 0;
case SSL_ERROR_ZERO_RETURN:
case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL:
default:
return -1;
}
}
}
void log_ssl()
{
int err;
while (err = ERR_get_error()) {
char *str = ERR_error_string(err, 0);
if (!str)
return;
printf(str);
printf("\n");
fflush(stdout);
}
}
int main(int argc, char *argv[])
{
int s;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
printf("Error creating socket.\n");
return -1;
}
struct sockaddr_in sa;
memset (&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("173.194.222.139"); // address of google.ru
sa.sin_port = htons (443);
socklen_t socklen = sizeof(sa);
if (connect(s, (struct sockaddr *)&sa, socklen)) {
printf("Error connecting to server.\n");
return -1;
}
SSL_library_init();
SSLeay_add_ssl_algorithms();
SSL_load_error_strings();
const SSL_METHOD *meth = TLSv1_2_client_method();
SSL_CTX *ctx = SSL_CTX_new (meth);
ssl = SSL_new (ctx);
if (!ssl) {
printf("Error creating SSL.\n");
log_ssl();
return -1;
}
sock = SSL_get_fd(ssl);
SSL_set_fd(ssl, s);
int err = SSL_connect(ssl);
if (err <= 0) {
printf("Error creating SSL connection. err=%x\n", err);
log_ssl();
fflush(stdout);
return -1;
}
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
char *request = "GET https://about.google/intl/en/ HTTP/1.1\r\n\r\n";
SendPacket(request);
RecvPacket();
return 0;
}
Note that if you want to exchange data between client and server with openssl, you might need to process error codes SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE as described in documentation. But it's not necessary here as HTTPS protocol is serial.
I'm trying to write a game that will let multiple clients connect and play - below is the relevant code (it's very messy - cleaning up later):
Edit: I realized it's a lot of scrolling... the crash occurs towards the end of the game during:
std::cout << black_hits << " black hits & " << white_hits
<< " white hits.\n";
if (black_hits == 4) {
std::cout << "you won!\n";
std::cin.ignore().get();
close(client); //<<<< CRASH HERE
return 0;
}
Not really a crash I guess... but close enough :)
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define BACKLOG 10
#define MAXDATASIZE 100
typedef enum {RED,GREEN,BLUE,YELLOW,ORANGE} color;
int StartMasterMind(int client, sockaddr_storage addr_in);
struct msgstruct {
int length;
char* send_data;
};
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int tcp_connect(const char *serv, const char *host = NULL)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(host, serv, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
//if (send(new_fd, "Hello, world!", 13, 0) == -1)
// perror("send");
//close(new_fd);
StartMasterMind(new_fd,their_addr);
// exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
void InitializeGame(const char* port)
{
tcp_connect(port);
}
std::vector<color> GetInputAsColorMap(char* input)
{
[...]//redacted for clarity
}
int StartMasterMind(int client, sockaddr_storage addr_in)
{
struct msgstruct message;
struct sockaddr_storage their_addr = addr_in;
socklen_t addr_len;
message.send_data = "Welcome to ... M A S T E R M I N D.\n";
message.length = strlen(message.send_data);
send(client, message.send_data, message.length, 0);
[...]//redacted for clarity
if (strcmp(theValue, "random") == 0 || strcmp(theValue, "Random") == 0)
{
[...]//redacted for clarity
}
else
{
[...]//redacted for clarity
}
char* buf;
for (int i = 0; i < 8; ++i) {
std::vector<color> current_try(4);
int black_hits = 0, white_hits = 0;
std::vector<int> correctColorIndex;
std::vector<int> correctColor;
bool exclude[4] = {false};
std::cout << "test\n";
message.send_data = "Please enter your guess: ";
message.length = strlen(message.send_data);
send(client, message.send_data, message.length, 0);
addr_len = sizeof their_addr;
std::cout << "addr_len: " << addr_len << std::endl;
recvfrom(client, buf, MAXDATASIZE-1, 0, (struct sockaddr *)&their_addr, &addr_len);
current_try = GetInputAsColorMap(buf);
std::cout << "the buffer: " << buf << std::endl;
std::cout << "current_try: " << current_try[0] << current_try[1] << current_try[2] << current_try[3] << std::endl;
[...]//redacted for clarity
std::cout << black_hits << " black hits & " << white_hits
<< " white hits.\n";
if (black_hits == 4) {
std::cout << "you won!\n";
std::cin.ignore().get();
close(client); //<<<< CRASH HERE
return 0;
}
}
[...]//redacted for clarity
}
int main(int argc, char** argv)
{
InitializeGame(argv[1]);
return 0;
}
Here is sample output:
server: waiting for connections...
server: got connection from 127.0.0.1
value or random:
1122
test
addr_len: 128
the buffer: 1123�
current_try: 1123
3 black hits & 0 white hits.
test
addr_len: 128
the buffer: 1223�
current_try: 1223
2 black hits & 1 white hits.
test
addr_len: 128
the buffer: 1122�
current_try: 1122
4 black hits & 0 white hits.
you won!
accept: Bad file descriptor
accept: Bad file descriptor
accept: Bad file descriptor
... // continuously, hundreds of times
I'm very new to socket programming; could someone give me a hand? This crashes with or without trying to close(client) at the end of the game.
I think when the child process is wrapping back to start of while(1) loop, it tries to accept a connection with server socket descriptor = "sockfd" which you already closed for the child:
if (!fork()) { // this is the child process
close(sockfd);
....
}
Try this link to read as how to terminate the child process after its work is complete.
That message means that you're calling accept() on an invalid file descriptor, i.e. probably one that you've closed.