Solved

major problems with socks + pthreads + sending mail: need code

Posted on 2003-11-12
13
775 Views
Last Modified: 2011-09-20
I am trying to write a c program that sends email really fast.

i am an absolute novice in c programming , and managed to workmy way through some example code and copy pasted a couple of ideas together.

I am trying to run threads and socks at the same time , but it seems like threads block each other because the use the same sockets

I read around for a solution and I saw some that were talking about select() , but unfortunately this is way beyond me to understand.

I am posting the beginning of the code that I wrote and I cant get much further than that.

I am offering <<Financial Reward Disallowed per site guidelines>> for somebody that can build a solution that will work and do what I need.

p.s. this is supposed to run on both linux and freebsd

-------------------------------- SNIP -----------------------------------------


#include <stdio.h>
#include <stdlib.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/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>

#define NUM_THREADS     15


extern int errno;  /* Error codes are returned here. */

struct hostent *hostent;
struct sockaddr_in sockaddr;
int sock,status,hostaddr,smtp_port=25,socket_option=0;
char buffer[4096];
fd_set socket_read_status;
struct timeval socket_time_structure;

#define TIMEOUT_SECONDS 30
#define BUFFER_SIZE 16000
time_t current_time,hold_time;

char smtp_server[128],smtp_account[32],smtp_password[32],smtp_recipient[64],
     smtp_subject[64];
char temp_string[BUFFER_SIZE],email_body[BUFFER_SIZE],
     form_data_string[BUFFER_SIZE],form_data_string_2[BUFFER_SIZE];
int message_number,temp_int,temp_int_2,temp_string_pointer;
char message_number_string[8],byte_count_string[8],temp_char;
int byte_count,byte_count_string_pointer,bytes_printed;


/*----------------------------- Subroutines ----------------------------------*/

int get_message_from_socket(void)  /* Returns 0 for success for 1 for error. */
{
int result_code,bytes_read=0,return_code=0;
hold_time = time((time_t *) 0);
while (1)
  {
  current_time = time((time_t *) 0);
  if (current_time - hold_time > TIMEOUT_SECONDS)
    {
    printf("Timeout waiting for smtp server; quitting.\n");
    return_code = 1;
    break;
    }
  result_code = read(sock,buffer,1);  /* Try to read just one character. */
  if (result_code != 1)  /* Nothing received? */
    {
    //sleep(1);
    continue;
    }
  if (buffer[0] == 13)  /* CR received?  If so, then skip.  */
    continue;
  if (buffer[0] == 10)  /* LF received? */
    break;
  temp_string[bytes_read++] = buffer[0];
  }
temp_string[bytes_read] = 0;  /* Terminate output string. */
return(0);
}

void find_field_in_form_data_string(char *field_to_find)  /* Returns temp_string. */
{
char field_name_string[255],field_value_string[255];
int form_data_string_pointer=0,result_string_pointer;
while (1)  /* Once through for each fieldname/value combination. */
  {
  result_string_pointer = 0;
  while (form_data_string[form_data_string_pointer]!='=')
    field_name_string[result_string_pointer++] = form_data_string[form_data_string_pointer++];
  field_name_string[result_string_pointer] = 0;  /* Terminate fieldname string. */
  form_data_string_pointer++;  /* Skip = sign. */
  result_string_pointer = 0;
  while ((form_data_string[form_data_string_pointer]!='&')
   &&    (form_data_string[form_data_string_pointer]!=0))
    field_value_string[result_string_pointer++] = form_data_string[form_data_string_pointer++];
  field_value_string[result_string_pointer] = 0;
  /* Now we have the field name and field value. */
  if (!strcmp(field_name_string,field_to_find))  /* Is this the one? */
    {
    strcpy(temp_string,field_value_string);
    break;
    }
  /* That wasn't the correct pair; try for another? */
  if (form_data_string[form_data_string_pointer] == 0)  /* End of input? */
    {
    temp_string[0] = 0;
    break;
    }
  form_data_string_pointer++;  /* Skip the & sign and try again. */
  }
/* Here we've broken out; the result is in temp_string, or it's blank. */
}



/*----------------------------- Main Program ---------------------------------*/

