3 /* tcp trp (transport) - send/receive a bunch of bytes from a tcp socket */
5 /* Copyright (c) 2004 Martin Quinson. All rights reserved. */
7 /* This program is free software; you can redistribute it and/or modify it
8 * under the terms of the license (GNU LGPL) which comes with this package. */
13 # include <signal.h> /* close() pipe() read() write() */
14 # include <sys/wait.h> /* waitpid() */
18 #include "transport_private.h"
20 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(trp_tcp,transport,"TCP transport");
25 void gras_trp_tcp_socket_client(gras_trp_plugin_t self, gras_socket_t sock);
26 void gras_trp_tcp_socket_server(gras_trp_plugin_t self, gras_socket_t sock);
27 gras_socket_t gras_trp_tcp_socket_accept(gras_socket_t sock);
29 void gras_trp_tcp_socket_close(gras_socket_t sd);
31 void gras_trp_tcp_chunk_send(gras_socket_t sd,
33 unsigned long int size);
35 void gras_trp_tcp_chunk_recv(gras_socket_t sd,
37 unsigned long int size);
39 void gras_trp_tcp_exit(gras_trp_plugin_t plug);
42 static int TcpProtoNumber(void);
44 *** Specific plugin part
50 } gras_trp_tcp_plug_data_t;
53 *** Specific socket part
58 } gras_trp_tcp_sock_data_t;
64 void gras_trp_tcp_setup(gras_trp_plugin_t plug) {
66 gras_trp_tcp_plug_data_t *data = xbt_new(gras_trp_tcp_plug_data_t,1);
68 FD_ZERO(&(data->msg_socks));
69 FD_ZERO(&(data->meas_socks));
71 plug->socket_client = gras_trp_tcp_socket_client;
72 plug->socket_server = gras_trp_tcp_socket_server;
73 plug->socket_accept = gras_trp_tcp_socket_accept;
74 plug->socket_close = gras_trp_tcp_socket_close;
76 plug->chunk_send = gras_trp_tcp_chunk_send;
77 plug->chunk_recv = gras_trp_tcp_chunk_recv;
79 plug->flush = NULL; /* nothing's cached */
81 plug->data = (void*)data;
82 plug->exit = gras_trp_tcp_exit;
85 void gras_trp_tcp_exit(gras_trp_plugin_t plug) {
86 DEBUG1("Exit plugin TCP (free %p)", plug->data);
90 void gras_trp_tcp_socket_client(gras_trp_plugin_t self, gras_socket_t sock){
92 struct sockaddr_in addr;
94 struct in_addr *haddr;
95 int size = sock->bufSize * 1024;
97 sock->incoming = 1; /* TCP sockets are duplex'ed */
99 sock->sd = socket (AF_INET, SOCK_STREAM, 0);
102 THROW1(system_error,0, "Failed to create socket: %s", sock_errstr);
105 if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) ||
106 setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) {
107 WARN1("setsockopt failed, cannot set buffer size: %s",sock_errstr);
110 he = gethostbyname (sock->peer_name);
112 THROW2(system_error,0, "Failed to lookup hostname %s: %s",
113 sock->peer_name, sock_errstr);
116 haddr = ((struct in_addr *) (he->h_addr_list)[0]);
118 memset(&addr, 0, sizeof(struct sockaddr_in));
119 memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
120 addr.sin_family = AF_INET;
121 addr.sin_port = htons (sock->peer_port);
123 if (connect (sock->sd, (struct sockaddr*) &addr, sizeof (addr)) < 0) {
125 THROW3(system_error,0,
126 "Failed to connect socket to %s:%d (%s)",
127 sock->peer_name, sock->peer_port, sock_errstr);
129 VERB4("Connect to %s:%d (sd=%d, port %d here)",sock->peer_name, sock->peer_port, sock->sd, sock->port);
133 * gras_trp_tcp_socket_server:
135 * Open a socket used to receive messages.
137 void gras_trp_tcp_socket_server(gras_trp_plugin_t self, gras_socket_t sock){
138 int size = sock->bufSize * 1024;
140 struct sockaddr_in server;
142 gras_trp_tcp_plug_data_t *tcp=(gras_trp_tcp_plug_data_t*)self->data;
144 sock->outgoing = 1; /* TCP => duplex mode */
146 server.sin_port = htons((u_short)sock->port);
147 server.sin_addr.s_addr = INADDR_ANY;
148 server.sin_family = AF_INET;
149 if((sock->sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
150 THROW1(system_error,0,"Socket allocation failed: %s", sock_errstr);
152 if (setsockopt(sock->sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)))
153 THROW1(system_error,0,"setsockopt failed, cannot condition the socket: %s",
156 if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) ||
157 setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) {
158 WARN1("setsockopt failed, cannot set buffer size: %s",
162 if (bind(sock->sd, (struct sockaddr *)&server, sizeof(server)) == -1) {
164 THROW2(system_error,0,"Cannot bind to port %d: %s",sock->port, sock_errstr);
167 DEBUG2("Listen on port %d (sd=%d)",sock->port, sock->sd);
168 if (listen(sock->sd, 5) < 0) {
170 THROW2(system_error,0,"Cannot listen on port %d: %s",sock->port,sock_errstr);
174 FD_SET(sock->sd, &(tcp->meas_socks));
176 FD_SET(sock->sd, &(tcp->msg_socks));
178 VERB2("Openned a server socket on port %d (sd=%d)",sock->port,sock->sd);
181 gras_socket_t gras_trp_tcp_socket_accept(gras_socket_t sock) {
184 struct sockaddr_in peer_in;
185 socklen_t peer_in_len = sizeof(peer_in);
192 socklen_t s = sizeof(int);
195 gras_trp_socket_new(1,&res);
197 sd = accept(sock->sd, (struct sockaddr *)&peer_in, &peer_in_len);
201 gras_socket_close(sock);
202 THROW1(system_error,0,
203 "Accept failed (%s). Droping server socket.", sock_errstr);
206 if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, s)
207 || setsockopt(sd, TcpProtoNumber(), TCP_NODELAY, (char *)&i, s))
208 THROW1(system_error,0,"setsockopt failed, cannot condition the socket: %s",
211 res->bufSize = sock->bufSize;
212 size = sock->bufSize * 1024;
213 if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size))
214 || setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)))
215 WARN1("setsockopt failed, cannot set buffer size: %s", sock_errstr);
217 res->plugin = sock->plugin;
218 res->incoming = sock->incoming;
219 res->outgoing = sock->outgoing;
223 res->peer_port = peer_in.sin_port;
225 /* FIXME: Lock to protect inet_ntoa */
226 if (((struct sockaddr *)&peer_in)->sa_family != AF_INET) {
227 res->peer_name = (char*)strdup("unknown");
229 struct in_addr addrAsInAddr;
232 addrAsInAddr.s_addr = peer_in.sin_addr.s_addr;
234 tmp = inet_ntoa(addrAsInAddr);
236 res->peer_name = (char*)strdup(tmp);
238 res->peer_name = (char*)strdup("unknown");
242 VERB3("Accepted from %s:%d (sd=%d)", res->peer_name,res->peer_port,sd);
248 void gras_trp_tcp_socket_close(gras_socket_t sock){
249 gras_trp_tcp_plug_data_t *tcp;
251 if (!sock) return; /* close only once */
252 tcp=sock->plugin->data;
254 VERB1("close tcp connection %d", sock->sd);
256 /* FIXME: no pipe in GRAS so far
257 if(!FD_ISSET(sd, &connectedPipes)) {
258 if(shutdown(sd, 2) < 0) {
261 ReleaseNWSLock(&lock);
263 / * The other side may have beaten us to the reset. * /
264 if ((tmp_errno!=ENOTCONN) && (tmp_errno!=ECONNRESET)) {
265 WARN1("CloseSocket: shutdown error %d\n", tmp_errno);
270 #ifndef HAVE_WINSOCK_H
271 /* forget about the socket
272 ... but not when using winsock since accept'ed socket can not fit
275 FD_CLR(sock->sd, &(tcp->meas_socks));
277 FD_CLR(sock->sd, &(tcp->msg_socks));
281 /* close the socket */
282 if(tcp_close(sock->sd) < 0) {
283 WARN3("error while closing tcp socket %d: %d (%s)\n",
284 sock->sd, sock_errno, sock_errstr);
290 * gras_trp_tcp_chunk_send:
292 * Send data on a TCP socket
295 gras_trp_tcp_chunk_send(gras_socket_t sock,
297 unsigned long int size) {
299 /* TCP sockets are in duplex mode, don't check direction */
300 xbt_assert0(size >= 0, "Cannot send a negative amount of data");
305 status = tcp_write(sock->sd, data, (size_t)size);
306 DEBUG3("write(%d, %p, %ld);", sock->sd, data, size);
309 THROW4(system_error,0,"write(%d,%p,%ld) failed: %s",
310 sock->sd, data, size,
318 THROW1(system_error,0,"file descriptor closed (%s)",
324 * gras_trp_tcp_chunk_recv:
326 * Receive data on a TCP socket.
329 gras_trp_tcp_chunk_recv(gras_socket_t sock,
331 unsigned long int size) {
333 /* TCP sockets are in duplex mode, don't check direction */
334 xbt_assert0(sock, "Cannot recv on an NULL socket");
335 xbt_assert0(size >= 0, "Cannot receive a negative amount of data");
340 DEBUG3("read(%d, %p, %ld);", sock->sd, data, size);
341 status = tcp_read(sock->sd, data, (size_t)size);
344 THROW4(system_error,0,"read(%d,%p,%d) failed: %s",
345 sock->sd, data, (int)size,
353 THROW3(system_error,0,
354 "file descriptor closed (nothing read(%d, %p, %ld) on the socket)",
355 sock->sd, data, size);
362 * Returns the tcp protocol number from the network protocol data base.
364 * getprotobyname() is not thread safe. We need to lock it.
366 static int TcpProtoNumber(void) {
367 struct protoent *fetchedEntry;
368 static int returnValue = 0;
370 if(returnValue == 0) {
371 fetchedEntry = getprotobyname("tcp");
372 xbt_assert0(fetchedEntry, "getprotobyname(tcp) gave NULL");
373 returnValue = fetchedEntry->p_proto;
379 #ifdef HAVE_WINSOCK_H
380 #define RETSTR( x ) case x: return #x
382 const char *gras_wsa_err2string( int err ) {
390 RETSTR( WSAEWOULDBLOCK );
391 RETSTR( WSAEINPROGRESS );
392 RETSTR( WSAEALREADY );
393 RETSTR( WSAENOTSOCK );
394 RETSTR( WSAEDESTADDRREQ );
395 RETSTR( WSAEMSGSIZE );
396 RETSTR( WSAEPROTOTYPE );
397 RETSTR( WSAENOPROTOOPT );
398 RETSTR( WSAEPROTONOSUPPORT );
399 RETSTR( WSAESOCKTNOSUPPORT );
400 RETSTR( WSAEOPNOTSUPP );
401 RETSTR( WSAEPFNOSUPPORT );
402 RETSTR( WSAEAFNOSUPPORT );
403 RETSTR( WSAEADDRINUSE );
404 RETSTR( WSAEADDRNOTAVAIL );
405 RETSTR( WSAENETDOWN );
406 RETSTR( WSAENETUNREACH );
407 RETSTR( WSAENETRESET );
408 RETSTR( WSAECONNABORTED );
409 RETSTR( WSAECONNRESET );
410 RETSTR( WSAENOBUFS );
411 RETSTR( WSAEISCONN );
412 RETSTR( WSAENOTCONN );
413 RETSTR( WSAESHUTDOWN );
414 RETSTR( WSAETOOMANYREFS );
415 RETSTR( WSAETIMEDOUT );
416 RETSTR( WSAECONNREFUSED );
418 RETSTR( WSAENAMETOOLONG );
419 RETSTR( WSAEHOSTDOWN );
420 RETSTR( WSAEHOSTUNREACH );
421 RETSTR( WSAENOTEMPTY );
422 RETSTR( WSAEPROCLIM );
426 RETSTR( WSAEREMOTE );
427 RETSTR( WSASYSNOTREADY );
428 RETSTR( WSAVERNOTSUPPORTED );
429 RETSTR( WSANOTINITIALISED );
430 RETSTR( WSAEDISCON );
433 RETSTR( WSAENOMORE );
434 RETSTR( WSAECANCELLED );
435 RETSTR( WSAEINVALIDPROCTABLE );
436 RETSTR( WSAEINVALIDPROVIDER );
437 RETSTR( WSASYSCALLFAILURE );
438 RETSTR( WSASERVICE_NOT_FOUND );
439 RETSTR( WSATYPE_NOT_FOUND );
440 RETSTR( WSA_E_NO_MORE );
441 RETSTR( WSA_E_CANCELLED );
442 RETSTR( WSAEREFUSED );
443 #endif /* HAVE_WINSOCK2 */
445 RETSTR( WSAHOST_NOT_FOUND );
446 RETSTR( WSATRY_AGAIN );
447 RETSTR( WSANO_RECOVERY );
448 RETSTR( WSANO_DATA );
450 return "unknown WSA error";
452 #endif /* HAVE_WINSOCK_H */