Linux за българи: Форуми

Програмиране => Конкурс bash-майсторът => Темата е започната от: BULFON в Sep 11, 2007, 13:58



Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 11, 2007, 13:58
Да се напише скрипт (скриптове, програми), които работят като web service. Т.е. "слушат" на някой порт за заявка (HTTP) и отговарят. Целта е произведеното от тях да може лесно да бъде консумирано от различни други уеб услуги или сайтове.
В случая може да се ползва директно изхода от програми като fortune, рибата в гном или всякакви такива. Може и да работи с MySQL база данни с вицове за Чапай и Петка (някой има ли такава база). Изходът е добре да може да се избира - дали да е text/plain, applications/json (JSON - формат), application/xml. Сигурност не е нужна, но ако се реализира някаква схема за изибирателен достъп ще е плюс, за да не се закачат много маймуни. Логване на заявките също ще е добре да има.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 11, 2007, 14:24
Мамка му :(

Разширете малко срока, бе хора :(

С 2-3 дена
:)

На 15 си кацам в София и ще мога да се включа :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 11, 2007, 14:45
Заради нашия редовен участник, конкура се удължен до 19ти :).


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 11, 2007, 15:07
Е хубаво, ако едно участие е редовно :)

Много обичам да пиша сокет приложения на С, всъщност всичко което пратя ще бъде или на С или на PHP, шел скиптовете не са ми особено голяма сила :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 11, 2007, 15:24
Цитат (gat3way @ Сеп. 11 2007,15:07)
Е хубаво, ако едно участие е редовно :)

1/1 са си цели 100% ;)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 11, 2007, 15:34
:D


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 11, 2007, 17:01
FIRST!

pwww.pl
Примерен код

#!/usr/bin/perl -w
package WWWServer;

use Sys::Syslog;      
use base qw(Net::Server::Fork);
@ISA = qw(Net::Server::Fork);

our @acceptedTypes = ('text/html', 'applications/json', 'application/xml', );

sub process_request
{
    my $self = shift;
    my $service = 0;
    my $type = $acceptedTypes[0];


    while (<STDIN>)
    {
        s/\r?\n$//;

        if (m/GET \/(\w+) HTTP\/(1.1|1.0)/i)
        {
            if ($1 eq 'time')
            {
                syslog("info", "Service request: TIME");
                $service = 1;
            }
            elsif ($1 eq 'fortune')
            {
                syslog("info", "Service request: FORTUNE");
                $service = 2;
            }
            else
            {
                syslog("info", "Service not found");
            }
        }
        if (m/Accept:\s+\w+/i)
        {
            foreach my $accepted_type (@acceptedTypes)
            {
                if (/$accepted_type/)
                {
                    $type = $accepted_type;
                    last;
                }
            }
        }
        if ($_ eq '')
        {
            last;
        }
    }
    if ($service)
    {
        print "HTTP/1.1 200 OK\r\n";
        print "Content-Type: $type\r\n";
        print "Server: PWWW Server\r\n";
        print "Connection: close\r\n";
        print "\r\n";
        if ($service == 1)
        {
            print `/usr/bin/date`."\r\n";
        }
        elsif ($service == 2)
        {
            print `/usr/games/fortune`."\r\n";
        }
    }
    else
    {
        print "HTTP/1.1 400 Bad Request\r\n";
        print "Server: PWWW Server\r\n";
        print "Connection: close\r\n";
        print "\r\n";
        print "Not implemented.";
    }
}

my $server  = new WWWServer({conf_file => 'pwww.conf',});

$server->run();


pwww.conf
Примерен код

user            www
group           www

log_file        Sys::Syslog
log_level       4
syslog_logopt   pid,ndelay,nowait
syslog_ident    pwww

pid_file        pwww.pid

port            160
host            *

cidr_allow    192.168.0.0/16
cidr_allow    10.10.0.0/16
cidr_deny    192.168.1.0/24

background      1
setsid          1



EDIT: Малка грешка за content-type-a :)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: Hapkoc в Sep 11, 2007, 17:16
Примерен код

$ cat shttpd.sh
#! /bin/bash

### http functions

function send_response_headers {
        code="$1"

        # access logging
        code_num=$(echo $code | cut -d' ' -f1)
        date=$(date '+[%d/%b/%Y:%T %z]')
        echo "$REMOTE_HOST - - $date \"$method $url $proto\" $code_num 0 \"$referer\" \"$user_agent\"" >> /var/log/shttpd/access_log

        echo "HTTP/1.0 $code"
        echo "Date: " $(date -uR | sed -e 's/+0000/GMT/')
        echo "Connection: close"
        echo "Content-type: text/plain; charset=utf-8"
        echo "Server: shttpd"
        echo ""
}

### main program

method=""
url=""
proto=""
referer=""
user_agent=""

line_no=1
while read line; do
        # clean up ending ^M
        line=$(echo $line | head --bytes=-2)

        # check if this is the last header
        echo "$line" | grep -E '^\s*$' >/dev/null 2>&1 && break

        # get the request line
        if [ "$line_no" -eq 1 ]; then
                method=$(echo "$line" | awk '{ print $1 }')
                url=$(echo "$line" | awk '{ print $2 }')
                proto=$(echo "$line" | awk '{ print $3 }')
        # check the headers
        else
                header=$(echo "$line" | cut -d' ' -f1)
                header_contents=$(echo "$line" | cut -d' ' -f2-)

                case "$header" in
                        Referer:*) referer="$header_contents";;
                        User-Agent:*) user_agent="$header_contents";;
                        *);;
                esac
        fi

        let line_no=$((line_no + 1))
