# HG changeset patch # User etisserant # Date 1200385769 -3600 # Node ID 12adbd08e10ce9ccacbcd6d52bdd0cde9ea536a8 # Parent 396ac66670ad6e80075b704e6ae9053adf3757f6 TCP broadcasting chat server to exchange CAN messages between CanFestival nodes on windows. This let user simulate a CANopen network on windows. diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/.cvsignore Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,4 @@ +libcanfestival_can_socket.so +Makefile +*.exe +*.dll diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/Makefile.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/Makefile.in Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,86 @@ +#! gmake + +# +# Copyright (C) 2006 Edouard TISSERANT +# +# This file is part of canfestival, a library implementing the canopen +# stack +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +CC = SUB_CC +CXX = SUB_CXX +LD = SUB_LD +OPT_CFLAGS = -O2 +CFLAGS = SUB_OPT_CFLAGS +PROG_CFLAGS = SUB_PROG_CFLAGS +PREFIX = SUB_PREFIX +TARGET = SUB_TARGET +CAN_DRIVER = SUB_CAN_DRIVER +TIMERS_DRIVER = SUB_TIMERS_DRIVER +ENABLE_DLL_DRIVERS=SUB_ENABLE_DLL_DRIVERS +CAN_DLL_CFLAGS=SUB_CAN_DLL_CFLAGS + +INCLUDES = -I../../include -I../../include/$(TARGET) -I../../include/$(CAN_DRIVER) + +OBJS = Socket.o $(CAN_DRIVER).o + +ifeq ($(ENABLE_DLL_DRIVERS),1) +#CFLAGS += -fPIC +DRIVER = cyg$(CAN_DRIVER).dll +else +DRIVER = $(OBJS) +endif + +SERVER = $(CAN_DRIVER)_server + +TARGET_SOFILES = $(PREFIX)/lib/$(DRIVER) + +all: driver + +driver: $(DRIVER) $(SERVER).exe + +$(SERVER).exe: Socket.o $(SERVER).cpp + $(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) $^ -o $@ -lws2_32 + +Socket.o: Socket.cpp Socket.h + $(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -c $< -o $@ + +%o: %c + $(CC) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -o $@ -c $< + +%o: %cpp + $(CXX) $(CFLAGS) $(PROG_CFLAGS) ${PROGDEFINES} $(INCLUDES) -o $@ -c $< + +$(DRIVER): $(OBJS) + $(LD) $(PROG_CFLAGS) -shared -o $@ \ + -Wl,--export-all-symbols \ + -Wl,--enable-auto-import \ + -Wl,--whole-archive $^ \ + -Wl,--no-whole-archive $(CAN_DLL_CFLAGS) \ + -Wl,--exclude-libs,ALL -lws2_32 + +install: libcanfestival_$(CAN_DRIVER).so + mkdir -p $(PREFIX)/lib/ + cp $< $(PREFIX)/lib/ + +uninstall: + rm -f $(TARGET_SOFILES) + +clean: + rm -f $(OBJS) + +mrproper: clean diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/Socket.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/Socket.cpp Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,249 @@ +/* + Socket.cpp + + Copyright (C) 2002-2004 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + + +#include "Socket.h" +#include + +using namespace std; + +int Socket::nofSockets_= 0; + +void Socket::Start() { + if (!nofSockets_) { + WSADATA info; + if (WSAStartup(MAKEWORD(2,0), &info)) { + throw "Could not start WSA"; + } + } + ++nofSockets_; +} + +void Socket::End() { + WSACleanup(); +} + +Socket::Socket() : s_(0) { + Start(); + // UDP: use SOCK_DGRAM instead of SOCK_STREAM + s_ = socket(AF_INET,SOCK_STREAM,0); + + if (s_ == INVALID_SOCKET) { + throw "INVALID_SOCKET"; + } + + refCounter_ = new int(1); +} + +Socket::Socket(SOCKET s) : s_(s) { + Start(); + refCounter_ = new int(1); +}; + +Socket::~Socket() { + if (! --(*refCounter_)) { + Close(); + delete refCounter_; + } + + --nofSockets_; + if (!nofSockets_) End(); +} + +Socket::Socket(const Socket& o) { + refCounter_=o.refCounter_; + (*refCounter_)++; + s_ =o.s_; + + nofSockets_++; +} + +Socket& Socket::operator=(Socket& o) { + (*o.refCounter_)++; + + refCounter_=o.refCounter_; + s_ =o.s_; + + nofSockets_++; + + return *this; +} + +void Socket::Close() { + closesocket(s_); +} + +std::string Socket::ReceiveBytes() { + std::string ret; + char buf[1024]; + + while (1) { + u_long arg = 0; + if (ioctlsocket(s_, FIONREAD, &arg) != 0) + break; + + if (arg == 0) + break; + + if (arg > 1024) arg = 1024; + + int rv = recv (s_, buf, arg, 0); + if (rv <= 0) break; + + std::string t; + + t.assign (buf, rv); + ret += t; + } + + return ret; +} + +std::string Socket::ReceiveLine() { + std::string ret; + while (1) { + char r; + + switch(recv(s_, &r, 1, 0)) { + case 0: // not connected anymore; + // ... but last line sent + // might not end in \n, + // so return ret anyway. + return ret; + case -1: + return ""; +// if (errno == EAGAIN) { +// return ret; +// } else { +// // not connected anymore +// return ""; +// } + } + + if (r == '\n') return ret; + ret += r; + } +} + +void Socket::SendLine(std::string s) { + s += '\n'; + send(s_,s.c_str(),s.length(),0); +} + +void Socket::SendBytes(const std::string& s) { + send(s_,s.c_str(),s.length(),0); +} + +SocketServer::SocketServer(int port, int connections, TypeSocket type) { + sockaddr_in sa; + + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = PF_INET; + sa.sin_port = htons(port); + s_ = socket(AF_INET, SOCK_STREAM, 0); + if (s_ == INVALID_SOCKET) { + throw "INVALID_SOCKET"; + } + + if(type==NonBlockingSocket) { + u_long arg = 1; + ioctlsocket(s_, FIONBIO, &arg); + } + + /* bind the socket to the internet address */ + if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) { + closesocket(s_); + throw "INVALID_SOCKET"; + } + + listen(s_, connections); +} + +Socket* SocketServer::Accept() { + SOCKET new_sock = accept(s_, 0, 0); + if (new_sock == INVALID_SOCKET) { + int rc = WSAGetLastError(); + if(rc==WSAEWOULDBLOCK) { + return 0; // non-blocking call, no request pending + } + else { + throw "Invalid Socket"; + } + } + + Socket* r = new Socket(new_sock); + return r; +} + +SocketClient::SocketClient(const std::string& host, int port) : Socket() { + std::string error; + + hostent *he; + if ((he = gethostbyname(host.c_str())) == 0) { + error = strerror(errno); + throw error; + } + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *((in_addr *)he->h_addr); + memset(&(addr.sin_zero), 0, 8); + + if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) { + error = strerror(WSAGetLastError()); + throw error; + } +} + +SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) { + FD_ZERO(&fds_); + FD_SET(const_cast(s1)->s_,&fds_); + if(s2) { + FD_SET(const_cast(s2)->s_,&fds_); + } + + TIMEVAL tval; + tval.tv_sec = 0; + tval.tv_usec = 1; + + TIMEVAL *ptval; + if(type==NonBlockingSocket) { + ptval = &tval; + } + else { + ptval = 0; + } + + if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR) + throw "Error in select"; +} + +bool SocketSelect::Readable(Socket const* const s) { + if (FD_ISSET(s->s_,&fds_)) return true; + return false; +} diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/Socket.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/Socket.h Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,100 @@ +/* + Socket.h + + Copyright (C) 2002-2004 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + +#ifndef SOCKET_H +#define SOCKET_H + +#include + +#include + +enum TypeSocket {BlockingSocket, NonBlockingSocket}; + +class Socket { +public: + + virtual ~Socket(); + Socket(const Socket&); + Socket& operator=(Socket&); + + std::string ReceiveLine(); + std::string ReceiveBytes(); + + void Close(); + + // The parameter of SendLine is not a const reference + // because SendLine modifes the std::string passed. + void SendLine (std::string); + + // The parameter of SendBytes is a const reference + // because SendBytes does not modify the std::string passed + // (in contrast to SendLine). + void SendBytes(const std::string&); + +protected: + friend class SocketServer; + friend class SocketSelect; + + Socket(SOCKET s); + Socket(); + + + SOCKET s_; + + int* refCounter_; + +private: + static void Start(); + static void End(); + static int nofSockets_; +}; + +class SocketClient : public Socket { +public: + SocketClient(const std::string& host, int port); +}; + +class SocketServer : public Socket { +public: + SocketServer(int port, int connections, TypeSocket type=BlockingSocket); + + Socket* Accept(); +}; + +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.asp +class SocketSelect { + public: + SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket); + + bool Readable(Socket const * const s); + + private: + fd_set fds_; +}; + + + +#endif diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/can_tcp_win32.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/can_tcp_win32.cpp Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,120 @@ +/* +This file is part of CanFestival, a library implementing CanOpen Stack. + +Copyright (C): Edouard TISSERANT + +See COPYING file for copyrights details. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Socket.h" + +#include + +using namespace std; + +extern "C" { +#include "can_driver.h" +} + +//------------------------------------------------------------------------ +extern "C" + UNS8 canReceive_driver(CAN_HANDLE fd0, Message *m) + { + + string l = reinterpret_cast(fd0)->ReceiveLine(); + + int res = sscanf(l.c_str(),"{0x%3hx,%1hhd,%1hhd,{0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx,0x%2hhx}}", + &m->cob_id, + &m->rtr, + &m->len, + &m->data[0], + &m->data[1], + &m->data[2], + &m->data[3], + &m->data[4], + &m->data[5], + &m->data[6], + &m->data[7] + ); + + +#if defined DEBUG_MSG_CONSOLE_ON + printf("in : "); + print_message(m); +#endif + + return res==11 ? 0 : 1 ; + } + +extern "C" + UNS8 canSend_driver(CAN_HANDLE fd0, Message *m) + { + char s[1024]; + sprintf(s,"{0x%3.3x,%1d,%1d,{0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x}}", + m->cob_id, + m->rtr, + m->len, + m->data[0], + m->data[1], + m->data[2], + m->data[3], + m->data[4], + m->data[5], + m->data[6], + m->data[7] + ); + + reinterpret_cast(fd0)->SendLine(s); +#if defined DEBUG_MSG_CONSOLE_ON + printf("out : "); + print_message(m); +#endif + return 0; + } + +extern "C" + CAN_HANDLE canOpen_driver(s_BOARD *board) + { + Socket* s; + try { + s = new SocketClient(board->busname, 11898); + + //s.SendLine("GET / HTTP/1.0"); + //s.SendLine("Host: www.google.com"); + } + catch (const char* _s) { + cerr << _s << endl; + return NULL; + } + catch (std::string _s) { + cerr << _s << endl; + return NULL; + } + catch (...) { + cerr << "unhandled exception\n"; + return NULL; + } + return (CAN_HANDLE) s; + } + +extern "C" + int canClose_driver(CAN_HANDLE inst) + { + delete reinterpret_cast(inst); + return 1; + } + diff -r 396ac66670ad -r 12adbd08e10c drivers/can_tcp_win32/can_tcp_win32_server.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_tcp_win32/can_tcp_win32_server.cpp Tue Jan 15 09:29:29 2008 +0100 @@ -0,0 +1,86 @@ +/* +This file is part of CanFestival, a library implementing CanOpen Stack. + +Copyright (C): Edouard TISSERANT + +See COPYING file for copyrights details. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "Socket.h" +#include +#include +#include +#include + +using namespace std; + +typedef std::list socket_list; + +socket_list g_connections; + +unsigned __stdcall Connection(void* a) { + Socket* s = (Socket*) a; + + g_connections.push_back(s); + + //s->SendLine("Welcome to the Message Distributor"); + printf("Accepted new connection (0x%x).\n"); + while (1) { + std::string r = s->ReceiveLine(); + if (r.empty()) break; + //cout << r << endl; + for (socket_list::iterator os =g_connections.begin(); + os!=g_connections.end(); + os++) { + if (*os != s) (*os)->SendLine(r); + } + } + + g_connections.remove(s); + + delete s; + + printf("Connection closed (0x%x).\n",s); + + return 0; +} + +int main() { + printf("************************************************\n" + "* TCP broadcasting chat server for CanFestival *\n" + "* for use with can_tcp_win32 CAN driver DLL *\n" + "************************************************\n" + "\n" + "Accepts connections on port 11898\n" + "and repeat '\\n' terminated lines \n" + "to each connected client\n" + "\n" + "Use netcat to monitor trafic\n" + " nc 127.0.0.1 11898\n" + "\n"); + + SocketServer in(11898,5); + + while (1) { + Socket* s=in.Accept(); + + unsigned ret; + _beginthreadex(0,0,Connection,(void*) s,0,&ret); + } + + return 0; +}