prova_simplesso.c
/* Copyright (C) 2003 by Gionata Massi */
/*
* Compilare con:
*
* $ gcc prova_simplesso.c -o prova_simplesso
*
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#define PORT 80
#define MAXMSG 65536
#define POST_SIZE 4096
#define MSG_SIZE 4096
void init_sockaddr (struct sockaddr_in *name, // inizializza il socket
const char *hostname,
uint16_t port);
void write_to_server (int filede, // scrive il msg al socket
char *msg);
int read_from_socket (int filedes, // copia da socket a file
char *outfile);
char *mappa (char token); // converte i simboli speciali
char *enc (char *string); // stringa codificata
int create_msg (char *msg, // crea il msg da file
char *SERVERHOST,
char *URL,
char *file_to_parse);
void usage(char *prg_name); // regole d'utilizzo
/* variabile globale */
char *date;
int
main (int argc, char **argv)
{
int sock;
struct sockaddr_in servername;
char msg[MSG_SIZE], *SERVERHOST=argv[1], *URL=argv[2], *FILENAME=argv[3];
time_t local_time;
if (argc != 4) {
usage(argv[0]);
exit(1);
}
local_time = time (NULL);
date = ctime (&local_time);
date[strlen (date)-1]='\0';
/* Cambiamo i descrittori standard */
if (! freopen ("log/request_log", "a", stdout)) {
fprintf(stderr,"[%s] Non riesco a redirigere lo stdout.\n", date);
/* exit (EXIT_FAILURE); */
}
if (! freopen ("log/error_log", "a", stderr)) {
fprintf(stderr,"[%s] Non riesco a redirigere lo stderr.\n", date);
/* exit (EXIT_FAILURE); */
}
/* Create the message */
if (! (create_msg (msg, SERVERHOST, URL, FILENAME))) {
fprintf(stderr,"[%s] Parse error", date);
exit (EXIT_FAILURE);
}
fprintf (stdout, "####################### BEGIN [%s] #######################\n", date);
fprintf (stdout, "==> Richiesta al web server: <==\n\n%s", msg);
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror ("socket");
exit (EXIT_FAILURE);
}
/* Connect to the server. */
init_sockaddr (&servername, SERVERHOST, PORT);
if (0 > connect (sock,
(struct sockaddr *) &servername,
sizeof (servername)))
{
perror ("connect");
exit (EXIT_FAILURE);
}
/* Send data to the server. */
write_to_server (sock, msg);
/* Receive data to the server. */
read_from_socket (sock, strcat (FILENAME, ".html"));
close (sock);
fprintf (stdout, "######################## END [%s] ########################\n\n", date);
exit (EXIT_SUCCESS);
}
void
init_sockaddr (struct sockaddr_in *name,
const char *hostname,
uint16_t port)
{
struct hostent *hostinfo;
name->sin_family = AF_INET;
name->sin_port = htons (port);
hostinfo = gethostbyname (hostname);
if (hostinfo == NULL)
{
fprintf (stderr, "[%s] Unknown host %s.\n", date, hostname);
exit (EXIT_FAILURE);
}
name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
}
void
write_to_server (int filedes, char *msg)
{
int nbytes;
nbytes = write (filedes, msg, strlen (msg) + 1);
if (nbytes < 0)
{
perror ("write");
exit (EXIT_FAILURE);
}
}
int
read_from_socket (int filedes, char *outfile)
{
char buffer[MAXMSG], *html;
int nbytes;
FILE *output;
nbytes = read (filedes, buffer, MAXMSG);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else {
/* In fondo al buffer mettiamo uno '\0`, che probabilmente e' ridondante */
buffer[nbytes] = '\0';
/* Se il file di ouptput gia' esiste CANCELLALO */
remove (outfile);
/* Data read. */
output = /*popen ("less ", "w");*/ fopen (outfile ,"w");
if (!output) {
fprintf (stderr,
"\n\n[%s] Non riesco ad aprire '%s`.\n", date, outfile);
return EXIT_FAILURE;
}
if (chmod (outfile, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH))
{
fprintf (stderr,
"\n\n[%s] Non riesco ad settare i permessi di '%s`.\n", date, outfile);
return EXIT_FAILURE;
}
/* controlla che il codice di risposta sia "200 OK" */
if (! strstr (buffer, "200 OK"))
/* cerca "Content-Length: " e scan ("%d", &len); */
/* html = strstr (buffer, "Content-Length: ");
* {
* if (html) {
* html += strlen ("Content-Length: ");
* sscanf (html, "%d", &len);
*}else
* len = -1;
*} else
* len = -1;
*/
fprintf (stderr, "\n\n[%s] Il web server non e' in grado di trovare o generare la pagina.\n", date);
fprintf (stdout, "\n\n==> Header inviati dal web server: <==\n\n");
html = buffer;
/* fino a "\r\n\r\n" si tratta di header */
while (strncasecmp (html, "\r\n\r\n", 4) && html[0]) {
putchar (html[0]);
html++;
}
for (nbytes=0; nbytes<4 && html[0]; nbytes++, html++)
/*putchar (html[0])*/;
fprintf (stdout, "\n\n==> Scrittura del file %s. <==\n", outfile);
/* fprintf (output, "%s", html); */
while (/*len-- &&*/ html[0]) {
fputc (html[0], output);
html++;
}
if (/*pclose (output)*/ fclose (output) != 0)
{
fprintf (stderr,
/*"[%s] Could not run more or other error.\n", date*/
"\n\nNon riesco a chiudere '%s`.\n", outfile);
}
}
return EXIT_SUCCESS;
}
char *
mappa (char token)
{
char *str;
/* '<' == 3C;'=' == 3D; '>' == 3E; */
if (token == '<')
return "%3C";
if (token == '=')
return "%3D";
if (token == '>')
return "%3E";
if (token == '/')
return "%2F";
str = calloc (2, 1);
str[0] = token;
return str;
}
char *
enc (char *string)
/* codifica string */
{
char *tmp;
int len, i;
len = strlen (string);
tmp = calloc (1, 5*len);
if (tmp == NULL)
exit (EXIT_FAILURE);
for (i=0; i<len; i++)
strcat (tmp, mappa (string[i]));
return tmp;
}
/* Crea il messaggio in POST */
int
create_msg (char *msg, char *SERVERHOST, char *URL, char *file_to_parse)
{
FILE *fp;
struct stat f;
char *string_to_parse, post[POST_SIZE], tmp[512], *token;
const char delimiters[] = " =,\t\n";
const char subdelimiters[] = " ,\t\n";
int uscita, riga;
/* Apre il file con il problema */
if ((fp = fopen(file_to_parse, "r")) == NULL) {
fprintf(stderr, "[%s] Impossibile aprire il file '%s`\n", date, file_to_parse);
exit (EXIT_FAILURE);
}
if (fstat (fileno(fp), &f) < 0) {
perror("stat");
exit(EXIT_FAILURE);
}
/* Copia il file da processare in una stringa */
if (! (string_to_parse = (char *)malloc (f.st_size))) {
perror("memory");
exit(EXIT_FAILURE);
}
fread (string_to_parse, 1, f.st_size, fp);
fclose (fp);
post[0] = '\0';
token = strtok (string_to_parse, delimiters);
while ( token != NULL ) {
if (! strncasecmp ("#", token, 1)) // commento fino al prossimo #
token = strtok (NULL, "#");
if (! strcasecmp ("minmax", token)) { // minmax (intero)
token = strtok (NULL, delimiters);
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected 'min' or 'max' after 'minmax = '\n", date);
exit(EXIT_FAILURE);
}
sprintf (tmp, "minmax=%s&", token);
strcat ( post, tmp);
} else if (! strcasecmp ("numConstraints", token)) { // numConstraints (intero)
token = strtok (NULL, delimiters);
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after 'numConstraints = '\n", date);
exit(EXIT_FAILURE);
}
sprintf (tmp, "numConstraints=%d&", atoi(token));
strcat (post, tmp);
} else if (! strcasecmp ("numVariables", token)) { // numVariables (intero)
token = strtok (NULL, delimiters);
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after 'numVariables = '\n", date);
exit(EXIT_FAILURE);
}
sprintf (tmp, "numVariables=%d&", atoi(token));
strcat (post, tmp);
} else if (! strcasecmp ("intera", token)) { // intera (stringa)
token = strtok (NULL, delimiters);
if (! strcasecmp ("true", token))
strcat ( post, "intera=true&");
else
strcat ( post, "intera=false&");
} else if (! strcasecmp ("d", token)) { // d (frazione)
token = strtok (NULL, delimiters);
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after 'd = '\n", date);
exit(EXIT_FAILURE);
}
sprintf (tmp, "d=%s&", enc(token));
strcat (post, tmp);
} else if (! strcasecmp ("c", token)) { // c (frazione)
token = strtok (NULL, delimiters);
// prima un "["
if ( strcasecmp (token, "[")) {
fprintf (stderr, "[%s] Parse error: expected '[ ' after 'c = '\n", date);
exit(EXIT_FAILURE);
}
token = strtok (NULL, delimiters);
uscita = 1;
while ( token != NULL && uscita != 0 ) {
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after '[ '\n", date);
exit(EXIT_FAILURE);
} else if (! strcasecmp (token, "]"))
uscita = 0;
else {
sprintf (tmp, "c%%5B%d%%5D=%s&", uscita, enc(token));
strcat (post, tmp);
token = strtok (NULL, delimiters);
uscita++;
}
}
} else if (! strcasecmp ("b", token)) { // b (frazione)
token = strtok (NULL, delimiters);
// prima un "["
if ( strcasecmp (token, "[")) {
fprintf (stderr, "[%s] Parse error: expected '[ ' after 'b = '\n", date);
exit(EXIT_FAILURE);
}
token = strtok (NULL, delimiters);
uscita = 1;
while ( token != NULL && uscita != 0 ) {
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after '[ '\n", date);
exit(EXIT_FAILURE);
} else if (! strcasecmp (token, "]"))
uscita = 0;
else {
sprintf (tmp, "b%%5B%d%%5D=%s&", uscita, enc(token));
strcat (post, tmp);
token = strtok (NULL, delimiters);
uscita++;
}
}
} else if (! strcasecmp ("lge", token)) { // lge ("=, =<, >=")
token = strtok (NULL, delimiters);
// prima un "["
if ( strcasecmp (token, "[")) {
fprintf (stderr, "[%s] Parse error: expected '[ ' after 'lge = '\n", date);
exit(EXIT_FAILURE);
}
token = strtok (NULL, subdelimiters);
uscita = 1;
while ( token != NULL && uscita != 0 ) {
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# after '[ '\n", date);
exit(EXIT_FAILURE);
} else if (! strcasecmp (token, "]"))
uscita = 0;
else {
sprintf (tmp, "lge%%5B%d%%5D=%s&", uscita, enc(token));
strcat (post, tmp);
token = strtok (NULL, subdelimiters);
uscita++;
}
}
} else if (! strcasecmp ("a", token)) { // a (frazione)
token = strtok (NULL, delimiters);
// prima un "["
if ( strcasecmp (token, "[")) {
fprintf (stderr, "[%s] Parse error: expected '[ ' after 'a = '\n", date);
exit(EXIT_FAILURE);
}
token = strtok (NULL, delimiters);
uscita = 1;
riga= 1;
while ( token != NULL && uscita != 0 ) {
if (token == NULL) {
fprintf (stderr, "[%s] Parse error: expected #num# or ' ; ' after '[ '\n", date);
exit(EXIT_FAILURE);
} else if (! strcasecmp (token, "]"))
uscita = 0;
else if (! strcasecmp (token, ";")) {
riga++;
uscita = 1;
token = strtok (NULL, delimiters);
} else {
sprintf (tmp, "a%%5B%d%%5D%%5B%d%%5D=%s&", riga, uscita, enc(token));
strcat (post, tmp);
token = strtok (NULL, delimiters);
uscita++;
}
}
}
/* avanza al prossimo token */
token = strtok (NULL, delimiters);
}
/* rimuovi l'ultimo '&' */
strcat (post, "name=");
strcat (post, file_to_parse);
/* iniziamo il messaggio */
strcpy (msg, "POST ");
strcat (msg, URL);
strcat (msg, " HTTP/1.0\r\n");
strcat (msg, "Connection: close\r\n");
strcat (msg, "User-Agent: Nemo (by gim)\r\n");
// strcat (msg, "Referer: \r\n");
strcat (msg, "Pragma: no-cache\r\n");
strcat (msg, "Cache-control: no-cache\r\n");
strcat (msg, "Accept: text/*, image/jpeg, image/png, image/*, */*\r\n");
// strcat (msg, "Accept-Encoding: x-gzip, x-deflate, gzip, deflate, identity\r\n");
strcat (msg, "Accept-Charset: iso-8859-1, iso-8859-15, utf-8;q=0.5, *;q=0.5\r\n");
strcat (msg, "Accept-Language: it, en\r\n");
strcat (msg, "Host: ");
strcat (msg, SERVERHOST);
strcat (msg, "\r\n");
strcat (msg, "Content-Type: application/x-www-form-urlencoded\r\n");
sprintf (tmp, "Content-Length: %d\r\n\r\n", strlen(post));
strcat (msg, tmp);
strcat (msg, post);
free (string_to_parse);
free (post);
return 1;
}
/* Riepilogo sull'uso del programma */
void
usage(char *prg_name)
{
fprintf(stderr, "Uso: %s [server_host] [url] [input_file]\n", prg_name);
}
/* Sintassi per il parser:
COMMENTI:
definiti fra due cancelletti
esempio:
# questo e' un commento valido #
#anche
questo#
# questo non funziona perche' non ha termine
ASSEGNAMENTI:
keyword = value_in_keyword_range
KEYWORD e relativi tipi:
minmax ==> stringa con valore in {"min", "max}
numConstrints ==> intero
numVariables ==> intero
intera ==> stringa con valore in {"true", "false"}
a
b
c
d
lge
Il file per generare una richiesta valida deve contenere TUTTE le stringhe keyword.
Uno strano esempio di file corrispondente alle regole grammaticali e'
il seguente:
#######################################################
## #
## Test sulla sintassi accettata da prova_simplesso #
## #
#######################################################
#
# commento semplice su una riga #
#
commento che occupa
piu' di una riga
#
### ancora un commento valido #
# le stringhe a sinistra del simbolo '=' sono CASE INSENSITIVE #
MinMax = max
Numvariables = 2
numconstraints = 3
INTERA = true
#
i ritorni a capo '\n' contenuti fra '[' e `]`vengono ignorati
e il punto e virgola ';' rimane necessario per separare le rghe
della matrice 'a'
#
### i commenti non sono validi all'interno delle quadre #
C = [ 2 1 ]
d = 0
A = [ 1 -2 ;
-3 1 ;
1 1 ]
b = [ 2 3 4 ]
lge = [ =<
=<
=< ]
*/