Subversion Repositories HelenOS

Rev

Rev 4327 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4327 Rev 4581
Line 91... Line 91...
91
 *          Otherwise return 0.
91
 *          Otherwise return 0.
92
 */
92
 */
93
static inline int method_is_forwardable(unative_t method)
93
static inline int method_is_forwardable(unative_t method)
94
{
94
{
95
    switch (method) {
95
    switch (method) {
-
 
96
    case IPC_M_CONNECTION_CLONE:
-
 
97
    case IPC_M_CONNECT_ME:
96
    case IPC_M_PHONE_HUNGUP:
98
    case IPC_M_PHONE_HUNGUP:
97
        /* This message is meant only for the original recipient. */
99
        /* This message is meant only for the original recipient. */
98
        return 0;
100
        return 0;
99
    default:
101
    default:
100
        return 1;
102
        return 1;
Line 138... Line 140...
138
 *          Return 0 otherwise.
140
 *          Return 0 otherwise.
139
 */
141
 */
140
static inline int answer_need_old(call_t *call)
142
static inline int answer_need_old(call_t *call)
141
{
143
{
142
    switch (IPC_GET_METHOD(call->data)) {
144
    switch (IPC_GET_METHOD(call->data)) {
-
 
145
    case IPC_M_CONNECTION_CLONE:
-
 
146
    case IPC_M_CONNECT_ME:
143
    case IPC_M_CONNECT_TO_ME:
147
    case IPC_M_CONNECT_TO_ME:
144
    case IPC_M_CONNECT_ME_TO:
148
    case IPC_M_CONNECT_ME_TO:
145
    case IPC_M_SHARE_OUT:
149
    case IPC_M_SHARE_OUT:
146
    case IPC_M_SHARE_IN:
150
    case IPC_M_SHARE_IN:
147
    case IPC_M_DATA_WRITE:
151
    case IPC_M_DATA_WRITE:
Line 180... Line 184...
180
    }
184
    }
181
 
185
 
182
    if (!olddata)
186
    if (!olddata)
183
        return 0;
187
        return 0;
184
 
188
 
-
 
189
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
-
 
190
        phoneid = IPC_GET_ARG1(*olddata);
-
 
191
        phone_t *phone = &TASK->phones[phoneid];
-
 
192
        if (IPC_GET_RETVAL(answer->data) != EOK) {
-
 
193
            /*
-
 
194
             * The recipient of the cloned phone rejected the offer.
-
 
195
             * In this case, the connection was established at the
-
 
196
             * request time and therefore we need to slam the phone.
-
 
197
             * We don't merely hangup as that would result in
-
 
198
             * sending IPC_M_HUNGUP to the third party on the
-
 
199
             * other side of the cloned phone.
-
 
200
             */
-
 
201
            mutex_lock(&phone->lock);
-
 
202
            if (phone->state == IPC_PHONE_CONNECTED) {
-
 
203
                spinlock_lock(&phone->callee->lock);
-
 
204
                list_remove(&phone->link);
-
 
205
                phone->state = IPC_PHONE_SLAMMED;
-
 
206
                spinlock_unlock(&phone->callee->lock);
-
 
207
            }
-
 
208
            mutex_unlock(&phone->lock);
-
 
209
        }
-
 
210
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME) {
-
 
211
        phone_t *phone = (phone_t *)IPC_GET_ARG5(*olddata);
-
 
212
        if (IPC_GET_RETVAL(answer->data) != EOK) {
-
 
213
            /*
-
 
214
             * The other party on the cloned phoned rejected our
-
 
215
             * request for connection on the protocol level.
-
 
216
             * We need to break the connection without sending
-
 
217
             * IPC_M_HUNGUP back.
-
 
218
             */
-
 
219
            mutex_lock(&phone->lock);
-
 
220
            if (phone->state == IPC_PHONE_CONNECTED) {
-
 
221
                spinlock_lock(&phone->callee->lock);
-
 
222
                list_remove(&phone->link);
-
 
223
                phone->state = IPC_PHONE_SLAMMED;
-
 
224
                spinlock_unlock(&phone->callee->lock);
-
 
225
            }
-
 
226
            mutex_unlock(&phone->lock);
-
 
227
        }
185
    if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
228
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
186
        phoneid = IPC_GET_ARG5(*olddata);
229
        phoneid = IPC_GET_ARG5(*olddata);
187
        if (IPC_GET_RETVAL(answer->data)) {
230
        if (IPC_GET_RETVAL(answer->data) != EOK) {
188
            /* The connection was not accepted */
231
            /* The connection was not accepted */
189
            phone_dealloc(phoneid);
232
            phone_dealloc(phoneid);
190
        } else {
233
        } else {
191
            /* The connection was accepted */
234
            /* The connection was accepted */
192
            phone_connect(phoneid, &answer->sender->answerbox);
235
            phone_connect(phoneid, &answer->sender->answerbox);
Line 194... Line 237...
194
            IPC_SET_ARG5(answer->data,
237
            IPC_SET_ARG5(answer->data,
195
                (unative_t) &TASK->phones[phoneid]);
238
                (unative_t) &TASK->phones[phoneid]);
196
        }
239
        }
197
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
240
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
198
        /* If the users accepted call, connect */
241
        /* If the users accepted call, connect */
199
        if (!IPC_GET_RETVAL(answer->data)) {
242
        if (IPC_GET_RETVAL(answer->data) == EOK) {
200
            ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
243
            ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
201
                &TASK->answerbox);
244
                &TASK->answerbox);
202
        }
245
        }
203
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_OUT) {
246
    } else if (IPC_GET_METHOD(*olddata) == IPC_M_SHARE_OUT) {
204
        if (!IPC_GET_RETVAL(answer->data)) {
247
        if (!IPC_GET_RETVAL(answer->data)) {
Line 291... Line 334...
291
        answer->buffer = NULL;
334
        answer->buffer = NULL;
292
    }
335
    }
293
    return 0;
336
    return 0;
294
}
337
}
295
 
338
 
-
 
339
static void phones_lock(phone_t *p1, phone_t *p2)
-
 
340
{
-
 
341
    if (p1 < p2) {
-
 
342
        mutex_lock(&p1->lock);
-
 
343
        mutex_lock(&p2->lock);
-
 
344
    } else if (p1 > p2) {
-
 
345
        mutex_lock(&p2->lock);
-
 
346
        mutex_lock(&p1->lock);
-
 
347
    } else {
-
 
348
        mutex_lock(&p1->lock);
-
 
349
    }
-
 
350
}
-
 
351
 
-
 
352
static void phones_unlock(phone_t *p1, phone_t *p2)
-
 
353
{
-
 
354
    mutex_unlock(&p1->lock);
-
 
355
    if (p1 != p2)
-
 
356
        mutex_unlock(&p2->lock);
-
 
357
}
-
 
358
 
296
/** Called before the request is sent.
359
/** Called before the request is sent.
297
 *
360
 *
298
 * @param call      Call structure with the request.
361
 * @param call      Call structure with the request.
299
 * @param phone     Phone that the call will be sent through.
362
 * @param phone     Phone that the call will be sent through.
300
 *
363
 *
Line 306... Line 369...
306
    size_t size;
369
    size_t size;
307
    uintptr_t src;
370
    uintptr_t src;
308
    int rc;
371
    int rc;
309
 
372
 
310
    switch (IPC_GET_METHOD(call->data)) {
373
    switch (IPC_GET_METHOD(call->data)) {
-
 
374
    case IPC_M_CONNECTION_CLONE: {
-
 
375
        phone_t *cloned_phone;
-
 
376
        GET_CHECK_PHONE(cloned_phone, IPC_GET_ARG1(call->data),
-
 
377
            return ENOENT);
-
 
378
        phones_lock(cloned_phone, phone);
-
 
379
        if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
-
 
380
            phone->state != IPC_PHONE_CONNECTED) {
-
 
381
            phones_unlock(cloned_phone, phone);
-
 
382
            return EINVAL;
-
 
383
        }
-
 
384
        /*
-
 
385
         * We can be pretty sure now that both tasks exist and we are
-
 
386
         * connected to them. As we continue to hold the phone locks,
-
 
387
         * we are effectively preventing them from finishing their
-
 
388
         * potential cleanup.
-
 
389
         */
-
 
390
        newphid = phone_alloc(phone->callee->task);
-
 
391
        if (newphid < 0) {
-
 
392
            phones_unlock(cloned_phone, phone);
-
 
393
            return ELIMIT;
-
 
394
        }
-
 
395
        ipc_phone_connect(&phone->callee->task->phones[newphid],
-
 
396
            cloned_phone->callee);
-
 
397
        phones_unlock(cloned_phone, phone);
-
 
398
        /* Set the new phone for the callee. */
-
 
399
        IPC_SET_ARG1(call->data, newphid);
-
 
400
        break;
-
 
401
    }
-
 
402
    case IPC_M_CONNECT_ME:
-
 
403
        IPC_SET_ARG5(call->data, (unative_t) phone);
-
 
404
        break;
311
    case IPC_M_CONNECT_ME_TO:
405
    case IPC_M_CONNECT_ME_TO:
312
        newphid = phone_alloc();
406
        newphid = phone_alloc(TASK);
313
        if (newphid < 0)
407
        if (newphid < 0)
314
            return ELIMIT;
408
            return ELIMIT;
315
        /* Set arg5 for server */
409
        /* Set arg5 for server */
316
        IPC_SET_ARG5(call->data, (unative_t) &TASK->phones[newphid]);
410
        IPC_SET_ARG5(call->data, (unative_t) &TASK->phones[newphid]);
317
        call->flags |= IPC_CALL_CONN_ME_TO;
411
        call->flags |= IPC_CALL_CONN_ME_TO;
Line 397... Line 491...
397
static int process_request(answerbox_t *box, call_t *call)
491
static int process_request(answerbox_t *box, call_t *call)
398
{
492
{
399
    int phoneid;
493
    int phoneid;
400
 
494
 
401
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
495
    if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME) {
402
        phoneid = phone_alloc();
496
        phoneid = phone_alloc(TASK);
403
        if (phoneid < 0) { /* Failed to allocate phone */
497
        if (phoneid < 0) { /* Failed to allocate phone */
404
            IPC_SET_RETVAL(call->data, ELIMIT);
498
            IPC_SET_RETVAL(call->data, ELIMIT);
405
            ipc_answer(box, call);
499
            ipc_answer(box, call);
406
            return -1;
500
            return -1;
407
        }
501
        }