00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015 #include <sys/types.h>
00016 #if defined(__MINGW__) || defined(__MINGW32__)
00017 #  include <winsock.h>
00018 #  undef ERROR
00019 #else
00020 #  include <sys/wait.h>
00021 #  include <netinet/in.h>
00022 #  include <netdb.h>
00023 #  include <arpa/inet.h>
00024 #endif
00025 #include <basix/posix_port.hpp>
00026 
00028 
00029 namespace mmx {
00030 
00031 
00032 
00033 
00034 
00035 class socket_port_rep: public posix_port_rep {
00036   string host;
00037   int    pnr;
00038   int    role;
00039 
00040 public:
00041   syntactic expression () const {
00042     if (role == 0)
00043       return syn ("socket_server_port", syntactic (host), syntactic (pnr));
00044     else if (role == 1)
00045       return syn ("socket_accept_port", syntactic (host), syntactic (pnr));
00046     else
00047       return syn ("socket_client_port", syntactic (host), syntactic (pnr));
00048   }
00049 
00050   void send (const char* s, nat len) {
00051     if (this->alive) {
00052       nat total= 0;          
00053       nat bytes_left= len;   
00054       nat n= 0;
00055       while (total < len) {
00056         n= ::send (this->fd, s+total, bytes_left, 0);
00057         if (n == ((nat) -1)) break;
00058         total += n;
00059         bytes_left -= n;
00060       }
00061     }
00062   }
00063 
00064   void feed () {
00065     if (this->pos > ((N(this->buffer) >> 1) + 1024)) {
00066       this->buffer= this->buffer (this->pos, N(this->buffer));
00067       this->pos= 0;
00068     }
00069     while (this->alive && wait (0)) {
00070       char tempout[1024];
00071       int r= recv (this->fd, tempout, 1024, 0);
00072       if (r <= 0) { this->alive= false; break; }
00073       else this->buffer << string (tempout, r);
00074     }
00075   }
00076 
00077   port accept ();
00078 
00079 public:
00080   inline socket_port_rep (const string& host2, int pnr2, int role2, int fd):
00081     posix_port_rep (3, fd),
00082     host (host2), pnr (pnr2), role (role2) {}
00083   inline ~socket_port_rep () {
00084     close (this->fd); }
00085 };
00086 
00087 port
00088 socket_port (const string& host, int pnr, int role, int fd) {
00089   return (port_rep*) new socket_port_rep (host, pnr, role, fd);
00090 }
00091 
00092 
00093 
00094 
00095 
00096 port
00097 socket_server_port (const string& host, int pnr) {
00098   
00099   int fd;
00100   if ((fd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
00101     return error_port ("call to 'socket' failed");
00102 
00103   
00104 #if defined(__MINGW__) || defined(__MINGW32__)
00105   if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, NULL, 0) == -1)
00106     return error_port ("call to 'setsockopt' failed");
00107 #else
00108   int yes= 1;
00109   if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
00110                   &yes, sizeof (int)) == -1)
00111     return error_port ("call to 'setsockopt' failed");
00112 #endif
00113 
00114   
00115   struct sockaddr_in local_address;
00116   local_address.sin_family = AF_INET;
00117   local_address.sin_addr.s_addr = INADDR_ANY;
00118   local_address.sin_port = htons (pnr);
00119   memset (local_address.sin_zero, '\0', sizeof local_address.sin_zero);
00120   if (bind (fd, (struct sockaddr *) &local_address,
00121             sizeof (local_address)) == -1)
00122     return error_port ("call to 'bind' failed");
00123 
00124   
00125   if (::listen (fd, 10) == -1)
00126     return error_port ("call to 'listen' failed");
00127   return socket_port (host, pnr, 0, fd);
00128 }
00129 
00130 
00131 
00132 
00133 
00134 port
00135 socket_port_rep::accept () {
00136   ASSERT (role == 0, "socket server port expected");
00137   if (!this->alive || !wait (0)) return error_port ("no incoming connection");
00138   struct sockaddr_in remote_address;
00139 #if defined(__MINGW__) || defined(__MINGW32__)
00140   int addrlen= sizeof (remote_address);
00141 #else
00142   socklen_t addrlen= sizeof (remote_address);
00143 #endif
00144   int client=
00145     ::accept (this->fd, (struct sockaddr *) &remote_address, &addrlen);
00146   if (client == -1)
00147     return error_port ("Call to 'accept' failed");
00148   else {
00149     string addr= inet_ntoa (remote_address.sin_addr);
00150     return socket_port (host, pnr, 1, client);
00151   }
00152 }
00153 
00154 
00155 
00156 
00157 
00158 port
00159 socket_client_port (const string& host, int pnr) {
00160   
00161   char* _host= as_charp (host);
00162   struct hostent *hp = gethostbyname (_host);
00163   free_charp (_host);
00164   if (hp == NULL) return error_port ("no connection for '" * host * "'");
00165 
00166   
00167   int fd= socket (AF_INET, SOCK_STREAM, 0);
00168   if (fd < 0) return error_port ("socket could not be created");
00169 
00170   
00171   struct sockaddr_in insock;
00172   string where= host * ":" * as_string (pnr);
00173   memset ((char*) &insock, 0, sizeof (insock));
00174   insock.sin_family = AF_INET;
00175   insock.sin_port = htons ((unsigned short) pnr);
00176   memcpy ((char*) &insock.sin_addr, hp->h_addr, hp->h_length);
00177   if (connect (fd, (struct sockaddr*) &insock, sizeof (insock)) < 0)
00178     return error_port ("refused connection to '" * where * "'");
00179 
00180   
00181 #if defined(__MINGW__) || defined(__MINGW32__)
00182   unsigned long flags = -1;
00183   if (ioctlsocket (fd, FIONBIO, &flags) == SOCKET_ERROR)
00184     return error_port ("non working connection to '" * where * "'");
00185 #else
00186   int flags = O_NONBLOCK;
00187   if (fcntl (fd, F_SETFL, flags) < 0)
00188     return error_port ("non working connection to '" * where * "'");
00189 #endif
00190   return socket_port (host, pnr, 2, fd);
00191 }
00192 
00193 }