DCCConnect.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /*
  2. * The contents of this file are subject to the Mozilla Public
  3. * License Version 1.1 (the "License"); you may not use this file
  4. * except in compliance with the License. You may obtain a copy of
  5. * the License at http://www.mozilla.org/MPL/
  6. *
  7. * Software distributed under the License is distributed on an "AS
  8. * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9. * implied. See the License for the specific language governing
  10. * rights and limitations under the License.
  11. *
  12. * The Original Code is Vision.
  13. *
  14. * The Initial Developer of the Original Code is The Vision Team.
  15. * Portions created by The Vision Team are
  16. * Copyright (C) 1999, 2000, 2001 The Vision Team. All Rights
  17. * Reserved.
  18. *
  19. * Contributor(s): Rene Gollent
  20. * Wade Majors
  21. * Todd Lair
  22. */
  23. #include <StatusBar.h>
  24. #include <StringView.h>
  25. #include <Path.h>
  26. #include <Mime.h>
  27. #include <Window.h>
  28. #include <arpa/inet.h>
  29. #include <netinet/in.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <sys/time.h>
  33. #include <sys/socket.h>
  34. #include "Vision.h"
  35. #include "ServerAgent.h"
  36. #include "DCCConnect.h"
  37. #include "PlayButton.h"
  38. DCCConnect::DCCConnect (
  39. const char *n,
  40. const char *fn,
  41. const char *sz,
  42. const char *i,
  43. const char *p,
  44. const BMessenger &c)
  45. : BView (
  46. BRect (0.0, 0.0, 275.0, 150.0),
  47. "dcc connect",
  48. B_FOLLOW_LEFT | B_FOLLOW_TOP,
  49. B_WILL_DRAW),
  50. fCaller (c),
  51. fNick (n),
  52. fFileName (fn),
  53. fSize (sz),
  54. fIp (i),
  55. fPort (p),
  56. fTotalTransferred (0),
  57. fFinalRateAverage (0),
  58. fTid (-1),
  59. fIsStopped (false)
  60. {
  61. SetViewColor (ui_color (B_PANEL_BACKGROUND_COLOR));
  62. char trail[128];
  63. sprintf (trail, " / %.1fk", atol (fSize.String()) / 1024.0);
  64. fBar = new BStatusBar (
  65. BRect (10, 10, Bounds().right - 30, Bounds().bottom - 10),
  66. "progress",
  67. S_DCC_SPEED,
  68. trail);
  69. fBar->SetMaxValue (atol (fSize.String()));
  70. fBar->SetBarHeight (8.0);
  71. AddChild (fBar);
  72. fLabel = new BStringView (
  73. BRect (10, 10, Bounds().right - 10, Bounds().bottom - 10),
  74. "label",
  75. "",
  76. B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
  77. AddChild (fLabel);
  78. fStop = new StopButton (
  79. BPoint (fBar->Frame().right + 15, fBar->Frame().bottom - 18),
  80. new BMessage (M_DCC_STOP_BUTTON));
  81. AddChild (fStop);
  82. }
  83. DCCConnect::~DCCConnect (void)
  84. {
  85. }
  86. void
  87. DCCConnect::AttachedToWindow (void)
  88. {
  89. fStop->SetTarget (this);
  90. }
  91. void
  92. DCCConnect::AllAttached (void)
  93. {
  94. fStop->MoveTo (
  95. fBar->Frame().right + 15, fBar->Frame().bottom - 18);
  96. fLabel->MoveTo (
  97. fLabel->Frame().left,
  98. fBar->Frame().bottom + 1);
  99. float width, height;
  100. fLabel->GetPreferredSize (&width, &height);
  101. fLabel->ResizeTo (fLabel->Frame().Width(), height);
  102. ResizeTo (fStop->Frame().right + 5, fLabel->Frame().bottom + 5.0);
  103. }
  104. void
  105. DCCConnect::DetachedFromWindow (void)
  106. {
  107. }
  108. void
  109. DCCConnect::Draw (BRect)
  110. {
  111. BView *top (Window()->ChildAt (0));
  112. if (this != top)
  113. {
  114. BeginLineArray (2);
  115. AddLine (
  116. Bounds().LeftTop(),
  117. Bounds().RightTop(),
  118. tint_color (ViewColor(), B_DARKEN_2_TINT));
  119. AddLine (
  120. Bounds().LeftTop() + BPoint (0.0, 1.0),
  121. Bounds().RightTop() + BPoint (0.0, 1.0),
  122. tint_color (ViewColor(), B_LIGHTEN_MAX_TINT));
  123. EndLineArray();
  124. }
  125. }
  126. void
  127. DCCConnect::MessageReceived (BMessage *msg)
  128. {
  129. switch (msg->what)
  130. {
  131. case M_DCC_STOP_BUTTON:
  132. {
  133. Stopped();
  134. }
  135. break;
  136. case M_DCC_UPDATE_STATUS:
  137. {
  138. fLabel->SetText (msg->FindString ("text"));
  139. }
  140. break;
  141. case M_DCC_GET_CONNECT_DATA:
  142. {
  143. BMessage reply;
  144. reply.AddString ("port", fPort.String());
  145. reply.AddString ("ip", fIp.String());
  146. reply.AddString ("name", fFileName.String());
  147. reply.AddString ("nick", fNick.String());
  148. reply.AddString ("size", fSize.String());
  149. DCCReceive *recview (dynamic_cast<DCCReceive *>(this));
  150. if (recview != NULL)
  151. reply.AddBool ("resume", recview->fResume);
  152. DCCSend *sendview (dynamic_cast<DCCSend *>(this));
  153. if (sendview != NULL)
  154. reply.AddMessenger ("caller", sendview->fCaller);
  155. msg->SendReply(&reply);
  156. }
  157. break;
  158. case M_DCC_GET_RESUME_POS:
  159. {
  160. BMessage reply;
  161. DCCSend *sendview (dynamic_cast<DCCSend *>(this));
  162. if (sendview != NULL)
  163. reply.AddInt32 ("pos", sendview->fPos);
  164. msg->SendReply(&reply);
  165. }
  166. break;
  167. case M_DCC_UPDATE_TRANSFERRED:
  168. {
  169. fTotalTransferred = msg->FindInt32 ("transferred");
  170. }
  171. break;
  172. case M_DCC_UPDATE_AVERAGE:
  173. {
  174. fFinalRateAverage = msg->FindInt32 ("average");
  175. }
  176. break;
  177. default:
  178. BView::MessageReceived (msg);
  179. }
  180. }
  181. void
  182. DCCConnect::Stopped (void)
  183. {
  184. if (fTotalTransferred > 0)
  185. {
  186. BMessage xfermsg (M_DCC_COMPLETE);
  187. xfermsg.AddString("nick", fNick.String());
  188. xfermsg.AddString("file", fFileName.String());
  189. xfermsg.AddString("size", fSize.String());
  190. xfermsg.AddInt32("transferred", fTotalTransferred);
  191. xfermsg.AddInt32("transferRate", fFinalRateAverage);
  192. DCCReceive *recview = dynamic_cast<DCCReceive *>(this);
  193. if (recview)
  194. {
  195. xfermsg.AddString("type", "RECV");
  196. }
  197. else
  198. {
  199. xfermsg.AddString("type", "SEND");
  200. }
  201. fCaller.SendMessage(&xfermsg);
  202. }
  203. BMessage msg (M_DCC_FINISH);
  204. msg.AddPointer ("source", this);
  205. msg.AddBool ("stopped", true);
  206. Window()->PostMessage (&msg);
  207. }
  208. void
  209. DCCConnect::Lock (void)
  210. {
  211. }
  212. void
  213. DCCConnect::Unlock (void)
  214. {
  215. }
  216. void
  217. DCCConnect::UpdateBar (const BMessenger &msgr, int readSize, int cps, uint32 size, bool update)
  218. {
  219. BMessage msg (B_UPDATE_STATUS_BAR);
  220. if (update)
  221. {
  222. char text[128];
  223. sprintf (text, "%.1f", size / 1024.0);
  224. msg.AddString ("trailing_text", text);
  225. sprintf (text, "%d", cps);
  226. msg.AddString ("text", text);
  227. }
  228. msg.AddFloat ("delta", readSize);
  229. BLooper *looper (NULL);
  230. DCCConnect *transferView ((DCCConnect *)msgr.Target(&looper));
  231. if ((looper != NULL) && (transferView != NULL))
  232. looper->PostMessage (&msg, transferView->fBar);
  233. }
  234. void
  235. DCCConnect::UpdateStatus (const BMessenger &msgr, const char *text)
  236. {
  237. BMessage msg (M_DCC_UPDATE_STATUS);
  238. msg.AddString ("text", text);
  239. msgr.SendMessage (&msg);
  240. }
  241. DCCReceive::DCCReceive (
  242. const char *n,
  243. const char *fn,
  244. const char *sz,
  245. const char *i,
  246. const char *p,
  247. const BMessenger &c,
  248. bool cont)
  249. : DCCConnect (n, fn, sz, i, p, c),
  250. fResume (cont)
  251. {
  252. }
  253. DCCReceive::~DCCReceive (void)
  254. {
  255. }
  256. void
  257. DCCReceive::AttachedToWindow (void)
  258. {
  259. DCCConnect::AttachedToWindow();
  260. fTid = spawn_thread (
  261. Transfer,
  262. "DCC Receive",
  263. B_NORMAL_PRIORITY,
  264. this);
  265. resume_thread (fTid);
  266. }
  267. int32
  268. DCCReceive::Transfer (void *arg)
  269. {
  270. BMessenger msgr (reinterpret_cast<DCCReceive *>(arg));
  271. struct sockaddr_in address;
  272. BLooper *looper (NULL);
  273. int32 dccSock (-1);
  274. if ((dccSock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  275. {
  276. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  277. return B_ERROR;
  278. }
  279. BMessage reply;
  280. if (msgr.SendMessage (M_DCC_GET_CONNECT_DATA, &reply) == B_ERROR)
  281. return B_ERROR;
  282. memset (&address, 0, sizeof(sockaddr_in));
  283. address.sin_family = AF_INET;
  284. address.sin_port = htons (atoi (reply.FindString ("port")));
  285. address.sin_addr.s_addr = htonl(strtoul (reply.FindString("ip"), 0, 10));
  286. UpdateStatus (msgr, S_DCC_CONNECT_TO_SENDER);
  287. if (connect (dccSock, (sockaddr *)&address, sizeof (address)) < 0)
  288. {
  289. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  290. close (dccSock);
  291. return B_ERROR;
  292. }
  293. BPath path (reply.FindString("name"));
  294. BString buffer;
  295. off_t file_size (0);
  296. buffer << S_DCC_RECV1
  297. << path.Leaf()
  298. << S_DCC_RECV2
  299. << reply.FindString ("nick")
  300. << ".";
  301. UpdateStatus (msgr, buffer.String());
  302. BFile file;
  303. if (msgr.IsValid())
  304. {
  305. if (reply.FindBool ("resume"))
  306. {
  307. if (file.SetTo (
  308. reply.FindString("name"),
  309. B_WRITE_ONLY | B_OPEN_AT_END) == B_NO_ERROR
  310. && file.GetSize (&file_size) == B_NO_ERROR
  311. && file_size > 0LL)
  312. UpdateBar (msgr, file_size, 0, 0, true);
  313. else
  314. file_size = 0LL;
  315. }
  316. else
  317. {
  318. file.SetTo (
  319. reply.FindString("name"),
  320. B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
  321. }
  322. }
  323. uint32 bytes_received (file_size);
  324. uint32 size (atol (reply.FindString("size")));
  325. uint32 cps (0);
  326. if (file.InitCheck() == B_NO_ERROR)
  327. {
  328. bigtime_t last (system_time()), now;
  329. char inBuffer[8196];
  330. bigtime_t start = system_time();
  331. while ((msgr.Target(&looper) != NULL) && bytes_received < size)
  332. {
  333. int readSize;
  334. if ((readSize = recv (dccSock, inBuffer, 8196, 0)) < 0)
  335. break;
  336. file.Write (inBuffer, readSize);
  337. bytes_received += readSize;
  338. BMessage msg (M_DCC_UPDATE_TRANSFERRED);
  339. msg.AddInt32 ("transferred", bytes_received);
  340. msgr.SendMessage (&msg);
  341. uint32 feed_back (htonl (bytes_received));
  342. send (dccSock, &feed_back, sizeof (uint32), 0);
  343. now = system_time();
  344. bool hit (false);
  345. if (now - last > 500000)
  346. {
  347. cps = (int)ceil ((bytes_received - file_size) / ((now - start) / 1000000.0));
  348. BMessage updmsg (M_DCC_UPDATE_AVERAGE);
  349. updmsg.AddInt32 ("average", cps);
  350. msgr.SendMessage (&updmsg);
  351. last = now;
  352. hit = true;
  353. }
  354. DCCConnect::UpdateBar (msgr, readSize, cps, bytes_received, hit);
  355. }
  356. }
  357. if (msgr.IsValid())
  358. {
  359. BMessage msg (M_DCC_STOP_BUTTON);
  360. msgr.SendMessage (&msg);
  361. }
  362. if (dccSock > 0)
  363. {
  364. close (dccSock);
  365. }
  366. if (file.InitCheck() == B_OK)
  367. {
  368. file.Unset();
  369. update_mime_info (reply.FindString("name"), 0, 0, 1);
  370. }
  371. return 0;
  372. }
  373. DCCSend::DCCSend (
  374. const char *n,
  375. const char *fn,
  376. const char *sz,
  377. const BMessenger &c)
  378. : DCCConnect (n, fn, sz, "", "", c),
  379. fPos (0LL)
  380. {
  381. int32 dccPort (atoi (vision_app->GetString ("dccMinPort")));
  382. int32 diff (atoi (vision_app->GetString ("dccMaxPort")) - dccPort);
  383. if (diff > 0)
  384. dccPort += rand() % diff;
  385. fPort << dccPort;
  386. }
  387. DCCSend::~DCCSend (void)
  388. {
  389. }
  390. void
  391. DCCSend::AttachedToWindow (void)
  392. {
  393. DCCConnect::AttachedToWindow();
  394. fTid = spawn_thread (
  395. Transfer,
  396. "DCC Send",
  397. B_NORMAL_PRIORITY,
  398. this);
  399. resume_thread (fTid);
  400. }
  401. int32
  402. DCCSend::Transfer (void *arg)
  403. {
  404. BMessenger msgr (reinterpret_cast<DCCSend *>(arg));
  405. BMessage reply, ipdata;
  406. BLooper *looper (NULL);
  407. if (msgr.IsValid())
  408. msgr.SendMessage (M_DCC_GET_CONNECT_DATA, &reply);
  409. BMessenger callmsgr;
  410. reply.FindMessenger ("caller", &callmsgr);
  411. callmsgr.SendMessage (M_GET_IP, &ipdata);
  412. BPath path (reply.FindString ("name"));
  413. BString fileName, status;
  414. struct sockaddr_in address;
  415. struct in_addr sendaddr;
  416. memset (&sendaddr, 0, sizeof (struct in_addr));
  417. int sd, dccSock (-1);
  418. fileName.Append (path.Leaf());
  419. fileName.ReplaceAll (" ", "_");
  420. if ((sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  421. {
  422. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  423. return 0;
  424. }
  425. memset (&address, 0, sizeof (struct sockaddr_in));
  426. address.sin_family = AF_INET;
  427. address.sin_addr.s_addr = INADDR_ANY;
  428. address.sin_port = htons (atoi (reply.FindString("port")));
  429. int sin_size;
  430. sin_size = (sizeof (struct sockaddr_in));
  431. UpdateStatus (msgr, S_DCC_LOCK_ACQUIRE B_UTF8_ELLIPSIS);
  432. vision_app->AcquireDCCLock();
  433. if (!msgr.IsValid() || bind (sd, (sockaddr *)&address, sin_size) < 0)
  434. {
  435. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  436. vision_app->ReleaseDCCLock();
  437. close (sd);
  438. return 0;
  439. }
  440. UpdateStatus (msgr, S_DCC_ACK_WAIT);
  441. sendaddr.s_addr = inet_addr (ipdata.FindString ("ip"));
  442. if (msgr.IsValid())
  443. {
  444. status = "PRIVMSG ";
  445. status << reply.FindString ("nick")
  446. << " :\1DCC SEND "
  447. << fileName
  448. << " "
  449. << htonl (sendaddr.s_addr)
  450. << " "
  451. << reply.FindString ("port")
  452. << " "
  453. << reply.FindString ("size")
  454. << "\1";
  455. BMessage msg (M_SERVER_SEND);
  456. msg.AddString ("data", status.String());
  457. if (callmsgr.IsValid())
  458. callmsgr.SendMessage (&msg);
  459. UpdateStatus (msgr, S_DCC_LISTEN_CALL);
  460. if (listen (sd, 1) < 0)
  461. {
  462. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  463. vision_app->ReleaseDCCLock();
  464. close (sd);
  465. return 0;
  466. }
  467. }
  468. struct timeval t;
  469. t.tv_sec = 2;
  470. t.tv_usec = 0;
  471. uint32 try_count (0);
  472. while (msgr.Target(&looper) != NULL)
  473. {
  474. fd_set rset;
  475. FD_ZERO (&rset);
  476. FD_SET (sd, &rset);
  477. if (select (sd + 1, &rset, 0, 0, &t) < 0)
  478. {
  479. UpdateStatus (msgr, S_DCC_ESTABLISH_ERROR);
  480. vision_app->ReleaseDCCLock();
  481. close (sd);
  482. return 0;
  483. }
  484. if (FD_ISSET (sd, &rset))
  485. {
  486. dccSock = accept (sd, (sockaddr *)&address, (socklen_t *)&sin_size);
  487. UpdateStatus (msgr, S_DCC_ESTABLISH_SUCCEEDED);
  488. break;
  489. }
  490. ++try_count;
  491. status = S_DCC_WAIT_FOR_CONNECTION;
  492. status << try_count << ".";
  493. UpdateStatus (msgr, status.String());
  494. }
  495. vision_app->ReleaseDCCLock();
  496. char set[4];
  497. memset(set, 1, sizeof(set));
  498. close (sd);
  499. BFile file;
  500. file.SetTo(reply.FindString ("name"), B_READ_ONLY);
  501. int32 bytes_sent (0L),
  502. seekpos (0L);
  503. BMessage resumeData;
  504. msgr.SendMessage (M_DCC_GET_RESUME_POS, &resumeData);
  505. if (resumeData.HasInt32 ("pos"))
  506. {
  507. resumeData.FindInt32 ("pos", &seekpos);
  508. file.Seek (seekpos, SEEK_SET);
  509. UpdateBar (msgr, seekpos, 0, 0, true);
  510. bytes_sent = seekpos;
  511. }
  512. status = S_DCC_SEND1;
  513. status << path.Leaf()
  514. << S_DCC_SEND2
  515. << reply.FindString ("nick")
  516. << ".";
  517. UpdateStatus (msgr, status.String());
  518. int cps (0);
  519. if (file.InitCheck() == B_NO_ERROR)
  520. {
  521. bigtime_t last (system_time()), now;
  522. const uint32 DCC_BLOCK_SIZE (atoi(vision_app->GetString ("dccBlockSize")));
  523. #ifdef __INTEL__
  524. char buffer[DCC_BLOCK_SIZE];
  525. #else
  526. char *buffer = new char[DCC_BLOCK_SIZE];
  527. #endif
  528. int period (0);
  529. ssize_t count (0);
  530. bigtime_t start = system_time();
  531. while ((msgr.Target(&looper) != NULL)
  532. && (count = file.Read (buffer, DCC_BLOCK_SIZE - 1)) > 0)
  533. {
  534. int sent;
  535. if ((sent = send (dccSock, buffer, count, 0)) < count)
  536. {
  537. UpdateStatus (msgr, S_DCC_WRITE_ERROR);
  538. break;
  539. }
  540. uint32 confirm (0),
  541. newSize (bytes_sent + count);
  542. fd_set rset, eset;
  543. FD_ZERO (&rset);
  544. FD_ZERO (&eset);
  545. FD_SET (dccSock, &rset);
  546. t.tv_sec = 0;
  547. t.tv_usec = 10;
  548. while ((confirm < newSize)
  549. && (recv(dccSock, &confirm, sizeof (confirm), 0) > 0))
  550. {
  551. confirm = ntohl(confirm);
  552. bytes_sent = confirm;
  553. }
  554. BMessage msg (M_DCC_UPDATE_TRANSFERRED);
  555. msg.AddInt32 ("transferred", bytes_sent);
  556. msgr.SendMessage (&msg);
  557. now = system_time();
  558. period += sent;
  559. bool hit (false);
  560. if (now - last > 500000)
  561. {
  562. cps = (int) ceil ((bytes_sent - seekpos) / ((now - start) / 1000000.0));
  563. BMessage updmsg (M_DCC_UPDATE_AVERAGE);
  564. updmsg.AddInt32 ("average", cps);
  565. msgr.SendMessage (&updmsg);
  566. last = now;
  567. period = 0;
  568. hit = true;
  569. }
  570. UpdateBar (msgr, sent, cps, bytes_sent, hit);
  571. }
  572. #ifndef __INTEL__
  573. delete [] buffer;
  574. #endif
  575. }
  576. if (msgr.IsValid())
  577. {
  578. BMessage msg (M_DCC_STOP_BUTTON);
  579. msgr.SendMessage (&msg);
  580. }
  581. if (dccSock > 0)
  582. {
  583. close (dccSock);
  584. }
  585. if (file.InitCheck() == B_OK)
  586. file.Unset();
  587. return 0;
  588. }
  589. bool
  590. DCCSend::IsMatch (const char *n, const char *p) const
  591. {
  592. return fNick == n && fPort == p;
  593. }
  594. void
  595. DCCSend::SetResume (off_t p)
  596. {
  597. fPos = p;
  598. }