"Fossies" - the Fresh Open Source Software Archive

Member "postal-0.76/basictcp.cpp" (1 Jan 2012, 7953 Bytes) of package /linux/privat/postal-0.76.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "basictcp.cpp" see the Fossies "Dox" file reference documentation.

    1 #define TCP_BODY
    2 
    3 #include "basictcp.h"
    4 
    5 #include <sys/socket.h>
    6 #include <unistd.h>
    7 #include <arpa/inet.h>
    8 #include <fcntl.h>
    9 #include <errno.h>
   10 #include <stdarg.h>
   11 #include "postal.h"
   12 #include "userlist.h"
   13 #include "address.h"
   14 #include "logit.h"
   15 #include "results.h"
   16 
   17 #ifdef USE_GNUTLS
   18 int base_tcp::m_init_dh_params = 0;
   19 gnutls_dh_params_t base_tcp::m_dh_params;
   20 #endif
   21 
   22 base_tcp::base_tcp(int fd, Logit *log, Logit *debug, results *res
   23 #ifdef USE_SSL
   24        , int ssl
   25 #endif
   26       ) :
   27 #ifdef USE_SSL
   28    m_canTLS(false),
   29    m_useTLS(ssl),
   30 #endif
   31    m_sock(fd)
   32  , m_start(0)
   33  , m_end(0)
   34  , m_open(true)
   35  , m_log(log)
   36  , m_debug(debug)
   37  , m_res(res)
   38 #ifdef USE_SSL
   39 #ifdef USE_OPENSSL
   40  , m_sslMeth(NULL)
   41  , m_sslCtx(NULL)
   42  , m_ssl(NULL)
   43 #else
   44  , m_gnutls_session(NULL)
   45 #endif
   46  , m_isTLS(false)
   47 #endif
   48 {
   49   m_poll.fd = m_sock;
   50 #ifdef USE_SSL
   51   if(m_useTLS)
   52   {
   53 #ifdef USE_OPENSSL
   54 //don't seem to need this    SSL_library_init();
   55     SSLeay_add_ssl_algorithms();
   56     SSL_load_error_strings();
   57 #endif
   58   }
   59 #endif
   60 }
   61 
   62 base_tcp::~base_tcp()
   63 {
   64 }
   65 
   66 #ifdef USE_SSL
   67 
   68 #ifdef USE_GNUTLS
   69 #define DH_BITS 1024
   70 
   71 void base_tcp::m_initialize_tls_session()
   72 {
   73   gnutls_init(&m_gnutls_session, GNUTLS_SERVER);
   74 
   75   /* avoid calling all the priority functions, since the defaults
   76    * are adequate.
   77    */
   78   gnutls_set_default_priority(m_gnutls_session);
   79   // Need to enable anonymous specifically
   80   gnutls_priority_set_direct(m_gnutls_session, "NORMAL:+ANON-DH", NULL);
   81 
   82   gnutls_credentials_set(m_gnutls_session, GNUTLS_CRD_ANON, m_anoncred);
   83 
   84   gnutls_dh_set_prime_bits(m_gnutls_session, DH_BITS);
   85 }
   86 
   87 void base_tcp::m_generate_dh_params()
   88 {
   89   /* Generate Diffie Hellman parameters - for use with DHE
   90    * kx algorithms. These should be discarded and regenerated
   91    * once a day, once a week or once a month. Depending on the
   92    * security requirements.
   93    */
   94   gnutls_dh_params_init(&m_dh_params);
   95   gnutls_dh_params_generate2(m_dh_params, DH_BITS);
   96 }
   97 #endif // USE_GNUTLS
   98 
   99 int base_tcp::ConnectTLS()
  100 {
  101 #ifdef USE_OPENSSL
  102   m_sslMeth = NULL;
  103   m_sslCtx = NULL;
  104   m_ssl = NULL;
  105   m_sslMeth = SSLv2_client_method();
  106   if(m_sslMeth == NULL)
  107   {
  108     fprintf(stderr, "Can't get SSLv2_client_method.\n");
  109     return 2;
  110   }
  111   m_sslCtx = SSL_CTX_new(m_sslMeth);
  112   if(m_sslCtx == NULL)
  113   {
  114     fprintf(stderr, "Can't SSL_CTX_new\n");
  115     return 2;
  116   }
  117   if((m_ssl = SSL_new(m_sslCtx)) == NULL)
  118   {
  119     fprintf(stderr, "Can't SSL_new\n");
  120     SSL_CTX_free(m_sslCtx);
  121     return 2;
  122   }
  123   SSL_set_fd(m_ssl, m_sock);
  124   if(-1 == SSL_connect(m_ssl))
  125   {
  126     fprintf(stderr, "Can't SSL_CONNECT\n");
  127     SSL_free(m_ssl);
  128     SSL_CTX_free(m_sslCtx);
  129     return 1;
  130   }
  131   m_isTLS = true;
  132 
  133 // debugging code that may be useful to have around in a commented-out state.
  134 #if 0
  135   /* Following two steps are optional and not required for
  136      data exchange to be successful. */
  137  
  138   /* Get the cipher - opt */
  139  
  140   printf ("SSL connection using %s\n", SSL_get_cipher(m_ssl));
  141  
  142   /* Get server's certificate (note: beware of dynamic allocation) - opt */
  143  
  144   X509 *server_cert;
  145   server_cert = SSL_get_peer_certificate(m_ssl);
  146   if(!server_cert)
  147   {
  148     fprintf(stderr, "Can't SSL_get_peer_certificate\n");
  149     return 2;
  150   }
  151   printf ("Server certificate:\n");
  152  
  153   char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
  154   if(!str)
  155   {
  156     fprintf(stderr, "Can't X509_NAME_oneline\n");
  157     return 2;
  158   }
  159   printf ("\t subject: %s\n", str);
  160   Free (str);
  161   str = X509_NAME_oneline (X509_get_issuer_name(server_cert),0,0);
  162   if(!str)
  163   {
  164     fprintf(stderr, "Can't X509_get_issuer_name\n");
  165     return 2;
  166   }
  167   printf ("\t issuer: %s\n", str);
  168   Free (str);
  169  
  170   /* We could do all sorts of certificate verification stuff here before
  171      deallocating the certificate. */
  172  
  173   X509_free(server_cert);
  174 #endif  // 0
  175 #else
  176 
  177   gnutls_anon_allocate_server_credentials(&m_anoncred);
  178   m_initialize_tls_session();
  179 
  180   if(!m_init_dh_params)
  181   {
  182     m_init_dh_params = 1;
  183     m_generate_dh_params();
  184   }
  185 
  186   gnutls_anon_set_server_dh_params(m_anoncred, m_dh_params);
  187 
  188   gnutls_transport_set_ptr(m_gnutls_session, (gnutls_transport_ptr_t)m_sock);
  189   int rc = gnutls_handshake(m_gnutls_session);
  190   if(rc < 0)
  191   {
  192     gnutls_deinit(m_gnutls_session);
  193     return 2;
  194   }
  195   m_isTLS = 1;
  196 
  197   /* request client certificate if any.
  198    */
  199   gnutls_certificate_server_set_request(m_gnutls_session, GNUTLS_CERT_REQUEST);
  200 
  201 #endif // USE_OPENSSL
  202   return 0;
  203 }
  204 #endif // USE_SSL
  205 
  206 int base_tcp::disconnect()
  207 {
  208   if(m_open)
  209   {
  210 #ifdef USE_SSL
  211     if(m_isTLS)
  212     {
  213 #ifdef USE_OPENSSL
  214       SSL_shutdown(m_ssl);
  215       close(m_sock);
  216       SSL_free(m_ssl);
  217       SSL_CTX_free(m_sslCtx);
  218       m_isTLS = false;
  219 #else
  220 #endif
  221     }
  222     else
  223 #endif
  224     {
  225       close(m_sock);
  226     }
  227   }
  228   m_open = false;
  229   return 0;
  230 }
  231 
  232 ERROR_TYPE base_tcp::printf(CPCCHAR fmt, ...)
  233 {
  234   va_list argp;
  235   va_start(argp, fmt);
  236   char buf[1024];
  237   int len = vsnprintf(buf, sizeof(buf), fmt, argp);
  238   if(len > (int)sizeof(buf))
  239     len = sizeof(buf);
  240   return sendData(buf, len);
  241 }
  242 
  243 ERROR_TYPE base_tcp::sendData(CPCCHAR buf, int size)
  244 {
  245   if(!m_open)
  246     return eCorrupt;
  247   int sent = 0;
  248   m_poll.events = POLLOUT | POLLERR | POLLHUP;
  249   int rc;
  250   while(sent != size)
  251   {
  252     rc = poll(&m_poll, 1, 60000);
  253     if(rc == 0)
  254     {
  255       fprintf(stderr, "Server timed out on write.\n");
  256       return eTimeout;
  257     }
  258     if(rc < 0)
  259     {
  260       fprintf(stderr, "Poll error.\n");
  261       return eSocket;
  262     }
  263 #ifdef USE_SSL
  264     if(m_isTLS)
  265     {
  266 #ifdef USE_OPENSSL
  267       rc = SSL_write(m_ssl, &buf[sent], size - sent);
  268 #else
  269       rc = gnutls_record_send(m_gnutls_session, &buf[sent], size - sent);
  270 #endif
  271     }
  272     else
  273 #endif
  274     {
  275       rc = write(m_sock, &buf[sent], size - sent);
  276     }
  277     if(rc < 1)
  278     {
  279 //      fprintf(stderr, "Can't write to socket.\n");
  280       return eSocket;
  281     }
  282     if(m_debug)
  283       m_debug->Write(buf, rc);
  284     sent += rc;
  285   }
  286   sentData(size);
  287   return eNoError;
  288 }
  289 
  290 int base_tcp::readLine(char *buf, int bufSize, bool stripCR, int timeout)
  291 {
  292   if(!m_open)
  293     return eCorrupt;
  294   int ind = 0;
  295   if(m_start < m_end)
  296   {
  297     do
  298     {
  299       buf[ind] = m_buf[m_start];
  300       ind++;
  301       m_start++;
  302     }
  303     while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
  304   }
  305   if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
  306   {
  307     receivedData(ind);
  308     if(m_debug)
  309       m_debug->Write(buf, ind);
  310     if(ind < bufSize)
  311     {
  312       ind--;
  313       buf[ind] = '\0';
  314       if(stripCR && buf[ind - 1] == '\r')
  315       {
  316         ind--;
  317         buf[ind] = '\0';
  318       }
  319     }
  320     return ind;
  321   }
  322   // buffer is empty
  323   m_start = 0;
  324   m_end = 0;
  325 
  326   time_t now = time(NULL);
  327   m_poll.events = POLLIN | POLLERR | POLLHUP;
  328   while(1)
  329   {
  330     int tmo = timeout - (time(NULL) - now);
  331     int rc;
  332     if(tmo < 0 || (rc = poll(&m_poll, 1, tmo * 1000)) == 0)
  333     {
  334       return eTimeout;
  335     }
  336     if(rc < 0)
  337     {
  338       fprintf(stderr, "Poll error.\n");
  339       return eCorrupt;
  340     }
  341 #ifdef USE_SSL
  342     if(m_isTLS)
  343     {
  344 #ifdef USE_OPENSSL
  345       rc = SSL_read(m_ssl, m_buf, sizeof(m_buf));
  346 #else
  347       rc = gnutls_record_recv(m_gnutls_session, m_buf, sizeof(m_buf));
  348 #endif
  349     }
  350     else
  351 #endif
  352     {
  353       rc = read(m_sock, m_buf, sizeof(m_buf));
  354     }
  355     if(rc < 0)
  356       return eSocket;
  357     m_end = rc;
  358     do
  359     {
  360       buf[ind] = m_buf[m_start];
  361       ind++;
  362       m_start++;
  363     } while(m_start < m_end && m_buf[m_start - 1] != '\n' && ind < bufSize);
  364 
  365     if(ind == bufSize || (ind > 0 && buf[ind - 1] == '\n') )
  366     {
  367       receivedData(ind);
  368       if(m_debug)
  369         m_debug->Write(buf, ind);
  370       if(ind < bufSize)
  371       {
  372         ind--;
  373         buf[ind] = '\0';
  374         if(stripCR && buf[ind - 1] == '\r')
  375         {
  376           ind--;
  377           buf[ind] = '\0';
  378         }
  379       }
  380       return ind;
  381     }
  382     if(m_start == m_end)
  383     {
  384       m_start = 0;
  385       m_end = 0;
  386     }
  387   }
  388   return 0; // never reached
  389 }
  390 
  391 void base_tcp::sentData(int)
  392 {
  393 }
  394 
  395 void base_tcp::receivedData(int bytes)
  396 {
  397   m_res->dataBytes(bytes);
  398 }
  399