Beispiel #1
0
static int timeout_connect( int fd, const struct sockaddr *serv_addr,
	socklen_t addrlen )
{
	if( socket_connect( fd, serv_addr, addrlen) < 0 ) {
		if( errno != EINPROGRESS ) {
			return -1;
		}
	}
	if( wait_socket( fd, WAIT_WRITE  ) <= 0 ) {
		if( errno == 0 ) {
			errno = ETIMEDOUT;
		}
		return -1;
	}

	/* Completed or failed */
	int optval = 0;
	socklen_t optlen = sizeof(optval);
	/* casting  &optval to char* is required for win32 */
	if( getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&optval, &optlen) == -1 ) {
		return -1;
	}
	if (optval != 0) {
		errno = optval;
		return -1;
	}
	return 0;
}
Beispiel #2
0
static int
send_header(tcp_con_t *con,const char *response){
  int rc;
  size_t soc_remains;
  ssize_t send_len;
  char *wp;
  int buff_len;
  const char *peer_addr=NULL;
  struct sigaction saved_act;
  gchar *send_buffer = NULL;

  if ( (!con) || (!response) )
    return -EINVAL;

  peer_addr = tcp_get_peeraddr(con);

  rc = ipmsg_convert_string_external(peer_addr, response, (const char **)&send_buffer); 
  if (rc != 0) {
    ipmsg_err_dialog("%s\n", 
		     _("Can not convert header into external representation"));
    goto no_free_out;
  }

  soc_remains = strlen(send_buffer);
  if (wait_socket(con->soc, WAIT_FOR_WRITE, TCP_SELECT_SEC) < 0) {
    err_out("Can not send socket\n");
    goto error_out;
  }

  wp=(char *)send_buffer;
  dbg_out("Send:%s(%d, %x)\n",wp,soc_remains,soc_remains);
  while(soc_remains>0) {
    disable_pipe_signal(&saved_act);
    send_len=send(con->soc,wp,soc_remains,0);
    enable_pipe_signal(&saved_act);
    if (send_len<0) {
      if (errno == EINTR)
	continue;
      rc=-errno;
      err_out("Error:%s (%d)\n",strerror(errno),errno);
      goto error_out;
    }
    wp += send_len;
    soc_remains -= send_len;
    dbg_out("soc remains:%d\n",soc_remains);
  }

  rc=0;

 error_out:
  if (send_buffer != NULL)
    g_free(send_buffer);

 no_free_out:
  return rc; 
}
Beispiel #3
0
static int
tcp_ipmsg_finalize_connection(tcp_con_t *con){
  int rc=0;
  char dummy[1];

  g_assert(con);
  sock_set_buffer(con->soc, _TCP_BUF_MIN_SIZE, _TCP_BUF_SIZE);
  dbg_out("Wait for closing by peer.\n");
  sock_set_recv_timeout(con->soc,TCP_CLOSE_WAIT_SEC);
  rc=wait_socket(con->soc,WAIT_FOR_READ,TCP_SELECT_SEC);
  if (rc<0) {
    dbg_out("OK timeout select :%s(%d)\n",strerror(errno),errno);
    return -errno;
  }
  memset(dummy, 0, sizeof(dummy));
  rc=recv(con->soc, dummy,sizeof(dummy),0); /* 相手のクローズ検出 */

  if (rc<0)
    dbg_out("OK timeout:%s(%d)\n",strerror(errno),errno);
  else
    rc=0;

  return rc;
}
Beispiel #4
0
gpointer
ipmsg_tcp_recv_thread(gpointer data){
  ssize_t recv_len;
  size_t addr_len;
  int rc;
  tcp_con_t *con;
  char *recv_buf=NULL;
  int count=200;
  struct addrinfo *info;

  con=(tcp_con_t *)data;
  if (!con) {
    err_out("No connection recived\n");
    g_assert(con);
    return NULL;
  }
  if (!(con->peer_info)) {
    err_out("Invalid connection recived\n");
    g_assert(con->peer_info);
    return NULL;
  }
  
  rc=tcp_enable_keepalive(con);
  if (rc<0)
    return NULL;

  recv_buf=g_malloc(_MSG_BUF_SIZE);
  if (!recv_buf)
    return NULL;

  memset(recv_buf,0,_MSG_BUF_SIZE);

  while(1) {
    if (wait_socket(con->soc,WAIT_FOR_READ,TCP_SELECT_SEC)<0) {
      err_out("Can not send socket\n");
      destroy_tcp_connection(con);
      goto error_out;
    }else{
    read_retry:
      errno=0;
      memset(recv_buf, 0, sizeof(recv_buf));
      info=con->peer_info;
      recv_len=recv(con->soc,
		    recv_buf,
		    _MSG_BUF_SIZE,
		    MSG_PEEK);

      if (recv_len<=0) {
	if (errno==EINTR)
	  goto read_retry;
	if (errno)
	  err_out("Can not peek message %s(errno:%d)\n",strerror(errno),errno);
	destroy_tcp_connection(con);
	goto error_out;
      }

      dbg_out("tcp peek read:%d %s\n",recv_len,recv_buf);

      recv_len=recv(con->soc,
		    recv_buf,
		    recv_len,
		    MSG_PEEK);

      dbg_out("tcp read:%d %s\n",recv_len,recv_buf);
      if (recv_len>0) {
	msg_data_t msg;
	request_msg_t req;
	char *path;
	off_t size;
	unsigned long ipmsg_fattr;

	recv_buf[recv_len-1]='\0';
	memset(&req,0,sizeof(request_msg_t));

	init_message_data(&msg);
	parse_message(NULL,&msg,recv_buf,recv_len);
	parse_request(&req,msg.message);
	rc=refer_attach_file(req.pkt_no,req.fileid,&ipmsg_fattr,(const char **)&path,&size);
	if (rc<0) {
	  err_out("Can not find message:pktno %ld id : %d\n",
		  req.pkt_no,
		  req.fileid);
	  close(con->soc); /* エラーとしてクローズする  */
	}else{
	  dbg_out("transfer:%s (%d)\n",path,size);
	  switch(ipmsg_fattr) 
	    {
	    case IPMSG_FILE_REGULAR:
	      if (!tcp_transfer_file(con,path,size,0)) {
		tcp_ipmsg_finalize_connection(con);
		download_monitor_release_file(req.pkt_no,req.fileid);
	      }
	      break;
	    case IPMSG_FILE_DIR:
	      if (!tcp_transfer_dir(con,path)){
		download_monitor_release_file(req.pkt_no,req.fileid);
		tcp_ipmsg_finalize_connection(con);
	      }
	      break;
	    default:
	      break;
	    }
	  release_message_data(&msg);
	  g_free(path);
	  break;
	}
	release_message_data(&msg);
	break;
      }
    }
    --count;
    if (!count)
      break;
  }
  if (con->peer_info) /* closeは相手側で行うので, destroy_tcp_connectionは呼び出せない
		  * (Win版ipmsgの仕様).  
		  */
    freeaddrinfo(con->peer_info); 
 error_out:
  g_free(con);
  if (recv_buf)
    g_free(recv_buf);

  return NULL;
}
Beispiel #5
0
static int
tcp_transfer_file(tcp_con_t *con,const char *path,const off_t size, off_t offset){
  int fd;
  int rc;
  char *buff = NULL;
  off_t read_len;
  off_t file_remains;
  off_t soc_remains;
  off_t write_len;
  off_t total_write;
  char *wp;
  struct sigaction saved_act;

  if ( (!con) || (!path) )
    return -EINVAL;

  buff = g_malloc(TCP_FILE_BUFSIZ);
  if (buff == NULL)
    return -ENOMEM;

  fd=open(path,O_RDONLY);
  if (fd<0)
    return -errno;

  rc=lseek(fd, offset, SEEK_SET);
  if (rc<0) {
    rc=-errno;
    goto close_out;
  }
  total_write=0;
  file_remains=size;

  while(file_remains>0) {
    read_len=read(fd,buff,TCP_FILE_BUFSIZ);
    if (read_len<0) {
      rc=-errno;
      err_out("Can not read file %s %d\n",strerror(errno),errno);
      goto close_out;
    }
    file_remains -= read_len;
    soc_remains = read_len;
    wp = buff;

    if (wait_socket(con->soc,WAIT_FOR_WRITE,TCP_SELECT_SEC)<0) {
      err_out("Can not send socket\n");
      goto close_out;
    }

    dbg_out("sock remains:%d\n",soc_remains);
    disable_pipe_signal(&saved_act);
    while(soc_remains > 0) {
      write_len = write(con->soc, wp, soc_remains);
      if (write_len<0) {
	if (errno==EINTR)
	  continue;
	err_out("Can not send %s %d\n",strerror(errno),errno);
	enable_pipe_signal(&saved_act);
	goto close_out;
      }
      dbg_out("write len :%d\n",write_len);
      wp += write_len;
      total_write += write_len;
      soc_remains -= write_len;
    }
    enable_pipe_signal(&saved_act);
    dbg_out("transfer %s %d/%d(%d)\n",path,total_write,size,file_remains);
  }
  rc=0;
 close_out:
  close(fd);
  if (rc<0)
    dbg_out("Can not send file:%s %s %d\n",path,strerror(errno),errno);
  if (buff != NULL)
    g_free(buff);
  return rc;
}
Beispiel #6
0
/**
 * Same as eConnect() except you may the specify address family here (default is
 * AF_UNSPEC).
 * We couldn't just add the new family arg to eConnect because the original one
 * is pure virtual declared in EClientSocketBase. Thanks C++ design crap ...
 */
