source: trunk/MagicSoft/Control/SubsystemIO/TCPListener.select.cxx@ 9194

Last change on this file since 9194 was 1054, checked in by casaldaliga, 23 years ago
changed .H to .hxx in includes to work with new naming
File size: 6.7 KB
Line 
1/* Copyright (C) 2001 Marc Casaldaliga Albisu <casaldaliga@ifae.es>
2================================================================
3
4 This code is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This code is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Emacs (which is required to make this stuff work); if
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.
18==================================================================
19*/
20
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include "socket_functions.h"
25#include "TCPListener.hxx"
26#include <string>
27//for signals/slots (Callbacks in C++, see http://libsigc.sourceforge.net/
28#include <sigc++/signal_system.h>
29using namespace SigC;
30//for perror
31#include <stdio.h>
32//for close
33#include <unistd.h>
34
35
36TCPListener::TCPListener (int port_)
37 :port(port_),newReceived(false),comMode(false)//,destroy(false)
38{
39 socketItself=make_socket(port);
40 //specify that socketItself it's willing to listen only at one client at a time
41
42 if( listen(socketItself,1)<0){
43 perror("in listen");
44 }
45 pthread_create(&thread,NULL,&TCPListener::Listening,this);
46 pthread_mutex_init(&mutex,NULL);
47}
48void * TCPListener::Listening( void* arg)
49{
50 TCPListener* self=(TCPListener *) arg;
51#ifdef DEBUG
52 printf("TCPListener: Created Listening thread\n");
53
54#endif
55 fd_set active_fd_set, read_fd_set;
56 int i;
57 size_t size;
58
59
60 /* Initialize the set of active sockets. */
61 FD_ZERO (&active_fd_set);
62 FD_SET (self->socketItself, &active_fd_set);
63
64 while (1)
65 {
66// pthread_mutex_lock(&(self->mutex));
67// if(self->destroy) break;
68// pthread_mutex_unlock(&(self->mutex));
69
70 /* Block until input arrives on one or more active sockets. */
71 read_fd_set = active_fd_set;
72 if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)
73 {
74 perror("TCPListener: select");
75 exit (EXIT_FAILURE);
76 }
77
78 /* Service all the sockets with input pending. */
79 for (i = 0; i < FD_SETSIZE; ++i) {
80
81 if (FD_ISSET (i, &read_fd_set))
82 {
83 if (i == self->socketItself)
84 {
85 /* Connection request on original socket. */
86#ifdef DEBUG
87 printf("TCPListener: Accepting connections\n");
88#endif
89 self->Accept();
90 //monitor the created channel
91 FD_SET (self->channel, &active_fd_set);
92 //but since we don't more than two clients, don't monitor incoming_connections_fd
93 FD_CLR (self->socketItself, &active_fd_set);
94 }
95 else
96 {
97
98 /* Data arriving on an already-connected socket. */
99#ifdef DEBUG
100 printf("TCPListener: Received\n");
101#endif
102
103
104 self->Receive();
105 if(!self->comMode){ //if connection has been closed to client (after the Receive), until new connection is open don't monitor this
106 FD_CLR (self->channel, &active_fd_set);
107//monitor incoming_connections_fd back again
108 FD_SET (self->socketItself, &active_fd_set);
109 }
110
111 }
112 }
113 }
114
115 }
116#ifdef DEBUG
117 printf("TCPListener: Listening thread finishing\n");
118
119#endif
120
121}
122
123
124TCPListener::~TCPListener() {
125 if(comMode){
126#ifdef DEBUG
127 printf("TCPListener: deleting\n");
128#endif
129 this->ClosingChannel();
130 }
131// pthread_mutex_lock(&mutex);
132// destroy=true;
133// pthread_mutex_unlock(&mutex);
134// pthread_join(thread,NULL);
135 pthread_cancel(thread);
136
137 close(socketItself);
138
139}
140
141void TCPListener::Accept () {
142 size_t size=sizeof(socketAddr);
143 channel=accept(socketItself, (struct sockaddr *) &socketAddr, &size);
144 if(channel<0){
145 perror("in Accept");
146// exit (EXIT_FAILURE);
147 }else{
148 clientAddress=inet_ntoa(socketAddr.sin_addr);
149 clientPort=ntohs(socketAddr.sin_port);
150#ifdef DEBUG
151 fprintf(stderr, "TCPListener: client contacted from %s:%hd\n", clientAddress, clientPort);
152#endif
153// fconfigure $channel -buffering line
154 comMode=true;
155
156 }
157}
158
159
160//this next method is only internally called when something arrives at channel (be careful, it can be the connection has closed)
161
162void TCPListener::Receive () { //Syncronous receive. If you are not sure there will be data to read, schedule this receive with IONotifier or something. Otherwise it will block
163#ifdef DEBUG
164 printf("TCPListener: Receive from TCPListener %d\n", this);
165#endif
166 int nbytes;
167 nbytes = read (channel, receivedStream, MAXMSG);
168 if (nbytes < 0){
169 /* Read error. */
170 perror("TCPListener: read");
171 exit (EXIT_FAILURE);
172 }else if (nbytes == 0){
173
174 /* End-of-file. */
175 receivedStream[0]='0';
176 receivedStream[1]='\0';
177 this->ClosingChannel();
178 }else{
179 /* Data read. */
180 //look for '\n' and chomp, in anycase read doesn't supply the \n so add it
181 if(receivedStream[nbytes-1]=='\n'){
182 receivedStream[nbytes-1]='\0';
183#ifdef DEBUG
184 printf("TCPListener: chomp\n");
185#endif
186 }else{
187 receivedStream[nbytes]='\0';
188 }
189#ifdef DEBUG
190 printf("TCPListener: got message: `%s'\n", receivedStream);
191#endif
192 this->process();
193 newReceived=true;
194 }
195}
196
197void TCPListener::ClosingChannel(){
198#ifdef DEBUG
199 printf("TCPListener: closing socket to client from %d:%d\n",clientAddress,clientPort);
200#endif
201
202 close(channel);
203 comMode=false;
204
205}
206//this public method should be capitalized for some consistency. Put the change should be propagated. class Make up!
207void TCPListener::process (){
208//to be overriden
209#ifdef DEBUG
210 printf("TCPListener: message Received [%s] and processed from client %s:%d \n",receivedStream,clientAddress,clientPort);
211#endif
212
213}
214
215string TCPListener::ReturnNew () {
216 if (newReceived) {
217 newReceived=false;
218 return string(receivedStream);
219 }else{
220 return string("0");
221 }
222}
223
224
Note: See TracBrowser for help on using the repository browser.