Вдохновленный первой
статьей об управлении компьютером через
мобильный
, я решил сделать подобную
программу, так как тоже давно пытался дать
волю своим пальчикам - сделать что-нибудь
серьезное. После небольшого теста первой
программы, я пришел к выводу, что все
сотовые (a точнее wap-браузеры) разные :).
Поэтому “зашивать” страницу в программу
было бы слишком банально (и не мобильно, так
как нельзя быстро что-то исправить). Да и к
тому же все предложенные программы были под
windows, и выполняли лишь незначительные
никому ненужные ф-ии (открывание\закрывание
CD и др. ерунду). Мой замысел куда интереснее:
программа должна выполнять любые (почти
любые 🙂 команды и даже команды с какими-нибудь
аргументами. Естественно проще всего
написать такую программу под Unix систему, в
частности под Linux (так как я только им и
пользуюсь :). Сразу оговорюсь, что программа
выполняет заданную команду (хотя и не
всегда), но не возвращает результат, потому
что сотовый много не примет, да и скорость
не большая, а ограничивать посылаемые
данные, я считаю, бесчеловечно.

А вообще такую функцию реализовать не
сложно. Но обо всем по порядку.

#include <sys/socket.h> // Это
сокеты 

#include <netinet/in.h> //
Различные
константы для работы все с теми же сокетами

#include <stdio.h> //
perror и
друие ф-ии ввода\вывода

#include <fcntl.h> //
костанты
для open

#include <string.h> //
строковые
ф-ии

#include <unistd.h> //
еще
костанты

#include <ctype.h>//
ф-ия isspace
#include <stdlib.h> //
тоже ф-ии
и константы

#define max 400 //
максимальное
значение для буфера и еще чего-нибудь

#define SPC 32 //
код пробела
#define PORT 80 //
HTTP порт

// Простенькая
банальная ф-ия для удаления пробелов –
ничего необычного.

void delthreesp(char *space, int len) 
{
int i,j,k;
k=0;

for(i=0;i<=len;i++) // "проходим"
ф-ию по длине

if(space[i]==SPC && space[i+1]==SPC) //
Если
находим пару пробелов, то сдвигаем

{ //
массив влево на
символ

for(j=i;j<=len;j++)
space[j]=space[j+1];
k++;
}

space[len-k]='\0';
}

// Ооо. Вот над этой ф-ей
я долго извращался, даже хотел, чтобы она
возвращала мне двумерный 

//
массив, но вовремя
испугался геморроя

char *strmy(const char *ext,int alen) 

//
Задача - отдавать по
фразе из строки, разбитой на пробелы, пока
слова не кончаться

// Объявляем переменную
статической, чтобы “помнить” на каком
месте в строке мы находимся
,
//
так как фразы мы
будем получать за несколько вызовов.

static int currpos=0; //
Здесь мы
сохраним текущее значение позиции в строке

char tmp[alen+1]; //
А сюда мы
поместим нашу фразу

int k;
bzero(&tmp,alen+1); //
Обнуляем...
//
Проверяем не
добрались ли мы до конца строки 

if (currpos>=alen) 
{
currpos=0;
return NULL;
}

// Это просто
переинициализация ф-ии для последующей
работы 

else if(ext==NULL && alen == -1) 
{
currpos=0;
return NULL;
}
k=0;

// Главная часть ф-ии,
где мы и берем какую-то фразу

while((isspace(ext[currpos])==0) && (currpos<alen))
{
tmp[k]=ext[currpos];
currpos++;
k++;
}

tmp[currpos++]='\0'; // Заканчиваем
строку официально

return strdup(tmp); //
Ну и
возвращаем указатель на ее копию

}

void fat_err(char *text) // Ф-ия для
аварийного выхода

{
perror(text); //
Печатаем, что
за ошибка случилась

exit(1); // Выходим...
}

// Ф-ия, которая просто
вернет нам то, что хочет от нас мобильник,
предварительно проверив
//
являются ли полученные данные запросом и
удалив из строки символы %20.
// Вообще
http запрос имеет вид: GET /file bla-bla-bla...............

//
От этого мы и будем
отталкиваться

char *getlistcmd(char *data,int size)
{
char cmd[size]; //
Здесь и
будим хранить строку-запрос

int i,k;

if(strncmp("GET",data,3)!=0) return NULL; // А
запрос ли это?

if(data[5]==SPC) return strdup("ls"); //
А
может это нулевой запрос (типа "GET / ")

i=0; //
Ну тогда пусть
выведется список файлов

do // Ищем первое
вхождение символа '/'

{
i++;
}
while(data[i]!='/');
i++;
k=0;

do // сохраняем строку
{
cmd[k]=data[i];
i++;
k++;
}
while(data[i]!=SPC); //
Очень
важный момент: не все браузеры в конце
запроса посылают пробел,

//
многие посылают
символ '/' ,поэтому кому надо - исправьте 

cmd[k]='\0'; // Пусть все
будет красиво

for(i=0;i<k;i++) // Заменяем
пробелами последовательность %20

{
if(cmd[i]=='%')
{
cmd[i]=' ';
i++;
cmd[i]=' ';
i++;
cmd[i]=' ';
}

}

return strdup(cmd); // Возвращаем
указатель на копию нашей строчки

}

