Socket.cc

00001 // ----------------------------------------------------------------------^
00002 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
00003 // (mailto: <gcalderone@ifc.inaf.it>)
00004 // 
00005 // This file is part of MCS.
00006 // 
00007 // MCS is free software; you can redistribute it and/or modify
00008 // it under the terms of the GNU General Public License as published by
00009 // the Free Software Foundation; either version 2 of the License, or
00010 // (at your option) any later version.
00011 // 
00012 // MCS is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 // 
00017 // You should have received a copy of the GNU General Public License
00018 // along with MCS; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 // 
00021 // ----------------------------------------------------------------------$
00022 
00023 
00024 #include "mcs.hh"
00025 using namespace mcs;
00026 
00027 #include "fcntl.h"
00028 
00029 
00030 #define MCS_SOCKET_START     "DATA-START %d (%d)"
00031 #define MCS_SOCKET_SENDING   "DATA-CHUNK %d"
00032 #define MCS_SOCKET_STOP      "DATA-STOP"
00033 
00034 
00035 
00036 
00037 //--------------------------------------------------------
00038 mcs::NetInterface::NetInterface(string name)
00039 {
00040   struct if_nameindex* ni;
00041   unsigned int i=0;
00042   bool found = false;
00043 
00044   ni = if_nameindex();
00045   while (ni[i].if_index) {
00046     names.push_back(string(ni[i].if_name));
00047     i++;
00048   }
00049   if_freenameindex(ni);
00050 
00051 
00052   for (i=0; i<names.size(); i++)
00053     if (name == names[i]) {
00054       lindex = i;
00055       found = true;
00056       break;
00057     }
00058   if (! found)
00059       throw MCS_FATAL(MSG_NET_INTERFACE_NAME_NOT_EXISTS, name.csz);
00060 
00061   if (! isup())
00062       throw MCS_FATAL(MSG_NET_INTERFACE_NOT_ACTIVE, name.csz);
00063 }
00064 
00065 
00066 mcs::NetInterface::~NetInterface()
00067 {}
00068 
00069 
00070 string mcs::NetInterface::name(int index)
00071 {
00072   if (index == -1)
00073     return names[lindex];
00074 
00075   if ((unsigned int) index >= names.size())
00076       throw MCS_FATAL(MSG_NET_INTERFACE_ID_NOT_EXISTS, index, names.size());
00077 
00078 
00079   return names[index];
00080 }
00081 
00082 unsigned int mcs::NetInterface::index()
00083 {
00084   return lindex;
00085 }
00086 
00087 unsigned int mcs::NetInterface::count()
00088 {
00089   return names.size();
00090 }
00091 
00092 
00093 int mcs::NetInterface::req(int ioctl_num, struct ifreq *ifr)
00094 {
00095   int sock, ret;
00096 
00097   sock = socket(AF_INET, SOCK_STREAM, 0);
00098   strncpy(ifr->ifr_name, names[lindex].c_str(), IFNAMSIZ-1);
00099   ifr->ifr_name[IFNAMSIZ-1] = 0;
00100 
00101   ret = ioctl(sock, ioctl_num, ifr);
00102   close(sock);
00103   if (ret == -1)
00104       throw MCS_FATAL(MSG_RETRIEVING_INTERFACE_FLAGS, names[lindex].csz);
00105 
00106   return ret;
00107 }
00108 
00109 
00110 int mcs::NetInterface::getflags()
00111 {
00112   struct ifreq ifr;
00113   req(SIOCGIFFLAGS, &ifr);
00114   return ifr.ifr_flags;
00115 }
00116 
00117 
00118 bool mcs::NetInterface::isup()
00119 {
00120   return ((getflags() & IFF_UP) ? true : false);
00121 }
00122 
00123 
00124 void mcs::NetInterface::str_sockaddr(struct sockaddr* sa)
00125 {
00126   struct ifreq ifr;
00127 
00128   ifr.ifr_addr.sa_family = AF_INET;
00129   req(SIOCGIFADDR, &ifr);
00130 
00131   sa->sa_family = ifr.ifr_addr.sa_family;
00132   memcpy(sa->sa_data, ifr.ifr_addr.sa_data, 14);
00133 }
00134 
00135 
00136 void mcs::NetInterface::str_sockaddr_in(struct sockaddr_in* sin)
00137 {
00138   struct sockaddr sa;
00139   str_sockaddr(&sa);
00140   memcpy(sin, &sa, sizeof(struct sockaddr_in));
00141 }
00142 
00143 
00144 string mcs::NetInterface::ipaddress(int index)
00145 {
00146   string s;
00147   struct sockaddr_in sin;
00148 
00149   int actIndex = lindex;
00150   if (index != -1 ) {
00151   if ((unsigned int) index >= names.size())
00152       throw MCS_FATAL(MSG_NET_INTERFACE_ID_NOT_EXISTS, index, names.size());
00153 
00154     lindex = index;
00155   }
00156 
00157   s = "(not available)";
00158   try {
00159     str_sockaddr_in(&sin);
00160     s = inet_ntoa(sin.sin_addr);
00161   }
00162   catch (Event e) {}
00163 
00164   lindex = actIndex;
00165   return s;
00166 }
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 //--------------------------------------------------------
00177 mcs::HostInfo::HostInfo(string host)
00178 {
00179   struct hostent* he;
00180 
00181   he = gethostbyname(host.c_str());
00182   if (he == NULL)
00183       throw MCS_FATAL(MSG_RETRIEVING_HOSTNAME, hstrerror(h_errno));
00184 
00185   host = he->h_name;
00186   ipaddr = inet_ntoa(*(struct in_addr*)he->h_addr);
00187   populate_sockaddr_in();
00188 }
00189 
00190 
00191 mcs::HostInfo::HostInfo(int sockfd)
00192 {
00193   int ret;
00194   socklen_t len;
00195 
00196   len = sizeof(sin);
00197   ret = getpeername(sockfd, (struct sockaddr*)&sin, &len);
00198   if (ret == -1)
00199       throw MCS_FATAL(MSG_RETRIEVING_PEERNAME, strerror(errno));
00200 
00201   struct hostent* he;
00202   he = gethostbyaddr(&(sin.sin_addr), sizeof(struct in_addr), AF_INET);
00203 
00204 //  if (he == NULL)
00205 //      throw MCS_FATAL(MSG_RETRIEVING_HOST_INFO, hstrerror(errno));
00206 
00207   if (he != NULL) {
00208       host = he->h_name;
00209       ipaddr = inet_ntoa(*(struct in_addr*)he->h_addr);
00210       populate_sockaddr_in();
00211   }
00212 }
00213 
00214 mcs::HostInfo::~HostInfo()
00215 {}
00216 
00217 
00218 void mcs::HostInfo::populate_sockaddr_in()
00219 {
00220   struct in_addr addr;
00221   inet_aton(ipaddr.c_str(), &addr);
00222 
00223   sin.sin_family = AF_INET;
00224   sin.sin_port = htons(0);
00225   sin.sin_addr.s_addr = addr.s_addr;
00226   memset(&(sin.sin_zero), '\0', 8);
00227 }
00228 
00229 string mcs::HostInfo::hostname() { return host; }
00230 string mcs::HostInfo::ipaddress() { return ipaddr; }
00231 
00232 
00233 
00234 
00235 
00236 
00237 
00238 
00239 
00240 
00241 //--------------------------------------------------------
00242 mcs::Socket::Socket(string host, unsigned short int port,
00243             unsigned int readTimeout, unsigned int writeTimeout,
00244             bool use_ssl) : HostInfo(host)
00245 {
00246   MCS_DEBUG_SETUP(0, "Socket");
00247 
00248   this->port    = port;
00249   this->use_ssl = use_ssl;
00250 #ifdef HAVE_OPENSSL_SSL_H
00251   this->ssl_ctx = NULL;
00252 #endif //HAVE_OPENSSL_SSL_H
00253 
00254   set_struct_timeval(readTimeout , &readto);
00255   set_struct_timeval(writeTimeout, &writeto);
00256 
00257   sockfd = socketToHost(port);
00258 
00259 #ifdef HAVE_OPENSSL_SSL_H
00260   if (use_ssl) {
00261     SSL_library_init();
00262     ERR_load_crypto_strings();
00263     SSL_load_error_strings();
00264 
00265     ssl_ctx = SSL_CTX_new(SSLv23_method());
00266 
00267     ssl=SSL_new(ssl_ctx);
00268     sbio=BIO_new_socket(sockfd, BIO_NOCLOSE);
00269     SSL_set_bio(ssl, sbio, sbio);
00270 
00271     int ret = SSL_connect(ssl);
00272     if (ret <= 0)
00273       throw MCS_ERROR( MSG_SSL_CONNECT_ERROR );
00274 
00275     //ret = SSL_get_error(ssl, ret);
00276     //switch (ret) {
00277     //case SSL_ERROR_NONE:
00278     //  break;
00279     //case SSL_ERROR_ZERO_RETURN:     cout << "qui1" << endl; break;
00280     //case SSL_ERROR_WANT_READ:       cout << "qui2" << endl; break;
00281     //case SSL_ERROR_WANT_WRITE:        cout << "qui3" << endl; break;
00282     //case SSL_ERROR_WANT_CONNECT:    cout << "qui4" << endl; break;
00283     //case SSL_ERROR_WANT_ACCEPT:       cout << "qui5" << endl; break;
00284     //case SSL_ERROR_WANT_X509_LOOKUP:cout << "qui6" << endl; break;
00285     //case SSL_ERROR_SYSCALL:       cout << "qui7" << endl; break;
00286     //case SSL_ERROR_SSL:             cout << "qui8" << endl; break;
00287     //}
00288     //cout << ERR_error_string(ret, NULL) <<  endl;
00289     //
00290     //ERR_print_errors_fp(stderr);
00291     //throw MCS_ERROR( MSG_SSL_CONNECT_ERROR );
00292   }
00293 #endif //HAVE_OPENSSL_SSL_H
00294 }
00295 
00296 
00297 mcs::Socket::Socket(int sockfd,
00298             unsigned int readTimeout,
00299             unsigned int writeTimeout,
00300             void* ssl_ctx) : HostInfo(sockfd)
00301 {
00302   MCS_DEBUG_SETUP(0, "Socket");
00303 
00304   this->port    = 0;
00305   this->use_ssl = (ssl_ctx != NULL);
00306 #ifdef HAVE_OPENSSL_SSL_H
00307   this->ssl_ctx = NULL;
00308 #endif //HAVE_OPENSSL_SSL_H
00309 
00310   set_struct_timeval(readTimeout , &readto);
00311   set_struct_timeval(writeTimeout, &writeto);
00312 
00313   this->sockfd       = sockfd;
00314 
00315 
00316 #ifdef HAVE_OPENSSL_SSL_H
00317   if (use_ssl) {
00318     SSL_CTX* ctx = (SSL_CTX*) ssl_ctx;
00319 
00320     sbio=BIO_new_socket(sockfd, BIO_NOCLOSE);
00321     ssl=SSL_new(ctx);
00322     SSL_set_bio(ssl, sbio, sbio);
00323 
00324     if(SSL_accept(ssl) <= 0)
00325       throw MCS_ERROR( MSG_SSL_ACCEPT_ERROR );
00326   }
00327 #endif //HAVE_OPENSSL_SSL_H
00328 }
00329 
00330 
00331 
00332 int mcs::Socket::socketToHost(unsigned short port)
00333 {
00334   int ret;
00335   //int sockfd;
00336   long socketflags;
00337 
00338   sockfd = socket(PF_INET, SOCK_STREAM, 0);
00339 
00340   sin.sin_port = htons(port);
00341 
00342   // Set non-blocking
00343   socketflags = fcntl(sockfd, F_GETFL, NULL);
00344   fcntl(sockfd, F_SETFL, socketflags | O_NONBLOCK);
00345 
00346   ret = connect(sockfd, (struct sockaddr *)&sin, sizeof(struct sockaddr));
00347 
00348   if (ret == -1) {
00349     if (errno == EINPROGRESS)
00350       chkSend(THROW);
00351     else
00352       throw MCS_FATAL(MSG_CANT_CONNECT_TO_HOST, strerror(errno));
00353   }
00354 
00355   // Set to blocking mode again...
00356   fcntl(sockfd, F_SETFL, socketflags);
00357 
00358   return sockfd;
00359 }
00360 
00361 
00362 mcs::Socket::~Socket()
00363 {
00364     Socket::Close();
00365 }
00366 
00367 
00368 void mcs::Socket::Close()
00369 {
00370   if (sockfd) {
00371 #ifdef HAVE_OPENSSL_SSL_H
00372     if (use_ssl) {
00373       SSL_shutdown(ssl);
00374       SSL_free(ssl);
00375 
00376       if (ssl_ctx)
00377     SSL_CTX_free (ssl_ctx);
00378     }
00379 #endif //HAVE_OPENSSL_SSL_H
00380 
00381     close(sockfd);
00382     sockfd = 0;
00383   }
00384 }
00385 
00386 
00387 bool mcs::Socket::chkSend(enum ThrowExceptions throwexc)
00388 {
00389   bool b = false;
00390   int ret;
00391   struct timeval timeout;
00392   timeout.tv_sec = writeto.tv_sec;
00393   timeout.tv_usec = writeto.tv_usec;
00394 
00395   FD_ZERO(&fds);
00396   FD_SET(sockfd, &fds);
00397 
00398   ret = select(sockfd+1, NULL, &fds, NULL, &timeout);
00399   if (ret == -1) //Error
00400       if (throwexc)
00401       throw MCS_FATAL(MSG_CALLING_SELECT, strerror(errno));
00402 
00403   else if (ret == 0) //Timeout
00404     if (throwexc)
00405     throw MCS_FATAL(MSG_TIME_OUT);
00406 
00407   else {  //Should be ok
00408     if (FD_ISSET(sockfd, &fds))
00409       b = true;
00410     else //We didn't get an error nor a timeout, but the socket is not in the list???
00411     throw MCS_FATAL(MSG_UNEXPECTED);
00412   }
00413 
00414   return b;
00415 }
00416 
00417 
00418 bool mcs::Socket::chkRecv(bool chkDataAvailable, enum ThrowExceptions throwexc)
00419 {
00420   bool b = false;
00421   int ret;
00422   struct timeval timeout;
00423 
00424   if (chkDataAvailable) {
00425       timeout.tv_sec  = 0;
00426       timeout.tv_usec = 0;
00427   }
00428   else {
00429       timeout.tv_sec  = readto.tv_sec;
00430       timeout.tv_usec = readto.tv_usec;
00431   }
00432 
00433   FD_ZERO(&fds);
00434   FD_SET(sockfd, &fds);
00435 
00436 #ifdef HAVE_OPENSSL_SSL_H
00437   if (use_ssl) {
00438     ret = SSL_pending(ssl);
00439     if (ret > 0)
00440       return true;
00441   }
00442 #endif //HAVE_OPENSSL_SSL_H
00443 
00444   ret = select(sockfd+1, &fds, NULL, NULL, &timeout);
00445   if (ret == -1) { //Error
00446     if (throwexc)
00447     throw MCS_FATAL(MSG_CALLING_SELECT, strerror(errno));
00448   }
00449   else if (ret == 0) { //Timeout
00450     if (throwexc)
00451     throw MCS_FATAL(MSG_TIME_OUT);
00452   }
00453   else { //Should be ok
00454     if (FD_ISSET(sockfd, &fds)) {
00455       char a;
00456       ret = recv(sockfd, &a, 1, MSG_PEEK);
00457       if (ret == -1) {  //Error
00458     if (throwexc)
00459         throw MCS_FATAL(MSG_CALLING_RECV, strerror(errno));
00460       }
00461       else if (ret == 0) { //Connection closed by peer
00462     if (throwexc)
00463         throw MCS_FATAL(MSG_CLOSED_BY_PEER);
00464       }
00465       else {
00466     b = true;
00467       }
00468     }
00469     else //We didn't get an error nor a timeout but the socket isn't in the list
00470     throw MCS_FATAL(MSG_UNEXPECTED);
00471   }
00472 
00473   return b;
00474 }
00475 
00476 
00477 void mcs::Socket::sendChunk(void* p, unsigned int size)
00478 {
00479   string s;
00480   char buf[40];
00481   unsigned int resp;
00482 
00483   sprintf(buf, MCS_SOCKET_SENDING, size);
00484   print(buf);
00485     
00486   s = getline();
00487   if ((sscanf(s.c_str(), "%d", &resp) == 1)   &&   (resp == size) ) {
00488     write(p, size);
00489   }
00490   else
00491       throw MCS_WARN(MSG_SEND_ABORT_BY_RECEIVER);
00492 }
00493 
00494 
00495 unsigned int mcs::Socket::recvChunk(void* p, unsigned int maxsize)
00496 {
00497     string s;
00498     char buf[60];
00499     unsigned int chunksize;
00500 
00501     s = getline();
00502     if (s == MCS_SOCKET_STOP)
00503     return 0;
00504 
00505     if (sscanf(s.c_str(), MCS_SOCKET_SENDING, &chunksize) != 1)
00506     throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00507     
00508     if (chunksize > maxsize)
00509     throw MCS_FATAL(MSG_NOT_ENOUGH_SPACE, chunksize, maxsize);
00510 
00511     sprintf(buf, "%d", chunksize);
00512     print(buf);
00513 
00514     read(p, chunksize);
00515     return chunksize;
00516 }
00517 
00518 
00519 unsigned int mcs::Socket::recvChunk(Buffer* abuf)
00520 {
00521     string s;
00522     char buf[60];
00523     unsigned int chunksize;
00524 
00525     s = getline();
00526     if (s == MCS_SOCKET_STOP)
00527     return 0;
00528 
00529     if (sscanf(s.c_str(), MCS_SOCKET_SENDING, &chunksize) != 1)
00530     throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00531     
00532     abuf->resize(chunksize);
00533     char* p = (*abuf)[0];
00534 
00535     sprintf(buf, "%d", chunksize);
00536     print(buf);
00537 
00538     read(p, chunksize);
00539     return chunksize;
00540 }
00541 
00542 
00543 
00544 
00545 unsigned int mcs::Socket::read(void* buf, unsigned int count)
00546 {
00547   unsigned int ret, lcount;
00548   char* p = (char*) buf;
00549   chkRecv();
00550 
00551   lcount = 0;
00552   while (count>0) {
00553 
00554 #ifdef HAVE_OPENSSL_SSL_H
00555     if (use_ssl) {
00556       ret = SSL_read(ssl, p ,count);
00557       switch(SSL_get_error(ssl, ret)) {
00558       case SSL_ERROR_NONE:
00559     break;
00560       //case SSL_ERROR_ZERO_RETURN:
00561       //    goto shutdown;
00562       //case SSL_ERROR_SYSCALL:
00563       //    fprintf(stderr,
00564       //        "SSL Error: Premature close\n");
00565       //    goto done;
00566       default:
00567     throw MCS_FATAL(MSG_CLOSED_BY_PEER);
00568     //berr_exit("SSL read problem");
00569       }
00570     }
00571     else
00572 #endif //HAVE_OPENSSL_SSL_H
00573       ret = recv(sockfd, (void*) p, count, 0);
00574 
00575     if (ret == 0)
00576     throw MCS_FATAL(MSG_CLOSED_BY_PEER);
00577 
00578     count -= ret;
00579     p += ret;
00580     lcount += ret;
00581   }
00582 
00583   return lcount;
00584 }
00585 
00586 
00587 unsigned int mcs::Socket::write(void* buf, unsigned int count)
00588 {
00589   unsigned int ret;
00590 
00591   chkSend();
00592 
00593 #ifdef HAVE_OPENSSL_SSL_H
00594   if (use_ssl) {
00595     ret = SSL_write(ssl, buf, count);
00596     switch(SSL_get_error(ssl, ret)) {
00597     case SSL_ERROR_NONE:
00598       break;
00599     default:
00600       throw MCS_FATAL(MSG_CALLING_SEND, "SSL write problem");
00601     }
00602   }
00603   else
00604 #endif //HAVE_OPENSSL_SSL_H
00605     ret = send(sockfd, buf, count, 0);
00606 
00607   if (ret != count)
00608       throw MCS_FATAL(MSG_CALLING_SEND, strerror(errno));
00609 
00610   return ret;
00611 }
00612 
00613 
00614 string mcs::Socket::getline()
00615 {
00616   char p = 0;
00617   string s = "";
00618 
00619   while (p != '\n') {
00620     read(&p, 1);
00621     s += p;
00622   }
00623 
00624   remTrailing(s, "\n");
00625   return s;
00626 }
00627 
00628 
00629 void mcs::Socket::print(string s)
00630 {
00631   s += "\n";
00632   write((void*) s.c_str(), s.length());
00633 }
00634 
00635 
00636 void   mcs::Socket::sendData(Serializable* from)
00637 {
00638   void* p;
00639   char buf[40];
00640   unsigned int chunksize;
00641 
00642   MCS_DEBUG_ENTER(NOARGS);
00643 
00644   if (from->knowSize())
00645       sprintf(buf, MCS_SOCKET_START, from->size(), from->maxChunkSize());
00646   else
00647       sprintf(buf, MCS_SOCKET_START, 0, from->maxChunkSize());
00648   print(buf);
00649 
00650   while ((p = from->nextChunk(chunksize))) {
00651     if (chunksize > 0)
00652       sendChunk(p, chunksize);
00653   }
00654 
00655   sprintf(buf, MCS_SOCKET_STOP);
00656   print(buf);
00657   MCS_DEBUG_LEAVE(NOARGS);
00658 }
00659 
00660 
00661 unsigned int mcs::Socket::recvData(char** buffer, unsigned int maxsize)
00662 {
00663   unsigned int size, chunksize, accum, tmp;
00664   string s;
00665 
00666   s = getline();
00667   if (sscanf(s.c_str(), MCS_SOCKET_START, &size, &chunksize) != 2)
00668     throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00669 
00670   Buffer* abuf;
00671   if (*buffer)
00672     abuf = new Buffer(*buffer, maxsize);
00673   else
00674     abuf = new Buffer(DONT_FREE);
00675 
00676   accum = 0;
00677   while ((tmp = recvChunk(abuf)))
00678     accum += tmp;
00679 
00680   if (! (*buffer))
00681     *buffer = (*abuf)[0];
00682 
00683   return accum;
00684 
00685 //  unsigned int size, chunksize, accum, tmp;
00686 //  char* p;
00687 //  string s;
00688 //
00689 //  s = getline();
00690 //  if (sscanf(s.c_str(), MCS_SOCKET_START, &size, &chunksize) != 2)
00691 //    throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00692 //
00693 //  if (! (*buffer)) {
00694 //    if (size > 0) {
00695 //      *buffer = (char*) malloc(size);
00696 //      maxsize = size;
00697 //    }
00698 //    else {
00699 //      *buffer = (char*) malloc(chunksize);
00700 //      maxsize = chunksize;
00701 //    }
00702 //  }
00703 //  else {
00704 //    if (chunksize > maxsize)
00705 //      throw MCS_FATAL(MSG_NOT_ENOUGH_SPACE, chunksize, maxsize);
00706 //  }
00707 //
00708 //  accum = 0;
00709 //  p = *buffer;
00710 //  while ((tmp = recvChunk(p, maxsize))) {
00711 //    p += tmp;
00712 //    accum += tmp;
00713 //    if (accum > maxsize)
00714 //      *buffer = (char*) realloc(*buffer, maxsize + chunksize);
00715 //  }
00716 //
00717 //  return accum;
00718 }
00719 
00720 
00721 
00722 unsigned int mcs::Socket::recvData(string filename)
00723 {
00724   ofstream out(filename.c_str(), ios::binary);
00725   if (! out.is_open())
00726       throw MCS_ERROR(MSG_CANT_OPEN_FILE, filename.c_str());
00727 
00728   return recvData(out);
00729 }
00730 
00731 
00732 unsigned int mcs::Socket::recvData(ofstream& out)
00733 {
00734   unsigned int size, chunksize, accum, tmp;
00735   char* p;
00736   string s;
00737 
00738   s = getline();
00739   if (sscanf(s.c_str(), MCS_SOCKET_START, &size, &chunksize) != 2)
00740       throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00741 
00742   p = (char*) malloc (chunksize);
00743   accum = 0;
00744   while ((tmp = recvChunk(p, chunksize))) {
00745     out.write(p, tmp);
00746     accum += tmp;
00747   }
00748 
00749   free(p);
00750 
00751   return accum;
00752 }
00753 
00754 
00755 
00756 unsigned int mcs::Socket::recvData(int filedes)
00757 {
00758   unsigned int size, chunksize, accum, tmp;
00759   char* p;
00760   string s;
00761 
00762   s = getline();
00763   if (sscanf(s.c_str(), MCS_SOCKET_START, &size, &chunksize) != 2)
00764       throw MCS_FATAL(MSG_PROTOCOL, s.c_str());
00765 
00766   p = (char*) malloc (chunksize);
00767   accum = 0;
00768   while ((tmp = recvChunk(p, chunksize))) {
00769       ::write(filedes, p, tmp);
00770       accum += tmp;
00771   }
00772 
00773   free(p);
00774 
00775   return accum;
00776 }
00777 
00778 
00779 
00780 
00781 void mcs::Socket::set_struct_timeval(unsigned int millisec, struct timeval* time)
00782 {
00783   float fsec = ((float) millisec) / 1000.0;
00784   int   isec = (int) rintf(fsec);
00785   time->tv_sec = isec;
00786   time->tv_usec = 0;
00787 }
00788 
00789 
00790 
00791 
00792 
00793 
00794 
00795 
00796 
00797 //--------------------------------------------------------
00798 mcs::ServerSocket::ServerSocket(string interface, unsigned short int port,
00799                 bool use_ssl, string sslcert, string sslpriv) :
00800   NetInterface(interface)
00801 {
00802   int ret;
00803   struct sockaddr_in sin;
00804 
00805   this->use_ssl = use_ssl;
00806 
00807   sockfd = socket(PF_INET, SOCK_STREAM, 0);
00808   str_sockaddr_in(&sin);
00809   sin.sin_port = htons(port);
00810 
00811   ret = 1;
00812   ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int));
00813   ret = bind(sockfd, (struct sockaddr *)&sin, sizeof(struct sockaddr));
00814 
00815   if (ret == -1)
00816       throw MCS_FATAL(MSG_CALLING_BIND, strerror(errno));
00817 
00818   ret = listen(sockfd, 10);
00819   if (ret == -1)
00820       throw MCS_FATAL(MSG_CALLING_LISTEN, strerror(errno));
00821 
00822 
00823   //Eventually initialize the SSL library and a SSL context object
00824 #ifdef HAVE_OPENSSL_SSL_H
00825   ssl_ctx = NULL;
00826 
00827   if (use_ssl) {
00828     SSL_library_init();
00829     SSL_load_error_strings();
00830     ERR_load_crypto_strings();
00831 
00832     ssl_ctx=SSL_CTX_new(SSLv23_server_method());
00833 
00834 
00835     if (! SSL_CTX_use_certificate_file(ssl_ctx, sslcert.c_str(),
00836                        SSL_FILETYPE_PEM))
00837       throw MCS_FATAL ( MSG_UNEXPECTED );
00838 
00839     if (! SSL_CTX_use_PrivateKey_file(ssl_ctx, sslpriv.c_str(),
00840                       SSL_FILETYPE_PEM))
00841       throw MCS_FATAL ( MSG_UNEXPECTED );
00842 
00843     if (! SSL_CTX_check_private_key(ssl_ctx))
00844       throw MCS_FATAL ( MSG_UNEXPECTED );
00845   }
00846 #endif //HAVE_OPENSSL_SSL_H
00847 }
00848 
00849 
00850 mcs::ServerSocket::~ServerSocket()
00851 {
00852   close(sockfd);
00853 
00854 #ifdef HAVE_OPENSSL_SSL_H
00855   if (use_ssl)
00856     if (ssl_ctx)
00857       SSL_CTX_free (ssl_ctx);
00858 #endif //HAVE_OPENSSL_SSL_H
00859 }
00860 
00861 
00862 
00863 void* mcs::ServerSocket::getSSLContext()
00864 {
00865 #ifdef HAVE_OPENSSL_SSL_H
00866   if (use_ssl)
00867     return ssl_ctx;
00868   else
00869     return NULL;
00870 #else
00871   return NULL;
00872 #endif //HAVE_OPENSSL_SSL_H
00873 }
00874 
00875 
00876 
00877 bool mcs::ServerSocket::acceptConnection(int& newsock, unsigned int millisec)
00878 {
00879   struct sockaddr_in sin;
00880   socklen_t sin_size = sizeof(struct sockaddr_in);
00881 
00882   fd_set fds;
00883   FD_ZERO(&fds);
00884   FD_SET(sockfd, &fds);
00885 
00886   struct timeval timeout;
00887   Socket::set_struct_timeval(millisec, &timeout);
00888 
00889   int ret = select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
00890   if (ret == -1) { //Error
00891       throw MCS_FATAL(MSG_CALLING_SELECT, strerror(errno));
00892   }
00893   else if (ret == 0) { //Timeout
00894       return false;
00895   }
00896   else { //Should be ok
00897     if (FD_ISSET(sockfd, &fds))
00898     newsock = accept(sockfd, (struct sockaddr *)&sin, &sin_size);
00899     else //We didn't get an error nor a timeout but the socket isn't in the list
00900     throw MCS_FATAL(MSG_UNEXPECTED);
00901   }
00902 
00903   return true;
00904 }

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha3
Documentation generated on Thu Mar 22 13:22:23 UTC 2012