void server(const char *bindAddr, int port, int ssl) { int soc_ec = -1, maxfd, res, nc; fd_set set_read; fd_set set_write; struct sockaddr_in addrS; char methods[2]; #ifdef _WIN32 WSADATA wsaData; int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); if (wsaInit != 0) { ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); exit(1); } #endif s_socks_conf conf; s_socks_server_config config; conf.config.srv = &config; char versions[] = { SOCKS5_V, SOCKS4_V }; config.allowed_version = versions; config.n_allowed_version = sizeof(versions); if ( globalArgsServer.fileauth[0] != 0 ) { methods[0] = 0x02; --config.n_allowed_version; /* Disable socks4 don't support auth */ } else { methods[0] = 0x00; } config.allowed_method = methods; config.n_allowed_method = 1; config.check_auth = check_auth; /* Init client tab */ for (nc = 0; nc < MAXCLI; nc++) init_client (&tc[nc], nc, M_SERVER, &conf); if(bindAddr[0] == 0) soc_ec = new_listen_socket (NULL, port, 0, &addrS); else soc_ec = new_listen_socket (bindAddr, port, 0, &addrS); if (soc_ec < 0) goto fin_serveur; #ifndef _WIN32 if ( globalArgsServer.daemon == 1 ) { TRACE(L_NOTICE, "server: mode daemon ..."); if ( daemon(0, 0) != 0 ) { perror("daemon"); exit(1); } writePID(PID_FILE); } bor_signal (SIGINT, capte_fin, SA_RESTART); /* Need in daemon to remove the PID file properly */ bor_signal (SIGTERM, capte_fin, SA_RESTART); bor_signal (SIGPIPE, capte_sigpipe, SA_RESTART); /* TODO: Find a better way to exit the select and recall the init_select * SIGUSR1 is send by a thread to unblock the select */ bor_signal (SIGUSR1, capte_usr1, SA_RESTART); #endif while (boucle_princ) { init_select_server (soc_ec, tc, &maxfd, &set_read, &set_write); res = select (maxfd+1, &set_read, &set_write, NULL, NULL); if (res > 0) { /* Search eligible sockets */ if (FD_ISSET (soc_ec, &set_read)) new_connection (soc_ec, tc, ssl); for (nc = 0; nc < MAXCLI; nc++) { dispatch_server(&tc[nc], &set_read, &set_write); } } else if ( res == 0) { } else if (res < 0) { if (errno == EINTR) ; /* Received signal, it does nothing */ else { perror ("select"); goto fin_serveur; } } } fin_serveur: #ifdef HAVE_LIBSSL if (globalArgsServer.ssl == 1) ssl_cleaning(); #endif TRACE(L_NOTICE, "server: closing sockets ..."); close_log(); for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); if (soc_ec != -1) CLOSE_SOCKET(soc_ec); if ( globalArgsServer.daemon == 1 ) removePID(PID_FILE); #ifdef _WIN32 WSACleanup(); #endif }
void server_relay(int port, int listen, int ssl) { int soc_ec_cli = -1, soc_ec = -1, maxfd, res, nc; fd_set set_read; fd_set set_write; struct sockaddr_in addrS; #ifdef _WIN32 WSADATA wsaData; int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); if (wsaInit != 0) { ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); exit(1); } #endif /* Init client tab */ for (nc = 0; nc < MAXCLI; nc++) init_socket(&socks_pool[nc]); for (nc = 0; nc < MAXCLI; nc++) init_client (&tc[nc], nc, 0, NULL); TRACE(L_NOTICE, "server: set listening client socks relay ..."); soc_ec = new_listen_socket (NULL, port, MAXCLI, &addrS); if (soc_ec < 0) goto fin_serveur; TRACE(L_NOTICE, "server: set server relay ..."); soc_ec_cli = new_listen_socket (NULL, listen, MAXCLI, &addrS); if (soc_ec_cli < 0) goto fin_serveur; #ifndef _WIN32 if ( globalArgs.background == 1 ) { TRACE(L_NOTICE, "server: background ..."); if ( daemon(0, 0) != 0 ) { perror("daemon"); exit(1); } } bor_signal (SIGINT, capte_fin, SA_RESTART); /* TODO: Find a better way to exit the select and recall the init_select * SIGUSR1 is send by a thread to unblock the select */ bor_signal (SIGUSR1, capte_usr1, SA_RESTART); #endif while (boucle_princ) { init_select_reverse(soc_ec, soc_ec_cli, tc, &maxfd, &set_read, &set_write); res = select (maxfd+1, &set_read, &set_write, NULL,NULL); if (res > 0) { /* Search eligible sockets */ if (FD_ISSET (soc_ec, &set_read)) new_connection_socket (soc_ec, socks_pool, ssl); if (FD_ISSET (soc_ec_cli, &set_read)) new_connection_reverse (soc_ec_cli, tc, socks_pool); for (nc = 0; nc < MAXCLI; nc++) { dispatch_server(&tc[nc], &set_read, &set_write); } } else if ( res == 0) { /* If timeout was set in select and expired */ } else if (res < 0) { if (errno == EINTR) ; /* Received signal, it does nothing */ else { perror ("select"); goto fin_serveur; } } } fin_serveur: #ifdef HAVE_LIBSSL if (ssl == 1) ssl_cleaning(); #endif printf ("Server: closing sockets ...\n"); if (soc_ec != -1) CLOSE_SOCKET(soc_ec); for (nc = 0; nc < MAXCLI; nc++) close_socket(&socks_pool[nc]); for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); #ifdef _WIN32 WSACleanup(); #endif }
int main(int argc, char **argv) { char buf[1024]; fd_set * readselect = malloc(sizeof(fd_set)); fd_set * writeselect = malloc(sizeof(fd_set)); fd_set * errorselect = malloc(sizeof(fd_set)); unsigned int maxfd = 3; readsockets = array_init(); readsockets->name = "read"; writesockets = array_init(); writesockets->name = "write"; errorsockets = array_init(); errorsockets->name = "error"; buffer_socket * stdin_sock = malloc(sizeof(buffer_socket)); stdin_sock->type = SOCKTYPE_LOCAL; stdin_sock->fd = STDIN_FILENO; ringbuffer_init(&stdin_sock->rxbuffer); ringbuffer_init(&stdin_sock->txbuffer); readsockets = array_push(readsockets, stdin_sock); errorsockets = array_push(errorsockets, stdin_sock); char * printer_port = DEFAULT_PORT; int printer_baud = DEFAULT_BAUD; // TODO: parse command line options printer_socket *printer = new_printer_socket(printer_port, printer_baud); file_socket *file = NULL; /***********************************************************************\ * * * Now set up network sockets * * * \***********************************************************************/ new_listen_socket(DEFAULT_LISTEN_PORT, SOCKTYPE_CLIENT); new_listen_socket(DEFAULT_LISTEN_PORT + 1, SOCKTYPE_HTTP); /***********************************************************************\ * * * Main Loop * * * \***********************************************************************/ int running = 1; while (running) { FD_ZERO(readselect); FD_ZERO(writeselect); FD_ZERO(errorselect); for (int i = 0; i < readsockets->length; i++) { local_socket *ls = ((local_socket *) readsockets->data[i]); int fd = ls->fd; //printf("check read %d\n", ((local_socket *) readsockets->data[i])->fd); if ((ls->type == SOCKTYPE_PRINTER) || (printer->tokens > 0)) { FD_SET(fd, readselect); if (fd >= maxfd) maxfd = fd + 1; } } for (int i = 0; i < writesockets->length; i++) { local_socket *ls = ((local_socket *) writesockets->data[i]); int fd = ls->fd; //printf("check write %d\n", ((local_socket *) writesockets->data[i])->fd); if ((ls->type != SOCKTYPE_PRINTER) || (printer->tokens > 0)) { FD_SET(fd, writeselect); if (fd >= maxfd) maxfd = fd + 1; } } for (int i = 0; i < errorsockets->length; i++) { local_socket *ls = ((local_socket *) errorsockets->data[i]); int fd = ls->fd; //printf("check error %d\n", ((local_socket *) errorsockets->data[i])->fd); FD_SET(((local_socket *) errorsockets->data[i])->fd, errorselect); if (fd >= maxfd) maxfd = fd + 1; } select(maxfd, readselect, writeselect, errorselect, NULL); /*******************************************************************\ * * * Check Errors * * * \*******************************************************************/ for (int i = 0; i < errorsockets->length; i++) { local_socket *s = (local_socket *) errorsockets->data[i]; if (FD_ISSET(s->fd, errorselect)) { printf("error on %d: %p\n", s->fd, s); switch (s->type) { case SOCKTYPE_LOCAL: break; case SOCKTYPE_PRINTER: break; case SOCKTYPE_CLIENT: break; case SOCKTYPE_LISTEN: break; } /* switch s->type */ } /* if FD_ISSET fd, errorselect */ } /* for errorsockets */ /*******************************************************************\ * * * Check Readable Sockets * * * \*******************************************************************/ for (int i = 0; i < readsockets->length; i++) { local_socket *s = (local_socket *) readsockets->data[i]; if (FD_ISSET(s->fd, readselect)) { //printf("read %d (type %d)\n", s->fd, s->type); switch (s->type) { case SOCKTYPE_LOCAL: { buffer_socket *sock = (buffer_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer)); if (r == 0) { printf("EOF on stdin, exiting...\n"); exit(0); } break; } case SOCKTYPE_CLIENT: { client_socket *sock = (client_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->inbuffer, s->fd, ringbuffer_canwrite(&sock->inbuffer)); //printf("writefromfd %p %d %d got %d nl %d\n", &sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer), r, sock->rxbuffer.nl); if (r == 0) { sock2a(&sock->addr, buf, BUFFER_SIZE); printf("client %s disconnected\n", buf); close(sock->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; } else if (sock->inbuffer.nl > 0) { char linebuffer[256]; while (ringbuffer_peekline(&sock->inbuffer, linebuffer, sizeof(linebuffer))) { switch (detect_line_type(linebuffer)) { case LINETYPE_GCODE: { unsigned int i = ringbuffer_readline(&sock->rxbuffer, linebuffer, sizeof(linebuffer)); ringbuffer_write(&sock->rxbuffer, linebuffer, i); break; }; case LINETYPE_SIMPLECMD: { unsigned int i = ringbuffer_readline(&sock->rxbuffer, linebuffer, sizeof(linebuffer)); parse_line(linebuffer); break; }; } } } break; } case SOCKTYPE_PRINTER: { //printf("can read printer\n"); printer_socket *sock = (printer_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, BUFFER_SIZE); if (r == 0) { //printf(" %d bytes: printer disconnected, trying to reconnect...\n", r); close(s->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; sock = new_printer_socket(printer_port, printer_baud); readsockets = array_push(readsockets, sock); errorsockets = array_push(errorsockets, sock); } else { //printf(" %d bytes, %d newlines", r, sock->rxbuffer.nl); while (sock->rxbuffer.nl > 0) { char line[BUFFER_SIZE]; int r = ringbuffer_readline(&sock->rxbuffer, line, BUFFER_SIZE); if (sock->lastmsgsock->fd > 2) printf("< %s", line); int m = snprintf(buf, BUFFER_SIZE, "< %s", line); if (sock->lastmsgsock->type == SOCKTYPE_LOCAL) { int i = 0; do { i += write(sock->lastmsgsock->fd, &buf[i], m - i); } while (i < m); } else if (sock->lastmsgsock->type == SOCKTYPE_CLIENT) { //printf("client type\n"); client_socket *cs = (client_socket *) sock->lastmsgsock; ringbuffer_write(&cs->txbuffer, line, r); if (array_indexof(writesockets, cs) == -1) { writesockets = array_push(writesockets, cs); //printf("pushed %p/%d to writesockets\n", cs, cs->socket.fd); } } if (strncmp(line, "ok", 2) == 0) { //fprintf(stderr, "got token!"); if (sock->tokens < sock->maxtoken) sock->tokens++; for (int i = 0; i < errorsockets->length; i++) { if (((local_socket *) errorsockets->data[i])->type == SOCKTYPE_CLIENT) readsockets = array_push(readsockets, errorsockets->data[i]); } if (file != NULL) writesockets = array_push(writesockets, sock); //fprintf(stderr, " tokens: %d\n", sock->tokens); } else { //fprintf(stderr, "no token\n"); } } } break; } case SOCKTYPE_LISTEN: { listen_socket *ls = (listen_socket *) s; if (ls->protocol == SOCKTYPE_HTTP) { new_http_socket(ls); } else if (ls->protocol == SOCKTYPE_CLIENT) { new_client_socket(ls); } break; } case SOCKTYPE_FILE: { break; } case SOCKTYPE_HTTP: { http_socket *sock = (http_socket *) s; unsigned int r = ringbuffer_writefromfd(&sock->rxbuffer, s->fd, ringbuffer_canwrite(&sock->rxbuffer)); if (r == 0) { sock2a(&sock->addr, buf, BUFFER_SIZE); printf("client %s disconnected\n", buf); close(sock->fd); readsockets = array_delete(readsockets, sock); writesockets = array_delete(writesockets, sock); errorsockets = array_delete(errorsockets, sock); free(sock); sock = NULL; } else { } break; } } /* switch s->type */ } /* if FD_ISSET fd, readselect */ } /* for readsockets */ /*******************************************************************\ * * * Check Writable Sockets * * * \*******************************************************************/ for (int i = 0; i < writesockets->length; i++) { local_socket *s = (local_socket *) writesockets->data[i]; if (FD_ISSET(s->fd, writeselect)) { //printf("write %d", s->fd); switch (s->type) { case SOCKTYPE_LOCAL: case SOCKTYPE_CLIENT: case SOCKTYPE_HTTP: { //printf("write client socket\n"); buffer_socket *sock = (buffer_socket *) s; if (ringbuffer_canread(&sock->txbuffer) > 0) { //printf("readtofd %d %p: %d\n", s->fd, &sock->txbuffer, ringbuffer_readtofd(&sock->txbuffer, s->fd); //); } if (ringbuffer_canread(&sock->txbuffer) == 0) { //printf("client txbuffer empty\n"); writesockets = array_delete(writesockets, s); } break; } case SOCKTYPE_PRINTER: { printer_socket *sock = (printer_socket *) s; //printf("write: nl: %d\n", sock->txbuffer.nl); if (sock->rxbuffer.nl == 0) { int i = (sock->lastmsgindex + 1) % errorsockets->length; for (int j = 0; j <= errorsockets->length; j++) { buffer_socket * x = errorsockets->data[i]; if (x->type == SOCKTYPE_LOCAL || x->type == SOCKTYPE_CLIENT || x->type == SOCKTYPE_FILE) { int r = ringbuffer_readline(&x->rxbuffer, buf, BUFFER_SIZE); ringbuffer_write(&printer->txbuffer, buf, r); sock->lastmsgsock = (local_socket *) x; sock->lastmsgindex = i; break; } i = (i + 1) % errorsockets->length; } } if (sock->txbuffer.nl > 0) { //printf("write: nl: %d\n", sock->txbuffer.nl); unsigned int r = ringbuffer_readline(&sock->txbuffer, buf, BUFFER_SIZE); buf[r] = 0; printf(">>> %s", buf); int i = 0; do { i += write(s->fd, &buf[i], r - i); } while (i < r); sock->tokens--; if (sock->tokens == 0) { for (int i = 0; i < errorsockets->length; i++) { if (((local_socket *) errorsockets->data[i])->type == SOCKTYPE_CLIENT) readsockets = array_delete(readsockets, errorsockets->data[i]); } } } else if ((sock->tokens > 0) && (file != NULL) && (file->paused == 0)) { if ((ringbuffer_canwrite(&file->rxbuffer) > 0) && (file->eof == 0)) { int w = ringbuffer_writefromfd(&file->rxbuffer, file->fd, BUFFER_SIZE); if (w == 0) file->eof = 1; } if (file->rxbuffer.nl > 0) { int r = ringbuffer_readline(&file->rxbuffer, buf, BUFFER_SIZE); buf[r] = 0; printf(">>> %s", buf); int i = 0; do { i += write(s->fd, &buf[i], r - i); } while (i < r); sock->tokens--; } else if (file->eof) { // file is completely printed printf("File %s complete. Print time: \n", file->filename); // TODO:close file } } if ((ringbuffer_canread(&sock->txbuffer) == 0) || (sock->tokens == 0)) writesockets = array_delete(writesockets, sock); break; } } /* switch s->type */ } /* if FD_ISSET fd, writeselect */ } /* for writesockets */ } /* while running */ return 0; } /* main() */