123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- #include <unistd.h>
- #include <limits.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <clock.h>
- #include <zio.h>
- #include <log.h>
- #include <zloop.h>
- #include "base64.h"
- #include "io_buf.h"
- struct web_client_http:ev::io
- {
- in_buff m_buff;
- int m_data_len=-1;
- int m_mask_pos=-1;
- int m_data_pos=-1;
- int m_fd,m_status;
- web_client_http()
- :m_buff(8192)
- {
- m_fd=-1;
- }
- int connect_tcp(const char*ip,int port)
- {
- int fd=zio::build_stream();
- if(zio::connect(fd,ip,port))
- {
- zio::close(fd);
- return m_fd=-1;
- }
- zio::setiobuf(fd,16<<10,16<<10);
- zio::setblocking(fd,false);
- return m_fd=fd;
- }
- void ws_reset()
- {
- if(m_data_pos+m_data_len>0)
- {
- m_buff.free(m_data_len+m_data_pos);
- }
- m_data_len=-1;
- m_mask_pos=-1;
- m_data_pos=-1;
- }
- bool ws_fin()const
- {
- return (m_buff[0]&0x80) != 0;
- }
- bool ws_more()const
- {
- return (m_buff[0]&0xF) ==0 ;
- }
- bool ws_text()const
- {
- return (m_buff[0]&0xF) ==1 ;
- }
- bool ws_bin()const
- {
- return (m_buff[0]&0xF) ==2 ;
- }
- bool ws_ping()const
- {
- return (m_buff[0]&0xF) ==9 ;
- }
- bool ws_pong()const
- {
- return (m_buff[0]&0xF) ==10 ;
- }
- bool ws_close()const
- {
- return (m_buff[0]&0xF) ==8 ;
- }
- bool ws_mask()const
- {
- return (m_buff[1]&0x80) !=0 ;
- }
- int parse_length()
- {
- if(m_buff.len_data()<2)
- return -1;
- if(m_data_pos>0)
- return 0;
- if((m_buff[1]&0x7F)<=125)
- {
- m_mask_pos=ws_mask()?2:-1;
- m_data_pos=ws_mask()?6:2;
- m_data_len=m_buff[1]&0x7F;
- }
- else
- if((m_buff[1]&0x7F)==126)
- {
- if(m_buff.len_data()<4)
- return -1;
- m_mask_pos=ws_mask()?4:-1;
- m_data_pos=ws_mask()?8:4;
- m_data_len=(m_buff[2]<<8) | m_buff[3];
- }
- else
- {
- if(m_buff.len_data()<9)
- return -1;
- m_mask_pos=ws_mask()?9:-1;
- m_data_pos=ws_mask()?13:9;
- //不考虑大于20G的数据
- m_data_len=(m_buff[6]<<24)|(m_buff[7]<<16)|(m_buff[8]<<8)|(m_buff[9]);
- }
-
- int i=0;
- for(i=0;i<m_data_len;i++)
- {
- uint8_t b=m_buff[m_data_pos+i];
- if(b>=0x30 && b<=0x39)
- continue;
- break;
- }
- m_data_len-=i;
- m_data_pos+=i;
- return 0;
- }
- void mask(const uint8_t*m,uint8_t*d,int len)
- {
- for(int i=0;i<len;i++)
- d[i]=d[i]^m[i&3];
- }
- int ws_parse()
- {
- if(parse_length()<0)
- return -1;
- if(m_buff.len_data()<m_data_pos+m_data_len)
- return -1;
- if(ws_mask())
- {
- mask(&m_buff[m_mask_pos],&m_buff[m_data_pos],m_data_len);
- }
- for(int i=0;i<m_data_len;i++)
- {
- printf("%c",m_buff[m_data_pos+i]);
- }
- printf("\n\n");
- return 0;
- }
- int connect_ws(const char*ip,int port)
- {
- unsigned char k[16], k6[128];
- for(size_t i=0;i<sizeof(k);i++)
- k[i]=rand();
- base64::encode(k,sizeof(k),k6);
- const char*fmt=
- "GET /socket.io/?EIO=3&transport=websocket HTTP/1.1\r\n"
- "Host: %s:%d\r\n"
- "Connection: Upgrade\r\n"
- "Pragma: no-cache\r\n"
- "Cache-Control: no-cache\r\n"
- "Upgrade: websocket\r\n"
- "Origin: http://%s:%d\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Accept-Encoding: gzip, deflate\r\n"
- "Accept-Language: zh-CN,zh;q=0.9\r\n"
- "Sec-WebSocket-Key: %s\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n";
- if(connect_tcp(ip,port)<0)
- return -1;
- char buf[512];
- int len=sprintf(buf,fmt,ip,port,ip,port,k6);
- if(len!=zio::writev(m_fd, buf, len))
- {
- close();
- return -1;
- }
- sleep(1);
- if(read_until("\r\n\r\n")<=0)
- {
- close();
- return -1;
- }
- if(m_buff.find("101 Switching Protocols\r\n"))
- {
- m_buff.skip(m_buff.find("\r\n\r\n"));
- return 0;
- }
- close();
- return -1;
- }
- int request(const char*what)
- {
- int len=strlen(what);
- if(len!=zio::writev(m_fd, what, len))
- {
- close();
- return -1;
- }
- return 0;
- }
- int read_until(const char*what,int timeout=10*1000)
- {
- int rc=0;
- zclock c;
- for(;;)
- {
- buff_t b=m_buff.alloc();
- if(b.empty())
- {
- m_buff.grow(1024);
- b=m_buff.alloc();
- }
- int len=zio::read(m_fd,b.ptr(),b.len());
- if((int)c.count_ms()>timeout)
- {
- log_error("websocket read timeout in %dms",timeout);
- return -1;
- }
- if(len==-1)
- {
- return -1;
- }
- if(len==-2)
- continue;
- if(len==0)
- {
- log_info("remote close the socket");
- return 0;
- }
- m_buff.commit(len);
- rc+=len;
- if(m_buff.find(what))
- return rc;
- }
- }
- void close()
- {
- zio::close(m_fd);
- }
- ~web_client_http()
- {
- close();
- }
- };
- int realpath_test()
- {
- char buf[4096];
- realpath(".",buf);
- log_info("curpath=%s",buf);
- return 0;
- }
- #if 0
- std::string test_json()
- {
- struct json
- {
- json&put(const char*k,const json&n)
- {
-
- return *this;
- }
-
- json&put(const char*k,int v)
- {
-
- return *this;
- }
- json&put(const char*k,const char*v)
- {
-
- return *this;
- }
- std::string to_string()const
- {
- return std::string();
- }
- };
- return json().put("cmd","login")
- .put("data",json()
- .put("uname","wyj")
- .put("passwd",111111)
- ).to_string();
- }
- #endif
- int main()
- {
- unsigned char buf[32];
- const char*s64="puVOuWb7rel6z2AVZBKnfw==";
- const char*login="{\"cmd\":\"login\",\"data\":{\"user_name\":\"zzj\",\"user_pass\":\"111111\"}}\n";
- int blen=32;
- base64::decode((char*)s64,strlen(s64),buf,blen);
- web_client_http client;
- client.connect_ws("127.0.0.1",9001);
- for(;;)
- {
- while(client.ws_parse()==0)
- client.ws_reset();
- client.request(login);
- client.read_until("\n");
- }
- return 0;
- }
|