static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist) { struct sockaddr_in sin; int sockfd; long flags; memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_port = htons(listen_port); if (listen_addr) { /* Well, host better be an IP address here. */ if (inet_pton(AF_INET, listen_addr, &sin.sin_addr.s_addr) <= 0) return 0; } else { sin.sin_addr.s_addr = htonl(INADDR_ANY); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) return 0; if (set_reuse_addr(sockfd)) { logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); close(sockfd); return 0; } set_keep_alive(sockfd); if ( bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0 ) { logerror("Could not bind to %s: %s", ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), strerror(errno)); close(sockfd); return 0; } if (listen(sockfd, 5) < 0) { logerror("Could not listen to %s: %s", ip2str(AF_INET, (struct sockaddr *)&sin, sizeof(sin)), strerror(errno)); close(sockfd); return 0; } flags = fcntl(sockfd, F_GETFD, 0); if (flags >= 0) fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); socklist->list[socklist->nr++] = sockfd; return 1; }
static int execute(void) { char *line = packet_buffer; int pktlen, len, i; char *addr = getenv("REMOTE_ADDR"), *port = getenv("REMOTE_PORT"); struct hostinfo hi; hostinfo_init(&hi); if (addr) loginfo("Connection from %s:%s", addr, port); set_keep_alive(0); alarm(init_timeout ? init_timeout : timeout); pktlen = packet_read(0, NULL, NULL, packet_buffer, sizeof(packet_buffer), 0); alarm(0); len = strlen(line); if (pktlen != len) loginfo("Extended attributes (%d bytes) exist <%.*s>", (int) pktlen - len, (int) pktlen - len, line + len + 1); if (len && line[len-1] == '\n') { line[--len] = 0; pktlen--; } if (len != pktlen) parse_host_arg(&hi, line + len + 1, pktlen - len - 1); for (i = 0; i < ARRAY_SIZE(daemon_service); i++) { struct daemon_service *s = &(daemon_service[i]); const char *arg; if (skip_prefix(line, "git-", &arg) && skip_prefix(arg, s->name, &arg) && *arg++ == ' ') { /* * Note: The directory here is probably context sensitive, * and might depend on the actual service being performed. */ int rc = run_service(arg, s, &hi); hostinfo_clear(&hi); return rc; } } hostinfo_clear(&hi); logerror("Protocol error: '%s'", line); return -1; }
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { int ret; int connfd = 0; while ((connfd = g_sys_accept(sockfd, addr, addrlen)) < 0) { if (EINTR == errno) continue; if (!fd_not_ready()) return -1; ret = add_fd_event(sockfd, EVENT_READABLE, event_conn_callback, current_coro()); if (ret) return -2; schedule_timeout(ACCEPT_TIMEOUT); del_fd_event(sockfd, EVENT_READABLE); if (is_wakeup_by_timeout()) { errno = ETIME; return -3; } } ret = set_nonblock(connfd); if (ret) { close(connfd); return -4; } ret = enable_tcp_no_delay(connfd); if (ret) { close(connfd); return -5; } ret = set_keep_alive(connfd, KEEP_ALIVE); if (ret) { close(connfd); return -6; } return connfd; }
static int socket_set_options(int lsocket) { struct linger l; int linger_timeout = 5; int yes = 1, no = 0; #ifdef SO_REUSEPORT CP_SSO(lsocket, SOL_SOCKET, SO_REUSEPORT, yes); #endif #ifdef SO_REUSEADDR CP_SSO(lsocket, SOL_SOCKET, SO_REUSEADDR, yes); #endif //XXX: use lignering socket ? #if USE_LINGER #ifdef SOL_SOCKET l.l_onoff = 1; l.l_linger = 30; CP_SSO(lsocket, SOL_SOCKET, SO_LINGER, l); #endif #ifdef TCP_LINGER2 CP_SSO(lsocket, SOL_SOCKET, TCP_LINGER2, linger_timeout); #endif #endif #if USE_TCP_KEEPALIVE set_keep_alive(lsocket, yes); #endif #if USE_TCP_NODELAY set_tcp_nodelay_option(lsocket, yes); #endif #if USE_TCP_NOPUSH set_tcp_nopush_option(lsocket, yes); #endif #ifdef TCP_QUICKACK CP_SSO(lsocket, IPPROTO_TCP, TCP_QUICKACK, yes); #endif #ifdef TCP_DEFER_ACCEPT CP_SSO(lsocket, IPPROTO_TCP, TCP_DEFER_ACCEPT, no); #endif return CPO_OK; }
static int connect_to(struct client* c, int ssh_id){ if (c->cnt >= TOTAL_CONNECTION) { fprintf(stderr, "%s client max connection.....\n", get_time()); return -1; } const char* ip; int port; if (ssh_id < 0) { if (c->free_connection > 0) return -1; struct timeval tv; gettimeofday(&tv, NULL); if (tv.tv_sec - c->time < FREE_CONNECT_TIME) { return -1; }else { c->time = tv.tv_sec; } ip = c->remote_ip; port = c->remote_port; } else { ip = "0.0.0.0"; port = c->ssh_port; } int id; int idx; struct client_info* info; struct ring_buffer* rb; struct addrinfo hints; struct addrinfo* res = NULL; struct addrinfo* ai_ptr = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; char portstr[16]; sprintf(portstr, "%d", port); int status = getaddrinfo(ip, portstr, &hints, &res); if (status != 0) { return -1; } int sock = -1; for (ai_ptr = res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) { sock = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); if (sock < 0) { continue; } set_keep_alive(sock); sp_nonblocking(sock); status = connect(sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen); if (status != 0 && errno != EINPROGRESS) { close(sock); sock = -1; continue; } break; } if (sock < 0) { goto _failed; } id = get_id(c); assert(id != -1); idx = id % TOTAL_CONNECTION; info = &c->all_fds[idx]; info->fd = sock; info->id = id; info->to_id = ssh_id; snprintf(info->client_ip, sizeof(info->client_ip), "%s:%d", ip, port); rb = alloc_ring_buffer(MAX_CLIENT_BUFFER); info->buffer = rb; c->all_ids[c->cnt++] = id; if (ssh_id < 0) { c->free_connection += 1; } if (status != 0) { //connect no block, need check after FD_SET(sock, &c->fd_wset); info->connect_type = SOCKET_CONNECTING; }else { //success FD_SET(sock, &c->fd_rset); info->connect_type = SOCKET_CONNECTED; struct sockaddr* addr = ai_ptr->ai_addr; void* sin_addr = (ai_ptr->ai_family == AF_INET) ? (void*)&((struct sockaddr_in*)addr)->sin_addr : (void*)&((struct sockaddr_in6*)addr)->sin6_addr; inet_ntop(ai_ptr->ai_family, sin_addr, info->client_ip, sizeof(info->client_ip)); fprintf(stderr, "%s connected to %s. \n", get_time(), info->client_ip); } if (c->max_fd < sock + 1) { c->max_fd = sock + 1; } return id; _failed: freeaddrinfo(res); return -1; }
static struct conn_t *conn_new(struct sockaddr_in *raddr, struct sockaddr_in *laddr) { struct conn_t *c; int lsize, errnosave; struct sockaddr_in tmp; c = smalloc(sizeof(*c)); memset(c, 0, sizeof(*c)); c->state = CONN_NEW; INIT_LIST_HEAD(&c->reqs); if ((c->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { errnosave = errno; syslog(LOG_ERR, "socket: %s", strerror(errno)); free(c); errno = errnosave; return 0; } /* If this is not the first connection, do a non-blocking connect */ if (!list_empty(&clist)) set_non_block(c->fd); tmp = *laddr; /* use a temp here because * bindresvport writes it. */ if (laddr->sin_port || bindresvport(c->fd, &tmp) == -1) { syslog(LOG_ERR, "bindresvport: %s (ignoring)", strerror(errno)); /* If we specified a port or failed to bind to a reserved * port for some reason, try a normal bind. */ if (bind(c->fd, (struct sockaddr *) laddr, sizeof(*laddr)) == -1) { errnosave = errno; syslog(LOG_ERR, "bind(%s:%d): %s (ignoring)", inet_ntoa(laddr->sin_addr), ntohs(laddr->sin_port), strerror(errno)); close(c->fd); free(c); errno = errnosave; return 0; } } if (verbose) syslog(LOG_INFO, "Connecting to %s:%d...", inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port)); if (connect(c->fd, (struct sockaddr *) raddr, sizeof(*raddr)) == -1) { if (errno != EINPROGRESS) { errnosave = errno; syslog(LOG_ERR, "connect(%s:%d): %s", inet_ntoa(raddr->sin_addr), ntohs(raddr->sin_port), strerror(errno)); close(c->fd); free(c); errno = errnosave; return 0; } } /* Make note of our local address */ lsize = sizeof(c->laddr); getsockname(c->fd, (struct sockaddr *)&c->laddr, &lsize); c->raddr = *raddr; /* Prime output buffer with version information and cookie */ conn_send_version(c); set_keep_alive(c->fd); set_no_delay(c->fd); set_non_block(c->fd); /* Append to list of connections */ list_add_tail(&c->list, &clist); return c; }
static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist) { int socknum = 0; char pbuf[NI_MAXSERV]; struct addrinfo hints, *ai0, *ai; int gai; long flags; xsnprintf(pbuf, sizeof(pbuf), "%d", listen_port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); if (gai) { logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai)); return 0; } for (ai = ai0; ai; ai = ai->ai_next) { int sockfd; sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd < 0) continue; if (sockfd >= FD_SETSIZE) { logerror("Socket descriptor too large"); close(sockfd); continue; } #ifdef IPV6_V6ONLY if (ai->ai_family == AF_INET6) { int on = 1; setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); /* Note: error is not fatal */ } #endif if (set_reuse_addr(sockfd)) { logerror("Could not set SO_REUSEADDR: %s", strerror(errno)); close(sockfd); continue; } set_keep_alive(sockfd); if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { logerror("Could not bind to %s: %s", ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), strerror(errno)); close(sockfd); continue; /* not fatal */ } if (listen(sockfd, 5) < 0) { logerror("Could not listen to %s: %s", ip2str(ai->ai_family, ai->ai_addr, ai->ai_addrlen), strerror(errno)); close(sockfd); continue; /* not fatal */ } flags = fcntl(sockfd, F_GETFD, 0); if (flags >= 0) fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC); ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc); socklist->list[socklist->nr++] = sockfd; socknum++; } freeaddrinfo(ai0); return socknum; }
int reqs_proc(struct conn_t *conn) { struct vhost_t *vhost; struct uhook_t *uhook; struct reqs_t *reqs; reqs = reqs_new(conn); if (!reqs) { return 0; } /* reqs parse */ if (!reqs_parse(reqs)) { conn->keep_alive = 0; reqs_throw_status(reqs, 400, ""); /* "400 Bad Request" */ chtd_log(reqs->htdx, "reqs_parse() failed!"); reqs->htdx->nBadReqs++; reqs_del(reqs); return 1; } reqs->wker->nReqs++; set_keep_alive(reqs, 1); /* match uhook */ uhook = chtd_uhook_match(reqs); if (uhook) { if (uhook->func(reqs)) { if (reqs->rp_header_sent == 0) { reqs_throw_status(reqs, 400, ""); /* "400 Bad Request" */ } if (reqs->post_read_flag == 0) { reqs_skip_post(reqs); } reqs_del(reqs); return 1; } } /* match vhost */ vhost = chtd_vhost_match(reqs); if (vhost) { if (vhost_proc(reqs, vhost)) { if (reqs->post_read_flag == 0) { reqs_skip_post(reqs); } reqs_del(reqs); return 1; } } /* Bad Request */ set_keep_alive(reqs, 0); reqs_throw_status(reqs, 400, ""); /* "400 Bad Request" */ chtd_log(reqs->htdx, "Got a bad request."); pthread_mutex_lock(&reqs->htdx->mutex); reqs->htdx->nBadReqs++; pthread_mutex_unlock(&reqs->htdx->mutex); reqs_del(reqs); return 1; }