done

# verify whether the access is allowed
if [ -r "/etc/shttpd.d/access_list" ]; then
        grep -E "^$REMOTE_HOST$" /etc/shttpd.d/access_list >/dev/null 2>&1 || {
                send_response_headers "403 Forbidden"
                echo "403 Forbidden"
                exit
        }
fi

# verify the method and url
if [ -z "$method" ] || [ -z "$url" ]; then
        send_response_headers "400 Bad Request"
        echo "400 Bad Request"
fi

# send the reply
case "$method" in
        "GET" | "POST")
                send_response_headers "200 OK"
                /usr/games/fortune
                ;;
        "HEAD")
                send_response_headers "200 OK"
                ;;
        *)
                send_response_headers "405 Method Not Allowed"
                echo "405 Method Not Allowed"
                ;;
esac

exit




Примерен код

# cat /etc/xinetd.d/shttpd
service www
{
        type            = UNLISTED
        disable         = no
        socket_type     = stream
        protocol        = tcp
        port            = 8081
        wait            = no
        user            = nobody
        group           = nogroup
        server          = /usr/local/bin/shttpd.sh
}


В /etc/shttpd.d/access_list се описват IP адресите, които могат да достъпват нещото. /var/log/shttpd/access_log е (както подсказва името) access log-а. :)

Не гарантирам за пълно спазване на HTTP/1.1. :)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: the_real_maniac в Sep 11, 2007, 21:36
Цитат (VladSun @ Сеп. 11 2007,18:01)
FIRST!

offtopic:

Примерен код

F U C K !


 :D  :D  :D  :D  :p  B)  :D  :D

http://www.linux-bg.org/cgi-bin....t=20656





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 12, 2007, 02:53
Цитат (the_real_maniac @ Сеп. 11 2007,21:36)
Цитат на: VladSun,Сеп. 11 2007,18:01
FIRST!

offtopic:

Примерен код

F U C K !


 :D  :D  :D  :D  :p  B)  :D  :D

http://www.linux-bg.org/cgi-bin....t=20656хахаххахаха - първият досетил се - имаш една бира от мен ;)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: cvludmiloff в Sep 12, 2007, 11:28
quotes.py

Примерен код

import BaseHTTPServer
import sys
import re
import random

class SimpleDispatchHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    cleanse_re = re.compile('\W')

    # -----------------------------------------------

    def do_GET(self):
        """
        The main dispatcher.
        Assumes the first part of the url is the method to call and the subsequent parts are parameters for the method.
        For example, "http://localhost:8000/test/a/b/c"
        would invoke self.method_test() passing it the list ['a', 'b', 'c']
        """
        path = self.path.split('/')
        method = path[1]
        method = self.cleanse_re.sub('',method)
        method_imp = None

        try:
            method_impl = getattr(self, "method_"+method)
        except Exception, e:
            self.send_error( 404 )
            self.wfile.write( "<br/ ><b>Method unknown [" + method + "]</b>\n" )
            return

        try:
            method_impl( path[2:] )
        except Exception, e:
            self.send_error( 500 )
            self.wfile.write( "<br/ ><b>Error in method [" + method + "]: " + str(e) + "</b>\n" )

        return

    # -----------------------------------------------

    def html( self ):
        """
        Sends the appropriate headers to indicate html output
        """
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

    def fortunes(self, infile):
        """ Yield fortunes as lists of lines """
        result = []
        for line in infile:
            if line == "%\n":
                yield result
                result = []
            else:
                result.append(line)
        if result:
            yield result

    def findfortune(self, filename):
        """ Pick a random fortune from a file """
        for index, fortune in enumerate(self.fortunes(file(filename))):
            if random.random() < (1.0 / (index+1)):
                chosen = fortune

        return "".join(chosen)

    # -----------------------------------------------

    def method_fortune( self, params ):
        """
        Test method, included only to show how custom methods would be created.
        """
        self.html()
        if len(params) == 0:
            params = ['/usr/share/games/fortunes/fortunes',]
        text = self.findfortune(params[0])
        self.wfile.write(text)
        self.wfile.write( "<br /><br />Here are the parameters: " + str(params) + "<br />")

PORT = 8000
httpd = BaseHTTPServer.HTTPServer(("", PORT), SimpleDispatchHandler)
print "serving at port", PORT
httpd.serve_forever()    


стартира се:
python quotes.py

от браузер: http://localhost:8000/fortune





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: zeridon в Sep 15, 2007, 10:22
VladSun бих препоръчал изхода да се загради в някакви разделители (от гледна точка на по добро парсене от външен софт)

Иначе до момента всичките предложения ми изглеждат читави :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: paranoid в Sep 15, 2007, 13:59
Според мен, условието не е зададено правилно, защото доколкото знам уеб-сървисите работят на основата на SOAP протокола, а доколкото видях нищо такова не се казваше в условието. Освен това къде е изискването за WSDL?


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 15, 2007, 14:50
@zeridon - по-скоро трябва да си оправя изхода в контекста на content-type-a, ама реших, че това трябва да е проблем на `fortune` ;)  :p


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: task_struct в Sep 16, 2007, 10:17
Ето и моя вариант:
Примерен код

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <pwd.h>

#define _GNU_SOURCE
#include <getopt.h>

