~ubuntu-branches/ubuntu/intrepid/meanwhile/intrepid

« back to all changes in this revision

Viewing changes to samples/socket.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-01-13 12:38:18 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060113123818-zod7j3hd9z0iz5fy
Tags: 1.0.2-0ubuntu1
* New upstream release
* Rename libmeanwhile0 to libmeanwhile1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
  Meanwhile - Unofficial Lotus Sametime Community Client Library
 
4
  Copyright (C) 2004  Christopher (siege) O'Brien
 
5
  
 
6
  This library is free software; you can redistribute it and/or
 
7
  modify it under the terms of the GNU Library General Public
 
8
  License as published by the Free Software Foundation; either
 
9
  version 2 of the License, or (at your option) any later version.
 
10
  
 
11
  This library is distributed in the hope that it will be useful,
 
12
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
  Library General Public License for more details.
 
15
  
 
16
  You should have received a copy of the GNU Library General Public
 
17
  License along with this library; if not, write to the Free
 
18
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
19
*/
 
20
 
 
21
 
 
22
 
 
23
/**
 
24
   @file socket.c
 
25
   
 
26
   This file is a simple demonstration of using unix socket code to
 
27
   connect a mwSession to a sametime server and get it fully logged
 
28
   in. It doesn't do anything after logging in.
 
29
   
 
30
   Here you'll find examples of:
 
31
    - opening a socket to the host
 
32
    - using the socket to feed data to the session
 
33
    - using a session handler to allow the session to write data to the
 
34
      socket
 
35
    - using a session handler to allow the session to close the socket
 
36
    - watching for error conditions on read/write
 
37
*/
 
38
 
 
39
 
 
40
 
 
41
#include <netdb.h>
 
42
#include <netinet/in.h>
 
43
#include <stdio.h>
 
44
#include <stdlib.h>
 
45
#include <string.h>
 
46
#include <sys/socket.h>
 
47
#include <sys/types.h>
 
48
#include <unistd.h>
 
49
 
 
50
#include <glib.h>
 
51
 
 
52
#include <mw_common.h>
 
53
#include <mw_session.h>
 
54
 
 
55
 
 
56
 
 
57
/** help text if you don't give the right number of arguments */
 
58
#define HELP \
 
59
"Meanwhile sample socket client\n" \
 
60
"Usage: %s server userid password\n" \
 
61
"\n" \
 
62
"Connects to a sametime server and logs in with the supplied user ID\n" \
 
63
"and password. Doesn't actually do anything useful after that.\n\n"
 
64
 
 
65
 
 
66
 
 
67
/** how much to read from the socket in a single call */
 
68
#define BUF_LEN 2048
 
69
 
 
70
 
 
71
 
 
72
/* client data should be put into a structure and associated with the
 
73
   session. Then it will be available from the many call-backs
 
74
   handling events from the session */
 
75
struct sample_client {
 
76
  struct mwSession *session;  /* the actual meanwhile session */
 
77
  int sock;                   /* the socket connecting to the server */
 
78
  int sock_event;             /* glib event id polling the socket */
 
79
};
 
80
 
 
81
 
 
82
 
 
83
/* the io_close function from the session handler */
 
84
static void mw_session_io_close(struct mwSession *session) {
 
85
  struct sample_client *client;
 
86
 
 
87
  /* get the client data from the session */
 
88
  client = mwSession_getClientData(session);
 
89
 
 
90
  /* safety check */
 
91
  g_return_if_fail(client != NULL);
 
92
 
 
93
  /* if the client still has a socket to be closed, close it */
 
94
  if(client->sock) {    
 
95
    g_source_remove(client->sock_event);
 
96
    close(client->sock);
 
97
    client->sock = 0;
 
98
    client->sock_event = 0;
 
99
  }
 
100
}
 
101
 
 
102
 
 
103
 
 
104
/* the io_write function from the session handler */
 
