825 lines
60 KiB
HTML
825 lines
60 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Be Newsletters - Volume 4: 1999</title><link rel="stylesheet" href="be_newsletter.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_newsletter_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Be Newsletters" /><link rel="up" href="volume4.html" title="Volume 4: 1999" /><link rel="prev" href="Issue4-15.html" title="Issue 4-15, April 14, 1999" /><link rel="next" href="Issue4-17.html" title="Issue 4-17, April 28, 1999" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue4-15.html" title="Issue 4-15, April 14, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="Issue4-17.html" title="Issue 4-17, April 28, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">Be Newsletters - Volume 4: 1999</div></div><div id="headerB">Prev: <a href="Issue4-15.html">Issue 4-15, April 14, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-17.html">Issue 4-17, April 28, 1999</a></div><hr /></div><div class="article"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Issue4-16"></a>Issue 4-16, April 21, 1999</h2></div></div></div><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Marketing4-16"></a>Here Comes the First Big Marketing Wave</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Roy</span> <span class="surname">Graham</span></span></div></div></div><p>
|
||
I'm nearing the end of my first month at Be and it has been the most
|
||
exciting and inspiring start that I have had at any company. I've been
|
||
particularly inspired by the passion shown by you, our Developers. Never
|
||
before have I seen such commitment to help a company succeed. Your
|
||
suggestions and comments come in thick and fast—some negatively
|
||
worded, most positive—but all with a passion that tells me you're
|
||
trying to help us all be even more successful. I love that.
|
||
</p><p>
|
||
Be has, you tell me, delivered great technology. Now it's time to
|
||
complement this with aggressive marketing, so we can rapidly expand the
|
||
user base to which you can market your applications. We're planning a
|
||
major marketing campaign for the second half of this year, with the
|
||
express goal of raising the market awareness of Be significantly, and
|
||
also of achieving a major expansion of the user base. Make plans to
|
||
attend PCExpo and be a part of our campaign kickoff.
|
||
</p><p>
|
||
In order to start our campaign with a bang, we needed a great product
|
||
platform. When I started at Be I spent a lot of time with Be developers,
|
||
learning the 4.1 release and where we were in the release cycle. It
|
||
quickly became apparent that it would not be ready for prime time until
|
||
June. You've come to expect very high quality from us and we're not about
|
||
to change that. So, late June is when to look for our next release.
|
||
</p><p>
|
||
Next we needed to decide what to call the release. Unfortunately, we'd
|
||
backed ourselves into a corner by calling it 4.1. Not any more. From now
|
||
on, all future releases will have a project name that is unrelated to
|
||
release numbers. Accordingly, 4.1 is now called Genki (Japanese for "all
|
||
is well"!!).
|
||
</p><p>
|
||
Closer to the release date we'll decide the exact version number (OK,
|
||
it's marketing, but give me some slack—I'm trying to help you by
|
||
expanding the user base for your applications!!). The good news is that
|
||
Genki (like 4.1) will remain an update, so it's free to all BeOS Release
|
||
4.0 users.
|
||
</p><p>
|
||
Other news that I announced at the BeDC included our expanded commitment
|
||
to the Japanese market, as attested to by the hiring of our first
|
||
employee in Japan, Takeaki Akahoshi, as Channel Sales Manager. Also, I've
|
||
initiated a crash program to get BeDepot into reasonable shape for now,
|
||
with a view to replacing it later this year with a longer term solution.
|
||
</p><p>
|
||
Finally, this quarter you'll see changes on the Be web site. We are
|
||
adding a commercial front end to give it a more polished look and feel,
|
||
with a view toward appealing to a wider audience.
|
||
</p><p>
|
||
So, I'm delighted to be on board and I look forward to working with you
|
||
as we ride the first big marketing wave.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering4-16"></a>Be Engineering Insights: Son of Teletype Meets Multimedia</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Rico</span> <span class="surname">Tudor</span></span></div></div></div><p>
|
||
I write this article a few days after the BeDC devoted to the Media Kit.
|
||
There, the air was abuzz with MP3, AVI, EXIF, and other esoteric
|
||
encodings. And yet, the lowly data format called ASCII lives on in the
|
||
waning light of the second millennium. Long after everyone has forgotten
|
||
how to interpret the data flavors of this month, there will still be a
|
||
way to read those old e-mail messages. If you can imagine the BeOS
|
||
Terminal app as the MediaPlayer for ASCII, then I will discuss part of
|
||
the ASCII kit cryptically named the pseudo-tty driver.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id780032"></a>History</h3></div></div></div><p>
|
||
The term "tty" is a contraction of Teletype, maker of such famous icons
|
||
as the Model 37 terminal. Printing noisily on paper, with margin bell and
|
||
optional paper tape punch, it was a multimedia device in its own right.
|
||
Historians can review its output in the early service of UNIX at
|
||
<a class="ulink" href="http://cm.bell-labs.com/cm/cs/who/dmr/1stEdman.html">http://cm.bell-labs.com/cm/cs/who/dmr/1stEdman.html</a>
|
||
</p><p>
|
||
The standard configuration in those days was
|
||
</p><pre class="screen">
|
||
shell—tty driver == tty
|
||
</pre><p>
|
||
where "--" indicates a user/kernel space interface, and "==" is a serial
|
||
cable. Hard copy terminals were replaced in time by "glass" ttys, and
|
||
ttys were replaced altogether by the PC (running a terminal emulator
|
||
program):
|
||
</p><pre class="screen">
|
||
shell—tty driver == tty driver—tty emulator
|
||
</pre><p>
|
||
As the PC gained CPU power and OS sophistication, there was no need for
|
||
the command line (shell) to reside on a distant, and expensive,
|
||
mini-computer or mainframe. This has resulted in entirely local plumbing
|
||
like so:
|
||
</p><pre class="screen">
|
||
shell—pty driver—tty emulator
|
||
</pre><p>
|
||
In essence, the pseudo-tty, or pty, driver acts as a tty driver with
|
||
serial line looped back. This concept was pioneered by the Berkeley
|
||
version of Unix, and is now universally available on UNIX and UNIX-like
|
||
systems.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id780092"></a>Purpose</h3></div></div></div><p>
|
||
Two distinct, but related, reasons for using the pty driver are to direct
|
||
interactive programs, and to provide tty services for them. These reasons
|
||
apply to command line programs only; BeOS apps that function graphically
|
||
are not going to be interested.
|
||
</p><p>
|
||
An interactive program tends to write <code class="filename">stdout</code> unbuffered or line-by-line.
|
||
This is less efficient, but operates sensibly with alternating prompts
|
||
and user input. The user can better see realtime progress, too. Posix
|
||
libraries determine whether the output is a "terminal" and, if not,
|
||
buffer output fully. Unfortunately, this means that running an
|
||
interactive program through a pipe doesn't work well:
|
||
</p><pre class="screen">
|
||
(sleep 1; echo bc; echo 1; echo '2^99999/2^99998') | sh
|
||
(sleep 1; echo bc; echo 1; echo '2^99999/2^99998') | sh | cat
|
||
</pre><p>
|
||
In the first case, the shell is instructed to start the desk calculator
|
||
<code class="command">bc</code>, which evaluates arithmetic expressions. Since the output is a
|
||
terminal, we see each result as it's ready. In the second case, <code class="command">bc</code> is
|
||
writing to a pipe, and all results are buffered until it exits.
|
||
</p><p>
|
||
Some programs behave even more radically when the output is a terminal.
|
||
Compare
|
||
</p><pre class="screen">
|
||
ls /bin
|
||
ls /bin | cat
|
||
</pre><p>
|
||
The general desire in all these cases is to control the shell and its
|
||
subprocesses with our own program, while appearing to be a terminal at
|
||
the far end of a serial line.
|
||
</p><p>
|
||
The second reason for using the pty driver is to provide tty services,
|
||
which includes input echoing, character erase
|
||
(<span class="keysym">ctrl</span>+<span class="keycap">H</span>),
|
||
signals
|
||
(<span class="keysym">ctrl</span>+<span class="keycap">C</span>),
|
||
etc. The services in BeOS are a subset of the Posix "termios" standard.
|
||
As an example, the Backspace key
|
||
(<span class="keysym">ctrl</span>+<span class="keycap">H</span>) erases the last character on
|
||
the current line of input; a program like <code class="command">bc</code> will see the fully formed
|
||
line only when you hit Return.
|
||
</p><p>
|
||
Current BeOS clients of the pty driver include "telnetd" (incoming telnet
|
||
connections), <span class="application">/bin/getty</span> (shell session on serial port), Terminal, and
|
||
Pavel's Eddie (C++ development environment).
|
||
</p><p>
|
||
The remainder of this article documents the code for a useful app called
|
||
"script." Modeled after the similarly named UNIX utility, it starts an
|
||
interactive subshell such that all I/O activity is recorded verbatim to a
|
||
log file, called "typescript." The code consists of two parts: first, a
|
||
reusable class called <code class="classname">PTY</code> and second, the particular use of this code for
|
||
"script."
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id780219"></a>The Code</h3></div></div></div><p>
|
||
Here is the declaration for the <code class="classname">PTY</code> class, which conveniently wraps the
|
||
pty driver. A program like "script" has quite a few chores, but these are
|
||
handled almost entirely by <code class="classname">PTY</code>. To use, you must derive your own class
|
||
from <code class="classname">PTY</code>, and define the hook functions
|
||
<code class="methodname">GetData()</code>, <code class="methodname">PutData()</code>,
|
||
and <code class="methodname">Done()</code>. Their
|
||
purpose is described later.
|
||
</p><pre class="programlisting cpp">
|
||
#include <Application.h>
|
||
#include <signal.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <termios.h>
|
||
#include <dirent.h>
|
||
|
||
#define <code class="function">ctrl</code>( <code class="parameter">c</code>) ((<code class="parameter">c</code>) - 0100)
|
||
|
||
struct <span class="type">PTY</span> {
|
||
<code class="methodname">PTY</code>( );
|
||
<code class="methodname">~PTY</code>( );
|
||
<span class="type">bool</span> <code class="methodname">Init</code>( <span class="type">char *</span>[]);
|
||
virtual <span class="type">int</span> <code class="methodname">GetData</code>( <span class="type">uchar</span> [], <span class="type">uint</span>) = 0;
|
||
virtual <span class="type">int</span> <code class="methodname">PutData</code>( <span class="type">uchar</span> [], <span class="type">uint</span>) = 0;
|
||
virtual <span class="type">void</span> <code class="methodname">Done</code>( ) = 0;
|
||
private:
|
||
<span class="type">bool</span> <code class="methodname">ptyinit</code>( );
|
||
static <span class="type">int32</span> <code class="methodname">feeder</code>( <span class="type">PTY *</span>),
|
||
<code class="methodname">drainer</code>( <span class="type">PTY *</span>);
|
||
<span class="type">struct termios</span> <code class="varname">tsaved</code>;
|
||
<span class="type">int</span> <code class="varname">ptyfd</code>,
|
||
<code class="varname">ttyfd</code>;
|
||
<span class="type">thread_id</span> <code class="varname">fid</code>,
|
||
<code class="varname">did</code>;
|
||
<span class="type">char</span> <code class="varname">tty</code>[40];
|
||
};
|
||
</pre><p>
|
||
A pair of devices are employed in a pty connection: master and slave. If
|
||
the master is <code class="filename">/dev/pt/p0</code>, then
|
||
the slave will be <code class="filename">/dev/tt/p0</code>. The shell
|
||
will inherit file descriptors to the slave, while "script" directs
|
||
through the master side. Finding an available pair uses the traditional
|
||
(ok, baroque) method: try to open each master device until one succeeds.
|
||
That master device is now yours exclusively. Here is the code:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">bool</span> <code class="classname">PTY</code>::<code class="methodname">ptyinit</code>( )
|
||
{
|
||
<span class="type">DIR *</span><code class="varname">dd</code> = <code class="function">opendir</code>( "/dev/pt");
|
||
while (<span class="type">dirent *</span><code class="varname">d</code> = <code class="function">readdir</code>( <code class="varname">dd</code>))
|
||
if (<code class="varname">d</code>-><code class="varname">d_name</code>[0] != '.') {
|
||
<code class="function">sprintf</code>( <code class="varname">tty</code>, "/dev/pt/%s", <code class="varname">d</code>-><code class="varname">d_name</code>);
|
||
<code class="varname">ptyfd</code> = <code class="function">open</code>( <code class="varname">tty</code>, <code class="constant">O_RDWR</code>);
|
||
if (<code class="varname">ptyfd</code> > 0) {
|
||
<code class="function">sprintf</code>( <code class="varname">tty</code>, "/dev/tt/%s", <code class="varname">d</code>-><code class="varname">d_name</code>);
|
||
<code class="varname">ttyfd</code> = <code class="function">open</code>( <code class="varname">tty</code>, <code class="constant">O_RDWR</code>);
|
||
if (<code class="varname">ttyfd</code> > 0) {
|
||
<code class="function">closedir</code>( <code class="varname">dd</code>);
|
||
return (<code class="constant">TRUE</code>);
|
||
}
|
||
<code class="function">close</code>( <code class="varname">ptyfd</code>);
|
||
}
|
||
}
|
||
<code class="function">closedir</code>( <code class="varname">dd</code>);
|
||
return (<code class="constant">FALSE</code>);
|
||
}
|
||
</pre><p>
|
||
The "." and ".." directory entries need to be skipped.
|
||
</p><p>
|
||
<span class="application">script</span> must maintain two data paths.
|
||
The first comes from the <code class="filename">stdin</code> of <span class="application">script</span>,
|
||
goes through the pty driver from master side to slave side, and
|
||
finally to the shell's <code class="filename">stdin</code>. The second path originates from the shell's
|
||
<code class="filename">stdout</code>, goes through the pty driver from slave side to master side, and
|
||
finally to the <code class="filename">stdout</code> of <span class="application">script</span>. It is that
|
||
<code class="filename">stdout</code> which is cloned off to the log file, <code class="filename">typescript</code>.
|
||
Each data path has a dedicated BeOS thread, using the following code:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">int32</span> <code class="classname">PTY</code>::<code class="methodname">feeder</code>( <span class="type">PTY *</span><code class="parameter">pty</code>)
|
||
{
|
||
<span class="type">uchar</span> <code class="varname">data</code>[1000];
|
||
<span class="type">int</span> <code class="varname">i</code>;
|
||
|
||
while ((<code class="varname">i</code> = <code class="parameter">pty</code>-><code class="methodname">GetData</code>( <code class="varname">data</code>, sizeof <code class="varname">data</code>)) > 0)
|
||
<code class="function">write</code>( <code class="parameter">pty</code>-><code class="varname">ptyfd</code>, <code class="varname">data</code>, <code class="varname">i</code>);
|
||
<code class="parameter">pty</code>-><code class="methodname">Done</code>( );
|
||
}
|
||
|
||
<span class="type">int32</span> <code class="classname">PTY</code>::<code class="methodname">drainer</code>( <span class="type">PTY *</span><code class="parameter">pty</code>)
|
||
{
|
||
<span class="type">uchar</span> <code class="varname">data</code>[1000];
|
||
<span class="type">int</span> <code class="varname">i</code>;
|
||
|
||
while ((<code class="varname">i</code> = <code class="function">read</code>( <code class="parameter">pty</code>-><code class="varname">ptyfd</code>, <code class="varname">data</code>, sizeof <code class="varname">data</code>)) > 0)
|
||
<code class="parameter">pty</code>-><code class="methodname">PutData</code>( <code class="varname">data</code>, <code class="varname">i</code>);
|
||
<code class="parameter">pty</code>-><code class="methodname">Done</code>( );
|
||
}
|
||
</pre><p>
|
||
The read and write system calls typically block until data is available,
|
||
which is why we need the dedicated threads. This also ensures the desired
|
||
data flow control. In the idle state of <span class="application">script</span>,
|
||
the feeder thread is
|
||
blocked in a read of <code class="filename">stdin</code>, while the drainer thread is blocked in a read
|
||
of the master side pty. Meanwhile, the team's main thread can service
|
||
<code class="classname">BApplication</code>.
|
||
</p><p>
|
||
The constructor/destructor code saves and restores the tty mode of
|
||
<span class="application">script</span> stdio. The destructor must kill
|
||
the feeder and drainer threads,
|
||
since they are most likely blocked where polite methods, like semaphores,
|
||
cannot help.
|
||
</p><pre class="programlisting cpp">
|
||
<code class="classname">PTY</code>::<code class="methodname">PTY</code>( )
|
||
{
|
||
<code class="varname">fid</code> = <code class="varname">did</code> = -1;
|
||
<code class="function">tcgetattr</code>( 0, &<code class="varname">tsaved</code>);
|
||
}
|
||
|
||
<code class="classname">PTY</code>::<code class="methodname">~PTY</code>( )
|
||
{
|
||
<code class="function">tcsetattr</code>( 0, <code class="constant">TCSANOW</code>, &<code class="varname">tsaved</code>);
|
||
if (<code class="varname">did</code> > 0)
|
||
<code class="function">kill_thread</code>( <code class="varname">did</code>);
|
||
if (<code class="varname">fid</code> > 0)
|
||
<code class="function">kill_thread</code>( <code class="varname">fid</code>);
|
||
}
|
||
</pre><p>
|
||
Take a deep breath! This code exercises both BeOS and Posix functions, and
|
||
is where the bureaucratic details are hiding. Our pty connection consists
|
||
of slave side file descriptor "ttyfd" and master side
|
||
"ptyfd". The slave side tty mode is set to something human
|
||
friendly. Between the <code class="function">fork()</code> and the
|
||
<code class="function">execv()</code>, we have a chance to customize the execution
|
||
environment of the subshell. This includes its <code class="filename">stdin</code>,
|
||
<code class="filename">stdout</code>, <code class="filename">stderr</code>, name of
|
||
controlling tty device, and its own process group for signals. The subshell
|
||
will have no knowledge of "ptyfd", or the execution environment
|
||
of "script." If the subshell exits, "script" will get
|
||
master side i/o errors; if <span class="application">script</span> exits, the
|
||
entire subshell session will get a hangup signal
|
||
(<code class="constant">SIGHUP</code>).
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">bool</span> <code class="classname">PTY</code>::<code class="methodname">Init</code>( <span class="type">char *</span><code class="parameter">com</code>[])
|
||
{
|
||
if ( ! <code class="function">ptyinit</code>( )) {
|
||
<code class="function">fprintf</code>( <code class="varname">stderr</code>, "no available pty\n");
|
||
return (<code class="constant">FALSE</code>);
|
||
}
|
||
<span class="type">struct termios</span> <code class="varname">t</code>;
|
||
<span class="type">struct winsize</span> <code class="varname">w</code>;
|
||
<code class="function">memset</code>( &<code class="varname">t</code>, 0, <code class="function">sizeof</code>(<code class="varname">t</code>));
|
||
<code class="varname">t</code>.<code class="varname">c_iflag</code> = <code class="constant">ICRNL</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_oflag</code> = <code class="constant">OPOST</code> | <code class="constant">ONLCR</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_cflag</code> = <code class="constant">B19200</code> | <code class="constant">CS8</code> | <code class="constant">CREAD</code> | <code class="constant">HUPCL</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_lflag</code> = <code class="constant">ISIG</code> | <code class="constant">ICANON</code> | <code class="constant">ECHO</code> | <code class="constant">ECHOE</code> | <code class="constant">ECHONL</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VINTR</code>] = <code class="function">ctrl</code>( 'C');
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VQUIT</code>] = <code class="function">ctrl</code>( '\\');
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VERASE</code>] = <code class="function">ctrl</code>( 'H');
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VKILL</code>] = <code class="function">ctrl</code>( 'U');
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VEOF</code>] = <code class="function">ctrl</code>( 'D');
|
||
<code class="function">tcsetattr</code>( <code class="varname">ptyfd</code>, <code class="constant">TCSANOW</code>, &<code class="varname">t</code>);
|
||
if (<code class="function">ioctl</code>( 0, <code class="constant">TIOCGWINSZ</code>, &<code class="varname">w</code>) == 0)
|
||
<code class="function">ioctl</code>( <code class="varname">ptyfd</code>, <code class="constant">TIOCSWINSZ</code>, &<code class="varname">w</code>);
|
||
|
||
switch (<span class="type">pid_t</span> <code class="varname">pid</code> = <code class="function">fork</code>( )) {
|
||
case -1:
|
||
<code class="function">fprintf</code>( <code class="varname">stderr</code>, "system too busy\n");
|
||
return (<code class="constant">FALSE</code>);
|
||
case 0:
|
||
<span class="type">char</span> <code class="varname">te</code>[30];
|
||
<code class="varname">pid</code> = <code class="function">getpid</code>( );
|
||
<code class="function">setpgid</code>( <code class="varname">pid</code>, <code class="varname">pid</code>);
|
||
<code class="function">ioctl</code>( <code class="varname">ttyfd</code>, 'pgid', <code class="varname">pid</code>);
|
||
<code class="function">signal</code>( <code class="constant">SIGHUP</code>, <code class="constant">SIG_DFL</code>);
|
||
<code class="function">sprintf</code>( <code class="varname">te</code>, "TTY=%s", <code class="varname">tty</code>);
|
||
<code class="function">putenv</code>( <code class="varname">te</code>);
|
||
<code class="function">close</code>( 0);
|
||
<code class="function">close</code>( 1);
|
||
<code class="function">close</code>( 2);
|
||
<code class="function">dup</code>( <code class="varname">ttyfd</code>);
|
||
<code class="function">dup</code>( <code class="varname">ttyfd</code>);
|
||
<code class="function">dup</code>( <code class="varname">ttyfd</code>);
|
||
<code class="function">close</code>( <code class="varname">ptyfd</code>);
|
||
<code class="function">close</code>( <code class="varname">ttyfd</code>);
|
||
<code class="function">execv</code>( <code class="varname">com</code>[0], <code class="varname">com</code>);
|
||
<code class="function">fprintf</code>( <code class="varname">stderr</code>, "cannot exec %s\n", <code class="varname">com</code>[0]);
|
||
<code class="function">exit</code>( 0);
|
||
}
|
||
<code class="function">close</code>( <code class="varname">ttyfd</code>);
|
||
|
||
<code class="varname">t</code> = <code class="varname">tsaved</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_iflag</code> &= ~ <code class="constant">ICRNL</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_oflag</code> &= ~ <code class="constant">ONLCR</code>;
|
||
<code class="varname">t</code>.<code class="varname">c_lflag</code> &= ~ (<code class="constant">ISIG</code>|<code class="constant">ICANON</code>|<code class="constant">ECHO</code>|<code class="constant">ECHOE</code>|<code class="constant">ECHONL</code>);
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VMIN</code>] = 1;
|
||
<code class="varname">t</code>.<code class="varname">c_cc</code>[<code class="constant">VTIME</code>] = 0;
|
||
<code class="function">tcsetattr</code>( 0, <code class="constant">TCSANOW</code>, &<code class="varname">t</code>);
|
||
|
||
<code class="varname">fid</code> = <code class="function">spawn_thread</code>(<code class="varname">feeder</code>, "f", <code class="constant">B_NORMAL_PRIORITY</code>,
|
||
<code class="varname">this</code>);
|
||
<code class="varname">did</code> = <code class="function">spawn_thread</code>(<code class="varname">drainer</code>, "d", <code class="constant">B_NORMAL_PRIORITY</code>,
|
||
<code class="varname">this</code>);
|
||
if (<code class="varname">fid</code> < 0 || <code class="varname">did</code> < 0) {
|
||
<code class="function">fprintf</code>( <code class="varname">stderr</code>, "cannot spawn a thread\n");
|
||
return (<code class="constant">FALSE</code>);
|
||
}
|
||
<code class="function">resume_thread</code>( <code class="varname">fid</code>);
|
||
<code class="function">resume_thread</code>( <code class="varname">did</code>);
|
||
return (<code class="constant">TRUE</code>);
|
||
}
|
||
</pre><p>
|
||
With the subshell launched, <span class="application">script</span> must complete its own
|
||
initialization. Its own tty mode is set to "no echo" and "raw" (no
|
||
interpretation). This gives complete control of tty services to the
|
||
remote shell and its minions ("stty," text editors, etc). Finally, the
|
||
feeder and drainer threads are started.
|
||
</p><p>
|
||
That concludes the <code class="classname">PTY</code> class. With so much work already done, the
|
||
"script" app is almost a footnote. The boffo Script class, below, is
|
||
compactly defined with multiple inheritance.
|
||
</p><pre class="programlisting cpp">
|
||
struct <code class="classname">Script</code>: <code class="classname">BApplication</code>, <code class="classname">PTY</code>
|
||
{
|
||
<code class="methodname">Script</code>(<span class="type">char *</span><code class="parameter">sig</code>, <span class="type">char *</span><code class="parameter">c</code>[], <span class="type">char *</span><code class="parameter">log</code>): <code class="classname">BApplication</code>(<code class="parameter">sig</code>)
|
||
{
|
||
<code class="varname">com</code> = <code class="parameter">c</code>;
|
||
<code class="varname">logfd</code> = <code class="function">creat</code>( <code class="varname">log</code>, 0666);
|
||
<code class="methodname">Run</code>( );
|
||
}
|
||
|
||
<span class="type">void</span> <code class="methodname">ReadyToRun</code>()
|
||
{
|
||
if (<code class="varname">logfd</code> < 0)
|
||
<code class="function">fprintf</code>( <code class="filename">stderr</code>, "cannot create logfile\n");
|
||
else if (!<code class="methodname">Init</code>(<code class="varname">com</code>))
|
||
<code class="methodname">Quit</code>();
|
||
}
|
||
|
||
<span class="type">void</span> <code class="methodname">Done</code>()
|
||
{
|
||
<code class="methodname">mLock</code>();
|
||
<code class="methodname">Quit</code>();
|
||
<code class="methodname">Unlock</code>( );
|
||
}
|
||
|
||
<span class="type">int</span> <code class="methodname">GetData</code>(<span class="type">uchar</span> <code class="parameter">data</code>[], <span class="type">uint</span> <code class="parameter">n</code>)
|
||
{
|
||
return (<code class="function">read</code>(0, <code class="parameter">data</code>, <code class="parameter">n</code>));
|
||
}
|
||
|
||
<span class="type">int</span> <code class="methodname">PutData</code>(<span class="type">uchar</span> <code class="parameter">data</code>[], <span class="type">uint</span> <code class="parameter">n</code>)
|
||
{
|
||
<code class="function">write</code>( <code class="varname">logfd</code>, <code class="parameter">data</code>, <code class="parameter">n</code>);
|
||
return (<code class="function">write</code>( 1, <code class="parameter">data</code>, <code class="parameter">n</code>));
|
||
}
|
||
|
||
<span class="type">char **</span><code class="varname">com</code>;
|
||
<span class="type">int</span> <code class="varname">logfd</code>;
|
||
};
|
||
|
||
<code class="function">main</code>()
|
||
{
|
||
<span class="type">static char *</span><code class="varname">com</code>[] = { "/bin/sh", 0 };
|
||
<code class="classname">Script</code> <code class="varname">s</code>( "application/script", <code class="varname">com</code>, "typescript");
|
||
|
||
return (0);
|
||
}
|
||
</pre><p>
|
||
The <code class="methodname">GetData()</code> hook is called by
|
||
<code class="classname">PTY</code> to get more data for the slave side. The
|
||
<code class="methodname">PutData()</code> hook is called when data from the slave
|
||
side has arrived. The <code class="methodname">Done()</code> hook is called when
|
||
<code class="classname">PTY</code> has detected that the subshell has exited. The
|
||
Be app can initiate a shutdown at any time by inducing a
|
||
<code class="classname">PTY</code> destructor call.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id781812"></a>Usage</h3></div></div></div><p>
|
||
To compile <span class="application">script</span>, clip out the code to
|
||
<code class="filename">script.cpp</code>, and type
|
||
</p><pre class="screen">
|
||
gcc script.cpp -lbe
|
||
</pre><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id781833"></a>Example 1: Capture some command output.</h4></div></div></div><pre class="screen">
|
||
$ script
|
||
sh-2.02# date
|
||
Fri Apr 16 02:01:26 CDT 1999
|
||
sh-2.02# exit
|
||
$ cat typescript
|
||
sh-2.02# date
|
||
Fri Apr 16 02:01:26 CDT 1999
|
||
sh-2.02# exit
|
||
$
|
||
</pre><p>
|
||
(Hmm, says something about my schedule.)
|
||
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id781852"></a>Example 2: A fully scripted Terminal.</h4></div></div></div><pre class="screen">
|
||
Terminal script
|
||
</pre><p>
|
||
Of course, this doesn't work if you are accessing your machine remotely
|
||
(e.g., using "telnet"); see Example 1 for this situation.
|
||
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id781869"></a>Example 3: Interactive program under program control.</h4></div></div></div><pre class="screen">
|
||
(sleep 1; echo bc; echo 1; echo '2^99999/2^99998'; sleep 60)
|
||
| script
|
||
</pre><p>
|
||
Compare the behavior and output with the earlier <code class="command">bc</code> example; the "sleep
|
||
60" is needed because an early EOF to <span class="application">script</span> will cause it to shut
|
||
down, and lose the long calculation. Given a command language and
|
||
bi-direction data flow to/from the target program, you can create a
|
||
powerful program-driving utility (like the popular <span class="application">"expect"</span>).
|
||
</p></div></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id781904"></a>Caveat</h3></div></div></div><p>
|
||
The content of "typescript" is a chronological record of all output, both
|
||
from programs and your own echoed input. It will likely contain ASCII
|
||
Return (octal 015), Bell (007), Backspace (010), Tab (011), and any ANSI
|
||
escape sequences. All these effects are faithfully reproduced with
|
||
</p><pre class="screen">
|
||
cat typescript
|
||
</pre><p>
|
||
You can see the uninterpreted stream by using a text editor or with
|
||
</p><pre class="screen">
|
||
od -c typescript
|
||
</pre><p>
|
||
"typescript" is quite different from Terminal copy-n-paste, where you are
|
||
selecting inert glyphs—different tools for different purposes.
|
||
</p></div></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering4-16-2"></a>Be Engineering Insights: Duty Now for the Future</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Howard</span> <span class="surname">Berkey</span></span></div></div></div><p>
|
||
Besides being the name of a great DEVO album, the title of this article
|
||
represents what I'd like to do with my space in this week's newsletter.
|
||
That is, describe some of the upcoming features in BeOS networking.
|
||
</p><p>
|
||
For Genki, the most visible change from a developer's standpoint is the
|
||
new C++ networking API. This was shipped in the 4.1 beta CD's
|
||
Experimental folder, and will be a part of the main Genki distribution.
|
||
The entire kit may be accessed by including
|
||
<code class="filename">NetworkKit.h</code> and linking
|
||
against <code class="filename">libnet.so</code>
|
||
and <code class="filename">libnetapi.so</code>. The new API introduces three main
|
||
classes: <code class="classname">BNetEndpoint</code>, <code class="classname">BNetAddress</code>,
|
||
and <code class="classname">BNetBuffer</code>. These classes
|
||
simplify creating and using network data connections, addresses, and
|
||
data, respectively. Documentation is forthcoming; until then, this
|
||
newsletter article and comments in the headers should be enough to get
|
||
you started.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782020"></a>BNetEndpoint</h3></div></div></div><p>
|
||
The <code class="classname">BNetEndpoint</code> class abstracts network communication endpoints—think
|
||
of it as a "socket object." <code class="classname">BNetEndpoint</code> takes care of all the necessary
|
||
initialization in its constructor; it makes creating network connections
|
||
very simple:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">int32</span> <code class="function">send_data</code>(<span class="type">const char *</span><code class="parameter">host</code>, <span class="type">short</span> <code class="parameter">port</code>,
|
||
<span class="type">const void*</span><code class="parameter">data</code>, <span class="type">int32</span> <code class="parameter">datalen</code>)
|
||
{
|
||
<code class="classname">BNetEndpoint</code> <code class="varname">comm</code>(<code class="constant">SOCK_STREAM</code>);
|
||
<span class="type">int32</span> <code class="varname">rc</code> = -1;
|
||
|
||
|
||
if(<code class="varname">comm</code>.<code class="methodname">InitCheck</code>() == <code class="constant">B_NO_ERROR</code>)
|
||
{
|
||
if(<code class="varname">comm</code>.<code class="methodname">Connect</code>(<code class="parameter">host</code>, <code class="parameter">port</code>) == <code class="constant">B_NO_ERROR</code>)
|
||
{
|
||
<code class="varname">rc</code> = <code class="varname">comm</code>.<code class="methodname">Send</code>(<code class="parameter">data</code>, <code class="parameter">datalen</code>);
|
||
}
|
||
}
|
||
return <code class="varname">rc</code>;
|
||
}
|
||
</pre><p>
|
||
The above code creates a <acronym class="acronym" title="Transmission Control Protocol">TCP</acronym>
|
||
connection to the specified hostname and
|
||
port, sends the data passed in, and automatically closes the connection,
|
||
returning the amount of data sent, or -1 on failure. As you can see, much
|
||
of the setup and housekeeping typically required when doing network
|
||
programming is taken care of by the <code class="classname">BNetEndpoint</code> object.
|
||
</p><p>
|
||
Many <code class="classname">BNetEndpoint</code> member functions map orthogonally
|
||
to the <acronym class="acronym">BSD</acronym> sockets
|
||
<acronym class="acronym">API</acronym>; it's also possible to get the socket descriptor out of a
|
||
<code class="classname">BNetEndpoint</code> for use with the standard sockets API. See
|
||
<code class="filename">NetEndpoint.h</code>
|
||
for details.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782200"></a>BNetAddress</h3></div></div></div><p>
|
||
Just as you can think of <code class="classname">BNetEndpoint</code> as a class that encapsulates the
|
||
<acronym class="acronym">BSD</acronym> sockets <acronym class="acronym">API</acronym>, <code class="classname">BNetAddress</code>
|
||
is a class that encapsulates the
|
||
functionality found in <code class="filename">netdb.h</code>.
|
||
<code class="classname">BNetAddress</code> is a convenient way to
|
||
store, resolve, and manipulate network addresses.
|
||
</p><p>
|
||
<code class="classname">BNetAddress</code> is used to represent network addresses, and provide useful
|
||
access to a network address in a variety of formats. <code class="classname">BNetAddress</code> provides
|
||
various ways to get and set a network address, converting to or from the
|
||
chosen representation into a generic internal one.
|
||
</p><p>
|
||
<code class="methodname">BNetAddress::SetTo()</code> is used to set the object to refer to the address
|
||
passed in, which can be specified in a variety of formats (omitting
|
||
<code class="methodname">InitCheck()</code>ing):
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">void</span> <code class="function">addrs</code>()
|
||
{
|
||
BNetAddress <code class="varname">addr</code>;
|
||
struct sockaddr_in <code class="varname">sa</code>;
|
||
in_addr <code class="varname">ia</code>;
|
||
|
||
<code class="varname">addr</code>.<code class="methodname">SetTo</code>("www.be.com", 80);
|
||
<code class="varname">addr</code>.<code class="methodname">SetTo</code>("www.be.com", "tcp", "http");
|
||
|
||
<span class="comment">// www.be.com == 207.126.103.9</span>
|
||
<code class="varname">ia</code>.<code class="varname">s_addr</code> = <code class="function">inet_addr</code>("207.126.103.9");
|
||
<code class="varname">addr</code>.<code class="methodname">SetTo</code>(<code class="varname">ia</code>, 80);
|
||
|
||
<code class="varname">sa</code>.<code class="varname">sin_family</code> = <code class="constant">AF_INET</code>;
|
||
<code class="varname">sa</code>.<code class="varname">sin_port</code> = <code class="function">htons</code>(80);
|
||
<code class="varname">sa</code>.<code class="varname">sin_addr</code> = <code class="function">inet_addr</code>("207.126.103.9");
|
||
<code class="varname">addr</code>.<code class="methodname">SetTo</code>(<code class="varname">sa</code>);
|
||
}
|
||
</pre><p>
|
||
All calls to <code class="code">addr.SetTo</code> in the above example are equivalent.
|
||
</p><p>
|
||
Similarly, <code class="methodname">BNetAddress::GetAddr()</code> returns the address referred to by the
|
||
<code class="classname">BNetAddress</code> object in a variety of formats. For example, the following
|
||
code converts <span class="type">sockaddr_in</span> structures into human-readable hostnames:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">void</span> <code class="function">sin_convert</code>(<span class="type">const struct sockaddr_in &</span><code class="parameter">sa</code>)
|
||
{
|
||
<code class="classname">BNetAddress</code> <code class="varname">addr</code>(<code class="parameter">sa</code>);
|
||
<span class="type">char</span> <code class="varname">host</code>[256];
|
||
<span class="type">unsigned short</span> <code class="varname">port</code>;
|
||
|
||
<code class="varname">addr</code>.<code class="methodname">GetAddr</code>(<code class="varname">host</code>, <code class="varname">port</code>);
|
||
|
||
cout << "Host: " << <code class="varname">host</code> << "Port: " << <code class="varname">port</code> << endl;
|
||
}
|
||
</pre><p>
|
||
Likewise, to resolve a host name into a sockaddr_in:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">struct sockaddr_in</span> <code class="function">resolve</code>(<span class="type">const char *</span><code class="parameter">host</code>)
|
||
{
|
||
<code class="classname">BNetAddress</code> <code class="varname">addr</code>(<code class="parameter">host</code>);
|
||
<span class="type">struct sockaddr_in</span> <code class="varname">sa</code>;
|
||
|
||
<code class="varname">addr</code>.<code class="methodname">GetAddr</code>(<code class="varname">sa</code>);
|
||
|
||
return <code class="varname">sa</code>;
|
||
}
|
||
</pre><p>
|
||
As you can see from these examples, <code class="classname">BNetAddress</code> has a number of
|
||
constructors that mirror its <code class="methodname">SetTo()</code>
|
||
member functions. <code class="classname">BNetAddress</code> also
|
||
takes care of any byte order conversion that's necessary with network
|
||
addresses.
|
||
</p><p>
|
||
<code class="classname">BNetEndpoint</code> is designed to work closely with
|
||
<code class="classname">BNetAddress</code>; any addresses
|
||
it expects can be represented by a <code class="classname">BNetAddress</code>, such as in
|
||
<code class="methodname">BNetEndpoint::SendTo()</code>.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782572"></a>BNetBuffer</h3></div></div></div><p>
|
||
Unlike <code class="classname">BNetAddress</code> and <code class="classname">BNetEndpoint</code>,
|
||
<code class="classname">BNetBuffer</code> has no analog in the <acronym class="acronym">BSD</acronym>
|
||
sockets <acronym class="acronym">API</acronym>. <code class="classname">BNetBuffer</code> is
|
||
a convenient way to manage network data that
|
||
is to be sent across the wire, including mundane tasks such as byte order
|
||
conversion. <code class="classname">BNetBuffer</code> is a network data container class. As I mention in
|
||
<code class="filename">NetBuffer.h</code>: <code class="classname">BNetBuffer</code>
|
||
is a dynamic buffer useful for storing data to
|
||
be sent across the network. Data is inserted into and removed from the
|
||
object using one of the many <code class="methodname">Append()</code>
|
||
and <code class="methodname">Remove()</code> member functions. Access
|
||
to the raw stored data is possible. The <code class="classname">BNetEndpoint</code>
|
||
class has a <code class="methodname">Send()</code> and
|
||
<code class="methodname">Receive()</code> function for use with
|
||
<code class="classname">BNetBuffer</code>. Network byte order conversion
|
||
is done automatically for all appropriate integral types in the <code class="methodname">Append()</code>
|
||
and <code class="methodname">Remove()</code> functions for that type.
|
||
</p><p>
|
||
<code class="classname">BNetBuffer</code> is best illustrated by an example. Suppose you have a
|
||
transaction protocol between a network client and a server application
|
||
which specifies that whenever the client receives a <code class="classname">BMessage</code>, it forwards
|
||
it to the server over the network connection, along with a client
|
||
timestamp and a transaction ID, which is a monotonically increasing
|
||
<span class="type">uint32</span>. It could be coded thusly:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">static uint32</span> gTransID = 0;
|
||
|
||
[...]
|
||
|
||
<span class="type">int32</span> <code class="function">forwardBMessageToServer</code>(<span class="type">const <code class="classname">BMessage</code> &</span><code class="parameter">msg</code>,
|
||
BNetEndpoint &serverConn)
|
||
{
|
||
BNetBuffer packet, sizepack;
|
||
bigtime_t timestamp;
|
||
uint32 trans_id, size;
|
||
|
||
timestamp = system_time();
|
||
trans_id = atomic_add(&gTransID, 1);
|
||
|
||
packet.AppendUInt32(trans_id);
|
||
packet.AppendUInt64(timestamp);
|
||
packet.AppendMessage(msg);
|
||
|
||
size = packet.Size();
|
||
sizepack.AppendUInt32(size);
|
||
|
||
serverConn.Send(sizepack);
|
||
return serverConn.Send(packet);
|
||
}
|
||
</pre><p>
|
||
Voila! Networked <code class="classname">BMessage</code>s. <code class="classname">BNetBuffer</code>
|
||
does all the necessary byte order
|
||
conversion, so the server simply needs to call the matching <code class="methodname">Remove()</code>
|
||
member functions to get at the data the client was sending.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782730"></a>Archiving</h3></div></div></div><p>
|
||
Astute readers of the header files will have noticed by now that the C++
|
||
Networking API classes are all derived from <code class="classname">BArchivable</code>. In the case of
|
||
<code class="classname">BNetAddress</code> and <code class="classname">BNetBuffer</code>,
|
||
the archived data is just what you would
|
||
expect; a byte-gender-neutral archive of the address info or network
|
||
data, respectively.
|
||
</p><p>
|
||
For <code class="classname">BNetEndpoint</code>, it goes one step further—network connections are
|
||
archived. For example, if you're connected to a host and port when you
|
||
archive the <code class="classname">BNetEndpoint</code> object, later instantiation of that archive
|
||
returns a <code class="classname">BNetEndpoint</code> that is connected to the same host and port.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782775"></a>Debugging</h3></div></div></div><p>
|
||
There's also a class called <code class="classname">BNetDebug</code>, which provides (surprise!) some
|
||
debugging functionality. Calling <code class="code">BNetDebug::Enable(true)</code> turns Net API
|
||
debugging on; you can then call <code class="methodname">BNetDebug::Dump()</code> with buffers of data
|
||
for a nice hd-like output when you run your program from the Terminal.
|
||
Many <code class="classname">BNetEndpoint</code> calls generate debugging output when debugging is
|
||
enabled; play around and you'll see what I mean. The debug messages are
|
||
printed to <code class="filename">stderr</code>.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id782811"></a>Wrapping It Up</h3></div></div></div><p>
|
||
This overview should be enough to get you started with the new C++
|
||
networking API. But what would a newsletter article be without some
|
||
sample code for you to play with? You can find the source code for a
|
||
simple FTP client I wrote using the new networking API at:
|
||
ftp://ftp.be.com/pub/samples/network kit/FtpClient.zip
|
||
</p></div></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="DevWorkshop4-16"></a>Developers' Workshop: Media Kit Basics: Muxamania Part 1: The Media
|
||
Control Panel Application</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Owen</span> <span class="surname">Smith</span></span></div></div></div><p>
|
||
This week I've cooked up one of several Media Kit goodies that was
|
||
requested at the BeDC. It's a node, completely encapsulated in a media
|
||
add-on, that allows you to select one of several inputs to pass to the
|
||
output.
|
||
</p><p>
|
||
This code works with the upcoming beta release, genki/5. Go grab it from:
|
||
</p><p>
|
||
ftp://ftp.be.com/pub/samples/media_kit/Selector.zip
|
||
</p><p>
|
||
In this article, I'll illustrate how to create a simple UI for the node.
|
||
In the next installment, I plan to show you how the node handles buffers
|
||
and manages connections.
|
||
</p><p>
|
||
In Selector, I want users to be able to select the input they want routed
|
||
to the output. But, since the acrid smoke from BeDC preparations still
|
||
hasn't cleared from my Kube, I don't want to spend a lot of time working
|
||
on the UI. I'm looking for the simplest fire-and-forget mechanism I can
|
||
come up with.
|
||
</p><p>
|
||
In this case, <code class="methodname">BMediaRoster::StartControlPanel()</code> is definitely the answer.
|
||
It's designed to take care of all the details of running a UI for our
|
||
node, with no sticky residue. Unless your node says otherwise,
|
||
<code class="methodname">StartControlPanel()</code> simply launches your add-on as an application. The ID
|
||
of the node that you're editing will be passed to the newly launched
|
||
application as a command line argument.
|
||
</p><p>
|
||
There's one piece that is left for you, the add-on writer, to fill in:
|
||
you must determine what the add-on does once it's launched. Generally,
|
||
this involves displaying a window containing controls for editing the
|
||
node.
|
||
</p><p>
|
||
I've created a simple class to do most of the work for you:
|
||
<code class="classname">MediaControlPanelApp</code>. This
|
||
<code class="classname">BApplication</code>-derived class does the following:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
It parses the command line to get the node IDs that will be passed to
|
||
it, and launches control panels for each of the nodes it's editing.
|
||
</p></li><li><p>
|
||
It keeps track of all currently running control panels, and quits
|
||
when all control panels have been closed.
|
||
</p></li><li><p>
|
||
It provides a virtual function <code class="methodname">CreateControlPanel()</code> (not related to
|
||
<code class="methodname">BMediaRoster::StartControlPanel()</code>!) which gets called when a new
|
||
control panel must be created for a node. By default, it creates a
|
||
simple window that shrinkwraps around the default media theme's view
|
||
for the node. However, you can override this function to create custom
|
||
<code class="classname">BWindow</code>s for your own kinds of nodes if you wish.
|
||
</p></li></ul><p>
|
||
Now, what does it take to get this awesome functionality in your add-on?
|
||
</p><pre class="programlisting cpp">
|
||
int main()
|
||
{
|
||
MediaControlPanelApp app;
|
||
app.Run();
|
||
return 0;
|
||
}
|
||
</pre><p>
|
||
... Not too much, I guess.
|
||
</p><p>
|
||
In conclusion, I'd like to extend greetings to all of the developers I
|
||
managed to meet in person at the BeDC. Even jacked up on a week's worth
|
||
of Dew and adrenaline, I somehow managed to relax a bit (especially after
|
||
the presentations were over!), and it was a singular treat for me to hang
|
||
out with you, the people that make this job really worthwhile.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Gassee4-16"></a>More Better Formats...and a New Wing for the Great Roach Motel</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Jean-Louis</span> <span class="surname">Gassée</span></span></div></div></div><p>
|
||
It is a thing of beauty. We must take our hats off to Microsoft, again --
|
||
this time for two reasons: last week's announcement of MS Audio and the
|
||
soon-to-be-released Office 2000. Seriously, one has to admire the
|
||
strategic foresight and speedy execution, not to mention the way that
|
||
Microsoft moves the battle to a new field, leaving behind browser and
|
||
contractual skirmishes.
|
||
</p><p>
|
||
Let's start with the roach motel metaphor. It refers to file formats and
|
||
their use to trap files and their owners—and their wallets. As the old
|
||
slogan goes, "They can get in, but they can't check out."
|
||
</p><p>
|
||
Let's say that your business is
|
||
<acronym class="acronym" title="Computer Aided Design">CAD</acronym> software.
|
||
Files store complex designs
|
||
in a structured way, ready to be fed again into a kind of interpreter
|
||
that can further edit the design and render it on a screen or on paper,
|
||
on some <acronym class="acronym" title="Printed Circuit Board">PCB</acronym>
|
||
layout, or on chip-making equipment. The file format helps
|
||
your business in two ways, apart from offering rich constructs,
|
||
reliability and speed: 1) It can keep your competitors from seducing your
|
||
customers; and 2) It can help you generate revenue with new releases.
|
||
</p><p>
|
||
Both outcomes exhibit the same wonderful, hard to unscramble, mix of
|
||
legitimate and manipulative characteristics. In some cases, the law is on
|
||
your side and lets you protect trade secrets or even grants you a patent,
|
||
as we've seen for some formats. Or, you can keep your competitors
|
||
guessing or running if you hide and modify at the appropriate pace. In
|
||
addition, a new and richer format "encourages" customers to upgrade if
|
||
they want to continue exchanging files. In any given group, one or two
|
||
users of the new version is all it takes, and the newer/richer <acronym class="acronym">CAD</acronym> cannot
|
||
be read by the old version, without some information being lost.
|
||
</p><p>
|
||
We saw this game played with Office 97. Initially, in spite of using the
|
||
same three-letter suffix, Word 95 could not read the <code class="filename">.doc</code> files stored by
|
||
Word 97 users, thus encouraging users to move to the new version. But
|
||
users were not encouraged, they were enraged, thus in turn encouraging
|
||
Microsoft to issue a fix to allow interoperation of <code class="filename">.doc</code> files. In
|
||
another instance, the use of the <acronym class="acronym">RTF</acronym> format is now suggested by the Word
|
||
assistant. RTF is referred to as an exchange format that other non-MS
|
||
word processors can read. But if my information is correct, this is only
|
||
partly true. If you use "shapes" in your Word 97 document and store it in
|
||
<acronym class="acronym">RTF</acronym> format, you might believe the document will "interoperate" with
|
||
<acronym class="acronym">RTF</acronym>-capable word processors, but you might lose the drawings inserted in
|
||
the text. Again, I'm not saying this is automatically a bad thing, but
|
||
you see how it could be manipulated, used to thwart competitors and to
|
||
get more revenue from the installed base. A good example of the hard-to-
|
||
unscramble mix. But this is the old style roach motel.
|
||
</p><p>
|
||
Windows begat Explorer and Explorer begat Microsoft's version of <acronym class="acronym">HTML</acronym>,
|
||
thus advancing the fulfillment of Nathan Myrhvold, Microsoft's chief
|
||
scientist. In a white paper discussed in a celebrated New Yorker article,
|
||
Nathan saw an opportunity in the future for Microsoft to get a "vig" on
|
||
Net transactions. Controlling the de facto standard for <acronym class="acronym">HTML</acronym> is a good
|
||
first step. Try raising money for a Web company whose site will use a
|
||
version of HTML Explorer doesn't "speak." Explorer is a roach motel of
|
||
larger dimension than Office. And it's expanding.
|
||
</p><p>
|
||
Last week we had the announcement of MS Audio, a new format presented as
|
||
full of goodies: smaller than MP3, higher sound quality, copy protection,
|
||
and permission features. One has to salute again the speed and quality of
|
||
response to the threat posed by MP3, a format Microsoft didn't control,
|
||
and to the Secure Digital Music Initiative, a future standard being
|
||
designed by a consortium of music publishers, their own response to the
|
||
dangerously libertarian MP3. Explorer begat MS Audio, and we can imagine
|
||
what could happen to the non-MS audio formats.
|
||
</p><p>
|
||
And next month, or in June, we'll have Office 2000, which takes the game
|
||
to yet another level. The default format for Office will embrace an
|
||
extension of <acronym class="acronym">HTML</acronym>, Microsoft's own <acronym class="acronym">XML</acronym>. The good news is that it uses the
|
||
Web as a publishing and exchange medium. The other news is that Microsoft
|
||
now has even more control over the formats used for business and
|
||
entertainment on the Web.
|
||
</p><p>
|
||
In my country of birth, government officials (and cultural pundits --
|
||
when different) worry about US domination through the primacy of American
|
||
English, the US dollar, and Hollywood entertainment. The way they see it,
|
||
if you mint all these tokens of human commerce, it gives you an
|
||
advantage. I don't think all French people will convert to English any
|
||
time soon, but, for computers, all you need is a Windows or Office
|
||
upgrade and the new tokens are in circulation. This is what I meant when
|
||
I wondered if Microsoft hadn't succeeded in moving past the antitrust
|
||
suit—even before its conclusion—in a truly awesome way.
|
||
</p></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue4-15.html">Issue 4-15, April 14, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-17.html">Issue 4-17, April 28, 1999</a> </div><div id="footerB"><div id="footerBL"><a href="Issue4-15.html" title="Issue 4-15, April 14, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="Issue4-17.html" title="Issue 4-17, April 28, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|