#define DEFAULT_PORT 1987
#define DEFAULT_USER "nikolay"
#define LOGFILE "/home/nikolay/access_log"
#define BACKLOG 5

int sockfd, sockfd_new; /* дескриптори на гнезда */

void sisd_log(char *fmt, ...)
{
     va_list args;
     char buffer[128];
     FILE *logfd;

     if((logfd = fopen(LOGFILE, "a")) == 0) {
          fclose(logfd);
          exit(1);
     }

     va_start(args, fmt);
     vsprintf(buffer, fmt, args);
     va_end(args);

     fprintf(logfd, buffer);

     fclose(logfd);

}

void p_error(char error[], int errnum, int how)
{
     sisd_log("%s error #%d\n", errno, errnum);

     if(how == 0)
          exit(2);
     if(how == 1) {
          close(sockfd);
          exit(3);
     }
     if(how == 2) return;
     if(how == 3) {
          shutdown(sockfd_new, 2);
          close(sockfd_new);
          return;
     }
     if(how == 4) {
          shutdown(sockfd_new, 2);
          close(sockfd_new);
          usleep(100);
          exit(4);
     }
}

void process(FILE *f, char *cl)
{
     time_t now;
     char timebuf[128];

     fprintf(f, "HTTP/1.1 200 OK\r\n");
     fprintf(f, "Server: SIS\r\n");
     now = time(NULL);
     strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now));
     fprintf(f, "Date: %s\r\n", timebuf);
     fprintf(f, "Content-Type: text/html\r\n");
     fprintf(f, "Connection: close\r\n");
     fprintf(f, "\r\n");
     fprintf(f, "<html><head><title>SISD</title></head><body>");

     FILE *read_fp;
     char buf[BUFSIZ];

     memset(buf, '\0', sizeof(buf));
     read_fp = popen("fortune", "r");
     if(read_fp != NULL) {
          fread(buf, sizeof(buf), 1, read_fp);
          pclose(read_fp);
          fprintf(f, buf);
     }
     else {
          fprintf(f, "Error!");
     }
     memset(buf, '\0', sizeof(buf));

     fprintf(f, "</body></html>");

     sisd_log("Connection from %s at %s\n", cl, timebuf);
}

int main(int argc, char *argv[])
{
     int opt;
     int port = -1;
     char user[21] = "\n", logfile[256] = "\n";
     struct option opts[] = {
          {"port", 2, NULL, 'p'},
          {"username", 2, NULL, 'u'},
          {"logfile", 2, NULL, 'l'},
          {"version", 0, NULL, 'v'},
          {"help", 0, NULL, 'h'}};

     /*************************************************/
     /* обработване на входните параметри */
     /************************************************/
     while((opt = getopt_long(argc, argv, "p:u:l:vh", opts, NULL)) != -1) {
          switch(opt) {
               case 'p': {
                    if(optarg) {
                         port = (int)optarg;
                    }
                    else {
                         port = DEFAULT_PORT;
                    }
                    break;
               }
               case 'u': {
                    if(optarg) {
                         strncpy(user, optarg, 20);
                    }
                    else {
                         strcpy(user, DEFAULT_USER);
                    }
                    break;
               }
               case 'l': {
                    if(optarg) {
                         strncpy(logfile, optarg, 255);
                    }
                    else {
                         strcpy(logfile, LOGFILE);
                    }
                    break;
               }
               case 'v': {
                    printf("Simple Info Server deamon (SISD) 1.0\n");
                    return 0;
               }
               case 'h': {
                    printf("Simple Info Server deamon (SISD) 1.0\n");
                    printf("Server provides system information in text/html format.\n");
                    printf("Nikolay Stefanov 2007\n");
                    return 1;
               }
               case ':': {
                    printf("Option %s needs a value\n", optarg);
                    return 1;
               }
               case '?': {
                    printf("Unknown option: %c\n", optopt);
                    return 2;
               }
          }
     }

     /* ако не са зададени опции p,u,l */
     if(port == -1) {
          port = DEFAULT_PORT;
     }

     if(strcmp(user, "\n") == 0) {
          strcpy(user, DEFAULT_USER);
     }

     if(strcmp(logfile, "\n") == 0) {
          strcpy(logfile, LOGFILE);
     }

     /****************************************************************/
     /* Настройване на сървъра за работа като deamon */
     /***************************************************************/
     struct passwd *usr = getpwnam(user);

     printf("Starting deamon as %s(%d:%d) at port: %d ...\n", user, usr->pw_uid, usr->pw_gid, htons(port));
     /* затварят се всички отворени файлове */
     int i;
     for(i=0; i<NOFILE; i++)
          close(i);
     /* стартира се нова сесия */
     switch(fork()) {
          case -1: p_error("First fork()", errno, 0);
          default: exit(0);
          case 0: { /* първо дете стартира нова сесия */
               if(setsid() == -1) /* детето става лидер на новата сесия */
                    p_error("setsid()", errno, 0);
               if(setuid(usr->pw_uid) == -1)
                    p_error("setuid()", errno, 0);
               if(setgid(usr->pw_gid) == -1)
                    p_error("setgid()", errno, 0);
               switch(fork()) { /* второ пораждане на дете */
                    case -1: p_error("Second fork()", errno, 0);
                    case 0: umask(0); break; /* второто дете не е лидер на сесия */
                    default: exit(0); /* завършва втория родител (първо дете) */
               }
          }
     }

     sigset(SIGCHLD, SIG_IGN); /* сигнала се игнорира за да няма зомбита */

     /* създава се потоково гнездо */
     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
          p_error("Could not create socket", errno, 0);

     struct sockaddr_in addr, client_addr;
     socklen_t addrlen;
     int flags;

     memset(&addr, 0, sizeof(addr));
     memset(&client_addr, 0, sizeof(client_addr));

     addr.sin_family = AF_INET;
     addr.sin_port = htons(port);
     addr.sin_addr.s_addr = INADDR_ANY;

     /* присвоява се адрес на гнездото */
     if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
          p_error("bind()", errno, 1);

     /* подготовка на гнездото за приемане на заявки */
     if(listen(sockfd, BACKLOG) == -1)
          p_error("listen()", errno, 1);
     if((flags = fcntl(sockfd, F_GETFL)) == -1 || fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK) == -1) /* блокира до пристигане на заявката */
          p_error("fcntl()", errno, 1);

     /* получаване и обслужване на клиентски заявки */
     for(;;) {
          addrlen = sizeof(client_addr);
          
          /* ново гнездо и установяване на връзка с гнездо на клиент */
          if((sockfd_new = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen)) < 0) {
               p_error("accept()", errno, 2); continue;
          }
          switch(fork()) {
               case -1: p_error("fork() client", errno, 2); continue;
               case 0: {
                    FILE *f;
                    if(!(f = fdopen(sockfd_new, "r+"))) {
                         p_error("fdopen", errno, 2); continue;
                    }
                    process(f, inet_ntoa(client_addr.sin_addr));
                    fclose(f);

                    shutdown(sockfd_new, 2); /* закрива се връзката */
                    close(sockfd_new); /* новото гнездо се унищожава */
                    sleep(1); /* дава шанс на клиента да завърши успешно */
                    exit(0); /* детето завършва */
               }
          }
          close(sockfd_new); /* родител - затваря новия дескриптор */
     }
     return 0;
}


