Inital
This commit is contained in:
		
						commit
						da117507f2
					
				
					 5 changed files with 914 additions and 0 deletions
				
			
		
							
								
								
									
										355
									
								
								Socket.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								Socket.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,355 @@ | |||
| 
 | ||||
| #include "Socket.h" | ||||
| 
 | ||||
| 
 | ||||
|   #include <sys/types.h>       // For data types
 | ||||
|   #include <sys/socket.h>      // For socket(), connect(), send(), and recv()
 | ||||
|   #include <netdb.h>           // For gethostbyname()
 | ||||
|   #include <arpa/inet.h>       // For inet_addr()
 | ||||
|   #include <unistd.h>          // For close()
 | ||||
|   #include <netinet/in.h>      // For sockaddr_in
 | ||||
|   #include <netinet/tcp.h>     // TCP_KEEPCNT
 | ||||
|   #include <fcntl.h> | ||||
|   typedef void raw_type;       // Type used for raw data on this platform
 | ||||
| 
 | ||||
| #include <errno.h>             // For errno
 | ||||
| 
 | ||||
| using namespace std; | ||||
| 
 | ||||
| // SocketException Code
 | ||||
| 
 | ||||
| SocketException::SocketException(const string &message, bool inclSysMsg) | ||||
|    : userMessage(message) { | ||||
|   if (inclSysMsg) { | ||||
|     userMessage.append(": "); | ||||
|     userMessage.append(strerror(errno)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| SocketException::~SocketException()  { | ||||
| } | ||||
| 
 | ||||
| const char *SocketException::what(){ | ||||
|   return userMessage.c_str(); | ||||
| } | ||||
| 
 | ||||
| // Function to fill in address structure given an address and port
 | ||||
| static void fillAddr(const string &address, unsigned short port,  | ||||
|                      sockaddr_in &addr) { | ||||
|   memset(&addr, 0, sizeof(addr));  // Zero out address structure
 | ||||
|   addr.sin_family = AF_INET;       // Internet address
 | ||||
| 
 | ||||
|   hostent *host;  // Resolve name
 | ||||
|   if ((host = gethostbyname(address.c_str())) == NULL) { | ||||
|     // strerror() will not work for gethostbyname() and hstrerror() 
 | ||||
|     // is supposedly obsolete
 | ||||
|     throw SocketException("Failed to resolve name (gethostbyname())"); | ||||
|   } | ||||
|   addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); | ||||
| 
 | ||||
|   addr.sin_port = htons(port);     // Assign port in network byte order
 | ||||
| } | ||||
| 
 | ||||
| // Socket Code
 | ||||
| 
 | ||||
| Socket::Socket(int type, int protocol)  { | ||||
| 
 | ||||
|   // Make a new socket
 | ||||
|   if ((sockDesc = socket(PF_INET, type, protocol)) < 0) { | ||||
|     throw SocketException("Socket creation failed (socket())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| Socket::Socket(int sockDesc) { | ||||
|   this->sockDesc = sockDesc; | ||||
| } | ||||
| 
 | ||||
| Socket::~Socket()  | ||||
| { | ||||
|   close(sockDesc); | ||||
|   sockDesc = -1; | ||||
| } | ||||
| 
 | ||||
| string Socket::getLocalAddress()  { | ||||
|   sockaddr_in addr; | ||||
|   unsigned int addr_len = sizeof(addr); | ||||
| 
 | ||||
|   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) { | ||||
|     throw SocketException("Fetch of local address failed (getsockname())", true); | ||||
|   } | ||||
|   return inet_ntoa(addr.sin_addr); | ||||
| } | ||||
| 
 | ||||
| unsigned short Socket::getLocalPort()  { | ||||
|   sockaddr_in addr; | ||||
|   unsigned int addr_len = sizeof(addr); | ||||
| 
 | ||||
|   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) { | ||||
|     throw SocketException("Fetch of local port failed (getsockname())", true); | ||||
|   } | ||||
|   return ntohs(addr.sin_port); | ||||
| } | ||||
| 
 | ||||
| void Socket::setLocalPort(unsigned short localPort)  { | ||||
|   // Bind the socket to its port
 | ||||
|   sockaddr_in localAddr; | ||||
|   memset(&localAddr, 0, sizeof(localAddr)); | ||||
|   localAddr.sin_family = AF_INET; | ||||
|   localAddr.sin_addr.s_addr = htonl(INADDR_ANY); | ||||
|   localAddr.sin_port = htons(localPort); | ||||
| 
 | ||||
|   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) { | ||||
|     throw SocketException("Set of local port failed (bind())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Socket::setLocalAddressAndPort(const string &localAddress, | ||||
|     unsigned short localPort)  { | ||||
|   // Get the address of the requested host
 | ||||
|   sockaddr_in localAddr; | ||||
|   fillAddr(localAddress, localPort, localAddr); | ||||
| 
 | ||||
|   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) { | ||||
|     throw SocketException("Set of local address and port failed (bind())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void Socket::setKeepalive() | ||||
| { | ||||
|       int optval = 1; | ||||
|       setsockopt(sockDesc, SOL_SOCKET, SO_KEEPALIVE,&optval, sizeof(optval)); | ||||
|        | ||||
|       optval = 2; | ||||
|       setsockopt(sockDesc, SOL_SOCKET, TCP_KEEPCNT, &optval, sizeof(optval)); | ||||
|        | ||||
|       optval = 10; | ||||
|       setsockopt(sockDesc, SOL_SOCKET, TCP_KEEPIDLE, &optval, sizeof(optval)); | ||||
|        | ||||
|       optval = 5; | ||||
|       setsockopt(sockDesc, SOL_SOCKET, TCP_KEEPINTVL, &optval, sizeof(optval)); | ||||
| } | ||||
| 
 | ||||
| void Socket::cleanUp()  { | ||||
|      | ||||
| } | ||||
| 
 | ||||
| unsigned short Socket::resolveService(const string &service, | ||||
|                                       const string &protocol) { | ||||
|   struct servent *serv;        /* Structure containing service information */ | ||||
| 
 | ||||
|   if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL) | ||||
|     return atoi(service.c_str());  /* Service is port number */ | ||||
|   else  | ||||
|     return ntohs(serv->s_port);    /* Found port (network byte order) by name */ | ||||
| } | ||||
| 
 | ||||
| // CommunicatingSocket Code
 | ||||
| 
 | ||||
| CommunicatingSocket::CommunicatingSocket(int type, int protocol)   | ||||
|      : Socket(type, protocol) { | ||||
| } | ||||
| 
 | ||||
| CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) { | ||||
| } | ||||
| 
 | ||||
| void CommunicatingSocket::connect(const string &foreignAddress, | ||||
|     unsigned short foreignPort)  { | ||||
|   // Get the address of the requested host
 | ||||
|   sockaddr_in destAddr; | ||||
|   fillAddr(foreignAddress, foreignPort, destAddr); | ||||
| 
 | ||||
|   // Try to connect to the given port
 | ||||
|   if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) { | ||||
|     throw SocketException("Connect failed (connect())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void CommunicatingSocket::send(const void *buffer, int bufferLen)  | ||||
|      { | ||||
|   if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) { | ||||
|     throw SocketException("Send failed (send())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int CommunicatingSocket::recv(void *buffer, int bufferLen)  | ||||
| { | ||||
|   int rtn; | ||||
|   if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, MSG_DONTWAIT)) < 0 )  | ||||
|   { | ||||
|     if(errno == EWOULDBLOCK || errno == EAGAIN) return -1; | ||||
|     else throw SocketException("Received failed (recv())", true); | ||||
|   } | ||||
| 
 | ||||
|   return rtn; | ||||
| } | ||||
| 
 | ||||
| string CommunicatingSocket::getForeignAddress()  | ||||
|      { | ||||
|   sockaddr_in addr; | ||||
|   unsigned int addr_len = sizeof(addr); | ||||
| 
 | ||||
|   if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) { | ||||
|     throw SocketException("Fetch of foreign address failed (getpeername())", true); | ||||
|   } | ||||
|   return inet_ntoa(addr.sin_addr); | ||||
| } | ||||
| 
 | ||||
| unsigned short CommunicatingSocket::getForeignPort()  { | ||||
|   sockaddr_in addr; | ||||
|   unsigned int addr_len = sizeof(addr); | ||||
| 
 | ||||
|   if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) { | ||||
|     throw SocketException("Fetch of foreign port failed (getpeername())", true); | ||||
|   } | ||||
|   return ntohs(addr.sin_port); | ||||
| } | ||||
| 
 | ||||
| // TCPSocket Code
 | ||||
| 
 | ||||
| TCPSocket::TCPSocket()  | ||||
|      : CommunicatingSocket(SOCK_STREAM,  | ||||
|     IPPROTO_TCP) { | ||||
| } | ||||
| 
 | ||||
| TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort, bool keepalive) | ||||
|      : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) { | ||||
|   connect(foreignAddress, foreignPort); | ||||
|   if(keepalive) setKeepalive(); | ||||
| } | ||||
| 
 | ||||
| TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) { | ||||
| } | ||||
| 
 | ||||
| // TCPServerSocket Code
 | ||||
| 
 | ||||
| TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen, bool keepaliveIN)  | ||||
|      : Socket(SOCK_STREAM, IPPROTO_TCP)  | ||||
| { | ||||
|   keepalive = keepaliveIN; | ||||
|   setLocalPort(localPort); | ||||
|   setListen(queueLen); | ||||
| } | ||||
| 
 | ||||
| TCPServerSocket::TCPServerSocket(const string &localAddress, unsigned short localPort, int queueLen, bool keepaliveIN)  | ||||
|      : Socket(SOCK_STREAM, IPPROTO_TCP)  | ||||
| { | ||||
|   keepalive = keepaliveIN; | ||||
|   setLocalAddressAndPort(localAddress, localPort); | ||||
|   setListen(queueLen); | ||||
| } | ||||
| 
 | ||||
| TCPSocket* TCPServerSocket::accept()   | ||||
| { | ||||
|   int newConnSD; | ||||
|   if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0  ) | ||||
|   { | ||||
|     throw SocketException("Accept failed (accept())", true); | ||||
|   } | ||||
|   if(keepalive) setKeepalive(); | ||||
|   return new TCPSocket(newConnSD); | ||||
| } | ||||
| 
 | ||||
