OpenSSL digest: different results on command-line and in c++ - c++

when i calculate the sha256-digest of a file with openssl-command-line it differs completely from the digest generated in c++ with the openssl-library.
command-line:
openssl dgst -binary -sha256 MyFile.txt
c++:
BIO* bio = BIO_new_file("MyFile.txt", "rb");
if (bio != NULL)
{
OpenSSL_add_all_digests();
const EVP_MD* md = EVP_sha256();
if (md != NULL)
{
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
if (EVP_DigestInit_ex(ctx, md, NULL))
{
const int bufLength = 4096;
unsigned char buf[bufLength];
unsigned int len;
while (BIO_read(bio, buf, bufLength))
EVP_DigestUpdate(ctx, buf, bufLength);
unsigned char digest[EVP_MAX_MD_SIZE];
int ok = EVP_DigestFinal_ex(ctx, digest, &len); // ok == 1; digest in variable "digest" is totally different from the one calculated on command-line
}
EVP_MD_CTX_cleanup(ctx);
BIO_free_all(bio);
}
}
why is the digest calcuated via c++ totally different, than the one calculated on command-line? (MyFile.txt has no line-breaks or whitespaces in it)
kind regards,
matthias

You handle the reading wrong. With this codechange, the hash is correct:
int readlen;
while ( (readlen = BIO_read(bio, buf, bufLength)) > 0)
{
EVP_DigestUpdate(ctx, buf, readlen);
}
In general, you should have more error handling to make your code more robust.
Cheers,
/Erik Alapää

Related

send and receive binary files properly using sockets c++