Има някой бъгчета, но това ми е първата програма със сокети която пиша :)

P.S. Мисля да напиша и един сървър на С#. Най-вероятно няма да успея да спазя срока, но да има пример и за такъв. Може пък на някой някога да му потрябва пример как НЕ се прави  :p  :D





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 15:54
Ъммм, замалко да изтърва срока бе :)

Ето я моята бъглива тъпотия:

Цитат

// blablabla
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <string.h>


// port to listen to, connection limit, maximum number of threads
#define PORT 1800
#define MAXCONN 100
#define MAXTHREADS 10
#define MAXBUF 20000 //socket buffer size

// external program
char *EXTERNAL_BIN="/usr/games/fortune";

int sd=-1; // listening socketfd

// connection table
struct contable
{
    int fd; //filedes
    unsigned long peer; //peer inet addr, unused
    char *buf; // socket buffer
    char *buf1; // mini socket buffer :)
} *ctab[MAXCONN];

int cti=1; //global connection count


// threads struct table
struct thstable
{
    int epfd; // epoll fd
    pthread_t pth; //thread
    int lock; // a primitive lock - unused
} ttab[MAXTHREADS];

int tti=MAXTHREADS; // the number of spawned threads (by default=MAXTHREADS)
struct epoll_event *ev[MAXTHREADS]; //epoll events


// remove connection from table
void conn_remove(int id, int tid)
{
    if (cti==1) {}
    if (cti>=2)
    {

// delete from events pool, close socket
        ev[tid]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
        epoll_ctl(ttab[tid].epfd,EPOLL_CTL_DEL,ctab[id]->fd, ev[tid] );
        close(ctab[id]->fd);
#ifdef DEBUG
        printf("Client fd #%d closing connection,cti=%d\n",ctab[id]->fd,cti);
#endif

//table-related bs
        ctab[id]->fd=ctab[cti]->fd;
        strcpy(ctab[id]->buf,ctab[cti]->buf);
        bzero(ctab[cti]->buf,MAXBUF);
        cti--;
    }
}