105
static int mw_session_io_write(struct mwSession *session,
 
106
                               const guchar *buf, gsize len) {
 
107
 
 
108
  struct sample_client *client;
 
109
  int ret = 0;
 
110
 
 
111
  /* get the client data from the session */
 
112
  client = mwSession_getClientData(session);
 
113
 
 
114
  /* safety check */
 
115
  g_return_val_if_fail(client != NULL, -1);
 
116
 
 
117
  /* socket was already closed, so we can't possibly write to it */
 
118
  if(client->sock == 0) return -1;
 
119
 
 
120
  /* write out the data to the socket until it's all gone */
 
121
  while(len) {
 
122
    ret = write(client->sock, buf, len);
 
123
    if(ret <= 0) break;
 
124
    len -= ret;
 
125
  }
 
126
 
 
127
  /* if for some reason we couldn't finish writing all the data, there
 
128
     must have been a problem */
 
129
  if(len > 0) {
 
130
    /* stop watching the socket */
 
131
    g_source_remove(client->sock_event);
 
132
 
 
133
    /* close the socket */
 
134
    close(client->sock);
 
135
 
 
136
    /* remove traces of socket from client */
 
137
    client->sock = 0;
 
138
    client->sock_event = 0;
 
139
 
 
140
    /* return error code */
 
141
    return -1;
 
142
  }
 
143
 
 
144
  /* return success code */
 
145
  return 0;
 
146
}
 
147
 
 
148
 
 
149
 
 
150
/* the on_stateChange function from the session handler */
 
151
static void mw_session_stateChange(struct mwSession *session,
 
152
                                   enum mwSessionState state, 
 
153
                                   gpointer info) {
 
154
 
 
155
  if(state == mwSession_STARTED) {
 
156
    /* at this point the session is all ready to go. */
 
157
    printf("session fully started\n");
 
158
  }
 
159
}
 
160
 
 
161
 
 
162
 
 
163
/* the session handler structure is where you should indicate what
 
164
   functions will perform many of the functions necessary for the
 
165
   session to operate. Among these, only io_write and io_close are
 
166
   absolutely required. */
 
167
static struct mwSessionHandler mw_session_handler = {
 
168
  .io_write = mw_session_io_write,  /**< handle session to socket */
 
169
  .io_close = mw_session_io_close,  /**< handle session closing socket */
 
170
  .clear = NULL,                    /**< cleanup function */
 
171
  .on_stateChange = mw_session_stateChange,  /**< session status changed */
 
172
  .on_setPrivacyInfo = NULL,        /**< received privacy information */
 
173
  .on_setUserStatus = NULL,         /**< received status information */
 
174
  .on_admin = NULL,                 /**< received an admin message */
 
175
};
 
176
 
 
177
 
 
178
 
 
179
/** called from read_cb, attempts to read available data from sock and
 
180
    pass it to the session. Returns zero when the socket has been
 
181
    closed, less-than zero in the event of an error, and greater than
 
182
    zero for success */
 
183
static int read_recv(struct mwSession *session, int sock) {
 
184
  guchar buf[BUF_LEN];
 
185
  int len;
 
186
 
 
187
  len = read(sock, buf, BUF_LEN);
 
188
  if(len > 0) mwSession_recv(session, buf, len);
 
189
 
 
190
  return len;
 
191
}
 
192
 
 
193
 
 
194
 
 
195
/** callback registerd via g_io_add_watch in main, watches the socket
 
196
    for available data to be processed by the session */
 
197
static gboolean read_cb(GIOChannel *chan,
 
198
                        GIOCondition cond,
 
199
                        gpointer data) {
 
200
 
 
201
  struct sample_client *client = data;
 
202
  int ret = 0;
 
203
 
 
204
  if(cond & G_IO_IN) {
 
205
    ret = read_recv(client->session, client->sock);
 
206
 
 
207
    /* successful operation ends here, as the read_recv function
 
208
       should only return sero or lower in the event of a disconnect
 
209
       or error */
 
210
    if(ret > 0) return TRUE;
 
211
  }
 
212
 
 
213
  /* read problem occured if we're here, so we'll need to take care of
 
214
     it and clean up internal state */
 
215
  if(client->sock) {
 
216
 
 
217
    /* stop watching the socket */
 
218
    g_source_remove(client->sock_event);
 
219
 
 
220
    /* close it */
 
221
    close(client->sock);
 
222
 
 
223
    /* don't reference the socket or its event now that they're gone */
 
224
    client->sock = 0;
 
225
    client->sock_event = 0;
 
226
  }
 
227
 
 
228
  return FALSE;
 
229
}
 
