/** * @brief Connect to server with a timeout. * * @param fd [in] client fd * @param cli_addr [in] client sockaddr_in * @param tm_ms [in] time out * * @return 0, if succ; -1, if fail */ int socket_time_connect(int fd, void *cli_addr, int tm_ms) { struct timeval tv = {0}; fd_set wfd; int rt = -1; int interval = 100; if (fd < 0) return -1; /* make socket non blocking */ make_socket_nonblock(fd); /* connect to server looply */ while (1) { /* empty fd sets */ FD_ZERO(&wfd); FD_SET(fd, &wfd); /* timer */ tv.tv_sec = 0; tv.tv_usec = 1000 * interval; /* connect to server */ rt = connect(fd, (struct sockaddr *)cli_addr, sizeof(struct sockaddr)); if (rt == 0 || errno != EINPROGRESS) break; /* detect whether is connected successfully */ if (select(fd + 1, NULL, &wfd, NULL, &tv) > 0) { if (FD_ISSET(fd, &wfd)) { if (!getsockopt(fd, SOL_SOCKET, SO_ERROR, NULL, NULL)) { rt = 0; break; } } } /* timer decline */ tm_ms -= interval; if (tm_ms <= 0) { rt = -1; break; } } /* close socket if connected failed */ if (rt < 0) close(fd); return rt; }
/* If we get a "truncated" UDP DNS packet upstream, and have connected via * TCP to make our original DNS query, connect via TCP to the upstream * server to try and get the non-truncated reply */ void tcp_truncated_retry(int b, dw_str *query, int id, int udp_id, int is_up) { dw_str *tmp = 0; sockaddr_all_T server; socklen_t len = sizeof(struct sockaddr_in); if(tcp_pend[b].buffer != 0) { free(tcp_pend[b].buffer); tcp_pend[b].buffer = 0; } /* Prepare packet to send */ tmp = make_dns_query_packet(query,id,is_up); if(tmp == 0) { goto catch_tcp_truncated_retry; } tcp_pend[b].buffer = malloc(tmp->len + 3); if(tcp_pend[b].buffer == 0) { goto catch_tcp_truncated_retry; } tcp_pend[b].buffer[0] = (tmp->len & 0xff00) >> 8; /* Header byte 1 */ tcp_pend[b].buffer[1] = tmp->len & 0xff; /* Header byte 2 */ memcpy(tcp_pend[b].buffer + 2, tmp->str, tmp->len); /* DNS query */ tcp_pend[b].state = 3; /* Send buffer upstream */ tcp_pend[b].got = 0; /* No bytes sent */ tcp_pend[b].wanted = tmp->len + 2; /* Send entire packet */ /* Connect to upstream server over TCP */ tcp_pend[b].upstream = setup_tcp_server(&server,query,udp_id); if(tcp_pend[b].upstream == INVALID_SOCKET) { goto catch_tcp_truncated_retry; } make_socket_nonblock(tcp_pend[b].upstream); #ifdef IPV6 if (server.Family == AF_INET6) len = sizeof(struct sockaddr_in6); #endif /* IPV6 */ if(connect(tcp_pend[b].upstream,(struct sockaddr *)&server,len) == -1 && SCKT_ERR != EINPROGRESS) { closesocket(tcp_pend[b].upstream); goto catch_tcp_truncated_retry; } /* Clean-up */ dw_destroy(tmp); return; catch_tcp_truncated_retry: if(tmp != 0) { dw_destroy(tmp); } closesocket(tcp_pend[b].local); reset_tcp_pend(b); }
/* Given a tcp socket s, accept the connection on that socket, then * prepare things so we can get <len><DNS packet>, send the query in their * packet upstream, then send <len><DNS reply> back to the TCP client */ void local_tcp_accept(SOCKET s) { sockaddr_all_T client; SOCKET local = 0; socklen_t len = sizeof(struct sockaddr_in); int b = 0; ip_addr_T from_ip; b = find_free_tcp_pend(); if(b == -1) { /* Out of active TCP connections */ return; } len = sizeof(client); local = accept(s,(struct sockaddr *)&client,&len); make_socket_nonblock(local); if(local == INVALID_SOCKET) { /* accept() error */ return; } /* This is where we do ip-based packet rejection */ get_from_ip_port(&from_ip,&client); if(check_ip_acl(&from_ip) != 1) { closesocket(local); return; } /* At this point, we want to get the 2-byte * length of the DNS packet, followed by getting the DNS packet; * we then want to be able to send UDP queries upstream to get * the information we want, then we went to send the reply back * over TCP */ init_tcp_pend(b); tcp_pend[b].buffer = malloc(3); /* To put the two bytes we want */ if(tcp_pend[b].buffer == 0) { closesocket(local); reset_tcp_pend(b); return; } tcp_pend[b].local = local; tcp_pend[b].wanted = 2; /* We want to get the two-byte DNS length * header from the client */ tcp_pend[b].die = get_time() + ((int64_t)timeout_seconds_tcp << 8); }
int main(int argc, char **argv) { int sockfd; int newfd; int portno; int ready; fd_set read_set; socklen_t socklen; struct sockaddr_in serv_addr; struct sockaddr_in cli_addr; thread_args_t *thread_args; pthread_t stream_thread; mpg123_handle *mh; char buffer[32]; int bytes_read; if (argc < 2) { fprintf(stderr, "specify port to listen too\n"); return 1; } sockfd = -1; newfd = -1; stream_thread = -1; fprintf(stderr, "bring up ao\n"); ao_initialize(); fprintf(stderr, "bring up mpg123\n"); mpg123_init(); mh = mpg123_new(NULL, NULL); if (!mh) { fprintf(stderr, "error mpg123_new()\n"); goto cleanup; } fprintf(stderr, "mpg123 initialized\n"); mpg123_param(mh, MPG123_VERBOSE, 2, 0); signal(SIGINT, handle_sigint); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); goto cleanup; } memset(&serv_addr, 0, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind"); goto cleanup; } if (listen(sockfd, 5) < 0) { perror("listen"); goto cleanup; } socklen = sizeof(cli_addr); g_go_on = 1; g_cmd_sock = -1; g_busy = 0; g_stop = 0; FD_ZERO(&g_read_master); FD_SET(sockfd, &g_read_master); while (g_go_on) { read_set = g_read_master; ready = select(10, &read_set, NULL, NULL, NULL); if (ready < 0) { perror("select!!!!"); //g_go_on = 0; } else if (ready > 0) { if (FD_ISSET(sockfd, &read_set)) { newfd = accept(sockfd, (struct sockaddr *)&cli_addr, &socklen); if (newfd < 0) { perror("accept"); } else { bytes_read = read(newfd, buffer, sizeof(buffer)); if (bytes_read > 0) { if (bytes_read >= strlen(IDENT_STREAM_SOCK) && strncmp(buffer, IDENT_STREAM_SOCK, strlen(IDENT_STREAM_SOCK)) == 0) { fprintf(stderr, "stream sock %d connected\n", newfd); thread_args = malloc(sizeof(thread_args_t)); thread_args->mh = mh; thread_args->stream_socket = newfd; if (stream_thread != -1) { pthread_detach(stream_thread); stream_thread = -1; } if (pthread_create(&stream_thread, NULL, stream_thread_main, thread_args) < 0) { free(thread_args); perror("pthread create"); break; } } else if (bytes_read >= strlen(IDENT_CMD_SOCK) && strncmp(buffer, IDENT_CMD_SOCK, strlen(IDENT_CMD_SOCK)) == 0) { make_socket_nonblock(newfd); FD_SET(newfd, &g_read_master); g_cmd_sock = newfd; fprintf(stderr, "cmd sock %d connected\n", newfd); } } } } if (FD_ISSET(g_cmd_sock, &read_set)) { memset(buffer, 0, sizeof(buffer)); bytes_read = read(g_cmd_sock, buffer, sizeof(buffer)); if (bytes_read <= 0) { fprintf(stderr, "read() - lost cmd_sock\n"); close_cmd_sock(); /* reset paused state here.. otherwise we get in dead lock */ /* and stop that bitch */ g_paused = 0; g_stop = 1; if (bytes_read != 0) { perror("cmd_sock read"); } } else { handle_command(buffer, bytes_read); } } } } fprintf(stderr, "shutdown... waiting for thread\n"); if (stream_thread != -1 ) { pthread_join(stream_thread, NULL); pthread_detach(stream_thread); } fprintf(stderr, "shutdown\n"); cleanup: if (g_cmd_sock != -1) { close_cmd_sock(); } if (sockfd != -1) { close(sockfd); } if (mh) { fprintf(stderr, "close mpg123\n"); mpg123_close(mh); mpg123_delete(mh); } mpg123_exit(); fprintf(stderr, "shutdown ao\n"); ao_shutdown(); return 0; }
static void* cmd_thread_main(void *args) { int socket; fd_set read_set; int bytes_written; int bytes_read; int num_ready; char buffer[256]; socket = *(int*)args; free(args); make_socket_nonblock(STDIN_FILENO); make_socket_nonblock(socket); while (1) { FD_ZERO(&read_set); FD_SET(STDIN_FILENO, &read_set); FD_SET(socket, &read_set); num_ready = select(20, &read_set, NULL, NULL, NULL); if (num_ready < 0) { perror("select"); break; } else if (num_ready > 0) { if (FD_ISSET(STDIN_FILENO, &read_set)) { memset(buffer, 0, sizeof(buffer)); bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer)); if (bytes_read > 0) { fprintf(stderr, "jo\n"); bytes_written = write(socket, buffer, strlen(buffer)); fprintf(stderr, "wrote %d to socket\n", bytes_written); if (bytes_written <= 0) { fprintf(stderr, "can't write cmd_sock\n"); if (bytes_written < 0) { perror("cmd_socket write"); } break; } } } if (FD_ISSET(socket, &read_set)) { bytes_read = read(socket, buffer, sizeof(buffer)); if (bytes_read > 0) { if (strncmp(buffer, REMOTE_CMD_DONE, strlen(REMOTE_CMD_DONE)) == 0) { fprintf(stderr, "DONE SIGNAL\n"); break; } } else { if (bytes_read < 0) { perror("read"); } break; } } } } fprintf(stderr, "leave cmd_thread\n"); return NULL; }