pppob.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       pppob.cc
00003 ///             In the same vein as pppoe, used with pppd to create a
00004 ///             pty tunnel and GPRS modem link.
00005 ///
00006 
00007 /*
00008     Copyright (C) 2007-2008, Net Direct Inc. (http://www.netdirect.ca/)
00009 
00010     This program is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     This program is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019     See the GNU General Public License in the COPYING file at the
00020     root directory of this project for more details.
00021 */
00022 
00023 #include <barry/barry.h>
00024 #include <iomanip>
00025 #include <iostream>
00026 #include <fstream>
00027 #include <vector>
00028 #include <string>
00029 #include <memory>
00030 #include <getopt.h>
00031 #include <sys/select.h>
00032 #include <sys/time.h>
00033 #include <sys/types.h>
00034 #include <unistd.h>
00035 #include <signal.h>
00036 
00037 
00038 using namespace std;
00039 using namespace Barry;
00040 
00041 bool data_dump = false;
00042 volatile bool signal_end = false;
00043 
00044 void Usage()
00045 {
00046    int major, minor;
00047    const char *Version = Barry::Version(major, minor);
00048 
00049    cerr
00050    << "pppob - PPP over Barry\n"
00051    << "        Copyright 2007-2008, Net Direct Inc. (http://www.netdirect.ca/)\n"
00052    << "        Using: " << Version << "\n"
00053    << "\n"
00054    << "   -l file   Direct pppob log output to file (useful with -v)\n"
00055    << "   -p pin    PIN of device to talk with\n"
00056    << "             If only one device plugged in, this flag is optional\n"
00057    << "   -P pass   Simplistic method to specify device password\n"
00058    << "   -s        Use Serial mode instead of IpModem\n"
00059    << "   -v        Dump protocol data during operation (debugging only!)\n"
00060    << endl;
00061 }
00062 
00063 void signal_handler(int signum)
00064 {
00065         signal_end = true;
00066 }
00067 
00068 void SerialDataCallback(void *context, const unsigned char *data, int len)
00069 {
00070         if( len && data_dump )
00071                 barryverbose("ReadThread:\n" << Data(data, len));
00072 
00073         while( len ) {
00074                 int written = write(1, data, len);
00075                 if( written > 0 ) {
00076                         len -= written;
00077                         data += written;
00078                 }
00079                 else {
00080                         barryverbose("Error in write()");
00081                 }
00082         }
00083 }
00084 
00085 void ProcessStdin(Modem &modem)
00086 {
00087         // Read from stdin and write to USB, until
00088         // stdin is closed
00089         Data data;
00090         int bytes_read;
00091         fd_set rfds;
00092         struct timeval tv;
00093         int ret;
00094 
00095         // Handle interrupt signals from pppd
00096         signal_end = false;
00097         signal(SIGINT, &signal_handler);
00098         signal(SIGHUP, &signal_handler);
00099         signal(SIGTERM, &signal_handler);
00100 
00101         FD_ZERO(&rfds);
00102         while( signal_end == false ) {
00103                 // Need to use select() here, so that pppd doesn't
00104                 // hang when it tries to set the line discipline
00105                 // on our stdin.
00106 
00107                 FD_SET(0, &rfds);
00108                 tv.tv_sec = 30;
00109                 tv.tv_usec = 0;
00110 
00111                 ret = select(1, &rfds, NULL, NULL, &tv);
00112                 if( ret == -1 ) {
00113                         perror("select()");
00114                 }
00115                 else if( ret && FD_ISSET(0, &rfds) ) {
00116                         bytes_read = read(0, data.GetBuffer(), data.GetBufSize());
00117                         if( bytes_read == 0 )
00118                                 break;
00119 
00120                         if( bytes_read > 0 ) {
00121                                 data.ReleaseBuffer(bytes_read);
00122                                 modem.Write(data);
00123                         }
00124                 }
00125         }
00126 }
00127 
00128 int main(int argc, char *argv[])
00129 {
00130         cout.sync_with_stdio(true);     // leave this on, since libusb uses
00131                                         // stdio for debug messages
00132 
00133         try {
00134 
00135                 uint32_t pin = 0;
00136                 bool force_serial = false;
00137                 std::string logfile;
00138                 std::string password;
00139 
00140                 // process command line options
00141                 for(;;) {
00142                         int cmd = getopt(argc, argv, "l:p:P:sv");
00143                         if( cmd == -1 )
00144                                 break;
00145 
00146                         switch( cmd )
00147                         {
00148                         case 'l':       // Verbose log file
00149                                 logfile = optarg;
00150                                 break;
00151 
00152                         case 'p':       // Blackberry PIN
00153                                 pin = strtoul(optarg, NULL, 16);
00154                                 break;
00155 
00156                         case 'P':       // Device password
00157                                 password = optarg;
00158                                 break;
00159 
00160                         case 's':       // Use Serial mode
00161                                 force_serial = true;
00162                                 break;
00163 
00164                         case 'v':       // data dump on
00165                                 data_dump = true;
00166                                 break;
00167 
00168                         case 'h':       // help
00169                         default:
00170                                 Usage();
00171                                 return 0;
00172                         }
00173                 }
00174 
00175                 // Initialize the barry library.  Must be called before
00176                 // anything else.
00177                 // Log to stderr, since stdout is for data in this program.
00178                 std::auto_ptr<std::ofstream> log;
00179                 if( logfile.size() ) {
00180                         log.reset( new std::ofstream(logfile.c_str(), ios::app) );
00181                         Barry::Init(data_dump, log.get());
00182                 }
00183                 else {
00184                         Barry::Init(data_dump, &std::cerr);
00185                 }
00186 
00187                 // Probe the USB bus for Blackberry devices and display.
00188                 // If user has specified a PIN, search for it in the
00189                 // available device list here as well
00190                 Barry::Probe probe;
00191                 int activeDevice = probe.FindActive(pin);
00192                 if( activeDevice == -1 ) {
00193                         if( pin )
00194                                 cerr << "PIN " << setbase(16) << pin
00195                                         << " not found" << endl;
00196                         cerr << "No device selected" << endl;
00197                         return 1;
00198                 }
00199 
00200                 const ProbeResult &device = probe.Get(activeDevice);
00201 
00202                 if( !force_serial && device.HasIpModem() ) {
00203                         barryverbose("Using IpModem mode...");
00204 
00205                         // Create our controller object using our threaded router.
00206                         Controller con(probe.Get(activeDevice));
00207 
00208                         // Open serial mode... the callback handles reading from
00209                         // USB and writing to stdout
00210                         Mode::IpModem modem(con, SerialDataCallback, 0);
00211                         modem.Open(password.c_str());
00212 
00213                         ProcessStdin(modem);
00214                         modem.Close();  // graceful close so we can restart without unplugging
00215                 }
00216                 else {
00217                         barryverbose("Using Serial mode...");
00218 
00219                         // Create our socket router and start thread to handle
00220                         // the USB reading, instead of creating our own thread.
00221                         SocketRoutingQueue router;
00222                         router.SpinoffSimpleReadThread();
00223 
00224                         // Create our controller object using our threaded router.
00225                         Controller con(probe.Get(activeDevice), router);
00226 
00227                         // Open desktop mode... this handles the password side
00228                         // of things
00229                         Mode::Desktop desktop(con);
00230                         desktop.Open(password.c_str());
00231 
00232                         // Open serial connection
00233                         Mode::Serial modem(con, SerialDataCallback, 0);
00234                         modem.Open();
00235 
00236                         ProcessStdin(modem);
00237                 }
00238 
00239                 barryverbose("Exiting");
00240 
00241         }
00242         catch( std::exception &e ) {
00243                 cerr << "exception caught in main(): " << e.what() << endl;
00244                 return 1;
00245         }
00246 
00247         return 0;
00248 }
00249 

Generated on Wed Sep 24 21:27:32 2008 for Barry by  doxygen 1.5.1