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; }
/* 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); } }