int XHCP_loadConfig (node_t* argXmlConfig) { node_t **result; int nb_result; char buffer[XHCP_BUFFER_SZ]; int sz_buffer; char *xhcp_fileName; printf ("Loading XHCP server configuration...\n"); if ( (xhcp_fileName = XHCP_getConfigFile ()) != NULL ) domConfig = roxml_load_doc (xhcp_fileName); else if ( argXmlConfig != NULL ) domConfig = argXmlConfig; else Error_Quit ("Unable to find XHCP configuration"); /* Time Out */ result = roxml_xpath ( domConfig, "//XHCPserver/ConnectionTimeOut[@delay]", &nb_result); if ( nb_result == 1 ) { char *zaza = roxml_get_content ( roxml_get_attr (result[0], "delay", 0), buffer, XHCP_BUFFER_SZ, &sz_buffer ); XHCP_connexionTimeOut = atoi (zaza); if ( XHCP_connexionTimeOut <= 0 ) XHCP_connexionTimeOut=2; } else if ( nb_result == 0) { XHCP_connexionTimeOut = 5; } else Error_Quit ("Erroe parsing XHCP config file (ConnectionTimeOut)"); roxml_release (RELEASE_LAST); printf ("XHCP_connexionTimeOut = %d\n", XHCP_connexionTimeOut); return 0; }
ssize_t Writeline(int sockd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *buffer; buffer = vptr; nleft = n; while ( nleft > 0 ) { if ( (nwritten = write(sockd, buffer, nleft)) <= 0 ) { if ( errno == EINTR ) nwritten = 0; else Error_Quit("Error in Writeline()"); } nleft -= nwritten; buffer += nwritten; } return n; }
/* Gets request headers. A CRLF terminates a HTTP header line, but if one is never sent we would wait forever. Therefore, we use select() to set a maximum length of time we will wait for the next complete header. If we timeout before this is received, we terminate the connection. */ int Get_Request(int conn, struct ReqInfo * reqinfo) { char buffer[MAX_REQ_LINE] = {0}; int rval; fd_set fds; struct timeval tv; /* Set timeout to 5 seconds */ tv.tv_sec = 5; tv.tv_usec = 0; /* Loop through request headers. If we have a simple request, then we will loop only once. Otherwise, we will loop until we receive a blank line which signifies the end of the headers, or until select() times out, whichever is sooner. */ do { /* Reset file descriptor set */ FD_ZERO(&fds); FD_SET(conn, &fds); /* Wait until the timeout to see if input is ready */ rval = select(conn + 1, &fds, NULL, NULL, &tv); /* Take appropriate action based on return from select() */ if (rval < 0) { Error_Quit("Error calling select() in get_request()"); } else if (rval == 0) { p(" input not ready after timeout "); return -1; } else { /* We have an input line waiting, so retrieve it */ Readline(conn, buffer, MAX_REQ_LINE - 1); // Trim(buffer); if (buffer[0] == '\0') break; if (Parse_HTTP_Header(buffer, reqinfo)) break; } } while (reqinfo->type != SIMPLE); return 0; }
int main(int argc, char *argv[]) { int listener, conn; pid_t pid; struct sockaddr_in servaddr; /* Create socket */ if ( (listener = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) Error_Quit("Couldn't create listening socket."); /* Populate socket address structure */ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERVER_PORT); /* Assign socket address to socket */ if ( bind(listener, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) Error_Quit("Couldn't bind listening socket."); /* Make socket a listening socket */ if ( listen(listener, LISTENQ) < 0 ) Error_Quit("Call to listen failed."); /* Loop infinitely to accept and service connections */ while ( 1 ) { /* Wait for connection */ if ( (conn = accept(listener, NULL, NULL)) < 0 ) Error_Quit("Error calling accept()"); /* Fork child process to service connection */ if ( (pid = fork()) == 0 ) { /* This is now the forked child process, so close listening socket and service request */ if ( close(listener) < 0 ) Error_Quit("Error closing listening socket in child."); Service_Request(conn); /* Close connected socket and exit */ if ( close(conn) < 0 ) Error_Quit("Error closing connection socket."); exit(EXIT_SUCCESS); } /* If we get here, we are still in the parent process, so close the connected socket, clean up child processes, and go back to accept a new connection. */ if ( close(conn) < 0 ) Error_Quit("Error closing connection socket in parent."); waitpid(-1, NULL, WNOHANG); } return EXIT_FAILURE; /* We shouldn't get here */ }
void start_server() { printf("STARTING SERVER!\n localhost:%d\n", SERVER_PORT); if(SERVER_PORT<1024)p("sudo netbase if port < 1024 !!!"); flush(); /* Create socket */ if ((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0) Error_Quit("Couldn't create listening socket."); int flag = 1;// allow you to bind a local port that is in TIME_WAIT. // This is very useful to ensure you don't have to wait 4 minutes after killing a server before restarting it. setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); /* Populate socket address structure */ memset(&servaddr, 0, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERVER_PORT); /* Assign socket address to socket */ // __bind<int&,sockaddr *,unsigned long> x= bind(listener, (struct sockaddr *) &servaddr, sizeof (servaddr)); if(listener<0) Error_Quit("Couldn't bind listening socket."); /* Make socket a listening socket */ // if (listen(listener, BACKLOG) < 0) if (listen(listener, LISTENQ) < 0) Error_Quit("Call to listen failed."); printf("listening on %d port %d\n", INADDR_ANY, SERVER_PORT); p(" [debugging server doesn't work with xcode, use ./compile.sh ]"); /* Loop infinitely to accept and service connections */ while (1) { /* Wait for connection */ // NOT with XCODE -> WEBSERV conn = accept(listener, NULL, NULL); if (conn < 0) Error_Quit("Error calling accept()! debugging not supported, are you debugging?"); else p("conn = accept OK"); // WORKS FINE, but not when debugging /* Fork child process to service connection */ pid = fork(); if (pid == 0) { /* This is now the forked child process, so close listening socket and service request */ if (close(listener) < 0) Error_Quit("Error closing listening socket in child."); Service_Request(conn); /* Close connected socket and exit forked process */ if (close(conn) < 0) Error_Quit("Error closing connection socket."); exit(EXIT_SUCCESS); }else{ // p("not forked yet"); // !!?! // Service_Request(conn);// whatever } /* If we get here, we are still in the parent process, so close the connected socket, clean up child processes, and go back to accept a new connection. */ waitpid(-1, NULL, WNOHANG); if (close(conn) < 0) Error_Quit("Error closing connection socket in parent."); } Error_Quit("FORK web server failed"); return; // EXIT_FAILURE; /* We shouldn't get here */ }
int XHCP_server (node_t* argXmlConfig) { static int listener; static int conn; static pid_t pid; static struct sockaddr_in servaddr; static char *additionalDataBuffer=NULL; static int argc = 0; static char *argv[MAX_CMD_ARGS+1]; static char buffer[MAX_REQ_LINE] = {0}; int status, nbCar; switch (XHCP_running_status) { /* ------------------------------------------------------------------------ */ case (XHCPstate_init): XHCP_loadConfig(argXmlConfig); /* Create socket */ if ( (listener = socket (AF_INET, SOCK_STREAM, 0)) < 0 ) Error_Quit ("Couldn't create listening socket."); /* Populate socket address structure */ memset (&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl (INADDR_ANY); servaddr.sin_port = htons (XHCP_SERVER_PORT); /* "Address already in use" error message killer !!!! */ int tr=1; if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } /* Assign socket address to socket */ if ( bind (listener, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) { perror("Bind"); Error_Quit ("Couldn't bind listening socket."); } /* Make socket a listening socket */ if ( listen (listener, LISTENQ) < 0 ) Error_Quit ("Call to listen failed."); int flags = fcntl(listener, F_GETFL ); fcntl(listener, F_SETFL, flags | O_NONBLOCK ); XHCP_customWelcomeMessage (); /* L'initialisation est terminée, on passe à la suite */ XHCP_running_status = XHCPstate_waitConnect; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitConnect): /* Wait for connection */ if ( (conn = accept (listener, NULL, NULL)) < 0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } //TODO Gestion du timeout XHCP_printXHCPResponse (conn, RES_HALWELCOM ); // Petit message de bienvenue XHCP_running_status = XHCPstate_waitCommand; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitCommand): if ( (nbCar = recv(conn, buffer, MAX_REQ_LINE - 1, MSG_DONTWAIT)) <0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { //TODO Gestion du timeout return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } buffer[nbCar]='\0'; Trim (buffer, 0); // We suppress all extra characters if ( buffer[0] == '\0' ) return XHCP_running_status; // We continue.... printf ("Ligne lue : %s\n", buffer); cut_Line (buffer, &argc, argv); printf ("%d arguments :\n", argc); int i; for ( i=0; i<argc; i++ ) printf ( "%d - %s\n", i, argv[i]); status = exec_Line (conn, argc, argv ); // We compute the line... printf("Ligne executee, statut = %d\n",status); switch (status) { case -1: // deconnexion XHCP_running_status = XHCPstate_endConnect; return XHCP_running_status; break; case 0: // Fin de la commande return XHCP_running_status; break; // default : // On continue } XHCP_running_status = XHCPstate_waitData; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitData): if ( (nbCar = recv(conn, buffer, MAX_REQ_LINE - 1, MSG_DONTWAIT)) <0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { //TODO Gestion du timeout return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } buffer[nbCar]='\0'; /* We suppress all extra characters on the right except '.' and '>' */ Trim (buffer, 1); /* The handler is activate, so all lignes are added in buffer */ if ( buffer[0] == '.' && buffer[1] == '\0') { additionalDataHandler (conn, argc, argv, additionalDataBuffer ); additionalDataHandler = NULL; free (additionalDataBuffer); additionalDataBuffer = NULL; XHCP_running_status = XHCPstate_waitCommand; } else { additionalDataBuffer = addBuffer (additionalDataBuffer, buffer); } break; /* ------------------------------------------------------------------------ */ case (XHCPstate_endConnect): XHCP_printXHCPResponse (conn, RES_CLOCONBYE ); if ( close (conn) < 0 ) Error_Quit ("Error closing connection socket in parent."); XHCP_running_status = XHCPstate_waitConnect; //default : /* (XHCPstate_death) */ /* Do nothing ... */ } return XHCP_running_status; }
int XHCP_server (node_t* argXmlConfig) { static const int zero=0; static int listener; static int conn; static pid_t pid; //static struct sockaddr_in servaddr; static struct sockaddr_storage servaddr; static struct timeval time_conn, time_resp; static char *additionalDataBuffer=NULL; static int argc = 0; static char *argv[MAX_CMD_ARGS+1]; static char buffer[MAX_REQ_LINE] = {0}; int status, nbCar; // Variables non persistantes int sockV4, sockV6; struct addrinfo hints, *list_addr, *p_adresse, *aiv4, *aiv6, *choix_ai; switch (XHCP_running_status) { /* ------------------------------------------------------------------------ */ case (XHCPstate_init): XHCP_loadConfig(argXmlConfig); /* Create socket */ // if ( (listener = socket (AF_INET, SOCK_STREAM, 0)) < 0 ) // Error_Quit ("Couldn't create listening socket."); /* Populate socket address structure */ memset (&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if ( (getaddrinfo(NULL, XHCP_SERVER_PORT, &hints, &list_addr)) < 0 ) { //printf("getaddrinfo: %s\n",gai_strerroe(flags)); perror("getaddrinfo"); exit(1); } sockV4=-1; sockV6=-1; p_adresse = list_addr; // Vérification des protocoles en testant l'ouverture d'une socket while (p_adresse) { if ( p_adresse->ai_family == AF_INET6) { if ( sockV6 < 0 ) { printf("Scanning IPV6..."); if ( (sockV6=socket(p_adresse->ai_family, p_adresse->ai_socktype, p_adresse->ai_protocol)) >= 0 ) { aiv6 = p_adresse; printf(" found"); } printf("\n"); } } else if ( p_adresse->ai_family == AF_INET) { if ( sockV4 < 0 ) { printf("Scanning IPV4..."); if ( (sockV4=socket(p_adresse->ai_family, p_adresse->ai_socktype, p_adresse->ai_protocol)) >= 0 ) { aiv4 = p_adresse; printf(" found"); } printf("\n"); } } p_adresse = p_adresse->ai_next; } // Selection de la socket if ( sockV6 >= 0 ) { choix_ai = aiv6; listener = sockV6; // Tentative d'activation de la traduction IPV6->IPV4 if ( setsockopt(sockV6, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) < 0 ) { perror("notice : setsockopt(IPV6_ONLY)"); printf("IPV6 ONLY ! Tentative de passer en IPV4...\n"); if (sockV4 >=0) { close(sockV6); sockV6 = -1; } } else { //Traduction possible, on ferme l'ipv4 if (sockV4 >= 0) { printf("IPV4 over IPV6 => close IPV4\n"); close(sockV4); sockV4=-1; } } } if ( sockV4 >= 0 ) { choix_ai = aiv4; listener = sockV4; } else if ( sockV6 < 0 ) { Error_Quit ("Aucun protocole IPV4 ou IPV6 possible."); } /* "Address already in use" error message killer !!!! */ int tr=1; if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } /* Assign socket address to socket */ if ( bind (listener, choix_ai->ai_addr, choix_ai->ai_addrlen) < 0 ) { perror("Bind"); Error_Quit ("Couldn't bind listening socket."); } /* Make socket a listening socket */ if ( listen (listener, LISTENQ) < 0 ) Error_Quit ("Call to listen failed."); int flags = fcntl(listener, F_GETFL ); fcntl(listener, F_SETFL, flags | O_NONBLOCK ); freeaddrinfo(list_addr); /* Diverses initialisations */ XHCP_customWelcomeMessage (); /* L'initialisation est terminée, on passe à la suite */ XHCP_running_status = XHCPstate_waitConnect; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitConnect): /* Wait for connection */ if ( (conn = accept (listener, NULL, NULL)) < 0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } //Gestion du timeout pour la bascule en mode commande gettimeofday(&time_conn, NULL); //XHCP_running_status = XHCPstate_waitCommand; XHCP_running_status = XHCPstate_waitHTTPRequest; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitHTTPRequest): if ( (nbCar = recv(conn, buffer, MAX_REQ_LINE - 1, MSG_DONTWAIT)) <0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { //TODO Gestion du timeout gettimeofday(&time_resp, NULL); if ( timerdiff(&time_conn, &time_resp) > 100000 ) { // On passe en mode "Commande" XHCP_running_status = XHCPstate_waitCommand; XHCP_printXHCPResponse (conn, RES_HALWELCOM ); // Petit message de bienvenue } return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } buffer[nbCar]='\0'; /* We suppress all extra characters */ Trim (buffer, 0); processHttpRequest(conn, buffer); if ( close (conn) < 0 ) Error_Quit ("Error closing connection socket in parent."); XHCP_running_status = XHCPstate_waitConnect; return XHCP_running_status; /* ------------------------------------------------------------------------ */ case (XHCPstate_waitCommand): if ( (nbCar = recv(conn, buffer, MAX_REQ_LINE - 1, MSG_DONTWAIT)) <0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { //TODO Gestion du timeout return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } buffer[nbCar]='\0'; Trim (buffer, 0); // We suppress all extra characters if ( buffer[0] == '\0' ) return XHCP_running_status; // We continue.... printf ("Ligne lue : %s\n", buffer); cut_Line (buffer, &argc, argv); printf ("%d arguments :\n", argc); int i; for ( i=0; i<argc; i++ ) printf ( "%d - %s\n", i, argv[i]); status = exec_Line (conn, argc, argv ); // We compute the line... printf("Ligne executee, statut = %d\n",status); switch (status) { case -1: // deconnexion XHCP_running_status = XHCPstate_endConnect; return XHCP_running_status; break; case 0: // Fin de la commande return XHCP_running_status; break; // default : // On continue } XHCP_running_status = XHCPstate_waitData; /* No break, we continue !!!*/ /* ------------------------------------------------------------------------ */ case (XHCPstate_waitData): if ( (nbCar = recv(conn, buffer, MAX_REQ_LINE - 1, MSG_DONTWAIT)) <0 ) { if ( (errno == EWOULDBLOCK) || (errno == EAGAIN) ) { //TODO Gestion du timeout return XHCP_running_status; } else Error_Quit ("Error calling accept()"); } buffer[nbCar]='\0'; /* We suppress all extra characters on the right except '.' and '>' */ Trim (buffer, 1); /* The handler is activate, so all lignes are added in buffer */ if ( buffer[0] == '.' && buffer[1] == '\0') { additionalDataHandler (conn, argc, argv, additionalDataBuffer ); additionalDataHandler = NULL; free (additionalDataBuffer); additionalDataBuffer = NULL; XHCP_running_status = XHCPstate_waitCommand; } else { additionalDataBuffer = addBuffer (additionalDataBuffer, buffer); } break; /* ------------------------------------------------------------------------ */ case (XHCPstate_endConnect): XHCP_printXHCPResponse (conn, RES_CLOCONBYE ); if ( close (conn) < 0 ) Error_Quit ("Error closing connection socket in parent."); XHCP_running_status = XHCPstate_waitConnect; //default : /* (XHCPstate_death) */ /* Do nothing ... */ } return XHCP_running_status; }