| void TCPServerSocket::setListen(int queueLen)  { | ||||
|   if (listen(sockDesc, queueLen) < 0) { | ||||
|     throw SocketException("Set listening socket failed (listen())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // UDPSocket Code
 | ||||
| 
 | ||||
| UDPSocket::UDPSocket()  : CommunicatingSocket(SOCK_DGRAM, | ||||
|     IPPROTO_UDP) { | ||||
|   setBroadcast(); | ||||
| } | ||||
| 
 | ||||
| UDPSocket::UDPSocket(unsigned short localPort)   :  | ||||
|     CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) { | ||||
|   setLocalPort(localPort); | ||||
|   setBroadcast(); | ||||
| } | ||||
| 
 | ||||
| UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort)  | ||||
|       : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) { | ||||
|   setLocalAddressAndPort(localAddress, localPort); | ||||
|   setBroadcast(); | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::setBroadcast() { | ||||
|   // If this fails, we'll hear about it when we try to send.  This will allow 
 | ||||
|   // system that cannot broadcast to continue if they don't plan to broadcast
 | ||||
|   int broadcastPermission = 1; | ||||
|   setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST,  | ||||
|              (raw_type *) &broadcastPermission, sizeof(broadcastPermission)); | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::disconnect()  { | ||||
|   sockaddr_in nullAddr; | ||||
|   memset(&nullAddr, 0, sizeof(nullAddr)); | ||||
|   nullAddr.sin_family = AF_UNSPEC; | ||||
| 
 | ||||
|   // Try to disconnect
 | ||||
|   if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) { | ||||
|     if (errno != EAFNOSUPPORT) { | ||||
|       throw SocketException("Disconnect failed (connect())", true); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::sendTo(const void *buffer, int bufferLen,  | ||||
|     const string &foreignAddress, unsigned short foreignPort)  | ||||
|      { | ||||
|   sockaddr_in destAddr; | ||||
|   fillAddr(foreignAddress, foreignPort, destAddr); | ||||
| 
 | ||||
|   // Write out the whole buffer as a single message.
 | ||||
|   if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0, | ||||
|              (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) { | ||||
|     throw SocketException("Send failed (sendto())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress, | ||||
|     unsigned short &sourcePort)  { | ||||
|   sockaddr_in clntAddr; | ||||
|   socklen_t addrLen = sizeof(clntAddr); | ||||
|   int rtn; | ||||
|   if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, MSG_DONTWAIT, (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0)  | ||||
|   { | ||||
|     throw SocketException("Receive failed (recvfrom())", true); | ||||
|   } | ||||
|   sourceAddress = inet_ntoa(clntAddr.sin_addr); | ||||
|   sourcePort = ntohs(clntAddr.sin_port); | ||||
| 
 | ||||
|   return rtn; | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::setMulticastTTL(unsigned char multicastTTL)  { | ||||
|   if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL,  | ||||
|                  (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) { | ||||
|     throw SocketException("Multicast TTL set failed (setsockopt())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::joinGroup(const string &multicastGroup)  { | ||||
|   struct ip_mreq multicastRequest; | ||||
| 
 | ||||
|   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str()); | ||||
|   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY); | ||||
|   if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,  | ||||
|                  (raw_type *) &multicastRequest,  | ||||
|                  sizeof(multicastRequest)) < 0) { | ||||
|     throw SocketException("Multicast group join failed (setsockopt())", true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UDPSocket::leaveGroup(const string &multicastGroup)  { | ||||
|   struct ip_mreq multicastRequest; | ||||
| 
 | ||||
|   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str()); | ||||
|   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY); | ||||
|   if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,  | ||||
|                  (raw_type *) &multicastRequest,  | ||||
|                  sizeof(multicastRequest)) < 0) { | ||||
|     throw SocketException("Multicast group leave failed (setsockopt())", true); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										324
									
								
								Socket.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										324
									
								
								Socket.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,324 @@ | |||
| #ifndef __SOCKET_INCLUDED__ | ||||
| #define __SOCKET_INCLUDED__ | ||||
| 
 | ||||
| #include <string>            // For std::string | ||||
| #include <exception>         // For exception class | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| /**
 | ||||
|  *   Signals a problem with the execution of a socket call. | ||||
|  */ | ||||
| class SocketException : public std::exception { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Construct a SocketException with a explanatory message. | ||||
|    *   @param message explanatory message | ||||
|    *   @param incSysMsg true if system message (from strerror(errno)) | ||||
|    *   should be postfixed to the user provided message | ||||
|    */ | ||||
|   SocketException(const std::string &message, bool inclSysMsg = false) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Provided just to guarantee that no exceptions are thrown. | ||||
|    */ | ||||
|   ~SocketException() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Get the exception message | ||||
|    *   @return exception message | ||||
|    */ | ||||
|   const char *what(); | ||||
| 
 | ||||
| private: | ||||
|   std::string userMessage;  // Exception message
 | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  *   Base class representing basic communication endpoint | ||||
|  */ | ||||
| class Socket { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Close and deallocate this socket | ||||
|    */ | ||||
|   ~Socket(); | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Get the local address | ||||
|    *   @return local address of socket | ||||
|    *   @exception SocketException thrown if fetch fails | ||||
|    */ | ||||
|   std::string getLocalAddress(); | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Get the local port | ||||
|    *   @return local port of socket | ||||
|    *   @exception SocketException thrown if fetch fails | ||||
|    */ | ||||
|   unsigned short getLocalPort() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Set the local port to the specified port and the local address | ||||
|    *   to any interface | ||||
|    *   @param localPort local port | ||||
|    *   @exception SocketException thrown if setting local port fails | ||||
|    */ | ||||
|   void setLocalPort(unsigned short localPort) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Set the local port to the specified port and the local address | ||||
|    *   to the specified address.  If you omit the port, a random port  | ||||
|    *   will be selected. | ||||
|    *   @param localAddress local address | ||||
|    *   @param localPort local port | ||||
|    *   @exception SocketException thrown if setting local port or address fails | ||||
|    */ | ||||
|   void setLocalAddressAndPort(const std::string &localAddress,  | ||||
|     unsigned short localPort = 0) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   If WinSock, unload the WinSock DLLs; otherwise do nothing.  We ignore | ||||
|    *   this in our sample client code but include it in the library for | ||||
|    *   completeness.  If you are running on Windows and you are concerned | ||||
|    *   about DLL resource consumption, call this after you are done with all | ||||
|    *   Socket instances.  If you execute this on Windows while some instance of | ||||
|    *   Socket exists, you are toast.  For portability of client code, this is  | ||||
|    *   an empty function on non-Windows platforms so you can always include it. | ||||
|    *   @param buffer buffer to receive the data | ||||
|    *   @param bufferLen maximum number of bytes to read into buffer | ||||
|    *   @return number of bytes read, 0 for EOF, and -1 for error | ||||
|    *   @exception SocketException thrown WinSock clean up fails | ||||
|    */ | ||||
|   static void cleanUp() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Resolve the specified service for the specified protocol to the | ||||
|    *   corresponding port number in host byte order | ||||
|    *   @param service service to resolve (e.g., "http") | ||||
|    *   @param protocol protocol of service to resolve.  Default is "tcp". | ||||
|    */ | ||||
|   static unsigned short resolveService(const std::string &service, | ||||
|                                        const std::string &protocol = "tcp"); | ||||
|    | ||||
|   void setKeepalive(); | ||||
| 
 | ||||
| private: | ||||
|   // Prevent the user from trying to use value semantics on this object
 | ||||
|   Socket(const Socket &sock); | ||||
|   void operator=(const Socket &sock); | ||||
| 
 | ||||
| protected: | ||||
|   int sockDesc;              // Socket descriptor
 | ||||
|   Socket(int type, int protocol) ; | ||||
|   Socket(int sockDesc); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  *   Socket which is able to connect, send, and receive | ||||
|  */ | ||||
| class CommunicatingSocket : public Socket { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Establish a socket connection with the given foreign | ||||
|    *   address and port | ||||
|    *   @param foreignAddress foreign address (IP address or name) | ||||
|    *   @param foreignPort foreign port | ||||
|    *   @exception SocketException thrown if unable to establish connection | ||||
|    */ | ||||
|   void connect(const std::string &foreignAddress, unsigned short foreignPort) | ||||
|     ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Write the given buffer to this socket.  Call connect() before | ||||
|    *   calling send() | ||||
|    *   @param buffer buffer to be written | ||||
|    *   @param bufferLen number of bytes from buffer to be written | ||||
|    *   @exception SocketException thrown if unable to send data | ||||
|    */ | ||||
|   void send(const void *buffer, int bufferLen) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Read into the given buffer up to bufferLen bytes data from this | ||||
|    *   socket.  Call connect() before calling recv() | ||||
|    *   @param buffer buffer to receive the data | ||||
|    *   @param bufferLen maximum number of bytes to read into buffer | ||||
|    *   @return number of bytes read, 0 for EOF, and -1 for error | ||||
|    *   @exception SocketException thrown if unable to receive data | ||||
|    */ | ||||
|   int recv(void *buffer, int bufferLen) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Get the foreign address.  Call connect() before calling recv() | ||||
|    *   @return foreign address | ||||
|    *   @exception SocketException thrown if unable to fetch foreign address | ||||
|    */ | ||||
|   std::string getForeignAddress() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Get the foreign port.  Call connect() before calling recv() | ||||
|    *   @return foreign port | ||||
|    *   @exception SocketException thrown if unable to fetch foreign port | ||||
|    */ | ||||
|   unsigned short getForeignPort() ; | ||||
| 
 | ||||
| protected: | ||||
|   CommunicatingSocket(int type, int protocol) ; | ||||
|   CommunicatingSocket(int newConnSD); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  *   TCP socket for communication with other TCP sockets | ||||
|  */ | ||||
| class TCPSocket : public CommunicatingSocket { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Construct a TCP socket with no connection | ||||
|    *   @exception SocketException thrown if unable to create TCP socket | ||||
|    */ | ||||
|   TCPSocket() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Construct a TCP socket with a connection to the given foreign address | ||||
|    *   and port | ||||
|    *   @param foreignAddress foreign address (IP address or name) | ||||
|    *   @param foreignPort foreign port | ||||
|    *   @exception SocketException thrown if unable to create TCP socket | ||||
|    */ | ||||
|   TCPSocket(const std::string &foreignAddress, unsigned short foreignPort, bool keepalive = false)  | ||||
|       ; | ||||
| 
 | ||||
|   bool isOpen(); | ||||
|      | ||||
| private: | ||||
|   // Access for TCPServerSocket::accept() connection creation
 | ||||
|   friend class TCPServerSocket; | ||||
|   TCPSocket(int newConnSD); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  *   TCP socket class for servers | ||||
|  */ | ||||
| class TCPServerSocket : public Socket { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Construct a TCP socket for use with a server, accepting connections | ||||
|    *   on the specified port on any interface | ||||
|    *   @param localPort local port of server socket, a value of zero will | ||||
|    *                   give a system-assigned unused port | ||||
|    *   @param queueLen maximum queue length for outstanding  | ||||
|    *                   connection requests (default 5) | ||||
|    *   @exception SocketException thrown if unable to create TCP server socket | ||||
|    */ | ||||
|   TCPServerSocket(unsigned short localPort, int queueLen = 5, bool keepaliveIN = false); | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Construct a TCP socket for use with a server, accepting connections | ||||
|    *   on the specified port on the interface specified by the given address | ||||
|    *   @param localAddress local interface (address) of server socket | ||||
|    *   @param localPort local port of server socket | ||||
|    *   @param queueLen maximum queue length for outstanding  | ||||
|    *                   connection requests (default 5) | ||||
|    *   @exception SocketException thrown if unable to create TCP server socket | ||||
|    */ | ||||
|   TCPServerSocket(const std::string &localAddress, unsigned short localPort, | ||||
|       int queueLen = 5, bool keepaliveIN = false); | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Blocks until a new connection is established on this socket or error | ||||
|    *   @return new connection socket | ||||
|    *   @exception SocketException thrown if attempt to accept a new connection fails | ||||
|    */ | ||||
|   TCPSocket *accept() ; | ||||
| 
 | ||||
| private: | ||||
|   void setListen(int queueLen) ; | ||||
|   bool keepalive; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   *   UDP socket class | ||||
|   */ | ||||
| class UDPSocket : public CommunicatingSocket { | ||||
| public: | ||||
|   /**
 | ||||
|    *   Construct a UDP socket | ||||
|    *   @exception SocketException thrown if unable to create UDP socket | ||||
|    */ | ||||
|   UDPSocket() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Construct a UDP socket with the given local port | ||||
|    *   @param localPort local port | ||||
|    *   @exception SocketException thrown if unable to create UDP socket | ||||
|    */ | ||||
|   UDPSocket(unsigned short localPort) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Construct a UDP socket with the given local port and address | ||||
|    *   @param localAddress local address | ||||
|    *   @param localPort local port | ||||
|    *   @exception SocketException thrown if unable to create UDP socket | ||||
|    */ | ||||
|   UDPSocket(const std::string &localAddress, unsigned short localPort)  | ||||
|       ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Unset foreign address and port | ||||
|    *   @return true if disassociation is successful | ||||
|    *   @exception SocketException thrown if unable to disconnect UDP socket | ||||
|    */ | ||||
|   void disconnect() ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Send the given buffer as a UDP datagram to the | ||||
|    *   specified address/port | ||||
|    *   @param buffer buffer to be written | ||||
|    *   @param bufferLen number of bytes to write | ||||
|    *   @param foreignAddress address (IP address or name) to send to | ||||
|    *   @param foreignPort port number to send to | ||||
|    *   @return true if send is successful | ||||
|    *   @exception SocketException thrown if unable to send datagram | ||||
|    */ | ||||
|   void sendTo(const void *buffer, int bufferLen, const std::string &foreignAddress, | ||||
|             unsigned short foreignPort) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Read read up to bufferLen bytes data from this socket.  The given buffer | ||||
|    *   is where the data will be placed | ||||
|    *   @param buffer buffer to receive data | ||||
|    *   @param bufferLen maximum number of bytes to receive | ||||
|    *   @param sourceAddress address of datagram source | ||||
|    *   @param sourcePort port of data source | ||||
|    *   @return number of bytes received and -1 for error | ||||
|    *   @exception SocketException thrown if unable to receive datagram | ||||
|    */ | ||||
|   int recvFrom(void *buffer, int bufferLen, std::string &sourceAddress,  | ||||
|                unsigned short &sourcePort) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Set the multicast TTL | ||||
|    *   @param multicastTTL multicast TTL | ||||
|    *   @exception SocketException thrown if unable to set TTL | ||||
|    */ | ||||
|   void setMulticastTTL(unsigned char multicastTTL) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Join the specified multicast group | ||||
|    *   @param multicastGroup multicast group address to join | ||||
|    *   @exception SocketException thrown if unable to join group | ||||
|    */ | ||||
|   void joinGroup(const std::string &multicastGroup) ; | ||||
| 
 | ||||
|   /**
 | ||||
|    *   Leave the specified multicast group | ||||
|    *   @param multicastGroup multicast group address to leave | ||||
|    *   @exception SocketException thrown if unable to leave group | ||||
|    */ | ||||
|   void leaveGroup(const std::string &multicastGroup) ; | ||||
| 
 | ||||
| private: | ||||
|   void setBroadcast(); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										150
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								main.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,150 @@ | |||
| #include <iostream> | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/un.h> | ||||
| #include <string> | ||||
| #include <cstdlib> | ||||
| #include <vector> | ||||
| #include <thread> | ||||
| 
 | ||||
| #include "serial_io.h" | ||||
| #include "Socket.h" | ||||
| 
 | ||||
| bool stop = false; | ||||
| 
 | ||||
| void intHandler(int dummy)  | ||||
| { | ||||
|     stop = true; | ||||
| } | ||||
| 
 | ||||
| static void printUsage() | ||||
| { | ||||
|     std::cout<<"usage mulitplexer [option]-\n\
 | ||||
|                 Available options:\n\ | ||||
|                 -h, --help       print this help\n\ | ||||
|                 -p, --serialport serial port device to use\n\ | ||||
|                 -P, --port       tcp port to use\n\ | ||||
|                 -b, --baud       set baud rate with termios id\n"; | ||||
| } | ||||
| 
 | ||||
| class Config | ||||
| { | ||||
| public: | ||||
|     std::string portFileName = "/dev/ttyUSB0"; | ||||
|     unsigned short port = 6856; | ||||
|     int baud = 0000017; | ||||
| }; | ||||
| 
 | ||||
| static int parseCmdArgs(int argc, char** argv, Config *config) | ||||
| { | ||||
|     for (int i = 1; i < argc; i++) | ||||
|     { | ||||
|         if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") | ||||
|         { | ||||
|             printUsage(); | ||||
|             return -1; | ||||
|         } | ||||
|         else if (std::string(argv[i]) == "--serialport" || std::string(argv[i]) == "-p") | ||||
|         { | ||||
|             if(argc > i+1) config->portFileName = argv[i+1]; | ||||
|             else return -1; | ||||
|         } | ||||
|         else if (std::string(argv[i]) == "--port" || std::string(argv[i]) == "-P") | ||||
|         { | ||||
|             if(argc > i+1) config->portFileName = atoi(argv[i+1]); | ||||
|             else return -1; | ||||
|         } | ||||
|          else if (std::string(argv[i]) == "--baud" || std::string(argv[i]) == "-b") | ||||
|         { | ||||
|             if(argc > i+1) config->baud = atoi(argv[i+1]); | ||||
|             else return -1; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void acceptThreadFunction( TCPServerSocket* servSock,  std::vector<TCPSocket*>* clientSockets, volatile bool* stop ) | ||||
| { | ||||
|     while(!(*stop))  | ||||
|     {   // Run forever
 | ||||
|         clientSockets->push_back(servSock->accept());       // Wait for a client to connect
 | ||||
|         clientSockets->back()->send("UVOS serial port multiplexer v0.1\n", sizeof("uvos serial port multiplexer v0.1\n")-1); | ||||
|         std::cout<<"got client\n"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char* argv[]) | ||||
| { | ||||
|     Config config; | ||||
|      | ||||
|     if(parseCmdArgs(argc, argv, &config) != 0) return -1; | ||||
|      | ||||
|     std::cout<<"UVOS serial mulitplexer v0.1\n"; | ||||
|      | ||||
|     int serial = serialport_init(config.portFileName.c_str(), config.baud); | ||||
| 
 | ||||
|     std::vector<TCPSocket*> clientSockets; | ||||
|      | ||||
|     std::cout<<"opening TCP socet on port "<<config.port<<'\n'; | ||||
|     TCPServerSocket servSock(config.port, 5, true);     // Server Socket object
 | ||||
|      | ||||
|     volatile bool threadStopper = false; | ||||
|     std::thread acceptThread(acceptThreadFunction, &servSock, &clientSockets,  &threadStopper); | ||||
|      | ||||
|     char buffer[256]; | ||||
|      | ||||
|     std::cout<<"starting loop\n"; | ||||
|      | ||||
|     while(!stop) | ||||
|     { | ||||
|         int readlen = sRead(serial, buffer, 256); | ||||
|         //std::cout<<clientSockets.size()<<std::endl;
 | ||||
|         for(unsigned int i = 0; i < clientSockets.size(); i++) | ||||
|         { | ||||
|             try | ||||
|             { | ||||
| 
 | ||||
|                 if(readlen > 0)  | ||||
|                 { | ||||
|                     std::cout<<"sending: "; | ||||
|                     for( int j = 0; j < readlen; j++  )std::cout<<buffer[j]; | ||||
|                     clientSockets[i]->send(buffer, readlen); | ||||
|                     std::cout<<std::endl; | ||||
|                 } | ||||
|                  | ||||
|                 char inBuffer[256]; | ||||
|                 int reclen = clientSockets[i]->recv(inBuffer, 256); | ||||
|                 if( reclen > 0 )  | ||||
|                 { | ||||
|                     std::cout<<"rec "<<reclen<<'\n'; | ||||
|                     for( int j = 0; j < reclen; j++  )std::cout<<inBuffer[j]; | ||||
|                     sWrite(serial, inBuffer, reclen); | ||||
|                 } | ||||
|                 else if(reclen == 0) | ||||
|                 { | ||||
|                     std::cout<<"disconnect client "<<i<<'\n'; | ||||
|                     clientSockets[i]->cleanUp(); | ||||
|                     clientSockets.erase(clientSockets.begin()+i); | ||||
|                     i--; | ||||
|                     if(i < 0) i=0; | ||||
|                 } | ||||
|             } | ||||
|             catch(SocketException e) | ||||
|             { | ||||
|                 std::cout<<e.what()<<std::endl; | ||||
|                 clientSockets[i]->cleanUp(); | ||||
|                 clientSockets.erase(clientSockets.begin()+i); | ||||
|                 i--; | ||||
|                 if(i < 0) i=0; | ||||
|             } | ||||
|         } | ||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(20)); | ||||
|     } | ||||
|      | ||||
|     threadStopper = true; | ||||
|     acceptThread.join(); | ||||
|     for(unsigned int i = 0; i < clientSockets.size(); i++) clientSockets[i]->cleanUp(); | ||||
|     servSock.cleanUp(); | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										65
									
								
								serial_io.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								serial_io.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| #include "serial_io.h" | ||||
| 
 | ||||
| struct termios toptions; | ||||
| 
 | ||||
| void sWrite(int port, char string[], size_t length) | ||||
| { | ||||
|     if(port != -1) write(port, string, length); | ||||
|     else for( int j = 0; j < length; j++  )std::cout<<string[j]; | ||||
| } | ||||
| 
 | ||||
| void sWrite(int port, const char string[], size_t length) | ||||
| { | ||||
|     if(port != -1) write(port, string, length); | ||||
|     else for( int j = 0; j < length; j++  )std::cout<<string[j]; | ||||
| } | ||||
| 
 | ||||
| ssize_t sRead(int port, void *buf, size_t count) | ||||
| { | ||||
|     return (port != -1) ? read(port, buf, count) : 0; | ||||
| } | ||||
| 
 | ||||
| int serialport_init(const char* device, int baud) | ||||
| { | ||||
|     int fd; | ||||
|     fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); | ||||
|     if (fd == -1) | ||||
|         { | ||||
|         perror("init_serialport: Unable to open port "); | ||||
|         return -1; | ||||
|         } | ||||
| 
 | ||||
|     if (tcgetattr(fd, &toptions) < 0) | ||||
|         { | ||||
|         perror("init_serialport: Couldn't get term attributes"); | ||||
|         return -1; | ||||
|          | ||||
|     cfsetispeed(&toptions, baud); | ||||
|     cfsetospeed(&toptions, baud); | ||||
|     // 8N1
 | ||||
|     toptions.c_cflag &= ~PARENB; | ||||
|     toptions.c_cflag &= ~CSTOPB; | ||||
|     toptions.c_cflag &= ~CSIZE; | ||||
|     toptions.c_cflag |= CS8; | ||||
|     // no flow control
 | ||||
|     toptions.c_cflag &= ~(CRTSCTS | CLOCAL); | ||||
| 
 | ||||
|     toptions.c_cflag |= IGNPAR | CREAD;  // turn on READ & ignore ctrl lines
 | ||||
|     toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
 | ||||
| 
 | ||||
|     toptions.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE); // make raw
 | ||||
|     toptions.c_oflag &= ~OPOST; // make raw
 | ||||
| 
 | ||||
|     // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
 | ||||
|     /*toptions.c_cc[VMIN]  = 0;
 | ||||
|     toptions.c_cc[VTIME] = 20; | ||||
|     fcntl(fd, F_SETFL, FNDELAY);*/ | ||||
| 
 | ||||
|     if( tcsetattr(fd, TCSANOW, &toptions) < 0) | ||||
|         { | ||||
|         perror("init_serialport: Couldn't set term attributes"); | ||||
|         return -1; | ||||
|         } | ||||
|     return fd; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										20
									
								
								serial_io.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								serial_io.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| #ifndef SERIAL_H | ||||
| #define SERIAL_H | ||||
| #include <termios.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #define BAUDRATE B38400 | ||||
| 
 | ||||
| void sWrite(int port, char string[], size_t length); | ||||
| 
 | ||||
| void sWrite(int port, const char string[], size_t length); | ||||
| 
 | ||||
| ssize_t sRead(int port, void *buf, size_t count); | ||||
| 
 | ||||
| 
 | ||||
| int serialport_init(const char* device, int baud = BAUDRATE); | ||||
| 
 | ||||
| 
 | ||||
| #endif // SERIAL_H
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 IMback
						IMback