bool EPosixClientSocket::eConnect2( const char *host, unsigned int port,
	int clientId, int family )
{
	// already connected?
	if( m_fd >= 0) {
		assert(false); // for now we don't allow that
		return true;
	}

	// initialize Winsock DLL (only for Windows)
	if ( !SocketsInit())	{
		// Does this set errno?
		getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(),
			"Initializing Winsock DLL failed.");
		return false;
	}

	// use local machine if no host passed in
	if ( !( host && *host)) {
		host = "127.0.0.1";
	}

	// starting to connect to server
	struct addrinfo *aitop;

	int s = resolveHost( host, port, family, &aitop );
	if( s != 0 ) {
		SocketsDestroy();
		const char *err;
#ifdef HAVE_GETADDRINFO
		err = gai_strerror(s);
#else
		err = "Invalid address, hostname resolving not supported.";
#endif
		getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err );
		return false;
	}

	int con_errno = 0;
	for( struct addrinfo *ai = aitop; ai != NULL; ai = ai->ai_next ) {

		// create socket
		m_fd = socket(ai->ai_family, ai->ai_socktype, 0);
		if( m_fd < 0) {
			con_errno = errno;
			continue;
		}

		/* Set socket O_NONBLOCK. If wanted we could handle errors
		   (portability!) We could even make O_NONBLOCK optional. */
		int sn = set_socket_nonblock( m_fd );
		assert( sn == 0 );

		// try to connect
		if( timeout_connect( m_fd, ai->ai_addr, ai->ai_addrlen ) < 0 ) {
			con_errno = errno;
			SocketClose(m_fd);
			m_fd = -1;
			continue;
		}
		/* successfully  connected */
		break;
	}

	freeaddrinfo(aitop);

	/* connection failed, tell the error which happened in our last try  */
	if( m_fd < 0 ) {
		const char *err = strerror(con_errno);
		SocketsDestroy();
		getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err );
		return false;
	}

	// set client id
	setClientId( clientId);

	errno = 0;
	onConnectBase();
	if( !isOutBufferEmpty() ) {
		/* For now we consider it as error if it's not possible to send an
		   integer string within a single tcp packet. Here we don't know weather
		   ::send() really failed or not. If so then we hopefully still have
		   it's errno set.*/
		const char *err = (errno != 0) ? strerror(errno)
			: "Sending client id failed.";
		eDisconnect();
		getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err );
		return false;
	}

	if( wait_socket( m_fd, WAIT_READ ) <= 0 ) {
		const char *err = (errno != 0) ? strerror(errno) : strerror(ENODATA);
		eDisconnect();
		getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err );
		return false;
	}

	while( !isConnected() ) {
		assert( isSocketOK() ); // need to be handled if send() would destroy it
		if ( !checkMessagesConnect()) {
			const char *err = (errno != 0) ? strerror(errno)
				: "The remote host closed the connection.";
			eDisconnect();
			getWrapper()->error( NO_VALID_ID, CONNECT_FAIL.code(), err );
			return false;
		}
	}
	// successfully connected
	return true;
}
Beispiel #7
0
int
as_tls_connect(as_socket* sock, uint64_t deadline)
{
	int rv;

#if defined(_MSC_VER)
	// Windows SSL_connect() will fail with SSL_ERROR_SYSCALL if non-blocking
	// socket has not completed TCP connect.  Wait on socket before calling
	// SSL_connect() when on Windows.
	rv = wait_socket(sock->fd, 0, deadline, false);
	if (rv != 0) {
		as_log_warn("wait_writable failed: %d", rv);
		return rv;
	}
#endif

	while (true) {
		rv = SSL_connect(sock->ssl);
		if (rv == 1) {
			log_session_info(sock);
			return 0;
		}

		int sslerr = SSL_get_error(sock->ssl, rv);
		unsigned long errcode;
		char errbuf[1024];
		switch (sslerr) {
		case SSL_ERROR_WANT_READ:
			rv = wait_socket(sock->fd, 0, deadline, true);
			if (rv != 0) {
				as_log_warn("wait_readable failed: %d", rv);
				return rv;
			}
			// loop back around and retry
			break;
		case SSL_ERROR_WANT_WRITE:
			rv = wait_socket(sock->fd, 0, deadline, false);
			if (rv != 0) {
				as_log_warn("wait_writable failed: %d", rv);
				return rv;
			}
			// loop back around and retry
			break;
		case SSL_ERROR_SSL:
			log_verify_details(sock);
			errcode = ERR_get_error();
			ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
			as_log_warn("SSL_connect failed: %s", errbuf);
			return -1;
		case SSL_ERROR_SYSCALL:
			errcode = ERR_get_error();
			if (errcode != 0) {
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				as_log_warn("SSL_connect I/O error: %s", errbuf);
			}
			else {
				if (rv == 0) {
					as_log_warn("SSL_connect I/O error: unexpected EOF");
				}
				else {
					as_log_warn("SSL_connect I/O error: %d", as_last_error());
				}
			}
			return -2;
		default:
			as_log_warn("SSL_connect: unexpected ssl error: %d", sslerr);
			return -3;
			break;
		}
	}
}
Beispiel #8
0
int
as_tls_write(as_socket* sock, void* bufp, size_t len, uint32_t socket_timeout, uint64_t deadline)
{
	uint8_t* buf = (uint8_t *) bufp;
	size_t pos = 0;

	while (true) {
		int rv = SSL_write(sock->ssl, buf + pos, (int)(len - pos));
		if (rv > 0) {
			pos += rv;
			if (pos >= len) {
				return 0;
			}
		}
		else /* if (rv <= 0) */ {
			int sslerr = SSL_get_error(sock->ssl, rv);
			unsigned long errcode;
			char errbuf[1024];
			switch (sslerr) {
			case SSL_ERROR_WANT_READ:
				rv = wait_socket(sock->fd, socket_timeout, deadline, true);
				if (rv != 0) {
					return rv;
				}
				// loop back around and retry
				break;
			case SSL_ERROR_WANT_WRITE:
				rv = wait_socket(sock->fd, socket_timeout, deadline, false);
				if (rv != 0) {
					return rv;
				}
				// loop back around and retry
				break;
			case SSL_ERROR_SSL:
				log_verify_details(sock);
				errcode = ERR_get_error();
				ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
				as_log_warn("SSL_write failed: %s", errbuf);
				return -1;
			case SSL_ERROR_SYSCALL:
				errcode = ERR_get_error();
				if (errcode != 0) {
					ERR_error_string_n(errcode, errbuf, sizeof(errbuf));
					as_log_warn("SSL_write I/O error: %s", errbuf);
				}
				else {
					if (rv == 0) {
						as_log_warn("SSL_write I/O error: unexpected EOF");
					}
					else {
						as_log_warn("SSL_write I/O error: %d", as_last_error());
					}
				}
				return -1;
			default:
				as_log_warn("SSL_write: unexpected ssl error: %d", sslerr);
				return -1;
				break;
			}
		}
	}
}
Beispiel #9
0
int
main(
	int argc,
	char ** argv
)
{
	/* getopt_long stores the option index here. */
	int option_index = 0;
	int port = 9999;
	const char * config_file = NULL;
	const char * startup_message = "";
	int timeout = 60;
	unsigned width = 512;
	unsigned height = 64;
	int no_init = 0;

	while (1)
	{
		const int c = getopt_long(
			argc,
			argv,
			"vp:c:t:W:H:m:n",
			long_options,
			&option_index
		);

		if (c == -1)
			break;
		switch (c)
		{
		case 'v':
			verbose++;
			break;
		case 'n':
			no_init++;
			break;
		case 'c':
			config_file = optarg;
			break;
		case 't':
			timeout = atoi(optarg);
			break;
		case 'W':
			width = atoi(optarg);
			break;
		case 'H':
			height = atoi(optarg);
			break;
		case 'm':
			startup_message = optarg;
			break;
		default:
			usage();
			return -1;
		}
	}

	const int sock = udp_socket(port);
	if (sock < 0)
		die("socket port %d failed: %s\n", port, strerror(errno));

	const size_t image_size = width * height * 3;
	const size_t buf_size = (width*height*4)/packets_per_frame + 1;

	// largest possible UDP packet
	uint8_t *buf = malloc(buf_size);
#if 0
	if (sizeof(buf) < image_size + 1)
		die("%u x %u too large for UDP\n", width, height);
#endif

	fprintf(stderr, "%u x %u, UDP port %u\n", width, height, port);

	ledscape_config_t * config = &ledscape_matrix_default;
	if (config_file)
	{
		config = ledscape_config(config_file);
		if (!config)
			return EXIT_FAILURE;
	}

	if (config->type == LEDSCAPE_MATRIX)
	{
		config->matrix_config.width = width;
		config->matrix_config.height = height;
	}

	ledscape_t * const leds = ledscape_init(config, no_init);
	if (!leds)
		return EXIT_FAILURE;

	const unsigned report_interval = 10;
	unsigned last_report = 0;
	unsigned long delta_sum = 0;
	unsigned frames = 0;

	uint32_t * const fb = calloc(width*height,4);
	ledscape_printf(fb, width, 0xFF0000, "%s", startup_message);
	ledscape_printf(fb+16*width, width, 0x00FF00, "%dx%d UDP port %d", width, height, port);
	ledscape_draw(leds, fb);

	while (1)
	{
		int rc = wait_socket(sock, timeout*1000);
		if (rc < 0)
		{
			// something failed
			memset(fb, 0, width*height*4);
			ledscape_printf(fb, width, 0xFF0000, "read failed?");
			ledscape_draw(leds, fb);
			exit(EXIT_FAILURE);
		}

		if (rc == 0)
		{
			// go into timeout mode
			memset(fb, 0, width*height*4);
			ledscape_printf(fb, width, 0xFF0000, "timeout");
			ledscape_draw(leds, fb);
			continue;
		}

		const ssize_t rlen = recv(sock, buf, buf_size, 0);
		if (rlen < 0)
			die("recv failed: %s\n", strerror(errno));
		warn_once("received %zu bytes\n", rlen);

		/*
		if (buf[0] == 2)
		{
			// image type
			printf("image type: %.*s\n",
				(int) rlen - 1,
				&buf[1]
			);
			continue;
		}

		if (buf[0] != 1)
		{
			// What is it?
			warn_once("Unknown image type '%c' (%02x)\n",
				buf[0],
				buf[0]
			);
			continue;
		}
		*/
		const unsigned frame_part = buf[0];
		if (frame_part != 0 && frame_part != 1)
		{
			printf("bad type %d\n", frame_part);
			continue;
		}

		if ((size_t) rlen != image_size + 1)
		{
			warn_once("WARNING: Received packet %zu bytes, expected %zu\n",
				rlen,
				image_size + 1
			);
		}

		struct timeval start_tv, stop_tv, delta_tv;
		gettimeofday(&start_tv, NULL);

		const unsigned frame_num = 0;

		// copy the 3-byte values into the 4-byte framebuffer
		// and turn onto the side
		for (unsigned x = 0 ; x < width ; x++) // 256
		{
			for (unsigned y = 0 ; y < 32 ; y++) // 64
			{
				uint32_t * out = (void*) &fb[(y+32*frame_part)*width + x];
				const uint8_t * const in = &buf[1 + 3*(y*width + x)];
				uint32_t r = in[0];
				uint32_t g = in[1];
				uint32_t b = in[2];
				*out = (r << 16) | (g << 8) | (b << 0);
			}
		}

		// only draw after the second frame
		if (frame_part == 1)
			ledscape_draw(leds, fb);

		gettimeofday(&stop_tv, NULL);
		timersub(&stop_tv, &start_tv, &delta_tv);

		frames++;
		delta_sum += delta_tv.tv_usec;
		if (stop_tv.tv_sec - last_report < report_interval)
			continue;
		last_report = stop_tv.tv_sec;

		const unsigned delta_avg = delta_sum / frames;
		printf("%6u usec avg, max %.2f fps, actual %.2f fps (over %u frames)\n",
			delta_avg,
			report_interval * 1.0e6 / delta_avg,
			frames * 1.0 / report_interval,
			frames
		);

		frames = delta_sum = 0;
	}

	return 0;
}