// parse request - very lame
void parse(int id, int tid)
{
    char *str=malloc(150);
    char *str1=malloc(150);
    char *buf=malloc(1024);
    FILE *outp;
    int a=0;
    pid_t pid;

// VERY VERY LAME!!!
    if ( strstr(ctab[id]->buf,"\r\n") )
        if ( (strstr(ctab[id]->buf,"text/html")) || (strstr(ctab[id]->buf,"text/html")) || (strstr(cta
b[id]->buf,"text/html")))
        {
            sprintf(str,"/var/tmp/mypr-np-%d",id);
            outp=fopen(str,"r");
            a=1;
            sprintf(str1,"%s > %s",EXTERNAL_BIN,str);

            sprintf(buf,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><head><title>%s output</title></head><body><center><b><h2>%s output:</center></h2><br><br><center><table height=100% width=
100%><tr align=center valign=top><td><table height=50% width=50% border=1><tr valign=middle align=cent
er><td bgcolor=lightyellow>\n",EXTERNAL_BIN,EXTERNAL_BIN);
            write(ctab[id]->fd,buf,strlen(buf));
            system(str1);
            usleep(1000);
            while (feof(outp)==0)
            {
                if (fgets(buf,1024,outp))
                {
                    write(ctab[id]->fd,buf,strlen(buf));
                }
            }
            close(outp);
            sprintf(buf,"</td></tr></table></td></tr></table></body></html>\n");

            conn_remove(id,tid);
        }

    free(buf);free(str);free(str1);
}


// this actually performs the socket I/O
void serve(int fd, int tid)
{
    int len,a;
    int id=0;

    // find our conntab entry
    for (a=1;a<=cti;a++) if (ctab[a]->fd==fd) id=a;
    if (id==0) {printf("Socket error?!?\n");exit(1);}
    bzero(ctab[id]->buf1,MAXBUF/10);
    // read from socket
    for (a=1;a<=100;a++)
    {
        len=read(fd,ctab[id]->buf1,MAXBUF/10);
        if (len>0) goto cont;
        usleep(1000);
    }
    cont:
    if (len>0)
    {
        strcat(ctab[id]->buf,ctab[id]->buf1);
        parse(id,tid);
    }
    // socket closed?
    if (len==0)
    {
        conn_remove(id,tid);
    }

}

// wait for socket event and transfer it to serve()
void workthread(int num)
{
    int nfds,a,b,fd;

    while (1)
    {
        out:
        nfds  = epoll_wait(ttab[num].epfd, ev[num],tti,1);
        usleep(5000);
        if (nfds < 0) {
#ifdef DEBUG
            printf("Epoll confusion, LOL! :)\n");
#endif
            goto out;
        }
        for (a=1;a<=nfds;a++)
        {
            fd=ev[num]->data.fd;
            if (fd>0) serve(fd,num);
        }
    }
}


// Another thread designed to terminate incoming connections
void listener_thread(void *arg)
{

    int a=1;
    struct timeval tv;
    int len,client;
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    int flags;

    while (1)
    {
// sleep a little
        usleep(5000);

// accept connection. fd>=4 means most certainly this is a socket fd
        client = accept(sd, (struct sockaddr*)&addr, &addrlen);
        if ((client>=4)&&(addrlen>0))
        {

// socket timeouts setting
            tv.tv_usec=5;
            tv.tv_sec=0;
            setsockopt( client, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );

// make the newly accepted socket non-blocking..
            if ((flags = fcntl(client, F_GETFL, 0)) < 0)
            {
                perror("fcntl");
            }
            if (fcntl(client, F_SETFL, flags | O_NONBLOCK) < 0)
            {
                perror("fcntl");
            }

#ifdef DEBUG
            printf("Connected: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
#endif
            if (cti == MAXCONN) {close(client);} // EXAMPLE OF BAD CONNECTION LIMIT HANDLING!!!
            else
            {
// tables & epoll bs
                if (cti>1) cti++;
                a++;
                if (a==tti) a=1;
                ctab[cti]->fd=client;
                ctab[cti]->peer=addr.sin_addr.s_addr;
                ev[a]->events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP;
                ev[a]->data.fd=client;
                epoll_ctl(ttab[a].epfd,EPOLL_CTL_ADD,client, ev[a] );
                if (cti==1) cti++;
            }
        }
    }
}


// main function
int main()
{

// socket-related vars
    struct sockaddr_in addr;
    int addrlen = sizeof(addr);
    int flags;
    struct timeval tv;
    int len,client,a;
// listener thread
    pthread_t listener;

    printf("server starting..\n");
// SIGPIPE suck in a threaded app :(
    signal( SIGPIPE , SIG_IGN );
// Init Serversocket
    if ( (sd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) perror("Socket");
    flags=1;
// Socket is to be reused (avoid stupid bind:already in use errors)
    setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags) );
// bind(), listen()
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = INADDR_ANY;

    if ( bind(sd, (struct sockaddr*)&addr, addrlen) < 0 ) {perror("bind");abort();}
    if ( listen(sd, MAXCONN) < 0 ) perror("listen");
// non-blocking server socket
    if ((flags = fcntl(sd, F_GETFL, 0)) < 0)
    {
        perror("fcntl");
    }

    if (fcntl(sd, F_SETFL, flags | O_NONBLOCK) < 0)
    {
        perror("fcntl");
    }
    printf("init threads");
// Init worker threads..
    for (a=1;a<=tti;a++)
    {
        ev[a]=malloc(300);
        pthread_create(&ttab[a].pth, NULL, workthread, a);
        ttab[a].epfd=epoll_create(MAXCONN/tti);
        ttab[a].lock=ttab[a].lock=0;
        printf(".");
    }
    printf("OK!\n");

// Init listener thread
    pthread_create(&listener, NULL, listener_thread,"");

// Init connection table..
    for (a=1;a<=MAXCONN;a++)
    {
        ctab[a]=malloc(sizeof(int)*4);
        ctab[a]->buf=malloc(MAXBUF);
        bzero(ctab[a]->buf,MAXBUF);
        ctab[a]->buf1=malloc(MAXBUF/10);
        bzero(ctab[a]->buf1,MAXBUF/10);
        ctab[a]->fd=0;
    }

// wait for listener thread to finish..
    pthread_join(listener,NULL);
    return 0;
}



Значи принципно е threaded и използва epoll, за да си се занимава със сокетите. Не се форк-ва отделен процес за всяка конекция (обаче това не е точно така с оглед на това, че се вика външна програма). Би следвало да е бързичко, пестеливо откъм ползване на РАМ и в тоя ред на мисли, да държи повече едновременни конекции, само дето не знам дали е така.

Дотук с хубавите неща :) Това е най-малоумната многонишкова програма, която съм писал (добре де, на второ място след една друга подобна). Не съм се замислял особено, но на теория е напълно възможно при повечко едновременно работещи нишки да се случат лоши неща и програмата да се сбъгяса или крашне (например да се опита да изпише резултата вместо където трябва, в току-що затворен сокет :) ). Отделно, parse-ването на заявката е левашко и глупаво.

