示例#1
0
文件: afp.c 项目: 007/afpfs-ng
int afp_server_connect(struct afp_server *server, int full)
{
	int 	error = 0;
	struct 	timeval t1, t2;
	struct 	addrinfo *address;
	char	log_msg[64];
	char	ip_addr[INET6_ADDRSTRLEN];

	address = server->address;
   	while (address) 
	{
		switch(address->ai_family) 
		{
			case AF_INET6:
			    inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)address->ai_addr)->sin6_addr),
			            ip_addr, INET6_ADDRSTRLEN);
			break;
			case AF_INET:
			    inet_ntop(AF_INET, &(((struct sockaddr_in *)address->ai_addr)->sin_addr),
			            ip_addr, INET6_ADDRSTRLEN);
			break;
			default:
				snprintf(ip_addr, 22, "unknown address family");
			break;
		}

		snprintf(log_msg, sizeof(log_msg), "trying %s ...", ip_addr);

		log_for_client(NULL, AFPFSD, LOG_NOTICE, log_msg);

       	server->fd = socket(address->ai_family,
                        address->ai_socktype, address->ai_protocol);

        if (server->fd >= 0) 
		{
        	    if (connect(server->fd, address->ai_addr, address->ai_addrlen) == 0)
        	        break;
        	    close(server->fd);
        	    server->fd	= -1;
       	}
        address	= address->ai_next;
   	}

	if(server->fd < 0)
	{
		error = errno;
		goto error;
	}

	server->exit_flag		= 0;
	server->lastrequestid	= 0;
	server->connect_state	= SERVER_STATE_CONNECTED;
	server->used_address	= address;

	add_server(server);

	add_fd_and_signal(server->fd);
	if (!full) {
		return 0;
	}

	/* Get the status, and calculate the transmit time.  We use this to
	* calculate our rx quantum. */
	gettimeofday(&t1,NULL);

	if ((error=dsi_getstatus(server))!=0) 
		goto error;
	gettimeofday(&t2,NULL);

        afp_server_identify(server);

	if ((t2.tv_sec - t1.tv_sec) > 0)
		server->tx_delay= (t2.tv_sec - t1.tv_sec) * 1000;
	else
		server->tx_delay= (t2.tv_usec - t1.tv_usec) / 1000;

	/* Calculate the quantum based on our tx_delay and a threshold */
	/* For now, we'll just set a default */
	/* This is the default in 10.4.x where x > 7 */
	server->rx_quantum = 128 * 1024;


	return 0;
error:
	return -error;
}
示例#2
0
/* hand off the command. return child connection to the main program */
afp_child_t *dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval)
{
  pid_t pid;
  unsigned int ipc_fds[2];  
  afp_child_t *child;

  if (socketpair(PF_UNIX, SOCK_STREAM, 0, ipc_fds) < 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
      exit( EXITERR_CLNT );
  }

  if (setnonblock(ipc_fds[0], 1) != 0 || setnonblock(ipc_fds[1], 1) != 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: setnonblock: %s", strerror(errno));
      exit(EXITERR_CLNT);
  }

  switch (pid = dsi->proto_open(dsi)) { /* in libatalk/dsi/dsi_tcp.c */
  case -1:
    /* if we fail, just return. it might work later */
    LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
    return NULL;

  case 0: /* child. mostly handled below. */
    break;

  default: /* parent */
    /* using SIGQUIT is hokey, but the child might not have
     * re-established its signal handler for SIGTERM yet. */
    if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds)) < 0) {
      LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno));
      dsi->header.dsi_flags = DSIFL_REPLY;
      dsi->header.dsi_code = DSIERR_SERVBUSY;
      dsi_send(dsi);
      dsi->header.dsi_code = DSIERR_OK;
      kill(pid, SIGQUIT);
    }
    dsi->proto_close(dsi);
    return child;
  }
  
  /* child: check number of open connections. this is one off the
   * actual count. */
  if ((serv_children->count >= serv_children->nsessions) &&
      (dsi->header.dsi_command == DSIFUNC_OPEN)) {
    LOG(log_info, logtype_dsi, "dsi_getsess: too many connections");
    dsi->header.dsi_flags = DSIFL_REPLY;
    dsi->header.dsi_code = DSIERR_TOOMANY;
    dsi_send(dsi);
    exit(EXITERR_CLNT);
  }

  /* get rid of some stuff */
  close(dsi->serversock);
  server_child_free(serv_children); 

  switch (dsi->header.dsi_command) {
  case DSIFUNC_STAT: /* send off status and return */
    {
      /* OpenTransport 1.1.2 bug workaround: 
       *
       * OT code doesn't currently handle close sockets well. urk.
       * the workaround: wait for the client to close its
       * side. timeouts prevent indefinite resource use. 
       */
      
      static struct timeval timeout = {120, 0};
      fd_set readfds;
      
      dsi_getstatus(dsi);

      FD_ZERO(&readfds);
      FD_SET(dsi->socket, &readfds);
      free(dsi);
      select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);    
      exit(0);
    }
    break;
    
  case DSIFUNC_OPEN: /* setup session */
    /* set up the tickle timer */
    dsi->timer.it_interval.tv_sec = dsi->timer.it_value.tv_sec = tickleval;
    dsi->timer.it_interval.tv_usec = dsi->timer.it_value.tv_usec = 0;
    signal(SIGPIPE, SIG_IGN); /* we catch these ourselves */
    dsi_opensession(dsi);
    if ((child = calloc(1, sizeof(afp_child_t))) == NULL)
        exit(EXITERR_SYS);
    child->ipc_fds[1] = ipc_fds[1];
    return child;
    break;

  default: /* just close */
    LOG(log_info, logtype_dsi, "DSIUnknown %d", dsi->header.dsi_command);
    dsi->proto_close(dsi);
    exit(EXITERR_CLNT);
  }
}