Monday, March 31, 2008

Socket eMail Example

Hi Friends, today We need to send a simple alert mail from our application and I have wanted to send this email from C using sockets.

It isn't difficult, you need to open a socket connection to the server using the port of email service and exchange some messages to send the alert message.

All messages you have to send, should be terminated by "\r\n" and after each message you have to call to recv function to get the response from the server.

The first message to send to the Server is the HELO %s\r\n message, replacing %s with the server ip address.

After this message you have to send the EHLO\r\n message, this message will be responsed by the Server with all operations permited by the server.

If you need to send some login information to your email server, you'll need to send the auth\r\n message and after this, you'll have to send the user uid\r\n and pwd\r\n in base64 format.
To do this, I've used Openssl again.

At this point you have to send the information about the from address, to address, subject and body.

For ending the comunication with the server you need to send a blank line and after this blank line send a quit\r\n message.

Bellow I paste the code I've used to do this, I hope it'll be useful for you



// Mail.c : email function example
//


#include <stdio.h>
#include <memory.h>
#include <errno.h>
#includee <sys/types.h>
#ifdef WIN32
  #include <winsock.h>
#else
  #include <sys/socket.h>
  #include <netinet/in.h>
#endif

#include <openssl/bio.h>
#include <openssl/evp.h>
#include "applink.c"

BIO_METHOD * BIO_f_base64(void);

#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>

char *base64(const unsigned char *input, int length);


int main (int argc, char* argv[])
{
  char ret[2500]="";

  // Init OpenSSL
  _fmode=_O_BINARY;
  CRYPTO_malloc_init();
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  ENGINE_load_builtin_engines();

  ERR_load_crypto_strings();

  return SendMail("uid@server.es","uidTo@server.es", "MailServerIp", "Subject", "UID","PWD", "Message");

}


/*
*
* Send Text Mail from user requested to the target user, using the server and the specified credentials.
*
*/

BOOL SendMail(const char* _From, const char* _To, const char* host,
const char* _Subject, const char* uid, const char* pwd, const char* _MessageFormat, ...)
{
  int iProtocolPort = 0;
  char szBuffer[4096] = "";
  SOCKET sd;
  struct sockaddr_in sa;
  LPSERVENT lpServEntry;
  va_list message_parts;
  char message[65536];
  int err=0;
  char _SMTP[16]="";
  #ifdef WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
  #endif

  #ifdef WIN32
    wVersionRequested = MAKEWORD( 1, 1 );
    err = WSAStartup(wVersionRequested, &wsaData );
    if ( err != 0 )
    {
      exit(1);
    }
  #endif

  // traslating namehost to ip address
  strcpy(_SMTP, GetIpAddress((char*)host));

  // creating the Socket
  sd = socket(PF_INET, SOCK_STREAM, 0);
  if (sd == INVALID_SOCKET)
  {
    // Cannot open mail server socket!
    return FALSE;
    }

  // Getting the mail port
  lpServEntry = getservbyname("mail", 0);

  // if we havent't a port, we use the default port to SMTP
  if (!lpServEntry)
    iProtocolPort = htons(IPPORT_SMTP);
  else
    iProtocolPort = lpServEntry->s_port;

  memset (&sa, '\0', sizeof(sa));
  sa.sin_family = AF_INET;
  sa.sin_addr.s_addr = inet_addr (_SMTP); /* Server IP*/
  sa.sin_port = (iProtocolPort); /* Server Port*/


  // Connecting to the Server
  if(connect(sd, (struct sockaddr*) &sa, sizeof(sa)))
  {
    // Error connecting to the Server!
    return FALSE;
  }

  // Initial response from the Server
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Init dialog
  sprintf(szBuffer, "HELO %s\r\n", _SMTP);
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);


  sprintf(szBuffer,"ehlo\r\n");
  send(sd,szBuffer,strlen(szBuffer),0);
  recv(sd,szBuffer,sizeof(szBuffer),0);

  // Sending login
  strcpy(szBuffer, "auth login\r\n");
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Send userid
  sprintf(szBuffer,"%s\r\n", base64(uid, strlen(uid)));
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);


  // Send Pwd
  sprintf(szBuffer,"%s\r\n", base64(pwd, strlen(pwd)));
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // send From
  sprintf(szBuffer, "MAIL FROM:<%s>\r\n", _From);
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Send To
  // repeat for each target address

  sprintf(szBuffer, "RCPT TO:<%s>\r\n", _To);
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Send Data
  sprintf(szBuffer, "DATA\r\n");
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Preparing the string to send
  va_start(message_parts, _MessageFormat);
  vsprintf(message, _MessageFormat, message_parts);
  va_end(message_parts);

  // Setting Subject and Body
  sprintf(szBuffer,"Subject: %s\r\n\r\n%s\r\n.\r\n",_Subject, message);


  // Send a blank line to end the transmision
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // Sending end command
  sprintf(szBuffer, "quit\r\n");
  send(sd, szBuffer, strlen(szBuffer), 0);
  recv(sd, szBuffer, sizeof(szBuffer), 0);

  // closing the connection
  #ifdef WIN32
    closesocket (sd);
  #else
    close(sd);
  #endif

  return TRUE;
}


char *base64(const unsigned char *input, int length)
{
  BIO *bmem, *b64;
  BUF_MEM *bptr;
  char *buff="";

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new(BIO_s_mem());
  b64 = BIO_push(b64, bmem);
  BIO_write(b64, input, length);
  BIO_flush(b64);
  BIO_get_mem_ptr(b64, &bptr);

  buff = (char *)malloc(bptr->length);
  memcpy(buff, bptr->data, bptr->length-1);
  buff[bptr->length-1] = 0;

  BIO_free_all(b64);

  return buff;
}

/*
*
* Return Ip from hostname
*
*/

char* GetIpAddress(char *hostname)
{

  struct sockaddr_in SocketAddress;
  struct hostent *pHost = 0;
  char aszIPAddresses[16];
  int iCnt=0;

  pHost = gethostbyname(hostname);
  if(!pHost)
    return "";

  // get first server ip
  memcpy(&SocketAddress.sin_addr, pHost->h_addr_list[0], pHost->h_length);
  strcpy(aszIPAddresses, inet_ntoa(SocketAddress.sin_addr));

  // returning ip
  return aszIPAddresses;

}

Wednesday, March 5, 2008

SSL HTTP POST

Hi, friends

I'm developing a module to connect C programs with WebServices and newly I've used OpenSSL. Actually it hasn't very difficult, although I had some problem. It's very important to set properly the method to use. I'm connecting with a JBoss HTTPs WebService and I had to set this one:


meth = TLSv1_client_method();
ctx = SSL_CTX_new (meth);

I copy bellow the main function I had used, to send the HTTP POST message, I hope it'll be usefull for you:

int sendPOST(void* sd, SSL* ssl, ;char* server, char* port, char* post, char* action, char* csoap, char *response){

int ret=0;
char msg[5000]="";
char buff[5000]="";
int err=0;
int len=0;
char header[200]="";

    // Setting HTTP Headers
    sprintf(msg,"POST %s HTTP/1.1\r\n", post);
    sprintf(header,"Host: %s:%s\r\n", server, port);
    len=strlen(msg) ;
    memcpy(msg + len , header, strlen(header));
    len+=strlen(header);
    strcpy(header,"Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n");
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    sprintf(header,"Content-Length: %d\r\n", strlen(datos));
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    sprintf(header,"SOAPAction: %s\r\n\r\n",action);
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    // Adding csoap
    memcpy(msg + len, datos, strlen(datos));

    if(sd!=NULL){
        // No SSL Connections

        err=send((int)sd, msg, len + strlen(datos),0);
        if (err == SOCKET_ERROR) {
            printf("send() failed with error: %d\n", WSAGetLastError());
            closesocket((int)sd);
            WSACleanup();
            exit(1);
        }

        do {
            err = recv((int)sd, buff, sizeof(buff) - 1, 0);
            if ( err > 0 )
                printf("Bytes received: %d\n", err);
            else if ( err == 0 )
                printf("Connection closed\n");
            else
                printf("recv failed with error: %d\n", WSAGetLastError());

        } while( err > 0 );


    }else{
        // SSL Connections
        err = SSL_write (ssl, msg, len + strlen(datos)); CHK_SSL(err);

        err = SSL_read (ssl, buff, sizeof(buff) - 1);
        CHK_SSL(err);
        buff[err] = '\0';

        SSL_shutdown (ssl);
    }

    strcpy(respuesta, buff);

    return ret;

}