И накрая, програмата използва libpthread (компилира се с флаг -lpthread) . Използва epoll като механизъм за poll-ване на сокетите за нови събития. Това е много хубаво нещо, само дето съществува от 2.6 насам, за всички със стари ядра, съжалявам, няма как да го компилирате :(  Идеята е една нишка или процес да може да сервира някакъв брой конекции едновременно, да не се налага да се форк-ват нови такива за всяка нова, защото това е огромно разхищение. За да стане това, има два варианта за poll-ване на сокетите - select() и epoll_wait(). select е по-универсален, но се базира на обхождане на един свързан списък, и е доказано тромав :) Важното при тоя подход обаче е сокетите да са non-blocking, в противен случай занятието придобива малко идиотски измерения :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 18, 2007, 17:55
А къде искате да се видим утре в 19.30?


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 18, 2007, 17:59
Цитат (BULFON @ Сеп. 18 2007,17:55)
А къде искате да се видим утре в 19.30?

Аз мислех, че вече е уговорено ... както обикновено - в "Кривото" на ул. Будапеща?

Ама, ако решите нещо друго - няма проблеми :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 18:32
Забелязвам сериозен overdesign и в двете решения на C. Keep it simple, stupid.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 18:40
yup, KISS е хубав принцип, ама когато си си планирал нещата като хората. За има-няма половин ден занимания, толкова. Както вече споделих с един друг участник :) на средата вече псувах много лошо задето съм се захванал да правя тая глупост по тоя начин.Нещо се бях обсебил от няколко идеи, добре че изтърпях до края :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 19:14
gateway,

Например процес (или ако много държиш тред) за връзка опростява много решението без да е ужасно неефективно. Все пак това е задача, не код за production, най-важното е прегледността, а не оптимизацията.

Има един програмист дето разправя, че твърде ранното оптимизиране било коренът на всички злини в програмирането...


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 19:18
Процесът да.

Нишката не.

Не че ми пука особено, щото не съм си играл да правя никакъв locking. Ама когато имаш няколко нишки дето барат обща заделена памет, общи файлови дескриптори и общи променливи, вероятностите за race conditions не са никак малки.

Процесите поне не си споделят толкова неща между родителя и "детето", там не се налага да мислиш особено за такива подробности.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 19:21
Кой е казал, че нишките ще използват общи променливи? Всяка нишка си получава сокета, пуска fortune, праща и затваря...


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 19:30
...в това време нишката все някъде среща block-ваща функция и task scheduler-a пали некоя друга нишка. Все пак не мисля да пиша 100 отделни функции за 100 отделни нишки, които правят в общи линии едно и също, само че върху различен дескриптор. Вторият thread променя стойността на някакъв прост брояч и също заспива в един момент. Scheduler-a подкарва отново първата нишка, която пък точно се намирала в някакъв цикъл, зависещ от същият този, сега "променен" брояч. И да речем става някаква малка или голяма беля, в зависимост от случая.

Това е само един възможен сценарии и много зависи от дизайна, естествено. Ама многонишковото програмиране като цяло е една грозна каша и трябва да се мисли много внимателно в началото, защото после изникват разни такива странни моменти. Освен това много трудно се дебъгва, например strace отказва да ти следи кво ставало в рамките на някоя нишка.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 19:41
> Все пак не мисля да пиша 100 отделни функции за 100 отделни нишки,
> които правят в общи линии едно и също, само че върху различен
> дескриптор.

А на мен ми се струва, че изобщо не мислиш. :) Защо трябва да са отделни функциите след като локалните им променливи са в стека?

Многонишковото програмиране не е чак толкова трудно, изисква известна практика. Тренирайте, защото multicore процесорите няма да изчезнат и единствения начин за ефективното им използване ще е многонишковото прогрмиране :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 20:08
Имам предвид ако имаш някаква структура описваща всички конекции, състоянието им и т.н. Няма как да ти е локална променлива все пак :) И например единия клиент затвори конекцията, ще се наложи нишката да го отрази по някакъв начин.

Уфф абе добре, ясно, пак опираме до дизайна на нещата очевидно :) И в тоя случай специално може да се измисли наистина :) От друга страна, този случай специално е доста прост :) В един по-забавен вариант, отделните клиенти трябва да си обменят някакви данни, например става въпрос за някакъв елементарен чат сървър, тогава вече няма да има измъкване от тая проблематика, поне аз сега не мога да измисля :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 20:15
> Имам предвид ако имаш някаква структура описваща всички конекции,
> състоянието им и т.н.

За какво ти е такава структура??? Основната нишка прави

fd = accept();
pthread_create(x, NULL, process_connection, fd);

process_creation чете и пише от fd-то и накрая го затваря.

Проблемът е от т.нар. embarrassingly parallel, няма нужда от никакви заключвания или комуникации между нишките.

Отделно не виждам никакъв смисъл програмите сами да се занимават със сокети след като могат да използват inetd за целта. KISS!


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 20:18
Шшшшш xinetd :) RHEL не ползваш ли? :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 20:25
x, y, z, inetd си е inetd, от програмистка гледна точка няма разлика, за другото да му мислят сисадмините.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 20:29
Ееееем...аз не съм програмист. inetd е много лоша идея между другото ако става въпрос за каквото и да било UDP-базирано :)