230
 
 
231
 
 
232
 
 
233
/* address lookup used by init_sock */
 
234
static void init_sockaddr(struct sockaddr_in *addr,
 
235
                          const char *host, int port) {
 
236
 
 
237
  struct hostent *hostinfo;
 
238
 
 
239
  addr->sin_family = AF_INET;
 
240
  addr->sin_port = htons (port);
 
241
  hostinfo = gethostbyname(host);
 
242
  if(hostinfo == NULL) {
 
243
    fprintf(stderr, "Unknown host %s.\n", host);
 
244
    exit(1);
 
245
  }
 
246
  addr->sin_addr = *(struct in_addr *) hostinfo->h_addr;
 
247
}
 
248
 
 
249
 
 
250
 
 
251
/* open and return a network socket fd connected to host:port */
 
252
static int init_sock(const char *host, int port) {
 
253
  struct sockaddr_in srvrname;
 
254
  int sock;
 
255
 
 
256
  sock = socket(PF_INET, SOCK_STREAM, 0);
 
257
  if(sock < 0) {
 
258
    fprintf(stderr, "socket failure");
 
259
    exit(1);
 
260
  }
 
261
  
 
262
  init_sockaddr(&srvrname, host, port);
 
263
  connect(sock, (struct sockaddr *)&srvrname, sizeof(srvrname));
 
264
 
 
265
  return sock;
 
266
}
 
267
 
 
268
 
 
269
 
 
270
int main(int argc, char *argv[]) {
 
271
 
 
272
  /* the meanwhile session itself */
 
273
  struct mwSession *session;
 
274
 
 
275
  /* client program data */
 
276
  struct sample_client *client;
 
277
 
 
278
  /* something glib uses to watch the socket for available data */
 
279
  GIOChannel *io_chan;
 
280
 
 
281
  /* specify host, user, pass on the command line */
 
282
  if(argc != 4) {
 
283
    fprintf(stderr, HELP, *argv);
 
284
    return 1;
 
285
  }
 
286
 
 
287
  /* create the session and set the user and password */
 
288
  session = mwSession_new(&mw_session_handler);
 
289
  mwSession_setProperty(session, mwSession_AUTH_USER_ID, argv[2], NULL);
 
290
  mwSession_setProperty(session, mwSession_AUTH_PASSWORD, argv[3], NULL);
 
291
 
 
292
 
 
293
  /* create the client data. This is arbitrary data that a client will
 
294
     want to store along with the session for its own use */
 
295
  client = g_new0(struct sample_client, 1);
 
296
  client->session = session;
 
297
 
 
298
  /* associate the client data with the session, specifying an
 
299
     optional cleanup function which will be called upon the data when
 
300
     the session is free'd via mwSession_free */
 
301
  mwSession_setClientData(session, client, g_free);
 
302
 
 
303
  /* set up a connection to the host */
 
304
  client->sock = init_sock(argv[1], 1533);
 
305
 
 
306
  /* start the session. This will cause the session to send the
 
307
     handshake message (using the io_write function specified in the
 
308
     session handler). */
 
309
  mwSession_start(session);
 
310
 
 
311
  /* add a watch on the socket. Any data returning from the server
 
312
     will trigger read_cb, which will in turn read the data and pass
 
313
     it to the session for interpretation */
 
314
  io_chan = g_io_channel_unix_new(client->sock);
 
315
  client->sock_event = g_io_add_watch(io_chan, G_IO_IN | G_IO_ERR | G_IO_HUP,
 
316
                                      read_cb, client);
 
317
 
 
318
  /* Create a new main loop and start it. This will cause the above
 
319
     watch to begin actually polling the socket. Use g_idle_add,
 
320
     g_timeout_add to insert events into the event loop */
 
321
  g_main_loop_run(g_main_loop_new(NULL, FALSE));
 
322
 
 
323
  /* this won't happen until after the main loop finally terminates */
 
324
  return 0;
 
325
}
 
326
 
 
327