00001
00024 #include <cstdlib>
00025 #include "libport/cstdio"
00026 #include <cerrno>
00027
00028 #include <locale.h>
00029 #include "urbi/uclient.hh"
00030 #include "libport/lockable.hh"
00031 #include "libport/thread.hh"
00032
00033
00034
00035
00036
00037 #ifdef WIN32
00038
00039 # define LIBPORT_FD_SET(N, P) FD_SET(static_cast<u_int>(N), P)
00040 #else
00041 # define LIBPORT_FD_SET(N, P) FD_SET(N, P)
00042 #endif
00043
00044 #ifdef WIN32
00045 # include "libport/windows.hh"
00046 # include <fcntl.h>
00047 # include <io.h>
00048 # include <winsock.h>
00049 #else
00050 # include <sys/time.h>
00051 # include <sys/socket.h>
00052 # include <netinet/in.h>
00053 # include <arpa/inet.h>
00054 # include <netdb.h>
00055 # include <unistd.h>
00056 #endif
00057
00058 namespace urbi
00059 {
00064 UClient::UClient(const char *_host, int _port, int _buflen)
00065 : UAbstractClient(_host, _port, _buflen)
00066 {
00067 setlocale(LC_NUMERIC, "C");
00068 control_fd[0] = control_fd[1] = -1;
00069
00070 #ifndef WIN32
00071 if (::pipe(control_fd) == -1)
00072 {
00073 rc = -1;
00074 perror("UClient::UClient failed to create pipe");
00075 return;
00076 }
00077 #endif
00078
00079
00080 struct hostent *hen;
00081 struct sockaddr_in sa;
00082
00083 memset(&sa, 0, sizeof (sa));
00084 #ifdef WIN32
00085 WSADATA wsaData;
00086 WORD wVersionRequested;
00087 wVersionRequested = MAKEWORD( 1, 1 );
00088 WSAStartup( wVersionRequested, &wsaData );
00089 #endif
00090 sa.sin_family = AF_INET;
00091 sa.sin_port = htons(port);
00092
00093 hen = gethostbyname(host);
00094
00095 if (!hen)
00096 {
00097
00098 sa.sin_addr.s_addr = inet_addr(host);
00099 if (sa.sin_addr.s_addr == INADDR_NONE)
00100 {
00101 printf("UClient::UClient cannot resolve host name.\n");
00102 rc = -1;
00103 return;
00104 }
00105 }
00106 else
00107 memcpy(&sa.sin_addr.s_addr, hen->h_addr_list[0], hen->h_length);
00108
00109 sd = socket(AF_INET, SOCK_STREAM, 0);
00110 if (sd < 0)
00111 {
00112 printf("UClient::UClient socket allocation failed.\n");
00113 rc = -1;
00114 return;
00115 }
00116
00117
00118 rc = connect(sd, (struct sockaddr *) &sa, sizeof (sa));
00119
00120
00121 if (rc)
00122 {
00123 usleep(20000);
00124 rc = connect(sd, (struct sockaddr *) &sa, sizeof (sa));
00125 }
00126
00127
00128 if (rc)
00129 {
00130 std::cerr << "UClient::UClient cannot connect." << std::endl;
00131 return;
00132 }
00133
00134
00135 int pos=0;
00136 while (pos==0)
00137 pos = ::recv(sd, recvBuffer, buflen, 0);
00138 if (pos<0)
00139 {
00140 rc = pos;
00141 printf("UClient::UClient cannot connect: read error %d.\n", rc);
00142 return;
00143 }
00144 else
00145 recvBufferPosition = pos;
00146 recvBuffer[recvBufferPosition] = 0;
00147 thread = libport::startThread(this, &UClient::listenThread);
00148 if (!defaultClient)
00149 defaultClient = this;
00150 }
00151
00152 UClient::~UClient()
00153 {
00154 close(sd);
00155 sd = -1;
00156 if (control_fd[1] != -1 )
00157 ::write(control_fd[1], "a", 1);
00158
00159 libport::joinThread(thread);
00160 if (control_fd[1] != -1)
00161 close(control_fd[1]);
00162 if (control_fd[0] != -1)
00163 close(control_fd[0]);
00164 }
00165
00166
00167 bool
00168 UClient::canSend(int)
00169 {
00170 return true;
00171 }
00172
00173
00174 int
00175 UClient::effectiveSend(const void * buffer, int size)
00176 {
00177 #if DEBUG
00178 char output[size+1];
00179 memcpy (static_cast<void*> (output), buffer, size);
00180 output[size]=0;
00181 cout << ">>>> SENT : [" << output << "]" << endl;
00182 #endif
00183 if (rc)
00184 return -1;
00185 int pos = 0;
00186 while (pos!=size)
00187 {
00188 int retval = ::send(sd, (char *) buffer + pos, size-pos, 0);
00189 if (retval<0)
00190 {
00191 rc = retval;
00192 return rc;
00193 }
00194 pos += retval;
00195 }
00196 return 0;
00197 }
00198
00199 void
00200 UClient::listenThread()
00201 {
00202 fd_set rfds;
00203 int maxfd=1+ (sd>control_fd[0]? sd:control_fd[0]);
00204 int res;
00205 while (true)
00206 {
00207 do {
00208 if (sd==-1)
00209 return;
00210 FD_ZERO(&rfds);
00211 LIBPORT_FD_SET(sd, &rfds);
00212 #ifndef WIN32
00213 LIBPORT_FD_SET(control_fd[0], &rfds);
00214 #endif
00215 struct timeval tme;
00216 tme.tv_sec = 1;
00217 tme.tv_usec = 0;
00218 res = select(maxfd+1, &rfds, NULL, NULL, &tme);
00219 if (res < 0 && errno != EINTR)
00220 {
00221 this->rc = -1;
00222 #ifdef WIN32
00223 res = WSAGetLastError();
00224 #endif
00225 std::cerr << "select error "<<res<<std::endl;
00226
00227
00228 return;
00229 }
00230 if (res == -1)
00231 {
00232 res=0;
00233 continue;
00234 }
00235 #ifndef WIN32
00236 if (res != 0 && FD_ISSET(control_fd[0], &rfds))
00237 return;
00238 #endif
00239 } while (res == 0);
00240 int count = ::recv(sd,
00241 &recvBuffer[recvBufferPosition],
00242 buflen - recvBufferPosition - 1, 0);
00243 if (count < 0)
00244 {
00245 rc = -1;
00246 std::cerr << "error " << count << std::endl;
00247
00248
00249 return;
00250 }
00251
00252 recvBufferPosition += count;
00253 recvBuffer[recvBufferPosition] = 0;
00254 processRecvBuffer();
00255 }
00256 }
00257
00258
00259 void
00260 UClient::printf(const char * format, ...)
00261 {
00262 va_list arg;
00263 va_start(arg, format);
00264 vfprintf(stderr, format, arg);
00265 va_end(arg);
00266 }
00267
00268 unsigned int UClient::getCurrentTime() const
00269 {
00270
00271 #ifdef WIN32
00272 return GetTickCount();
00273 #else
00274 struct timeval tv;
00275 gettimeofday(&tv, NULL);
00276 return tv.tv_sec*1000+tv.tv_usec/1000;
00277 #endif
00278 }
00279
00280 void execute(void)
00281 {
00282 #ifdef WIN32
00283 while (true)
00284 Sleep(100000);
00285 #else
00286 while (true)
00287 sleep(100);
00288 #endif
00289 }
00290
00291 void exit(int code)
00292 {
00293 ::exit(code);
00294 }
00295
00296
00297 UClient & connect(const char* host)
00298 {
00299 return *new UClient(host);
00300 }
00301
00302 }