Между другото, от администраторска гледна хич не е едно и също :)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 20:47
Няма смисъл да се обсъждат недостатъците на нещо за хипотетични случаи. Като се получи задание, се пише най-простото решение. Мери се, ако не върши работа се мисли за оптимизацията му. Всеки, който смята, че ще измисли от раз правилния дизайн е идиот :)

Друг умен човек (Фред Брукс, не съм сигурен, че е програмист) е казал:

The question, therefore, is not whether to build a pilot system and throw it away. You will do that. The question is whether to plan in advance to build a throwaway, or to promise to deliver the throwaway to customers.

Та, планирайте за throw-away...


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 21:04
Дадаааам, съгласен съм :)

Струва ми се все пак че много навътре го приемаш. Напълно ти приемам критиките, но не виждам какво толкова си се запритеснил. Върши си работата колкото трябва там, аз лично за себе си се радвам, че не отебах да го довърша, щото ми се въртеше из главата докато ходих да обядвам :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 21:07
> Струва ми се все пак че много навътре го приемаш.

Трябва да се образова младежта. :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 21:13
Е, мани ся, ела тука да я образоваш :) Отвъд океана и аз мога :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: the_real_maniac в Sep 18, 2007, 21:58
offtopic:

Не е вярно gat3way и тук все още има младеж , която се образова , иска и/или пробва и не много очудващо, но (логично или не) със желание успява. :-)

нищо че и аз вече се подготвям лека по-лека да ходя да уча в Germany + имах вече 1 предложение за работа там .. още по време на средното ми образование (но не заради това, което ме учеха в СОУ-то) , та ... да и аз се чудя как още има хора да работят тук ... и вече си отговарям, но все пак .. за учене определено ... тука е сложна работата - да не кажа , почти я няма .. хъх. и жалко нали ;)

така че полезно инфо, но мога да кажа, наистина очудващо как покрай всичко накрая можа да се види и нещо, което от едно четене да ти светне -> още идеи за това как нещат амогат да се правят simple и работещи :p :) Не е 'просто' да е 'просто', ами трябва да мислиш за  throwaway-а, грубо казано ;-)

И все пак бях почти убеден , че някой админ или модератор ще Ви среже, за малко по-острият тон, но браво :-D че все пак оцеляхте хаха


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: gat3way в Sep 18, 2007, 22:10
Тука си е забавно :)

Между другото, България наистина е забавна държава и само заради тарапаната която сами си сътворяваме си заслужава да живееш тука :) Това лято например се размотавах из Италия, Испания и Франция (от Франция се върнах преди 2 дена). Хубави държави и много странни мисли ти минават през главата там. Много надълго и много офф-топик ще стане ако трябва да обяснявам защо твърде много неща, които ни се виждат като проклятие тука всъщност са си направо бял кахър...накратко проблемът на България според мен е много прост и той е: просто нема достатъчно пари в системата за момента :) Всичко друго е просто следствие :) Но пък е интересно. Как и да е, въпрос на мислене според мен :) Аз лично нямам никакво намерение да емигрирам, в чужбина ходя само на почивки и екскурзии и не виждам защо трябва това да се променя :)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: the_real_maniac в Sep 18, 2007, 23:20
Тук грешиш само в едно !

И то не е ... факта, ами извода от факта

проблема на България не е че няма много пари в системата, ами той е следствие от проблема ! и да това все пак само по себе си е доста голям проблем.

но за да решиш проблема , трябва да решиш причината
а причината също е проблем и то по-голямият, и то причинителя

значи е безмислено да решава 2-рият проблем причинен от първият , нещо като

симптом на болест Х е болест Y

защо да лекуваш болест Y?


Та пробелма -> болест Х -> вика му се алчност, егоизъм , в деношно време КОРУПЦИЯ !

така -  от там нататък

честност, преданост - към работа или към дълг, медицински работник - себе си и клетвата , полицяй - реда, закона и съвестта, политик - съвест за хората и себе си  и т.н , и т.н

а учителя ... ехх тук мисля, че учетителите, тези който наистина са , сега са едва 20-30% , а останалите 70% вече не са учители - т.е

амм не преподават вече така
или са си намерили по-доходна работа и тя не е на учител
или е на учител, но частен или в частсно училище/колеж, бла-бла
или навън, което нас не ни грее, чак толквоа

та така , колега


1. алността на личността
2. липсата на чест или по-скоро незащитването й
и чак после идва следвствието от 1 -> липсата на пари и следствието от 2-> при някои не просто липстава желаниет, те не усещат нужда от промяна, щото виждаш ли и онзи би направил така..


е сори онзи да , ама не и аз , не и ти , не и тя .. и е*ати .. то промяна, значи смяна на посоката в нашият случей ...

Така че ... има алчност и алчност , егоизъм и егоизъм и не казвам , че не съм човек , точно обранотно - СЪМ и ... затова знам за какво говря , но има ралзика от това да имаш съвест и да нямаш. (точка).

мм така че gat3way , темата е весела + не съм казал , че на вън е супер , казвам само хората ти дават да пробваш, иска шда пробваш - заповядай пробвай , това не значи че ще ти помогнат ..., даже може би напротив , ако си чужденец в началото, но поне няма да ти пречат и ще ти дадът да пробваш.

