boost:asioを使って、ファイルをWebサーバにマルチパートでPOSTしてみる
boost:asioを使って、ファイルをWebサーバにPOSTしてみる
かなり昔に書いたコードです。
HDDの整理中で、誤ってソースを削除しそうなのでここにメモ。
制限
- ファイルはカレントディレクトリ
- ポートは80固定
- ドメインでなく、IPアドレス
#include <iostream> #include <string> #include <boost/asio.hpp> #include <boost/regex.hpp> #include <boost/lexical_cast.hpp> using namespace std; using namespace boost::asio; int main() { string filename="postfile.bin";//ポストしたいファイル名 string ipaddress="192.168.1.1";//アップしたいサーバのIPアドレス ifstream f(filename.c_str(),ios::in | ios_base::binary); if (!f){ cerr << "ファイルが開けません "<< endl; return -2; } //Content-Lengthに入れるためのファイルサイズの取得 size_t filesize = (size_t)f.seekg(0, std::ios::end).tellg(); f.seekg(0, std::ios::beg); //boost::asioの出番 ip::tcp::iostream s( ipaddress, "80" ); if(s.fail()){ cerr << "Webサーバが応答しません" << endl; return -1; } // 送信 s << "POST /filerecv.htm HTTP/1.1\r\n"; s << "Content-Type: multipart/form-data; boundary=---------------------------7d97d32d00e4\r\n"; s << "Host: "; s << ipaddress; s << ":80"; s << "Content-Length: "; s << dec << filesize + fileheader.length() + filehooter.length(); s << "\r\n"; s << "Connection: Keep-Alive\r\n"; s << "Cache-Control: no-cache\r\n"; // s << "Authorization: Basic **********\r\n"; 認証がある場合 s << "\r\n"; s << "-----------------------------7d97d32d00e4\r\n"; s << "Content-Disposition: form-data; name=\"BinaryCodeFile\"; filename=\""; s << filename; s << "\"\r\n"; s << "Content-Type: application/octet-stream\r\n"; s << "\r\n"; char buffer[1024]; int readsize = 0; while(!f.eof()){ f.read(buffer,sizeof(buffer)); s.write(buffer,f.gcount()); } f.close(); s << "\r\n-----------------------------7d97d32d00e4--\r\n\r\n"; s << flush; // バッファに溜めずに確実にネットワーク送信 // 受信 boost::regex reg("([0-9]{3})"); string line; boost::smatch result; int statuscode = 0; getline(s, line); if(boost::regex_search(line, result, reg)){//ステータスコードがある場合 statuscode = boost::lexical_cast<int>(result.str(1));//数値へ変換 } if(statuscode != 200){ return -3; } return 0; }
ActiveXとjavascriptの連携
ActiveXとjavascriptの関連のメモ。
1.javascript側からActiveXのメソッドをコール
objectタグにidをつけ、ActiveXのメソッドをそのまま呼び出すだけ。
ActiveXを作るときに命名したメソッド名がそのまま使える。
たとえばActiveXが以下のobjectだったとする。
<object id="baka" classid="省略">
で、ActiveX側のメソッド名が"aho"だった場合、javascriptからの呼び出し方は、
baka.aho()
でオーケー。追加コードなし
2.javascriptからActiveXに値を渡す"プロパティ"
objectタグの中で
<param name="" value="">
で指定できる。
ActiveX側で、永続性の確保をするコードを忘れずに↓
PX_String(pPX, _T("URL"), m_URL, _T("http://")); // url(cam1)
プロパティの追加は"メンバ変数"で。Get/Setは知らない。
3.ActiveX側のイベントを、javascript側で取得
ActiveX側で、コントロールを右クリックしてイベントの追加する。
javascript側のコードはこんな感じ。
<script for="ActiveXnoID" event="Eventer(fire)" alert("event=" + fire);> </script>
そのメソッドをActiveXで呼び出したらイベントが発生し、
javascript側でalertダイアログが表示される。
boost::asioで、sip messegeを送信する
boost::asioを使って、UDPの送受信をしてみる.
受信待ちは5秒でタイムアウト
本当は受信を先に動かしておかなければいけないんだろうな
#include "StdAfx.h" #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <boost/system/error_code.hpp> #include <Wincrypt.h> class datagram_handler { public: datagram_handler(io_service& ios): io_service_(ios), timer_(ios), socket_(ios, udp::endpoint(udp::v4(), 5060)) { memset(data_,0,sizeof(data_)); socket_.async_receive_from( boost::asio::buffer(data_, max_length), sender_endpoint_, boost::bind( &datagram_handler::handle_receive_from, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) ); timer_.expires_from_now(boost::posix_time::seconds(5));//タイムアウト値のセット timer_.async_wait(boost::bind(&datagram_handler::close, this));//タイムアウトしたらclose } void handle_receive_from(const boost::system::error_code& err, size_t /*length*/) { timer_.cancel(); if (err){ std::cerr << "Receive error: " << err.message() << "\n"; }else{ //ステータスコードの取得 std::string line(data_); std::string statuscode; boost::regex reg_status("SIP/2.0 (\\d*)"); boost::smatch result; if(boost::regex_search(line, result, reg_status)){//status statuscode = result.str(1); }else{ std::cerr << "errror : status code not found.\n"; return; } if(statuscode != "200"){ std::cerr << "errror : status code not found.<< statuscode << "\n"; return; } std::cout << "Successful receive\n"; } } void close() { socket_.close(); } private: io_service& io_service_; deadline_timer timer_; udp::socket socket_; udp::endpoint sender_endpoint_; enum { max_length = 512 }; char data_[max_length]; }; std::string sjis2utf8(const std::string &sjisstr) { //ShiftJIS → UFT8 std::wstring wstr = ConvertMultiToWide(sjisstr); //UTF16に変換 std::string strUtf8 = ConvertWideToMulti(wstr,CP_UTF8); //CP_UTF8に変換 return strUtf8; } std::string MakeRandom() { HCRYPTPROV hProv; BYTE buf[5]; int i; CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0); CryptGenRandom(hProv, sizeof(buf), buf); std::string callid; for(i=0;i<sizeof(buf);i++){ callid += boost::lexical_cast<std::string>(static_cast<int>(buf[i])); if(i != sizeof(buf)-1){ callid += '-'; } } CryptReleaseContext(hProv, 0); return callid; } void handle_send_to(const boost::system::error_code& err) { if (err){ std::cerr << "Send error: " << err.message() << "\n"; } } int main(){ try{ std::string _s_ip("192.168.1.1");//SIPサーバのアドレス std::string _l_ip("192.168.1.100");//自分のIPアドレス gethostname+gethostbynameで取得 std::string _l_num("3000");//自分の番号 std::string _s_num("3001");//相手の番号 std::string msg("こんにちは");//送信メッセージ boost::asio::io_service io_service; udp::socket s(io_service, udp::endpoint(udp::v4(), 0)); udp::resolver resolver(io_service); udp::resolver::query query(udp::v4(),_s_ip, "5060");//SIPポート udp::resolver::iterator iterator = resolver.resolve(query); std::string utf8message=sjis2utf8(msg.c_str());//utf-8に変換しておく using namespace std; std::string sendmessege="MESSAGE sip:"; sendmessege+= num; sendmessege+= "@"; sendmessege+= _s_ip; sendmessege+= ":15060 SIP/2.0\r\n"; sendmessege+= "Via: SIP/2.0/UDP "; sendmessege+= _l_ip; sendmessege+= ":5060;branch=z9hG4bK"; sendmessege+= MakeRandom();//ランダム値生成 sendmessege+= "\r\n"; sendmessege+= "From: <sip:"; sendmessege+= _l_num; sendmessege+= "@"; sendmessege+= _s_ip; sendmessege+= ":5060>;tag=da3676\r\n"; sendmessege+= "To: <sip:"; sendmessege+= num; sendmessege+= "@"; sendmessege+= _s_ip; sendmessege+= ":5060>\r\n"; sendmessege+= "Call-ID: "; sendmessege+= MakeRandom(); sendmessege+= "@"; sendmessege+= _l_ip; sendmessege+= "\r\n"; sendmessege+= "CSeq: 1 MESSAGE\r\n"; sendmessege+= "Content-Type: text/plain; charset=utf8\r\n"; sendmessege+= "Max-forwards: 69\r\nContent-Length: "; sendmessege+= boost::lexical_cast<string>(utf8message.length()); sendmessege+="\r\n\r\n"; sendmessege+=utf8message; size_t request_length = sendmessege.length();//strlen(request); //SIP Message 送信 s.async_send_to( boost::asio::buffer(sendmessege, request_length), *iterator, boost::bind( &handle_send_to, boost::asio::placeholders::error ) ); / //応答を受信 datagram_handler dh(io_service); //実行 io_service.run(); s.close(); }catch (std::exception& e){ std::cerr << "Exception: " << e.what() << "\n"; } }
オープンソースのSIPライブラリ eXosipを VC9.0でコンパイルする
必要なもの
Microsoft Visual Studio 9.0
eXosip
http://savannah.nongnu.org/projects/exosip
osip
http://www.gnu.org/software/osip/
openssl
http://www.02.246.ne.jp/~torutk/cxx/openssl/install.html
ディレクトリ構造を以下のようにする
d:\sip\libeXosip2-3.3.0
d:\sip\osip [リネームしておく]
d:\lib\openssl
VCのインクルードファイルにd:\lib\opensslを追加しておく
あとは、
\libeXosip2-3.3.0\platform\vsnet\eXosip.slnをVCで開いてコンパイルするだけ
WindowsのADSIを使用して、LDAPサーバからアドレスデータを取得するコード
WindowsではADSI(winldap32.dll)というやつが用意されているので、これでLDAPのアクセスを行う。
LDAPサーバに格納したinetOrgPersonから、全アドレスの電話番号、名前、グループ名称を取得する
LDAPに格納されたデータは、base64化されていたり、文字コードがutf-8だったりする(RFC)が、base64のデコードや、utf-8からの変換を、勝手にやってくれるので便利
wldap32.libをリンカに追加しておくこと
#include "StdAfx.h" #include <winldap.h> using namespace std; int main(void) { LDAP *ld; LDAPMessage* pMsg = NULL; if ( ( ld = ldap_open( "192.168.1.1", LDAP_PORT ) ) == NULL ) { printf("ldap_open error"); return -1; } const PCHAR SEARCH_BASE= "ou=sample,o=example,dc=test,dc=com"; const PCHAR ATTRIBUTE_CN = "cn"; const PCHAR ATTRIBUTE_Phone = "telephoneNumber"; const PCHAR ATTRIBUTE_OU = "ou"; //タイムアウト l_timeval tm; tm.tv_sec = 0; tm.tv_usec = 5*1000*1000; // LDAPサーチ if ( ldap_search_st( ld, SEARCH_BASE, LDAP_SCOPE_SUBTREE, NULL, NULL, 0,&tm, &pMsg ) != LDAP_SUCCESS ) { ldap_perror(ld, "ldap_search_s"); ldap_unbind ( ld ); _error_msg = "ldap_search_st timeout"; return -2; } if ( pMsg == NULL ) { _error_msg = "ldap_search_s returns NULL result."; ldap_unbind ( ld ); return -3; } //カウント int nCount = ldap_count_entries( ld, pMsg ); if ( nCount <= 0 ) { ldap_msgfree( pMsg ); ldap_unbind (ld ); return -4; } parray_address->reserve(nCount);//効率化 // Get each entry LDAPMessage* pEntry; for ( pEntry = ldap_first_entry( ld, pMsg ); pEntry != NULL ; pEntry = ldap_next_entry( ld, pEntry ) ) { char** ppszPhone = NULL; char** ppszCn = NULL; char** ppszOu = NULL; ppszPhone = ldap_get_values( ld, pEntry, ATTRIBUTE_Phone ); if(ppszPhone == NULL){ continue; }else if(ppszPhone[0] == NULL){ ldap_value_free( ppszPhone ); continue; } ppszCn = ldap_get_values( ld, pEntry, ATTRIBUTE_CN ); if(ppszCn == NULL){ ldap_value_free( ppszPhone ); continue; }else if(ppszCn[0] == NULL){ ldap_value_free( ppszPhone ); ldap_value_free( ppszCn ); continue; } ppszOu = ldap_get_values( ld, pEntry, ATTRIBUTE_OU ); if(ppszOu == NULL){ ldap_value_free( ppszPhone ); ldap_value_free( ppszCn ); continue; }//グループは空を許可 printf("telnumber = %s\n",ppszPhone[0]); printf("name = %s\n",ppszCn[0]); printf("group = %s\n",ppszOu[0]); //文字列解放 if(ppszPhone){ ldap_value_free( ppszPhone ); } if(ppszCn){ ldap_value_free( ppszCn ); } if(ppszOu){ ldap_value_free( ppszOu ); } } //解放 ldap_msgfree( pMsg ); ldap_unbind ( ld ); return 0; }
Javascript正規表現オンラインチェッカー
すぐ忘れてしまい必死にググってもなかなか出てこないのに
懲りたのでメモる。
Regex Tester
http://regexpal.com/
下段にデータを入れ、上段に正規表現を記入する
matchした部分は、黄色くハイライトされ、わかりやすい。
一番いいところは、リアルタイムに結果がわかるので非常に助かる。
Trac 0.10.5で、BatchModifyPluginインストール後、カスタムクエリのリンクが消える
Trac 0.10.5の管理をまかされてしまった。
ちまちまチケットを変更するのが面倒なので、カスタムクエリの結果に対して、一気にチケットを修正できるBatchModifyPluginを入れ、こりゃあ便利だな、と思ってたところ、TICKET_BATCH_MODIFY権限が無い人からクレームが。
「カスタムクエリへのリンクが消えてるじゃないか、どうなってんの?」
一般権限で入ると、たしかにカスタムクエリへのリンクが無くなっている。
なんだろう。0.10.5の日本語版との相性だろうか。
ググッっても全く情報が出てこない。うちの環境だけだろうか。
どう設定を変更してもダメだったので、ソースを参照して自分で修正するしかないと観念した。
tracのプラグインどころか、pythonを読むのもいじるのはじめてだったので、カット&トライの繰り返し。(運用中にやるなよ)
batchmod/web_ui.pyを開き、26行目から
# INavigationContributor methods def get_active_navigation_item(self, req): return QueryModule(self.env).get_active_navigation_item(req) def get_navigation_items(self, req): # from trac.ticket.report import ReportModule # if req.perm.has_permission('TICKET_VIEW') and \ # not self.env.is_component_enabled(ReportModule): # yield ('mainnav', 'tickets', # html.A('View Tickets', href=req.href.query())) # elif req.perm.has_permission('TICKET_BATCH_MODIFY'): yield ('mainnav', 'query', html.A('Custom Query', href=req.href.query()))
こんな感じにコメントアウト
一般権限でも無条件で表示させるようにした。
あとはpython setup.py installで終了。
ちゃんとBatchModify画面は表示されていないことも確認済み。