void *PrintHello(void *threadid)
{

printf("Mail Thread Nummer: %d\n", threadid);

strcpy(smtp_server,"mail.my_samlpe_foo.com");
smtp_port=25;
strcpy(smtp_account,"my_smtp_sample_account");
strcpy(smtp_recipient,"me@my_sample_server.com");
strcpy(smtp_subject,"This is the subject");


/* Now get connected. */
hostent = gethostbyname(smtp_server);  /* Do DNS lookup. */
if (hostent == NULL)
  {
  printf("Couldn't resolve SMTP server address; quitting.\n");
  pthread_exit(NULL);
}

sock = socket(AF_INET,SOCK_STREAM,0);  /* Allocate a socket. */
if (sock < 0)
  {
  printf("Unable to allocate a socket; quitting.\n");
  pthread_exit(NULL);
  }

/* Initialize sockaddr fields. */
memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
memcpy((char *)&(sockaddr.sin_addr.s_addr),(char *)hostent->h_addr_list[0],
 (size_t)hostent->h_length);
sockaddr.sin_port = htons(smtp_port);

/* Connect to remote port now. */
if (connect(sock,(struct sockaddr *)&sockaddr,sizeof(sockaddr)) < 0)
  {
  printf("Unable to connect to your SMTP server; quitting.\n");
  close(sock);
  pthread_exit(NULL);
  }
fcntl(sock,F_SETFL,O_NONBLOCK);  /* Set socket to non-blocking. */

/*-------------------------------------*/
/* Now we're ready to talk with the SMTP server, with text messages. */

/* Get welcome message from server. */
if (get_message_from_socket())
  {
  printf("Didn't get welcome message from smtp server; quitting.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
 }
if (strncmp(temp_string,"220 ",4))  /* Not ok? */
  {
  printf("Bad welcome message from SMTP server: %s\n",temp_string);
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }

strcpy(buffer,"HELO mail.dynamicnetworks.com\r\n");
write(sock,buffer,strlen(buffer));
if (get_message_from_socket())
  {
  printf("Error getting HELO response from smtp server.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }
if (strncmp(temp_string,"250 ",4))  /* Not ok? */
  {
  printf("Bad HELO response from server: %s\n",temp_string);
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }

strcpy(buffer,"MAIL FROM: ");
strcat(buffer,"foo@bar.com");
strcat(buffer,"\r\n");
strcat(buffer,"RCPT TO: ");
strcat(buffer,"foo@bar.com");
strcat(buffer,"\r\n");
write(sock,buffer,strlen(buffer));
if (get_message_from_socket())
  {
  printf("Error getting MAIL FROM response from smtp server.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }
if (strncmp(temp_string,"250 ",4))  /* Not ok? */
  {
  printf("Bad MAIL FROM response from server: %s\n",temp_string);
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }

if (get_message_from_socket())
  {
  printf("Error getting RCPT TO response from smtp server.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }
if (strncmp(temp_string,"250 ",4))  /* Didn't get +OK? */
  {
  printf("Bad RCPT TO response from server; quitting.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }

strcpy(buffer,"DATA\r\n");
write(sock,buffer,strlen(buffer));
if (get_message_from_socket())
  {
  printf("Error getting DATA response from server; quitting.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }
if (strncmp(temp_string,"354 ",4))
  {
  printf("Bad DATA response from server; quitting.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }


strcpy(buffer,"Subject: ");
strcat(buffer,"Test Subject5");
sprintf(buffer,"%s von Thread %i",buffer,threadid);


strcat(buffer,"\r\n");
write(sock,buffer,strlen(buffer));
//printf("buffer: %s\n",buffer);

strcpy(buffer,"From: ");
strcat(buffer,"p@rick.lu");
strcat(buffer,"\r\n\r\n");
write(sock,buffer,strlen(buffer));

strcpy(buffer,"Buy the Penis Patch now!");
strcat(buffer,"\r\n");
write(sock,buffer,strlen(buffer));
strcpy(buffer,".\r\n");  /* The terminating period. */
write(sock,buffer,strlen(buffer));

/* Now log out from the smtp server. */
strcpy(buffer,"QUIT\r\n");
write(sock,buffer,strlen(buffer));
if (get_message_from_socket())
  {
  printf("Error getting QUIT response from smtp server.\n");
  shutdown(sock,2);
  close(sock);
  pthread_exit(NULL);
  }
printf("Result from SMTP server: %s\n",temp_string);

pthread_exit(NULL);

/*-------------------------------------*/

}



int main()
{
   pthread_t threads[NUM_THREADS];
   int rc, t;
   for(t=0;t < NUM_THREADS;t++){
      printf("Creating thread %d\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }
   pthread_exit(NULL);
}
0
Comment
Question by:dynamicman
  • 3
  • 3
  • 2
  • +2
13 Comments
 
LVL 45

Assisted Solution

by:sunnycoder
sunnycoder earned 140 total points
ID: 9737182
you have naot stated what you want

>I am trying to run threads and socks at the same time , but it seems like threads block each other because the use the same >sockets

>I read around for a solution and I saw some that were talking about select() , but unfortunately this is way beyond me to >understand.

select listens on multiple sockets for change in status... but still one thread can read from it at a time ... it cannot make mutiple threads to read at the same time ... if you can elaborate your problem a bit, may be we can help
0
 

Author Comment

by:dynamicman
ID: 9738260
I am trying to write a program which would take a list of emails (that part is not done yet) and then stars sending it out.
my initial idea was to launch 15 threads and use sock to connect to the receiving mailserver and run the necessairy commands to send the email through.

The probelm is that instead of 15 threads running concurrently , it seems like each thread is waiting for the las threade to end in order to do what it needs to do.
I thought select() could be my solution ,but I could be completely off base with that.

bottom line , is a need a small c program that can send as many emails as possible DIRECTLY and not going through sendmail qmail or whatever.

I also realize I cannot write this program the way I want it done, that is why I am offeren <<Financial Reward Disallowed per Site Guidelines>> for whoever writes a working version and then explains it to me.


There is <<Financial Reward Disallowed per site guidelines>> in it, since the program would need alot more stuff to be where I need it to me.

anybody interested?
0
 

Author Comment

by:dynamicman
ID: 9738264
Actually another thing that could work if is anybody could recommend a really experience programmer to me that you write this for me.

I would have to be somebody that has a little time on his or her hands, since there will be additions that will need to be made
0
 
LVL 45

Assisted Solution

by:sunnycoder
sunnycoder earned 140 total points
ID: 9738463
>The probelm is that instead of 15 threads running concurrently , it seems like each thread is waiting for the las threade to end
>in order to do what it needs to do.
>I thought select() could be my solution ,but I could be completely off base with that.
if you are opening several sockets for communicating with the server, select may be helpful
I haven't read your code thoroughly as yet .... No offence intended but lack of indentation and spacing makes it hard for me to read your code ...
I have friends who can do it for you but I am not sure if EE allows this ... I'll check up with some mod ... membership agreement disallows "Soliciting individuals for employment other than in designated areas (for example, within a discussion thread)"
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 70 total points
ID: 9738960
I have an easy-to-use and well documentd static C library that would  do what you need.

The main interface is this:

/*------------------------------------------------------------------------------*/
/* net_declare                                                                  */
/*                                                                              */
/* declare and establish a host connection:                                     */
/*  - get a new socket                                                          */
/*  - query the IP address                                                      */
/*  - bind IP and port                                                          */
/*  - listen for incoming attempts to connect                                   */
/*  - provide an asychronous thread that accepts connections                    */
/*  - returns the id of the host socket                                         */
/*  - an incoming connection will invoke the callback asynchronously            */
BOOL net_declare(const char* pszName, int portNo, CallbackFunc func,  
                  void* pParam, CallbackFunc errFunc, ConnectId* pConnId);
                             
/*------------------------------------------------------------------------------*/
/* net_read                                                                     */
/*                                                                              */
/* make a client connection ready to read data                                  */
/* get data asynchrously by callback, check message completeness by callback    */
BOOL net_read(ConnectId cid, CallbackFunc func, void* pParam,
               IsCompleteFunc isCompleteFunc);

/*------------------------------------------------------------------------------*/
/* net_write                                                                    */
/*                                                                              */
/* make a client connection ready to write data                                 */
/* put data asynchrously and notify application by callback                     */
BOOL net_write(ConnectId cid, void* pBuf, ULong lenBuf, CallbackFunc func,
                void* pParam);

/*------------------------------------------------------------------------------*/
/* net_disconnect                                                               */
/*                                                                              */
/* close a client connection                                                    */
/* make closing asynchrously and notify application by callback                 */
BOOL net_disconnect(ConnectId cid, CallbackFunc func, void* pParam);

/*------------------------------------------------------------------------------*/
/* net_connect                                                                  */
/*                                                                              */
/* establish a client connection:                                               */
/*  - get a new socket                                                          */
/*  - query the IP address                                                      */
BOOL net_connect(const char* pszName, int portNo, CallbackFunc func,  
                  void* pParam, CallbackFunc errFunc, ConnectId* pConnId);

All asynchronous callbacks are invoked by threads.

For example: If you want to open a server connection that listens for incoming clients you would do this:

      net_declare("MyServer", portNo, OnAccept, pParam, OnError, &connectId);

When a client connects the OnAccept() handler will be called by a thread.

To read data from a client connection you would simply call:

      net_read(clientId, OnReceive, pParam, NULL);

Whenever data comes OnReceive() is called by a thread.

A similar use is for net_write, net_disconnect and net_connect. Last is to open a client connection.

You only have to implement the callback functions, the connection calls and a polling loop that hold the program in memory (and waits for some signal to stop program).

---------------------------------------------------------------------------------------------------


If you are interested, you can get the code. There is only one (little) problem. The code runs on NT and VAX/VMS. The few UNIX specific parts different from VAX/VMS are most likely easily to add because the sample code i had when i developed the library was from AIX. But i couldn't do it because i currently have no UNIX SPU running.

Regards Alex
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 5

Accepted Solution

by:
g0rath earned 80 total points
ID: 9739528
I've written such a program for my last job....but email is an interesting system.

My first interface was to fork off to sendmail, but I needed performance so I dropped the fork(), exec() model,

the 2nd attempt was alot nicer, I created a socket based moethod to connect to the SMTP port of my "Fast" Mailer, and then I wrote all the headers, and everyting else correctly, here it is very important to collate all of your email by domains...

for instance do not do send in this order:

abc@aol.com
xyz@compuserv.com
a123@aol.com

since this may send the emails in three passes. This may be fixed in later versions of sendmail, but not at the time I wrote it.

If you send the messages in this order:

abc@aol.com
a123@aol.com
xyz@compuserv.com

Then sendmail would make only one conenction to the aol.com domain, and send all messages in one connection.

If you do not use sendmail, well then just connect to the aol.com mailer and send all your aol mail in one connection stream.

Also, an intersting method that I came up with was that if you modify the headers such that the Return-To: address is different from the From address:, as in the From Address was back to a mail alias that automatically deleted the person from my mailing list. Since the remote hosts would always send back to the From Address. If a user replied then it would respond to the Return-To: header and I could distinguish between people and automated systems. Not full proof, but it was > 90% accurate.

It would take 20 min to send half a million mail message where 60% - 75% were actually delivered in that hour, and around 10% in the next few hours, with around 10% that were rejected and sent back, and the rest took > 5 hours

I didn't go about the multi-threaded issues, because I wanted it to be a simple proccess but efficient. I also had locking on my master list, so that I could run multiple instance of my program to hit another mail server if I had a really heavy load.

This is just some ideas of how to go about it.
0
 
LVL 6

Assisted Solution

by:GloomyFriar
GloomyFriar earned 210 total points
ID: 9740252
2 dynamicman:
send me a message:
<email address removed by RomMod>
0
 
LVL 6

Assisted Solution

by:GloomyFriar
GloomyFriar earned 210 total points
ID: 9741819
2 dynamicman:
I have multithreaded chat client. It was tested on linux.
I can adopt it to sending e-mails.
But it'll take some time.
Answer please, if you are still interested.
0
 
LVL 6

Assisted Solution

by:GloomyFriar
GloomyFriar earned 210 total points
ID: 9742032
Here is a sample how to use select:

 int sockDataAvailable(SOCKET sock)
{
    int rv;
    struct timeval  tv;
    fd_set          fds;
    tv.tv_sec       = 0;
    tv.tv_usec      = 250000;
    FD_ZERO(&fds);
    FD_SET(sock, &fds);
 
    rv = select(sock+1, &fds, NULL, NULL, &tv);
 
    if (rv > 0)
    {   char x[2];
        if (recv(sock, x, 1, MSG_PEEK) < 1)
            rv = -1;
    }
 
    return rv;
}

 int selectRecv(SOCKET sock, char *buf, int siz, int flags)
{
        if (sockDataAvailable(sock))
            return recv(sock, buf, siz, flags);

 return 0;
}

0
 

Author Comment

by:dynamicman
ID: 9744949
Thanks for all your help guys, and thanks for the guys who provided code.

unfortunately it is too complicated for me to figure out on my own and I really needed somebody to write the project for me .

I will split up the points to everybody if the system allows me to do that.

you all have a nice day.

if somebody needs to get in touch with me you can email <Removed by RomMod>
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now