Както казвам ... в Германия искаш лаборатория за дейности извън упражнения, но учебни .. за теб или някоя група студенти , ок ... заповядай

тук не че няма лаб (това едно на ръка), такова нещо рядко ще стане ! (поне в близките 10г, че и повече)

пп: до 5 г вече няма да има много преподавателите с опит в ТУ, казаха го по новините , казвали са го и в самото ТУ  - факт.

защо
ми не му плащат достатъчно на даскала да седи и да гледа
манталитета на 90% студентите е като на 90% депутатите , пука ми , нали е държавно , да уча ли че защо - има по-лесен начин, идеи ли  ? - пари , жени , коли ,супер ... еми ок , аз няма проблем - кефи те САМО това ... добре ,хубаво, ама защо трябва да си го взимаш по най-отвратителният начин ?
а проблемтие са хиляди .. и т.н

...

ехх пак се разговорих , Smith я направи една тема , като отделиш последните 2 мнение, т.е това и на gat3way.

Само тези двете, първото ми мнение си е по темата и не искам да се маха, просто защото е по-темата на темата :-D

а иначе , всеки има право на мнение и дори ма вероятност много да греша, но ... това е моето мнение ... :-) и го казвам, който иска да не чете ;-) който не е съгалсен ок , въпреки че ... фактите са си факти , поне тях можем да обсъдим ;) :-) ако не мненията ни :-D :p :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: tarator в Sep 18, 2007, 23:36
gateway,

Не можете да си позволите да се върна. :) В България не се дават пари за научноизследователска дейност.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: task_struct в Sep 19, 2007, 02:55
Цитат
до 5 г вече няма да има много преподавателите с опит в ТУ, казаха го по новините , казвали са го и в самото ТУ  - факт.
Напълно съм съгласен. Аз уча там, приложна математика, и вмомента ми преподават много добри учители, но всички искат да се изнесат от България. :(

Иначе за управлението на държавата смятам, че ще стане както в Библията за Мойсей и 40 години бродене. Докато има хора, който си спомнят социализма, няма да се оправим. Та все пак повечето от тези, който са опозиция на БСП, преди са били за тях.


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 19, 2007, 10:10
Среща тази вечер, 20.30, Кривото на Будапеща. Аз ще нося бутилка вино и платки. Ще ме познаете по зелената риза.

Ако някой часът му е неудобен бързо да коментира!


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 19, 2007, 10:15
И още нещо - може ли всеки да направи по една страница в която да сложи връзка към решението си или поне да сложи връзка към работеща услуга. За да можем да напишем тест за резултатите :)
Ако някой няма машина, която да е публично достъпна ще измислим нещо :)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 19, 2007, 12:04
сорс

http://ipclassify.relef.net:160/time
http://ipclassify.relef.net:160/fortune


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: the_real_maniac в Sep 19, 2007, 12:12
СТана ми весело като прочетох последните няколко коментара, нищо че 2 бяха сериозни ;) :-)

А сега нова задача:

Задача 3 - почвайте да пишете експлойти за написаните вече мрежови услуги ххххххх хаххах .. сори, обаче в момента това ми е супер смешно, защото имаме услуга, имаме порт, имаме публично достъпно ип/адрес... какво остава само едно - нова задача , ПРОДЪЛЖЕНИЕ на предишната :-D :p :-)

Denial of Service ... xxxx

пък и ще е весело наистина , хх ;-) :-) просто .. нова задача

спрете fortune .. отговор : you can't stop the signal/aka the future :-D *rofl* както се казва хаха
:)

пп: знам какво значи думата fortune, но има общо с бъдещето ,, та и затова малко игра на думи ;) :-)


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 19, 2007, 12:40
@the_real_maniac

 :) точно това казах и аз ;)

Цитат

VladSun (12:07 PM) :
сега остава някой да ме хакне, хахаха


Само да ти кажа ... имам ти ИП-то ;) хахаххахахаа

Довечера на линия ли си?

Едит: офлайн линия имах предвид ;)





Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: task_struct в Sep 19, 2007, 13:34
Леле к`ви неща пиша, когата съм подпийнал  :p

Иначе по задачата: Аз нямам къде да я кача :(


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: Hapkoc в Sep 19, 2007, 14:50
http://fortune.mamul.org:8082/fortune
http://fortune.mamul.org:8082/code
http://fortune.mamul.org:8082/


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: zeridon в Sep 19, 2007, 14:57
@task_struct:
http://imbuza.no-ip.org:9999/

там ти е решението. Само е компилирано с променен юзер и лог файл ... а да трябваше да си инсталирам и фортунес ... дано сета да ви хареса


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: task_struct в Sep 19, 2007, 16:26
zeridon, мерси :)

За сбирката това съм аз. Ако някой ме познае да свирка, че незнам как ще ви намеря  ???


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: BULFON в Sep 19, 2007, 16:48
Кривото, ул. Будапеща, София
начало 20.30
масата е горе, в "градината"


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: VladSun в Sep 19, 2007, 16:58
Цитат (task_struct @ Сеп. 19 2007,16:26)
За сбирката това съм аз. Ако някой ме познае да свирка, че незнам как ще ви намеря  ???

/offtopic

Кой от двамата ;)
муахахаха


Титла: Задача 2 - 10.09 - 16.09 - quotes web service
Публикувано от: NikiAlexandrov в Sep 19, 2007, 17:48
Този път може и аз да се появя :) Ще ме познаете по блузата с "Unix-like" на нея