hello stackflow users,
so i want to send and receive my binary file using sockets in c++ and here is how i send it from server program
send(Connections[conindex], reinterpret_cast<char*>(rawData), sizeof(rawData), NULL);
and here is how my client program receives it
char raw[647680];
recv(Connection, raw, sizeof(raw), NULL);
is there any proper way than this? i want so that i don't have to hard code the size every time.
or any other alternatives etc
A rather general way to achieve this (in both C and C++) is something like this:
if (FILE *fp = fopen(filename, "rb"))
{
size_t readBytes;
char buffer[4096];
while ((readBytes = fread(buffer, 1, sizeof(buffer), fp) > 0)
{
if (send(Connections[conindex], buffer, readBytes, 0) != readBytes)
{
handleErrors();
break;
}
}
close(Connections[conindex]);
}
And on the client side:
if (FILE *fp = fopen(filename, "wb"))
{
size_t readBytes;
char buffer[4096];
while ((readBytes = recv(socket, buffer, sizeof(buffer), 0) > 0)
{
if (fwrite(buffer, 1, readBytes, fp) != readBytes)
{
handleErrors();
break;
}
}
}
Alternatives to this rather FTP-esque connection style includes sending the size of the file first, so the client will know when to stop listening instead of waiting for the disconnect.
Please note that this code is untested and merely meant to illustrate the concept.

NKE socket filter (MacOS): can't properly re-inject the output packets

I'm having a problem in MacOS when using a kernel extension that should filter network traffic.
The kext (through the sftl_filter) starts to filter all packets, and
sends them to a process in userspace
The client performs some operations (in this case, it simply sends the packet data back to the driver unmodified)
The driver re-injects the modified packet back into the network stream
Incoming data works great. However, uploading data larger than 500kb results in an abruptly closed connection. Smaller files can be uploaded without issue. This is via any protocol, tested on ftp, http, https, etc.
Simplified driver code:
errno_t tl_data_fn(void *cookie, socket_t so, const struct sockaddr *addr, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags, FilterSocketDataDirection direction) {
if (check_tag(data, gidtag, FILTER_TAG_TYPE, direction == FilterSocketDataDirectionIn ? IN_DONE : OUT_DONE)) {
return 0;
}
if (!cookie) return result;
filter_cookie *f_cookie = get_filter_cookie(cookie);
FilterNotification notification;
if (direction == FilterSocketDataDirectionIn) {
notification.event = FilterEventDataIn;
} else {
notification.event = FilterEventDataOut;
}
notification.socketId = (uint64_t)so;
notification.inputoutput.dataSize = (uint32_t)mbuf_pkthdr_len(*data);
mbuf_copydata(*data, offset, notification.inputoutput.dataSize, notification.inputoutput.data);
ctl_enqueuedata(f_cookie->ctl_ref, f_cookie->ctl_unit, &notification, sizeof(FilterNotification), CTL_DATA_EOR);
mbuf_freem(*data);
if (control != NULL && *control != NULL)
mbuf_freem(*control);
return EJUSTRETURN;
}
errno_t tl_data_in_fn(void *cookie, socket_t so, const struct sockaddr *from, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, from, data, control, flags, FilterSocketDataDirectionIn);
}
errno_t tl_data_out_fn(void *cookie, socket_t so, const struct sockaddr *to, mbuf_t *data, mbuf_t *control, sflt_data_flag_t flags) {
return tl_data_fn(cookie, so, to, data, control, flags, FilterSocketDataDirectionOut);
}
errno_t ctl_send(kern_ctl_ref ctl_ref, u_int32_t unit, void *unitinfo, mbuf_t m, int flags) {
FilterClientResponse response;
mbuf_copydata(m, 0, sizeof(response), &response);
mbuf_t data;
mbuf_allocpacket(MBUF_WAITOK, response.dataSize, NULL, &data);
mbuf_copyback(data, 0, response.dataSize, response.data, MBUF_WAITOK);
set_tag(&data, gidtag, FILTER_TAG_TYPE, response.direction == FilterSocketDataDirectionIn ? IN_DONE : OUT_DONE);
if (response.direction == FilterSocketDataDirectionIn) {
sock_inject_data_in((socket_t)response.socketId, NULL, data, NULL, 0);
} else {
sock_inject_data_out((socket_t)response.socketId, NULL, data, NULL, 0);
}
mbuf_freem(m);
return 0;
}
tl_data_in_fn and tl_data_out_fn functions are used in sftl_filter. ctl_send is used in kern_ctl_reg as ctl_send_func.
Simplified userspace process code:
int s = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
//connect to driver
FilterNotification notification;
while (recv(s, &notification, sizeof(FilterNotification), 0) == sizeof(FilterNotification)) {
FilterClientResponse response;
response.socketId = notification.socketId;
response.direction = (notification.event == FilterEventDataIn) ? FilterSocketDataDirectionIn : FilterSocketDataDirectionOut;
response.dataSize = notification.inputoutput.dataSize;
memcpy(response.data, notification.inputoutput.data, notification.inputoutput.dataSize);
send(s, &response, sizeof(response), 0);
}
Any help / advice would be appreciated. Kext and userspace process repository.
Thank you

PKCS#12 Invalid Password

I am using this OpenSSL code on the iPhone to generate a PKCS#12 file given some data of a certificate/private key. I am able to verify that this PKCS#12 is parseable on OpenSSL, since it doesn't print out an error when I check for it in the code. However, when I transfer it to my server, it says: Error: PKCS#12 MAC could not be verified. Invalid password? Does anyone know why this is? I am using the same password, which is 'password'
- (NSData *)generateP12AsNSData:(NSData *)keyData certificate:(NSData *)certificateData {
//put the certificateData into a X509 certificate
const unsigned char *certificateDataBytes = (const unsigned char*)[certificateData bytes];
X509 *certificateX509 = d2i_X509(NULL, &certificateDataBytes, [certificateData length]);
EVP_PKEY *privateKey;
PKCS12 *p12;
//cast the key data as an unsigned char so that we can convert it to the OpenSSL key format
const unsigned char *bits = (unsigned char *) [keyData bytes];
int length = (int)[keyData length];
privateKey = EVP_PKEY_new();
//convert the unsigned char to OpenSSL Key format
RSA *rsa = NULL;
d2i_RSAPrivateKey(&rsa, &bits, &length);
EVP_PKEY_assign_RSA(privateKey, rsa);
//create the PKCS#12
OpenSSL_add_all_algorithms();
p12 = PKCS12_create("password", "ExtraDeviceP12", privateKey, certificateX509, NULL, 0,0,0,0,0);
//make sure the p12 exists
if(!p12) {
fprintf(stderr, "Error creating PKCS#12 ");
ERR_print_errors_fp(stderr);
return nil;
}
//error checking to make sure we generated the CSR correctly
STACK_OF(X509) *ca = NULL;
EVP_PKEY *parseKey;
X509 *parseCert;
if (!PKCS12_parse(p12, "password", &parseKey, &parseCert, &ca)) {
printf("error parsing PKCS#12 file");
return nil;
}
//convert the PKCS#12 to binary data
//create a new memory BIO. A BIO is used for basic I/O abstraction.
BIO *bio;
bio = BIO_new(BIO_s_mem());
//i2d_PKCS12_bio is used to export a PKCS12 object
i2d_PKCS12_bio(bio, p12);
BUF_MEM *buffer;
BIO_get_mem_ptr(bio, &buffer);
//int bioLen = BIO_pending(&buffer);
char *buff = (char*)malloc(buffer->length);
memcpy(buff, buffer->data, buffer->length - 1);
buff[buffer->length - 1] = 0;
NSData *data = [NSData dataWithBytes:buff length:buffer->length];
NSString *string = [data base64EncodedStringWithOptions:0];
NSLog(#"Base64 PKCS#12: %#", string);
BIO_free_all(bio);
return data;
}
EDIT:
Here is the code on my server side written in Javascript. In this case req.body is the NSData sent from the iPhone. I get the invalid password error.
var p12b64 = req.body.toString('base64');
var p12Der = forge.util.decode64(pk12b64);
var p12Asn1 = forge.asn1.fromDer(p12Der);
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password');
Try the following. It shows you where some key return values should be checked, and it avoids extra copies of the data:
BIO *bio = BIO_new(BIO_s_mem());
ASSERT(bio != NULL);
int ret = i2d_PKCS12_bio(bio, p12);
ASSERT(ret == 1);
BUF_MEM *buffer;
BIO_get_mem_ptr(bio, &buffer);
ASSERT(buffer != NULL);
NSData *data = [NSData dataWithBytes:buffer->data length:buffer->length];
BIO_free_all(bio);
You can find the docs for i2d_PKCS12_bio at i2d_PKCS12_bio man pages.
If you want, you can Base64 encode the binary data from i2d_PKCS12_bio. See Non-printable character after generating random n-byte Base64 string for using a BIO chain and ensuring the Base64 string is NULL terminated.

Sending mail to smtp server requiring authentication using Dev C++

I am working on a program that connects to a tcp server, get some data and under certain conditions need to send an alert via email.(I'm helping someone with a school project)
I'm using DevC++.
It's been a few years since I've had anything to do with programming and have never done any programming in a network environment. (Hope that make sense)
I got the TCP client and log file part going, but I can't get the mail sending part to work.
Since I'm relatively inexperienced I've already wasted a lot of time, for example first of all I thought of trying POCO, but now it looks like you need Visual C++ to build the libraries.
Next I tried jwsmtp, but the examples I could find didn't do authentication, and it seems that authentication is a must nowadays. Next I tried libCurl, but can't get the examples to work, first of all I get CURLOPT_MAIL_FROM was not declared in this scope, I read in some post that is caused by error in newest version, then the curl header files started giving all sorts of errors.
My problem is that I am now fast running out of time. I would love to get it all working by myself, and even learn enough to write my own code, not just modifying and pasting together examples, but I made a promise and the deadline doesn't give me that option.
Can someone please help with anything that will actually work on windows using DevC++ sending mail to a gmail account?
I assume you will be using Mingw and MSYS.. What I did was download the latest OpenSSL from: http://www.openssl.org/source/
Then I opened MSYS and ran the following commands:
./configure mingw no-shared --prefix='C:/OpenSSL'
It should print Configured for mingw if successful.
Next I went to the OpenSSL source and then the test folder. I opened md2test.c and replaced dummytest.c with: #include "dummytest.c". I did the same thing for rc5test.c and for jpaketest.c.
Next I ran the following commands:
make depend && make install
This will build the static libraries. If you want to build the shared libraries then you need to replace no-shared with shared in the first command (the ./configure line).
When finished, I created some raw sockets and sent emails as follows (need to do some error checking within the sendemail function but I hope you get the gist of it.. It works):
/** © 2014, Brandon T. All Rights Reserved.
*
* This file is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this file. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined _WIN32 || defined _WIN64
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#include <stdio.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifndef __cplusplus
typedef enum {false, true} bool;
#endif
bool ssl_init_count = 0;
typedef struct
{
int sock;
const char* address;
unsigned short port;
} sock_info;
typedef struct
{
SSL* ssl;
SSL_CTX* ctx;
} ssl_info;
typedef struct
{
char b64username[256];
char b64password[256];
} email;
bool initsocket()
{
#if defined _WIN32 || defined _WIN64
WSADATA wsaData = {0};
return !WSAStartup(MAKEWORD(2, 2), &wsaData);
#else
return true;
#endif
}
void destroysocket(sock_info* info)
{
#if defined _WIN32 || defined _WIN64
shutdown(info->sock, SD_BOTH);
closesocket(info->sock);
WSACleanup();
#else
shutdown(info->sock, SHUT_RDWR);
close(info->sock);
#endif
}
bool connectsocket(sock_info* info)
{
struct sockaddr_in* sockaddr_ipv4 = NULL;
struct addrinfo* it = NULL, *result = NULL;
getaddrinfo(info->address, NULL, NULL, &result);
for (it = result; it != NULL; it = it->ai_next)
{
sockaddr_ipv4 = (struct sockaddr_in*)it->ai_addr;
info->address = inet_ntoa(sockaddr_ipv4->sin_addr);
if (strncmp(info->address, "0.0.0.0", 7))
break;
}
freeaddrinfo(result);
if ((info->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
perror("Error creating socket..");
return false;
}
struct sockaddr_in SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(info->port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(info->address);
if (connect(info->sock, (struct sockaddr*)&SockAddr, sizeof(SockAddr)) < 0)
{
perror("Error connecting socket..");
return false;
}
return true;
}
bool setssl(sock_info* sockinfo, ssl_info* sslinfo)
{
sslinfo->ctx = SSL_CTX_new(SSLv23_client_method());
if (sslinfo->ctx)
{
sslinfo->ssl = SSL_new(sslinfo->ctx);
SSL_set_fd(sslinfo->ssl, sockinfo->sock);
return SSL_connect(sslinfo->ssl) != -1;
}
return false;
}
void removessl(sock_info* sockinfo, ssl_info* sslinfo)
{
if (sslinfo->ctx)
{
SSL_CTX_free(sslinfo->ctx);
}
if (sslinfo->ssl)
{
SSL_shutdown(sslinfo->ssl);
SSL_free(sslinfo->ssl);
}
sslinfo->ssl = NULL;
sslinfo->ctx = NULL;
}
void initssl()
{
if (!ssl_init_count)
{
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
++ssl_init_count;
}
void freessl()
{
if (!--ssl_init_count)
{
ERR_free_strings();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
}
}
void sslb64encode(const char* buffer, char* outbuffer)
{
char* b64str = NULL;
BIO* b64 = BIO_new(BIO_f_base64());
BIO* mem = BIO_new(BIO_s_mem());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
b64 = BIO_push(b64, mem);
BIO_write(b64, buffer, strlen(buffer));
BIO_flush(b64);
int len = BIO_get_mem_data(mem, &b64str);
memcpy(outbuffer, b64str, len);
outbuffer[len] = '\0';
BIO_free_all(b64);
}
void initemail(const char* username, const char* password, email* outemail)
{
char ubuffer[256];
char pbuffer[256];
unsigned int bytes_written = 0;
sslb64encode(username, &ubuffer[0]);
sslb64encode(password, &pbuffer[0]);
sprintf(outemail->b64username, "%s", ubuffer);
sprintf(outemail->b64password, "%s", pbuffer);
}
bool printsocketbuffer(ssl_info* sslinfo)
{
char buffer[1024];
unsigned int bytes_read = SSL_read(sslinfo->ssl, &buffer[0], sizeof(buffer));
if (bytes_read > 0)
{
printf("%.*s", bytes_read, buffer);
return true;
}
return false;
}
void sendemail(ssl_info* sslinfo, const char* username, const char* password, const char* recipient, const char* from, const char* to, const char* message, const char* subject, unsigned int messagelen)
{
email em;
char buffer[512];
unsigned int bufflen = sizeof(buffer);
initemail(username, password, &em);
SSL_write(sslinfo->ssl, "HELO\r\n", 6);
printsocketbuffer(sslinfo);
SSL_write(sslinfo->ssl, "AUTH LOGIN\r\n", 12);
printsocketbuffer(sslinfo);
bufflen = sprintf(buffer, "%s\r\n", em.b64username);
SSL_write(sslinfo->ssl, buffer, bufflen);
printsocketbuffer(sslinfo);
bufflen = sprintf(buffer, "%s\r\n", em.b64password);
SSL_write(sslinfo->ssl, buffer, bufflen);
printsocketbuffer(sslinfo);
printsocketbuffer(sslinfo);
bufflen = sprintf(buffer, "MAIL FROM: <%s>\r\n", username);
SSL_write(sslinfo->ssl, buffer, bufflen);
printsocketbuffer(sslinfo);
bufflen = sprintf(buffer, "RCPT TO: <%s>\r\n", recipient);
SSL_write(sslinfo->ssl, buffer, bufflen);
printsocketbuffer(sslinfo);
SSL_write(sslinfo->ssl, "DATA\r\n", 6);
printsocketbuffer(sslinfo);
bufflen = sprintf(buffer, "From: <%s><%s>\r\n", from, username);
bufflen += sprintf(&buffer[bufflen], "To: <%s><%s>\r\n", to, recipient);
bufflen += sprintf(&buffer[bufflen], "Subject: <%s>\r\n", subject);
SSL_write(sslinfo->ssl, buffer, bufflen);
bufflen = 0;
while (bufflen < messagelen)
{
bufflen += SSL_write(sslinfo->ssl, &message[bufflen], messagelen - bufflen);
}
SSL_write(sslinfo->ssl, "\r\n.\r\n", 5);
printsocketbuffer(sslinfo);
SSL_write(sslinfo->ssl, "QUIT\r\n", 6);
printsocketbuffer(sslinfo);
}
int main()
{
ssl_info sslinfo = {0};
sock_info sockinfo = {0, "smtp.gmail.com", 465};
const char* username = "ICantChooseUsernames#gmail.com";
const char* password = "*****";
const char* recipient = "ICantChooseUsernames#gmail.com";
const char* message = "hello there!";
const char* subject = "Testing Emails";
const char* from = "Brandon";
const char* to = "Brandon";
unsigned int messagelen = strlen(message);
if (initsocket())
{
if (connectsocket(&sockinfo))
{
initssl();
if (setssl(&sockinfo, &sslinfo))
{
sendemail(&sslinfo, username, password, recipient, from, to, message, subject, messagelen);
}
else
{
ERR_print_errors_fp(stderr);
}
removessl(&sockinfo, &sslinfo);
freessl();
}
destroysocket(&sockinfo);
}
return 0;
}
Well it seems I'm not going to get this working. Tried all openssl, mingw and msys directories. After speaking to a friend I got Visual Studio Express and got a c# example to work fairly quickly. Not having even seen c# before I couldn't rewrite everything else, so I just modified my example to make a mail sending application I call from my other program. Maybe not the best way but hey, it works and my time is up.
Hopefully I will be able to start learning this stuff.
Thanks for trying to help this ignoramus, I really appreciate it.

Linux sockets: Segmentation error

Linux n00b here. So about a month ago I installed emacs and the gcc/g++ compiler and have gotten started with programming. I found some code online for an echo server program, copied it and compiled it to test the networking functions. It compiled but then when I tried to run it I got the error message: Segmentation fault(core dumped). When I looked carefully at the debugger details it was an error in the "fwrite()" function. I linked the code to the library libstdc++.a upon compiling and creating the output file so it does make me wonder if there is some critical error in the actual library functions and I need to go back, find the function .c sourcecode, and then add them to the headers to make it work. The code is posted below. Anybody else had this problem?
#include <sys-socket.h> /* socket definitions */
#include <sys-types.h> /* socket types */
#include <netinet-in.h> /* inet (3) functions */
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ether.h>
#include <string.h>
/* Global constants */
#define ECHO_PORT 2002
#define MAX_LINE 1000
#define LISTENQ 5
ssize_t Readline(int sockd, char *vptr,size_t maxlen) {
ssize_t n, rc;
char* c;
msghdr* buffer;
buffer->msg_iov->iov_base = vptr;
buffer->msg_iov->iov_len = maxlen;
for ( n = 1; n < maxlen; n++ ) {
if ( (rc = recvmsg(sockd,buffer, 1)) == 1 ) {
c = buffer->msg_iov->iov_base++;
if (*c == '\n' )
break;
}
else if ( rc == 0 ) {
if ( n == 1 )
return 0;
else
break;
}
else {
if (rc < 0 )
continue;
return -1;
}
}
buffer->msg_iov->iov_base = 0;
return n;
}
/* Write a line to a socket */
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
buffer->msg_iov->iov_base = vptr;
size_t nleft = buffer->msg_iov->iov_len;
ssize_t nwritten;
while ( nleft > 0 ) {
if ( (nwritten = sendmsg(sockd, buffer, nleft)) < 0 ) {
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return nwritten;
}
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char *endptr; /* for strtol() */
char buffer[MAX_LINE];
port = 5000;
/* Create the listening socket */
if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind our socket addresss to the
listening socket, and call listen() */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
if ( listen(list_s, LISTENQ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
/* Enter an infinite loop to respond
to client requests and echo input */
while ( 1 ) {
/* Wait for a connection, then accept() it */
if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept()\n");
exit(EXIT_FAILURE);
}
/* Retrieve an input line from the connected socket
then simply write it back to the same socket. */
Readline(conn_s, buffer, MAX_LINE-1);
Writeline(conn_s, buffer);
/* Close the connected socket */
if ( shutdown(conn_s,0) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}
}
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
buffer->msg_iov->iov_base = vptr;
your pointer buffer is not initialized. You might look at this code snippet to do it correctly:
/* This structure contains parameter information for sendmsg. */
struct msghdr mh;
/* The message header contains parameters for sendmsg. */
mh.msg_name = (caddr_t) &dest;
mh.msg_namelen = sizeof(dest);
mh.msg_iov = iov;
mh.msg_iovlen = 3;
mh.msg_accrights = NULL; /* irrelevant to AF_INET */
mh.msg_accrightslen = 0; /* irrelevant to AF_INET */
rc = sendmsg(s, &mh, 0); /* no flags used */
if (rc == -1) {
perror("sendmsg failed");
return -1;
}
return 0;
}
sendmsg
You are not setting the buffer pointer variables in your Writeline() and ReadLine() functions.
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
//this is not appropriate as buffer does not point to appropriate memory.
buffer->msg_iov->iov_base = vptr;
size_t nleft = buffer->msg_iov->iov_len;
ssize_t nwritten;
...
return nwritten;
}
Accessing buffer->msg_iov->iov_base or buffer->msg_iov->iov_len or even buffer is not appropriate without allocating it or setting to appropriate memory is not valid.
Did you actually COPY this, or did you copy bits and then paste it together yourself?
It's not very hard to fix at least to the point where it doesn't crash by itself - I didn't get further because my firewall settings are too strict to just fire up a program and use a random port, and I don't feel like messing up my firewall setting just to test your code.
So, as pointed out msghdr *buffer; means that the pointer for buffer is uninitialized. The easy fix is to NOT use a pointer, and instead use the address of buffer when you need it. You then need to have an iov data structure.
So, in receive, you end up with something like this:
msghdr buffer;
iovec iov;
buffer.msg_iov = &iov;
...
if ( (rc = recvmsg(sockd, &buffer, 1)) == 1 ) {
c = vptr++;
buffer.msg_iov->iov_base = vptr;
Note the & in front of buffer. I also changed the next line, as it was doing ++ on a void pointer, which is not clearly defined in C++, so the compiler gave a warning. (There's also a warning for buffer not initialized).
A similar treatment is needed in the `WriteLine function.
iovec iov;
buffer.msg_iov = &iov;
buffer.msg_iov->iov_base = vptr;
size_t nleft = MAX_LINE;
...
if ( (nwritten = sendmsg(sockd, &buffer, nleft)) < 0 ) {
....
nleft -= nwritten;
vptr += nwritten;
buffer.msg_iov->iov_base = vptr;
Again, the increment of iov_base is incrementing a void *, which hasn't been defined since I wrote it above, so need to make sure that the pointer has a different type - reusing vptr is decent here.
As an aside, I changed the nleft to set to MAX_LINE, as you don't pass in the size of the line. I would suggest that you change it so that it does take the size as an argument, similar to the ReadLine function.
Finally, please do yourself a favour and use -Wall -Werror when compiling the code - that means that you will get warnings when you do "silly" things - it may work, but it may also NOT work. Nearly all warnings from the compiler are USEFUL.
Remember when using a pointer in C or C++, you should make sure it points at something. Just writing T* ptr; only gives you a pointer, there is no memory attached to the pointer, so before you USE that pointer, you should assign it in some way.
I'm far from convinced this covers everything - but it should get you somewhat on the way to getting something working.