Я думаю, теперь стоит
подробнее рассказать от том загадочном
файле, который открывает и отсылает
программа. Файл содержит, помимо страницы,
которая будет отображаться на вашем
сотовом, строчки из самого протокола HTTP,
необходимые для того, чтобы объяснить
браузеру, что все нормально (200 ОК), что мы
используем HTTP 1.1, и что из себя представляет
документ отсылаемый нами (Content-type). Вообще,
сама wml-страница, которую я запихнул в этот
файл - не лучшее решение, потому что в wml я не
очень разбираюсь. Так что сделайте лучше
свою страницу, если получиться что-то лучше,
проще и меньше, то обязательно поделитесь
со мной (и с остальными конечно :).

Ну вот и добрались до нашей
главной ф-ии, в задачу которой входит

  1. Организация сокетов.
  2. Посылка из файла страницы (с
    кодом “200 ОК”).

  3. Прием и обработка данных.
  4. Собственно выполнение
    полученной команды.

int main(void) 
{
//
Различные переменные
для работы

struct sockaddr_in local; //
Здесь
будут данные о локальном адресе

int file,s,s1,res,i; //
различные
переменные для дескрипторов и другой
ерунды

char buff[max],*cmd,*argus[10]; //
Массивы
для хранения данных и команд

const int on = 1; //
Это
необходимо для setsockopt

pid_t pid; //
для вызова fork (можно
и int'ом)

int status=1; 
bzero(&local,sizeof(local)); //
Обнуляем
структуры и

bzero(&buff,max); //
массивы
local.sin_family=AF_INET; //
Семейство
протоколов

local.sin_port=htons(PORT); //
Вот он
наш порт

local.sin_addr.s_addr = htonl(INADDR_ANY); //
Соглашаемся
на любой адрес

s=socket(AF_INET,SOCK_STREAM,0); //
Открываем
наш главный - "прослушивающий"

// сокет 
if(s<0) fat_err("Error opening socket"); //
Проверяем
на наличие ошибок

if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))) fat_err("Error
calling setsockopt");
//
Устанавливаем опцию
SO_REUSEADDR

res=bind(s,(struct sockaddr *)&local,sizeof(local)); //
Привязываем
наш сокет к

//
локальному адресу
if(res<0) fat_err("Error calling bind"); //
Проверяем
на наличие ошибок

res=listen(s,1); // Прослушиваем
на наличие запроса (причем создается не
более 

//
одного сервера)

if(res) fat_err("Error calling listen"); // Проверяем
на наличие ошибок

while(status!=0) // Крутимся
пока не придет заветная строка (см. ниже)

{
i=-1;
//
Вот он наш главный
цикл – то для чего и нужна была вся эта
громоздкая прелюдия

strmy(NULL,-1); // На всякий
случай обнуляем статическую переменную

s1=accept(s,NULL,NULL);//
Неужели
кто-то подключился?

//
Ну тогда понеслась...
if(s1<0) fat_err("Error calling accept"); //
Проверяем
на наличие ошибок

res=recv(s1,buff,max,0); // Принимаем
данные

if(res<=0) fat_err("Error calling recv"); // Проверяем
на наличие ошибок

cmd=getlistcmd((char *)buff,res);// Получаем
строку-запрос

delthreesp(cmd,strlen(cmd)); //
Удаляем
лишние пробелы

printf("%s\n",cmd); //
Посмотрим
что же у нас получилось

// Этот цикл
теоретически мог войти в ф-ию strmy()

do
{ //
Я не стал вставлять
этот цикл в ф-ию, потому что не хотел

i++; //
получить геморрой
с двумерным массивом

argus[i]=strmy(cmd,strlen(cmd)); //
Получаем
кусочки из строки

}
while(argus[i]!=NULL && i<=10);
//
Я думаю десяти
аргументов достаточно?

argus[i]=(char *)0; // для execvp
последний аргумент должен быть нулевым
указателем

status=strncmp("konec",argus[0],7); //
Вот
и она - наша “последняя” строчка

//
Вообще можно выйти
тут же, но тогда пришлось

//
бы тут же закрывать
все сокеты и т.п.

//
А команда “konec”
ничего страшного, я думаю,

//
компьютеру не
сделает.

printf("Opening file...\n");
file=open("index.wml",O_RDONLY); //
Открываем
файл с данными (http ответ и // страница)

if(file<0) fat_err("Error opening file"); // Проверяем
наличие ошибок

res=read(file,buff,max); // Читаем
if(res<=0) fat_err("Error calling read"); //
Проверяем
на наличие ошибок

printf("Sending data...\n"); // и
res=send(s1,buff,res,0); //
тут же
отсылаем...

if(res<=0) fat_err("Error calling send"); // Проверяем
на наличие ошибок

pid=fork(); // Создаем
процесс-потомок

if(pid==0) //Неужели потомок?
{
if(argus[0]!=NULL)
execvp(argus[0],argus); //
Ну тогда
пытаемся выполнить эту чушь

}

close(s1); // Как это ни
странно закрываем сокет, чтобы потом его
снова открыть

}
if(pid!=0)
{
printf("Server was stopped by extremly danger command :\"KONEC\"\n");
close(s); //
Если уж
доберемся до сюда то закроем

close(file);//
все
дескрипторы


return 0;
}

Вообще эта программа далеко не идеал и
даже не собиралась им быть. Она создана как
основа, так как, во-первых, без
дополнительных изменении она может не
работать на каком-нибудь сотовом; во-вторых,
на основе этого исходника можно сделать, я
думаю, более интересную и эффективную вещь.
Подведя итог могу сказать, что человеку
увлеченному и разбирающемуся во всей этой
фигне исходник пригодится...

Writed by Glk0x70

Исходники: mobile.tar

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии